Skip to content
75 changes: 68 additions & 7 deletions JSImpl/src/ASTInterpreter.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#include "ASTInterpreter.h"
#include "Expression.h"
#include <iostream>
#include <limits>
#include <math.h>

#undef NOT_IMPLEMENTED
#define NOT_IMPLEMENTED (void)e; assert(0 && "not-implemented")

#define FLOAT_EQUALS(first, second) fabs(first - second) < std::numeric_limits<double>::epsilon()

struct LValueExtractor : public ExpressionVisitor
{
public:
Expand Down Expand Up @@ -70,6 +73,9 @@ struct StackScope
};

ASTInterpreter::ASTInterpreter()
: m_Fallthrough(false)
, m_Break(false)
, m_Continue(false)
{
// Allow globals
EnterScope();
Expand Down Expand Up @@ -101,6 +107,15 @@ bool ASTInterpreter::EvalToBool(const ExpressionPtr& e)
return result != 0.0;
}

bool ASTInterpreter::EvalIsEqual(const ExpressionPtr& e)
{
e->Accept(*this);
auto second = m_Evaluation.back();
m_Evaluation.pop_back();
auto first = m_Evaluation.back();
return FLOAT_EQUALS(first, second);
}

void ASTInterpreter::EnterScope()
{
m_Scopes.push(Scope{});
Expand Down Expand Up @@ -137,15 +152,20 @@ bool ASTInterpreter::HasVariable(const IPLString& name)
return m_Variables.find(name) != m_Variables.end();
}

bool ASTInterpreter::IsInSkipMode()
{
return m_Break || m_Continue;
}

void ASTInterpreter::Visit(LiteralNull* e) {
NOT_IMPLEMENTED;
NOT_IMPLEMENTED;
}

void ASTInterpreter::Visit(LiteralUndefined* e) {
NOT_IMPLEMENTED;
NOT_IMPLEMENTED;
}
void ASTInterpreter::Visit(LiteralString* e) {
NOT_IMPLEMENTED;
NOT_IMPLEMENTED;
}

void ASTInterpreter::Visit(LiteralObject* e)
Expand Down Expand Up @@ -198,10 +218,10 @@ void ASTInterpreter::Visit(BinaryExpression* e) {
m_Evaluation.push_back(right);
break;
case TokenType::EqualEqual:
m_Evaluation.push_back(fabs(left - right) < 0.0001);
m_Evaluation.push_back(FLOAT_EQUALS(left, right));
break;
case TokenType::BangEqual:
m_Evaluation.push_back(fabs(left - right) > 0.0001);
m_Evaluation.push_back(FLOAT_EQUALS(left, right));
break;
case TokenType::Equal:
{
Expand All @@ -216,6 +236,18 @@ void ASTInterpreter::Visit(BinaryExpression* e) {
}

void ASTInterpreter::Visit(UnaryExpression* e) {
switch (e->GetOperator())
{
case TokenType::Break:
m_Break = true;
return;
case TokenType::Continue:
m_Continue = true;
return;
default:
;
}

LValueExtractor extractor(this);
auto lvalue = extractor.Run(e->GetExpr().get());
if (e->GetSuffix())
Expand Down Expand Up @@ -278,19 +310,45 @@ void ASTInterpreter::Visit(IfStatement* e) {
}
}

void ASTInterpreter::Visit(SwitchStatement* e) { NOT_IMPLEMENTED;}
void ASTInterpreter::Visit(CaseStatement *e) { NOT_IMPLEMENTED;}
void ASTInterpreter::Visit(SwitchStatement* e)
{
VariableScope scope(this);
e->GetCondition()->Accept(*this);
for (const auto& stmt : e->GetCases())
stmt->Accept(*this);
RunExpression(e->GetDefaultCase());
m_Evaluation.pop_back();

m_Fallthrough = false;
m_Break = false;
}

void ASTInterpreter::Visit(CaseStatement *e)
{
if (m_Break)
return;

if (m_Fallthrough || EvalIsEqual(e->GetCondition()))
{
RunExpression(e->GetBody());
m_Fallthrough = true;
}
}

void ASTInterpreter::Visit(WhileStatement* e) {
VariableScope scope(this);
if (e->GetDoWhile()) {
VariableScope bodyScope(this);
RunExpression(e->GetBody());
m_Continue = false;
}
while (EvalToBool(e->GetCondition())) {
VariableScope bodyScope(this);
RunExpression(e->GetBody());
m_Continue = false;
}

m_Break = false;
}

void ASTInterpreter::Visit(ForStatement* e) {
Expand All @@ -305,12 +363,15 @@ void ASTInterpreter::Visit(ForStatement* e) {
{
VariableScope bodyScope(this);
RunExpression(e->GetBody());
m_Continue = false;
}
{
StackScope stackScope(this);
RunExpression(e->GetIteration());
}
}

m_Break = false;
}

void ASTInterpreter::Visit(FunctionDeclaration* e) { NOT_IMPLEMENTED;}
Expand Down
7 changes: 7 additions & 0 deletions JSImpl/src/ASTInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class ASTInterpreter : public ExpressionVisitor

ValueStack Run(Expression* program);

virtual bool IsInSkipMode() override;

virtual void Visit(LiteralNull* e) override;
virtual void Visit(LiteralUndefined* e) override;
virtual void Visit(LiteralString* e) override;
Expand Down Expand Up @@ -52,6 +54,7 @@ class ASTInterpreter : public ExpressionVisitor
private:
void RunExpression(const ExpressionPtr& e);
bool EvalToBool(const ExpressionPtr& e);
bool EvalIsEqual(const ExpressionPtr& e);

void EnterScope();
void LeaveScope();
Expand All @@ -63,4 +66,8 @@ class ASTInterpreter : public ExpressionVisitor

typedef IPLVector<IPLString> Scope;
IPLStack<Scope> m_Scopes;

bool m_Fallthrough;
bool m_Break;
bool m_Continue;
};
69 changes: 68 additions & 1 deletion JSImpl/src/ByteCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class ByteCodeGenerator : public ExpressionVisitor
virtual void Visit(EmptyExpression* e) override { (void)e; }
virtual void Visit(IfStatement* e) override;
virtual void Visit(ForStatement* e) override;
virtual void Visit(SwitchStatement* e) override;
virtual void Visit(CaseStatement* e) override;
virtual void Visit(UnaryExpression* e) override;

IPLString GetCode();
Expand Down Expand Up @@ -106,6 +108,10 @@ class ByteCodeGenerator : public ExpressionVisitor
IPLStack<IPLString> m_RegisterStack;
IPLString m_OutputCode;
ByteCodeGeneratorOptions m_Options;

IPLVector<std::pair<size_t, ExpressionPtr>> m_SwitchCases;
IPLVector<size_t> m_BreakInstructionAddresses;
IPLVector<size_t> m_ContinueInstructionAddresses;
};

size_t ByteCodeGenerator::PushInstruction(Instruction::Type opcode, const IPLString& arg0, const IPLString& arg1, const IPLString& arg2)
Expand Down Expand Up @@ -343,6 +349,55 @@ void ByteCodeGenerator::Visit(ForStatement* e)
e->GetIteration()->Accept(*this);
PushInstruction(Instruction::Type::JMP, compareAddress);
m_Code[endAddress].Values.Address[0] = m_Code.size();

for (auto breakInstructionAddress : m_BreakInstructionAddresses)
m_Code[breakInstructionAddress].Values.Address[0] = m_Code.size();
m_BreakInstructionAddresses.clear();

for (auto continueInstructionAddress : m_ContinueInstructionAddresses)
m_Code[continueInstructionAddress].Values.Address[0] = compareAddress;
m_ContinueInstructionAddresses.clear();
}

void ByteCodeGenerator::Visit(SwitchStatement* e)
{
// unfortunately, we cannot use a jump table for the switch as JS allows non-integer values as conditions
e->GetCondition()->Accept(*this);
for (const auto& c : e->GetCases())
{
c->Accept(*this);
}

auto jumpToDefaultAddress = PushInstruction(Instruction::Type::JMP);

for (const auto& c : m_SwitchCases)
{
auto jumpAddress = c.first;
m_Code[jumpAddress].Values.Address[0] = m_Code.size();
c.second->Accept(*this);
}

m_Code[jumpToDefaultAddress].Values.Address[0] = m_Code.size();
e->GetDefaultCase()->Accept(*this);

m_SwitchCases.clear();
m_RegisterStack.pop();

for (auto breakInstructionAddress : m_BreakInstructionAddresses)
m_Code[breakInstructionAddress].Values.Address[0] = m_Code.size();
m_BreakInstructionAddresses.clear();
}

void ByteCodeGenerator::Visit(CaseStatement* e)
{
e->GetCondition()->Accept(*this);
auto caseCondition = m_RegisterStack.top();
m_RegisterStack.pop();
auto switchCondition = m_RegisterStack.top();
auto result = CreateRegister();
PushInstruction(Instruction::Type::EQ, result, switchCondition, caseCondition);
auto jumpAddress = PushInstruction(Instruction::Type::JMPT, result, (size_t)0);
m_SwitchCases.emplace_back(jumpAddress, e->GetBody());
}

void ByteCodeGenerator::Visit(IdentifierExpression* e)
Expand Down Expand Up @@ -391,6 +446,18 @@ void ByteCodeGenerator::Visit(UnaryExpression* e)
PushInstruction(Instruction::Type::SUB, reg, reg, one);
}
return;
case TokenType::Break:
{
auto breakAddress = PushInstruction(Instruction::Type::JMP);
m_BreakInstructionAddresses.push_back(breakAddress);
}
return;
case TokenType::Continue:
{
auto continueAddress = PushInstruction(Instruction::Type::JMP);
m_ContinueInstructionAddresses.push_back(continueAddress);
}
return;
default:
NOT_IMPLEMENTED;
break;
Expand Down Expand Up @@ -654,7 +721,7 @@ IPLString ByteCodeGenerator::GetCode()
default:
NOT_IMPLEMENTED;
break;

}
++programCounter;
}
Expand Down
2 changes: 1 addition & 1 deletion JSImpl/src/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Expression : public IPLEnableShared<Expression>
: \
MEMBERS_ITERATOR(EXPAND_INITIALIZER_LIST) m_dummy(__dummy) {} \
virtual ~ClassName() {} \
virtual void Accept(ExpressionVisitor& v) override { v.Visit(this); } \
virtual void Accept(ExpressionVisitor& v) override { if (!v.IsInSkipMode()) v.Visit(this); } \
\
MEMBERS_ITERATOR(GENERATE_GETTERS) \
private: \
Expand Down
2 changes: 2 additions & 0 deletions JSImpl/src/ExpressionVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class ExpressionVisitor
public:
~ExpressionVisitor() {}

virtual bool IsInSkipMode() { return false; }

virtual void Visit(LiteralNull* e) { (void)e; NOT_IMPLEMENTED; }
virtual void Visit(LiteralUndefined* e) { (void)e; NOT_IMPLEMENTED; }
virtual void Visit(LiteralString* e) { (void)e; NOT_IMPLEMENTED; }
Expand Down