diff options
| Commit | 6ba49b30cf1e33fb0dd6782a404ec34b7964cb59 (patch) | |
|---|---|---|
| Author | 2020-11-24 18:06:26 +0200 | |
| Committer | 2020-11-24 18:06:26 +0200 | |
| Files | a89b314c4d0b942d2350b9adbd741d6fa3375bfb /JSImpl | |
| IPL-6ba49b30cf1e33fb0dd6782a404ec34b7964cb59.tar IPL-6ba49b30cf1e33fb0dd6782a404ec34b7964cb59.tar.gz IPL-6ba49b30cf1e33fb0dd6782a404ec34b7964cb59.zip | ||
| Parent | 4e883334a14ff22f12765204d6bf223d07c0298f (diff) | |
Feature/object getters (#101)
* Add member access expression.
* Implement property getters.
* Add test for property getters.
* Add test for property setter.
* Implement while and do-while
Signed-off-by: Martin Dobrev <martindobrev0@gmail.com>
* Add implement byte code generation for break/continue in for/while.
10 files changed, 463 insertions, 38 deletions
| -rw-r--r-- | JSImpl/src/ASTInterpreter.cpp | 9 | ||||
| -rw-r--r-- | JSImpl/src/ASTInterpreter.h | 2 | ||||
| -rw-r--r-- | JSImpl/src/ASTPrinter.cpp | 7 | ||||
| -rw-r--r-- | JSImpl/src/ByteCodeGenerator.cpp | 119 | ||||
| -rw-r--r-- | JSImpl/src/ExpressionDefinitions.h | 14 | ||||
| -rw-r--r-- | JSImpl/src/ExpressionVisitor.h | 6 | ||||
| -rw-r--r-- | JSImpl/src/ExpressionsFwd.h | 5 | ||||
| -rw-r--r-- | JSImpl/src/Parser.cpp | 47 | ||||
| -rw-r--r-- | JSImpl/src/main.cpp | 20 | ||||
| -rw-r--r-- | JSImpl/test/CodeGenerationTests.cpp | 272 |
diff --git a/JSImpl/src/ASTInterpreter.cpp b/JSImpl/src/ASTInterpreter.cpp index f550da9..f56706a 100644 --- a/JSImpl/src/ASTInterpreter.cpp +++ b/JSImpl/src/ASTInterpreter.cpp @@ -240,6 +240,7 @@ public: } virtual void Visit(IdentifierExpression* e) override { m_LValue = m_Interpreter->ModifyVariable(e->GetName()); } + virtual void Visit(Call* e) override { e->GetObjectOrCall()->Accept(*this); } ASTInterpreter* m_Interpreter; ASTInterpreter::ValuePtr m_LValue; @@ -565,9 +566,13 @@ void ASTInterpreter::Visit(EmptyExpression* e) { NOT_IMPLEMENTED; } -void ASTInterpreter::Visit(CallExpression* e) +void ASTInterpreter::Visit(Call* e) { - NOT_IMPLEMENTED; + e->GetObjectOrCall()->Accept(*this); + if (e->GetMember()) + { + e->GetMember()->Accept(*this); + } } void ASTInterpreter::Print(Printer& p) diff --git a/JSImpl/src/ASTInterpreter.h b/JSImpl/src/ASTInterpreter.h index cce6108..0c2c776 100644 --- a/JSImpl/src/ASTInterpreter.h +++ b/JSImpl/src/ASTInterpreter.h @@ -38,7 +38,7 @@ public: virtual void Visit(FunctionDeclaration* e) override; virtual void Visit(TopStatements* e) override; virtual void Visit(EmptyExpression* e) override; - virtual void Visit(CallExpression* e) override; + virtual void Visit(Call* e) override; ValuePtr& ModifyVariable(const IPLString& name); bool HasVariable(const IPLString& name); diff --git a/JSImpl/src/ASTPrinter.cpp b/JSImpl/src/ASTPrinter.cpp index 8c5783f..4a05510 100644 --- a/JSImpl/src/ASTPrinter.cpp +++ b/JSImpl/src/ASTPrinter.cpp @@ -126,11 +126,14 @@ public: virtual void Visit(CaseStatement *) override; virtual void Visit(WhileStatement* e) override; virtual void Visit(ForStatement* e) override; + virtual void Visit(Break* e) override; + virtual void Visit(Continue* e) override; virtual void Visit(FunctionDeclaration* e) override; virtual void Visit(TopStatements* e) override; virtual void Visit(EmptyExpression* e) override; - virtual void Visit(CallExpression* e) override; - + virtual void Visit(Call* e) override; + virtual void Visit(MemberAccess* e) override; + void Print( const char* name, const ExpressionPtr& expr, bool isLast); void Print( const char* name, const IPLVector<ExpressionPtr>& list, bool isLast); void Print( const char* name, const IPLVector<IPLString>& list, bool isLast); diff --git a/JSImpl/src/ByteCodeGenerator.cpp b/JSImpl/src/ByteCodeGenerator.cpp index 31a80bd..4d5cb09 100644 --- a/JSImpl/src/ByteCodeGenerator.cpp +++ b/JSImpl/src/ByteCodeGenerator.cpp @@ -22,10 +22,15 @@ public: virtual void Visit(EmptyExpression* e) override { (void)e; }
virtual void Visit(IfStatement* e) override;
virtual void Visit(ForStatement* e) override;
+ virtual void Visit(WhileStatement* e) override;
+ virtual void Visit(Break* e) override;
+ virtual void Visit(Continue* e) override;
virtual void Visit(UnaryExpression* e) override;
virtual void Visit(LiteralField* e) override;
virtual void Visit(LiteralObject* e) override;
virtual void Visit(LiteralString* e) override;
+ virtual void Visit(MemberAccess* e) override;
+ virtual void Visit(Call* e) override;
IPLString GetCode();
unsigned ResolveRegisterName(IPLString& name);
@@ -101,16 +106,62 @@ private: void PushConst(double c);
IPLString CreateRegister();
bool CheckOpCode(int opcode) { return opcode >= Instruction::Type::FIRST && opcode <= Instruction::Type::LAST; }
+
+ void OpenBreakScope() { m_BreakScopeStack.push(IPLVector<size_t>()); };
+ void OpenContinueScope() { m_ContinueScopeStack.push(IPLVector<size_t>()); };
+ void CloseBreakScope(size_t addr);
+ void CloseContinueScope(size_t addr);
+ void PushBreak();
+ void PushContinue();
private:
IPLVector<IPLString> m_RegisterTable;
IPLVector<Instruction> m_Code;
IPLVector<IPLString> m_Source;
+ IPLStack<IPLVector<size_t>> m_BreakScopeStack;
+ IPLStack<IPLVector<size_t>> m_ContinueScopeStack;
+
IPLStack<IPLString> m_RegisterStack;
IPLString m_OutputCode;
ByteCodeGeneratorOptions m_Options;
};
+void ByteCodeGenerator::PushBreak()
+{
+ assert(!m_BreakScopeStack.empty());
+ auto addr = PushInstruction(Instruction::Type::JMP, 0);
+ m_BreakScopeStack.top().push_back(addr);
+}
+
+void ByteCodeGenerator::PushContinue()
+{
+ assert(!m_ContinueScopeStack.empty());
+ auto addr = PushInstruction(Instruction::Type::JMP, 0);
+ m_ContinueScopeStack.top().push_back(addr);
+}
+
+void ByteCodeGenerator::CloseBreakScope(size_t addr)
+{
+ auto currentScope = m_BreakScopeStack.top();
+ for (const auto& br : currentScope)
+ {
+ assert(m_Code[br].Descriptor == Instruction::Type::JMP);
+ m_Code[br].Values.Address[0] = addr;
+ }
+ m_BreakScopeStack.pop();
+};
+
+void ByteCodeGenerator::CloseContinueScope(size_t addr)
+{
+ auto currentScope = m_ContinueScopeStack.top();
+ for (const auto& br : currentScope)
+ {
+ assert(m_Code[br].Descriptor == Instruction::Type::JMP);
+ m_Code[br].Values.Address[0] = addr;
+ }
+ m_ContinueScopeStack.pop();
+};
+
size_t ByteCodeGenerator::PushInstruction(Instruction::Type opcode, const IPLString& arg0, const IPLString& arg1, const IPLString& arg2)
{
assert(CheckOpCode(opcode));
@@ -337,15 +388,60 @@ void ByteCodeGenerator::Visit(IfStatement* e) void ByteCodeGenerator::Visit(ForStatement* e)
{
+ OpenBreakScope();
+ OpenContinueScope();
+
e->GetInitialization()->Accept(*this);
auto compareAddress = m_Code.size();
e->GetCondition()->Accept(*this);
auto endAddress = PushInstruction(Instruction::Type::JMPF, m_RegisterStack.top(), (size_t)0);
m_RegisterStack.pop();
e->GetBody()->Accept(*this);
+
+ auto iterationAddress = m_Code.size();
e->GetIteration()->Accept(*this);
+
PushInstruction(Instruction::Type::JMP, compareAddress);
m_Code[endAddress].Values.Address[0] = m_Code.size();
+
+ CloseBreakScope(m_Code.size());
+ CloseContinueScope(iterationAddress);
+}
+
+void ByteCodeGenerator::Visit(WhileStatement* e)
+{
+ auto startAddress = m_Code.size();
+
+ OpenBreakScope();
+ OpenContinueScope();
+
+ if (e->GetDoWhile())
+ {
+ e->GetBody()->Accept(*this);
+ e->GetCondition()->Accept(*this);
+ PushInstruction(Instruction::Type::JMPT, m_RegisterStack.top(), startAddress);
+ }
+ else {
+ e->GetCondition()->Accept(*this);
+ auto endAddress = PushInstruction(Instruction::Type::JMPF, m_RegisterStack.top(), (size_t)0);
+ m_RegisterStack.pop();
+ e->GetBody()->Accept(*this);
+ PushInstruction(Instruction::Type::JMP, startAddress);
+ m_Code[endAddress].Values.Address[0] = m_Code.size();
+ }
+
+ CloseBreakScope(m_Code.size());
+ CloseContinueScope(startAddress);
+}
+
+void ByteCodeGenerator::Visit(Break*)
+{
+ PushBreak();
+}
+
+void ByteCodeGenerator::Visit(Continue*)
+{
+ PushContinue();
}
void ByteCodeGenerator::Visit(IdentifierExpression* e)
@@ -485,6 +581,29 @@ void ByteCodeGenerator::Visit(LiteralString* e) m_RegisterStack.push(stringReg);
}
+void ByteCodeGenerator::Visit(Call* e)
+{
+ e->GetObjectOrCall()->Accept(*this);
+ if (e->GetMember())
+ {
+ e->GetMember()->Accept(*this);
+ }
+}
+
+void ByteCodeGenerator::Visit(MemberAccess* e)
+{
+ auto objectReg = m_RegisterStack.top();
+ m_RegisterStack.pop();
+
+ auto identifierNameReg = CreateRegister();
+ PushInstruction(Instruction::Type::STRING, identifierNameReg, e->GetName());
+
+ auto resultReg = CreateRegister();
+ PushInstruction(Instruction::Type::GET, objectReg, identifierNameReg, resultReg);
+
+ m_RegisterStack.push(resultReg);
+}
+
unsigned ByteCodeGenerator::ResolveRegisterName(IPLString& name)
{
auto it = std::find_if(m_RegisterTable.begin(), m_RegisterTable.end(), [&](IPLString& current) {
diff --git a/JSImpl/src/ExpressionDefinitions.h b/JSImpl/src/ExpressionDefinitions.h index 1fad948..33f13b3 100644 --- a/JSImpl/src/ExpressionDefinitions.h +++ b/JSImpl/src/ExpressionDefinitions.h @@ -79,8 +79,13 @@ MACRO(IPLVector<ExpressionPtr>, Values, IPLVector<ExpressionPtr>()) #define CALL_EXPRESSION_MEMBERS(MACRO)\ - MACRO(ExpressionPtr, Identifier, ExpressionPtr())\ - MACRO(ExpressionPtr, Arguments, ExpressionPtr()) + MACRO(ExpressionPtr, ObjectOrCall, ExpressionPtr())\ + MACRO(ExpressionPtr, Member, ExpressionPtr()) + +#define MEMBER_ACCESS_EXPRESSION_MEMBERS(MACRO)\ + MACRO(IPLString, Name, "") + +#define MEMBER_NO_MEMBERS(MACRO) #define EXPRESSION_DEFINITION_ITERATOR(MACRO)\ MACRO(LiteralNull, NO_MEMBERS)\ @@ -105,4 +110,7 @@ MACRO(FunctionDeclaration, FUNCTION_EXPRESSION_MEMBERS)\ MACRO(TopStatements, TOP_EXPRESSION_MEMBERS)\ MACRO(EmptyExpression, NO_MEMBERS)\ - MACRO(CallExpression, CALL_EXPRESSION_MEMBERS) + MACRO(Call, CALL_EXPRESSION_MEMBERS)\ + MACRO(MemberAccess, MEMBER_ACCESS_EXPRESSION_MEMBERS)\ + MACRO(Break, MEMBER_NO_MEMBERS)\ + MACRO(Continue, MEMBER_NO_MEMBERS) diff --git a/JSImpl/src/ExpressionVisitor.h b/JSImpl/src/ExpressionVisitor.h index a44f581..8fbab7d 100644 --- a/JSImpl/src/ExpressionVisitor.h +++ b/JSImpl/src/ExpressionVisitor.h @@ -26,10 +26,14 @@ public: virtual void Visit(CaseStatement *e) { (void)e; NOT_IMPLEMENTED; } virtual void Visit(WhileStatement* e) { (void)e; NOT_IMPLEMENTED; } virtual void Visit(ForStatement* e) { (void)e; NOT_IMPLEMENTED; } + virtual void Visit(Break* e) { (void)e; NOT_IMPLEMENTED; } + virtual void Visit(Continue* e) { (void)e; NOT_IMPLEMENTED; } virtual void Visit(FunctionDeclaration* e) { (void)e; NOT_IMPLEMENTED; } virtual void Visit(TopStatements* e) { (void)e; NOT_IMPLEMENTED; } virtual void Visit(EmptyExpression* e) { (void)e; NOT_IMPLEMENTED; } - virtual void Visit(CallExpression* e) { (void)e; NOT_IMPLEMENTED; } + virtual void Visit(Call* e) { (void)e; NOT_IMPLEMENTED; } + virtual void Visit(MemberAccess* e) { (void)e; NOT_IMPLEMENTED; } + virtual void Visit(Expression* e) { (void)e; NOT_IMPLEMENTED; } // Unkown case };
\ No newline at end of file diff --git a/JSImpl/src/ExpressionsFwd.h b/JSImpl/src/ExpressionsFwd.h index 38f9330..753167d 100644 --- a/JSImpl/src/ExpressionsFwd.h +++ b/JSImpl/src/ExpressionsFwd.h @@ -25,6 +25,9 @@ class ForStatement; class FunctionDeclaration; class TopStatements; class EmptyExpression; -class CallExpression; +class Call; +class MemberAccess; +class Break; +class Continue; using ExpressionPtr = IPLSharedPtr<Expression>; diff --git a/JSImpl/src/Parser.cpp b/JSImpl/src/Parser.cpp index bc4920f..4bc97ce 100644 --- a/JSImpl/src/Parser.cpp +++ b/JSImpl/src/Parser.cpp @@ -23,6 +23,7 @@ private: bool MatchOneOf(IPLVector<TokenType> types); bool Match(TokenType type); + bool Peek(TokenType type); ExpressionPtr RegularExpression(); ExpressionPtr ParenthesizedExpression(); ExpressionPtr PrimaryExpression(NormalType a); @@ -125,6 +126,11 @@ bool Parser::Match(TokenType type) return false; } +bool Parser::Peek(TokenType type) +{ + return type == m_Tokens[m_Current].Type; +} + ExpressionPtr Parser::RegularExpression() { return nullptr; @@ -383,23 +389,32 @@ ExpressionPtr Parser::LeftSideExpression(NormalType a) ExpressionPtr Parser::CallExpression(NormalType a) { ExpressionPtr result; + auto ss = Snapshot(); - if (result = PrimaryExpression(a)) + if (auto pe = PrimaryExpression(a)) { - return result; + result = IPLMakeSharePtr<Call>(pe); } - Restore(ss); - if (result = FullNewExpression()) + else { - return result; + Restore(ss); } - - if (result = CallExpressionHelper(a)) + if (auto fne = FullNewExpression()) { - return result; + result = IPLMakeSharePtr<::Call>(fne); } - // TODO error - return nullptr; + + ExpressionPtr right; + do + { + right = CallExpressionHelper(a); + if (right) + { + result = IPLMakeSharePtr<::Call>(result, right); + } + } while (right); + + return result; } ExpressionPtr Parser::CallExpressionHelper(NormalType a) @@ -420,9 +435,7 @@ ExpressionPtr Parser::CallExpressionHelper(NormalType a) { if (Match(TokenType::Identifier)) { - auto next = CallExpressionHelper(a); - // return meaningfull expr - return nullptr; + return IPLMakeSharePtr<MemberAccess>(Prev().Lexeme); } // TODO error return nullptr; @@ -991,10 +1004,8 @@ ExpressionPtr Parser::ContinueStatement() { if (Match(TokenType::Continue)) { - auto type = TokenType::Continue; ExpressionPtr expr = OptionalLabel(); - bool suffix = true; - return IPLMakeSharePtr<UnaryExpression>(expr, type, suffix); + return IPLMakeSharePtr<Continue>(); } return nullptr; } @@ -1003,10 +1014,8 @@ ExpressionPtr Parser::BreakStatement() { if (Match(TokenType::Break)) { - auto type = TokenType::Break; ExpressionPtr expr = OptionalLabel(); - bool suffix = true; - return IPLMakeSharePtr<UnaryExpression>(expr, type, suffix); + return IPLMakeSharePtr<Break>(); } return nullptr; } diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp index 06421a7..aee465d 100644 --- a/JSImpl/src/main.cpp +++ b/JSImpl/src/main.cpp @@ -76,15 +76,16 @@ void Generate() { //Tokenize("var a = 0; var b = a + 123;a+b;", tokens); /*Tokenize("var a; if(a < 4) { a = 8; if(a < 7) {var b = 4;}} else { a = 2} ", tokens);*/ - IPLString source = "var i = 0; \n" - "for (var j = 0; j < 10; j++)\n" - "{\n" - " i = i + j;\n" - "}"; + //IPLString source = "var i = 0; \n" + // "for (var j = 0; j < 10; j++)\n" + // "{\n" + // " i = i + j;\n" + // "}"; + IPLString source = "var a = 5; do{ a--; if(a == 4) continue; }while(a != 0)\n"; auto tokens = Tokenize(source.c_str()).tokens; auto asmb = GenerateByteCode(Parse(tokens), source, - ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, true)); + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); //sets the color to intense red on blue background #if defined(_WIN32) @@ -231,13 +232,16 @@ private: int main(int argc, char* argv[]) { + (void)argv; + (void)argc; // You can try => // Working dir: $(ProjectDir) // Command arguments: --input ./../examples/code.js --output ./../examples/some.ast --ast - CammandLineApp cmd; - cmd.RunAsCommandLine(argc, argv); + //CammandLineApp cmd; + //cmd.RunAsCommandLine(argc, argv); //auto r = Tokenize("a#4", {true ,true}); //RunParseCalc(); + Generate(); #if defined(_WIN32) //std::system("pause"); #endif diff --git a/JSImpl/test/CodeGenerationTests.cpp b/JSImpl/test/CodeGenerationTests.cpp index 4a8ebbe..dd13855 100644 --- a/JSImpl/test/CodeGenerationTests.cpp +++ b/JSImpl/test/CodeGenerationTests.cpp @@ -235,4 +235,274 @@ TEST(CodeGen, NestedObjects) "17: halt\n"; ASSERT_TRUE(asmb == expected); -}
\ No newline at end of file +} + + +TEST(CodeGen, ObjectGetters) +{ + IPLString source = "var a = {c: 3}; var k = a.c.t;\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 9\n" + "1: const r2 3.000000\n" + "2: string r3 c\n" + "3: set r1 r3 r2\n" + "4: mov r0 r1\n" + "5: string r5 c\n" + "6: get r0 r5 r6\n" + "7: string r7 t\n" + "8: get r6 r7 r8\n" + "9: mov r4 r8\n" + "10: pop 9\n" + "11: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, ObjectSetter) +{ + IPLString source = "var a = {c: 3}; a.c = 5;\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 7\n" + "1: const r2 3.000000\n" + "2: string r3 c\n" + "3: set r1 r3 r2\n" + "4: mov r0 r1\n" + "5: const r4 5.000000\n" + "6: string r5 c\n" + "7: get r0 r5 r6\n" + "8: mov r6 r4\n" + "9: pop 7\n" + "10: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + + +TEST(CodeGen, BasicDoWhile) +{ + IPLString source = "var a = 5; do{ a--; }while(a != 0)\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 6\n" + "1: const r1 5.000000\n" + "2: mov r0 r1\n" + "3: const r2 1.000000\n" + "4: mov r3 r0\n" + "5: sub r0 r0 r2\n" + "6: const r4 0.000000\n" + "7: neq r5 r0 r4\n" + "8: jmpt r5 3\n" + "9: pop 6\n" + "10: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + + +TEST(CodeGen, BasicWhile) +{ + IPLString source = "var a = 5; while(a != 0){ a--; }\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 6\n" + "1: const r1 5.000000\n" + "2: mov r0 r1\n" + "3: const r2 0.000000\n" + "4: neq r3 r0 r2\n" + "5: jmpf r3 10\n" + "6: const r4 1.000000\n" + "7: mov r5 r0\n" + "8: sub r0 r0 r4\n" + "9: jmp 3\n" + "10: pop 6\n" + "11: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, ContinueDoWhile) +{ + IPLString source = "var a = 5;\n" + "do {\n" + " a--;\n" + " if(a == 4) continue;\n" + "}while(a != 0)\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 8\n" + "1: const r1 5.000000\n" + "2: mov r0 r1\n" + "3: const r2 1.000000\n" + "4: mov r3 r0\n" + "5: sub r0 r0 r2\n" + "6: const r4 4.000000\n" + "7: eq r5 r0 r4\n" + "8: jmpf r5 10\n" + "9: jmp 3\n" + "10: const r6 0.000000\n" + "11: neq r7 r0 r6\n" + "12: jmpt r7 3\n" + "13: pop 8\n" + "14: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, BreakDoWhile) +{ + IPLString source = "var a = 5;\n" + "do {\n" + " a--;\n" + " if(a == 4) break;\n" + "}while(a != 0)\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 8\n" + "1: const r1 5.000000\n" + "2: mov r0 r1\n" + "3: const r2 1.000000\n" + "4: mov r3 r0\n" + "5: sub r0 r0 r2\n" + "6: const r4 4.000000\n" + "7: eq r5 r0 r4\n" + "8: jmpf r5 10\n" + "9: jmp 13\n" + "10: const r6 0.000000\n" + "11: neq r7 r0 r6\n" + "12: jmpt r7 3\n" + "13: pop 8\n" + "14: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + + +TEST(CodeGen, BreakWhile) +{ + IPLString source = "var a = 5;\n" + "while(a != 0) {\n" + " a--;\n" + " if(a == 4) break;\n" + "}\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 8\n" + "1: const r1 5.000000\n" + "2: mov r0 r1\n" + "3: const r2 0.000000\n" + "4: neq r3 r0 r2\n" + "5: jmpf r3 14\n" + "6: const r4 1.000000\n" + "7: mov r5 r0\n" + "8: sub r0 r0 r4\n" + "9: const r6 4.000000\n" + "10: eq r7 r0 r6\n" + "11: jmpf r7 13\n" + "12: jmp 14\n" + "13: jmp 3\n" + "14: pop 8\n" + "15: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, ContinueWhile) +{ + IPLString source = "var a = 5;\n" + "while(a != 0) {\n" + " a--;\n" + " if(a == 4) continue;\n" + "}\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 8\n" + "1: const r1 5.000000\n" + "2: mov r0 r1\n" + "3: const r2 0.000000\n" + "4: neq r3 r0 r2\n" + "5: jmpf r3 14\n" + "6: const r4 1.000000\n" + "7: mov r5 r0\n" + "8: sub r0 r0 r4\n" + "9: const r6 4.000000\n" + "10: eq r7 r0 r6\n" + "11: jmpf r7 13\n" + "12: jmp 3\n" + "13: jmp 3\n" + "14: pop 8\n" + "15: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, ContinueFor) +{ + IPLString source = "for (var i = 0; i < 5; i++ ){ if(i == 1) continue; }\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 8\n" + "1: const r1 0.000000\n" + "2: mov r0 r1\n" + "3: const r2 5.000000\n" + "4: less r3 r0 r2\n" + "5: jmpf r3 14\n" + "6: const r4 1.000000\n" + "7: eq r5 r0 r4\n" + "8: jmpf r5 10\n" + "9: jmp 10\n" + "10: const r6 1.000000\n" + "11: mov r7 r0\n" + "12: add r0 r0 r6\n" + "13: jmp 3\n" + "14: pop 8\n" + "15: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, BreakFor) +{ + IPLString source = "for (var i = 0; i < 5; i++ ){ if(i == 1) break; }\n"; + IPLVector<Token> tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 8\n" + "1: const r1 0.000000\n" + "2: mov r0 r1\n" + "3: const r2 5.000000\n" + "4: less r3 r0 r2\n" + "5: jmpf r3 14\n" + "6: const r4 1.000000\n" + "7: eq r5 r0 r4\n" + "8: jmpf r5 10\n" + "9: jmp 14\n" + "10: const r6 1.000000\n" + "11: mov r7 r0\n" + "12: add r0 r0 r6\n" + "13: jmp 3\n" + "14: pop 8\n" + "15: halt\n"; + + ASSERT_TRUE(asmb == expected); +} |
