aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/couscous
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-01-04 23:28:22 +0000
committerMichael Williamson <mike@zwobble.org>2016-01-04 23:28:22 +0000
commit75b69c7f4e7ed84f82c549e36a3928a48720cc26 (patch)
treed400967b67b7e6ec7c922a586ae14c6cda35f6ed /src/main/java/org/zwobble/couscous
parentbb0b36b86f841ec6340fe6e727ed2ea9db1c2d64 (diff)
Move type coercion decisions into the backends
Diffstat (limited to 'src/main/java/org/zwobble/couscous')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionNode.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Node.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java25
-rw-r--r--src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java87
-rw-r--r--src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java11
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java1
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java16
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionMethodReferenceReader.java2
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java39
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java37
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))