diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-01-04 23:28:22 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-01-04 23:28:22 +0000 |
| commit | 75b69c7f4e7ed84f82c549e36a3928a48720cc26 (patch) | |
| tree | d400967b67b7e6ec7c922a586ae14c6cda35f6ed /src/main/java | |
| parent | bb0b36b86f841ec6340fe6e727ed2ea9db1c2d64 (diff) | |
Move type coercion decisions into the backends
Diffstat (limited to 'src/main/java')
13 files changed, 161 insertions, 79 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java index 0f1ab4f..c483bcd 100644 --- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java @@ -56,6 +56,11 @@ public interface ExpressionNode extends Node { public T visit(FieldAccessNode fieldAccess) { return visitor.visit(fieldAccess); } + + @Override + public T visit(TypeCoercionNode typeCoercion) { + return visitor.visit(typeCoercion); + } }); } diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java index 7c4d347..c9eed67 100644 --- a/src/main/java/org/zwobble/couscous/ast/Node.java +++ b/src/main/java/org/zwobble/couscous/ast/Node.java @@ -61,6 +61,12 @@ public interface Node { } @Override + public Void visit(TypeCoercionNode typeCoercion) { + visitor.visit(typeCoercion); + return null; + } + + @Override public Void visit(ReturnNode returnNode) { visitor.visit(returnNode); return null; diff --git a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java index ccb9854..7c3b90b 100644 --- a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java +++ b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java @@ -10,6 +10,7 @@ import org.zwobble.couscous.values.InternalCouscousValue; import org.zwobble.couscous.values.ObjectValues; import static java.util.Arrays.asList; +import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion; import static org.zwobble.couscous.util.ExtraLists.eagerMap; public class StaticMethodCallNode implements ExpressionNode { @@ -18,35 +19,19 @@ public class StaticMethodCallNode implements ExpressionNode { } public static ExpressionNode boxInt(ExpressionNode value) { - return staticMethodCall( - InternalCouscousValue.REF, - "boxInt", - asList(value), - ObjectValues.BOXED_INT); + return typeCoercion(value, ObjectValues.BOXED_INT); } public static ExpressionNode unboxInt(ExpressionNode value) { - return staticMethodCall( - InternalCouscousValue.REF, - "unboxInt", - asList(value), - IntegerValue.REF); + return typeCoercion(value, IntegerValue.REF); } public static ExpressionNode boxBoolean(ExpressionNode value) { - return staticMethodCall( - InternalCouscousValue.REF, - "boxBoolean", - asList(value), - ObjectValues.BOXED_BOOLEAN); + return typeCoercion(value, ObjectValues.BOXED_BOOLEAN); } public static ExpressionNode unboxBoolean(ExpressionNode value) { - return staticMethodCall( - InternalCouscousValue.REF, - "unboxBoolean", - asList(value), - BooleanValue.REF); + return typeCoercion(value, BooleanValue.REF); } public static StaticMethodCallNode staticMethodCall( diff --git a/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java b/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java new file mode 100644 index 0000000..2c7b68e --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java @@ -0,0 +1,87 @@ +package org.zwobble.couscous.ast; + +import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.values.BooleanValue; +import org.zwobble.couscous.values.IntegerValue; + +import java.util.function.Function; + +public class TypeCoercionNode implements ExpressionNode { + public static TypeCoercionNode typeCoercion(ExpressionNode expression, TypeName type) { + return new TypeCoercionNode(expression, type); + } + + private final ExpressionNode expression; + private final TypeName type; + + private TypeCoercionNode(ExpressionNode expression, TypeName type) { + this.expression = expression; + this.type = type; + } + + public ExpressionNode getExpression() { + return expression; + } + + @Override + public TypeName getType() { + return type; + } + + public boolean isIntegerBox() { + return expression.getType().equals(IntegerValue.REF) && + !type.equals(IntegerValue.REF); + } + + public boolean isIntegerUnbox() { + return !expression.getType().equals(IntegerValue.REF) && + type.equals(IntegerValue.REF); + } + + public boolean isBooleanBox() { + return expression.getType().equals(BooleanValue.REF) && + !type.equals(BooleanValue.REF); + } + + public boolean isBooleanUnbox() { + return !expression.getType().equals(BooleanValue.REF) && + type.equals(BooleanValue.REF); + } + + @Override + public <T> T accept(ExpressionNodeMapper<T> visitor) { + return visitor.visit(this); + } + + @Override + public ExpressionNode replaceExpressions(Function<ExpressionNode, ExpressionNode> replace) { + return new TypeCoercionNode(replace.apply(expression), type); + } + + @Override + public String toString() { + return "TypeCoercionNode(" + + "expression=" + expression + + ", type=" + type + + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TypeCoercionNode that = (TypeCoercionNode) o; + + if (!expression.equals(that.expression)) return false; + return type.equals(that.type); + + } + + @Override + public int hashCode() { + int result = expression.hashCode(); + result = 31 * result + type.hashCode(); + return result; + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java index 47ba9b6..8b65f35 100644 --- a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java +++ b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java @@ -80,6 +80,11 @@ public class NodeStructure { } @Override + public Stream<? extends Node> visit(TypeCoercionNode typeCoercion) { + return Stream.of(typeCoercion.getExpression()); + } + + @Override public Stream<Node> visit(ReturnNode returnNode) { return Stream.of(returnNode.getValue()); } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java index c1c3e88..87b8598 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java @@ -1,14 +1,6 @@ package org.zwobble.couscous.ast.visitors; -import org.zwobble.couscous.ast.AssignmentNode; -import org.zwobble.couscous.ast.ConstructorCallNode; -import org.zwobble.couscous.ast.FieldAccessNode; -import org.zwobble.couscous.ast.LiteralNode; -import org.zwobble.couscous.ast.MethodCallNode; -import org.zwobble.couscous.ast.StaticMethodCallNode; -import org.zwobble.couscous.ast.TernaryConditionalNode; -import org.zwobble.couscous.ast.ThisReferenceNode; -import org.zwobble.couscous.ast.VariableReferenceNode; +import org.zwobble.couscous.ast.*; public interface ExpressionNodeMapper<T> { T visit(LiteralNode literal); @@ -20,4 +12,5 @@ public interface ExpressionNodeMapper<T> { T visit(StaticMethodCallNode staticMethodCall); T visit(ConstructorCallNode call); T visit(FieldAccessNode fieldAccess); + T visit(TypeCoercionNode typeCoercion); } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java index d38d7fa..4267c75 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java @@ -12,6 +12,7 @@ public interface NodeMapper<T> { T visit(StaticMethodCallNode staticMethodCall); T visit(ConstructorCallNode call); T visit(FieldAccessNode fieldAccess); + T visit(TypeCoercionNode typeCoercion); T visit(ReturnNode returnNode); T visit(ExpressionStatementNode expressionStatement); diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java index e4203e0..09cfcd3 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java @@ -55,6 +55,11 @@ public class NodeMapperWithDefault<T> implements NodeMapper<T> { } @Override + public T visit(TypeCoercionNode typeCoercion) { + return defaultValue; + } + + @Override public T visit(ReturnNode returnNode) { return defaultValue; } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java index 75e6da5..9f6be92 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java @@ -12,6 +12,7 @@ public interface NodeVisitor { void visit(StaticMethodCallNode staticMethodCall); void visit(ConstructorCallNode call); void visit(FieldAccessNode fieldAccess); + void visit(TypeCoercionNode typeCoercion); void visit(ReturnNode returnNode); void visit(ExpressionStatementNode expressionStatement); diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java index 913b1b7..ada7dea 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java @@ -261,6 +261,22 @@ public class PythonCodeGenerator { public PythonExpressionNode visit(FieldAccessNode fieldAccess) { return pythonAttributeAccess(generateExpression(fieldAccess.getLeft()), fieldAccess.getFieldName()); } + + @Override + public PythonExpressionNode visit(TypeCoercionNode typeCoercion) { + PythonExpressionNode value = generateExpression(typeCoercion.getExpression()); + if (typeCoercion.isIntegerBox()) { + return internalMethod("boxInt", asList(value)); + } else if (typeCoercion.isIntegerUnbox()) { + return internalMethod("unboxInt", asList(value)); + } else { + return value; + } + } + + private PythonExpressionNode internalMethod(String name, List<PythonExpressionNode> arguments) { + return pythonCall(pythonAttributeAccess(pythonVariableReference("_couscous"), name), arguments); + } } private static boolean isPrimitive(ExpressionNode value) { diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionMethodReferenceReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionMethodReferenceReader.java index 6c49d4e..d9a55e3 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionMethodReferenceReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionMethodReferenceReader.java @@ -30,7 +30,7 @@ public class JavaExpressionMethodReferenceReader { return lambda( formalArguments, - ImmutableList.of(returns(JavaExpressionReader.handleBoxing( + ImmutableList.of(returns(JavaExpressionReader.coerceExpression( typeOf(functionalInterfaceMethod.getReturnType()), generateValue(scope, expression, formalArguments))))); } diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java index 367a34f..0e910a1 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java @@ -14,6 +14,7 @@ import static java.util.Arrays.asList; import static org.zwobble.couscous.ast.ConstructorCallNode.constructorCall; import static org.zwobble.couscous.ast.LiteralNode.literal; import static org.zwobble.couscous.ast.MethodCallNode.not; +import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion; import static org.zwobble.couscous.frontends.java.JavaOperators.readOperator; import static org.zwobble.couscous.frontends.java.JavaTypes.typeOf; import static org.zwobble.couscous.util.ExtraLists.concat; @@ -29,20 +30,14 @@ public class JavaExpressionReader { ExpressionNode readExpression(TypeName targetType, Expression expression) { ExpressionNode couscousExpression = readExpressionWithoutBoxing(expression); - return handleBoxing(targetType, couscousExpression); + return coerceExpression(targetType, couscousExpression); } - static ExpressionNode handleBoxing(TypeName targetType, ExpressionNode couscousExpression) { - if (isIntegerBox(targetType, couscousExpression)) { - return StaticMethodCallNode.boxInt(couscousExpression); - } else if (isIntegerUnbox(targetType, couscousExpression)) { - return StaticMethodCallNode.unboxInt(couscousExpression); - } else if (isBooleanBox(targetType, couscousExpression)) { - return StaticMethodCallNode.boxBoolean(couscousExpression); - } else if (isBooleanUnbox(targetType, couscousExpression)) { - return StaticMethodCallNode.unboxBoolean(couscousExpression); - } else { + static ExpressionNode coerceExpression(TypeName targetType, ExpressionNode couscousExpression) { + if (targetType.equals(couscousExpression.getType())) { return couscousExpression; + } else { + return typeCoercion(couscousExpression, targetType); } } @@ -56,26 +51,6 @@ public class JavaExpressionReader { } } - private static boolean isIntegerBox(TypeName targetType, ExpressionNode expression) { - return expression.getType().equals(IntegerValue.REF) && - !targetType.equals(IntegerValue.REF); - } - - private static boolean isIntegerUnbox(TypeName targetType, ExpressionNode expression) { - return !expression.getType().equals(IntegerValue.REF) && - targetType.equals(IntegerValue.REF); - } - - private static boolean isBooleanBox(TypeName targetType, ExpressionNode expression) { - return expression.getType().equals(BooleanValue.REF) && - !targetType.equals(BooleanValue.REF); - } - - private static boolean isBooleanUnbox(TypeName targetType, ExpressionNode expression) { - return !expression.getType().equals(BooleanValue.REF) && - targetType.equals(BooleanValue.REF); - } - ExpressionNode readExpressionWithoutBoxing(Expression expression) { switch (expression.getNodeType()) { case ASTNode.BOOLEAN_LITERAL: @@ -308,7 +283,7 @@ public class JavaExpressionReader { Operator operator = readOperator(expression.getOperator()); return AssignmentNode.assign( left, - handleBoxing( + coerceExpression( left.getType(), readPrimitiveOperation(operator, expression.getLeftHandSide(), expression.getRightHandSide()))); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java index 3e01f36..bee536a 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -1,23 +1,12 @@ package org.zwobble.couscous.interpreter; -import java.util.List; -import java.util.stream.Collectors; -import org.zwobble.couscous.ast.AssignmentNode; -import org.zwobble.couscous.ast.ConstructorCallNode; -import org.zwobble.couscous.ast.ExpressionNode; -import org.zwobble.couscous.ast.FieldAccessNode; -import org.zwobble.couscous.ast.LiteralNode; -import org.zwobble.couscous.ast.MethodCallNode; -import org.zwobble.couscous.ast.StaticMethodCallNode; -import org.zwobble.couscous.ast.TernaryConditionalNode; -import org.zwobble.couscous.ast.ThisReferenceNode; -import org.zwobble.couscous.ast.VariableReferenceNode; +import org.zwobble.couscous.ast.*; import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; -import org.zwobble.couscous.interpreter.values.BooleanInterpreterValue; -import org.zwobble.couscous.interpreter.values.ConcreteType; -import org.zwobble.couscous.interpreter.values.InterpreterValue; -import org.zwobble.couscous.interpreter.values.InterpreterValues; +import org.zwobble.couscous.interpreter.values.*; + +import java.util.List; +import java.util.stream.Collectors; public class Evaluator implements ExpressionNodeMapper<InterpreterValue> { public static InterpreterValue eval(Environment environment, ExpressionNode expression) { @@ -107,7 +96,21 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> { InterpreterValue left = eval(fieldAccess.getLeft()); return left.getField(fieldAccess.getFieldName()); } - + + @Override + public InterpreterValue visit(TypeCoercionNode typeCoercion) { + // TODO: check that the type coercion is valid + // TODO: boxing booleans + InterpreterValue value = eval(typeCoercion.getExpression()); + if (typeCoercion.isIntegerBox()) { + return ((IntegerInterpreterValue)value).box(); + } else if (typeCoercion.isIntegerUnbox()) { + return value.getField("value"); + } else { + return value; + } + } + private List<InterpreterValue> evalArguments(List<? extends ExpressionNode> arguments) { return arguments.stream() .map(argument -> eval(argument)) |
