From cea99d4105bed749739997dc18ed292b5682eafb Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 8 Jan 2016 12:51:55 +0200 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=82=D0=B8=D0=BF=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20Map?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- program.own | 8 ++- src/com/annimon/ownlang/Main.java | 2 +- src/com/annimon/ownlang/lib/ArrayValue.java | 19 ++++++ .../annimon/ownlang/lib/FunctionValue.java | 19 ++++++ src/com/annimon/ownlang/lib/MapValue.java | 60 +++++++++++++++++++ src/com/annimon/ownlang/lib/NumberValue.java | 19 ++++++ src/com/annimon/ownlang/lib/StringValue.java | 19 ++++++ .../ownlang/lib/UserDefinedFunction.java | 5 ++ src/com/annimon/ownlang/parser/Parser.java | 24 +++++++- .../parser/ast/ArrayAccessExpression.java | 15 ++++- .../ownlang/parser/ast/MapExpression.java | 38 ++++++++++++ .../annimon/ownlang/parser/ast/Visitor.java | 1 + .../parser/visitors/AbstractVisitor.java | 8 +++ 13 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 src/com/annimon/ownlang/lib/MapValue.java create mode 100644 src/com/annimon/ownlang/parser/ast/MapExpression.java diff --git a/program.own b/program.own index f6fdf43..25141c6 100644 --- a/program.own +++ b/program.own @@ -81,4 +81,10 @@ for i = 0, i < 4, i = i + 1 { print functions[i] print "\n" print function(functions[i], 6, 3) -} \ No newline at end of file +} + +// map +map = {"+" : add, "-" : sub. "*" : mul, "/" : div} +//print map["+"] +print "\n" +print function(map["+"], 4, 5) \ No newline at end of file diff --git a/src/com/annimon/ownlang/Main.java b/src/com/annimon/ownlang/Main.java index 1d71c55..e964fdb 100644 --- a/src/com/annimon/ownlang/Main.java +++ b/src/com/annimon/ownlang/Main.java @@ -18,7 +18,7 @@ import java.util.List; public final class Main { public static void main(String[] args) throws IOException { - final String file = "examples/game/agar.own"; + final String file = "program.own"; final String input = new String( Files.readAllBytes(Paths.get(file)), "UTF-8"); final List tokens = new Lexer(input).tokenize(); for (int i = 0; i < tokens.size(); i++) { diff --git a/src/com/annimon/ownlang/lib/ArrayValue.java b/src/com/annimon/ownlang/lib/ArrayValue.java index 0ffbc3c..fbee729 100644 --- a/src/com/annimon/ownlang/lib/ArrayValue.java +++ b/src/com/annimon/ownlang/lib/ArrayValue.java @@ -41,6 +41,25 @@ public final class ArrayValue implements Value { return Arrays.toString(elements); } + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + Arrays.deepHashCode(this.elements); + 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 ArrayValue other = (ArrayValue) obj; + return Arrays.deepEquals(this.elements, other.elements); + } + + + @Override public String toString() { return asString(); diff --git a/src/com/annimon/ownlang/lib/FunctionValue.java b/src/com/annimon/ownlang/lib/FunctionValue.java index 6dfb6c3..29c7790 100644 --- a/src/com/annimon/ownlang/lib/FunctionValue.java +++ b/src/com/annimon/ownlang/lib/FunctionValue.java @@ -1,5 +1,7 @@ package com.annimon.ownlang.lib; +import java.util.Objects; + /** * * @author aNNiMON @@ -26,6 +28,23 @@ public final class FunctionValue implements Value { return value; } + @Override + public int hashCode() { + int hash = 7; + hash = 71 * hash + Objects.hashCode(this.value); + 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 FunctionValue other = (FunctionValue) obj; + return Objects.equals(this.value, other.value); + } + @Override public String toString() { return asString(); diff --git a/src/com/annimon/ownlang/lib/MapValue.java b/src/com/annimon/ownlang/lib/MapValue.java new file mode 100644 index 0000000..c636a17 --- /dev/null +++ b/src/com/annimon/ownlang/lib/MapValue.java @@ -0,0 +1,60 @@ +package com.annimon.ownlang.lib; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * + * @author aNNiMON + */ +public final class MapValue implements Value { + + private final Map map; + + public MapValue(int size) { + this.map = new HashMap<>(size); + } + + public Value get(Value key) { + return map.get(key); + } + + public void set(Value key, Value value) { + map.put(key, value); + } + + @Override + public double asNumber() { + throw new RuntimeException("Cannot cast map to number"); + } + + @Override + public String asString() { + return map.toString(); + } + + @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 String toString() { + return asString(); + } +} diff --git a/src/com/annimon/ownlang/lib/NumberValue.java b/src/com/annimon/ownlang/lib/NumberValue.java index 91cf759..0c522db 100644 --- a/src/com/annimon/ownlang/lib/NumberValue.java +++ b/src/com/annimon/ownlang/lib/NumberValue.java @@ -29,6 +29,25 @@ public final class NumberValue implements Value { return Double.toString(value); } + @Override + public int hashCode() { + int hash = 3; + hash = 71 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32)); + 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 NumberValue other = (NumberValue) obj; + return Double.doubleToLongBits(this.value) == Double.doubleToLongBits(other.value); + } + + + @Override public String toString() { return asString(); diff --git a/src/com/annimon/ownlang/lib/StringValue.java b/src/com/annimon/ownlang/lib/StringValue.java index d25f763..7b75ad0 100644 --- a/src/com/annimon/ownlang/lib/StringValue.java +++ b/src/com/annimon/ownlang/lib/StringValue.java @@ -1,5 +1,7 @@ package com.annimon.ownlang.lib; +import java.util.Objects; + /** * * @author aNNiMON @@ -26,6 +28,23 @@ public final class StringValue implements Value { return value; } + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + Objects.hashCode(this.value); + 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 StringValue other = (StringValue) obj; + return Objects.equals(this.value, other.value); + } + @Override public String toString() { return asString(); diff --git a/src/com/annimon/ownlang/lib/UserDefinedFunction.java b/src/com/annimon/ownlang/lib/UserDefinedFunction.java index 8226a09..d8686ee 100644 --- a/src/com/annimon/ownlang/lib/UserDefinedFunction.java +++ b/src/com/annimon/ownlang/lib/UserDefinedFunction.java @@ -36,4 +36,9 @@ public final class UserDefinedFunction implements Function { return rt.getResult(); } } + + @Override + public String toString() { + return String.format("function %s %s", argNames.toString(), body.toString()); + } } diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index e8feaf9..e009617 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -3,7 +3,9 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.lib.UserDefinedFunction; import com.annimon.ownlang.parser.ast.*; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @@ -170,6 +172,19 @@ public final class Parser { return new ArrayExpression(elements); } + private Expression map() { + consume(TokenType.LBRACE); + final Map elements = new HashMap<>(); + while (!match(TokenType.RBRACE)) { + final Expression key = primary(); + consume(TokenType.COLON); + final Expression value = expression(); + elements.put(key, value); + match(TokenType.COMMA); + } + return new MapExpression(elements); + } + private ArrayAccessExpression element() { final String variable = consume(TokenType.WORD).getText(); final List indices = new ArrayList<>(); @@ -393,15 +408,18 @@ public final class Parser { if (match(TokenType.HEX_NUMBER)) { return new ValueExpression(Long.parseLong(current.getText(), 16)); } - if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) { - return function(); - } if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LBRACKET)) { return element(); } + if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) { + return function(); + } if (lookMatch(0, TokenType.LBRACKET)) { return array(); } + if (lookMatch(0, TokenType.LBRACE)) { + return map(); + } if (match(TokenType.WORD)) { return new VariableExpression(current.getText()); } diff --git a/src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java b/src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java index 10bba7f..a4511a8 100644 --- a/src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java +++ b/src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java @@ -1,6 +1,7 @@ package com.annimon.ownlang.parser.ast; import com.annimon.ownlang.lib.ArrayValue; +import com.annimon.ownlang.lib.MapValue; import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Variables; import java.util.List; @@ -21,7 +22,11 @@ public final class ArrayAccessExpression implements Expression { @Override public Value eval() { - return getArray().get(lastIndex()); + Value container = Variables.get(variable); + if (container instanceof ArrayValue) { + return getArray().get(lastIndex()); + } + return consumeMap(container).get(indices.get(0).eval()); } public ArrayValue getArray() { @@ -49,6 +54,14 @@ public final class ArrayAccessExpression implements Expression { } } + private MapValue consumeMap(Value value) { + if (value instanceof MapValue) { + return (MapValue) value; + } else { + throw new RuntimeException("Map expected"); + } + } + @Override public void accept(Visitor visitor) { visitor.visit(this); diff --git a/src/com/annimon/ownlang/parser/ast/MapExpression.java b/src/com/annimon/ownlang/parser/ast/MapExpression.java new file mode 100644 index 0000000..95e7785 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ast/MapExpression.java @@ -0,0 +1,38 @@ +package com.annimon.ownlang.parser.ast; + +import com.annimon.ownlang.lib.MapValue; +import com.annimon.ownlang.lib.Value; +import java.util.Map; + +/** + * + * @author aNNiMON + */ +public final class MapExpression implements Expression { + + public final Map elements; + + public MapExpression(Map arguments) { + this.elements = arguments; + } + + @Override + public Value eval() { + final int size = elements.size(); + final MapValue map = new MapValue(size); + for (Expression key : elements.keySet()) { + map.set(key.eval(), elements.get(key).eval()); + } + return map; + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return elements.toString(); + } +} diff --git a/src/com/annimon/ownlang/parser/ast/Visitor.java b/src/com/annimon/ownlang/parser/ast/Visitor.java index 82aa15f..7f63d02 100644 --- a/src/com/annimon/ownlang/parser/ast/Visitor.java +++ b/src/com/annimon/ownlang/parser/ast/Visitor.java @@ -21,6 +21,7 @@ public interface Visitor { void visit(FunctionStatement s); void visit(FunctionalExpression s); void visit(IfStatement s); + void visit(MapExpression s); void visit(PrintStatement s); void visit(ReturnStatement s); void visit(TernaryExpression s); diff --git a/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java b/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java index 37dd5b4..ca18f19 100644 --- a/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java +++ b/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java @@ -99,6 +99,14 @@ public abstract class AbstractVisitor implements Visitor { s.elseStatement.accept(this); } } + + @Override + public void visit(MapExpression s) { + for (Expression key : s.elements.keySet()) { + key.accept(this); + s.elements.get(key).accept(this); + } + } @Override public void visit(PrintStatement s) {