]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
(refs #7090) Generated Function objects implement equals and hashCode 64/364/1
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 15 Mar 2017 14:13:46 +0000 (16:13 +0200)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 15 Mar 2017 14:26:51 +0000 (16:26 +0200)
Change-Id: I93118f7bd0f975bb68e14b7288dad6546a62faa1

17 files changed:
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/CodeBuilderUtils.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ModuleBuilder.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ValueFromMethod.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/interpreted/ILambda.java
bundles/org.simantics.scl.runtime/generation/org/simantics/scl/runtime/generation/GenerateFunctions.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/Lists.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction1.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction2.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction3.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction4.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction5.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction6.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction7.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunction8.java
bundles/org.simantics.scl.runtime/src/org/simantics/scl/runtime/function/UnsaturatedFunctionN.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionIdentity.scl [new file with mode: 0644]

index cc8f3e0c5ab5a7f5dfefb8cf43b77b28b76c756e..81f7b117a82f61f7ade860cd1362d5b4a85559e3 100644 (file)
@@ -93,72 +93,75 @@ public class CodeBuilderUtils {
             tsmb.finish();
         }
         
-        if(generateEqualsAndHashCode) {
-            // Create equals
-            {
-                TypeDesc CLASS = TypeDesc.forClass(Class.class);
+        if(generateEqualsAndHashCode)
+            implementHashCodeAndEquals(classBuilder, recordName, fieldNamePrefix, types);
+    }
 
-                MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
-                LocalVariable parameter = tsmb.getParameter(0);
-                Label success = tsmb.createLabel();
-                Label failure = tsmb.createLabel();
+    public static void implementHashCodeAndEquals(ClassBuilder classBuilder, String recordName, String fieldNamePrefix, TypeDesc[] types) {
+        // Create equals
+        {
+            TypeDesc CLASS = TypeDesc.forClass(Class.class);
 
-                // Check type
-                tsmb.loadThis();
-                tsmb.loadLocal(parameter);
-                tsmb.ifComparisonBranch(success, "==", TypeDesc.OBJECT);
-                tsmb.loadLocal(parameter);
-                tsmb.ifNullBranch(failure, true);
-                tsmb.loadLocal(parameter);
-                tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
-                tsmb.loadThis();
-                tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
-                tsmb.ifComparisonBranch(failure, "!=", CLASS);
-                tsmb.loadLocal(parameter);
-                tsmb.checkCast(classBuilder.getType());
-                LocalVariable other = tsmb.createLocalVariable("other", classBuilder.getType());
-                tsmb.storeLocal(other);
+            MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
+            LocalVariable parameter = tsmb.getParameter(0);
+            Label success = tsmb.createLabel();
+            Label failure = tsmb.createLabel();
 
-                // Compare fields
-                for(int i=0;i<types.length;++i) {
-                    TypeDesc type = types[i];
-                    if(type.equals(TypeDesc.VOID))
-                        continue;
-                    tsmb.loadThis();
-                    tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
-                    tsmb.loadLocal(other);
-                    tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
-                    equals(tsmb, type, failure);
-                }
+            // Check type
+            tsmb.loadThis();
+            tsmb.loadLocal(parameter);
+            tsmb.ifComparisonBranch(success, "==", TypeDesc.OBJECT);
+            tsmb.loadLocal(parameter);
+            tsmb.ifNullBranch(failure, true);
+            tsmb.loadLocal(parameter);
+            tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
+            tsmb.loadThis();
+            tsmb.invokeVirtual("java/lang/Object", "getClass", CLASS, Constants.EMPTY_TYPEDESC_ARRAY);
+            tsmb.ifComparisonBranch(failure, "!=", CLASS);
+            tsmb.loadLocal(parameter);
+            tsmb.checkCast(classBuilder.getType());
+            LocalVariable other = tsmb.createLocalVariable("other", classBuilder.getType());
+            tsmb.storeLocal(other);
 
-                // Return
-                tsmb.setLocation(success);
-                tsmb.loadConstant(true);
-                tsmb.returnValue(TypeDesc.BOOLEAN);
-                tsmb.setLocation(failure);
-                tsmb.loadConstant(false);
-                tsmb.returnValue(TypeDesc.BOOLEAN);
-                tsmb.finish();
+            // Compare fields
+            for(int i=0;i<types.length;++i) {
+                TypeDesc type = types[i];
+                if(type.equals(TypeDesc.VOID))
+                    continue;
+                tsmb.loadThis();
+                tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
+                tsmb.loadLocal(other);
+                tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
+                equals(tsmb, type, failure);
             }
 
-            // Create hashCode
-            {
-                MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "hashCode", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY);
-                tsmb.loadConstant(recordName.hashCode());
-                for(int i=0;i<types.length;++i) {
-                    TypeDesc type = types[i];
-                    if(type.equals(TypeDesc.VOID))
-                        continue;
-                    tsmb.loadConstant(31);
-                    tsmb.math(Opcodes.IMUL);
-                    tsmb.loadThis();
-                    tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
-                    hashCode(tsmb, type);
-                    tsmb.math(Opcodes.IADD);
-                }
-                tsmb.returnValue(TypeDesc.INT);
-                tsmb.finish();
+            // Return
+            tsmb.setLocation(success);
+            tsmb.loadConstant(true);
+            tsmb.returnValue(TypeDesc.BOOLEAN);
+            tsmb.setLocation(failure);
+            tsmb.loadConstant(false);
+            tsmb.returnValue(TypeDesc.BOOLEAN);
+            tsmb.finish();
+        }
+
+        // Create hashCode
+        {
+            MethodBuilderBase tsmb = classBuilder.addMethodBase(Opcodes.ACC_PUBLIC, "hashCode", TypeDesc.INT, Constants.EMPTY_TYPEDESC_ARRAY);
+            tsmb.loadConstant(recordName.hashCode());
+            for(int i=0;i<types.length;++i) {
+                TypeDesc type = types[i];
+                if(type.equals(TypeDesc.VOID))
+                    continue;
+                tsmb.loadConstant(31);
+                tsmb.math(Opcodes.IMUL);
+                tsmb.loadThis();
+                tsmb.loadField(classBuilder.getClassName(), fieldNamePrefix+i, type);
+                hashCode(tsmb, type);
+                tsmb.math(Opcodes.IADD);
             }
+            tsmb.returnValue(TypeDesc.INT);
+            tsmb.finish();
         }
     }
     
index e9d808c8c5eda034a40548e65aa7536e5ce96569..8db288a8976196486ec14ee0601ddbf4a14575b8 100644 (file)
@@ -93,7 +93,7 @@ public class ModuleBuilder {
             // Create fields
             CodeBuilderUtils.makeRecord(classBuilder, functionValue.toString(), Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p",
                     Arrays.copyOf(parameterTypes, knownParametersCount),
-                    false);
+                    true);
             
             // Create apply
             {
@@ -131,7 +131,7 @@ public class ModuleBuilder {
                 for(int i=0;i<knownParametersCount;++i) {
                     mb.loadThis();
                     mb.loadLocal(mb.getParameter(i));
-                    mb.storeField(className, "p"+i, parameterTypes[i]);            
+                    mb.storeField(className, "p"+i, parameterTypes[i]);
                 }
                 mb.returnVoid();
                 mb.finish();
@@ -160,7 +160,9 @@ public class ModuleBuilder {
                 functionValue.applyExact(mb, parameters);
                 mb.box(functionValue.getReturnType());
                 mb.returnValue(TypeDesc.OBJECT);
-            }      
+            }
+            
+            CodeBuilderUtils.implementHashCodeAndEquals(classBuilder, functionValue.toString(), "p", parameterTypes);
         }
             
         // Finish
index bccfa892832a05c2a024f5a7b0f3258c3e35c6c3..4efd2a8d404e7037925fd7d005d782e1fa5c8d3f 100644 (file)
@@ -11,6 +11,192 @@ import org.simantics.scl.runtime.tuple.Tuple0;
 
 public class ValueFromMethod {
 
+    private static final class Arity1Func extends FunctionImpl1<Object, Object> {
+        private final Method method;
+        private final boolean returnsVoid;
+
+        private Arity1Func(Method method, boolean returnsVoid) {
+            this.method = method;
+            this.returnsVoid = returnsVoid;
+        }
+
+        @Override
+        public Object apply(Object p0) {
+            try {
+                Object ret = method.invoke(null, p0);
+                return returnsVoid ? Tuple0.INSTANCE : ret;
+            } catch (ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return method == null ? 0 : method.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Arity1Func other = (Arity1Func) obj;
+            return method.equals(other.method);
+        }
+    }
+
+    private static final class Arity2Func extends FunctionImpl2<Object, Object, Object> {
+        private final Method method;
+        private final boolean returnsVoid;
+
+        private Arity2Func(Method method, boolean returnsVoid) {
+            this.method = method;
+            this.returnsVoid = returnsVoid;
+        }
+
+        @Override
+        public Object apply(Object p0, Object p1) {
+            try {
+                Object ret = method.invoke(null, p0, p1);
+                return returnsVoid ? Tuple0.INSTANCE : ret;
+            } catch (ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        @Override
+        public int hashCode() {
+            return method == null ? 0 : method.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Arity2Func other = (Arity2Func) obj;
+            return method.equals(other.method);
+        }
+    }
+
+    private static final class Arity3Func extends FunctionImpl3<Object, Object, Object, Object> {
+        private final Method method;
+        private final boolean returnsVoid;
+
+        private Arity3Func(Method method, boolean returnsVoid) {
+            this.method = method;
+            this.returnsVoid = returnsVoid;
+        }
+
+        @Override
+        public Object apply(Object p0, Object p1, Object p2) {
+            try {
+                Object ret = method.invoke(null, p0, p1, p2);
+                return returnsVoid ? Tuple0.INSTANCE : ret;
+            } catch (ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        @Override
+        public int hashCode() {
+            return method == null ? 0 : method.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Arity3Func other = (Arity3Func) obj;
+            return method.equals(other.method);
+        }
+    }
+
+    private static final class Arity4Func extends FunctionImpl4<Object, Object, Object, Object, Object> {
+        private final Method method;
+        private final boolean returnsVoid;
+
+        private Arity4Func(Method method, boolean returnsVoid) {
+            this.method = method;
+            this.returnsVoid = returnsVoid;
+        }
+
+        @Override
+        public Object apply(Object p0, Object p1, Object p2, Object p3) {
+            try {
+                Object ret = method.invoke(null, p0, p1, p2, p3);
+                return returnsVoid ? Tuple0.INSTANCE : ret;
+            } catch (ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        @Override
+        public int hashCode() {
+            return method == null ? 0 : method.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            Arity4Func other = (Arity4Func) obj;
+            return method.equals(other.method);
+        }
+    }
+
+    private static final class ArityNFunc extends FunctionImplN {
+        private final Method method;
+        private final boolean returnsVoid;
+
+        private ArityNFunc(int arity, Method method, boolean returnsVoid) {
+            super(arity);
+            this.method = method;
+            this.returnsVoid = returnsVoid;
+        }
+
+        @Override
+        public Object doApply(Object... ps) {
+            try {
+                Object ret =  method.invoke(null, ps);
+                return returnsVoid ? Tuple0.INSTANCE : ret;
+            } catch (ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        @Override
+        public int hashCode() {
+            return method == null ? 0 : method.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            ArityNFunc other = (ArityNFunc) obj;
+            return method.equals(other.method);
+        }
+    }
+
     public static Object getValueFromStaticMethod(final Method method) throws ReflectiveOperationException {
         int arity = method.getParameterTypes().length;
         final boolean returnsVoid = method.getReturnType().equals(void.class);
@@ -20,65 +206,15 @@ public class ValueFromMethod {
             return returnsVoid ? Tuple0.INSTANCE : ret;
         }
         case 1:
-            return new FunctionImpl1<Object,Object>() {
-                @Override
-                public Object apply(Object p0) {
-                    try {
-                        Object ret = method.invoke(null, p0);
-                        return returnsVoid ? Tuple0.INSTANCE : ret;
-                    } catch (ReflectiveOperationException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            };
+            return new Arity1Func(method, returnsVoid);
         case 2:
-            return new FunctionImpl2<Object,Object,Object>() {
-                @Override
-                public Object apply(Object p0, Object p1) {
-                    try {
-                        Object ret = method.invoke(null, p0, p1);
-                        return returnsVoid ? Tuple0.INSTANCE : ret;
-                    } catch (ReflectiveOperationException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            };
+            return new Arity2Func(method, returnsVoid);
         case 3:
-            return new FunctionImpl3<Object,Object,Object,Object>() {
-                @Override
-                public Object apply(Object p0, Object p1, Object p2) {
-                    try {
-                        Object ret = method.invoke(null, p0, p1, p2);
-                        return returnsVoid ? Tuple0.INSTANCE : ret;
-                    } catch (ReflectiveOperationException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            };
+            return new Arity3Func(method, returnsVoid);
         case 4:
-            return new FunctionImpl4<Object,Object,Object,Object,Object>() {
-                @Override
-                public Object apply(Object p0, Object p1, Object p2, Object p3) {
-                    try {
-                        Object ret = method.invoke(null, p0, p1, p2, p3);
-                        return returnsVoid ? Tuple0.INSTANCE : ret;
-                    } catch (ReflectiveOperationException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            };
+            return new Arity4Func(method, returnsVoid);
         default:
-            return new FunctionImplN(arity) {
-                @Override
-                public Object doApply(Object... ps) {
-                    try {
-                        Object ret =  method.invoke(null, ps);
-                        return returnsVoid ? Tuple0.INSTANCE : ret;
-                    } catch (ReflectiveOperationException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            };
+            return new ArityNFunc(arity, method, returnsVoid);
         }
     }
     
index aac13af73abe661ddcc275f0e3f83908b6937e4f..0695ebb4da8396bf3be8f680568419aadadd8b36 100644 (file)
@@ -1,5 +1,7 @@
 package org.simantics.scl.compiler.internal.interpreted;
 
+import java.util.Arrays;
+
 import org.simantics.scl.runtime.function.FunctionImpl1;
 import org.simantics.scl.runtime.function.FunctionImpl2;
 import org.simantics.scl.runtime.function.FunctionImpl3;
@@ -7,11 +9,229 @@ import org.simantics.scl.runtime.function.FunctionImpl4;
 import org.simantics.scl.runtime.function.FunctionImplN;
 
 public class ILambda implements IExpression {
+    private final class Arity1Func extends FunctionImpl1 {
+        private final Object[] inheritedVariableBindings;
+
+        private Arity1Func(Object[] inheritedVariableBindings) {
+            this.inheritedVariableBindings = inheritedVariableBindings;
+        }
+
+        @Override
+        public Object apply(Object param0) {
+            Object[] newVariableBindings = new Object[variableBindingsLength];
+            int i = 0;;
+            for(;i < inheritedVariableBindings.length;++i)
+                newVariableBindings[i] = inheritedVariableBindings[i];
+            newVariableBindings[i] = param0;
+            return body.execute(newVariableBindings);
+        }
+
+        @Override
+        public String toString() {
+            return ILambda.this.toString(inheritedVariableBindings);
+        }
+
+        @Override
+        public int hashCode() {
+            return ILambda.this.hashCode() + 31*Arrays.hashCode(inheritedVariableBindings);
+        }
+
+        private ILambda getParent() {
+            return ILambda.this;
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            if(obj == this)
+                return true;
+            if(obj == null || obj.getClass() != getClass())
+                return false;
+            Arity1Func other = (Arity1Func)obj;
+            return ILambda.this == other.getParent() && Arrays.equals(inheritedVariableBindings, other.inheritedVariableBindings);
+        }
+    }
+
+    private final class Arity2Func extends FunctionImpl2 {
+        private final Object[] inheritedVariableBindings;
+
+        private Arity2Func(Object[] inheritedVariableBindings) {
+            this.inheritedVariableBindings = inheritedVariableBindings;
+        }
+
+        @Override
+        public Object apply(Object param0, Object param1) {
+            Object[] newVariableBindings = new Object[variableBindingsLength];
+            int i = 0;;
+            for(;i < inheritedVariableBindings.length;++i)
+                newVariableBindings[i] = inheritedVariableBindings[i];
+            newVariableBindings[i++] = param0;
+            newVariableBindings[i] = param1;
+            return body.execute(newVariableBindings);
+        }
+
+        @Override
+        public String toString() {
+            return ILambda.this.toString(inheritedVariableBindings);
+        }
+        
+        @Override
+        public int hashCode() {
+            return ILambda.this.hashCode() + 31*Arrays.hashCode(inheritedVariableBindings);
+        }
+
+        private ILambda getParent() {
+            return ILambda.this;
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            if(obj == this)
+                return true;
+            if(obj == null || obj.getClass() != getClass())
+                return false;
+            Arity2Func other = (Arity2Func)obj;
+            return ILambda.this == other.getParent() && Arrays.equals(inheritedVariableBindings, other.inheritedVariableBindings);
+        }
+    }
+
+    private final class Arity3Func extends FunctionImpl3 {
+        private final Object[] inheritedVariableBindings;
+
+        private Arity3Func(Object[] inheritedVariableBindings) {
+            this.inheritedVariableBindings = inheritedVariableBindings;
+        }
+
+        @Override
+        public Object apply(Object param0, Object param1, Object param2) {
+            Object[] newVariableBindings = new Object[variableBindingsLength];
+            int i = 0;;
+            for(;i < inheritedVariableBindings.length;++i)
+                newVariableBindings[i] = inheritedVariableBindings[i];
+            newVariableBindings[i++] = param0;
+            newVariableBindings[i++] = param1;
+            newVariableBindings[i] = param2;
+            return body.execute(newVariableBindings);
+        }
+
+        @Override
+        public String toString() {
+            return ILambda.this.toString(inheritedVariableBindings);
+        }
+        
+        @Override
+        public int hashCode() {
+            return ILambda.this.hashCode() + 31*Arrays.hashCode(inheritedVariableBindings);
+        }
+
+        private ILambda getParent() {
+            return ILambda.this;
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            if(obj == this)
+                return true;
+            if(obj == null || obj.getClass() != getClass())
+                return false;
+            Arity3Func other = (Arity3Func)obj;
+            return ILambda.this == other.getParent() && Arrays.equals(inheritedVariableBindings, other.inheritedVariableBindings);
+        }
+    }
+
+    private final class Arity4Func extends FunctionImpl4 {
+        private final Object[] inheritedVariableBindings;
+
+        private Arity4Func(Object[] inheritedVariableBindings) {
+            this.inheritedVariableBindings = inheritedVariableBindings;
+        }
+
+        @Override
+        public Object apply(Object param0, Object param1, Object param2, Object param3) {
+            Object[] newVariableBindings = new Object[variableBindingsLength];
+            int i = 0;;
+            for(;i < inheritedVariableBindings.length;++i)
+                newVariableBindings[i] = inheritedVariableBindings[i];
+            newVariableBindings[i++] = param0;
+            newVariableBindings[i++] = param1;
+            newVariableBindings[i++] = param2;
+            newVariableBindings[i] = param3;
+            return body.execute(newVariableBindings);
+        }
+
+        @Override
+        public String toString() {
+            return ILambda.this.toString(inheritedVariableBindings);
+        }
+
+        @Override
+        public int hashCode() {
+            return ILambda.this.hashCode() + 31*Arrays.hashCode(inheritedVariableBindings);
+        }
+
+        private ILambda getParent() {
+            return ILambda.this;
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            if(obj == this)
+                return true;
+            if(obj == null || obj.getClass() != getClass())
+                return false;
+            Arity4Func other = (Arity4Func)obj;
+            return ILambda.this == other.getParent() && Arrays.equals(inheritedVariableBindings, other.inheritedVariableBindings);
+        }
+    }
+
+    private final class ArityNFunc extends FunctionImplN {
+        private final Object[] inheritedVariableBindings;
+
+        private ArityNFunc(Object[] inheritedVariableBindings) {
+            super(arity);
+            this.inheritedVariableBindings = inheritedVariableBindings;
+        }
+
+        @Override
+        public Object doApply(Object... ps) {
+            Object[] newVariableBindings = new Object[variableBindingsLength];
+            int i = 0;;
+            for(;i < inheritedVariableBindings.length;++i)
+                newVariableBindings[i] = inheritedVariableBindings[i];
+            for(Object p : ps)
+                newVariableBindings[i++] = p;
+            return body.execute(newVariableBindings);
+        }
+
+        @Override
+        public String toString() {
+            return ILambda.this.toString(inheritedVariableBindings);
+        }
+
+        @Override
+        public int hashCode() {
+            return ILambda.this.hashCode() + 31*Arrays.hashCode(inheritedVariableBindings);
+        }
+
+        private ILambda getParent() {
+            return ILambda.this;
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            if(obj == this)
+                return true;
+            if(obj == null || obj.getClass() != getClass())
+                return false;
+            ArityNFunc other = (ArityNFunc)obj;
+            return ILambda.this == other.getParent() && Arrays.equals(inheritedVariableBindings, other.inheritedVariableBindings);
+        }
+    }
+
     private final int[] inheritedVariableIds;
     private final int arity;
     private final int variableBindingsLength;
     private final IExpression body;
-    
+
     public ILambda(int[] inheritedVariableIds, int arity,
             int variableBindingsLength, IExpression body) {
         this.inheritedVariableIds = inheritedVariableIds;
@@ -20,7 +240,6 @@ public class ILambda implements IExpression {
         this.body = body;
     }
 
-    @SuppressWarnings("rawtypes")
     @Override
     public Object execute(Object[] variableBindings) {
         final Object[] inheritedVariableBindings = new Object[inheritedVariableIds.length];
@@ -28,100 +247,18 @@ public class ILambda implements IExpression {
             inheritedVariableBindings[i] = variableBindings[inheritedVariableIds[i]];
         switch(arity) {
         case 1:
-            return new FunctionImpl1() {
-                @Override
-                public Object apply(Object param0) {
-                    Object[] newVariableBindings = new Object[variableBindingsLength];
-                    int i = 0;;
-                    for(;i < inheritedVariableBindings.length;++i)
-                        newVariableBindings[i] = inheritedVariableBindings[i];
-                    newVariableBindings[i] = param0;
-                    return body.execute(newVariableBindings);
-                }
-                
-                @Override
-                public String toString() {
-                       return ILambda.this.toString(inheritedVariableBindings);
-                }
-            };
+            return new Arity1Func(inheritedVariableBindings);
         case 2:
-            return new FunctionImpl2() {
-                @Override
-                public Object apply(Object param0, Object param1) {
-                    Object[] newVariableBindings = new Object[variableBindingsLength];
-                    int i = 0;;
-                    for(;i < inheritedVariableBindings.length;++i)
-                        newVariableBindings[i] = inheritedVariableBindings[i];
-                    newVariableBindings[i++] = param0;
-                    newVariableBindings[i] = param1;
-                    return body.execute(newVariableBindings);
-                }
-                
-                @Override
-                public String toString() {
-                       return ILambda.this.toString(inheritedVariableBindings);
-                }
-            };
+            return new Arity2Func(inheritedVariableBindings);
         case 3:
-            return new FunctionImpl3() {
-                @Override
-                public Object apply(Object param0, Object param1, Object param2) {
-                    Object[] newVariableBindings = new Object[variableBindingsLength];
-                    int i = 0;;
-                    for(;i < inheritedVariableBindings.length;++i)
-                        newVariableBindings[i] = inheritedVariableBindings[i];
-                    newVariableBindings[i++] = param0;
-                    newVariableBindings[i++] = param1;
-                    newVariableBindings[i] = param2;
-                    return body.execute(newVariableBindings);
-                }
-                
-                @Override
-                public String toString() {
-                       return ILambda.this.toString(inheritedVariableBindings);
-                }
-            };
+            return new Arity3Func(inheritedVariableBindings);
         case 4:
-            return new FunctionImpl4() {
-                @Override
-                public Object apply(Object param0, Object param1, Object param2, Object param3) {
-                    Object[] newVariableBindings = new Object[variableBindingsLength];
-                    int i = 0;;
-                    for(;i < inheritedVariableBindings.length;++i)
-                        newVariableBindings[i] = inheritedVariableBindings[i];
-                    newVariableBindings[i++] = param0;
-                    newVariableBindings[i++] = param1;
-                    newVariableBindings[i++] = param2;
-                    newVariableBindings[i] = param3;
-                    return body.execute(newVariableBindings);
-                }
-                
-                @Override
-                public String toString() {
-                       return ILambda.this.toString(inheritedVariableBindings);
-                }
-            };
+            return new Arity4Func(inheritedVariableBindings);
         default:
-            return new FunctionImplN(arity) {
-                @Override
-                public Object doApply(Object... ps) {
-                    Object[] newVariableBindings = new Object[variableBindingsLength];
-                    int i = 0;;
-                    for(;i < inheritedVariableBindings.length;++i)
-                        newVariableBindings[i] = inheritedVariableBindings[i];
-                    for(Object p : ps)
-                        newVariableBindings[i++] = p;
-                    return body.execute(newVariableBindings);
-                }
-                
-                @Override
-                public String toString() {
-                       return ILambda.this.toString(inheritedVariableBindings);
-                }
-            };
+            return new ArityNFunc(inheritedVariableBindings);
         }
     }
-    
+
     @Override
     public String toString() {
         StringBuilder b = new StringBuilder();
@@ -136,22 +273,22 @@ public class ILambda implements IExpression {
         b.append(')');
         return b.toString();
     }
-    
+
     public String toString(Object[] variableBindings) {
-       StringBuilder sb = new StringBuilder();
-       appendVariableBindings(sb, variableBindings);
-       sb.append(this.toString());
-       return sb.toString();
+        StringBuilder sb = new StringBuilder();
+        appendVariableBindings(sb, variableBindings);
+        sb.append(this.toString());
+        return sb.toString();
     }
-    
+
     private static void appendVariableBindings(StringBuilder sb, Object[] variableBindings) {
-       if (variableBindings.length > 0) {
-               sb.append("(let {");
-               for(int i = 0; i < variableBindings.length; i++) {
-                       if (i > 0) sb.append("; ");
-                       sb.append("v").append(i).append("=").append(variableBindings[i].toString());
-               }
-               sb.append("} in ");
-       }       
+        if (variableBindings.length > 0) {
+            sb.append("(let {");
+            for(int i = 0; i < variableBindings.length; i++) {
+                if (i > 0) sb.append("; ");
+                sb.append("v").append(i).append("=").append(variableBindings[i].toString());
+            }
+            sb.append("} in ");
+        }      
     }
 }
index adf2dee305c3693064d1d2a5893888d589ab8087..2e61986e855103a48022305b764aed0b794a8b34 100644 (file)
@@ -11,9 +11,9 @@ public class GenerateFunctions {
     public static final int MAX_ARITY = 8;
     
     public static final String HEADER =
-            "/**\n"
-          + " * This code is generated in " + GenerateFunctions.class.getName() + ".\n"
-          + " * Do not edit manually!\n"
+            "/**\r\n"
+          + " * This code is generated in " + GenerateFunctions.class.getName() + ".\r\n"
+          + " * Do not edit manually!\r\n"
           + " */" 
             ;
     
@@ -342,6 +342,7 @@ public class GenerateFunctions {
             p.println("            nps[i + " + n + "] = ps[i];");
             p.println("        return f.applyArray(nps);");
             p.println("    }");
+            p.println();
         }
         {
             p.println("    @Override");
@@ -353,6 +354,40 @@ public class GenerateFunctions {
             p.println("        sb.append(\")\");");
             p.println("        return sb.toString();");
             p.println("    }");
+            p.println();
+        }
+        {
+            p.println("    @Override");
+            p.println("    public int hashCode() {");
+            p.println("        int result = f.hashCode();");
+            for(int i=0;i<n;++i)
+                p.println("        result = 31 * result + (p"+i+" == null ? 0 : p"+i+".hashCode());");
+            p.println("        return result;");
+            p.println("    }");
+            p.println();
+        }
+        {
+            p.println("    @Override");
+            p.println("    public boolean equals(Object obj) {");
+            p.println("        if (this == obj)");
+            p.println("            return true;");
+            p.println("        if (obj == null)");
+            p.println("            return false;");
+            p.println("        if (getClass() != obj.getClass())");
+            p.println("            return false;");
+            p.println("        UnsaturatedFunction"+n+" other = (UnsaturatedFunction"+n+") obj;");
+            p.println("        if(!f.equals(other.f))");
+            p.println("            return false;");
+            for(int i=0;i<n;++i) {
+                p.println("        if(p"+i+" == null) {");
+                p.println("            if (other.p"+i+" != null)");
+                p.println("                return false;");
+                p.println("        } else if (!p"+i+".equals(other.p"+i+"))");
+                p.println("            return false;");
+            }
+            p.println("        return true;");
+            p.println("    }");
+            p.println();
         }
         p.println("}");
     }
@@ -361,6 +396,8 @@ public class GenerateFunctions {
         p.println(HEADER);
         p.println("package " + PACKAGE + ";");
         p.println();
+        p.println("import java.util.Arrays;");
+        p.println();
         p.println("@SuppressWarnings(\"all\")");
         p.println("public class UnsaturatedFunctionN implements Function {");
         p.println("    private final Function f;");
@@ -396,6 +433,7 @@ public class GenerateFunctions {
             p.println("        System.arraycopy(ops, 0, nps, ps.length, ops.length);");
             p.println("        return f.applyArray(nps);");
             p.println("    }");
+            p.println();
         }
         {
             p.println("    @Override");
@@ -407,6 +445,28 @@ public class GenerateFunctions {
             p.println("        sb.append(\")\");");
             p.println("        return sb.toString();");
             p.println("    }");
+            p.println();
+        }
+        {
+            p.println("    @Override");
+            p.println("    public int hashCode() {");
+            p.println("        return f.hashCode() + 31 * Arrays.hashCode(ps);");
+            p.println("    }");
+            p.println();
+        }
+        {
+            p.println("    @Override");
+            p.println("    public boolean equals(Object obj) {");
+            p.println("        if (this == obj)");
+            p.println("            return true;");
+            p.println("        if (obj == null)");
+            p.println("            return false;");
+            p.println("        if (getClass() != obj.getClass())");
+            p.println("            return false;");
+            p.println("        UnsaturatedFunctionN other = (UnsaturatedFunctionN) obj;");
+            p.println("        return f.equals(other.f) && Arrays.equals(ps, other.ps);");
+            p.println("    }");
+            p.println();
         }
         p.println("}");
     }
index 7149fc63ef9d8d8ddc9256aa9ce4319213a8c924..a5722763551855d4d60525066732ba9943420d8c 100644 (file)
@@ -144,16 +144,17 @@ public class Lists {
     public static Object get(List l, double i) {
         return l.get((int)i);
     }
+
+    private static final FunctionImpl2 BUILD_FUNC = new FunctionImpl2() {
+        @Override
+        public Object apply(Object p0, Object p1) {
+            ((ArrayList)p0).add(p1);
+            return p0;
+        }
+    };
     
     public static List build(Function f) {
-        return (List)f.apply(new ArrayList(),
-                new FunctionImpl2() {
-            @Override
-            public Object apply(Object p0, Object p1) {
-                ((List)p0).add(p1);
-                return p0;
-            }
-        });
+        return (List)f.apply(new ArrayList(), BUILD_FUNC);
     }
     
     public static List range(int from, int to) {
index b3b858236a2b9c017adca1209ea073b4f1499dc9..1dbca0be94f8f223b8d117f7561c228bec085ceb 100644 (file)
@@ -62,6 +62,7 @@ public class UnsaturatedFunction1 implements Function {
             nps[i + 1] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -70,4 +71,31 @@ public class UnsaturatedFunction1 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction1 other = (UnsaturatedFunction1) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        return true;
+    }
+
 }
index a1ffa2d2ccee5bf6e05206f23f686936a6daadf5..7f02cf51f77f8d2432fb63326c63d3d9b0f541f5 100644 (file)
@@ -65,6 +65,7 @@ public class UnsaturatedFunction2 implements Function {
             nps[i + 2] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -74,4 +75,37 @@ public class UnsaturatedFunction2 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction2 other = (UnsaturatedFunction2) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        return true;
+    }
+
 }
index c9f740c8266f3b35d67dc534ad789eaa2cb76c83..68457f29fd4c135d71b997ee0068e6c792140dc9 100644 (file)
@@ -68,6 +68,7 @@ public class UnsaturatedFunction3 implements Function {
             nps[i + 3] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -78,4 +79,43 @@ public class UnsaturatedFunction3 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        result = 31 * result + (p2 == null ? 0 : p2.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction3 other = (UnsaturatedFunction3) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        if(p2 == null) {
+            if (other.p2 != null)
+                return false;
+        } else if (!p2.equals(other.p2))
+            return false;
+        return true;
+    }
+
 }
index 7d17072ff2d6d5c39315e1c0b5c7be100877b6a3..93baf458601642e25f9297a988069554b1ec4ddd 100644 (file)
@@ -71,6 +71,7 @@ public class UnsaturatedFunction4 implements Function {
             nps[i + 4] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -82,4 +83,49 @@ public class UnsaturatedFunction4 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        result = 31 * result + (p2 == null ? 0 : p2.hashCode());
+        result = 31 * result + (p3 == null ? 0 : p3.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction4 other = (UnsaturatedFunction4) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        if(p2 == null) {
+            if (other.p2 != null)
+                return false;
+        } else if (!p2.equals(other.p2))
+            return false;
+        if(p3 == null) {
+            if (other.p3 != null)
+                return false;
+        } else if (!p3.equals(other.p3))
+            return false;
+        return true;
+    }
+
 }
index bb6e861672a86e32c302d85d8650b0907ed29127..92952170267872e4ba2de48f5b6c3e0956c02975 100644 (file)
@@ -74,6 +74,7 @@ public class UnsaturatedFunction5 implements Function {
             nps[i + 5] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -86,4 +87,55 @@ public class UnsaturatedFunction5 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        result = 31 * result + (p2 == null ? 0 : p2.hashCode());
+        result = 31 * result + (p3 == null ? 0 : p3.hashCode());
+        result = 31 * result + (p4 == null ? 0 : p4.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction5 other = (UnsaturatedFunction5) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        if(p2 == null) {
+            if (other.p2 != null)
+                return false;
+        } else if (!p2.equals(other.p2))
+            return false;
+        if(p3 == null) {
+            if (other.p3 != null)
+                return false;
+        } else if (!p3.equals(other.p3))
+            return false;
+        if(p4 == null) {
+            if (other.p4 != null)
+                return false;
+        } else if (!p4.equals(other.p4))
+            return false;
+        return true;
+    }
+
 }
index cebc2943af9f69ab6c6cbb126e353f715c00e42d..ec20e47e5c4120bd8c103e6b8cb65118435048bf 100644 (file)
@@ -77,6 +77,7 @@ public class UnsaturatedFunction6 implements Function {
             nps[i + 6] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -90,4 +91,61 @@ public class UnsaturatedFunction6 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        result = 31 * result + (p2 == null ? 0 : p2.hashCode());
+        result = 31 * result + (p3 == null ? 0 : p3.hashCode());
+        result = 31 * result + (p4 == null ? 0 : p4.hashCode());
+        result = 31 * result + (p5 == null ? 0 : p5.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction6 other = (UnsaturatedFunction6) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        if(p2 == null) {
+            if (other.p2 != null)
+                return false;
+        } else if (!p2.equals(other.p2))
+            return false;
+        if(p3 == null) {
+            if (other.p3 != null)
+                return false;
+        } else if (!p3.equals(other.p3))
+            return false;
+        if(p4 == null) {
+            if (other.p4 != null)
+                return false;
+        } else if (!p4.equals(other.p4))
+            return false;
+        if(p5 == null) {
+            if (other.p5 != null)
+                return false;
+        } else if (!p5.equals(other.p5))
+            return false;
+        return true;
+    }
+
 }
index c5fdf4a441c28e9b09715cb3238a5b91a1b5d364..0a4f18203db442ae3e6758959cda121605a1f6a3 100644 (file)
@@ -80,6 +80,7 @@ public class UnsaturatedFunction7 implements Function {
             nps[i + 7] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -94,4 +95,67 @@ public class UnsaturatedFunction7 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        result = 31 * result + (p2 == null ? 0 : p2.hashCode());
+        result = 31 * result + (p3 == null ? 0 : p3.hashCode());
+        result = 31 * result + (p4 == null ? 0 : p4.hashCode());
+        result = 31 * result + (p5 == null ? 0 : p5.hashCode());
+        result = 31 * result + (p6 == null ? 0 : p6.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction7 other = (UnsaturatedFunction7) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        if(p2 == null) {
+            if (other.p2 != null)
+                return false;
+        } else if (!p2.equals(other.p2))
+            return false;
+        if(p3 == null) {
+            if (other.p3 != null)
+                return false;
+        } else if (!p3.equals(other.p3))
+            return false;
+        if(p4 == null) {
+            if (other.p4 != null)
+                return false;
+        } else if (!p4.equals(other.p4))
+            return false;
+        if(p5 == null) {
+            if (other.p5 != null)
+                return false;
+        } else if (!p5.equals(other.p5))
+            return false;
+        if(p6 == null) {
+            if (other.p6 != null)
+                return false;
+        } else if (!p6.equals(other.p6))
+            return false;
+        return true;
+    }
+
 }
index 4686cbc2b5e818e0628357cf1555b32c3a811174..6a030e9c0d3183aa8db08f2cacec7c28c907f4bf 100644 (file)
@@ -83,6 +83,7 @@ public class UnsaturatedFunction8 implements Function {
             nps[i + 8] = ps[i];
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -98,4 +99,73 @@ public class UnsaturatedFunction8 implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        int result = f.hashCode();
+        result = 31 * result + (p0 == null ? 0 : p0.hashCode());
+        result = 31 * result + (p1 == null ? 0 : p1.hashCode());
+        result = 31 * result + (p2 == null ? 0 : p2.hashCode());
+        result = 31 * result + (p3 == null ? 0 : p3.hashCode());
+        result = 31 * result + (p4 == null ? 0 : p4.hashCode());
+        result = 31 * result + (p5 == null ? 0 : p5.hashCode());
+        result = 31 * result + (p6 == null ? 0 : p6.hashCode());
+        result = 31 * result + (p7 == null ? 0 : p7.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunction8 other = (UnsaturatedFunction8) obj;
+        if(!f.equals(other.f))
+            return false;
+        if(p0 == null) {
+            if (other.p0 != null)
+                return false;
+        } else if (!p0.equals(other.p0))
+            return false;
+        if(p1 == null) {
+            if (other.p1 != null)
+                return false;
+        } else if (!p1.equals(other.p1))
+            return false;
+        if(p2 == null) {
+            if (other.p2 != null)
+                return false;
+        } else if (!p2.equals(other.p2))
+            return false;
+        if(p3 == null) {
+            if (other.p3 != null)
+                return false;
+        } else if (!p3.equals(other.p3))
+            return false;
+        if(p4 == null) {
+            if (other.p4 != null)
+                return false;
+        } else if (!p4.equals(other.p4))
+            return false;
+        if(p5 == null) {
+            if (other.p5 != null)
+                return false;
+        } else if (!p5.equals(other.p5))
+            return false;
+        if(p6 == null) {
+            if (other.p6 != null)
+                return false;
+        } else if (!p6.equals(other.p6))
+            return false;
+        if(p7 == null) {
+            if (other.p7 != null)
+                return false;
+        } else if (!p7.equals(other.p7))
+            return false;
+        return true;
+    }
+
 }
index c53b34735e4f1fdf4896227beb1b434148306f65..2ed78c5c4be38672dfd260dab473384f2668ff6f 100644 (file)
@@ -4,6 +4,8 @@
  */
 package org.simantics.scl.runtime.function;
 
+import java.util.Arrays;
+
 @SuppressWarnings("all")
 public class UnsaturatedFunctionN implements Function {
     private final Function f;
@@ -113,6 +115,7 @@ public class UnsaturatedFunctionN implements Function {
         System.arraycopy(ops, 0, nps, ps.length, ops.length);
         return f.applyArray(nps);
     }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -122,4 +125,22 @@ public class UnsaturatedFunctionN implements Function {
         sb.append(")");
         return sb.toString();
     }
+
+    @Override
+    public int hashCode() {
+        return f.hashCode() + 31 * Arrays.hashCode(ps);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        UnsaturatedFunctionN other = (UnsaturatedFunctionN) obj;
+        return f.equals(other.f) && Arrays.equals(ps, other.ps);
+    }
+
 }
index 1c134aff7054ea81445f858f73c6e16fe6eff850..cecc93e84c7df47f9f73463697419a38c1993062 100644 (file)
@@ -73,6 +73,7 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void FromDynamic4() { test(); }
     @Test public void FromDynamic5() { test(); }
     @Test public void FunctionFunctor() { test(); }
+    @Test public void FunctionIdentity() { test(); }
     @Test public void Functor() { test(); }
     @Test public void FunctorM1() { test(); }
     @Test public void Generalization() { test(); }
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionIdentity.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/FunctionIdentity.scl
new file mode 100644 (file)
index 0000000..cbf797b
--- /dev/null
@@ -0,0 +1,9 @@
+import "Prelude"
+
+f n = do
+  a = n+1
+  \x -> a + x
+
+main = [atan2 1==atan2 1, atan2 1==atan2 2, f 1==f 1, f 1==f 2]
+--
+[true, false, true, false]
\ No newline at end of file