#include "Lexer.h" #include "Parser.h" #include "ASTPrinter.h" #include "ASTInterpreter.h" #include #define LOG(msg) std::cout << msg << std::endl #define EXECUTE_TEST(test) std::cout << #test << " "; test(); #define CHECK(cond) if (cond) {LOG("PASS");} else {LOG(#cond " FAIL");} // Lexer Tests void TestLess() { IPLVector tokens; Tokenize("<", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::Less); } void TestNumber() { IPLVector tokens; Tokenize("213434.24", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::Number && tokens[0].Number == 213434.24); } void TestNumberStartWithNine() { IPLVector tokens; Tokenize("999", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::Number && tokens[0].Number == 999); } void TestNumberStartWithZero() { IPLVector tokens; Tokenize("0999", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::Number && tokens[0].Number == 999); } void TestSpaceNewLineSpace() { IPLVector tokens; Tokenize(" \n var a = 4; ", tokens); CHECK(tokens.size() == 6 && tokens[0].Type == TokenType::Var && tokens[1].Type == TokenType::Identifier && tokens[2].Type == TokenType::Equal && tokens[3].Type == TokenType::Number && tokens[4].Type == TokenType::Semicolon); } void TestString() { IPLVector tokens; Tokenize("\"alabala\"", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::String && tokens[0].Lexeme == "\"alabala\""); } void TestStringSingleQuotedStrings() { IPLVector tokens; Tokenize("'alabala'", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::String && tokens[0].Lexeme == "'alabala'"); } void TestKeyWord() { IPLVector tokens; Tokenize("for", tokens); CHECK(tokens.size() == 2 && tokens[0].Type == TokenType::For); } void TestVariableDeclaration() { IPLVector tokens; Tokenize("var pesho = 10", tokens); CHECK(tokens.size() == 5 && tokens[0].Type == TokenType::Var && tokens[1].Type == TokenType::Identifier && tokens[2].Type == TokenType::Equal && tokens[3].Type == TokenType::Number && tokens[4].Type == TokenType::Eof); } void TestStringError() { IPLVector tokens; const auto& res = Tokenize("\" aaaa", tokens); CHECK(!res.IsSuccessful && res.Error.Row == 0 && res.Error.Column == 6); } void TestWhiteSpaceTokens() { IPLVector tokens; const auto& res = Tokenize(" 1\n2 abc\n \n", tokens, { true, false }); CHECK(res.IsSuccessful && tokens.size() == 8 && tokens[0].Type == TokenType::Whitespace && tokens[0].Lexeme == " " && tokens[1].Type == TokenType::Number && tokens[1].Number == 1 && tokens[2].Type == TokenType::Whitespace && tokens[2].Lexeme == "\n" && tokens[3].Type == TokenType::Number && tokens[3].Number == 2 && tokens[4].Type == TokenType::Whitespace && tokens[4].Lexeme == " " && tokens[5].Type == TokenType::Identifier && tokens[5].Lexeme == "abc" && tokens[6].Type == TokenType::Whitespace && tokens[6].Lexeme == "\n \n" && tokens[7].Type == TokenType::Eof); } void TestSimpleComment() { IPLVector tokens; const auto& res = Tokenize("//comment", tokens, { false, true }); CHECK(res.IsSuccessful && tokens.size() == 2 && tokens[0].Type == TokenType::Comment && tokens[0].Lexeme == "//comment" && tokens[1].Type == TokenType::Eof); } void TestSimpleMultiLineComment() { IPLVector tokens; const auto& res = Tokenize("/*comment\ncomment*/", tokens, { false, true }); CHECK(res.IsSuccessful && tokens.size() == 2 && tokens[0].Type == TokenType::Comment && tokens[0].Lexeme == "/*comment\ncomment*/" && tokens[1].Type == TokenType::Eof); } void TestConsecutiveMultiLineComment() { IPLVector tokens; const auto& res = Tokenize("/*comment1\ncomment1*//*comment2\ncomment2*/", tokens, { false, true }); CHECK(res.IsSuccessful && tokens.size() == 3 && tokens[0].Type == TokenType::Comment && tokens[0].Lexeme == "/*comment1\ncomment1*/" && tokens[1].Type == TokenType::Comment && tokens[1].Lexeme == "/*comment2\ncomment2*/" && tokens[2].Type == TokenType::Eof); } void TestConsecutiveMultiLineCommentWithSpace() { IPLVector tokens; const auto& res = Tokenize("/*comment1\ncomment1*/\n\n\n/*comment2\ncomment2*/", tokens, { false, true }); CHECK(res.IsSuccessful && tokens.size() == 3 && tokens[0].Type == TokenType::Comment && tokens[0].Lexeme == "/*comment1\ncomment1*/" && tokens[1].Type == TokenType::Comment && tokens[1].Lexeme == "/*comment2\ncomment2*/" && tokens[2].Type == TokenType::Eof); } void TestConsecutiveMultiLineCommentWithSpaceWithTokens() { IPLVector tokens; const auto& res = Tokenize("//comment1\n/*comment2\ncomment2*/\n\n\n/*comment3\ncomment3*/", tokens, { true, true }); CHECK(res.IsSuccessful && tokens.size() == 6 && tokens[0].Type == TokenType::Comment && tokens[0].Lexeme == "//comment1" && tokens[1].Type == TokenType::Whitespace && tokens[1].Lexeme == "\n" && tokens[2].Type == TokenType::Comment && tokens[2].Lexeme == "/*comment2\ncomment2*/" && tokens[3].Type == TokenType::Whitespace && tokens[3].Lexeme == "\n\n\n" && tokens[4].Type == TokenType::Comment && tokens[4].Lexeme == "/*comment3\ncomment3*/" && tokens[5].Type == TokenType::Eof); } void TestCommentError() { IPLVector tokens; const auto& res = Tokenize(" aa\n /*", tokens); CHECK(!res.IsSuccessful && res.Error.Row == 1 && res.Error.Column == 3); } // Parser Tests void TestParseUnaryExpr() { IPLVector tokens; Tokenize("function pesho() { var a = 0; return a; }", tokens); // TODO make actual test :D auto expr = Parse(tokens); ASTPrinter p(std::cout); expr->Accept(p); } void RunParseCalc() { IPLVector tokens; //Tokenize("var a = 0; var b = a + 123;a+b;", tokens); Tokenize("123 + 321", tokens); // TODO make actual test :D auto expr = Parse(tokens); ASTPrinter p(std::cout); expr->Accept(p); ASTInterpreter i; std::cout << "Running" << std::endl; auto result = i.Run(expr.get()); std::cout << "Stack after run, top to bottom:" << std::endl; while (!result.empty()) { std::cout << result.top() << std::endl; result.pop(); } } void TestHexNumber() { IPLVector tokens; const auto& res = Tokenize("0x10", tokens); CHECK(res.IsSuccessful && tokens[0].Type == TokenType::Number && tokens[0].Number == 16); } void TestScientificNotationNumber() { IPLVector tokens; const auto& res = Tokenize("1e2", tokens); CHECK(res.IsSuccessful && tokens[0].Type == TokenType::Number && tokens[0].Number == 100); } int main() { EXECUTE_TEST(TestLess); EXECUTE_TEST(TestNumber); EXECUTE_TEST(TestNumberStartWithNine); EXECUTE_TEST(TestNumberStartWithZero); EXECUTE_TEST(TestString); EXECUTE_TEST(TestSpaceNewLineSpace); EXECUTE_TEST(TestStringSingleQuotedStrings); EXECUTE_TEST(TestKeyWord); EXECUTE_TEST(TestVariableDeclaration); EXECUTE_TEST(TestWhiteSpaceTokens); EXECUTE_TEST(TestSimpleComment); EXECUTE_TEST(TestSimpleMultiLineComment); EXECUTE_TEST(TestConsecutiveMultiLineComment); EXECUTE_TEST(TestConsecutiveMultiLineCommentWithSpace); EXECUTE_TEST(TestConsecutiveMultiLineCommentWithSpaceWithTokens); EXECUTE_TEST(TestCommentError); EXECUTE_TEST(TestHexNumber); EXECUTE_TEST(TestScientificNotationNumber); //TestParseUnaryExpr(); //RunParseCalc(); #if defined(_WIN32) std::system("pause"); #endif return 0; }