From fd0769bde1ffad49ca74a404f18aae5d7226c558 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Fri, 1 Jan 2016 15:33:57 +0000 Subject: Get interpreter compiler tests working --- .../java/org/zwobble/couscous/ast/ClassNode.java | 80 ++++++++++------------ .../org/zwobble/couscous/ast/ClassNodeBuilder.java | 6 +- .../couscous/frontends/java/JavaReader.java | 17 ++++- .../zwobble/couscous/frontends/java/JavaTypes.java | 45 ++++++++++-- .../couscous/interpreter/InterpreterTypes.java | 16 +++-- .../values/BoxedIntegerInterpreterValue.java | 18 ++++- .../couscous/interpreter/values/ConcreteType.java | 38 +++++++--- .../values/IntegerInterpreterValue.java | 6 ++ .../values/InternalCouscousInterpreterValue.java | 6 +- .../org/zwobble/couscous/values/BooleanValue.java | 1 + 10 files changed, 167 insertions(+), 66 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index 55453f4..3545084 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -3,6 +3,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; import java.util.List; +import java.util.Set; public class ClassNode implements Node { public static ClassNodeBuilder builder(String name) { @@ -10,23 +11,27 @@ public class ClassNode implements Node { } public static ClassNode declareClass( TypeName name, + Set superTypes, List fields, ConstructorNode constructor, List methods) { - return new ClassNode(name, fields, constructor, methods); + return new ClassNode(name, superTypes, fields, constructor, methods); } private final TypeName name; + private final Set superTypes; private final List fields; private final ConstructorNode constructor; private final List methods; private ClassNode( TypeName name, + Set superTypes, List fields, ConstructorNode constructor, List methodNodes) { this.name = name; + this.superTypes = superTypes; this.fields = fields; this.constructor = constructor; methods = methodNodes; @@ -35,7 +40,11 @@ public class ClassNode implements Node { public TypeName getName() { return name; } - + + public Set getSuperTypes() { + return superTypes; + } + public List getFields() { return fields; } @@ -59,51 +68,38 @@ public class ClassNode implements Node { @Override public String toString() { - return "ClassNode(name=" + name + ", fields=" + fields - + ", constructor=" + constructor + ", methods=" + methods + ")"; + return "ClassNode(" + + "name=" + name + + ", superTypes=" + superTypes + + ", fields=" + fields + + ", constructor=" + constructor + + ", methods=" + methods + + ')'; } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((constructor == null) ? 0 : constructor.hashCode()); - result = prime * result + ((fields == null) ? 0 : fields.hashCode()); - result = prime * result + ((methods == null) ? 0 : methods.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ClassNode classNode = (ClassNode) o; + + if (name != null ? !name.equals(classNode.name) : classNode.name != null) return false; + if (superTypes != null ? !superTypes.equals(classNode.superTypes) : classNode.superTypes != null) return false; + if (fields != null ? !fields.equals(classNode.fields) : classNode.fields != null) return false; + if (constructor != null ? !constructor.equals(classNode.constructor) : classNode.constructor != null) + return false; + return methods != null ? methods.equals(classNode.methods) : classNode.methods == null; + } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ClassNode other = (ClassNode) obj; - if (constructor == null) { - if (other.constructor != null) - return false; - } else if (!constructor.equals(other.constructor)) - return false; - if (fields == null) { - if (other.fields != null) - return false; - } else if (!fields.equals(other.fields)) - return false; - if (methods == null) { - if (other.methods != null) - return false; - } else if (!methods.equals(other.methods)) - return false; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (superTypes != null ? superTypes.hashCode() : 0); + result = 31 * result + (fields != null ? fields.hashCode() : 0); + result = 31 * result + (constructor != null ? constructor.hashCode() : 0); + result = 31 * result + (methods != null ? methods.hashCode() : 0); + return result; } } diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java index 5981e34..9be591c 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java @@ -1,10 +1,11 @@ package org.zwobble.couscous.ast; +import com.google.common.collect.ImmutableList; + import java.util.Optional; import java.util.function.Function; -import com.google.common.collect.ImmutableList; - +import static java.util.Collections.emptySet; import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg; import static org.zwobble.couscous.ast.VariableDeclaration.var; @@ -81,6 +82,7 @@ public class ClassNodeBuilder { public ClassNode build() { return ClassNode.declareClass( name, + emptySet(), fields.build(), constructor.orElse(ConstructorNode.DEFAULT), methods.build()); diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java index 76dcf22..2963fd6 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java @@ -12,6 +12,7 @@ import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import static com.google.common.collect.Iterables.concat; @@ -29,6 +30,7 @@ import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference; import static org.zwobble.couscous.ast.VariableDeclaration.var; import static org.zwobble.couscous.ast.VariableReferenceNode.reference; import static org.zwobble.couscous.frontends.java.FreeVariables.findFreeVariables; +import static org.zwobble.couscous.frontends.java.JavaTypes.superTypes; import static org.zwobble.couscous.frontends.java.JavaTypes.typeOf; import static org.zwobble.couscous.util.Casts.tryCast; import static org.zwobble.couscous.util.ExtraLists.*; @@ -58,6 +60,7 @@ public class JavaReader { TypeDeclarationBody body = readTypeDeclarationBody(type.bodyDeclarations()); return ClassNode.declareClass( name, + superTypes(type), body.getFields(), body.getConstructor(), body.getMethods()); @@ -75,7 +78,11 @@ public class JavaReader { lambda.getFormalArguments(), lambda.getBody()); - GeneratedClosure closure = classWithCapture(className, emptyList(), ImmutableList.of(method)); + GeneratedClosure closure = classWithCapture( + className, + superTypes(expression), + emptyList(), + ImmutableList.of(method)); classes.add(closure.getClassNode()); return closure; @@ -132,13 +139,18 @@ public class JavaReader { GeneratedClosure readAnonymousClass(AnonymousClassDeclaration declaration) { TypeName className = generateClassName(declaration); TypeDeclarationBody bodyDeclarations = readTypeDeclarationBody(declaration.bodyDeclarations()); - GeneratedClosure closure = classWithCapture(className, bodyDeclarations.getFields(), bodyDeclarations.getMethods()); + GeneratedClosure closure = classWithCapture( + className, + superTypes(declaration), + bodyDeclarations.getFields(), + bodyDeclarations.getMethods()); classes.add(closure.getClassNode()); return closure; } private GeneratedClosure classWithCapture( TypeName className, + Set superTypes, List declaredFields, List methods ) { @@ -151,6 +163,7 @@ public class JavaReader { ClassNode classNode = ClassNode.declareClass( className, + superTypes, fields, buildConstructor(className, freeVariables), eagerMap(methods, method -> diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java index d6b2160..4b62a17 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java @@ -1,10 +1,14 @@ package org.zwobble.couscous.frontends.java; -import org.eclipse.jdt.core.dom.Expression; -import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jdt.core.dom.IVariableBinding; -import org.eclipse.jdt.core.dom.Type; +import com.google.common.collect.ImmutableSet; +import org.eclipse.jdt.core.dom.*; import org.zwobble.couscous.ast.TypeName; +import org.zwobble.couscous.values.ObjectValues; + +import java.util.Set; + +import static com.google.common.collect.Iterables.transform; +import static java.util.Arrays.asList; class JavaTypes { static TypeName typeOf(Expression expression) { @@ -22,4 +26,37 @@ class JavaTypes { static TypeName typeOf(ITypeBinding typeBinding) { return TypeName.of(typeBinding.getQualifiedName()); } + + static Set superTypes(TypeDeclaration declaration) { + return superTypes(declaration.resolveBinding()); + } + + static Set superTypes(AnonymousClassDeclaration declaration) { + return superTypes(declaration.resolveBinding()); + } + + static Set superTypes(LambdaExpression expression) { + ImmutableSet.Builder superTypes = ImmutableSet.builder(); + ITypeBinding typeBinding = expression.resolveTypeBinding(); + superTypes.addAll(superTypes(typeBinding)); + superTypes.add(typeOf(typeBinding)); + return superTypes.build(); + } + + private static Set superTypes(ITypeBinding typeBinding) { + ImmutableSet.Builder superTypes = ImmutableSet.builder(); + superTypes.addAll(transform( + asList(typeBinding.getInterfaces()), + JavaTypes::typeOf)); + superTypes.add(superClass(typeBinding)); + return superTypes.build(); + } + + private static TypeName superClass(ITypeBinding typeBinding) { + if (typeBinding.getSuperclass() == null) { + return ObjectValues.OBJECT; + } else { + return typeOf(typeBinding.getSuperclass()); + } + } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/InterpreterTypes.java b/src/main/java/org/zwobble/couscous/interpreter/InterpreterTypes.java index bb76280..1e644c8 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/InterpreterTypes.java +++ b/src/main/java/org/zwobble/couscous/interpreter/InterpreterTypes.java @@ -1,17 +1,25 @@ package org.zwobble.couscous.interpreter; import org.zwobble.couscous.ast.TypeName; +import org.zwobble.couscous.interpreter.values.ConcreteType; import org.zwobble.couscous.interpreter.values.InterpreterValue; import org.zwobble.couscous.values.ObjectValues; public class InterpreterTypes { public static void checkIsInstance(TypeName type, InterpreterValue value) { - checkIsSubType(type, value.getType().getName()); + checkIsSubType(type, value.getType()); } - private static void checkIsSubType(TypeName superType, TypeName subType) { - if (!superType.equals(subType) && !superType.equals(ObjectValues.OBJECT)) { - throw new UnexpectedValueType(superType, subType); + private static void checkIsSubType(TypeName superTypeName, ConcreteType subType) { + if (!isSubType(superTypeName, subType)) { + throw new UnexpectedValueType(superTypeName, subType.getName()); } } + + private static boolean isSubType(TypeName superTypeName, ConcreteType subType) { + return + superTypeName.equals(subType.getName()) || + superTypeName.equals(ObjectValues.OBJECT) || + subType.getSuperTypes().contains(superTypeName); + } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/BoxedIntegerInterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/BoxedIntegerInterpreterValue.java index 458eca7..3ffa244 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/BoxedIntegerInterpreterValue.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/BoxedIntegerInterpreterValue.java @@ -1,16 +1,32 @@ package org.zwobble.couscous.interpreter.values; +import org.zwobble.couscous.ast.Operator; +import org.zwobble.couscous.values.IntegerValue; +import org.zwobble.couscous.values.ObjectValues; import org.zwobble.couscous.values.StringValue; import static java.util.Arrays.asList; public class BoxedIntegerInterpreterValue { public static final ConcreteType TYPE = ConcreteType.classBuilder("java.lang.Integer") + .field("value", IntegerValue.REF) + .staticMethod("parseInt", asList(StringValue.REF), (environment, arguments) -> { StringInterpreterValue value = (StringInterpreterValue)arguments.get(0); return new IntegerInterpreterValue(Integer.parseInt(value.getValue())); }) - + + .method(Operator.EQUALS.getMethodName(), asList(ObjectValues.OBJECT), + (environment, arguments) -> { + InterpreterValue right = arguments.getPositionalArguments().get(0); + if (right.getType().getName().equals(ObjectValues.BOXED_INT)) { + IntegerInterpreterValue leftValue = (IntegerInterpreterValue)arguments.getReceiver().getField("value"); + IntegerInterpreterValue rightValue = (IntegerInterpreterValue)right.getField("value"); + return new BooleanInterpreterValue(leftValue.getValue() == rightValue.getValue()); + } else { + return new BooleanInterpreterValue(false); + } + }) .build(); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java index 8d2c2d5..c053739 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java @@ -1,8 +1,6 @@ package org.zwobble.couscous.interpreter.values; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.BiFunction; import java.util.stream.Collectors; import org.zwobble.couscous.ast.ClassNode; @@ -34,6 +32,7 @@ public class ConcreteType { } public static class Builder { + private final ImmutableMap.Builder fields = ImmutableMap.builder(); private final ImmutableMap.Builder methods = ImmutableMap.builder(); private final ImmutableMap.Builder staticMethods = ImmutableMap.builder(); private final Class interpreterValueType; @@ -43,7 +42,12 @@ public class ConcreteType { this.interpreterValueType = interpreterValueType; this.name = name; } - + + public Builder field(String name, TypeName type) { + fields.put(name, new FieldValue(name, type)); + return this; + } + public Builder method(String name, List argumentsTypes, BiFunction, InterpreterValue> method) { methods.put(name, new MethodValue(argumentsTypes, (environment, arguments) -> { return Casts.tryCast(interpreterValueType, arguments.getReceiver()).map(typedReceiver -> method.apply(environment, MethodCallArguments.of(typedReceiver, arguments.getPositionalArguments()))).orElseThrow(() -> new RuntimeException("receiver is of wrong type")); @@ -57,7 +61,13 @@ public class ConcreteType { } public ConcreteType build() { - return new ConcreteType(name, ImmutableMap.of(), new MethodValue(ImmutableList.of(), (environment, arguments) -> InterpreterValues.UNIT), methods.build(), staticMethods.build()); + return new ConcreteType( + name, + Collections.emptySet(), + fields.build(), + new MethodValue(ImmutableList.of(), (environment, arguments) -> InterpreterValues.UNIT), + methods.build(), + staticMethods.build()); } } @@ -76,20 +86,28 @@ public class ConcreteType { return Executor.callMethod(environment, method, Optional.empty(), arguments); }); })); - return new ConcreteType(classNode.getName(), fields, constructor, methods, staticMethods); + return new ConcreteType(classNode.getName(), classNode.getSuperTypes(), fields, constructor, methods, staticMethods); } private static List getArgumentTypes(List arguments) { return arguments.stream().map(arg -> arg.getType()).collect(Collectors.toList()); } private final TypeName name; + private final Set superTypes; private final Map fields; private final MethodValue constructor; private final Map methods; private final Map staticMethods; - private ConcreteType(TypeName name, Map fields, MethodValue constructor, Map methods, Map staticMethods) { + private ConcreteType( + TypeName name, + Set superTypes, + Map fields, + MethodValue constructor, + Map methods, + Map staticMethods) { this.name = name; + this.superTypes = superTypes; this.fields = fields; this.constructor = constructor; this.methods = methods; @@ -99,7 +117,11 @@ public class ConcreteType { public TypeName getName() { return name; } - + + public Set getSuperTypes() { + return superTypes; + } + public Optional getField(String fieldName) { return Optional.ofNullable(fields.get(fieldName)); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java index da28bc5..3bcb41a 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java @@ -97,6 +97,12 @@ public final class IntegerInterpreterValue implements InterpreterValue { public int getValue() { return this.value; } + + public InterpreterValue box() { + ObjectInterpreterValue box = new ObjectInterpreterValue(BoxedIntegerInterpreterValue.TYPE); + box.setField("value", this); + return box; + } @java.lang.Override public boolean equals(final java.lang.Object o) { diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/InternalCouscousInterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/InternalCouscousInterpreterValue.java index ef4c37b..4d3f33a 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/InternalCouscousInterpreterValue.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/InternalCouscousInterpreterValue.java @@ -19,10 +19,10 @@ public class InternalCouscousInterpreterValue { ((environment, arguments) -> arguments.get(0))) .staticMethod("boxInt", asList(IntegerValue.REF), - ((environment, arguments) -> arguments.get(0))) + ((environment, arguments) -> ((IntegerInterpreterValue)arguments.get(0)).box())) - .staticMethod("unboxInt", asList(IntegerValue.REF), - ((environment, arguments) -> arguments.get(0))) + .staticMethod("unboxInt", asList(ObjectValues.BOXED_INT), + ((environment, arguments) -> arguments.get(0).getField("value"))) .build(); } diff --git a/src/main/java/org/zwobble/couscous/values/BooleanValue.java b/src/main/java/org/zwobble/couscous/values/BooleanValue.java index 5e6191f..1d2c0a4 100644 --- a/src/main/java/org/zwobble/couscous/values/BooleanValue.java +++ b/src/main/java/org/zwobble/couscous/values/BooleanValue.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.values; import org.zwobble.couscous.ast.TypeName; +import org.zwobble.couscous.interpreter.values.InterpreterValue; public final class BooleanValue implements PrimitiveValue { public static final TypeName REF = TypeName.of("boolean"); -- cgit v1.2.3