Skip to content

Commit

Permalink
Added break and continue
Browse files Browse the repository at this point in the history
  • Loading branch information
cdoucy committed Oct 29, 2023
1 parent b2ab059 commit 1723fa6
Show file tree
Hide file tree
Showing 22 changed files with 313 additions and 24 deletions.
17 changes: 17 additions & 0 deletions inc/ast/nodes/BreakNode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "StatementNode.hpp"

namespace ast
{
class BreakNode final : public StatementNode
{
public:
using ptr = std::shared_ptr<BreakNode>;
static ptr create();
BreakNode() = default;
~BreakNode() final = default;

void accept(IVisitor &visitor) final;
};
}
17 changes: 17 additions & 0 deletions inc/ast/nodes/ContinueNode.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "StatementNode.hpp"

namespace ast
{
class ContinueNode final : public StatementNode
{
public:
using ptr = std::shared_ptr<ContinueNode>;
static ptr create();
ContinueNode() = default;
~ContinueNode() final = default;

void accept(IVisitor &visitor) final;
};
}
7 changes: 6 additions & 1 deletion inc/ast/visitors/EvalVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include "ReturnNode.hpp"
#include "CallNode.hpp"

#include "BreakNode.hpp"
#include "ContinueNode.hpp"

#include "ProgramNode.hpp"

#include "State.hpp"
Expand Down Expand Up @@ -59,6 +62,9 @@ namespace ast
void visit(CallNode &node) final;
void visit(ReturnNode &node) final;

void visit(BreakNode &node) final;
void visit(ContinueNode &node) final;

void visit(ProgramNode &node) final;

[[nodiscard]] const runtime::Object &value() const noexcept;
Expand All @@ -73,7 +79,6 @@ namespace ast
runtime::Object _expressionResult;
runtime::State::ptr _globalState;
runtime::State::ptr _localState;
bool _isExecutingCall;

const runtime::Object &evaluate(const ast::ExpressionNode::ptr &expr);

Expand Down
6 changes: 6 additions & 0 deletions inc/ast/visitors/IVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ namespace ast
class CallNode;
class ReturnNode;

class BreakNode;
class ContinueNode;

class ProgramNode;

class IVisitor
Expand Down Expand Up @@ -52,6 +55,9 @@ namespace ast
virtual void visit(CallNode &node) = 0;
virtual void visit(ReturnNode &node) = 0;

virtual void visit(BreakNode &node) = 0;
virtual void visit(ContinueNode &node) = 0;

virtual void visit(ProgramNode &node) = 0;
};
}
2 changes: 2 additions & 0 deletions inc/parser/Parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class Parser
ast::StatementNode::ptr parseAssignmentStatement();
ast::StatementNode::ptr parseIncrementStatement();
ast::StatementNode::ptr parseReturnStatement();
ast::StatementNode::ptr parseBreakStatement();
ast::StatementNode::ptr parseContinueStatement();
ast::DeclarationNode::ptr parseDeclaration();
ast::AssignmentNode::ptr parseAssignment();
ast::IncrementNode::ptr parseIncrement();
Expand Down
12 changes: 12 additions & 0 deletions inc/runtime/Break.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include "Jump.hpp"

namespace runtime
{
class Break : public Jump
{
public:
Break();
};
};
12 changes: 12 additions & 0 deletions inc/runtime/Continue.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include "Jump.hpp"

namespace runtime
{
class Continue : public Jump
{
public:
Continue();
};
};
18 changes: 18 additions & 0 deletions inc/runtime/Jump.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include <exception>
#include <string>

namespace runtime
{
class Jump : public std::exception
{
public:
Jump(const std::string &jumpStatement, const std::string &appropriatePlace) noexcept;

[[nodiscard]] const char *what() const noexcept override;

private:
std::string _what;
};
};
4 changes: 2 additions & 2 deletions inc/runtime/Return.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#pragma once

#include <exception>
#include <optional>

#include "Jump.hpp"
#include "Object.hpp"

namespace runtime
{
class Return : public std::exception
class Return : public Jump
{
public:
explicit Return(std::optional<Object> object) noexcept;
Expand Down
2 changes: 0 additions & 2 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ void runFileMode(const std::string &filePath)

int main(int ac, char **av)
{
for (int i = 0; i < 10; i++) continue;

try {
if (ac < 2)
runInteractiveMode();
Expand Down
11 changes: 11 additions & 0 deletions src/ast/nodes/BreakNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "BreakNode.hpp"

ast::BreakNode::ptr ast::BreakNode::create()
{
return std::make_shared<BreakNode>();
}

void ast::BreakNode::accept(ast::IVisitor &visitor)
{
visitor.visit(*this);
}
11 changes: 11 additions & 0 deletions src/ast/nodes/ContinueNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "ContinueNode.hpp"

ast::ContinueNode::ptr ast::ContinueNode::create()
{
return std::make_shared<ContinueNode>();
}

void ast::ContinueNode::accept(ast::IVisitor &visitor)
{
visitor.visit(*this);
}
53 changes: 39 additions & 14 deletions src/ast/visitors/EvalVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "EvalVisitor.hpp"
#include "Return.hpp"
#include "Break.hpp"
#include "Continue.hpp"

#define OPERATOR_FUNCTION(type, op) {type, [](const auto &l, const auto &r){return l op r;}}

Expand Down Expand Up @@ -154,8 +156,13 @@ void ast::EvalVisitor::visit(ast::BlockNode &node)
{
this->_localState = runtime::State::create(this->_localState);

for (const auto &stmt : node.getStatements()) {
stmt->accept(*this);
try {
for (const auto &stmt: node.getStatements()) {
stmt->accept(*this);
}
} catch (const LogicalError &err) {
this->_localState = this->_localState->restoreParent();
throw err;
}

this->_localState = this->_localState->restoreParent();
Expand Down Expand Up @@ -205,8 +212,13 @@ void ast::EvalVisitor::visit(ast::WhileNode &node)
auto obj = this->evaluate(node.getExpression());

while (obj) {
if (stmt)
stmt->accept(*this);
try {
if (stmt)
stmt->accept(*this);
} catch (const runtime::Break &_) {
break;
} catch (const runtime::Continue &_) {
}

obj = this->evaluate(node.getExpression());
}
Expand Down Expand Up @@ -237,8 +249,14 @@ void ast::EvalVisitor::visit(ast::ForNode &node)
}

while (this->evaluate(expr)) {
if (stmt)
stmt->accept(*this);

try {
if (stmt)
stmt->accept(*this);
} catch (const runtime::Break &_) {
break;
} catch (const runtime::Continue &_) {
}

if (step)
step->accept(*this);
Expand Down Expand Up @@ -302,13 +320,10 @@ void ast::EvalVisitor::visit(ast::CallNode &node)
auto originalState = std::move(this->_localState);
this->_localState = state;
bool hasReturned = false;
bool previousExecCall = this->_isExecutingCall;
this->_isExecutingCall = true;

try {
function.getBlock()->accept(*this);
} catch (const runtime::Return &ret) {
this->_isExecutingCall = previousExecCall;
this->_localState = std::move(originalState);
originalState = nullptr;

Expand All @@ -324,10 +339,11 @@ void ast::EvalVisitor::visit(ast::CallNode &node)

} else if (function.getReturnType() != Token::VOID_TYPE)
throw invalidReturnType(Token::Type::VOID_TYPE, function.getReturnType());
} catch (const LogicalError &err) {
this->_localState = std::move(originalState);
throw err;
}

this->_isExecutingCall = previousExecCall;

if (!hasReturned && function.getReturnType() != Token::VOID_TYPE)
throw missingReturn(function.getReturnType());

Expand All @@ -337,9 +353,6 @@ void ast::EvalVisitor::visit(ast::CallNode &node)

void ast::EvalVisitor::visit(ast::ReturnNode &node)
{
if (!this->_isExecutingCall)
throw LogicalError("return statement used outside of a function");

std::optional<runtime::Object> returnedObject;

if (node.getExpression())
Expand All @@ -348,6 +361,18 @@ void ast::EvalVisitor::visit(ast::ReturnNode &node)
throw runtime::Return(returnedObject);
}

void ast::EvalVisitor::visit(ast::BreakNode &_)
{
(void)_;
throw runtime::Break();
}

void ast::EvalVisitor::visit(ast::ContinueNode &_)
{
(void)_;
throw runtime::Continue();
}

LogicalError ast::EvalVisitor::invalidArgType(std::string paramName, Token::Type actualType, Token::Type expectedType) {
return LogicalError(fmt::format(
"invalid type in call : {} is of type {} but expected type {}",
Expand Down
12 changes: 10 additions & 2 deletions src/evaluator/Evaluator.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
#include "Evaluator.hpp"
#include "Break.hpp"
#include "Continue.hpp"

void Evaluator::feed(const std::string &expression)
{
this->_parser.feed(expression);

auto root = this->_parser.getAstRoot();

if (root)
root->accept(this->_evalVisitor);
if (root) {

try {
root->accept(this->_evalVisitor);
} catch (const runtime::Jump &jump) {
throw LogicalError(jump.what());
}
}

this->_parser.clear();
}
Expand Down
4 changes: 3 additions & 1 deletion src/lexer/lexProgrammingWord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ static const std::unordered_map<std::string, Token::Type> keywordsTable{
{"else", Token::ELSE},
{"for", Token::FOR},
{"fnc", Token::FNC},
{"return", Token::RETURN}
{"return", Token::RETURN},
{"break", Token::BREAK},
{"continue", Token::CONTINUE}
};

bool Lexer::lexProgrammingWord(std::string::const_iterator &begin)
Expand Down
34 changes: 33 additions & 1 deletion src/parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ ast::StatementNode::ptr Parser::parseStatement()
&Parser::parseWhile,
&Parser::parseConditions,
&Parser::parseFor,
&Parser::parseReturnStatement
&Parser::parseReturnStatement,
&Parser::parseBreakStatement,
&Parser::parseContinueStatement
};

for (const auto &parse: statementsParser) {
Expand Down Expand Up @@ -138,6 +140,36 @@ ast::StatementNode::ptr Parser::parseReturnStatement()
return stmt;
}

ast::StatementNode::ptr Parser::parseBreakStatement()
{
auto token = this->_tokenItr.get();
if (!token || !token->isType(Token::BREAK))
return nullptr;
this->_tokenItr.advance();

token = this->_tokenItr.get();
if (!token || !token->isType(Token::SEMICOLON))
throw syntaxError("expecting \";\"", *this->_tokenItr.prev());
this->_tokenItr.advance();

return ast::BreakNode::create();
}

ast::StatementNode::ptr Parser::parseContinueStatement()
{
auto token = this->_tokenItr.get();
if (!token || !token->isType(Token::CONTINUE))
return nullptr;
this->_tokenItr.advance();

token = this->_tokenItr.get();
if (!token || !token->isType(Token::SEMICOLON))
throw syntaxError("expecting \";\"", *this->_tokenItr.prev());
this->_tokenItr.advance();

return ast::ContinueNode::create();
}

ast::IncrementNode::ptr Parser::parseIncrement()
{
auto token = this->_tokenItr.get();
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/Break.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "Break.hpp"

runtime::Break::Break()
: Jump("break", "loop")
{}
Loading

0 comments on commit 1723fa6

Please sign in to comment.