From d7b0c4d818796db2dcfa585940904baa8b3f2d2f Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 20 Sep 2025 20:23:57 +1000 Subject: [PATCH] Function calling in structs --- src/main.cpp | 80 +++++++++++++++++++++++++++++++++++++---------- tests/struct.grnd | 23 ++++++++------ 2 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 16f9b73..19fc99a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -507,8 +507,7 @@ Types getLitType(Literal in) { if (holds_alternative(in.val)) return Types::String; if (holds_alternative(in.val)) return Types::Char; if (holds_alternative(in.val)) return Types::List; - 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; + return Types::Other; } /* @@ -2221,24 +2220,61 @@ Literal exec(vector in, bool executingFunction) { break; } - // 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())); - } - // Create backup of variables to be restored map scopeBackup = variables; + Function fnToExec; + bool inStruct = false; + Struct structVal; + string structName; + + // Check if function exists + if (functions.find(ref.fnName) == functions.end()) { + if (isReferencingStruct(ref.fnName)) { + string fnInStruct; + + size_t dotPos = ref.fnName.find('.'); + if (dotPos != string::npos) { + structName = ref.fnName.substr(0, dotPos); + fnInStruct = ref.fnName.substr(dotPos + 1); + if (variables.find(structName) != variables.end()) { + if (holds_alternative(variables[structName].val)) { + structVal = get(variables[structName].val); + if (structVal.functions.find(fnInStruct) != structVal.functions.end()) { + fnToExec = structVal.functions[fnInStruct]; + inStruct = true; + } else { + error("Could not find function '" + fnInStruct + "' in struct '" + structName + "'"); + } + for (auto &[key, value] : structVal.values) { + variables[key] = value; + } + } else { + error("Variable '" + structName + "' is not a struct"); + } + } else { + error("Could not find struct '" + structName + "'"); + } + } else { + error("Invalid struct member access syntax"); + } + } else { + error("Function " + ref.fnName + " not found"); + } + } else { + fnToExec = functions[ref.fnName]; + } + + // Check argument count + if (fnArgs.size() != fnToExec.args.size()) { + error("Function " + ref.fnName + " expects " + + to_string(fnToExec.args.size()) + + " arguments, got " + to_string(fnArgs.size())); + } + // Create function arguments with type checking - for (int m = 0; m < functions[ref.fnName].args.size(); m++) { - FnArg arg = functions[ref.fnName].args[m]; + for (int m = 0; m < fnToExec.args.size(); m++) { + FnArg arg = fnToExec.args[m]; // Type checking - now with error reporting if (arg.type != getLitType(fnArgs[m])) { @@ -2257,12 +2293,22 @@ Literal exec(vector in, bool executingFunction) { preProcessLabels(functions[ref.fnName].instructions); // Call the function - Literal retVal = exec(functions[ref.fnName].instructions, true); + Literal retVal = exec(fnToExec.instructions, true); + + // If we were executing a function in a struct, add back values + if (inStruct) { + for (auto &[key, value] : structVal.values) { + structVal.values[key] = variables[key]; + } + } // Restore scope variables = scopeBackup; labelStack.pop(); + // Add back the struct values + variables[structName].val = structVal; + // Now, assign the return value in the current scope. if (expectList) { setVal(returnRef, retVal); diff --git a/tests/struct.grnd b/tests/struct.grnd index 684b574..82ff4a6 100644 --- a/tests/struct.grnd +++ b/tests/struct.grnd @@ -2,23 +2,28 @@ struct -point init &xpos -int init &ypos -int - fun -void !init -int &x -int &y + fun -int !init -int &x -int &y set &xpos $x set &ypos $y - return + return 0 endfun fun -string !toString - # do stuff - return "placeholder" - endfun - - fun -int !dingle - return 23 + tostring $xpos &xposstr + tostring $ypos &yposstr + add "x: " $xposstr &str + add $str ", y: " &str + add $str $yposstr &str + return $str endfun endstruct init &myPoint -point -set &myPoint.xpos 20 +pusharg 30 15 +!myPoint.init &out println $myPoint.xpos + +!myPoint.toString &out + +println $out