mirror of
https://github.com/aNNiMON/HotaruFX.git
synced 2024-09-19 14:14:21 +03:00
Add map support
This commit is contained in:
parent
d13c8ee849
commit
2a8d336fff
@ -0,0 +1,8 @@
|
|||||||
|
package com.annimon.hotarufx.exceptions;
|
||||||
|
|
||||||
|
public class TypeException extends HotaruRuntimeException {
|
||||||
|
|
||||||
|
public TypeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
98
app/src/main/java/com/annimon/hotarufx/lib/MapValue.java
Normal file
98
app/src/main/java/com/annimon/hotarufx/lib/MapValue.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package com.annimon.hotarufx.lib;
|
||||||
|
|
||||||
|
import com.annimon.hotarufx.exceptions.TypeException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class MapValue implements Value, Iterable<Map.Entry<String, Value>> {
|
||||||
|
|
||||||
|
public static final MapValue EMPTY = new MapValue(1);
|
||||||
|
|
||||||
|
public static MapValue merge(MapValue map1, MapValue map2) {
|
||||||
|
final MapValue result = new MapValue(map1.size() + map2.size());
|
||||||
|
result.map.putAll(map1.map);
|
||||||
|
result.map.putAll(map2.map);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Value> map;
|
||||||
|
|
||||||
|
public MapValue(int size) {
|
||||||
|
this.map = new HashMap<>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapValue(Map<String, Value> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int type() {
|
||||||
|
return Types.MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Value> getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object raw() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int asInt() {
|
||||||
|
throw new TypeException("Cannot cast map to integer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double asNumber() {
|
||||||
|
throw new TypeException("Cannot cast map to number");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String asString() {
|
||||||
|
return map.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Map.Entry<String, Value>> iterator() {
|
||||||
|
return map.entrySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 5;
|
||||||
|
hash = 37 * hash + Objects.hashCode(this.map);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null) return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
final MapValue other = (MapValue) obj;
|
||||||
|
return Objects.equals(this.map, other.map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Value o) {
|
||||||
|
if (o.type() == Types.MAP) {
|
||||||
|
final int lengthCompare = Integer.compare(size(), ((MapValue) o).size());
|
||||||
|
if (lengthCompare != 0) return lengthCompare;
|
||||||
|
}
|
||||||
|
return asString().compareTo(o.asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return asString();
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,14 @@ package com.annimon.hotarufx.parser.visitors;
|
|||||||
|
|
||||||
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
|
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
|
||||||
import com.annimon.hotarufx.lib.Context;
|
import com.annimon.hotarufx.lib.Context;
|
||||||
|
import com.annimon.hotarufx.lib.MapValue;
|
||||||
import com.annimon.hotarufx.lib.NumberValue;
|
import com.annimon.hotarufx.lib.NumberValue;
|
||||||
import com.annimon.hotarufx.lib.StringValue;
|
import com.annimon.hotarufx.lib.StringValue;
|
||||||
import com.annimon.hotarufx.lib.Types;
|
import com.annimon.hotarufx.lib.Types;
|
||||||
import com.annimon.hotarufx.lib.Value;
|
import com.annimon.hotarufx.lib.Value;
|
||||||
import com.annimon.hotarufx.parser.ast.*;
|
import com.annimon.hotarufx.parser.ast.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||||
@ -38,7 +41,11 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value visit(MapNode node, Context context) {
|
public Value visit(MapNode node, Context context) {
|
||||||
return NumberValue.ZERO;
|
Map<String, Value> map = new HashMap<>(node.elements.size());
|
||||||
|
for (Map.Entry<String, Node> entry : node.elements.entrySet()) {
|
||||||
|
map.put(entry.getKey(), entry.getValue().accept(this, context));
|
||||||
|
}
|
||||||
|
return new MapValue(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,13 +3,17 @@ package com.annimon.hotarufx.parser.visitors;
|
|||||||
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
|
import com.annimon.hotarufx.exceptions.VariableNotFoundException;
|
||||||
import com.annimon.hotarufx.lexer.HotaruLexer;
|
import com.annimon.hotarufx.lexer.HotaruLexer;
|
||||||
import com.annimon.hotarufx.lib.Context;
|
import com.annimon.hotarufx.lib.Context;
|
||||||
|
import com.annimon.hotarufx.lib.MapValue;
|
||||||
import com.annimon.hotarufx.lib.NumberValue;
|
import com.annimon.hotarufx.lib.NumberValue;
|
||||||
|
import com.annimon.hotarufx.lib.StringValue;
|
||||||
import com.annimon.hotarufx.lib.Value;
|
import com.annimon.hotarufx.lib.Value;
|
||||||
import com.annimon.hotarufx.parser.HotaruParser;
|
import com.annimon.hotarufx.parser.HotaruParser;
|
||||||
|
import java.util.Map;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.allOf;
|
import static org.hamcrest.Matchers.allOf;
|
||||||
import static org.hamcrest.Matchers.hasEntry;
|
import static org.hamcrest.Matchers.hasEntry;
|
||||||
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
@ -44,6 +48,19 @@ class InterpreterVisitorTest {
|
|||||||
assertThat(eval("A = -1").asInt(), is(-1));
|
assertThat(eval("A = -1").asInt(), is(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMap() {
|
||||||
|
Value value = eval("A = {x: 0, y: 1, text: 'hello'}");
|
||||||
|
assertThat(value, instanceOf(MapValue.class));
|
||||||
|
|
||||||
|
Map<String, Value> map = ((MapValue) value).getMap();
|
||||||
|
assertThat(map, allOf(
|
||||||
|
hasEntry("x", NumberValue.of(0)),
|
||||||
|
hasEntry("y", NumberValue.of(1))
|
||||||
|
));
|
||||||
|
assertThat(map, hasEntry("text", new StringValue("hello")));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRuntimeErrors() {
|
void testRuntimeErrors() {
|
||||||
assertThrows(VariableNotFoundException.class, () -> eval("A = B"));
|
assertThrows(VariableNotFoundException.class, () -> eval("A = B"));
|
||||||
|
Loading…
Reference in New Issue
Block a user