diff --git a/src/include/interpreter.h b/src/include/interpreter.h index 0a119cd..2dec731 100644 --- a/src/include/interpreter.h +++ b/src/include/interpreter.h @@ -12,4 +12,20 @@ using namespace std; */ EvalResult eval(Node &ast, Memory& memory); +class BreakException : public runtime_error { +public: + explicit BreakException(const string& message, CodePosition pos) + : runtime_error(message), pos(pos) {} + + const CodePosition pos; +}; + +class ContinueException : public runtime_error { +public: + explicit ContinueException(const string& message, CodePosition pos) + : runtime_error(message), pos(pos) {} + + const CodePosition pos; +}; + #endif \ No newline at end of file diff --git a/src/include/types.h b/src/include/types.h index b7fa25b..7b3fbb9 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -12,7 +12,7 @@ using namespace std; /** * Tokens definition */ -enum class TokenType { Identifier, Litteral, Plus, Minus, DoublePlus, DoubleMinus, DoubleEqual, Land, Lor, Lt, Gt, Leq, Geq, NotEqual, Not, Star, Slash, Percent, Equal, Semicolon, LParenthese, RParenthese, LCurlyBracket, RCurlyBracket, If, Else, While, For, Comma }; +enum class TokenType { Identifier, Litteral, Plus, Minus, DoublePlus, DoubleMinus, DoubleEqual, Land, Lor, Lt, Gt, Leq, Geq, NotEqual, Not, Star, Slash, Percent, Equal, Semicolon, LParenthese, RParenthese, LCurlyBracket, RCurlyBracket, If, Else, While, For, Break, Continue, Comma }; enum class Type { Int, Double }; using TokenData = variant; diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 268de7d..c42448d 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -79,7 +79,11 @@ EvalResult eval(Node &ast, Memory &memory) { int cond = bool_cast(eval(node.children[0], memory)); if (!cond) break; - eval(node.children[1], memory); + try { + eval(node.children[1], memory); + } + catch (const BreakException& e) { break; } + catch (const ContinueException& e) {} } return {}; @@ -87,24 +91,48 @@ EvalResult eval(Node &ast, Memory &memory) { case NodeType::For: { memory.add_scope(ScopeType::For); - eval(node.children[0], memory); + try { + eval(node.children[0], memory); - while (true) { - int cond = bool_cast(eval(node.children[1], memory)); - if (!cond) break; + while (true) { + int cond = bool_cast(eval(node.children[1], memory)); + if (!cond) break; - eval(node.children[3], memory); - eval(node.children[2], memory); + try { + eval(node.children[3], memory); + } + catch (const BreakException& e) { break; } + catch (const ContinueException& e) {} + + eval(node.children[2], memory); + } + + memory.remove_scope(); } + catch (...) { + memory.remove_scope(); - memory.remove_scope(); + exception_ptr e = current_exception(); + if (e) rethrow_exception(e); + } return {}; } break; case NodeType::Bloc: { memory.add_scope(ScopeType::Block); - eval(node.children[0], memory); - memory.remove_scope(); + + try { + eval(node.children[0], memory); + + memory.remove_scope(); + } + catch (...) { + memory.remove_scope(); + + exception_ptr e = current_exception(); + if (e) rethrow_exception(e); + } + return {}; } break; case NodeType::Eq: { @@ -393,6 +421,12 @@ EvalResult eval(Node &ast, Memory &memory) { return var.value; } break; + case TokenType::Break: { + throw BreakException("", token.pos); + } break; + case TokenType::Continue: { + throw ContinueException("", token.pos); + } break; default: throw exception(); break; diff --git a/src/tokenize.cpp b/src/tokenize.cpp index 257f4b9..cc113fe 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -14,6 +14,8 @@ vector> simpleTokens = { { "else", TokenType::Else }, { "while", TokenType::While }, { "for", TokenType::For }, + { "break", TokenType::Break }, + { "continue", TokenType::Continue }, { "++", TokenType::DoublePlus }, { "--", TokenType::DoubleMinus }, { "==", TokenType::DoubleEqual }, @@ -77,6 +79,9 @@ string _debug_get_token_type_name(TokenType type) { case TokenType::Else: return "Else"; case TokenType::While: return "While"; case TokenType::For: return "For"; + case TokenType::Break: return "Break"; + case TokenType::Continue: return "Continue"; + case TokenType::Comma: return "Comma"; default: return "Unknown"; } } @@ -172,6 +177,12 @@ void _debug_print_token(Token token) { case TokenType::For: cout << "For"; break; + case TokenType::Break: + cout << "Break"; + break; + case TokenType::Continue: + cout << "Continue"; + break; case TokenType::Comma: cout << "Comma"; break; diff --git a/test/tokenize.cpp b/test/tokenize.cpp index f799e5f..8063ae3 100644 --- a/test/tokenize.cpp +++ b/test/tokenize.cpp @@ -11,7 +11,7 @@ int main() { /* All tokens */ vector inputs = { - "int", "a", "=", "x", "++", "--", "==", "&&", "||", "<", ">", "<=", ">=", "!=", "!", "*", "/", "%", "=", ";", "(", ")", "{", "}", "if", "else", "while", "for", "," + "int", "a", "=", "x", "++", "--", "==", "&&", "||", "<", ">", "<=", ">=", "!=", "!", "*", "/", "%", "=", ";", "(", ")", "{", "}", "if", "else", "while", "for", "break", "continue", "," }; vector expectedTypes = { @@ -21,7 +21,7 @@ int main() { TokenType::Not, TokenType::Star, TokenType::Slash, TokenType::Percent, TokenType::Equal, TokenType::Semicolon, TokenType::LParenthese, TokenType::RParenthese, TokenType::LCurlyBracket, TokenType::RCurlyBracket, TokenType::If, TokenType::Else, TokenType::While, TokenType::For, - TokenType::Comma + TokenType::Break, TokenType::Continue, TokenType::Comma }; for (size_t i = 0; i < inputs.size(); i++) {