diff --git a/core/src/org/sbml/jsbml/math/compiler/UnitsCompiler.java b/core/src/org/sbml/jsbml/math/compiler/UnitsCompiler.java index 036e80b6d..94fe6373d 100644 --- a/core/src/org/sbml/jsbml/math/compiler/UnitsCompiler.java +++ b/core/src/org/sbml/jsbml/math/compiler/UnitsCompiler.java @@ -727,12 +727,23 @@ private ASTNode2Value invalid() { @Override // TODO: Specify generic type T i.e. ASTNode2Value public ASTNode2Value lambda(List values) throws SBMLException { + // When the lambda node is first constructed, its child list may be empty; + // in that case, there is no body and no arguments yet, so we cannot derive + // any meaningful units. Returning an invalid unit definition here avoids + // out-of-bounds exceptions while signalling "units unknown". + if (values == null || values.isEmpty()) { + return invalid(); + } + + // For a fully-formed lambda expression, all but the last child are + // arguments; the last child is the body whose units we want to derive. for (int i = 0; i < values.size() - 1; i++) { - namesToUnits.put(values.get(i).toString(), - values.get(i).compile(this)); + namesToUnits.put(values.get(i).toString(), values.get(i).compile(this)); } - return new ASTNode2Value(values.get(values.size() - 1).compile(this) - .getUnits(), this); + + return new ASTNode2Value( + values.get(values.size() - 1).compile(this).getUnits(), + this); } /* (non-Javadoc) diff --git a/core/test/org/sbml/jsbml/math/compiler/UnitsCompilerLambdaTest.java b/core/test/org/sbml/jsbml/math/compiler/UnitsCompilerLambdaTest.java new file mode 100644 index 000000000..218f23f59 --- /dev/null +++ b/core/test/org/sbml/jsbml/math/compiler/UnitsCompilerLambdaTest.java @@ -0,0 +1,37 @@ +package org.sbml.jsbml.math.compiler; + +import static org.junit.Assert.*; + +import java.util.Collections; + +import org.junit.Test; +import org.sbml.jsbml.math.ASTNode2; +// no import needed for ASTNode2Value since we are in the same package +// or, if you prefer, you could import: +// import org.sbml.jsbml.math.compiler.ASTNode2Value; + +/** + * Regression tests for lambda handling in {@link UnitsCompiler}. + */ +public class UnitsCompilerLambdaTest { + + /** + * Issue #248: Deriving units for a lambda expression while its child list + * is still empty must not cause an IndexOutOfBoundsException. + */ + @Test + public void testLambdaWithNoChildrenDoesNotThrow() throws Exception { + UnitsCompiler compiler = new UnitsCompiler(3, 1); // arbitrary level/version + + ASTNode2Value result = null; + try { + result = compiler.lambda(Collections.emptyList()); + } catch (IndexOutOfBoundsException ex) { + fail("lambda() must not throw IndexOutOfBoundsException when values list is empty: " + ex); + } + + assertNotNull("lambda() should return a non-null ASTNode2Value", result); + assertTrue("lambda() with no children should return invalid units", + result.getUnits().isInvalid()); + } +} \ No newline at end of file