From f7f397224804a4f428f06d374aeffc8d736fa4bf Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Fri, 22 Aug 2025 13:52:26 +1000 Subject: [PATCH] Function arguments, start of scoping --- src/main.cpp | 121 ++++++++++++++++++++++++++++++++----------- tests/functions.grnd | 4 ++ 2 files changed, 95 insertions(+), 30 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 771326a..a992cf8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,13 +239,18 @@ struct Instruction { vector> args; }; +struct FnArg { + Direct ref; + Types type; +}; + /* Function struct Contains information needed to run a Ground function. */ struct Function { Types returnType; - vector> args; + vector args; vector instructions; }; @@ -263,9 +268,9 @@ vector fnArgs; /* localArgStack stack - Contains the variables in a scope + This keeps track of all the local arguments in functions that are being called. */ -stack> localArgStack; +stack> localArgStack; /* error function @@ -376,6 +381,21 @@ Types getType(string in) { return Types::Int; } +/* + getLitType function + This function determines the type of a value inside a Literal based on the + holds_alternative() function. Returns a type from the Types enum class. +*/ +Types getLitType(Literal in) { + if (holds_alternative(in.val)) return Types::Int; + if (holds_alternative(in.val)) return Types::Double; + if (holds_alternative(in.val)) return Types::Bool; + if (holds_alternative(in.val)) return Types::String; + if (holds_alternative(in.val)) return Types::Char; + error("Literal for some reason has a weird type. This is not an issue with your program, but an issue with the Ground interpreter."); + return Types::Int; +} + bool processingFunction = false; string procFnName = ""; @@ -1473,7 +1493,7 @@ Literal exec(vector in) { } { Function newFunction; - + if (holds_alternative(l.args[0])) { newFunction.returnType = get(l.args[0]).type; } else { @@ -1481,38 +1501,38 @@ Literal exec(vector in) { } string fnName; - + if (holds_alternative(l.args[1])) { fnName = get(l.args[1]).fnName; } else { error("Second argument of function must be a function reference"); } - Types argType; - Direct ref; - bool expectingType = true; - for (int m = 2; m < l.args.size(); m++) { - if (expectingType) { - if (holds_alternative(l.args[m])) { - argType = get(l.args[m]).type; - } else { - error("Functions expect a type reference, then a direct reference. Missing a type reference."); - } - } else { - if (holds_alternative(l.args[m])) { - ref = get(l.args[m]); - } else { - error("Functions expect a type reference, then a direct reference. Missing a direct reference."); - } - newFunction.args.push_back(pair(ref, argType)); - } - expectingType = !expectingType; - } - - if (!expectingType) { - error("Incomplete function definition, expecting a direct reference after type reference"); + // Parse function arguments (type-direct pairs) + if ((l.args.size() - 2) % 2 != 0) { + error("Function arguments must be in type-direct pairs"); } + for (int m = 2; m < l.args.size(); m += 2) { + FnArg newArg; + + // Get type + if (holds_alternative(l.args[m])) { + newArg.type = get(l.args[m]).type; + } else { + error("Expected type reference in function argument definition"); + } + + // Get direct reference + if (m + 1 < l.args.size() && holds_alternative(l.args[m + 1])) { + newArg.ref = get(l.args[m + 1]); + } else { + error("Expected direct reference after type reference in function argument definition"); + } + + newFunction.args.push_back(newArg); + } + functions[fnName] = newFunction; processingFunction = true; procFnName = fnName; @@ -1562,10 +1582,10 @@ Literal exec(vector in) { if (l.args.size() < 2) { error("Could not find all arguments required for Call inbuilt"); } - + FunctionRef ref; Direct returnRef; - + if (holds_alternative(l.args[0])) { ref = get(l.args[0]); } else { @@ -1578,12 +1598,53 @@ Literal exec(vector in) { error("Second argument of call must be a direct reference"); } + // Check if function exists + if (functions.find(ref.fnName) == functions.end()) { + error("Function " + ref.fnName + " not found"); + } + + // Check argument count + if (fnArgs.size() != functions[ref.fnName].args.size()) { + error("Function " + ref.fnName + " expects " + + to_string(functions[ref.fnName].args.size()) + + " arguments, got " + to_string(fnArgs.size())); + } + + localArgStack.push(vector()); + + // Create function arguments with type checking + for (int m = 0; m < functions[ref.fnName].args.size(); m++) { + FnArg arg = functions[ref.fnName].args[m]; + + // Type checking - now with error reporting + if (arg.type != getLitType(fnArgs[m])) { + error("Function " + ref.fnName + " argument " + to_string(m + 1) + + " type mismatch. Expected type does not match provided argument type."); + } + + // Create the variable + variables[arg.ref.varName] = fnArgs[m]; + localArgStack.top().push_back(arg.ref); + } + + // Call the function variables[returnRef.varName] = exec(functions[ref.fnName].instructions); + + // Remove variables that were declared in this scope + for (Direct delref : localArgStack.top()) { + variables.erase(delref.varName); + } + localArgStack.pop(); + + // Clear function arguments for next call + fnArgs.clear(); } break; case Instructions::Use: + cout << "Still to be implemented" << endl; break; case Instructions::Extern: + cout << "Still to be implemented" << endl; break; default: cout << "Still to be implemented" << endl; diff --git a/tests/functions.grnd b/tests/functions.grnd index f99555c..8419fa5 100644 --- a/tests/functions.grnd +++ b/tests/functions.grnd @@ -1,10 +1,14 @@ fun -int !dingle -string &silly stdlnout "This is inside the function" +stdout "The function argument is " +stdlnout $silly return 10 endfun stdlnout "This is outside the function" +pusharg "heheheha" call !dingle &var +stdout "Function returned " stdlnout $var