From 4e883334a14ff22f12765204d6bf223d07c0298f Mon Sep 17 00:00:00 2001 From: Martin Dobrev Date: Sat, 21 Nov 2020 14:47:49 +0200 Subject: Implement byte code generation for object literals. --- JSImpl/src/ByteCodeGenerator.cpp | 62 +++++++++++++++++++++++++++------- JSImpl/test/CodeGenerationTests.cpp | 66 +++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 11 deletions(-) (limited to 'JSImpl') diff --git a/JSImpl/src/ByteCodeGenerator.cpp b/JSImpl/src/ByteCodeGenerator.cpp index 49e734b..31a80bd 100644 --- a/JSImpl/src/ByteCodeGenerator.cpp +++ b/JSImpl/src/ByteCodeGenerator.cpp @@ -23,6 +23,9 @@ public: virtual void Visit(IfStatement* e) override; virtual void Visit(ForStatement* 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; IPLString GetCode(); unsigned ResolveRegisterName(IPLString& name); @@ -447,6 +450,41 @@ void ByteCodeGenerator::Visit(UnaryExpression* e) } } +void ByteCodeGenerator::Visit(LiteralField* e) +{ + e->GetValue()->Accept(*this); + e->GetIdentifier()->Accept(*this); +} + +void ByteCodeGenerator::Visit(LiteralObject* e) +{ + auto initialSize = m_RegisterStack.size(); + auto objReg = CreateRegister(); + + for (const auto& field : e->GetValues()) + { + field->Accept(*this); + auto fieldName = m_RegisterStack.top(); + m_RegisterStack.pop(); + + auto fieldNameReg = CreateRegister(); + PushInstruction(Instruction::Type::STRING, fieldNameReg, fieldName); + + auto valueReg = m_RegisterStack.top(); + m_RegisterStack.pop(); + PushInstruction(Instruction::Type::SET, objReg, fieldNameReg, valueReg); + } + assert(m_RegisterStack.size() == initialSize); + m_RegisterStack.push(objReg); +} + +void ByteCodeGenerator::Visit(LiteralString* e) +{ + auto stringReg = CreateRegister(); + PushInstruction(Instruction::Type::STRING, stringReg, e->GetValue()); + m_RegisterStack.push(stringReg); +} + unsigned ByteCodeGenerator::ResolveRegisterName(IPLString& name) { auto it = std::find_if(m_RegisterTable.begin(), m_RegisterTable.end(), [&](IPLString& current) { @@ -592,20 +630,22 @@ IPLString ByteCodeGenerator::GetCode() NOT_IMPLEMENTED; break; case ByteCodeGenerator::Instruction::GET: - result += "get"; - NOT_IMPLEMENTED; + result += "get r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; break; case ByteCodeGenerator::Instruction::SET: - result += "set"; - NOT_IMPLEMENTED; + result += "set r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; break; case ByteCodeGenerator::Instruction::INC: - result += "inc"; - NOT_IMPLEMENTED; + result += "inc r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(i.Values.Int[0]) + '\n'; break; case ByteCodeGenerator::Instruction::DEC: - result += "dec"; - NOT_IMPLEMENTED; + result += "dec r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(i.Values.Int[0]) + '\n'; break; case ByteCodeGenerator::Instruction::AND: result += "and r" + std::to_string(ResolveRegisterName(i.Args[0])) @@ -623,7 +663,8 @@ IPLString ByteCodeGenerator::GetCode() + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; break; case ByteCodeGenerator::Instruction::NOT: - result += "not"; + result += "not r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + '\n'; NOT_IMPLEMENTED; break; case ByteCodeGenerator::Instruction::THROW: @@ -638,8 +679,7 @@ IPLString ByteCodeGenerator::GetCode() result += "const r" + std::to_string(ResolveRegisterName(i.Args[0])) + " " + std::to_string(i.Values.Double[0]) + '\n'; break; case ByteCodeGenerator::Instruction::STRING: - result += "string"; - NOT_IMPLEMENTED; + result += "string r" + std::to_string(ResolveRegisterName(i.Args[0])) + " " + i.Args[1] + '\n'; break; case ByteCodeGenerator::Instruction::HALT: result += "halt\n"; diff --git a/JSImpl/test/CodeGenerationTests.cpp b/JSImpl/test/CodeGenerationTests.cpp index a6ebc6e..4a8ebbe 100644 --- a/JSImpl/test/CodeGenerationTests.cpp +++ b/JSImpl/test/CodeGenerationTests.cpp @@ -168,5 +168,71 @@ TEST(CodeGen, SimpleFor) "14: pop 9\n" "15: halt\n"; + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, EmptyObject) +{ + IPLString source = "var a = {}"; + IPLVector tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 2\n" + "1: mov r0 r1\n" + "2: pop 2\n" + "3: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + + +TEST(CodeGen, ObjectWithFlatProps) +{ + IPLString source = "var a = {a: 5, n: \"pesho\"}"; + IPLVector 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 r2 5.000000\n" + "2: string r3 a\n" + "3: set r1 r3 r2\n" + "4: string r4 pesho\n" + "5: string r5 n\n" + "6: set r1 r5 r4\n" + "7: mov r0 r1\n" + "8: pop 6\n" + "9: halt\n"; + + ASSERT_TRUE(asmb == expected); +} + +TEST(CodeGen, NestedObjects) +{ + IPLString source = "var a = {a: 5, n: \"pesho\", obj1: {a: 4, b: 5}}\n"; + IPLVector tokens = Tokenize(source.c_str()).tokens; + auto ast = Parse(tokens); + auto asmb = GenerateByteCode(ast, source, + ByteCodeGeneratorOptions(ByteCodeGeneratorOptions::OptimizationsType::None, false)); + IPLString expected = "0: push 12\n" + "1: const r2 5.000000\n" + "2: string r3 a\n" + "3: set r1 r3 r2\n" + "4: string r4 pesho\n" + "5: string r5 n\n" + "6: set r1 r5 r4\n" + "7: const r7 4.000000\n" + "8: string r8 a\n" + "9: set r6 r8 r7\n" + "10: const r9 5.000000\n" + "11: string r10 b\n" + "12: set r6 r10 r9\n" + "13: string r11 obj1\n" + "14: set r1 r11 r6\n" + "15: mov r0 r1\n" + "16: pop 12\n" + "17: halt\n"; + ASSERT_TRUE(asmb == expected); } \ No newline at end of file -- cgit v1.3.1-23-gd82d