diff --git a/src/errors.cpp b/src/errors.cpp index 139286c..54bd83c 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -35,6 +35,7 @@ string UserError::get_message(void) const { case ErrorType::ModuloByZero: return "Modulo by 0"; case ErrorType::BreakNotWithinLoop: return "Break statement not within loop"; case ErrorType::ContinueNotWithinLoop: return "Continue statement not within loop"; + case ErrorType::ControlReachesEndOfNonVoidFn: return "Control reaches end of non-void function"; default: return "Unknown error type"; } } diff --git a/src/include/errors.h b/src/include/errors.h index 04c7c5a..91438cc 100644 --- a/src/include/errors.h +++ b/src/include/errors.h @@ -45,6 +45,7 @@ enum class ErrorType { ModuloByZero, BreakNotWithinLoop, ContinueNotWithinLoop, + ControlReachesEndOfNonVoidFn }; using ErrorData = variant; diff --git a/src/include/interpreter.h b/src/include/interpreter.h index 49eff90..3f7ca87 100644 --- a/src/include/interpreter.h +++ b/src/include/interpreter.h @@ -25,4 +25,12 @@ public: : InternalError(pos) {} }; +class ReturnException : public InternalError { +public: + EvalResult val; + + explicit ReturnException(EvalResult val) + : InternalError(), val(val) {} +}; + #endif \ No newline at end of file diff --git a/src/include/memory.h b/src/include/memory.h index 0f56a75..5175fc5 100644 --- a/src/include/memory.h +++ b/src/include/memory.h @@ -17,7 +17,7 @@ class Memory { MemoryVar& get(string identifier); Scope& get_function_scope(void); - void declare(string identifier, Type type, CodePosition pos); + void declare(string identifier, Type type, CodePosition pos = { }); void update(string identifier, EvalResult value); Scope& _debug_top(void); diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 84107ef..5c30bb4 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -42,6 +42,16 @@ double double_cast(EvalResult value) { } } +EvalResult cast_from_type(Type type, EvalResult val) { + switch (type.type) { + case TypeType::Int: return int_cast(val); + case TypeType::Double: return double_cast(val); + case TypeType::Void: return {}; + default: + throw exception(); + } +} + EvalResult eval(Node &ast, Memory &memory) { if (holds_alternative(ast)) { InnerNode node = get(ast); @@ -139,12 +149,12 @@ EvalResult eval(Node &ast, Memory &memory) { } break; case NodeType::FunctionPrototype: { Token retTypeTok = get(node.children[0]); - Token fnIdentifierTok = get(node.children[1]); - string fnIdentifier = get(fnIdentifierTok.data); + Token identifierTok = get(node.children[1]); + string identifier = get(identifierTok.data); FunctionPrototype prototype = make_fn_prototype(node); - memory.declare(fnIdentifier, { + memory.declare(identifier, { .type = TypeType::Function, .data = prototype }, retTypeTok.pos); @@ -153,25 +163,61 @@ EvalResult eval(Node &ast, Memory &memory) { } break; case NodeType::FunctionDeclaration: { Token retTypeTok = get(node.children[0]); - Token fnIdentifierTok = get(node.children[1]); - string fnIdentifier = get(fnIdentifierTok.data); + Token identifierTok = get(node.children[1]); + string identifier = get(identifierTok.data); FunctionPrototype prototype = make_fn_prototype(node); - memory.declare(fnIdentifier, { + memory.declare(identifier, { .type = TypeType::Function, .data = prototype }, retTypeTok.pos); - memory.update(fnIdentifier, node.children[3]); + memory.update(identifier, node.children[3]); return {}; } break; case NodeType::FunctionCall: { - memory.add_scope(ScopeType::Function); + Token identifierTok = get(node.children[0]); + string identifier = get(identifierTok.data); + vector args = get(node.children[1]).children; + + MemoryVar& var = memory.get(identifier); + + if (!var.initialized) + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); + + vector argValues = {}; + for (Node arg : args) { + argValues.push_back(eval(arg, memory)); + } + + FunctionPrototype prototype = get(var.type.data); + + EvalResult res = {}; + + memory.add_scope(ScopeType::Function, identifierTok.pos, &var); try { - + for (size_t i = 1; i < prototype.size(); i++) { + tuple argDef = prototype[i]; + Type argType = get<0>(argDef); + string argName = get<1>(argDef); + memory.declare(argName, argType); + memory.update(argName, cast_from_type(argType, argValues[i - 1])); + } + + try { + eval(get(var.value), memory); + + // Tmp: no flow control + if (get<0>(prototype[0]).type != TypeType::Void) { + throw RuntimeError(ErrorType::ControlReachesEndOfNonVoidFn, identifierTok.pos); + } + } + catch (const ReturnException& e) { + res = e.val; + } memory.remove_scope(); } @@ -181,6 +227,11 @@ EvalResult eval(Node &ast, Memory &memory) { exception_ptr e = current_exception(); if (e) rethrow_exception(e); } + + return cast_from_type(get<0>(prototype[0]), res); + } break; + case NodeType::Return: { + throw ReturnException(eval(node.children[0], memory)); } break; case NodeType::Eq: { EvalResult e1 = eval(node.children[0], memory); diff --git a/src/memory.cpp b/src/memory.cpp index 053bd00..bb6c306 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -50,6 +50,7 @@ Scope& Memory::get_function_scope(void) { if (scope.type == ScopeType::Function) return scope; } + // Tmp: no flow control throw InternalError(); }