diff --git a/.gitignore b/.gitignore index 2115369..a316f45 100644 --- a/.gitignore +++ b/.gitignore @@ -30,10 +30,10 @@ # Build files bin/ -cmake-build-debug/ -/cmake-build-debug/ +cmake-build-beginDebug/ +/cmake-build-beginDebug/ *.make -cmake-build-debug/CMakeFiles/Makefile2 +cmake-build-beginDebug/CMakeFiles/Makefile2 /interpreter/src/core/parser/generated/ /deps/antlr/build/ @@ -41,6 +41,7 @@ cmake-build-debug/CMakeFiles/Makefile2 /deps/antlr/run/ /deps/antlr/cmake/ .idea -/cmake-build-debug/antlr4cpp_generated_src/ -/cmake-build-debug/locals/ +/cmake-build-debug/ /docs/page/_site +/cmake-build-debugclang/ +/cmake-build-release/ diff --git a/examples/Debug.grace b/examples/Debug.grace new file mode 100644 index 0000000..50370d6 --- /dev/null +++ b/examples/Debug.grace @@ -0,0 +1,8 @@ +def out1 = 4; +def obj = object { + var in1 := 3; + var in2 := 5; + var in3 := 8; +}; +def out2 = 6; +def out3 = 6; diff --git a/examples/Lines.grace b/examples/Lines.grace new file mode 100644 index 0000000..5460473 --- /dev/null +++ b/examples/Lines.grace @@ -0,0 +1,3 @@ +var in1 := 3; +var in2 := 5; +var in3 := 8; \ No newline at end of file diff --git a/examples/Method.grace b/examples/Method.grace new file mode 100644 index 0000000..a84d2df --- /dev/null +++ b/examples/Method.grace @@ -0,0 +1,4 @@ +method add(a)to(b) { + a + b; +} +var x := {ba, bb -> add(ba)to(bb);}.apply(2, 4); \ No newline at end of file diff --git a/grammars/GraceLexer.g4 b/grammars/GraceLexer.g4 index cf48e4c..428d5ac 100644 --- a/grammars/GraceLexer.g4 +++ b/grammars/GraceLexer.g4 @@ -41,7 +41,7 @@ tokens { DUMMY } -WS : [ \r\t\n]+ -> skip ; +WS : [ \r\t\n]+ -> channel(HIDDEN); INT: Digit+; Digit: [0-9]; diff --git a/interpreter/src/core/control/DebugState.h b/interpreter/src/core/control/DebugState.h new file mode 100644 index 0000000..72d2a02 --- /dev/null +++ b/interpreter/src/core/control/DebugState.h @@ -0,0 +1,15 @@ +// +// Copyright (c) 2017 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_DEBUGSTATE_H +#define NAYLANG_DEBUGSTATE_H +enum DebugState { + CONTINUE, + STOP, + STEP_IN, + STEP_OVER, + STEP_OVER_SKIP +}; +#endif //NAYLANG_DEBUGSTATE_H diff --git a/interpreter/src/core/control/Debugger.cpp b/interpreter/src/core/control/Debugger.cpp new file mode 100644 index 0000000..fc9fb14 --- /dev/null +++ b/interpreter/src/core/control/Debugger.cpp @@ -0,0 +1,59 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include "Debugger.h" + +namespace naylang { + +Debugger::Debugger(DebugMode *mode, const std::string &code) : + Interpreter(std::make_unique(this)), + _frontend{mode}, + _AST{parse(code)}{} + +void Debugger::run() { + _eval->setDebugState(CONTINUE); + _eval->evaluateAST(_AST); + finish(); +} + +void Debugger::setBreakpoint(int line) { + _breakpoints.insert(line); + std::cout << "Breakpoint set at line " << line << std::endl; +} + +void Debugger::printEnvironment() { + std::cout << "Current environment: " << std::endl; + std::cout << _eval->currentScope()->prettyPrint(0) << std::endl; +} + +void Debugger::resume() { + _eval->setDebugState(CONTINUE); +} + +void Debugger::debug(Statement *node) { + if (node->stoppable()) { + if (_breakpoints.count(node->line()) != 0) { + std::cout << "Breakpoint found at line " << node->line() << ". Stop." << std::endl; + _eval->setDebugState(STOP); + } + while(_eval->getDebugState() == STOP) { + _frontend->executeNextCommand(); + } + } +} + +void Debugger::stepIn() { + _eval->setDebugState(STEP_IN); +} + +void Debugger::stepOver() { + _eval->setDebugState(STEP_OVER); +} + +void Debugger::finish() { + std::cout << "Process finished. Resulting environment: " << std::endl; + std::cout << _eval->currentScope()->prettyPrint(0) << std::endl; +} +} \ No newline at end of file diff --git a/interpreter/src/core/control/Debugger.h b/interpreter/src/core/control/Debugger.h new file mode 100644 index 0000000..16c44ae --- /dev/null +++ b/interpreter/src/core/control/Debugger.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_DEBUGGER_H +#define NAYLANG_DEBUGGER_H + +#include +#include +#include "Interpreter.h" + +namespace naylang { +class DebugMode; +class Debugger : public Interpreter { + + GraceAST _AST; + std::set _breakpoints; + DebugMode *_frontend; + +public: + + Debugger(DebugMode *frontend, const std::string &filename); + + void run(); + void setBreakpoint(int line); + void printEnvironment(); + void resume(); + void stepIn(); + void stepOver(); + + void debug(Statement *node); + +private: + + void finish(); +}; +} + +#endif //NAYLANG_DEBUGGER_H diff --git a/interpreter/src/core/control/Interpreter.cpp b/interpreter/src/core/control/Interpreter.cpp index 3682e63..48117f7 100644 --- a/interpreter/src/core/control/Interpreter.cpp +++ b/interpreter/src/core/control/Interpreter.cpp @@ -1,19 +1,16 @@ // -// Copyright (c) 2016 by Borja Lorente. -// Distributed under the GPLv3 license. +// Created by borja on 4/14/17. // +#include "REPLInterpreter.h" #include "Interpreter.h" namespace naylang { -void Interpreter::execute(const std::string &line) { - eval.evaluateAST(parse(line)); - std::cout << eval.currentScope()->prettyPrint(0) << std::endl; -} -void Interpreter::printResult(const std::string &line) { - eval.evaluateAST(parse(line)); - std::cout << eval.partial()->prettyPrint(0) << std::endl; +void Interpreter::printResult(std::string line) { + colonize(line); + auto res = _eval->evaluateSandbox(parse(line)); + std::cout << res->prettyPrint(0) << std::endl; } GraceAST Interpreter::parse(const std::string &line) const { @@ -25,4 +22,10 @@ GraceAST Interpreter::parse(const std::string &line) const { parserVisitor.visit(parser.program()); return parserVisitor.AST(); } -} \ No newline at end of file + +void Interpreter::colonize(std::string &line) { + if (line.at(line.length() - 1) != ';') { + line.append(";"); + } +} +} diff --git a/interpreter/src/core/control/Interpreter.h b/interpreter/src/core/control/Interpreter.h index 12c55e9..cbf18f7 100644 --- a/interpreter/src/core/control/Interpreter.h +++ b/interpreter/src/core/control/Interpreter.h @@ -6,7 +6,6 @@ #ifndef NAYLANG_INTERPRETER_H #define NAYLANG_INTERPRETER_H -#include #include #include #include @@ -16,17 +15,17 @@ using namespace antlr4::tree; namespace naylang { class Interpreter { - - ExecutionEvaluator eval; +protected: + std::unique_ptr _eval; public: + Interpreter(std::unique_ptr eval) : _eval{std::move(eval)} {} + void printResult(std::string line); - void execute(const std::string &line); - void printResult(const std::string &line); - -private: +protected: GraceAST parse(const std::string &line) const; + void colonize(std::string &line); }; -} -#endif //NAYLANG__INTERPRETER_H +} +#endif //NAYLANG_INTERPRETER_H diff --git a/interpreter/src/core/control/REPLInterpreter.cpp b/interpreter/src/core/control/REPLInterpreter.cpp new file mode 100644 index 0000000..0c57798 --- /dev/null +++ b/interpreter/src/core/control/REPLInterpreter.cpp @@ -0,0 +1,17 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include "REPLInterpreter.h" +#include + +namespace naylang { +void REPLInterpreter::execute(std::string line) { + colonize(line); + _eval->evaluateAST(parse(line)); + std::cout << _eval->currentScope()->prettyPrint(0) << std::endl; +} + +REPLInterpreter::REPLInterpreter() : Interpreter(std::make_unique()) {} +} \ No newline at end of file diff --git a/interpreter/src/core/control/REPLInterpreter.h b/interpreter/src/core/control/REPLInterpreter.h new file mode 100644 index 0000000..7f1f949 --- /dev/null +++ b/interpreter/src/core/control/REPLInterpreter.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_REPLINTERPRETER_H +#define NAYLANG_REPLINTERPRETER_H + +#include +#include "Interpreter.h" + +namespace naylang { +class REPLInterpreter : public Interpreter { + +public: + REPLInterpreter(); + + void execute(std::string line); +}; +} + +#endif //NAYLANG_REPLINTERPRETER_H diff --git a/interpreter/src/core/model/ast/ASTNodeDefinitions.h b/interpreter/src/core/model/ast/ASTNodeDefinitions.h index 4faa67d..a27c3f0 100644 --- a/interpreter/src/core/model/ast/ASTNodeDefinitions.h +++ b/interpreter/src/core/model/ast/ASTNodeDefinitions.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/interpreter/src/core/model/ast/ASTTreeDefinition.h b/interpreter/src/core/model/ast/ASTTreeDefinition.h deleted file mode 100644 index 821eaa1..0000000 --- a/interpreter/src/core/model/ast/ASTTreeDefinition.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// Copyright (c) 2017 by Borja Lorente. -// Distributed under the GPLv3 license. -// - -#ifndef NAYLANG_ASTTREEDEFINITION_H -#define NAYLANG_ASTTREEDEFINITION_H - -#include - -namespace naylang { -typedef std::vector GraceAST; -} -#endif //NAYLANG_ASTTREEDEFINITION_H diff --git a/interpreter/src/core/model/ast/GraceAST.cpp b/interpreter/src/core/model/ast/GraceAST.cpp new file mode 100644 index 0000000..9fe6cd5 --- /dev/null +++ b/interpreter/src/core/model/ast/GraceAST.cpp @@ -0,0 +1,28 @@ +// +// Copyright (c) 2017 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include "GraceAST.h" + +namespace naylang { +StatementPtr GraceAST::operator[](int index) { + return _nodes[index]; +} + +void GraceAST::addNode(StatementPtr node) { + _nodes.push_back(node); +} + +const std::vector &GraceAST::nodes() const { + return _nodes; +} + +void GraceAST::addLineLink(StatementPtr node) { + if (_nodeLinks.count(node->line()) == 0) { + _nodeLinks[node->line()] = node; + _lastLine = node->line() > _lastLine ? node->line() : _lastLine; + } +} +} + diff --git a/interpreter/src/core/model/ast/GraceAST.h b/interpreter/src/core/model/ast/GraceAST.h new file mode 100644 index 0000000..d207d95 --- /dev/null +++ b/interpreter/src/core/model/ast/GraceAST.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2017 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_ASTTREEDEFINITION_H +#define NAYLANG_ASTTREEDEFINITION_H + +#include +#include + +namespace naylang { +class GraceAST { + std::vector _nodes; + std::map _nodeLinks; + int _lastLine = 0; + +public: + + virtual StatementPtr operator[](int index); + void addNode(StatementPtr node); + void addLineLink(StatementPtr node); + const std::vector &nodes() const; + +}; +} +#endif //NAYLANG_ASTTREEDEFINITION_H diff --git a/interpreter/src/core/model/ast/Statement.h b/interpreter/src/core/model/ast/Statement.h index e331af5..115e6e6 100644 --- a/interpreter/src/core/model/ast/Statement.h +++ b/interpreter/src/core/model/ast/Statement.h @@ -21,16 +21,20 @@ class Statement { int _line; int _col; + bool _stoppable; public: - Statement() : _line{-1}, _col{-1} {} - Statement(int line, int col) : _line{line}, _col{col} {} + Statement() : _line{-1}, _col{-1}, _stoppable{false}{} + Statement(int line, int col) : _line{line}, _col{col}, _stoppable{false}{} virtual void accept(Evaluator &evaluator) = 0; - int line() {return _line;} - int col() {return _col;} + int line() const {return _line;} + int col() const {return _col;} + + bool stoppable() {return _stoppable;} + void makeStoppable() {_stoppable = true;} }; } diff --git a/interpreter/src/core/model/ast/declarations/ConstantDeclaration.cpp b/interpreter/src/core/model/ast/declarations/ConstantDeclaration.cpp index 423c093..45e6750 100644 --- a/interpreter/src/core/model/ast/declarations/ConstantDeclaration.cpp +++ b/interpreter/src/core/model/ast/declarations/ConstantDeclaration.cpp @@ -24,5 +24,4 @@ const std::string & ConstantDeclaration::name() const { ExpressionPtr ConstantDeclaration::value() const { return _value; } - } \ No newline at end of file diff --git a/interpreter/src/core/model/ast/declarations/MethodDeclaration.cpp b/interpreter/src/core/model/ast/declarations/MethodDeclaration.cpp index eafbcdd..8b7697e 100644 --- a/interpreter/src/core/model/ast/declarations/MethodDeclaration.cpp +++ b/interpreter/src/core/model/ast/declarations/MethodDeclaration.cpp @@ -30,4 +30,5 @@ const std::vector & MethodDeclaration::body() const { const std::vector &MethodDeclaration::params() const { return _params; } + } \ No newline at end of file diff --git a/interpreter/src/core/model/ast/declarations/MethodDeclaration.h b/interpreter/src/core/model/ast/declarations/MethodDeclaration.h index 1c4b89f..d4646c5 100644 --- a/interpreter/src/core/model/ast/declarations/MethodDeclaration.h +++ b/interpreter/src/core/model/ast/declarations/MethodDeclaration.h @@ -35,7 +35,6 @@ class MethodDeclaration : public Declaration { const std::string &name() const override; const std::vector ¶ms() const; const std::vector &body() const; - }; } // end namespace naylang diff --git a/interpreter/src/core/model/ast/declarations/VariableDeclaration.h b/interpreter/src/core/model/ast/declarations/VariableDeclaration.h index 0cd02f3..d4ebeeb 100644 --- a/interpreter/src/core/model/ast/declarations/VariableDeclaration.h +++ b/interpreter/src/core/model/ast/declarations/VariableDeclaration.h @@ -27,6 +27,7 @@ class VariableDeclaration : public Declaration { virtual void accept(Evaluator &evaluator); const std::string &name() const; const ExpressionPtr &value() const; + }; } diff --git a/interpreter/src/core/model/ast/expressions/ObjectConstructor.cpp b/interpreter/src/core/model/ast/expressions/ObjectConstructor.cpp index 9cd4076..4571111 100644 --- a/interpreter/src/core/model/ast/expressions/ObjectConstructor.cpp +++ b/interpreter/src/core/model/ast/expressions/ObjectConstructor.cpp @@ -23,4 +23,5 @@ void ObjectConstructor::accept(Evaluator &evaluator) { const std::vector &ObjectConstructor::statements() const { return _statements; } + } \ No newline at end of file diff --git a/interpreter/src/core/model/ast/expressions/ObjectConstructor.h b/interpreter/src/core/model/ast/expressions/ObjectConstructor.h index 1223a18..58c8f20 100644 --- a/interpreter/src/core/model/ast/expressions/ObjectConstructor.h +++ b/interpreter/src/core/model/ast/expressions/ObjectConstructor.h @@ -19,7 +19,7 @@ class ObjectConstructor : public Expression { ObjectConstructor(const std::vector &statements); virtual void accept(Evaluator &evaluator); - + const std::vector &statements() const; }; } // end namespace naylang diff --git a/interpreter/src/core/model/evaluators/BindingEvaluator.cpp b/interpreter/src/core/model/evaluators/BindingEvaluator.cpp index 8e1a660..fa2457e 100644 --- a/interpreter/src/core/model/evaluators/BindingEvaluator.cpp +++ b/interpreter/src/core/model/evaluators/BindingEvaluator.cpp @@ -13,35 +13,35 @@ const std::map &BindingEvaluator::symbolTable() cons void BindingEvaluator::evaluate(ImplicitRequestNode &expression) { if (_symbolTable.find(expression.identifier()) == _symbolTable.end()) { - throw "Binding not found in symbol table"; + throw std::string{"Binding not found in symbol table"}; } expression.bindTo(static_cast(*_symbolTable[expression.identifier()])); } void BindingEvaluator::evaluate(ConstantDeclaration &expression) { if(_symbolTable.find(expression.name()) != _symbolTable.end()) { - throw "Binding exists in symbol table"; + throw std::string{"Binding exists in symbol table"}; } _symbolTable[expression.name()] = &expression; } void BindingEvaluator::evaluate(VariableDeclaration &expression) { if(_symbolTable.find(expression.name()) != _symbolTable.end()) { - throw "Binding exists in symbol table"; + throw std::string{"Binding exists in symbol table"}; } _symbolTable[expression.name()] = &expression; } void BindingEvaluator::evaluate(MethodDeclaration &expression) { if(_symbolTable.find(expression.name()) != _symbolTable.end()) { - throw "Binding exists in symbol table"; + throw std::string{"Binding exists in symbol table"}; } _symbolTable[expression.name()] = &expression; } void BindingEvaluator::evaluate(ExplicitRequestNode &expression) { if (_symbolTable.find(expression.identifier()) == _symbolTable.end()) { - throw "Binding not found in symbol table"; + throw std::string{"Binding not found in symbol table"}; } expression.bindTo(static_cast(*_symbolTable[expression.identifier()])); } diff --git a/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp b/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp index dd8e02b..f4f202b 100644 --- a/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp +++ b/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp @@ -5,6 +5,8 @@ #include "ExecutionEvaluator.h" +#include + #include #include #include @@ -12,18 +14,38 @@ #include #include #include +#include namespace naylang { +ExecutionEvaluator::ExecutionEvaluator() : + ExecutionEvaluator(nullptr) {} -ExecutionEvaluator::ExecutionEvaluator() : _currentScope{make_obj()}, _partial{make_obj()}{} +ExecutionEvaluator::ExecutionEvaluator(Debugger *debugger) : + _currentScope{make_obj()}, + _partial{make_obj()}, + _debugger{debugger} { + _debugging = _debugger != nullptr; + _state = STOP; +} void ExecutionEvaluator::evaluateAST(const GraceAST &ast) { _partial = make_obj(); - for (auto inst : ast) { + for (auto inst : ast.nodes()) { inst->accept(*this); } } +GraceObjectPtr ExecutionEvaluator::evaluateSandbox(const GraceAST &ast) { + auto oldPart = _partial; + _partial = make_obj(); + for (auto inst : ast.nodes()) { + inst->accept(*this); + } + auto res = _partial; + _partial = oldPart; + return res; +} + void ExecutionEvaluator::evaluate(BooleanLiteral &expression) { _partial = make_obj(expression.value()); } @@ -53,7 +75,6 @@ void ExecutionEvaluator::evaluate(ImplicitRequestNode &expression) { _partial = _currentScope->dispatch(expression.identifier(), *this, paramValues); } - void ExecutionEvaluator::evaluate(MethodDeclaration &expression) { MethodPtr method = make_meth(expression.params(), expression.body()); _currentScope->addMethod(expression.name(), method); @@ -64,6 +85,7 @@ void ExecutionEvaluator::evaluate(Return &expression) { } void ExecutionEvaluator::evaluate(ExplicitRequestNode &expression) { + beginDebug(&expression); expression.receiver()->accept(*this); auto self = _partial; @@ -80,6 +102,7 @@ void ExecutionEvaluator::evaluate(ExplicitRequestNode &expression) { paramValues.push_back(_partial); } _partial = self->dispatch(expression.identifier(), *this, paramValues); + endDebug(&expression, STEP_OVER_SKIP); } void ExecutionEvaluator::evaluate(ObjectConstructor &expression) { @@ -93,17 +116,23 @@ void ExecutionEvaluator::evaluate(ObjectConstructor &expression) { } void ExecutionEvaluator::evaluate(ConstantDeclaration &expression) { + beginDebug(&expression); + DebugState prevState = _state; expression.value()->accept(*this); _currentScope->setField(expression.name(), _partial); + endDebug(&expression, prevState); } void ExecutionEvaluator::evaluate(VariableDeclaration &expression) { + beginDebug(&expression); + DebugState prevState = _state; if (expression.value()) { expression.value()->accept(*this); _currentScope->setField(expression.name(), _partial); } else { _currentScope->setField(expression.name(), make_obj()); } + endDebug(&expression, prevState); } void ExecutionEvaluator::evaluate(Block &expression) { @@ -133,4 +162,36 @@ void ExecutionEvaluator::restoreScope() { void ExecutionEvaluator::setScope(GraceObjectPtr scope) { _currentScope = scope; } + +void ExecutionEvaluator::beginDebug(Statement *node) { + if (!_debugging) + return; + + if (_state == STEP_OVER) + _state = CONTINUE; + + _debugger->debug(node); +} + +void ExecutionEvaluator::endDebug(Statement *node, DebugState prevState) { + if (!_debugging) + return; + + if (!node->stoppable()) + return; + + if (prevState == STEP_OVER) + _state = STOP; + + if (_state == STEP_IN) + _state = STOP; +} + +void ExecutionEvaluator::setDebugState(DebugState state) { + _state = state; +} + +DebugState ExecutionEvaluator::getDebugState() const { + return _state; +} } \ No newline at end of file diff --git a/interpreter/src/core/model/evaluators/ExecutionEvaluator.h b/interpreter/src/core/model/evaluators/ExecutionEvaluator.h index 66fe1e3..e9033b9 100644 --- a/interpreter/src/core/model/evaluators/ExecutionEvaluator.h +++ b/interpreter/src/core/model/evaluators/ExecutionEvaluator.h @@ -7,54 +7,60 @@ #define NAYLANG_EXECUTIONEVALUATOR_H #include -#include #include - -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include +#include +#include +#include +#include namespace naylang { +class GraceObject; +class Debugger; + class ExecutionEvaluator : public Evaluator { GraceObjectPtr _partial; GraceObjectPtr _currentScope; + + Debugger *_debugger; + bool _debugging; + + DebugState _state; + public: ExecutionEvaluator(); + ExecutionEvaluator(Debugger *debugger); const GraceObjectPtr &partial() const; + GraceObjectPtr currentScope() const; GraceObjectPtr createNewScope(); void restoreScope(); void setScope(GraceObjectPtr scope); void evaluateAST(const GraceAST &ast); + GraceObjectPtr evaluateSandbox(const GraceAST &ast); + + virtual void evaluate(BooleanLiteral &expression) override; + virtual void evaluate(NumberLiteral &expression) override; + virtual void evaluate(StringLiteral &expression) override; + virtual void evaluate(ImplicitRequestNode &expression) override; + virtual void evaluate(ExplicitRequestNode &expression) override; + virtual void evaluate(MethodDeclaration &expression) override; + virtual void evaluate(ConstantDeclaration &expression) override; + virtual void evaluate(Return &expression) override; + virtual void evaluate(Block &expression) override; + virtual void evaluate(ObjectConstructor &expression) override; + virtual void evaluate(VariableDeclaration &expression) override; + + // Debug Methods + void setDebugState(DebugState state); + DebugState getDebugState() const; - virtual void evaluate(BooleanLiteral &expression); - virtual void evaluate(NumberLiteral &expression); - virtual void evaluate(StringLiteral &expression); - virtual void evaluate(ImplicitRequestNode &expression); - virtual void evaluate(ExplicitRequestNode &expression); - virtual void evaluate(MethodDeclaration &expression); - virtual void evaluate(ConstantDeclaration &expression); - virtual void evaluate(Return &expression); - virtual void evaluate(Block &expression); - virtual void evaluate(ObjectConstructor &expression); - - void evaluate(VariableDeclaration &expression) override; +private: + void beginDebug(Statement *node); + void endDebug(Statement *node, DebugState prevState); }; } // end namespace naylang diff --git a/interpreter/src/core/model/execution/Definitions.h b/interpreter/src/core/model/execution/Definitions.h deleted file mode 100644 index c7f6fec..0000000 --- a/interpreter/src/core/model/execution/Definitions.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2017 by Borja Lorente. -// Distributed under the GPLv3 license. -// - -#ifndef NAYLANG_DEFINITIONS_H -#define NAYLANG_DEFINITIONS_H - -#include - -namespace naylang { -class GraceObject; -typedef std::shared_ptr GraceObjectPtr; - -class Method; -typedef std::shared_ptr MethodPtr; -} - -#endif //NAYLANG_DEFINITIONS_H diff --git a/interpreter/src/core/model/execution/methods/Method.h b/interpreter/src/core/model/execution/methods/Method.h index 3bf0f74..7688b31 100644 --- a/interpreter/src/core/model/execution/methods/Method.h +++ b/interpreter/src/core/model/execution/methods/Method.h @@ -8,13 +8,16 @@ #include #include -#include #include -#include +#include +#include #include "MethodRequest.h" namespace naylang { +class ExecutionEvaluator; +class GraceObject; + class Method { std::vector _params; std::vector _code; diff --git a/interpreter/src/core/model/execution/methods/MethodFactory.h b/interpreter/src/core/model/execution/methods/MethodFactory.h index 4a4143f..9262fd7 100644 --- a/interpreter/src/core/model/execution/methods/MethodFactory.h +++ b/interpreter/src/core/model/execution/methods/MethodFactory.h @@ -5,9 +5,11 @@ #ifndef NAYLANG_METHODFACTORY_H #define NAYLANG_METHODFACTORY_H -namespace naylang { +#include +namespace naylang { class Method; + static std::shared_ptr make_meth(std::shared_ptr &block) { return std::make_shared(block); } diff --git a/interpreter/src/core/model/execution/methods/MethodPtr.h b/interpreter/src/core/model/execution/methods/MethodPtr.h new file mode 100644 index 0000000..5e14b3c --- /dev/null +++ b/interpreter/src/core/model/execution/methods/MethodPtr.h @@ -0,0 +1,13 @@ +// +// Created by borja on 4/14/17. +// + +#ifndef NAYLANG_METHODPTR_H +#define NAYLANG_METHODPTR_H + +namespace naylang { +class Method; +typedef std::shared_ptr MethodPtr; +} + +#endif //NAYLANG_METHODPTR_H diff --git a/interpreter/src/core/model/execution/methods/MethodRequest.h b/interpreter/src/core/model/execution/methods/MethodRequest.h index 51c299c..0944132 100644 --- a/interpreter/src/core/model/execution/methods/MethodRequest.h +++ b/interpreter/src/core/model/execution/methods/MethodRequest.h @@ -8,7 +8,7 @@ #include #include -#include +#include namespace naylang { diff --git a/interpreter/src/core/model/execution/objects/GraceBoolean.cpp b/interpreter/src/core/model/execution/objects/GraceBoolean.cpp index bf7cd70..a062839 100644 --- a/interpreter/src/core/model/execution/objects/GraceBoolean.cpp +++ b/interpreter/src/core/model/execution/objects/GraceBoolean.cpp @@ -4,6 +4,7 @@ // #include +#include #include "GraceBoolean.h" #include "GraceString.h" diff --git a/interpreter/src/core/model/execution/objects/GraceBoolean.h b/interpreter/src/core/model/execution/objects/GraceBoolean.h index dff7f7b..b13deaa 100644 --- a/interpreter/src/core/model/execution/objects/GraceBoolean.h +++ b/interpreter/src/core/model/execution/objects/GraceBoolean.h @@ -22,10 +22,10 @@ class GraceBoolean : public GraceObject { GraceBoolean(bool value); virtual GraceObjectPtr - dispatch(const std::string &methodName, ExecutionEvaluator &eval, const std::vector ¶mValues); - virtual void addDefaultMethods(); + dispatch(const std::string &methodName, ExecutionEvaluator &eval, const std::vector ¶mValues) override; + virtual void addDefaultMethods() override; - virtual const GraceBoolean &asBoolean() const; + virtual const GraceBoolean &asBoolean() const override; bool value() const; diff --git a/interpreter/src/core/model/execution/objects/GraceNumber.cpp b/interpreter/src/core/model/execution/objects/GraceNumber.cpp index d908e69..dc52aef 100644 --- a/interpreter/src/core/model/execution/objects/GraceNumber.cpp +++ b/interpreter/src/core/model/execution/objects/GraceNumber.cpp @@ -6,6 +6,7 @@ +#include #include "GraceNumber.h" #include "GraceBoolean.h" #include "GraceString.h" diff --git a/interpreter/src/core/model/execution/objects/GraceNumber.h b/interpreter/src/core/model/execution/objects/GraceNumber.h index e321efb..b4b3527 100644 --- a/interpreter/src/core/model/execution/objects/GraceNumber.h +++ b/interpreter/src/core/model/execution/objects/GraceNumber.h @@ -18,9 +18,9 @@ class GraceNumber : public GraceObject { public: GraceNumber(double value); - virtual const GraceNumber &asNumber() const; + virtual const GraceNumber &asNumber() const override; - virtual void addDefaultMethods(); + virtual void addDefaultMethods() override; double value() const; diff --git a/interpreter/src/core/model/execution/objects/GraceObject.cpp b/interpreter/src/core/model/execution/objects/GraceObject.cpp index 4a22f87..4691f7c 100644 --- a/interpreter/src/core/model/execution/objects/GraceObject.cpp +++ b/interpreter/src/core/model/execution/objects/GraceObject.cpp @@ -7,6 +7,7 @@ #include +#include #include "GraceObject.h" namespace naylang { @@ -14,19 +15,19 @@ namespace naylang { GraceObject::GraceObject() : _outer{nullptr} {} const GraceBoolean & GraceObject::asBoolean() const { - throw "Trying to cast a generic GraceObject as GraceBoolean"; + throw std::string{"Trying to cast a generic GraceObject as GraceBoolean"}; } const GraceNumber &GraceObject::asNumber() const { - throw "Trying to cast a generic GraceObject as GraceNumber"; + throw std::string{"Trying to cast a generic GraceObject as GraceNumber"}; } const GraceString &GraceObject::asString() const { - throw "Trying to cast a generic GraceObject as GraceString"; + throw std::string{"Trying to cast a generic GraceObject as GraceString"}; } GraceIterable &GraceObject::asIterable() const { - throw "Trying to cast a generic GraceObject as GraceIterable"; + throw std::string{"Trying to cast a generic GraceObject as GraceIterable"}; } bool GraceObject::isUndefined() const { @@ -90,14 +91,14 @@ MethodPtr GraceObject::getMethod(const std::string &name) { } if (_outer == nullptr) - throw "Method not found"; + throw std::string{"Method not found"}; return _outer->getMethod(name); } GraceObjectPtr GraceObject::getField(const std::string &name) { if (_fields.find(name) == _fields.end()) { - throw "Field not found in object"; + throw std::string{"Field not found in object"}; } return _fields[name]; } diff --git a/interpreter/src/core/model/execution/objects/GraceObject.h b/interpreter/src/core/model/execution/objects/GraceObject.h index bfc1225..5a7579b 100644 --- a/interpreter/src/core/model/execution/objects/GraceObject.h +++ b/interpreter/src/core/model/execution/objects/GraceObject.h @@ -9,10 +9,9 @@ #include #include #include -#include -#include -#include +#include #include +#include namespace naylang { @@ -21,6 +20,9 @@ class GraceNumber; class GraceString; class GraceIterable; class ExecutionEvaluator; +class GraceObject; + +typedef std::shared_ptr GraceObjectPtr; class GraceObject { protected: diff --git a/interpreter/src/core/model/execution/objects/GraceString.cpp b/interpreter/src/core/model/execution/objects/GraceString.cpp index 1db20d0..d411eb7 100644 --- a/interpreter/src/core/model/execution/objects/GraceString.cpp +++ b/interpreter/src/core/model/execution/objects/GraceString.cpp @@ -6,6 +6,7 @@ +#include #include "GraceString.h" #include "GraceBoolean.h" #include "GraceNumber.h" diff --git a/interpreter/src/core/model/execution/objects/GraceString.h b/interpreter/src/core/model/execution/objects/GraceString.h index 8fc49a6..835d29a 100644 --- a/interpreter/src/core/model/execution/objects/GraceString.h +++ b/interpreter/src/core/model/execution/objects/GraceString.h @@ -18,9 +18,9 @@ class GraceString : public GraceObject { public: GraceString(const std::string &value); - virtual void addDefaultMethods(); + virtual void addDefaultMethods() override; - virtual const GraceString &asString() const; + virtual const GraceString &asString() const override; const std::string &value() const; diff --git a/interpreter/src/core/parser/NaylangParserStack.h b/interpreter/src/core/parser/NaylangParserStack.h index 17d3c23..1a5d3ce 100644 --- a/interpreter/src/core/parser/NaylangParserStack.h +++ b/interpreter/src/core/parser/NaylangParserStack.h @@ -6,7 +6,7 @@ #ifndef NAYLANG_NAYLANGPARSERSTACK_H #define NAYLANG_NAYLANGPARSERSTACK_H -#include +#include namespace naylang { class NaylangParserStack { diff --git a/interpreter/src/core/parser/NaylangParserVisitor.cpp b/interpreter/src/core/parser/NaylangParserVisitor.cpp index d0d57d9..62fa7be 100644 --- a/interpreter/src/core/parser/NaylangParserVisitor.cpp +++ b/interpreter/src/core/parser/NaylangParserVisitor.cpp @@ -77,13 +77,16 @@ antlrcpp::Any NaylangParserVisitor::visitPrefixExp(GraceParser::PrefixExpContext auto opname = popPartialStr(); ctx->rec->accept(this); auto rec = popPartialExp(); - pushPartialExp(make_node(opname, rec, getLine(ctx), getCol(ctx))); + auto req = make_node(opname, rec, getLine(ctx), getCol(ctx)); + pushPartialExp(req); return 0; } antlrcpp::Any NaylangParserVisitor::visitNumber(GraceParser::NumberContext *ctx) { - pushPartialExp(make_node(std::stod(ctx->getText()), getLine(ctx), getCol(ctx))); + int lastLine = ctx->stop->getLine(); + auto num = make_node(std::stod(ctx->getText()), getLine(ctx), getCol(ctx)); + pushPartialExp(num); return 0; } antlrcpp::Any NaylangParserVisitor::visitMulDivExp(GraceParser::MulDivExpContext *ctx) { @@ -93,7 +96,8 @@ antlrcpp::Any NaylangParserVisitor::visitMulDivExp(GraceParser::MulDivExpContext auto param = popPartialExp(); auto op = ctx->op->getText() + "(_)"; std::vector params{param}; - pushPartialExp(make_node(op, reciever, params, getLine(ctx), getCol(ctx))); + auto req = make_node(op, reciever, params, getLine(ctx), getCol(ctx)); + pushPartialExp(req); return 0; } @@ -104,28 +108,34 @@ antlrcpp::Any NaylangParserVisitor::visitAddSubExp(GraceParser::AddSubExpContext auto param = popPartialExp(); auto op = ctx->op->getText() + "(_)"; std::vector params{param}; - pushPartialExp(make_node(op, reciever, params, getLine(ctx), getCol(ctx))); + auto req = make_node(op, reciever, params, getLine(ctx), getCol(ctx)); + pushPartialExp(req); return 0; } antlrcpp::Any NaylangParserVisitor::visitString(GraceParser::StringContext *ctx) { auto contents = ctx->content->getText(); - pushPartialExp(make_node(contents, getLine(ctx), getCol(ctx))); + auto str = make_node(contents, getLine(ctx), getCol(ctx)); + pushPartialExp(str); return 0; } antlrcpp::Any NaylangParserVisitor::visitBoolean(GraceParser::BooleanContext *ctx) { bool value = ctx->TRUE() != nullptr; - pushPartialExp(make_node(value, getLine(ctx), getCol(ctx))); + auto bul = make_node(value, getLine(ctx), getCol(ctx)); + pushPartialExp(bul); return 0; } antlrcpp::Any NaylangParserVisitor::visitConstantDeclaration(GraceParser::ConstantDeclarationContext *ctx) { + int lastLine = getLine(ctx->DELIMITER()); ctx->identifier()->accept(this); auto name = popPartialStr(); ctx->expression()->accept(this); auto value = popPartialExp(); - pushPartialDecl(make_node(name, value, getLine(ctx), getCol(ctx))); + auto decl = make_node(name, value, getLine(ctx), getCol(ctx)); + notifyBreakable(decl); + pushPartialDecl(decl); return 0; } @@ -135,11 +145,14 @@ antlrcpp::Any NaylangParserVisitor::visitIdentifier(GraceParser::IdentifierConte } antlrcpp::Any NaylangParserVisitor::visitVariableDeclaration(GraceParser::VariableDeclarationContext *ctx) { + int lastLine = getLine(ctx->DELIMITER()); ctx->identifier()->accept(this); auto name = popPartialStr(); ctx->expression()->accept(this); auto value = popPartialExp(); - pushPartialDecl(make_node(name, value, getLine(ctx), getCol(ctx))); + auto decl = make_node(name, value, getLine(ctx), getCol(ctx)); + notifyBreakable(decl); + pushPartialDecl(decl); return 0; } @@ -160,6 +173,9 @@ antlrcpp::Any NaylangParserVisitor::visitUserMethod(GraceParser::UserMethodConte ctx->methodBody()->accept(this); int bodyLength = ctx->methodBody()->methodBodyLine().size(); auto body = popPartialStats(bodyLength); + for (auto node : body) { + notifyBreakable(node); + } auto methodDeclaration = make_node(methodName, formalParams, body, getLine(ctx), getCol(ctx)); pushPartialDecl(methodDeclaration); @@ -167,12 +183,12 @@ antlrcpp::Any NaylangParserVisitor::visitUserMethod(GraceParser::UserMethodConte } antlrcpp::Any NaylangParserVisitor::visitMethodSignature(GraceParser::MethodSignatureContext *ctx) { - clearPartials(); for (auto i : ctx->methodSignaturePart()) { i->accept(this); } return 0; } + antlrcpp::Any NaylangParserVisitor::visitMethodSignaturePart(GraceParser::MethodSignaturePartContext *ctx) { auto partName = ctx->identifier()->getText(); if (ctx->formalParameterList()->formalParameter().size() != 0) { @@ -190,7 +206,6 @@ antlrcpp::Any NaylangParserVisitor::visitMethodSignaturePart(GraceParser::Method ctx->formalParameterList()->accept(this); return 0; } - antlrcpp::Any NaylangParserVisitor::visitFormalParameterList(GraceParser::FormalParameterListContext *ctx) { for (auto i : ctx->formalParameter()) { i->accept(this); @@ -219,6 +234,7 @@ antlrcpp::Any NaylangParserVisitor::visitPrefixMethod(GraceParser::PrefixMethodC ctx->methodBody()->accept(this); int bodyLength = ctx->methodBody()->methodBodyLine().size(); for (auto line : popPartialStats(bodyLength)) { + notifyBreakable(line); body.push_back(line); } @@ -315,9 +331,13 @@ antlrcpp::Any NaylangParserVisitor::visitBlock(GraceParser::BlockContext *ctx) { for (auto line : ctx->methodBodyLine()) { line->accept(this); - block->addStatement(popPartialStat()); + auto node = popPartialStat(); + notifyBreakable(node); + block->addStatement(node); } + //TODO: Should I set the last line of block? + std::vector params; if (ctx->params) { ctx->params->accept(this); @@ -331,6 +351,11 @@ antlrcpp::Any NaylangParserVisitor::visitBlock(GraceParser::BlockContext *ctx) { return 0; } +void NaylangParserVisitor::notifyBreakable(StatementPtr node) { + node->makeStoppable(); + _tree.addLineLink(node); +} + antlrcpp::Any NaylangParserVisitor::visitLineup(GraceParser::LineupContext *ctx) { int elems = ctx->lineupContents()->expression().size(); ctx->lineupContents()->accept(this); @@ -343,7 +368,9 @@ antlrcpp::Any NaylangParserVisitor::visitProgram(GraceParser::ProgramContext *ct for (auto line : ctx->statement()) { clearPartials(); line->accept(this); - _tree.push_back(popPartialStat()); + auto node = popPartialStat(); + _tree.addNode(node); + _tree.addLineLink(node); } return 0; } @@ -355,4 +382,12 @@ int NaylangParserVisitor::getCol(const antlr4::ParserRuleContext *ctx) const { int NaylangParserVisitor::getLine(const antlr4::ParserRuleContext *ctx) const { return ctx->start->getLine(); } + +int NaylangParserVisitor::getLine(antlr4::tree::TerminalNode *terminal) const { + return terminal->getSymbol()->getLine(); +} + +int NaylangParserVisitor::getLastLine(const antlr4::ParserRuleContext *ctx) const { + return ctx->stop->getLine(); +} } \ No newline at end of file diff --git a/interpreter/src/core/parser/NaylangParserVisitor.h b/interpreter/src/core/parser/NaylangParserVisitor.h index 3441bb9..40ad94a 100644 --- a/interpreter/src/core/parser/NaylangParserVisitor.h +++ b/interpreter/src/core/parser/NaylangParserVisitor.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include namespace naylang { @@ -86,10 +86,15 @@ class NaylangParserVisitor : public GraceParserBaseVisitor { void clearPartials(); - antlrcpp::Any defaultResult(); + antlrcpp::Any defaultResult() override; int getLine(const antlr4::ParserRuleContext *ctx) const; + int getLine(antlr4::tree::TerminalNode *terminal) const; int getCol(const antlr4::ParserRuleContext *ctx) const; + + void notifyBreakable(StatementPtr node); + + int getLastLine(const antlr4::ParserRuleContext *ctx) const; }; } diff --git a/interpreter/src/frontends/ConsoleFrontend.cpp b/interpreter/src/frontends/ConsoleFrontend.cpp index f2c7f7d..4675201 100644 --- a/interpreter/src/frontends/ConsoleFrontend.cpp +++ b/interpreter/src/frontends/ConsoleFrontend.cpp @@ -3,25 +3,42 @@ // #include "ConsoleFrontend.h" -#include +#include +#include namespace naylang { -void ConsoleFrontend::runCommand(std::string line) { - setCommand(line); - _command->execute(_interpreter); + +ConsoleFrontend::ConsoleFrontend() : + _mode{std::move(std::make_unique(this))}, + _quit{false} {} + +void ConsoleFrontend::run() { + std::string line; + while (!_quit) { + promptAndRun(); + } +} + +void ConsoleFrontend::promptAndRun() { + _mode->prompt(); + FrontendCommand command = _mode->getNextCommand(); + if (!handleMetaCommand(command.name, command.body)) { + _mode->runCommand(command.name, command.body); + } } -void ConsoleFrontend::setCommand(std::string line) { - auto commandName = line.substr(0, line.find(" ")); - auto code = std::regex_replace(line.substr(line.find(" ")), std::regex("^ +"), ""); - if (commandName == "exec" || commandName == "e") { - _command = std::make_unique(code); - } else if (commandName == "load" || commandName == "l") { - _command = std::make_unique(code); - } else if (commandName == "print" || commandName == "p") { - _command = std::make_unique(code); - } else { - throw "Command not found"; +bool ConsoleFrontend::handleMetaCommand(const std::string &name, const std::string & body) { + bool handled = false; + if (name == "quit") { + _quit = true; + handled = true; + } else if (name == "debug" || name == "d") { + _mode = std::make_unique(this, body); + handled = true; + } else if (name == "interactive" || name == "repl") { + _mode = std::make_unique(this); + handled = true; } + return handled; } } diff --git a/interpreter/src/frontends/ConsoleFrontend.h b/interpreter/src/frontends/ConsoleFrontend.h index d183874..ca4c1e8 100644 --- a/interpreter/src/frontends/ConsoleFrontend.h +++ b/interpreter/src/frontends/ConsoleFrontend.h @@ -6,21 +6,34 @@ #ifndef NAYLANG_CONSOLEFRONTENDLISTENER_H #define NAYLANG_CONSOLEFRONTENDLISTENER_H -#include -#include +#include +#include namespace naylang { +class FrontendCommand { +public: + std::string name; + std::string body; + FrontendCommand(std::string _name, std::string _body) : + name{_name}, body{_body} {} +}; + +class ConsoleExecutionMode; class ConsoleFrontend { - Interpreter _interpreter; - std::unique_ptr _command; + std::unique_ptr _mode; + bool _quit; public: - void runCommand(std::string line); + + ConsoleFrontend(); + void run(); + void promptAndRun(); private: - void setCommand(std::string basic_string); + + bool handleMetaCommand(const std::string &name, const std::string & body); }; } #endif //NAYLANG_CONSOLEFRONTENDLISTENER_H diff --git a/interpreter/src/frontends/FrontendCommand.cpp b/interpreter/src/frontends/FrontendCommand.cpp deleted file mode 100644 index b2ccdb3..0000000 --- a/interpreter/src/frontends/FrontendCommand.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2016 by Borja Lorente. -// Distributed under the GPLv3 license. -// - -#include "FrontendCommand.h" - -namespace naylang { - -FrontendCommand::FrontendCommand(const std::string &code) : _code{code} {} - -ExecCommand::ExecCommand(const std::string &code) : FrontendCommand(code) {} - -void ExecCommand::execute(Interpreter &interpreter) { - interpreter.execute(_code); -} - -LoadCommand::LoadCommand(const std::string &code) : FrontendCommand(code) {} - -void LoadCommand::execute(Interpreter &interpreter) { - std::ifstream codeFile(_code, std::ifstream::in); - if (codeFile.is_open()) { - std::stringstream codeBuffer; - codeBuffer << codeFile.rdbuf(); - interpreter.execute(codeBuffer.str()); - codeFile.close(); - } else { - throw "Grace file could not be opened"; - } -} - -PrintCommand::PrintCommand(const std::string &code) : FrontendCommand(code) {} - -void PrintCommand::execute(Interpreter &interpreter) { - interpreter.printResult(_code); -} -} \ No newline at end of file diff --git a/interpreter/src/frontends/FrontendCommand.h b/interpreter/src/frontends/FrontendCommand.h deleted file mode 100644 index 36a03fb..0000000 --- a/interpreter/src/frontends/FrontendCommand.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2016 by Borja Lorente. -// Distributed under the GPLv3 license. -// - -#ifndef NAYLANG_FRONTENDCOMMAND_H -#define NAYLANG_FRONTENDCOMMAND_H - -#include - -namespace naylang { -class FrontendCommand { -protected: - std::string _code; - -public: - FrontendCommand(const std::string &code); - virtual void execute(Interpreter &interpreter) = 0; -}; - -class ExecCommand : public FrontendCommand { -public: - ExecCommand(const std::string &code); - - void execute(Interpreter &interpreter) override; -}; - -class LoadCommand : public FrontendCommand { -public: - LoadCommand(const std::string &code); - - void execute(Interpreter &interpreter) override; -}; - -class PrintCommand : public FrontendCommand { -public: - PrintCommand(const std::string &code); - - void execute(Interpreter &interpreter) override; -}; -} - -#endif //NAYLANG_FRONTENDCOMMAND_H diff --git a/interpreter/src/frontends/modes/ConsoleExecutionMode.cpp b/interpreter/src/frontends/modes/ConsoleExecutionMode.cpp new file mode 100644 index 0000000..57b15ae --- /dev/null +++ b/interpreter/src/frontends/modes/ConsoleExecutionMode.cpp @@ -0,0 +1,24 @@ +// +// Copyright (c) 2017 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include +#include "ConsoleExecutionMode.h" + +namespace naylang { + +FrontendCommand ConsoleExecutionMode::getNextCommand() { + std::string line; + getline(std::cin, line); + auto commandName = getCommandName(line); + auto commandBody = getCommandBody(line); + return FrontendCommand{commandName, commandBody}; +} + +void ConsoleExecutionMode::executeNextCommand() { + _frontend->promptAndRun(); +} +} + + diff --git a/interpreter/src/frontends/modes/ConsoleExecutionMode.h b/interpreter/src/frontends/modes/ConsoleExecutionMode.h new file mode 100644 index 0000000..a48b705 --- /dev/null +++ b/interpreter/src/frontends/modes/ConsoleExecutionMode.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_CONSOLEEXECUTIONMODE_H +#define NAYLANG_CONSOLEEXECUTIONMODE_H + +#include +#include + +namespace naylang { + +class ConsoleFrontend; +class FrontendCommand; +class ConsoleExecutionMode { +protected: + + ConsoleFrontend *_frontend; + +public: + + ConsoleExecutionMode(ConsoleFrontend *frontend) : _frontend{frontend} {} + virtual void prompt() = 0; + virtual void runCommand(const std::string &name, const std::string &body) = 0; + virtual FrontendCommand getNextCommand(); + virtual void executeNextCommand(); + +private: + + std::string getCommandName(const std::string &line) const { + return line.substr(0, line.find(" ")); + } + + std::string getCommandBody(const std::string &line) const { + if (line.find(" ") != -1) { + return std::regex_replace(line.substr(line.find(" ")), std::regex("^ +"), ""); + } else { + return ""; + } + } +}; +} + +#endif //NAYLANG_CONSOLEEXECUTIONMODE_H diff --git a/interpreter/src/frontends/modes/debug/DebugCommand.cpp b/interpreter/src/frontends/modes/debug/DebugCommand.cpp new file mode 100644 index 0000000..94328cd --- /dev/null +++ b/interpreter/src/frontends/modes/debug/DebugCommand.cpp @@ -0,0 +1,44 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include "DebugCommand.h" + +namespace naylang { +void DebugRun::execute(Debugger &debugger) { + debugger.run(); +} + +DebugBreak::DebugBreak(int line) : _line{line} {} + +void DebugBreak::execute(Debugger &debugger) { + debugger.setBreakpoint(_line); +} + +void DebugPrintEnv::execute(Debugger &debugger) { + debugger.printEnvironment(); +} + +DebugPrintExp::DebugPrintExp(const std::string &code) : _code{code} {} + +void DebugPrintExp::execute(Debugger &debugger) { + debugger.printResult(_code); +} + +void DebugContinue::execute(Debugger &debugger) { + debugger.resume(); +} + +void DebugInvalid::execute(Debugger &debugger) { + std::cout << "Command not found, try again" << std::endl; +} + +void DebugStepIn::execute(Debugger &debugger) { + debugger.stepIn(); +} + +void DebugStepOver::execute(Debugger &debugger) { + debugger.stepOver(); +} +} \ No newline at end of file diff --git a/interpreter/src/frontends/modes/debug/DebugCommand.h b/interpreter/src/frontends/modes/debug/DebugCommand.h new file mode 100644 index 0000000..628ba0b --- /dev/null +++ b/interpreter/src/frontends/modes/debug/DebugCommand.h @@ -0,0 +1,64 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + + +#ifndef NAYLANG_DEBUGCOMMAND_H +#define NAYLANG_DEBUGCOMMAND_H + +#include + +namespace naylang { +class Debugger; +class DebugCommand { +public: + virtual void execute(Debugger &debugger) = 0; +}; + +class DebugRun : public DebugCommand { +public: + void execute(Debugger &debugger) override; +}; + +class DebugBreak : public DebugCommand { + int _line; +public: + DebugBreak(int line); + void execute(Debugger &debugger) override; +}; + +class DebugPrintEnv : public DebugCommand { +public: + void execute(Debugger &debugger) override; +}; + +class DebugPrintExp : public DebugCommand { + std::string _code; +public: + DebugPrintExp(const std::string &code); + void execute(Debugger &debugger) override; +}; + +class DebugContinue : public DebugCommand { +public: + void execute(Debugger &debugger) override; +}; + +class DebugInvalid : public DebugCommand { +public: + void execute(Debugger &debugger) override; +}; + +class DebugStepIn : public DebugCommand { +public: + void execute(Debugger &debugger) override; +}; + +class DebugStepOver : public DebugCommand { +public: + void execute(Debugger &debugger) override; +}; +} + +#endif //NAYLANG_DEBUGCOMMAND_H diff --git a/interpreter/src/frontends/modes/debug/DebugMode.cpp b/interpreter/src/frontends/modes/debug/DebugMode.cpp new file mode 100644 index 0000000..c22f6cf --- /dev/null +++ b/interpreter/src/frontends/modes/debug/DebugMode.cpp @@ -0,0 +1,61 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include +#include "DebugMode.h" + +namespace naylang { +DebugMode::DebugMode(ConsoleFrontend *frontend, const std::string &filename) : + ConsoleExecutionMode(frontend) { + readCodeFile(filename); + _debugger = std::make_unique(this, _code); + std::cout << "Debugging file: " << filename << std::endl; +} + +void DebugMode::prompt() { + std::cout << "ndb> "; +} + +void DebugMode::runCommand(const std::string &name, const std::string &body) { + setCommand(name, body); + _command->execute(*_debugger); +} + +void DebugMode::readCodeFile(const std::string &filename) { + std::ifstream codeFile(filename, std::ios_base::in); + if (codeFile.is_open()) { + std::stringstream codeBuffer; + codeBuffer << codeFile.rdbuf(); + _code = codeBuffer.str(); + codeFile.close(); + } else { + throw std::string{"Grace file could not be opened"}; + } +} + +void DebugMode::setCommand(const std::string &name, const std::string &body) { + if (name == "run" || name == "r") { + _command = std::make_unique(); + } else if (name == "break" || name == "b") { + _command = std::make_unique(parseInt(body)); + } else if (name == "env" || name == "e") { + _command = std::make_unique(); + } else if (name == "print" || name == "p") { + _command = std::make_unique(body); + } else if (name == "continue" || name == "c") { + _command = std::make_unique(); + } else if (name == "step" || name == "st") { + _command = std::make_unique(); + } else if (name == "skip" || name == "sk") { + _command = std::make_unique(); + } else { + _command = std::make_unique(); + } +} + +int DebugMode::parseInt(const std::string &raw) { + return std::stoi(raw); +} +} diff --git a/interpreter/src/frontends/modes/debug/DebugMode.h b/interpreter/src/frontends/modes/debug/DebugMode.h new file mode 100644 index 0000000..37ac616 --- /dev/null +++ b/interpreter/src/frontends/modes/debug/DebugMode.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_DEBUGMODE_H +#define NAYLANG_DEBUGMODE_H + +#include +#include +#include +#include +#include "DebugCommand.h" + +namespace naylang { +class Debugger; +class DebugCommand; +class DebugMode : public ConsoleExecutionMode { + std::string _code; + std::unique_ptr _debugger; + std::unique_ptr _command; + +public: + DebugMode(ConsoleFrontend *frontend, const std::string &filename); + + void prompt() override; + void runCommand(const std::string &name, const std::string &body) override; + +private: + + void setCommand(const std::string &name, const std::string &body); + void readCodeFile(const std::string &filename); + int parseInt(const std::string &raw); +}; +} + +#endif //NAYLANG_DEBUGMODE_H diff --git a/interpreter/src/frontends/modes/repl/REPLCommand.cpp b/interpreter/src/frontends/modes/repl/REPLCommand.cpp new file mode 100644 index 0000000..48f70d5 --- /dev/null +++ b/interpreter/src/frontends/modes/repl/REPLCommand.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include "REPLCommand.h" + +namespace naylang { + +REPLCommand::REPLCommand(const std::string &code) : _code{code} {} + +ExecCommand::ExecCommand(const std::string &code) : REPLCommand(code) {} + +void ExecCommand::execute(REPLInterpreter &interpreter) { + interpreter.execute(_code); +} + +LoadCommand::LoadCommand(const std::string &code) : REPLCommand(code) {} + +void LoadCommand::execute(REPLInterpreter &interpreter) { + std::ifstream codeFile(_code, std::ifstream::in); + if (codeFile.is_open()) { + std::stringstream codeBuffer; + codeBuffer << codeFile.rdbuf(); + interpreter.execute(codeBuffer.str()); + codeFile.close(); + } else { + throw std::string{"Grace file could not be opened"}; + } +} + +PrintCommand::PrintCommand(const std::string &code) : REPLCommand(code) {} + +void PrintCommand::execute(REPLInterpreter &interpreter) { + interpreter.printResult(_code); +} +} \ No newline at end of file diff --git a/interpreter/src/frontends/modes/repl/REPLCommand.h b/interpreter/src/frontends/modes/repl/REPLCommand.h new file mode 100644 index 0000000..78db47a --- /dev/null +++ b/interpreter/src/frontends/modes/repl/REPLCommand.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_FRONTENDCOMMAND_H +#define NAYLANG_FRONTENDCOMMAND_H + +#include + +namespace naylang { +class REPLCommand { +protected: + std::string _code; + +public: + REPLCommand(const std::string &code); + virtual void execute(REPLInterpreter &interpreter) = 0; +}; + +class ExecCommand : public REPLCommand { +public: + ExecCommand(const std::string &code); + + void execute(REPLInterpreter &interpreter) override; +}; + +class LoadCommand : public REPLCommand { +public: + LoadCommand(const std::string &code); + + void execute(REPLInterpreter &interpreter) override; +}; + +class PrintCommand : public REPLCommand { +public: + PrintCommand(const std::string &code); + + void execute(REPLInterpreter &interpreter) override; +}; +} + +#endif //NAYLANG_FRONTENDCOMMAND_H diff --git a/interpreter/src/frontends/modes/repl/REPLMode.cpp b/interpreter/src/frontends/modes/repl/REPLMode.cpp new file mode 100644 index 0000000..ddbefd4 --- /dev/null +++ b/interpreter/src/frontends/modes/repl/REPLMode.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#include "REPLMode.h" + +namespace naylang { +REPLMode::REPLMode(ConsoleFrontend *frontend) : + ConsoleExecutionMode(frontend), + _interpreter{std::move(std::make_unique())} {} + +void REPLMode::runCommand(const std::string &name, const std::string &body) { + setCommand(name, body); + _command->execute(*_interpreter); +} + +void REPLMode::setCommand(const std::string &name, const std::string &body) { + if (name == "exec" || name == "e") { + _command = std::make_unique(body); + } else if (name == "load" || name == "l") { + _command = std::make_unique(body); + } else if (name == "print" || name == "p") { + _command = std::make_unique(body); + } else { + throw std::string{"Command not found"}; + } +} + +void REPLMode::prompt() { + std::cout << ">>>> "; +} + +} diff --git a/interpreter/src/frontends/modes/repl/REPLMode.h b/interpreter/src/frontends/modes/repl/REPLMode.h new file mode 100644 index 0000000..13789e0 --- /dev/null +++ b/interpreter/src/frontends/modes/repl/REPLMode.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2016 by Borja Lorente. +// Distributed under the GPLv3 license. +// + +#ifndef NAYLANG_REPLMODE_H +#define NAYLANG_REPLMODE_H + +#include +#include +#include +#include +#include + +namespace naylang { +class REPLMode : public ConsoleExecutionMode { + + std::unique_ptr _command; + std::unique_ptr _interpreter; + + void setCommand(const std::string &name, const std::string &body); + +public: + + REPLMode(ConsoleFrontend *frontend); + void runCommand(const std::string &name, const std::string &body) override; + void prompt() override; +}; +} + +#endif //NAYLANG_REPLMODE_H diff --git a/interpreter/src/main.cpp b/interpreter/src/main.cpp index 721d971..7eaf060 100644 --- a/interpreter/src/main.cpp +++ b/interpreter/src/main.cpp @@ -9,14 +9,11 @@ using namespace naylang; int main() { - std::string command; ConsoleFrontend frontend; - - while (command != "quit") { - std::cout << ">>> "; - getline(std::cin, command); - - frontend.runCommand(command); + try { + frontend.run(); + } catch (std::string msg){ + std::cerr << msg << std::endl; } return 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 61a962a..10b806d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,6 +20,8 @@ FILE(GLOB_RECURSE MODEL_SOURCES ../interpreter/src/core/model/*.cpp) set(SOURCE_FILES ${SOURCE_FILES} ${MODEL_SOURCES}) FILE(GLOB_RECURSE PARSER_SOURCES ../interpreter/src/core/parser/*.cpp) set(SOURCE_FILES ${SOURCE_FILES} ${PARSER_SOURCES}) +FILE(GLOB_RECURSE CONTROL_SOURCES ../interpreter/src/core/control/*.cpp) +set(SOURCE_FILES ${SOURCE_FILES} ${CONTROL_SOURCES}) add_executable(tests ${SOURCE_FILES} ${antlr4cpp_src_files_naylang}) add_dependencies(tests antlr4cpp antlr4cpp_generation_naylang) diff --git a/tests/src/core/model/ast/Statement_test.cpp b/tests/src/core/model/ast/Statement_test.cpp index 0c8d08f..6ab7cdf 100644 --- a/tests/src/core/model/ast/Statement_test.cpp +++ b/tests/src/core/model/ast/Statement_test.cpp @@ -19,8 +19,15 @@ TEST_CASE("Statements", "[AST]") { } SECTION("Statements have coordinates (-1, -1) by default") { - StatementPtr node = make_node(4); + StatementPtr node = make_node(5.0); REQUIRE(node->line() == -1); REQUIRE(node->col() == -1); } + + SECTION("A Statement can be stoppable") { + StatementPtr node = make_node(0.0); + REQUIRE(!node->stoppable()); + node->makeStoppable(); + REQUIRE(node->stoppable()); + } } \ No newline at end of file diff --git a/tests/src/core/model/ast/declarations/VariableDeclaration_test.cpp b/tests/src/core/model/ast/declarations/VariableDeclaration_test.cpp index e8431dc..f979d74 100644 --- a/tests/src/core/model/ast/declarations/VariableDeclaration_test.cpp +++ b/tests/src/core/model/ast/declarations/VariableDeclaration_test.cpp @@ -20,7 +20,7 @@ TEST_CASE("VariableDeclaration Statements", "[Declarations]") { SECTION("A variable declaration can also contain an initial value") { auto name = "y"; - auto five = make_node(5); + auto five = make_node(5.0); VariableDeclaration declareY(name, five); REQUIRE(declareY.name() == "y"); diff --git a/tests/src/core/model/execution/methods/Method_test.cpp b/tests/src/core/model/execution/methods/Method_test.cpp index 58dd5b2..fc031e3 100644 --- a/tests/src/core/model/execution/methods/Method_test.cpp +++ b/tests/src/core/model/execution/methods/Method_test.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "catch.h" @@ -48,7 +47,7 @@ TEST_CASE("Method", "[Methods]") { block->addParameter(make_node("zzz")); // Body ignored for prettyPrint - block->addStatement(make_node(5)); + block->addStatement(make_node(5.0)); Method meth(block); REQUIRE(meth.prettyPrint("two(_,_)things(_)", 0) == "method two(x,y)things(zzz) { }"); } diff --git a/tests/src/core/model/execution/objects/GraceBlock_test.cpp b/tests/src/core/model/execution/objects/GraceBlock_test.cpp index 34a8558..5d98c38 100644 --- a/tests/src/core/model/execution/objects/GraceBlock_test.cpp +++ b/tests/src/core/model/execution/objects/GraceBlock_test.cpp @@ -4,6 +4,8 @@ // #include +#include +#include #include "catch.h" using namespace naylang; diff --git a/tests/src/core/model/execution/objects/GraceClosure_test.cpp b/tests/src/core/model/execution/objects/GraceClosure_test.cpp index 79eb0e4..3f66a66 100644 --- a/tests/src/core/model/execution/objects/GraceClosure_test.cpp +++ b/tests/src/core/model/execution/objects/GraceClosure_test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "catch.h" using namespace naylang; diff --git a/tests/src/core/model/execution/objects/GraceIterable_test.cpp b/tests/src/core/model/execution/objects/GraceIterable_test.cpp index f0b4a41..f36229b 100644 --- a/tests/src/core/model/execution/objects/GraceIterable_test.cpp +++ b/tests/src/core/model/execution/objects/GraceIterable_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "catch.h" diff --git a/tests/src/core/model/execution/objects/GraceNumber_test.cpp b/tests/src/core/model/execution/objects/GraceNumber_test.cpp index 09220d2..7b64b07 100644 --- a/tests/src/core/model/execution/objects/GraceNumber_test.cpp +++ b/tests/src/core/model/execution/objects/GraceNumber_test.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include "catch.h" using namespace naylang; diff --git a/tests/src/core/model/execution/objects/UserObject_test.cpp b/tests/src/core/model/execution/objects/UserObject_test.cpp index 7b6bd65..37944e2 100644 --- a/tests/src/core/model/execution/objects/UserObject_test.cpp +++ b/tests/src/core/model/execution/objects/UserObject_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "catch.h" using namespace naylang; @@ -17,7 +18,7 @@ TEST_CASE("Grace User-defined object", "[GraceObjects]") { TEST_CASE("UserObject common utils", "[UserObject]") { SECTION("Calling prettyPrint on a UserObject a list of the fields and userMethods in brackets") { UserObject usr; - usr.setField("x", make_obj(5)); + usr.setField("x", make_obj(5.0)); auto param = make_node("n"); std::vector params{param}; std::vector body{}; diff --git a/tests/src/core/parser/NaylangParserVisitor_test.cpp b/tests/src/core/parser/NaylangParserVisitor_test.cpp index 9397856..2feb158 100644 --- a/tests/src/core/parser/NaylangParserVisitor_test.cpp +++ b/tests/src/core/parser/NaylangParserVisitor_test.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include using namespace naylang; @@ -39,8 +39,8 @@ TEST_CASE("Naylang Parser Visitor", "[Parser]") { auto request = static_cast(*(AST[0])); auto receiver = static_cast(*request.receiver()); - REQUIRE_NOTHROW(request.identifier() == "prefix-"); - REQUIRE_NOTHROW(receiver.value() == 4); + REQUIRE(request.identifier() == "prefix-"); + REQUIRE(receiver.value() == 4); } SECTION("Parsing 4 + 5 * 6 create the explicit request 4.+(5.*(6))") { @@ -51,11 +51,11 @@ TEST_CASE("Naylang Parser Visitor", "[Parser]") { auto five = static_cast(*subrequest.receiver()); auto six = static_cast(*subrequest.params()[0]); - REQUIRE_NOTHROW(request.identifier() == "+(_)"); - REQUIRE_NOTHROW(four.value() == 4); - REQUIRE_NOTHROW(subrequest.identifier() == "*(_)"); - REQUIRE_NOTHROW(five.value() == 5); - REQUIRE_NOTHROW(six.value() == 6); + REQUIRE(request.identifier() == "+(_)"); + REQUIRE(four.value() == 4); + REQUIRE(subrequest.identifier() == "*(_)"); + REQUIRE(five.value() == 5); + REQUIRE(six.value() == 6); } } @@ -63,18 +63,17 @@ TEST_CASE("Naylang Parser Visitor", "[Parser]") { TEST_CASE("Primitives", "[Naylang Parser Visitor]") { SECTION("Parsing an integer creates a NumberLiteral") { auto AST = translate("4\n;"); - REQUIRE_NOTHROW(dynamic_cast(*(AST[0]))); - REQUIRE_NOTHROW(dynamic_cast(*(AST[0])).value() == 4); + REQUIRE(dynamic_cast(*(AST[0])).value() == 4); } SECTION("Parsing a string in between quotes generates a StringLiteral") { auto AST = translate("\"Hello\";\n"); - REQUIRE_NOTHROW(dynamic_cast(*(AST[0])).value() == "Hello"); + REQUIRE(dynamic_cast(*(AST[0])).value() == "Hello"); } SECTION("Parsing a boolean generates a BooleanLiteral") { auto AST = translate("true;\n"); - REQUIRE_NOTHROW(dynamic_cast(*(AST[0])).value()); + REQUIRE(dynamic_cast(*(AST[0])).value()); } } @@ -167,7 +166,6 @@ TEST_CASE("Declarations", "[Naylang Parser Visitor]") { auto AST = translate("def x = 5;"); auto decl = static_cast(*(AST[0])); auto value = static_cast(*decl.value()); - REQUIRE_NOTHROW(static_cast(*(AST[0]))); REQUIRE(decl.name() == "x"); REQUIRE(value.value() == 5); } @@ -176,7 +174,6 @@ TEST_CASE("Declarations", "[Naylang Parser Visitor]") { auto AST = translate("var x := 5;"); auto decl = static_cast(*(AST[0])); auto value = static_cast(*decl.value()); - REQUIRE_NOTHROW(static_cast(*(AST[0]))); REQUIRE(decl.name() == "x"); REQUIRE(value.value() == 5); } @@ -271,6 +268,44 @@ TEST_CASE("Code Coordinates", "[Naylang Parser Visitor]") { } } +TEST_CASE("Stoppable nodes", "[Naylang Parser Visitor]") { + SECTION("Variable Declarations are stoppable") { + auto AST = translate("var x := 4;\n"); + auto x = static_cast(*(AST[0])); + REQUIRE(x.stoppable()); + } + + SECTION("Constant Declarations are stoppable") { + auto AST = translate("def x = 4;\n"); + auto x = static_cast(*(AST[0])); + REQUIRE(x.stoppable()); + } + + SECTION("Every line inside a MethodDeclaration is stoppable") { + auto AST = translate("method twice(n,m) { var x := 4; x * m; }\n"); + auto meth = static_cast(*(AST[0])); + for (auto line : meth.body()) { + REQUIRE(line->stoppable()); + } + } + + SECTION("Every line inside a Prefix method is stoppable") { + auto AST = translate("method prefix! { var x := 4; var m := -1; x * m; }\n"); + auto meth = static_cast(*(AST[0])); + for (auto line : meth.body()) { + REQUIRE(line->stoppable()); + } + } + + SECTION("Every line inside a Block is stoppable") { + auto AST = translate("{ x, m -> var x := 4; x * m; };\n"); + auto block = static_cast(*(AST[0])); + for (auto line : block.body()) { + REQUIRE(line->stoppable()); + } + } +} + GraceAST translate(std::string line) { ANTLRInputStream stream(line); GraceLexer lexer(&stream);