X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fconstants%2FFunctionValue.java;fp=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fconstants%2FFunctionValue.java;h=d37b75089f9aab03a6a0eb908d425548fa78396a;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java new file mode 100644 index 000000000..d37b75089 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/FunctionValue.java @@ -0,0 +1,201 @@ +package org.simantics.scl.compiler.constants; + +import java.util.Arrays; + +import org.cojen.classfile.TypeDesc; +import org.objectweb.asm.Opcodes; +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.internal.codegen.references.Val; +import org.simantics.scl.compiler.internal.codegen.types.BTypes; +import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; +import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils; +import org.simantics.scl.compiler.internal.codegen.utils.Constants; +import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy; +import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder; +import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilderBase; +import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder; +import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder; +import org.simantics.scl.compiler.runtime.MutableClassLoader; +import org.simantics.scl.compiler.top.SCLCompilerConfiguration; +import org.simantics.scl.compiler.types.TVar; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; + +import gnu.trove.map.hash.THashMap; + +public abstract class FunctionValue extends Constant { + + TVar[] typeParameters; + Type returnType; + protected Type[] parameterTypes; + Type effect; + + public FunctionValue(TVar[] typeParameters, Type effect, Type returnType, Type ... parameterTypes) { + super(Types.forAll(typeParameters, + Types.functionE(parameterTypes, effect, returnType))); + this.typeParameters = typeParameters; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + this.effect = effect; + } + + public Type getReturnType() { + return returnType; + } + + public Type[] getParameterTypes() { + return parameterTypes; + } + + public TVar[] getTypeParameters() { + return typeParameters; + } + + @Override + public int getArity() { + return parameterTypes.length; + } + + @Override + public void push(MethodBuilder mb) { + apply(mb, Type.EMPTY_ARRAY); + } + + @Override + public Type apply(MethodBuilder mb, Type[] typeParameters, Val... parameters) { + int arity = getArity(); + + /*System.out.println("MONADIC APPLICATION " + this); + System.out.println(" call arity: " + parameters.length); + System.out.println(" func arity: " + arity); + System.out.println(" func monadic: " + isMonadic()); + */ + if(parameters.length < arity) { + ModuleBuilder moduleBuilder = mb.getModuleBuilder(); + TypeDesc closureClass = moduleBuilder.getClosure(this, parameters.length); + CodeBuilderUtils.constructRecord(closureClass, mb, parameterTypes, parameters); + return Types.function(Arrays.copyOfRange(parameterTypes, parameters.length, parameterTypes.length), returnType); + } + else if(parameters.length > arity) { + Type returnType = applyExact(mb, Arrays.copyOf(parameters, arity)); + mb.pushBoxed(Arrays.copyOfRange(parameters, arity, parameters.length)); + int remainingArity = parameters.length - arity; + mb.genericApply(remainingArity); + + if(typeParameters.length > 0) + returnType = returnType.replace(this.typeParameters, typeParameters); + try { + returnType = BTypes.matchFunction(returnType, remainingArity)[remainingArity]; + } catch (MatchException e) { + throw new InternalCompilerError("Tried to apply value of type " + returnType + " with " + remainingArity + " parameters."); + } + mb.unbox(returnType); + return returnType; + } + else { + return applyExact(mb, parameters); + } + } + + public abstract Type applyExact(MethodBuilder mb, Val[] parameters); + + @Override + public int getEffectiveArity() { + return parameterTypes.length; + } + + + @Override + public Object realizeValue(TransientClassBuilder builder) { + THashMap valueCache = builder.classLoader.getConstantCache(); + if(valueCache != null) { + Object cachedResult = valueCache.get(this); + if(cachedResult != null) + return cachedResult; + } + + int arity = getEffectiveArity(); + if(arity == 0) + return super.realizeValue(builder); + + String packageName = builder.classLoader.getFreshPackageName(); + String moduleName = packageName + "/Temp"; + JavaNamingPolicy policy = new JavaNamingPolicy(moduleName); + ModuleBuilder moduleBuilder = new ModuleBuilder(policy, builder.javaTypeTranslator); + + ClassBuilder classFile; + if(arity <= Constants.MAX_FUNCTION_PARAMETER_COUNT) { + if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) + System.out.println("Create class " + policy.getModuleClassName()); + classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, policy.getModuleClassName(), + MethodBuilderBase.getClassName(Constants.FUNCTION_IMPL[arity])); + classFile.setSourceFile("_SCL_FunctionValue"); + classFile.addDefaultConstructor(); + + MethodBuilder mb =classFile.addMethod(Opcodes.ACC_PUBLIC, "apply", TypeDesc.OBJECT, Constants.OBJECTS[arity]); + Val[] parameters = new Val[arity]; + for(int i=0;i