diff options
Diffstat (limited to 'src/main/java/org')
4 files changed, 87 insertions, 14 deletions
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Environment.java b/src/main/java/org/zwobble/couscous/interpreter/Environment.java index ced87c8..5985a94 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Environment.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Environment.java @@ -2,6 +2,7 @@ package org.zwobble.couscous.interpreter; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.zwobble.couscous.Project; import org.zwobble.couscous.ast.VariableNode; @@ -9,24 +10,25 @@ import org.zwobble.couscous.values.ConcreteType; import org.zwobble.couscous.values.InterpreterValue; public class Environment { - private final Map<Integer, InterpreterValue> stackFrame; + private final Map<Integer, Optional<InterpreterValue>> stackFrame; private final Project project; - public Environment(Project project, Map<Integer, InterpreterValue> stackFrame) { + public Environment(Project project, Map<Integer, Optional<InterpreterValue>> stackFrame) { this.project = project; this.stackFrame = new HashMap<>(stackFrame); } public InterpreterValue get(int referentId) { - return stackFrame.get(referentId); + return stackFrame.get(referentId).get(); } public void put(int variableId, InterpreterValue value) { - stackFrame.put(variableId, value); + checkVariable(variableId); + stackFrame.put(variableId, Optional.of(value)); } public void put(VariableNode variable, InterpreterValue value) { - stackFrame.put(variable.getId(), value); + put(variable.getId(), value); } public ConcreteType<?> findClass(String className) { @@ -34,7 +36,13 @@ public class Environment { return project.findClass(className); } - public Environment withStackFrame(Map<Integer, InterpreterValue> stackFrame) { + public Environment withStackFrame(Map<Integer, Optional<InterpreterValue>> stackFrame) { return new Environment(project, stackFrame); } + + private void checkVariable(int variableId) { + if (!stackFrame.containsKey(variableId)) { + throw new VariableNotInScope(variableId); + } + } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Executor.java b/src/main/java/org/zwobble/couscous/interpreter/Executor.java index 49eca3f..95eddad 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java @@ -1,18 +1,19 @@ package org.zwobble.couscous.interpreter; +import java.util.List; import java.util.Optional; -import java.util.stream.IntStream; +import java.util.stream.Stream; import org.zwobble.couscous.ast.ExpressionStatementNode; import org.zwobble.couscous.ast.LocalVariableDeclarationNode; import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.StatementNode; +import org.zwobble.couscous.ast.VariableNode; import org.zwobble.couscous.ast.visitors.StatementNodeVisitor; import org.zwobble.couscous.values.InterpreterValue; import org.zwobble.couscous.values.UnitValue; -import static java.util.stream.Collectors.toMap; import static org.zwobble.couscous.interpreter.Evaluator.eval; import lombok.val; @@ -35,14 +36,37 @@ public class Executor implements StatementNodeVisitor<Optional<InterpreterValue> 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 environment.withStackFrame(stackFrame); + val stackFrame = new StackFrameBuilder(); + for (int index = 0; index < method.getArguments().size(); index++) { + stackFrame.declare(method.getArguments().get(index), arguments.get(index)); + } + + findDeclarations(method.getBody()).forEach(declaration -> + stackFrame.declare(declaration)); + + return environment.withStackFrame(stackFrame.build()); } + private static Stream<VariableNode> findDeclarations(List<StatementNode> body) { + return body.stream() + .flatMap(statement -> statement.accept(new StatementNodeVisitor<Stream<VariableNode>>() { + @Override + public Stream<VariableNode> visit(ReturnNode returnNode) { + return Stream.empty(); + } + + @Override + public Stream<VariableNode> visit(ExpressionStatementNode expressionStatement) { + return Stream.empty(); + } + + @Override + public Stream<VariableNode> visit(LocalVariableDeclarationNode localVariableDeclaration) { + return Stream.of(localVariableDeclaration); + } + })); + } + public static Optional<InterpreterValue> exec(Environment environment, StatementNode statement) { return statement.accept(new Executor(environment)); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java b/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java new file mode 100644 index 0000000..ac425cd --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java @@ -0,0 +1,29 @@ +package org.zwobble.couscous.interpreter; + +import java.util.Map; + +import org.zwobble.couscous.ast.VariableNode; +import org.zwobble.couscous.values.InterpreterValue; + +import com.google.common.collect.ImmutableMap; + +import java.util.Optional; + +public class StackFrameBuilder { + private final ImmutableMap.Builder<Integer, Optional<InterpreterValue>> variables + = ImmutableMap.builder(); + + public StackFrameBuilder declare(VariableNode variable, InterpreterValue value) { + variables.put(variable.getId(), Optional.of(value)); + return this; + } + + public StackFrameBuilder declare(VariableNode variable) { + variables.put(variable.getId(), Optional.empty()); + return this; + } + + public Map<Integer, Optional<InterpreterValue>> build() { + return variables.build(); + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/VariableNotInScope.java b/src/main/java/org/zwobble/couscous/interpreter/VariableNotInScope.java new file mode 100644 index 0000000..7760326 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/VariableNotInScope.java @@ -0,0 +1,12 @@ +package org.zwobble.couscous.interpreter; + +import lombok.EqualsAndHashCode; +import lombok.Value; + +@Value +@EqualsAndHashCode(callSuper=false) +public class VariableNotInScope extends InterpreterException { + private static final long serialVersionUID = 1L; + + int variableId; +} |
