Skip to content

Commit

Permalink
Add test for function invocation
Browse files Browse the repository at this point in the history
  • Loading branch information
asynchroza committed Nov 8, 2023
1 parent 1d48b2d commit b361310
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 41 deletions.
16 changes: 15 additions & 1 deletion nulascript/ast/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,18 @@ std::string Function::toString() {

return result;
}
std::string Function::tokenLiteral() { return token.literal; }
std::string Function::tokenLiteral() { return token.literal; }

Invocation::Invocation(Token token, Function* function)
: token(token), function(function) {}
std::string Invocation::toString() {
std::string result = "";
result += function->toString() + "(";
for (auto param : arguments) {
result += param->tokenLiteral() + ", ";
}
result += ")";

return result;
}
std::string Invocation::tokenLiteral() { return token.literal; }
12 changes: 12 additions & 0 deletions nulascript/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,16 @@ class Function : public Expression {
Function(Token token);
std::string tokenLiteral() override;
std::string toString() override;
};

class Invocation : public Expression {
public:
Token token;
Function* function;
std::vector<Expression*> arguments;

public:
Invocation(Token token, Function* function);
std::string tokenLiteral() override;
std::string toString() override;
};
47 changes: 28 additions & 19 deletions nulascript/parser/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ Parser::Parser(Lexer& l) {
registerInfixFunction(TokenType::IS, [&](Expression* left) -> Expression* {
return parseInfix(left);
});
registerInfixFunction(
TokenType::LPAR,
[&](Expression* left) -> Expression* { return parseInvocation(left); });

registerInfixFunction(
TokenType::IS_NOT,
Expand Down Expand Up @@ -346,29 +349,29 @@ Conditional* Parser::parseConditional() {
return conditional;
}

// std::vector<Expression*>* Parser::parseFunctionArguments() {
// std::vector<Expression*>* arguments = new std::vector<Expression*>();
std::vector<Expression*> Parser::parseInvocationArguments() {
std::vector<Expression*> arguments = std::vector<Expression*>();

// if(isEqualToPeekedTokenType(TokenType::RPAR)){
// getNextToken();
// return arguments;
// }
if (isEqualToPeekedTokenType(TokenType::RPAR)) {
getNextToken();
return arguments;
}

// getNextToken();
// arguments->push_back(parseExpression(Precedence::LOWEST));
getNextToken();
arguments.push_back(parseExpression(Precedence::LOWEST));

// while(isEqualToPeekedTokenType(TokenType::COMMA)){
// getNextToken();
// getNextToken();
// arguments->push_back(parseExpression(Precedence::LOWEST));
// }
while (isEqualToPeekedTokenType(TokenType::COMMA)) {
getNextToken();
getNextToken();
arguments.push_back(parseExpression(Precedence::LOWEST));
}

// if(!peekAndLoadExpectedToken(TokenType::RPAR)){
// return nullptr;
// }
if (!peekAndLoadExpectedToken(TokenType::RPAR)) {
return std::vector<Expression*>();
}

// return arguments;
// }
return arguments;
}

std::vector<Identifier*> Parser::parseFunctionArguments() {
auto arguments = std::vector<Identifier*>();
Expand Down Expand Up @@ -415,4 +418,10 @@ Function* Parser::parseFunction() {

// Function* Parser::parseFunctionExpression(Function) {
// auto function = new Function(currentToken);
// }
// }

Expression* Parser::parseInvocation(Expression* function) {
auto invocation = new Invocation(currentToken, (Function*)function);
invocation->arguments = parseInvocationArguments();
return invocation;
}
2 changes: 2 additions & 0 deletions nulascript/parser/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class Parser {
Expression* parseParensExpressions();
Function* parseFunction();
Function* parseFunctionExpression();
Expression* parseInvocation(Expression* function);
std::vector<Expression*> parseInvocationArguments();
std::vector<Identifier*> parseFunctionArguments();
bool isEqualToCurrentTokenType(TokenType tokenType);
bool isEqualToPeekedTokenType(TokenType tokenType);
Expand Down
71 changes: 50 additions & 21 deletions nulascript/tests/parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,24 @@ bool checkLiteral(Statement* expression, bool value) {
}

bool checkLiteral(Statement* expression, int value) {
ExpressionStatement* exp = dynamic_cast<ExpressionStatement*>(expression);
Integer* integer = dynamic_cast<Integer*>(expression);

if (!exp) {
std::cout << "literal is not ExpressionStatement. got="
<< typeid(*expression).name() << std::endl;
return false;
}
if (!integer) {
ExpressionStatement* exp =
dynamic_cast<ExpressionStatement*>(expression);
if (!exp) {
std::cout << "literal is not ExpressionStatement. got="
<< typeid(*expression).name() << std::endl;
return false;
}

Integer* integer = dynamic_cast<Integer*>(exp->expression);
integer = dynamic_cast<Integer*>(exp->expression);

if (!integer) {
std::cout << "expression is not Integer. got="
<< typeid(*expression).name() << std::endl;
return false;
if (!integer) {
std::cout << "expression is not Integer. got="
<< typeid(*expression).name() << std::endl;
return false;
}
}

if (std::stoi(integer->tokenLiteral()) != value) {
Expand Down Expand Up @@ -320,16 +324,6 @@ TEST(ParserSuite, TestIdentifierExpression) {
<< " statements instead of 1";
}

// if (!isCastableToDerivative(program->statements[0],
// typeid(ExpressionStatement))) {
// FAIL() << "Statement is not of type ExpressionStatement";
// }

// if (!isCastableToDerivative(program->statements[0], typeid(Identifier)))
// {
// FAIL() << "Statement is not of type Identifier";
// }

ASSERT_TRUE(
checkLiteral(program->statements[0], std::string("someIdentifier")));
}
Expand Down Expand Up @@ -627,4 +621,39 @@ TEST(ParserSuite, TestFunction) {
FAIL() << "Couldn't properly parse Infix expression nested in "
"ExpressionStatement";
}
}

TEST(ParserSuite, TestInvocation) {
std::string input = "multiply(1, 1 + 2, 1 * 2);";

Lexer l(input);
Parser p(l);
Program* program = p.parseProgram();

if (!p.getErrors().empty()) {
// logParserErrors(p.getErrors());
FAIL() << "There are errors after parsing invocation";
}

if (program->statements.size() != 1) {
FAIL() << "program.Statements does not contain 1 statement. got="
<< program->statements.size();
}

ExpressionStatement* stmt =
dynamic_cast<ExpressionStatement*>(program->statements[0]);

if (!stmt) {
FAIL() << "program.Statements[0] is not ExpressionStatement. got="
<< typeid(program->statements[0]).name();
}

Invocation* exp = dynamic_cast<Invocation*>(stmt->expression);

if (!exp) {
FAIL() << "exp is not Invocation. got="
<< typeid(stmt->expression).name();
}
EXPECT_EQ(exp->arguments.size(), 3);
EXPECT_TRUE(checkLiteral((Statement*)exp->arguments[0], 1));
}

0 comments on commit b361310

Please sign in to comment.