Added support for varargs
diff --git a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/FeatureCallExpression.java b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/FeatureCallExpression.java index cfbca99..0d51d45 100644 --- a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/FeatureCallExpression.java +++ b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/FeatureCallExpression.java
@@ -80,12 +80,13 @@ } /** + * Looks for the operation in the EolContext EolOperationFactory. * - * @param target - * @param name The requested operation name - * @param owningModel + * @param target The object this feature is called on. + * @param name The requested operation name. + * @param owningModel The model (optional). * @param context The context from which the EolOperationFactory is derived. - * @return The operation + * @return The operation. * @throws EolIllegalOperationException * @since 1.6 */
diff --git a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/OperationCallExpression.java b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/OperationCallExpression.java index daa8660..6b8f43f 100644 --- a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/OperationCallExpression.java +++ b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/dom/OperationCallExpression.java
@@ -142,8 +142,8 @@ return wrap(objectMethod.execute(nameExpression, context, nameExpression)); } + // Evaluate the parameters ArrayList<Object> parameterValues = new ArrayList<>(parameterExpressions.size()); - for (Expression parameter : parameterExpressions) { parameterValues.add(executorFactory.execute(parameter, context)); }
diff --git a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/execute/introspection/java/ObjectMethod.java b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/execute/introspection/java/ObjectMethod.java index f3bb0e4..7ed2e84 100644 --- a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/execute/introspection/java/ObjectMethod.java +++ b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/execute/introspection/java/ObjectMethod.java
@@ -9,13 +9,16 @@ ******************************************************************************/ package org.eclipse.epsilon.eol.execute.introspection.java; +import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.util.Collection; import java.util.stream.BaseStream; import org.eclipse.epsilon.common.module.ModuleElement; import org.eclipse.epsilon.eol.exceptions.EolRuntimeException; import org.eclipse.epsilon.eol.execute.context.IEolContext; import org.eclipse.epsilon.eol.execute.context.concurrent.EolContextParallel; import org.eclipse.epsilon.eol.execute.context.concurrent.IEolContextParallel; +import org.eclipse.epsilon.eol.execute.operations.contributors.IterableOperationContributor; import org.eclipse.epsilon.eol.util.ReflectionUtil; public class ObjectMethod extends DisposableObject { @@ -64,6 +67,22 @@ } public Object execute(Object[] parameters, ModuleElement ast) throws EolRuntimeException { + if (method.isVarArgs()) { + int varargIndex = method.getParameterCount() - 1; + Object[] adjustedParams = new Object[method.getParameterCount()]; + Class<?> varargType = method.getParameterTypes()[varargIndex].getComponentType(); + for (int i = 0; i < varargIndex; i++) { + adjustedParams[i] = parameters[i]; + } + int numberOfVarargs = parameters.length - varargIndex; + if (numberOfVarargs < 0) numberOfVarargs = 0; + Object varargParams = Array.newInstance(varargType, numberOfVarargs); + for (int i = 0; i < numberOfVarargs; i++) { + Array.set(varargParams, i, parameters[varargIndex + i]); + } + adjustedParams[adjustedParams.length-1] = varargParams; + parameters = adjustedParams; + } return ReflectionUtil.executeMethod(object, method, ast, parameters); }
diff --git a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/util/ReflectionUtil.java b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/util/ReflectionUtil.java index 2ddec4e..0a20f0c 100644 --- a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/util/ReflectionUtil.java +++ b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/util/ReflectionUtil.java
@@ -197,12 +197,18 @@ for (int stage = 0; stage < 2; ++stage) { for (Method method : methods) { if (getMethodName(method).equalsIgnoreCase(methodName)) { - Class<?>[] parameterTypes = method.getParameterTypes(); - boolean parametersMatch = parameterTypes.length == parameters.length; + boolean isVarargs = method.isVarArgs(), + parametersMatch = parameterTypes.length == parameters.length || isVarargs; + if (parametersMatch) { //TODO: See why parameter type checking does not work with EolSequence - for (int j = 0; j < parameterTypes.length && parametersMatch; j++) { + int varargIndex = method.getParameterCount() - 1; + int endIndex = isVarargs ? varargIndex : parameterTypes.length; + if (parameters.length < endIndex) { + continue; + } + for (int j = 0; j < endIndex && parametersMatch; j++) { Class<?> parameterType = parameterTypes[j]; Object parameter = parameters[j]; if (allowContravariantConversionForParameters) { @@ -212,10 +218,17 @@ parametersMatch = parametersMatch && parameterType.equals(parameter.getClass()); } } - if (parametersMatch) { - return method; + if (isVarargs) { + Class<?> varargType = parameterTypes[varargIndex].getComponentType(); + for (int va = varargIndex; va < parameters.length && parametersMatch; va++) { + Object parameter = parameters[va]; + parametersMatch = (stage == 0 ? varargType.isInstance(parameter) : isInstance(varargType, parameter)); + } } } + if (parametersMatch) { + return method; + } } } }
diff --git a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/EolAcceptanceTestSuite.java b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/EolAcceptanceTestSuite.java index e8bb409..fdf11f3 100644 --- a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/EolAcceptanceTestSuite.java +++ b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/EolAcceptanceTestSuite.java
@@ -51,7 +51,7 @@ ContextlessFirstOrderOperationTests.class, DomTests.class, VariableTests.class, - OperationOrderTests.class, + OperationTests.class, PostfixOperatorTests.class, CompositeAssignmentTests.class, SwitchTests.class,
diff --git a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationOrderTests.eol b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationOrderTests.eol deleted file mode 100644 index eb917be..0000000 --- a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationOrderTests.eol +++ /dev/null
@@ -1,4 +0,0 @@ -@test -operation testSplit() { - "foo,bar".split(",").first().println(); -} \ No newline at end of file
diff --git a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationTests.eol b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationTests.eol new file mode 100644 index 0000000..e259a2a --- /dev/null +++ b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationTests.eol
@@ -0,0 +1,33 @@ +@test +operation testSplit() { + "foo,bar".split(",").first().println(); +} + +@test +operation testVarargs() { + var Paths = Native("java.nio.file.Paths"); + var p = Paths.get("rel", "path", "to", "resource"); + assertFalse(p.toFile().exists()); + p = Paths.get("folder"); + assertFalse(p.toFile().isFile()); + p = Paths.get("first", "second"); + assertFalse(p.toFile().exists()); +} + +@test +operation testVarargsAmbigious() { + var s = Native("java.lang.String").format("foo"); + assertEquals(3, s.length()); + s = Native("java.lang.String").format("bazoo", null); + assertEquals(5, s.length()); +} + +@test +operation testVarargsMissingParameters() { + assertError(Native("java.nio.file.Paths").get()); +} + +@test +operation testVarargsInvalidNullLastParameter() { + assertError(Native("java.nio.file.Files").copy("a", "b", null)); +}
diff --git a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationOrderTests.java b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationTests.java similarity index 94% rename from tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationOrderTests.java rename to tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationTests.java index 299ec19..a0d7ac4 100644 --- a/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationOrderTests.java +++ b/tests/org.eclipse.epsilon.eol.engine.test.acceptance/src/org/eclipse/epsilon/eol/engine/test/acceptance/OperationTests.java
@@ -1,19 +1,19 @@ -/******************************************************************************* - * Copyright (c) 2008 The University of York. - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * Contributors: - * Dimitrios Kolovos - initial API and implementation -******************************************************************************/ - -package org.eclipse.epsilon.eol.engine.test.acceptance; - -import org.eclipse.epsilon.eol.engine.test.acceptance.eunit.EUnitRunner; -import org.junit.runner.RunWith; - -@RunWith(EUnitRunner.class) -public class OperationOrderTests { - +/******************************************************************************* + * Copyright (c) 2008 The University of York. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Dimitrios Kolovos - initial API and implementation +******************************************************************************/ + +package org.eclipse.epsilon.eol.engine.test.acceptance; + +import org.eclipse.epsilon.eol.engine.test.acceptance.eunit.EUnitRunner; +import org.junit.runner.RunWith; + +@RunWith(EUnitRunner.class) +public class OperationTests { + }