Website Summary Files Commits Branches @commit @diff @stats
path: root / JSImpl
diff options
context:
space:
mode:
Commit8f9f28a9875816f5b61893f69d7bd3d2cf4182c6 (patch)
Author
 Dimitar Trendafilov <dimitar@coherent-labs.com>
2018-10-24 19:49:08 +0300
Committer
 Dimitar Trendafilov <dimitar@coherent-labs.com>
2018-10-24 19:49:08 +0300
Files1898055fa2e7a1305ef4bd0dd79181d533cf0d65 /JSImpl
IPL-8f9f28a9875816f5b61893f69d7bd3d2cf4182c6.tar
IPL-8f9f28a9875816f5b61893f69d7bd3d2cf4182c6.tar.gz
IPL-8f9f28a9875816f5b61893f69d7bd3d2cf4182c6.zip
Parentd57561ef43c80fa6050e80f4876a45ba886818ff (diff)
Parent74363cca95d59c3b756675701f6e843597593225 (diff)
Merge branch 'tree_interpreter'
7 files changed, 421 insertions, 26 deletions
-rw-r--r--JSImpl/solution/JSImpl.vcxproj16
-rw-r--r--JSImpl/solution/JSImpl.vcxproj.filters8
-rw-r--r--JSImpl/src/ASTInterpreter.cpp284
-rw-r--r--JSImpl/src/ASTInterpreter.h54
-rw-r--r--JSImpl/src/CommonTypes.h4
-rw-r--r--JSImpl/src/Parser.cpp56
-rw-r--r--JSImpl/src/main.cpp25
diff --git a/JSImpl/solution/JSImpl.vcxproj b/JSImpl/solution/JSImpl.vcxproj
index 99b34cc..e8645d7 100644
--- a/JSImpl/solution/JSImpl.vcxproj
+++ b/JSImpl/solution/JSImpl.vcxproj
@@ -71,25 +71,28 @@
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
- <WarningLevel>Level3</WarningLevel>
+ <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
+ <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
- <WarningLevel>Level3</WarningLevel>
+ <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
+ <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
- <WarningLevel>Level3</WarningLevel>
+ <WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
+ <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -98,13 +101,14 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
- <WarningLevel>Level3</WarningLevel>
+ <WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>None</DebugInformationFormat>
<WholeProgramOptimization>true</WholeProgramOptimization>
+ <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -112,6 +116,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClInclude Include="..\src\ASTInterpreter.h" />
<ClInclude Include="..\src\ASTPrinter.h" />
<ClInclude Include="..\src\CommonTypes.h" />
<ClInclude Include="..\src\Expression.h" />
@@ -122,6 +127,7 @@
<ClInclude Include="..\src\Parser.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\src\ASTInterpreter.cpp" />
<ClCompile Include="..\src\ASTPrinter.cpp" />
<ClCompile Include="..\src\Expression.cpp" />
<ClCompile Include="..\src\Lexer.cpp" />
@@ -131,4 +137,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/JSImpl/solution/JSImpl.vcxproj.filters b/JSImpl/solution/JSImpl.vcxproj.filters
index 314e0f3..4a47e55 100644
--- a/JSImpl/solution/JSImpl.vcxproj.filters
+++ b/JSImpl/solution/JSImpl.vcxproj.filters
@@ -37,6 +37,9 @@
<Filter>Visitors</Filter>
</ClInclude>
<ClInclude Include="..\src\CommonTypes.h" />
+ <ClInclude Include="..\src\ASTInterpreter.h">
+ <Filter>Visitors</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\Expression.cpp">
@@ -52,5 +55,8 @@
<Filter>Visitors</Filter>
</ClCompile>
<ClCompile Include="..\src\main.cpp" />
+ <ClCompile Include="..\src\ASTInterpreter.cpp">
+ <Filter>Visitors</Filter>
+ </ClCompile>
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/JSImpl/src/ASTInterpreter.cpp b/JSImpl/src/ASTInterpreter.cpp
new file mode 100644
index 0000000..d66a9ce
--- /dev/null
+++ b/JSImpl/src/ASTInterpreter.cpp
@@ -0,0 +1,284 @@
+#include "ASTInterpreter.h"
+#include "Expression.h"
+#include <cassert>
+#include <iostream>
+
+
+#define NOT_IMPLEMENTED (void)e; assert(0 && "not-implemented")
+
+
+struct LValueExtractor : public ExpressionVisitor
+{
+public:
+ LValueExtractor(ASTInterpreter* interpreter)
+ : m_Interpreter(interpreter)
+ {}
+ ~LValueExtractor() {}
+
+ ASTInterpreter::value_type* Run(Expression* program)
+ {
+ m_LValue = nullptr;
+ program->Accept(*this);
+ return m_LValue;
+ }
+
+ virtual void Visit(LiteralNull* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(LiteralUndefined* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(LiteralString* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(LiteralNumber* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(LiteralBoolean* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(BinaryExpression* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(UnaryExpression* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(IdentifierExpression* e) override { m_LValue = &m_Interpreter->ModifyVariable(e->GetName()); }
+ virtual void Visit(ListExpression* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(VariableDefinitionExpression* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(BlockStatement* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(LabeledStatement* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(IfStatement* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(SwitchStatement* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(CaseStatement *e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(WhileStatement* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(ForStatement* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(FunctionDeclaration* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(TopStatements* e) override { NOT_IMPLEMENTED; }
+ virtual void Visit(EmptyExpression* e) override { NOT_IMPLEMENTED; }
+
+ ASTInterpreter* m_Interpreter;
+ ASTInterpreter::value_type* m_LValue;
+};
+
+
+struct VariableScope
+{
+ VariableScope(ASTInterpreter* interpreter)
+ : m_Interpreter(interpreter)
+ {
+ m_Interpreter->EnterScope();
+ }
+
+ ~VariableScope() {
+ m_Interpreter->LeaveScope();
+ }
+
+ VariableScope(VariableScope&) = delete;
+ VariableScope(VariableScope&&) = delete;
+ VariableScope& operator=(VariableScope&) = delete;
+ VariableScope& operator=(VariableScope&&) = delete;
+
+ ASTInterpreter* m_Interpreter;
+};
+
+ASTInterpreter::ASTInterpreter()
+{
+ // Allow globals
+ EnterScope();
+}
+
+ASTInterpreter::~ASTInterpreter()
+{}
+
+ASTInterpreter::ValueStack ASTInterpreter::Run(Expression* program)
+{
+ program->Accept(*this);
+ ValueStack result;
+ m_Evaluation.swap(result);
+ return result;
+}
+
+void ASTInterpreter::RunExpression(const ExpressionPtr& e)
+{
+ if (e) {
+ e->Accept(*this);
+ }
+}
+
+bool ASTInterpreter::EvalToBool(const ExpressionPtr& e)
+{
+ e->Accept(*this);
+ auto result = m_Evaluation.top();
+ m_Evaluation.pop();
+ return result != 0.0;
+}
+
+void ASTInterpreter::EnterScope()
+{
+ m_Scopes.push(Scope{});
+}
+
+void ASTInterpreter::LeaveScope()
+{
+ const auto& scope = m_Scopes.top();
+ for (auto& var : scope) {
+ auto values = m_Variables.find(var);
+ values->second.pop();
+ if (values->second.empty()) {
+ m_Variables.erase(values);
+ }
+ }
+ m_Scopes.pop();
+}
+
+ASTInterpreter::value_type& ASTInterpreter::ModifyVariable(const IPLString& name)
+{
+ auto values = m_Variables.find(name);
+ if (values != m_Variables.end()) {
+ return values->second.top();
+ }
+ else {
+ assert(0 && "not-defined");
+ }
+ static value_type undefined;
+ return undefined;
+}
+
+void ASTInterpreter::Visit(LiteralNull* e) {
+ NOT_IMPLEMENTED;
+}
+
+void ASTInterpreter::Visit(LiteralUndefined* e) {
+ NOT_IMPLEMENTED;
+}
+void ASTInterpreter::Visit(LiteralString* e) {
+ NOT_IMPLEMENTED;
+}
+
+void ASTInterpreter::Visit(LiteralNumber* e) {
+ m_Evaluation.push(e->GetValue());
+}
+void ASTInterpreter::Visit(LiteralBoolean* e) {
+ m_Evaluation.push(e->GetValue());
+}
+
+void ASTInterpreter::Visit(BinaryExpression* e) {
+ e->GetLeft()->Accept(*this);
+ e->GetRight()->Accept(*this);
+ auto right = m_Evaluation.top();
+ m_Evaluation.pop();
+
+ auto left = m_Evaluation.top();
+ m_Evaluation.pop();
+
+ switch (e->GetOperator()) {
+ case TokenType::Plus:
+ std::cout << "PLUS:" << left << ':' << right << std::endl;
+ m_Evaluation.push(left + right);
+ break;
+ case TokenType::Minus:
+ m_Evaluation.push(left - right);
+ break;
+ case TokenType::Star:
+ m_Evaluation.push(left * right);
+ break;
+ case TokenType::Division:
+ m_Evaluation.push(left / right);
+ break;
+ case TokenType::Less:
+ m_Evaluation.push(left < right);
+ break;
+ case TokenType::Comma:
+ m_Evaluation.push(right);
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ }
+}
+
+void ASTInterpreter::Visit(UnaryExpression* e) {
+ LValueExtractor extractor(this);
+ auto lvalue = extractor.Run(e->GetExpr().get());
+ if (e->GetSuffix())
+ {
+ m_Evaluation.push(*lvalue);
+ }
+ switch (e->GetOperator())
+ {
+ case TokenType::PlusPlus:
+ ++(*lvalue);
+ break;
+ case TokenType::MinusMinus:
+ --(*lvalue);
+ break;
+ default:
+ NOT_IMPLEMENTED;
+ }
+ if (!e->GetSuffix())
+ {
+ m_Evaluation.push(*lvalue);
+ }
+}
+
+void ASTInterpreter::Visit(IdentifierExpression* e) {
+ m_Evaluation.push(ModifyVariable(e->GetName()));
+}
+
+void ASTInterpreter::Visit(ListExpression* e) {
+ for (const auto& stmt: e->GetValues()) {
+ stmt->Accept(*this);
+ }
+}
+
+void ASTInterpreter::Visit(VariableDefinitionExpression* e) {
+ e->GetValue()->Accept(*this);
+ auto& name = e->GetName();
+ m_Variables[name].push(m_Evaluation.top());
+ m_Scopes.top().push_back(name);
+ m_Evaluation.pop();
+}
+
+void ASTInterpreter::Visit(BlockStatement* e) {
+ for (const auto& stmt: e->GetValues()) {
+ stmt->Accept(*this);
+ }
+}
+
+void ASTInterpreter::Visit(LabeledStatement* e) {
+ RunExpression(e->GetStatement());
+}
+
+void ASTInterpreter::Visit(IfStatement* e) {
+ VariableScope scope(this);
+ if (EvalToBool(e->GetCondition())) {
+ VariableScope ifScope(this);
+ RunExpression(e->GetIfStatement());
+ } else {
+ VariableScope elseScope(this);
+ RunExpression(e->GetElseStatement());
+ }
+}
+
+void ASTInterpreter::Visit(SwitchStatement* e) { NOT_IMPLEMENTED;}
+void ASTInterpreter::Visit(CaseStatement *e) { NOT_IMPLEMENTED;}
+
+void ASTInterpreter::Visit(WhileStatement* e) {
+ VariableScope scope(this);
+ if (e->GetDoWhile()) {
+ VariableScope bodyScope(this);
+ RunExpression(e->GetBody());
+ }
+ while (EvalToBool(e->GetCondition())) {
+ VariableScope bodyScope(this);
+ RunExpression(e->GetBody());
+ }
+}
+
+void ASTInterpreter::Visit(ForStatement* e) {
+ VariableScope scope(this);
+
+ for (RunExpression(e->GetInitialization());
+ EvalToBool(e->GetCondition());
+ RunExpression(e->GetIteration())) {
+ VariableScope bodyScope(this);
+ RunExpression(e->GetBody());
+ }
+}
+
+void ASTInterpreter::Visit(FunctionDeclaration* e) { NOT_IMPLEMENTED;}
+void ASTInterpreter::Visit(TopStatements* e) {
+ for (const auto& stmt: e->GetValues()) {
+ stmt->Accept(*this);
+ }
+}
+
+void ASTInterpreter::Visit(EmptyExpression* e) {
+ NOT_IMPLEMENTED;
+}
diff --git a/JSImpl/src/ASTInterpreter.h b/JSImpl/src/ASTInterpreter.h
new file mode 100644
index 0000000..4d5b46f
--- /dev/null
+++ b/JSImpl/src/ASTInterpreter.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "ExpressionVisitor.h"
+#include <stack>
+#include <string>
+#include <unordered_map>
+
+class ASTInterpreter : public ExpressionVisitor
+{
+public:
+ ASTInterpreter();
+ ~ASTInterpreter();
+
+ typedef double value_type;
+ typedef IPLStack<value_type> ValueStack;
+
+ ValueStack Run(Expression* program);
+
+ virtual void Visit(LiteralNull* e) override;
+ virtual void Visit(LiteralUndefined* e) override;
+ virtual void Visit(LiteralString* e) override;
+ virtual void Visit(LiteralNumber* e) override;
+ virtual void Visit(LiteralBoolean* e) override;
+ virtual void Visit(BinaryExpression* e) override;
+ virtual void Visit(UnaryExpression* e) override;
+ virtual void Visit(IdentifierExpression* e) override;
+ virtual void Visit(ListExpression* e) override;
+ virtual void Visit(VariableDefinitionExpression* e) override;
+ virtual void Visit(BlockStatement* e) override;
+ virtual void Visit(LabeledStatement* e) override;
+ virtual void Visit(IfStatement* e) override;
+ virtual void Visit(SwitchStatement* e) override;
+ virtual void Visit(CaseStatement *) override;
+ virtual void Visit(WhileStatement* e) override;
+ virtual void Visit(ForStatement* e) override;
+ virtual void Visit(FunctionDeclaration* e) override;
+ virtual void Visit(TopStatements* e) override;
+ virtual void Visit(EmptyExpression* e) override;
+
+ value_type& ModifyVariable(const IPLString& name);
+private:
+ void RunExpression(const ExpressionPtr& e);
+ bool EvalToBool(const ExpressionPtr& e);
+
+ void EnterScope();
+ void LeaveScope();
+ friend struct VariableScope;
+
+ ValueStack m_Evaluation;
+ IPLUnorderedMap<IPLString, ValueStack> m_Variables;
+
+ typedef IPLVector<IPLString> Scope;
+ IPLStack<Scope> m_Scopes;
+};
diff --git a/JSImpl/src/CommonTypes.h b/JSImpl/src/CommonTypes.h
index e9c1f1b..41e15d3 100644
--- a/JSImpl/src/CommonTypes.h
+++ b/JSImpl/src/CommonTypes.h
@@ -3,11 +3,15 @@
#include <vector>
#include <unordered_map>
#include <memory>
+#include <stack>
template<typename T>
using IPLVector = std::vector<T>;
using IPLString = std::string;
+template <typename T>
+using IPLStack = std::stack<T>;
+
template <typename Key, typename T>
using IPLUnorderedMap = std::unordered_map<Key, T>;
diff --git a/JSImpl/src/Parser.cpp b/JSImpl/src/Parser.cpp
index a2a46e2..4e1fbca 100644
--- a/JSImpl/src/Parser.cpp
+++ b/JSImpl/src/Parser.cpp
@@ -350,9 +350,10 @@ ExpressionPtr Parser::Unary()
TokenType::PlusPlus,
}))
{
+ auto op = Prev().Type;
auto ls = LeftSideExpression();
auto suffix = false;
- return IPLMakeSharePtr<UnaryExpression>(ls, Prev().Type, suffix);
+ return IPLMakeSharePtr<UnaryExpression>(ls, op, suffix);
}
else if (MatchOneOf({
TokenType::Void,
@@ -649,22 +650,23 @@ ExpressionPtr Parser::Expression()
ExpressionPtr Parser::Statement()
{
- if (auto result = EmptyStatement()) return result;
- else if(auto result = VariableDefinition()) return result;
- else if(auto result = Block()) return result;
- else if(auto result = LabeledStatement()) return result;
- else if(auto result = IfStatementfull()) return result;
- else if(auto result = SwitchStatement()) return result;
- else if(auto result = DoStatement()) return result;
- else if(auto result = WhileStatement()) return result;
- else if(auto result = ForStatement()) return result;
- else if(auto result = WithStatement()) return result;
- else if(auto result = ContinueStatement()) return result;
- else if(auto result = BreakStatement()) return result;
- else if(auto result = OptionalLabel()) return result;
- else if(auto result = ReturnStatement()) return result;
- else if(auto result = TryStatement()) return result;
- return nullptr;
+ ExpressionPtr result;
+ if (result = EmptyStatement()) return result;
+ else if(result = VariableDefinition()) return result;
+ else if(result = Block()) return result;
+ else if(result = LabeledStatement()) return result;
+ else if(result = IfStatementfull()) return result;
+ else if(result = SwitchStatement()) return result;
+ else if(result = DoStatement()) return result;
+ else if(result = WhileStatement()) return result;
+ else if(result = ForStatement()) return result;
+ else if(result = WithStatement()) return result;
+ else if(result = ContinueStatement()) return result;
+ else if(result = BreakStatement()) return result;
+ else if(result = OptionalLabel()) return result;
+ else if(result = ReturnStatement()) return result;
+ else if(result = TryStatement()) return result;
+ return result;
}
ExpressionPtr Parser::EmptyStatement()
@@ -738,13 +740,13 @@ ExpressionPtr Parser::Block()
if (Match(TokenType::LeftBrace))
{
- if (Match(TokenType::RightBrace))
+ if (!Match(TokenType::RightBrace))
{
return BlockStatementsPrefix();
}
else
{
- // TODO log error
+ // TODO log error - empty block?
assert(false);
return nullptr;
}
@@ -846,14 +848,30 @@ ExpressionPtr Parser::ForStatement()
{
if (Match(TokenType::For))
{
+ if (!Match(TokenType::LeftParen))
+ {
+ assert(false);
+ }
auto initializer = Expression();
if (!initializer)
{
initializer = VariableDefinition();
}
+ if (!Match(TokenType::Semicolon))
+ {
+ assert(false);
+ }
auto cond = Expression();
+ if (!Match(TokenType::Semicolon))
+ {
+ assert(false);
+ }
auto iteration = Expression();
+ if (!Match(TokenType::RightParen))
+ {
+ assert(false);
+ }
auto body = Statement();
return IPLMakeSharePtr<::ForStatement>(initializer, cond, iteration, body);
}
diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp
index 73f883f..dd54f38 100644
--- a/JSImpl/src/main.cpp
+++ b/JSImpl/src/main.cpp
@@ -1,6 +1,7 @@
#include "Lexer.h"
#include "Parser.h"
#include "ASTPrinter.h"
+#include "ASTInterpreter.h"
#include <iostream>
#define LOG(msg) std::cout << msg << std::endl
#define EXECUTE_TEST(test) std::cout << #test << " "; test();
@@ -198,6 +199,27 @@ void TestParseUnaryExpr()
expr->Accept(p);
}
+void RunParseCalc()
+{
+ IPLVector<Token> tokens;
+ //Tokenize("var a = 0; var b = a + 123;a+b;", tokens);
+ Tokenize("var s = 0; for (var i = 0; i < 10; ++i + --s) { s };", 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();
+ }
+ std::cout << "S = " << i.ModifyVariable("s") << std::endl;
+}
+
void TestHexNumber()
{
IPLVector<Token> tokens;
@@ -235,7 +257,8 @@ int main()
EXECUTE_TEST(TestHexNumber);
EXECUTE_TEST(TestScientificNotationNumber);
- // TestParseUnaryExpr();
+ //TestParseUnaryExpr();
+ RunParseCalc();
#if defined(_WIN32)
std::system("pause");
#endif