diff --git a/src/include/interpreter.h b/src/include/interpreter.h index 02b895d..a95aeee 100644 --- a/src/include/interpreter.h +++ b/src/include/interpreter.h @@ -6,12 +6,22 @@ #include using namespace std; -using EvalResult = variant; +#include "tokenize.h" + +using EvalResult = variant; + +struct MemoryEntry { + EvalResult value { }; + bool assigned { false }; + Type type; +}; class RuntimeError : public runtime_error { public: - explicit RuntimeError(const string& message) - : runtime_error(message) {} + explicit RuntimeError(const string& message, CodePosition pos) + : runtime_error(message), pos(pos) {} + + const CodePosition pos; }; /* diff --git a/src/include/tokenize.h b/src/include/tokenize.h index b0cfd36..6793636 100644 --- a/src/include/tokenize.h +++ b/src/include/tokenize.h @@ -25,8 +25,10 @@ struct Token { class TokenError : public runtime_error { public: - explicit TokenError(const string& message) - : runtime_error(message) {} + explicit TokenError(const string& message, CodePosition pos) + : runtime_error(message), pos(pos) {} + + const CodePosition pos; }; /* diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 55ce148..e682955 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -6,7 +6,7 @@ #include "include/interpreter.h" using namespace std; -unordered_map memory; +unordered_map memory; EvalResult eval(Node &ast) { if (ast.index() == 0) { @@ -37,13 +37,13 @@ EvalResult eval(Node &ast) { case NodeType::Div: { int e1 = get(eval(node.children[0])); int e2 = get(eval(node.children[1])); - if (e2 == 0) throw RuntimeError("Division by 0"); + if (e2 == 0) throw RuntimeError("Division by 0", node.pos); return e1 / e2; } break; case NodeType::Mod: { int e1 = get(eval(node.children[0])); int e2 = get(eval(node.children[1])); - if (e2 == 0) throw RuntimeError("Modulo by 0"); + if (e2 == 0) throw RuntimeError("Modulo by 0", node.pos); return e1 % e2; } break; case NodeType::UnaryPlus: { @@ -57,44 +57,92 @@ EvalResult eval(Node &ast) { case NodeType::Declaration: { Token typeTok = get(node.children[0]); Token identifierTok = get(node.children[1]); + Type type = get(typeTok.data); string identifier = get(identifierTok.data); - memory[identifier] = 0; + memory[identifier] = { + .type = type + }; return {}; } break; case NodeType::AssignedDeclaration: { Token typeTok = get(node.children[0]); Token identifierTok = get(node.children[1]); + Type type = get(typeTok.data); string identifier = get(identifierTok.data); - int expr = get(eval(node.children[2])); + EvalResult expr = eval(node.children[2]); - memory[identifier] = expr; + memory[identifier] = { + .value = expr, + .assigned = true, + .type = type, + }; return expr; } break; case NodeType::Assignment: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - int expr = get(eval(node.children[1])); + EvalResult expr = eval(node.children[1]); - memory[identifier] = expr; + if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + + memory[identifier].value = expr; return expr; } break; - case NodeType::LIncr: + case NodeType::LIncr: { + Token identifierTok = get(node.children[0]); + string identifier = get(identifierTok.data); + + if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + + if (memory[identifier].type == Type::Int) { + memory[identifier].value = get(memory[identifier].value) + 1; + } + + return memory[identifier].value; + } case NodeType::RIncr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - return node.type == NodeType::LIncr ? ++memory[identifier] : memory[identifier]++; + if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + + if (memory[identifier].type == Type::Int) { + EvalResult res = memory[identifier].value; + memory[identifier].value = get(memory[identifier].value) + 1; + return res; + } + + return memory[identifier].value; + } + case NodeType::LDecr: { + Token identifierTok = get(node.children[0]); + string identifier = get(identifierTok.data); + + if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + + if (memory[identifier].type == Type::Int) { + memory[identifier].value = get(memory[identifier].value) - 1; + } + + return memory[identifier].value; } - case NodeType::LDecr: case NodeType::RDecr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - return node.type == NodeType::LDecr ? --memory[identifier] : memory[identifier]--; + if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + + if (memory[identifier].type == Type::Int) { + EvalResult res = memory[identifier].value; + memory[identifier].value = get(memory[identifier].value) - 1; + return res; + } + + return memory[identifier].value; } } } @@ -106,8 +154,10 @@ EvalResult eval(Node &ast) { } break; case TokenType::Identifier: { string identifier = get(token.data); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier"); - return memory[identifier]; + + if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", token.pos); + + return memory[identifier].value; } break; default: throw; diff --git a/src/tokenize.cpp b/src/tokenize.cpp index 75726ef..d7f33e7 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -162,7 +162,7 @@ vector tokenize(vector input) { j += 1; } else { - throw TokenError("Unknown token {}"); + throw TokenError("Unknown token {}", pos); } } }