From b74d68227dc7c05e24705e3064ef961f95b8b729 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 4 Oct 2015 17:52:29 +0100 Subject: Throw exception if assigning value of wrong type --- .../org/zwobble/couscous/ast/VariableNode.java | 3 ++ .../zwobble/couscous/interpreter/Environment.java | 32 ++++++++++++++++------ .../couscous/interpreter/StackFrameBuilder.java | 8 +++--- .../org/zwobble/couscous/util/CousCousMaps.java | 14 ++++++++++ .../org/zwobble/couscous/values/ConcreteType.java | 2 +- 5 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/zwobble/couscous/util/CousCousMaps.java (limited to 'src/main/java') diff --git a/src/main/java/org/zwobble/couscous/ast/VariableNode.java b/src/main/java/org/zwobble/couscous/ast/VariableNode.java index 4c689c5..acfa29b 100644 --- a/src/main/java/org/zwobble/couscous/ast/VariableNode.java +++ b/src/main/java/org/zwobble/couscous/ast/VariableNode.java @@ -1,5 +1,8 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.values.TypeReference; + public interface VariableNode { int getId(); + TypeReference getType(); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Environment.java b/src/main/java/org/zwobble/couscous/interpreter/Environment.java index a24bf1c..27e337a 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Environment.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Environment.java @@ -1,6 +1,5 @@ package org.zwobble.couscous.interpreter; -import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -8,27 +7,36 @@ import org.zwobble.couscous.Project; import org.zwobble.couscous.ast.VariableNode; import org.zwobble.couscous.values.ConcreteType; import org.zwobble.couscous.values.InterpreterValue; +import org.zwobble.couscous.values.TypeReference; + +import static java.util.stream.Collectors.toMap; +import static org.zwobble.couscous.util.CousCousMaps.mapKeys; import lombok.val; public class Environment { - private final Map> stackFrame; private final Project project; + private final Map> stackFrameValues; + private final Map stackFrameTypes; - public Environment(Project project, Map> stackFrame) { + public Environment(Project project, Map> stackFrame) { this.project = project; - this.stackFrame = new HashMap<>(stackFrame); + this.stackFrameValues = mapKeys(stackFrame, variable -> variable.getId()); + this.stackFrameTypes = stackFrame.keySet() + .stream() + .collect(toMap(variable -> variable.getId(), variable -> variable.getType())); } public InterpreterValue get(int variableId) { checkVariableIsInScope(variableId); - val value = stackFrame.get(variableId); + val value = stackFrameValues.get(variableId); return value.orElseThrow(() -> new UnboundVariable(variableId)); } public void put(int variableId, InterpreterValue value) { checkVariableIsInScope(variableId); - stackFrame.put(variableId, Optional.of(value)); + checkVariableType(variableId, value); + stackFrameValues.put(variableId, Optional.of(value)); } public void put(VariableNode variable, InterpreterValue value) { @@ -40,13 +48,21 @@ public class Environment { return project.findClass(className); } - public Environment withStackFrame(Map> stackFrame) { + public Environment withStackFrame(Map> stackFrame) { return new Environment(project, stackFrame); } private void checkVariableIsInScope(int variableId) { - if (!stackFrame.containsKey(variableId)) { + if (!stackFrameValues.containsKey(variableId)) { throw new VariableNotInScope(variableId); } } + + private void checkVariableType(int variableId, InterpreterValue value) { + val variableType = stackFrameTypes.get(variableId); + val valueType = value.getType().getReference(); + if (!variableType.equals(valueType)) { + throw new UnexpectedValueType(variableType, valueType); + } + } } diff --git a/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java b/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java index ac425cd..658bf42 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java +++ b/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java @@ -10,20 +10,20 @@ import com.google.common.collect.ImmutableMap; import java.util.Optional; public class StackFrameBuilder { - private final ImmutableMap.Builder> variables + private final ImmutableMap.Builder> variables = ImmutableMap.builder(); public StackFrameBuilder declare(VariableNode variable, InterpreterValue value) { - variables.put(variable.getId(), Optional.of(value)); + variables.put(variable, Optional.of(value)); return this; } public StackFrameBuilder declare(VariableNode variable) { - variables.put(variable.getId(), Optional.empty()); + variables.put(variable, Optional.empty()); return this; } - public Map> build() { + public Map> build() { return variables.build(); } } diff --git a/src/main/java/org/zwobble/couscous/util/CousCousMaps.java b/src/main/java/org/zwobble/couscous/util/CousCousMaps.java new file mode 100644 index 0000000..5fb4dca --- /dev/null +++ b/src/main/java/org/zwobble/couscous/util/CousCousMaps.java @@ -0,0 +1,14 @@ +package org.zwobble.couscous.util; + +import java.util.Map; +import java.util.function.Function; + +import static java.util.stream.Collectors.toMap; + +public class CousCousMaps { + public static Map mapKeys(Map map, Function func) { + return map.entrySet() + .stream() + .collect(toMap(entry -> func.apply(entry.getKey()), entry -> entry.getValue())); + } +} diff --git a/src/main/java/org/zwobble/couscous/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/values/ConcreteType.java index 520b504..f3c226c 100644 --- a/src/main/java/org/zwobble/couscous/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/values/ConcreteType.java @@ -129,7 +129,7 @@ public class ConcreteType { return method; } - private TypeReference getReference() { + public TypeReference getReference() { return typeRef(name); } -- cgit v1.2.3