diff --git a/legend-pure-m3-core/src/test/java/org/finos/legend/pure/m3/tests/function/base/meta/AbstractTestCanReactivateDynamically.java b/legend-pure-m3-core/src/test/java/org/finos/legend/pure/m3/tests/function/base/meta/AbstractTestCanReactivateDynamically.java index 505203b5ea..37f86b96b7 100644 --- a/legend-pure-m3-core/src/test/java/org/finos/legend/pure/m3/tests/function/base/meta/AbstractTestCanReactivateDynamically.java +++ b/legend-pure-m3-core/src/test/java/org/finos/legend/pure/m3/tests/function/base/meta/AbstractTestCanReactivateDynamically.java @@ -52,4 +52,114 @@ public void testEval() this.execute("test():Boolean[1]"); } + @Test + public void testNonReactivatableFunction() + { + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(false == canReactivateDynamically({s:String[1]|$s}->evaluateAndDeactivate().expressionSequence->toOne()), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + } + + @Test + public void testNonReactivatableNestedFunction() + { + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(false == canReactivateDynamically({s:String[1]|$s + 'hi'}->evaluateAndDeactivate().expressionSequence->toOne()), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + + runtime.delete("fromString.pure"); + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(false == canReactivateDynamically({s:Any[1]|instanceOf($s, String) && true}->evaluateAndDeactivate().expressionSequence->toOne()), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + + runtime.delete("fromString.pure"); + compileTestSource("fromString.pure", + "Class A\n" + + "{\n" + + " prop: B[1];\n" + + "}\n" + + "Class B\n" + + "{\n" + + " prop: String[1];\n" + + "}\n" + + "function test():Boolean[1]\n" + + "{\n" + + " assert(false == canReactivateDynamically({s:String[1]|^A(prop = ^B(prop = $s))}->evaluateAndDeactivate().expressionSequence->toOne()), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + } + + @Test + public void testNonReactivatableNestedFunctionWithSomeVariablesMissing() + { + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(false == canReactivateDynamically({s:String[1], y:String[1]|$s + $y}->evaluateAndDeactivate().expressionSequence->toOne(), newMap(^Pair>(first = 's', second = ^List(values = 'dummy')))), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + } + + @Test + public void testSimpleFuncExpressionReactivationInScopeOfParams() + { + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(canReactivateDynamically({s:String[1]|$s}->evaluateAndDeactivate().expressionSequence->toOne(), newMap(^Pair>(first = 's', second = ^List(values = 'dummy')))), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + } + + @Test + public void testNestedFuncExpressionReactivationInScopeOfParams() + { + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(canReactivateDynamically({s:String[1]|$s + 'hi'}->evaluateAndDeactivate().expressionSequence->toOne(), newMap(^Pair>(first = 's', second = ^List(values = 'dummy')))), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + + runtime.delete("fromString.pure"); + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(canReactivateDynamically({s:String[1], y:String[1]|$s + $y}->evaluateAndDeactivate().expressionSequence->toOne(), newMap([^Pair>(first = 's', second = ^List(values = 'dummy')), ^Pair>(first = 'y', second = ^List(values = 'dummy'))])), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + + runtime.delete("fromString.pure"); + compileTestSource("fromString.pure", + "function test():Boolean[1]\n" + + "{\n" + + " assert(canReactivateDynamically({s:Any[1]|instanceOf($s, String) && true}->evaluateAndDeactivate().expressionSequence->toOne(), newMap(^Pair>(first = 's', second = ^List(values = 'dummy')))), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + + runtime.delete("fromString.pure"); + compileTestSource("fromString.pure", + "Class A\n" + + "{\n" + + " prop: B[1];" + + "}\n" + + "Class B\n" + + "{\n" + + " prop: String[1];" + + "}\n" + + "function test():Boolean[1]\n" + + "{\n" + + " assert(canReactivateDynamically({s:String[1]|^A(prop = ^B(prop = $s))}->evaluateAndDeactivate().expressionSequence->toOne(), newMap(^Pair>(first = 's', second = ^List(values = 'dummy')))), |'');\n" + + "}\n"); + this.execute("test():Boolean[1]"); + } } diff --git a/legend-pure-m3-platform/src/main/resources/platform/pure/corefunctions/meta.pure b/legend-pure-m3-platform/src/main/resources/platform/pure/corefunctions/meta.pure index f70424290c..079166f1ac 100644 --- a/legend-pure-m3-platform/src/main/resources/platform/pure/corefunctions/meta.pure +++ b/legend-pure-m3-platform/src/main/resources/platform/pure/corefunctions/meta.pure @@ -76,7 +76,12 @@ native function meta::pure::functions::meta::deactivate(var:Any[*]):ValueSpecifi native function meta::pure::functions::meta::reactivate(vs:ValueSpecification[1], vars:Map>[1]):Any[*]; -native function meta::pure::functions::meta::canReactivateDynamically(vs:ValueSpecification[1]):Boolean[1]; +function meta::pure::functions::meta::canReactivateDynamically(vs:ValueSpecification[1]):Boolean[1] +{ + canReactivateDynamically($vs, ^Map>()) +} + +native function meta::pure::functions::meta::canReactivateDynamically(vs:ValueSpecification[1], vars:Map>[1]):Boolean[1]; native function meta::pure::functions::meta::evaluateAndDeactivate(var:T[m]):T[m]; diff --git a/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/natives/core/meta/CanReactivateDynamically.java b/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/natives/core/meta/CanReactivateDynamically.java index dc95e4b74a..36f9162f0d 100644 --- a/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/natives/core/meta/CanReactivateDynamically.java +++ b/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/natives/core/meta/CanReactivateDynamically.java @@ -17,12 +17,13 @@ import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.valuespecification.ValueSpecification; import org.finos.legend.pure.m3.execution.ExecutionSupport; import org.finos.legend.pure.runtime.java.compiled.generation.processors.natives.AbstractNativeFunctionGeneric; +import org.finos.legend.pure.runtime.java.compiled.generation.processors.support.map.PureMap; public class CanReactivateDynamically extends AbstractNativeFunctionGeneric { public CanReactivateDynamically() { - super("CoreGen.canReactivateWithoutJavaCompilation",new Class[]{ValueSpecification.class, ExecutionSupport.class}, - false, true, false, "canReactivateDynamically_ValueSpecification_1__Boolean_1_"); + super("CoreGen.canReactivateWithoutJavaCompilation",new Class[]{ValueSpecification.class, PureMap.class, ExecutionSupport.class}, + false, true, false, "canReactivateDynamically_ValueSpecification_1__Map_1__Boolean_1_"); } } diff --git a/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/CoreExtensionCompiled.java b/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/CoreExtensionCompiled.java index b8d4c0d647..6a45c1849a 100644 --- a/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/CoreExtensionCompiled.java +++ b/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/CoreExtensionCompiled.java @@ -174,7 +174,7 @@ public CoreExtensionCompiled() " return Pure.canReactivateWithoutJavaCompilation(valueSpecification, es, new PureMap(UnifiedMap.newMap()), bridge);\n" + " }\n" + "\n" + - " public static boolean canReactivateWithoutJavaCompilation(ValueSpecification valueSpecification, ExecutionSupport es, PureMap lambdaOpenVariablesMap)\n" + + " public static boolean canReactivateWithoutJavaCompilation(ValueSpecification valueSpecification, PureMap lambdaOpenVariablesMap, ExecutionSupport es)\n" + " {\n" + " return Pure.canReactivateWithoutJavaCompilation(valueSpecification, es, lambdaOpenVariablesMap, bridge);\n" + " }\n" + diff --git a/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/Reactivator.java b/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/Reactivator.java index dc2a1c9908..76b5fa0e80 100644 --- a/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/Reactivator.java +++ b/legend-pure-runtime-java-engine-compiled/src/main/java/org/finos/legend/pure/runtime/java/compiled/generation/processors/support/Reactivator.java @@ -23,7 +23,11 @@ import org.eclipse.collections.api.set.MutableSet; import org.finos.legend.pure.m3.coreinstance.meta.pure.functions.collection.List; import org.finos.legend.pure.m3.coreinstance.meta.pure.functions.lang.KeyExpression; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.*; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.ConcreteFunctionDefinition; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.Function; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.FunctionDefinition; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.LambdaFunction; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.NativeFunction; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.property.Property; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.property.QualifiedProperty; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.valuespecification.InstanceValue; @@ -87,6 +91,11 @@ private static boolean canReactivateWithoutJavaCompilationImpl(ValueSpecificatio { return canReactivateWithoutJavaCompilationImpl((Function) o, es, false, lambdaOpenVariablesMap, bridge); } + if (o instanceof KeyExpression) + { + return canReactivateWithoutJavaCompilationImpl(((KeyExpression) o)._key(), es, false, lambdaOpenVariablesMap, bridge) && + canReactivateWithoutJavaCompilationImpl(((KeyExpression) o)._expression(), es, false, lambdaOpenVariablesMap, bridge); + } return true; }); } diff --git a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/FunctionExecutionInterpreted.java b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/FunctionExecutionInterpreted.java index 4163492305..933bbd6d38 100644 --- a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/FunctionExecutionInterpreted.java +++ b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/FunctionExecutionInterpreted.java @@ -299,7 +299,7 @@ public void init(PureRuntime runtime, Message message) this.nativeFunctions.put("subTypeOf_Type_1__Type_1__Boolean_1_", new SubTypeOf(repository)); this.nativeFunctions.put("deactivate_Any_MANY__ValueSpecification_1_", new Deactivate()); this.nativeFunctions.put("reactivate_ValueSpecification_1__Map_1__Any_MANY_", new Reactivate(this)); - this.nativeFunctions.put("canReactivateDynamically_ValueSpecification_1__Boolean_1_", new CanReactivateDynamically(repository)); + this.nativeFunctions.put("canReactivateDynamically_ValueSpecification_1__Map_1__Boolean_1_", new CanReactivateDynamically(this)); this.nativeFunctions.put("evaluateAndDeactivate_T_m__T_m_", new EvaluateAndDeactivate()); this.nativeFunctions.put("toString_Any_1__String_1_", new ToString(repository, this)); this.nativeFunctions.put("mutateAdd_T_1__String_1__Any_MANY__T_1_", new MutateAdd()); diff --git a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/CanReactivateDynamically.java b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/CanReactivateDynamically.java index 50084aaf5e..fefac38012 100644 --- a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/CanReactivateDynamically.java +++ b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/CanReactivateDynamically.java @@ -16,13 +16,13 @@ import org.eclipse.collections.api.list.ListIterable; import org.eclipse.collections.api.map.MutableMap; -import org.finos.legend.pure.m3.exception.PureExecutionException; import org.finos.legend.pure.m3.compiler.Context; -import org.finos.legend.pure.m3.navigation.ValueSpecificationBootstrap; +import org.finos.legend.pure.m3.exception.PureExecutionException; import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m3.navigation.ValueSpecificationBootstrap; import org.finos.legend.pure.m4.coreinstance.CoreInstance; -import org.finos.legend.pure.m4.ModelRepository; import org.finos.legend.pure.runtime.java.interpreted.ExecutionSupport; +import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted; import org.finos.legend.pure.runtime.java.interpreted.VariableContext; import org.finos.legend.pure.runtime.java.interpreted.natives.core.InstantiationContext; import org.finos.legend.pure.runtime.java.interpreted.natives.core.NativeFunction; @@ -32,17 +32,24 @@ public class CanReactivateDynamically extends NativeFunction { - private final ModelRepository repository; + private final FunctionExecutionInterpreted functionExecution; - public CanReactivateDynamically(ModelRepository repository) + public CanReactivateDynamically(FunctionExecutionInterpreted functionExecution) { - this.repository = repository; + this.functionExecution = functionExecution; } @Override public CoreInstance execute(ListIterable params, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, CoreInstance functionExpressionToUseInStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, Context context, ProcessorSupport processorSupport) throws PureExecutionException { - // return repository.newBooleanCoreInstance(true); - return ValueSpecificationBootstrap.newBooleanLiteral(repository, true, processorSupport); + try + { + ReactivateHelper.execute(this.functionExecution, params, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionToUseInStack, profiler, instantiationContext, executionSupport, context, processorSupport); + return ValueSpecificationBootstrap.newBooleanLiteral(this.functionExecution.getPureRuntime().getModelRepository(), true, processorSupport); + } + catch (PureExecutionException e) + { + return ValueSpecificationBootstrap.newBooleanLiteral(this.functionExecution.getPureRuntime().getModelRepository(), false, processorSupport); + } } } diff --git a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/Reactivate.java b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/Reactivate.java index dcecaa9b61..dd80bda0df 100644 --- a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/Reactivate.java +++ b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/Reactivate.java @@ -48,33 +48,6 @@ public Reactivate(FunctionExecutionInterpreted functionExecution) @Override public CoreInstance execute(ListIterable params, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, CoreInstance functionExpressionToUseInStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, Context context, ProcessorSupport processorSupport) throws PureExecutionException { - MapIterable openVariablesMap = ((MapCoreInstance)Instance.getValueForMetaPropertyToManyResolved(params.get(1), M3Properties.values, processorSupport).getFirst()).getMap(); - RichIterable> openVariables = openVariablesMap.keyValuesView(); - VariableContext newVarContext = VariableContext.newVariableContext(); - - for (Pair pair: openVariables) - { - try - { - String name = pair.getOne().getName(); - //todo: Should not need to do this, but there seem to be duplicates in the open variables - if (newVarContext.getValue(name) == null) - { - CoreInstance list = pair.getTwo(); - CoreInstance inst = processorSupport.newEphemeralAnonymousCoreInstance(M3Paths.InstanceValue); - Instance.addValueToProperty(inst, M3Properties.genericType, list.getValueForMetaPropertyToOne(M3Properties.genericType) , processorSupport); - Instance.addValueToProperty(inst, M3Properties.multiplicity, list.getValueForMetaPropertyToOne(M3Properties.multiplicity), processorSupport); - Instance.addValueToProperty(inst, M3Properties.values, list.getValueForMetaPropertyToMany(M3Properties.values), processorSupport); - newVarContext.registerValue(name, inst); - } - } - catch (VariableContext.VariableNameConflictException e) - { - throw new PureExecutionException(e); - } - } - - return this.functionExecution.executeValueSpecification(params.get(0).getValueForMetaPropertyToOne(M3Properties.values), - resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionToUseInStack, newVarContext, profiler, instantiationContext, executionSupport); + return ReactivateHelper.execute(this.functionExecution, params, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionToUseInStack, profiler, instantiationContext, executionSupport, context, processorSupport); } } diff --git a/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/ReactivateHelper.java b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/ReactivateHelper.java new file mode 100644 index 0000000000..b685e985c4 --- /dev/null +++ b/legend-pure-runtime-java-engine-interpreted/src/main/java/org/finos/legend/pure/runtime/java/interpreted/natives/core/meta/ReactivateHelper.java @@ -0,0 +1,71 @@ +// Copyright 2023 Goldman Sachs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.finos.legend.pure.runtime.java.interpreted.natives.core.meta; + +import org.eclipse.collections.api.RichIterable; +import org.eclipse.collections.api.list.ListIterable; +import org.eclipse.collections.api.map.MapIterable; +import org.eclipse.collections.api.map.MutableMap; +import org.eclipse.collections.api.tuple.Pair; +import org.finos.legend.pure.m3.compiler.Context; +import org.finos.legend.pure.m3.exception.PureExecutionException; +import org.finos.legend.pure.m3.navigation.Instance; +import org.finos.legend.pure.m3.navigation.M3Paths; +import org.finos.legend.pure.m3.navigation.M3Properties; +import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.runtime.java.interpreted.ExecutionSupport; +import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted; +import org.finos.legend.pure.runtime.java.interpreted.VariableContext; +import org.finos.legend.pure.runtime.java.interpreted.natives.core.InstantiationContext; +import org.finos.legend.pure.runtime.java.interpreted.natives.core.collection.map.MapCoreInstance; +import org.finos.legend.pure.runtime.java.interpreted.profiler.Profiler; + +import java.util.Stack; + +public class ReactivateHelper +{ + public static CoreInstance execute(FunctionExecutionInterpreted functionExecution, ListIterable params, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, CoreInstance functionExpressionToUseInStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, Context context, ProcessorSupport processorSupport) throws PureExecutionException + { + MapIterable openVariablesMap = ((MapCoreInstance) Instance.getValueForMetaPropertyToManyResolved(params.get(1), M3Properties.values, processorSupport).getFirst()).getMap(); + RichIterable> openVariables = openVariablesMap.keyValuesView(); + VariableContext newVarContext = VariableContext.newVariableContext(); + + for (Pair pair : openVariables) + { + try + { + String name = pair.getOne().getName(); + //todo: Should not need to do this, but there seem to be duplicates in the open variables + if (newVarContext.getValue(name) == null) + { + CoreInstance list = pair.getTwo(); + CoreInstance inst = processorSupport.newEphemeralAnonymousCoreInstance(M3Paths.InstanceValue); + Instance.addValueToProperty(inst, M3Properties.genericType, list.getValueForMetaPropertyToOne(M3Properties.genericType), processorSupport); + Instance.addValueToProperty(inst, M3Properties.multiplicity, list.getValueForMetaPropertyToOne(M3Properties.multiplicity), processorSupport); + Instance.addValueToProperty(inst, M3Properties.values, list.getValueForMetaPropertyToMany(M3Properties.values), processorSupport); + newVarContext.registerValue(name, inst); + } + } + catch (VariableContext.VariableNameConflictException e) + { + throw new PureExecutionException(e); + } + } + + return functionExecution.executeValueSpecification(params.get(0).getValueForMetaPropertyToOne(M3Properties.values), + resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionToUseInStack, newVarContext, profiler, instantiationContext, executionSupport); + } +}