From 8883bdfa5f500c16368d3181801534a2c49c7f03 Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Sun, 4 Jan 2026 09:26:31 +0530 Subject: [PATCH 1/2] Fix misinterpretation of function arguments with parameters (#45) --- .../sbml/astnode/ASTNodeInterpreter.java | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java b/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java index 27b2d466..110d97c9 100644 --- a/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java +++ b/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java @@ -163,11 +163,34 @@ public boolean compileBoolean(CallableSBase nsb, double time) { */ public double functionDouble(ASTNodeValue rightChild, List variables, ASTNodeValue[] children, int nArguments, double[] values, double time, double delay) { - for (int i = 0; i < nArguments; i++) { - values[i] = children[i].compileDouble(time, delay); + + // Save current function-argument environment (for nested function calls) + Map oldFuncArgs = funcArgs; + Map newFuncArgs = new HashMap<>(oldFuncArgs); + + // Number of arguments we can actually map (safety for mismatches) + int n = Math.min(nArguments, Math.min(children.length, variables.size())); + + // 1) Evaluate all argument expressions in the *caller* context + for (int i = 0; i < n; i++) { + double argVal = children[i].compileDouble(time, delay); + values[i] = argVal; + + String varName = variables.get(i); + if (varName != null) { + // 2) Bind each function variable (bvar) to its argument value + newFuncArgs.put(varName, argVal); + } + } + + // 3) Use the extended environment while evaluating the function body + funcArgs = newFuncArgs; + try { + return rightChild.compileDouble(time, delay); + } finally { + // 4) Restore the previous environment (important for nested calls) + funcArgs = oldFuncArgs; } - double value = rightChild.compileDouble(time, delay); - return value; } /** @@ -562,11 +585,29 @@ public boolean functionBoolean(String name, List children) { */ public boolean functionBoolean(ASTNodeValue rightChild, List variables, ASTNodeValue[] children, double[] values, double time) { - for (int i = 0; i < children.length; i++) { - values[i] = children[i].compileDouble(time, 0d); + + Map oldFuncArgs = funcArgs; + Map newFuncArgs = new HashMap<>(oldFuncArgs); + + int n = Math.min(children.length, variables.size()); + + // Evaluate arguments in caller context and bind to function variables + for (int i = 0; i < n; i++) { + double argVal = children[i].compileDouble(time, 0d); + values[i] = argVal; + + String varName = variables.get(i); + if (varName != null) { + newFuncArgs.put(varName, argVal); + } + } + + funcArgs = newFuncArgs; + try { + return rightChild.compileBoolean(time); + } finally { + funcArgs = oldFuncArgs; } - boolean value = rightChild.compileBoolean(time); - return value; } /** From ccc9f0a814ae38a642a73ba8713dbb2465f02297 Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Mon, 5 Jan 2026 20:59:48 +0530 Subject: [PATCH 2/2] Refactor function argument handling to avoid duplication --- .../sbml/astnode/ASTNodeInterpreter.java | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java b/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java index 110d97c9..86a299e4 100644 --- a/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java +++ b/src/main/java/org/simulator/sbml/astnode/ASTNodeInterpreter.java @@ -153,42 +153,50 @@ public boolean compileBoolean(CallableSBase nsb, double time) { } /** - * @param rightChild - * @param variables - * @param children - * @param nArguments - * @param values - * @param time - * @return doubleValue the interpreted double value of the node + * Evaluates function argument expressions, stores their values, and updates the + * {@code funcArgs} map so that identifiers inside a FunctionDefinition body resolve to + * the corresponding argument values. Returns the previous {@code funcArgs} map so it can + * be restored after evaluation. */ - public double functionDouble(ASTNodeValue rightChild, List variables, + private Map pushFunctionArguments(List variables, ASTNodeValue[] children, int nArguments, double[] values, double time, double delay) { - // Save current function-argument environment (for nested function calls) Map oldFuncArgs = funcArgs; Map newFuncArgs = new HashMap<>(oldFuncArgs); - // Number of arguments we can actually map (safety for mismatches) int n = Math.min(nArguments, Math.min(children.length, variables.size())); - - // 1) Evaluate all argument expressions in the *caller* context for (int i = 0; i < n; i++) { double argVal = children[i].compileDouble(time, delay); values[i] = argVal; String varName = variables.get(i); if (varName != null) { - // 2) Bind each function variable (bvar) to its argument value newFuncArgs.put(varName, argVal); } } - // 3) Use the extended environment while evaluating the function body funcArgs = newFuncArgs; + return oldFuncArgs; + } + + /** + * @param rightChild + * @param variables + * @param children + * @param nArguments + * @param values + * @param time + * @return doubleValue the interpreted double value of the node + */ + public double functionDouble(ASTNodeValue rightChild, List variables, + ASTNodeValue[] children, int nArguments, double[] values, double time, double delay) { + + Map oldFuncArgs = + pushFunctionArguments(variables, children, nArguments, values, time, delay); + try { return rightChild.compileDouble(time, delay); } finally { - // 4) Restore the previous environment (important for nested calls) funcArgs = oldFuncArgs; } } @@ -586,23 +594,11 @@ public boolean functionBoolean(String name, List children) { public boolean functionBoolean(ASTNodeValue rightChild, List variables, ASTNodeValue[] children, double[] values, double time) { - Map oldFuncArgs = funcArgs; - Map newFuncArgs = new HashMap<>(oldFuncArgs); - - int n = Math.min(children.length, variables.size()); + int nArguments = children.length; - // Evaluate arguments in caller context and bind to function variables - for (int i = 0; i < n; i++) { - double argVal = children[i].compileDouble(time, 0d); - values[i] = argVal; + Map oldFuncArgs = + pushFunctionArguments(variables, children, nArguments, values, time, 0d); - String varName = variables.get(i); - if (varName != null) { - newFuncArgs.put(varName, argVal); - } - } - - funcArgs = newFuncArgs; try { return rightChild.compileBoolean(time); } finally { @@ -1066,4 +1062,4 @@ public double rateOf(EquationSystem eqnSystem, CallableSBase sBase, double time, return 0d; } } -} +} \ No newline at end of file