diff options
| Commit | 8f9f28a9875816f5b61893f69d7bd3d2cf4182c6 (patch) | |
|---|---|---|
| Author | 2018-10-24 19:49:08 +0300 | |
| Committer | 2018-10-24 19:49:08 +0300 | |
| Files | 1898055fa2e7a1305ef4bd0dd79181d533cf0d65 /JSImpl | |
| IPL-8f9f28a9875816f5b61893f69d7bd3d2cf4182c6.tar IPL-8f9f28a9875816f5b61893f69d7bd3d2cf4182c6.tar.gz IPL-8f9f28a9875816f5b61893f69d7bd3d2cf4182c6.zip | ||
| Parent | d57561ef43c80fa6050e80f4876a45ba886818ff (diff) | |
| Parent | 74363cca95d59c3b756675701f6e843597593225 (diff) | |
Merge branch 'tree_interpreter'
7 files changed, 421 insertions, 26 deletions
| -rw-r--r-- | JSImpl/solution/JSImpl.vcxproj | 16 | ||||
| -rw-r--r-- | JSImpl/solution/JSImpl.vcxproj.filters | 8 | ||||
| -rw-r--r-- | JSImpl/src/ASTInterpreter.cpp | 284 | ||||
| -rw-r--r-- | JSImpl/src/ASTInterpreter.h | 54 | ||||
| -rw-r--r-- | JSImpl/src/CommonTypes.h | 4 | ||||
| -rw-r--r-- | JSImpl/src/Parser.cpp | 56 | ||||
| -rw-r--r-- | JSImpl/src/main.cpp | 25 |
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 |
