1
0
mirror of https://github.com/aNNiMON/HotaruFX.git synced 2024-09-19 14:14:21 +03:00

Add evaluation of assignment, value and variable expressions

This commit is contained in:
Victor 2017-08-23 17:47:12 +03:00
parent 037b7aa67e
commit 69cbd5a04f
4 changed files with 105 additions and 4 deletions

View File

@ -0,0 +1,14 @@
package com.annimon.hotarufx.exceptions;
import com.annimon.hotarufx.lexer.SourcePosition;
public class HotaruRuntimeException extends RuntimeException {
public HotaruRuntimeException(String s) {
super(s);
}
public HotaruRuntimeException(String string, SourcePosition start, SourcePosition end) {
super(string + " at " + start + " .. " + end);
}
}

View File

@ -0,0 +1,10 @@
package com.annimon.hotarufx.exceptions;
import com.annimon.hotarufx.lexer.SourcePosition;
public class VariableNotFoundException extends HotaruRuntimeException {
public VariableNotFoundException(String variable, SourcePosition start, SourcePosition end) {
super("Variable " + variable + " does not exists", start, end);
}
}

View File

@ -1,9 +1,11 @@
package com.annimon.hotarufx.parser.visitors;
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
import com.annimon.hotarufx.lib.Context;
import com.annimon.hotarufx.lib.NumberValue;
import com.annimon.hotarufx.lib.Value;
import com.annimon.hotarufx.parser.ast.*;
import lombok.val;
public class InterpreterVisitor implements ResultVisitor<Value, Context> {
@ -14,12 +16,17 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
@Override
public Value visit(AssignNode node, Context context) {
return NumberValue.ZERO;
val value = node.value.accept(this, context);
return node.target.set(this, value, context);
}
@Override
public Value visit(BlockNode node, Context context) {
return NumberValue.ZERO;
Value last = NumberValue.ZERO;
for (Node statement : node.statements) {
last = statement.accept(this, context);
}
return last;
}
@Override
@ -39,11 +46,35 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
@Override
public Value visit(ValueNode node, Context context) {
return NumberValue.ZERO;
return node.value;
}
@Override
public Value visit(VariableNode node, Context context) {
return NumberValue.ZERO;
return node.get(this, context);
}
@Override
public Value get(AccessNode node, Context context) {
return null;
}
@Override
public Value set(AccessNode node, Value value, Context context) {
return null;
}
@Override
public Value get(VariableNode node, Context context) {
val result = context.variables().get(node.name);
if (result == null)
throw new VariableNotFoundException(node.name, node.start(), node.end());
return result;
}
@Override
public Value set(VariableNode node, Value value, Context context) {
context.variables().put(node.name, value);
return value;
}
}

View File

@ -0,0 +1,46 @@
package com.annimon.hotarufx.parser.visitors;
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
import com.annimon.hotarufx.lexer.HotaruLexer;
import com.annimon.hotarufx.lib.Context;
import com.annimon.hotarufx.lib.NumberValue;
import com.annimon.hotarufx.lib.Value;
import com.annimon.hotarufx.parser.HotaruParser;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
class InterpreterVisitorTest {
static Value eval(String input) {
return eval(input, new Context());
}
static Value eval(String input, Context context) {
return HotaruParser.parse(HotaruLexer.tokenize(input))
.accept(new InterpreterVisitor(), context);
}
@Test
void testAssignVariables() {
Context context = new Context();
String input = "A = 1\nB = 2\nC = B";
Value result = eval(input, context);
assertThat(result.toString(), is("2"));
assertThat(context.variables(), allOf(
hasEntry("A", NumberValue.of(1)),
hasEntry("B", NumberValue.of(2)),
hasEntry("C", NumberValue.of(2))
));
}
@Test
void testRuntimeErrors() {
assertThrows(VariableNotFoundException.class, () -> eval("A = B"));
}
}