diff options
Diffstat (limited to 'src/main/java')
9 files changed, 133 insertions, 68 deletions
diff --git a/src/main/java/org/zwobble/couscous/Project.java b/src/main/java/org/zwobble/couscous/Project.java index 6afac6e..56b439f 100644 --- a/src/main/java/org/zwobble/couscous/Project.java +++ b/src/main/java/org/zwobble/couscous/Project.java @@ -1,7 +1,7 @@ package org.zwobble.couscous; -import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.values.ConcreteType; public interface Project { - ClassNode findClass(String name); + ConcreteType<?> findClass(String name); } diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index ffa5165..6dd7b12 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -9,6 +9,7 @@ import lombok.Value; @Builder @Value public class ClassNode { + String name; @Singular List<MethodNode> methods; } diff --git a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java index da3a838..72a5f51 100644 --- a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java @@ -1,9 +1,21 @@ package org.zwobble.couscous.ast; +import java.util.function.Supplier; + +import org.zwobble.couscous.values.ConcreteType; + +import lombok.AccessLevel; +import lombok.Getter; import lombok.Value; @Value public class FormalArgumentNode implements VariableNode { int id; + @Getter(value=AccessLevel.NONE) + Supplier<ConcreteType<?>> type; String name; + + public ConcreteType<?> getType() { + return type.get(); + } } diff --git a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java index cc57aef..0869653 100644 --- a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java +++ b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java @@ -10,6 +10,10 @@ import lombok.Value; @Value public class LiteralNode implements ExpressionNode { + public static LiteralNode literal(InterpreterValue value) { + return new LiteralNode(value); + } + public static LiteralNode literal(String value) { return new LiteralNode(new StringValue(value)); } diff --git a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java index 390c37f..4f1e9ff 100644 --- a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java +++ b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java @@ -14,6 +14,10 @@ public class StaticMethodCallNode implements ExpressionNode { return new StaticMethodCallNode(className, methodName, asList(arguments)); } + public static StaticMethodCallNode staticMethodCall(String className, String methodName, List<ExpressionNode> arguments) { + return new StaticMethodCallNode(className, methodName, arguments); + } + String className; String methodName; List<ExpressionNode> arguments; diff --git a/src/main/java/org/zwobble/couscous/interpreter/Environment.java b/src/main/java/org/zwobble/couscous/interpreter/Environment.java index ea4a5e4..76aa56b 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Environment.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Environment.java @@ -3,14 +3,16 @@ package org.zwobble.couscous.interpreter; import java.util.HashMap; import java.util.Map; +import org.zwobble.couscous.Project; import org.zwobble.couscous.values.ConcreteType; -import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.InterpreterValue; public class Environment { - private Map<Integer, InterpreterValue> stackFrame; + private final Map<Integer, InterpreterValue> stackFrame; + private final Project project; - public Environment(Map<Integer, InterpreterValue> stackFrame) { + public Environment(Project project, Map<Integer, InterpreterValue> stackFrame) { + this.project = project; this.stackFrame = new HashMap<>(stackFrame); } @@ -23,10 +25,7 @@ public class Environment { } public ConcreteType<?> findClass(String className) { - if (className == "java.lang.Integer") { - return IntegerValue.TYPE; - } else { - throw new UnsupportedOperationException(); - } + // TODO: handle missing classes + return project.findClass(className); } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Executor.java b/src/main/java/org/zwobble/couscous/interpreter/Executor.java new file mode 100644 index 0000000..633bf6b --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java @@ -0,0 +1,34 @@ +package org.zwobble.couscous.interpreter; + +import java.util.Optional; + +import org.zwobble.couscous.ast.ExpressionStatementNode; +import org.zwobble.couscous.ast.ReturnNode; +import org.zwobble.couscous.ast.StatementNode; +import org.zwobble.couscous.ast.visitors.StatementNodeVisitor; +import org.zwobble.couscous.values.InterpreterValue; + +import static org.zwobble.couscous.interpreter.Evaluator.eval; + +public class Executor implements StatementNodeVisitor<Optional<InterpreterValue>> { + public static Optional<InterpreterValue> exec(Environment environment, StatementNode statement) { + return statement.accept(new Executor(environment)); + } + + private final Environment environment; + + private Executor(Environment environment) { + this.environment = environment; + } + + @Override + public Optional<InterpreterValue> visit(ReturnNode returnNode) { + return Optional.of(eval(environment, returnNode.getValue())); + } + + @Override + public Optional<InterpreterValue> visit(ExpressionStatementNode expressionStatement) { + eval(environment, expressionStatement.getExpression()); + return Optional.empty(); + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java index bc82fee..884a082 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java @@ -1,20 +1,17 @@ package org.zwobble.couscous.interpreter; import java.util.List; -import java.util.Optional; -import java.util.stream.IntStream; +import java.util.stream.Collectors; 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.visitors.StatementNodeVisitor; +import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.values.InterpreterValue; -import static com.google.common.collect.Iterables.find; -import static java.util.stream.Collectors.toMap; +import com.google.common.collect.ImmutableMap; + +import static org.zwobble.couscous.ast.StaticMethodCallNode.staticMethodCall; import static org.zwobble.couscous.interpreter.Evaluator.eval; -import static org.zwobble.couscous.values.UnitValue.UNIT; import lombok.val; @@ -26,52 +23,11 @@ public class Interpreter { } public InterpreterValue run(String className, String methodName, List<InterpreterValue> arguments) { - val clazz = project.findClass(className); - val method = find(clazz.getMethods(), - method -> method.getName().equals(methodName)); - val environment = buildEnvironment(method, arguments); - - for (val statement : method.getBody()) { - val result = statement.accept(new Executor(environment)); - if (result.isPresent()) { - return result.get(); - } - } - return UNIT; - } - - private Environment buildEnvironment( - final MethodNode method, - List<InterpreterValue> arguments) { - - if (method.getArguments().size() != arguments.size()) { - throw new WrongNumberOfArguments(method.getArguments().size(), arguments.size()); - } - - val stackFrame = IntStream.range(0, method.getArguments().size()) - .boxed() - .collect(toMap( - index -> method.getArguments().get(index).getId(), - index -> arguments.get(index))); - return new Environment(stackFrame); - } - - private class Executor implements StatementNodeVisitor<Optional<InterpreterValue>> { - private Environment environment; - - public Executor(Environment environment) { - this.environment = environment; - } - - @Override - public Optional<InterpreterValue> visit(ReturnNode returnNode) { - return Optional.of(eval(environment, returnNode.getValue())); - } - - @Override - public Optional<InterpreterValue> visit(ExpressionStatementNode expressionStatement) { - eval(environment, expressionStatement.getExpression()); - return Optional.empty(); - } + val argumentExpressions = arguments + .stream() + .<ExpressionNode>map(LiteralNode::literal) + .collect(Collectors.toList()); + return eval(new Environment(project, ImmutableMap.of()), + staticMethodCall(className, methodName, argumentExpressions)); } } diff --git a/src/main/java/org/zwobble/couscous/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/values/ConcreteType.java index db5209e..6aea1db 100644 --- a/src/main/java/org/zwobble/couscous/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/values/ConcreteType.java @@ -5,14 +5,23 @@ 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 java.util.stream.IntStream; +import org.zwobble.couscous.Project; +import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.interpreter.Environment; import org.zwobble.couscous.interpreter.NoSuchMethod; import org.zwobble.couscous.interpreter.UnexpectedValueType; import org.zwobble.couscous.interpreter.WrongNumberOfArguments; import com.google.common.collect.ImmutableMap; +import static java.util.stream.Collectors.toMap; +import static org.zwobble.couscous.interpreter.Executor.exec; + import lombok.val; public class ConcreteType<T> { @@ -47,15 +56,61 @@ public class ConcreteType<T> { return new ConcreteType<T>(name, methods.build(), staticMethods.build()); } } + + public static ConcreteType<?> fromNode(ClassNode classNode) { + val staticMethods = classNode.getMethods() + .stream() + .filter(method -> method.isStatic()) + .collect(toMap( + method -> method.getName(), + method -> { + Supplier<List<ConcreteType<?>>> argumentTypes = () -> method.getArguments() + .stream() + .<ConcreteType<?>>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(); + } + } + return UnitValue.UNIT; + }); + })); + return new ConcreteType<Void>( + classNode.getName(), + ImmutableMap.of(), + staticMethods); + } + + private static Environment buildEnvironment( + final MethodNode method, + Arguments arguments) { + + val stackFrame = IntStream.range(0, method.getArguments().size()) + .boxed() + .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); + } private String name; private Map<String, MethodValue<T>> methods; - private ImmutableMap<String, StaticMethodValue> staticMethods; + private Map<String, StaticMethodValue> staticMethods; public ConcreteType( String name, Map<String, MethodValue<T>> methods, - ImmutableMap<String, StaticMethodValue> staticMethods) { + Map<String, StaticMethodValue> staticMethods) { this.name = name; this.methods = methods; this.staticMethods = staticMethods; |
