aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ReferenceNode.java10
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java7
-rw-r--r--src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java7
-rw-r--r--src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java2
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java2
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java28
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java7
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java5
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java82
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java2
11 files changed, 103 insertions, 57 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java
index ab4b1ea..cad359d 100644
--- a/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java
@@ -10,16 +10,16 @@ import static org.zwobble.couscous.util.ExtraLists.eagerMap;
public class ConstructorCallNode implements ExpressionNode {
public static ConstructorCallNode constructorCall(
TypeName type,
- List<ExpressionNode> arguments) {
+ List<? extends ExpressionNode> arguments) {
return new ConstructorCallNode(type, arguments);
}
private final TypeName type;
- private final List<ExpressionNode> arguments;
+ private final List<? extends ExpressionNode> arguments;
public ConstructorCallNode(
TypeName type,
- List<ExpressionNode> arguments) {
+ List<? extends ExpressionNode> arguments) {
this.type = type;
this.arguments = arguments;
}
@@ -29,7 +29,7 @@ public class ConstructorCallNode implements ExpressionNode {
return type;
}
- public List<ExpressionNode> getArguments() {
+ public List<? extends ExpressionNode> getArguments() {
return arguments;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/ReferenceNode.java
new file mode 100644
index 0000000..6e76fcd
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/ReferenceNode.java
@@ -0,0 +1,10 @@
+package org.zwobble.couscous.ast;
+
+public interface ReferenceNode extends ExpressionNode {
+ interface Visitor<T> {
+ T visit(VariableReferenceNode variableReference);
+ T visit(ThisReferenceNode thisReference);
+ }
+
+ <T> T accept(Visitor<T> visitor);
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java
index 3ef5527..a4851c8 100644
--- a/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java
@@ -4,7 +4,7 @@ import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import java.util.function.Function;
-public class ThisReferenceNode implements ExpressionNode {
+public class ThisReferenceNode implements ExpressionNode, ReferenceNode {
public static ThisReferenceNode thisReference(TypeName type) {
return new ThisReferenceNode(type);
}
@@ -30,6 +30,11 @@ public class ThisReferenceNode implements ExpressionNode {
}
@Override
+ public <T> T accept(Visitor<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
public String toString() {
return "ThisReferenceNode(type=" + type + ")";
}
diff --git a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java
index 50462e9..c1b022a 100644
--- a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java
@@ -6,7 +6,7 @@ import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import java.util.function.Function;
-public class VariableReferenceNode implements AssignableExpressionNode {
+public class VariableReferenceNode implements AssignableExpressionNode, ReferenceNode {
public static VariableReferenceNode reference(VariableNode variable) {
return new VariableReferenceNode(variable.getDeclaration());
}
@@ -50,6 +50,11 @@ public class VariableReferenceNode implements AssignableExpressionNode {
}
@Override
+ public <T> T accept(Visitor<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
public String toString() {
return "VariableReferenceNode(referent=" + referent + ")";
}
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 6054711..47ba9b6 100644
--- a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
+++ b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
@@ -70,7 +70,7 @@ public class NodeStructure {
}
@Override
- public Stream<ExpressionNode> visit(ConstructorCallNode call) {
+ public Stream<? extends ExpressionNode> visit(ConstructorCallNode call) {
return call.getArguments().stream();
}
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 574854d..913b1b7 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -194,7 +194,7 @@ public class PythonCodeGenerator {
return expression.accept(EXPRESSION_GENERATOR);
}
- private static List<PythonExpressionNode> generateExpressions(Iterable<ExpressionNode> expressions) {
+ private static List<PythonExpressionNode> generateExpressions(Iterable<? extends ExpressionNode> expressions) {
return ImmutableList.copyOf(Iterables.transform(expressions, PythonCodeGenerator::generateExpression));
}
private static final ExpressionGenerator EXPRESSION_GENERATOR = new ExpressionGenerator();
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
index 99cc9b4..00184b1 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
@@ -1,9 +1,9 @@
package org.zwobble.couscous.frontends.java;
-import com.google.common.collect.Sets;
import org.zwobble.couscous.ast.*;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -12,19 +12,23 @@ import static org.zwobble.couscous.util.Casts.tryCast;
import static org.zwobble.couscous.util.ExtraStreams.toStream;
public class FreeVariables {
- public static List<VariableDeclaration> findFreeVariables(List<? extends Node> body) {
- Stream<VariableDeclaration> referencedDeclarations = body.stream()
- .flatMap(FreeVariables::findReferencedDeclarations);
- Stream<VariableDeclaration> declarations = body.stream().flatMap(FreeVariables::findDeclarations);
- return Sets.difference(
- referencedDeclarations.collect(Collectors.toSet()),
- declarations.collect(Collectors.toSet())).stream().collect(Collectors.toList());
+ public static List<ReferenceNode> findFreeVariables(List<? extends Node> body) {
+ Set<VariableDeclaration> declarations = body.stream()
+ .flatMap(FreeVariables::findDeclarations)
+ .collect(Collectors.toSet());
+
+ return body.stream()
+ .flatMap(FreeVariables::findReferences)
+ .filter(reference ->
+ tryCast(VariableReferenceNode.class, reference)
+ .map(variableReference -> !declarations.contains(variableReference.getReferent()))
+ .orElse(true))
+ .collect(Collectors.toList());
}
- private static Stream<VariableDeclaration> findReferencedDeclarations(Node root) {
- Stream<VariableReferenceNode> references = descendantNodesAndSelf(root).flatMap(node ->
- toStream(tryCast(VariableReferenceNode.class, node)));
- return references.map(VariableReferenceNode::getReferent);
+ private static Stream<ReferenceNode> findReferences(Node root) {
+ return descendantNodesAndSelf(root).flatMap(node ->
+ toStream(tryCast(ReferenceNode.class, node)));
}
private static Stream<VariableDeclaration> findDeclarations(Node root) {
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java b/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java
index 88d214c..9386ff6 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java
@@ -1,6 +1,7 @@
package org.zwobble.couscous.frontends.java;
import org.zwobble.couscous.ast.ClassNode;
+import org.zwobble.couscous.ast.ReferenceNode;
import org.zwobble.couscous.ast.TypeName;
import org.zwobble.couscous.ast.VariableDeclaration;
@@ -8,9 +9,9 @@ import java.util.List;
public class GeneratedClosure {
private final ClassNode classNode;
- private final List<VariableDeclaration> captures;
+ private final List<ReferenceNode> captures;
- public GeneratedClosure(ClassNode classNode, List<VariableDeclaration> captures) {
+ public GeneratedClosure(ClassNode classNode, List<ReferenceNode> captures) {
this.classNode = classNode;
this.captures = captures;
}
@@ -23,7 +24,7 @@ public class GeneratedClosure {
return classNode.getName();
}
- public List<VariableDeclaration> getCaptures() {
+ public List<ReferenceNode> getCaptures() {
return captures;
}
}
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 13bc519..367a34f 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
@@ -17,7 +17,6 @@ import static org.zwobble.couscous.ast.MethodCallNode.not;
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;
-import static org.zwobble.couscous.util.ExtraLists.eagerMap;
public class JavaExpressionReader {
private final Scope scope;
@@ -232,8 +231,8 @@ public class JavaExpressionReader {
captureArguments(closure));
}
- private List<ExpressionNode> captureArguments(GeneratedClosure closure) {
- return eagerMap(closure.getCaptures(), VariableReferenceNode::reference);
+ private List<? extends ExpressionNode> captureArguments(GeneratedClosure closure) {
+ return closure.getCaptures();
}
private List<ExpressionNode> readArguments(IMethodBinding method, List<Expression> javaArguments) {
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 1c53a44..5e81ec9 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
@@ -32,7 +32,6 @@ import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
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.*;
-import static org.zwobble.couscous.util.Casts.tryCast;
import static org.zwobble.couscous.util.ExtraLists.*;
import static org.zwobble.couscous.util.ExtraMaps.toMap;
@@ -109,51 +108,47 @@ public class JavaReader {
private List<StatementNode> replaceCaptureReferences(
TypeName className,
List<StatementNode> body,
- List<VariableDeclaration> freeVariables)
+ List<CapturedVariable> freeVariables)
{
- Map<Identifier, ExpressionNode> freeVariablesById = Maps.transformValues(
- Maps.uniqueIndex(freeVariables, VariableDeclaration::getId),
+ Map<ExpressionNode, ExpressionNode> replacements = Maps.transformValues(
+ Maps.uniqueIndex(freeVariables, variable -> variable.freeVariable),
freeVariable -> captureAccess(className, freeVariable));
- Function<ExpressionNode, ExpressionNode> replaceExpression = new CaptureReplacer(freeVariablesById);
+ Function<ExpressionNode, ExpressionNode> replaceExpression = new CaptureReplacer(replacements);
return eagerMap(body, statement -> statement.replaceExpressions(replaceExpression));
}
private class CaptureReplacer implements Function<ExpressionNode, ExpressionNode> {
- private final Map<Identifier, ExpressionNode> freeVariablesById;
+ private final Map<ExpressionNode, ExpressionNode> replacements;
- public CaptureReplacer(Map<Identifier, ExpressionNode> freeVariablesById) {
- this.freeVariablesById = freeVariablesById;
+ public CaptureReplacer(Map<ExpressionNode, ExpressionNode> replacements) {
+ this.replacements = replacements;
}
@Override
public ExpressionNode apply(ExpressionNode expression) {
- return tryCast(VariableReferenceNode.class, expression)
- .flatMap(variableNode -> Optional.ofNullable(freeVariablesById.get(variableNode.getReferentId())))
+ return Optional.ofNullable(replacements.get(expression))
.orElseGet(() -> expression.replaceExpressions(this));
}
}
- private ConstructorNode buildConstructor(Scope outerScope, TypeName type, List<VariableDeclaration> freeVariables) {
+ private ConstructorNode buildConstructor(Scope outerScope, TypeName type, List<CapturedVariable> freeVariables) {
Scope scope = outerScope.enterConstructor();
- Map<Identifier, VariableDeclaration> argumentDeclarationsById = toMap(
- freeVariables,
- freeVariable -> immutableEntry(
- freeVariable.getId(),
- scope.generateVariable(freeVariable.getName(), freeVariable.getType())));
- List<FormalArgumentNode> arguments = eagerMap(
- freeVariables,
- freeVariable -> formalArg(argumentDeclarationsById.get(freeVariable.getId())));
+ ImmutableList.Builder<FormalArgumentNode> arguments = ImmutableList.builder();
+ ImmutableList.Builder<StatementNode> body = ImmutableList.builder();
- List<StatementNode> body = eagerMap(freeVariables, freeVariable -> assignStatement(
- captureAccess(type, freeVariable),
- reference(argumentDeclarationsById.get(freeVariable.getId()))));
+ for (CapturedVariable variable : freeVariables) {
+ FormalArgumentNode argument = scope.formalArgument(variable.field.getName(), variable.field.getType());
+ arguments.add(argument);
+ body.add(assignStatement(captureAccess(type, variable), reference(argument)));
+ }
- return constructor(arguments, body);
+ return constructor(arguments.build(), body.build());
}
- private FieldAccessNode captureAccess(TypeName type, VariableDeclaration freeVariable) {
- return fieldAccess(thisReference(type), freeVariable.getName(), freeVariable.getType());
+ private FieldAccessNode captureAccess(TypeName type, CapturedVariable freeVariable) {
+ FieldDeclarationNode field = freeVariable.field;
+ return fieldAccess(thisReference(type), field.getName(), field.getType());
}
GeneratedClosure readAnonymousClass(Scope outerScope, AnonymousClassDeclaration declaration) {
@@ -170,6 +165,16 @@ public class JavaReader {
return closure;
}
+ private static class CapturedVariable {
+ private final ReferenceNode freeVariable;
+ private final FieldDeclarationNode field;
+
+ public CapturedVariable(ReferenceNode freeVariable, FieldDeclarationNode field) {
+ this.freeVariable = freeVariable;
+ this.field = field;
+ }
+ }
+
private GeneratedClosure classWithCapture(
Scope scope,
TypeName className,
@@ -177,10 +182,11 @@ public class JavaReader {
List<FieldDeclarationNode> declaredFields,
List<MethodNode> methods
) {
- List<VariableDeclaration> freeVariables = findFreeVariables(ExtraLists.concat(declaredFields, methods));
- Iterable<FieldDeclarationNode> captureFields = transform(
+ List<ReferenceNode> freeVariables = findFreeVariables(ExtraLists.concat(declaredFields, methods));
+ List<CapturedVariable> capturedVariables = ImmutableList.copyOf(transform(
freeVariables,
- freeVariable -> field(freeVariable.getName(), freeVariable.getType()));
+ freeVariable -> new CapturedVariable(freeVariable, fieldForCapture(freeVariable))));
+ Iterable<FieldDeclarationNode> captureFields = transform(capturedVariables, capture -> capture.field);
List<FieldDeclarationNode> fields = ImmutableList.copyOf(concat(declaredFields, captureFields));
@@ -188,12 +194,28 @@ public class JavaReader {
className,
superTypes,
fields,
- buildConstructor(scope, className, freeVariables),
+ buildConstructor(scope, className, capturedVariables),
eagerMap(methods, method ->
- method.mapBody(body -> replaceCaptureReferences(className, body, freeVariables))));
+ method.mapBody(body -> replaceCaptureReferences(className, body, capturedVariables))));
return new GeneratedClosure(classNode, freeVariables);
}
+ private FieldDeclarationNode fieldForCapture(ReferenceNode freeVariable) {
+ return freeVariable.accept(new ReferenceNode.Visitor<FieldDeclarationNode>() {
+ @Override
+ public FieldDeclarationNode visit(VariableReferenceNode reference) {
+ return field(reference.getReferent().getName(), reference.getType());
+ }
+
+ @Override
+ public FieldDeclarationNode visit(ThisReferenceNode thisReference) {
+ TypeName type = thisReference.getType();
+ String name = "this_" + type.getQualifiedName().replace(".", "__");
+ return field(name, type);
+ }
+ });
+ }
+
private TypeName generateAnonymousName(ASTNode node) {
ITypeBinding type = findDeclaringClass(node);
while (type.isAnonymous()) {
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index 548f731..3e01f36 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -108,7 +108,7 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
return left.getField(fieldAccess.getFieldName());
}
- private List<InterpreterValue> evalArguments(List<ExpressionNode> arguments) {
+ private List<InterpreterValue> evalArguments(List<? extends ExpressionNode> arguments) {
return arguments.stream()
.map(argument -> eval(argument))
.collect(Collectors.toList());