From c02fac3e8b50b1941a8d3f35a033212c1e51d5d4 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Fri, 2 Oct 2015 19:06:57 +0100 Subject: Preserve environment across calls --- .../java/org/zwobble/couscous/JavaProject.java | 10 ++++++ .../org/zwobble/couscous/MapBackedProject.java | 23 +++++++++++++ .../java/org/zwobble/couscous/ast/ClassNode.java | 27 +++++++++++++-- .../zwobble/couscous/interpreter/Environment.java | 4 +++ .../zwobble/couscous/interpreter/Evaluator.java | 2 +- .../org/zwobble/couscous/interpreter/Executor.java | 38 +++++++--------------- .../org/zwobble/couscous/values/ConcreteType.java | 19 ++++++++--- .../org/zwobble/couscous/values/IntegerValue.java | 2 +- .../zwobble/couscous/values/StaticMethodValue.java | 9 ++--- 9 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 src/main/java/org/zwobble/couscous/JavaProject.java create mode 100644 src/main/java/org/zwobble/couscous/MapBackedProject.java (limited to 'src/main') diff --git a/src/main/java/org/zwobble/couscous/JavaProject.java b/src/main/java/org/zwobble/couscous/JavaProject.java new file mode 100644 index 0000000..49e9355 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/JavaProject.java @@ -0,0 +1,10 @@ +package org.zwobble.couscous; + +import org.zwobble.couscous.values.IntegerValue; + +public class JavaProject { + public static MapBackedProject.MapBackedProjectBuilder builder() { + return MapBackedProject.builder() + .addClass("java.lang.Integer", IntegerValue.TYPE); + } +} diff --git a/src/main/java/org/zwobble/couscous/MapBackedProject.java b/src/main/java/org/zwobble/couscous/MapBackedProject.java new file mode 100644 index 0000000..66b3681 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/MapBackedProject.java @@ -0,0 +1,23 @@ +package org.zwobble.couscous; + +import java.util.Map; + +import org.zwobble.couscous.values.ConcreteType; + +import lombok.Builder; +import lombok.Singular; + +@Builder +public class MapBackedProject implements Project { + @Singular(value="addClass") + private Map> classes; + + public MapBackedProject(Map> classes) { + this.classes = classes; + } + + @Override + public ConcreteType findClass(String name) { + return classes.get(name); + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index 6dd7b12..72e57d2 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -2,13 +2,36 @@ package org.zwobble.couscous.ast; import java.util.List; -import lombok.Builder; +import com.google.common.collect.ImmutableList; + import lombok.Singular; import lombok.Value; -@Builder @Value public class ClassNode { + public static ClassNode.Builder builder(String name) { + return new Builder(name); + } + + public static class Builder { + private final String name; + private final ImmutableList.Builder methods; + + public Builder(String name) { + this.name = name; + this.methods = ImmutableList.builder(); + } + + public Builder method(MethodNode method) { + this.methods.add(method); + return this; + } + + public ClassNode build() { + return new ClassNode(name, methods.build()); + } + } + String name; @Singular List methods; diff --git a/src/main/java/org/zwobble/couscous/interpreter/Environment.java b/src/main/java/org/zwobble/couscous/interpreter/Environment.java index 76aa56b..b4decd8 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Environment.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Environment.java @@ -28,4 +28,8 @@ public class Environment { // TODO: handle missing classes return project.findClass(className); } + + public Environment withStackFrame(Map stackFrame) { + return new Environment(project, stackFrame); + } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java index 5acef94..6287348 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -79,6 +79,6 @@ public class Evaluator implements ExpressionNodeVisitor { public InterpreterValue visit(StaticMethodCallNode staticMethodCall) { val clazz = environment.findClass(staticMethodCall.getClassName()); val arguments = evalArguments(staticMethodCall.getArguments()); - return clazz.callStaticMethod(staticMethodCall.getMethodName(), arguments); + return clazz.callStaticMethod(environment, staticMethodCall.getMethodName(), arguments); } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Executor.java b/src/main/java/org/zwobble/couscous/interpreter/Executor.java index cbeeaa4..4002238 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java @@ -1,20 +1,14 @@ package org.zwobble.couscous.interpreter; -import java.util.List; import java.util.Optional; -import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.IntStream; -import org.zwobble.couscous.Project; import org.zwobble.couscous.ast.ExpressionStatementNode; import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.StatementNode; import org.zwobble.couscous.ast.visitors.StatementNodeVisitor; -import org.zwobble.couscous.values.ConcreteType; import org.zwobble.couscous.values.InterpreterValue; -import org.zwobble.couscous.values.StaticMethodValue; import org.zwobble.couscous.values.UnitValue; import static java.util.stream.Collectors.toMap; @@ -23,25 +17,20 @@ import static org.zwobble.couscous.interpreter.Evaluator.eval; import lombok.val; public class Executor implements StatementNodeVisitor> { - public static StaticMethodValue callMethod(MethodNode method) { - Supplier>> argumentTypes = () -> method.getArguments() - .stream() - .>map(arg -> arg.getType()) - .collect(Collectors.toList()); - return new StaticMethodValue(argumentTypes, arguments -> { - val environment = buildEnvironment(method, arguments); - - for (val statement : method.getBody()) { - val result = exec(environment, statement); - if (result.isPresent()) { - return result.get(); - } + public static InterpreterValue callMethod(Environment environment, MethodNode method, Arguments arguments) { + val innerEnvironment = buildEnvironment(environment, method, arguments); + + for (val statement : method.getBody()) { + val result = exec(innerEnvironment, statement); + if (result.isPresent()) { + return result.get(); } - return UnitValue.UNIT; - }); + } + return UnitValue.UNIT; } private static Environment buildEnvironment( + final Environment environment, final MethodNode method, Arguments arguments) { @@ -50,12 +39,7 @@ public class Executor implements StatementNodeVisitor .collect(toMap( index -> method.getArguments().get(index).getId(), index -> arguments.get(index))); - return new Environment(new Project() { - @Override - public ConcreteType findClass(String name) { - throw new UnsupportedOperationException(); - } - }, stackFrame); + return environment.withStackFrame(stackFrame); } public static Optional exec(Environment environment, StatementNode statement) { diff --git a/src/main/java/org/zwobble/couscous/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/values/ConcreteType.java index 7d296db..43016d1 100644 --- a/src/main/java/org/zwobble/couscous/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/values/ConcreteType.java @@ -3,11 +3,12 @@ package org.zwobble.couscous.values; import java.util.List; import java.util.Map; import java.util.function.BiFunction; -import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.interpreter.Environment; import org.zwobble.couscous.interpreter.Executor; import org.zwobble.couscous.interpreter.NoSuchMethod; import org.zwobble.couscous.interpreter.UnexpectedValueType; @@ -42,7 +43,7 @@ public class ConcreteType { public Builder staticMethod( String name, Supplier>> argumentsTypes, - Function method) { + BiFunction method) { staticMethods.put(name, new StaticMethodValue(argumentsTypes, method)); return this; } @@ -58,7 +59,15 @@ public class ConcreteType { .filter(method -> method.isStatic()) .collect(toMap( method -> method.getName(), - Executor::callMethod)); + method -> { + Supplier>> argumentTypes = () -> method.getArguments() + .stream() + .>map(arg -> arg.getType()) + .collect(Collectors.toList()); + return new StaticMethodValue(argumentTypes, (environment, arguments) -> { + return Executor.callMethod(environment, method, arguments); + }); + })); return new ConcreteType( classNode.getName(), ImmutableMap.of(), @@ -88,9 +97,9 @@ public class ConcreteType { return method.apply((T)receiver, new Arguments(arguments)); } - public InterpreterValue callStaticMethod(String methodName, List arguments) { + public InterpreterValue callStaticMethod(Environment environment, String methodName, List arguments) { val method = findMethod(staticMethods, methodName, arguments); - return method.apply(new Arguments(arguments)); + return method.apply(environment, new Arguments(arguments)); } private static T findMethod(Map methods, String methodName, List arguments) { diff --git a/src/main/java/org/zwobble/couscous/values/IntegerValue.java b/src/main/java/org/zwobble/couscous/values/IntegerValue.java index 1b20a01..76d0c59 100644 --- a/src/main/java/org/zwobble/couscous/values/IntegerValue.java +++ b/src/main/java/org/zwobble/couscous/values/IntegerValue.java @@ -9,7 +9,7 @@ import lombok.val; public class IntegerValue implements InterpreterValue { public static final ConcreteType TYPE = ConcreteType.builder("Integer") .staticMethod("parseInt", () -> asList(StringValue.TYPE), - arguments -> { + (environment, arguments) -> { val value = (StringValue)arguments.get(0); return new IntegerValue(Integer.parseInt(value.getValue())); }) diff --git a/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java b/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java index 15a70d3..80ace03 100644 --- a/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java +++ b/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java @@ -1,10 +1,11 @@ package org.zwobble.couscous.values; import java.util.List; -import java.util.function.Function; +import java.util.function.BiFunction; import java.util.function.Supplier; import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.interpreter.Environment; import lombok.AccessLevel; import lombok.Getter; @@ -15,15 +16,15 @@ public class StaticMethodValue implements Callable { @Getter(value=AccessLevel.NONE) Supplier>> argumentTypes; @Getter(value=AccessLevel.NONE) - Function apply; + BiFunction apply; @Override public List> getArgumentTypes() { return argumentTypes.get(); } - public InterpreterValue apply(Arguments arguments) { - return apply.apply(arguments); + public InterpreterValue apply(Environment environment, Arguments arguments) { + return apply.apply(environment, arguments); } } -- cgit v1.2.3