From 6ba49b30cf1e33fb0dd6782a404ec34b7964cb59 Mon Sep 17 00:00:00 2001 From: Martin Dobrev Date: Tue, 24 Nov 2020 18:06:26 +0200 Subject: 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 * Add implement byte code generation for break/continue in for/while. --- JSImpl/src/ByteCodeGenerator.cpp | 119 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'JSImpl/src/ByteCodeGenerator.cpp') 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()); }; + void OpenContinueScope() { m_ContinueScopeStack.push(IPLVector()); }; + void CloseBreakScope(size_t addr); + void CloseContinueScope(size_t addr); + void PushBreak(); + void PushContinue(); private: IPLVector m_RegisterTable; IPLVector m_Code; IPLVector m_Source; + IPLStack> m_BreakScopeStack; + IPLStack> m_ContinueScopeStack; + IPLStack 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) { -- cgit v1.3.1-23-gd82d