From 32d40d9d0497ba923c2f0b0aff36f4758046e9cf Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 13 Feb 2016 12:01:11 +0200 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=20=D0=BA=20=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D1=8B=D0=BC=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D0=B5=D0=B9=D0=BD=D0=B5=D1=80=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- program.own | 10 ++- src/com/annimon/ownlang/parser/Parser.java | 69 +++++++++---------- .../parser/ast/ArrayAssignmentStatement.java | 41 ----------- ...on.java => ContainerAccessExpression.java} | 56 ++++++++------- .../ast/ContainerAssignmentStatement.java | 51 ++++++++++++++ .../annimon/ownlang/parser/ast/Visitor.java | 4 +- .../parser/visitors/AbstractVisitor.java | 26 +++---- .../parser/visitors/VariablePrinter.java | 4 +- 8 files changed, 143 insertions(+), 118 deletions(-) delete mode 100644 src/com/annimon/ownlang/parser/ast/ArrayAssignmentStatement.java rename src/com/annimon/ownlang/parser/ast/{ArrayAccessExpression.java => ContainerAccessExpression.java} (51%) create mode 100644 src/com/annimon/ownlang/parser/ast/ContainerAssignmentStatement.java diff --git a/program.own b/program.own index 94c8796..2244573 100644 --- a/program.own +++ b/program.own @@ -196,4 +196,12 @@ extract(var2, var1) = [var1, var2] echo(var1, var2) extract(, , var4) = arr -println var4 \ No newline at end of file +println var4 + +array1 = [[1, 2], [3], [4, 5], [6]] +println array1[0][1] +object1 = {"arr": array1} +println object1.arr +println object1.arr[0][1] +object1.arr[0][1] = "str" +println object1.arr[0][1] diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index 0f7849a..367ddf1 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -102,10 +102,12 @@ public final class Parser { consume(TokenType.EQ); return new AssignmentStatement(variable, expression()); } - if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LBRACKET)) { - final ArrayAccessExpression array = element(); + + final Expression qualifiedNameExpr = qualifiedName(); + if (lookMatch(0, TokenType.EQ) && (qualifiedNameExpr instanceof ContainerAccessExpression)) { consume(TokenType.EQ); - return new ArrayAssignmentStatement(array, expression()); + final ContainerAccessExpression containerExpr = (ContainerAccessExpression) qualifiedNameExpr; + return new ContainerAssignmentStatement(containerExpr, expression()); } throw new ParseException("Unknown statement: " + get(0)); } @@ -249,31 +251,6 @@ public final class Parser { return new MapExpression(elements); } - private ArrayAccessExpression element() { - // array[e1][e2]...[eN] - final String variable = consume(TokenType.WORD).getText(); - final List indices = new ArrayList<>(); - do { - consume(TokenType.LBRACKET); - indices.add(expression()); - consume(TokenType.RBRACKET); - } while(lookMatch(0, TokenType.LBRACKET)); - return new ArrayAccessExpression(variable, indices); - } - - private ArrayAccessExpression object() { - // object.field1.field2 - // Syntaxic sugar for object["field1"]["field2"] - final String variable = consume(TokenType.WORD).getText(); - final List indices = new ArrayList<>(); - while (match(TokenType.DOT)) { - final String fieldName = consume(TokenType.WORD).getText(); - final Expression key = new ValueExpression(fieldName); - indices.add(key); - } - return new ArrayAccessExpression(variable, indices); - } - private MatchExpression match() { // match expression { // case pattern1: result1 @@ -563,9 +540,11 @@ public final class Parser { } private Expression variable() { + // function(... if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) { return function(new ValueExpression(consume(TokenType.WORD).getText())); } + final Expression qualifiedNameExpr = qualifiedName(); if (qualifiedNameExpr != null) { // variable(args) || arr["key"](args) || obj.key(args) @@ -585,17 +564,35 @@ public final class Parser { } private Expression qualifiedName() { + // var || var.key[index].key2 final Token current = get(0); - if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LBRACKET)) { - return element(); - } - if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.DOT)) { - return object(); - } - if (match(TokenType.WORD)) { + if (!match(TokenType.WORD)) return null; + + final List indices = variableSuffix(); + if ((indices == null) || indices.isEmpty()) { return new VariableExpression(current.getText()); } - return null; + return new ContainerAccessExpression(current.getText(), indices); + } + + private List variableSuffix() { + // .key1.arr1[expr1][expr2].key2 + if (!lookMatch(0, TokenType.DOT) && !lookMatch(0, TokenType.LBRACKET)) { + return null; + } + final List indices = new ArrayList<>(); + while (lookMatch(0, TokenType.DOT) || lookMatch(0, TokenType.LBRACKET)) { + if (match(TokenType.DOT)) { + final String fieldName = consume(TokenType.WORD).getText(); + final Expression key = new ValueExpression(fieldName); + indices.add(key); + } + if (match(TokenType.LBRACKET)) { + indices.add(expression()); + consume(TokenType.RBRACKET); + } + } + return indices; } private Expression value() { diff --git a/src/com/annimon/ownlang/parser/ast/ArrayAssignmentStatement.java b/src/com/annimon/ownlang/parser/ast/ArrayAssignmentStatement.java deleted file mode 100644 index d39b7f6..0000000 --- a/src/com/annimon/ownlang/parser/ast/ArrayAssignmentStatement.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.annimon.ownlang.parser.ast; - -import com.annimon.ownlang.lib.Types; -import com.annimon.ownlang.lib.Value; -import com.annimon.ownlang.lib.Variables; - -/** - * - * @author aNNiMON - */ -public final class ArrayAssignmentStatement implements Statement { - - public final ArrayAccessExpression array; - public final Expression expression; - - public ArrayAssignmentStatement(ArrayAccessExpression array, Expression expression) { - this.array = array; - this.expression = expression; - } - - @Override - public void execute() { - final Value container = Variables.get(array.variable); - if (container.type() == Types.ARRAY) { - final int lastIndex = (int) array.lastIndex().asNumber(); - array.getArray().set(lastIndex, expression.eval()); - return; - } - array.getMap().set(array.lastIndex(), expression.eval()); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } - - @Override - public String toString() { - return String.format("%s = %s", array, expression); - } -} diff --git a/src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java b/src/com/annimon/ownlang/parser/ast/ContainerAccessExpression.java similarity index 51% rename from src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java rename to src/com/annimon/ownlang/parser/ast/ContainerAccessExpression.java index 2474c5e..9d04dc6 100644 --- a/src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java +++ b/src/com/annimon/ownlang/parser/ast/ContainerAccessExpression.java @@ -8,43 +8,53 @@ import java.util.List; * * @author aNNiMON */ -public final class ArrayAccessExpression implements Expression { +public final class ContainerAccessExpression implements Expression { public final String variable; public final List indices; - public ArrayAccessExpression(String variable, List indices) { + public ContainerAccessExpression(String variable, List indices) { this.variable = variable; this.indices = indices; } @Override public Value eval() { + final Value container = getContainer(); + final Value lastIndex = lastIndex(); + switch (container.type()) { + case Types.ARRAY: + final int arrayIndex = (int) lastIndex.asNumber(); + return ((ArrayValue) container).get(arrayIndex); + + case Types.MAP: + return ((MapValue) container).get(lastIndex); + + default: + throw new TypeException("Array or map expected"); + } + } + + public Value getContainer() { Value container = Variables.get(variable); - if (container.type() == Types.ARRAY) { - final int lastIndex = (int) lastIndex().asNumber(); - return getArray().get(lastIndex); - } - return getMap().get(lastIndex()); - } - - public ArrayValue getArray() { - ArrayValue array = consumeArray(Variables.get(variable)); final int last = indices.size() - 1; for (int i = 0; i < last; i++) { - final int index = (int) index(i).asNumber(); - array = consumeArray( array.get(index) ); + final Value index = index(i); + switch (container.type()) { + case Types.ARRAY: + final int arrayIndex = (int) index.asNumber(); + container = ((ArrayValue) container).get(arrayIndex); + break; + + case Types.MAP: + container = ((MapValue) container).get(index); + break; + + default: + throw new TypeException("Array or map expected"); + } } - return array; - } - - public MapValue getMap() { - MapValue map = consumeMap(Variables.get(variable)); - final int last = indices.size() - 1; - for (int i = 0; i < last; i++) { - map = consumeMap( map.get(index(i)) ); - } - return map; + return container; } public Value lastIndex() { diff --git a/src/com/annimon/ownlang/parser/ast/ContainerAssignmentStatement.java b/src/com/annimon/ownlang/parser/ast/ContainerAssignmentStatement.java new file mode 100644 index 0000000..8fd8d13 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ast/ContainerAssignmentStatement.java @@ -0,0 +1,51 @@ +package com.annimon.ownlang.parser.ast; + +import com.annimon.ownlang.exceptions.TypeException; +import com.annimon.ownlang.lib.ArrayValue; +import com.annimon.ownlang.lib.MapValue; +import com.annimon.ownlang.lib.Types; +import com.annimon.ownlang.lib.Value; + +/** + * + * @author aNNiMON + */ +public final class ContainerAssignmentStatement implements Statement { + + public final ContainerAccessExpression containerExpr; + public final Expression expression; + + public ContainerAssignmentStatement(ContainerAccessExpression array, Expression expression) { + this.containerExpr = array; + this.expression = expression; + } + + @Override + public void execute() { + final Value container = containerExpr.getContainer(); + final Value lastIndex = containerExpr.lastIndex(); + switch (container.type()) { + case Types.ARRAY: + final int arrayIndex = (int) lastIndex.asNumber(); + ((ArrayValue) container).set(arrayIndex, expression.eval()); + return; + + case Types.MAP: + ((MapValue) container).set(lastIndex, expression.eval()); + return; + + default: + throw new TypeException("Array or map expected. Got " + container.type()); + } + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + return String.format("%s = %s", containerExpr, expression); + } +} diff --git a/src/com/annimon/ownlang/parser/ast/Visitor.java b/src/com/annimon/ownlang/parser/ast/Visitor.java index afb5899..16ae8d4 100644 --- a/src/com/annimon/ownlang/parser/ast/Visitor.java +++ b/src/com/annimon/ownlang/parser/ast/Visitor.java @@ -6,14 +6,14 @@ package com.annimon.ownlang.parser.ast; */ public interface Visitor { - void visit(ArrayAccessExpression s); - void visit(ArrayAssignmentStatement s); void visit(ArrayExpression s); void visit(AssignmentStatement s); void visit(BinaryExpression s); void visit(BlockStatement s); void visit(BreakStatement s); void visit(ConditionalExpression s); + void visit(ContainerAccessExpression s); + void visit(ContainerAssignmentStatement s); void visit(ContinueStatement s); void visit(DoWhileStatement s); void visit(DestructuringAssignmentStatement s); diff --git a/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java b/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java index 23e3c3d..0bf56a7 100644 --- a/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java +++ b/src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java @@ -10,19 +10,6 @@ import java.util.Map; */ public abstract class AbstractVisitor implements Visitor { - @Override - public void visit(ArrayAccessExpression s) { - for (Expression index : s.indices) { - index.accept(this); - } - } - - @Override - public void visit(ArrayAssignmentStatement s) { - s.array.accept(this); - s.expression.accept(this); - } - @Override public void visit(ArrayExpression s) { for (Expression index : s.elements) { @@ -57,6 +44,19 @@ public abstract class AbstractVisitor implements Visitor { s.expr1.accept(this); s.expr2.accept(this); } + + @Override + public void visit(ContainerAccessExpression s) { + for (Expression index : s.indices) { + index.accept(this); + } + } + + @Override + public void visit(ContainerAssignmentStatement s) { + s.containerExpr.accept(this); + s.expression.accept(this); + } @Override public void visit(ContinueStatement s) { diff --git a/src/com/annimon/ownlang/parser/visitors/VariablePrinter.java b/src/com/annimon/ownlang/parser/visitors/VariablePrinter.java index e3009e4..821b129 100644 --- a/src/com/annimon/ownlang/parser/visitors/VariablePrinter.java +++ b/src/com/annimon/ownlang/parser/visitors/VariablePrinter.java @@ -9,13 +9,13 @@ import com.annimon.ownlang.parser.ast.*; public final class VariablePrinter extends AbstractVisitor { @Override - public void visit(ArrayAccessExpression s) { + public void visit(AssignmentStatement s) { super.visit(s); System.out.println(s.variable); } @Override - public void visit(AssignmentStatement s) { + public void visit(ContainerAccessExpression s) { super.visit(s); System.out.println(s.variable); }