Skip to content

Commit 32d40d9

Browse files
committed
Улучшен доступ к вложенным контейнерам
1 parent 9536c7f commit 32d40d9

File tree

8 files changed

+140
-115
lines changed

8 files changed

+140
-115
lines changed

program.own

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,12 @@ extract(var2, var1) = [var1, var2]
196196
echo(var1, var2)
197197

198198
extract(, , var4) = arr
199-
println var4
199+
println var4
200+
201+
array1 = [[1, 2], [3], [4, 5], [6]]
202+
println array1[0][1]
203+
object1 = {"arr": array1}
204+
println object1.arr
205+
println object1.arr[0][1]
206+
object1.arr[0][1] = "str"
207+
println object1.arr[0][1]

src/com/annimon/ownlang/parser/Parser.java

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ private Statement assignmentStatement() {
102102
consume(TokenType.EQ);
103103
return new AssignmentStatement(variable, expression());
104104
}
105-
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LBRACKET)) {
106-
final ArrayAccessExpression array = element();
105+
106+
final Expression qualifiedNameExpr = qualifiedName();
107+
if (lookMatch(0, TokenType.EQ) && (qualifiedNameExpr instanceof ContainerAccessExpression)) {
107108
consume(TokenType.EQ);
108-
return new ArrayAssignmentStatement(array, expression());
109+
final ContainerAccessExpression containerExpr = (ContainerAccessExpression) qualifiedNameExpr;
110+
return new ContainerAssignmentStatement(containerExpr, expression());
109111
}
110112
throw new ParseException("Unknown statement: " + get(0));
111113
}
@@ -249,31 +251,6 @@ private Expression map() {
249251
return new MapExpression(elements);
250252
}
251253

252-
private ArrayAccessExpression element() {
253-
// array[e1][e2]...[eN]
254-
final String variable = consume(TokenType.WORD).getText();
255-
final List<Expression> indices = new ArrayList<>();
256-
do {
257-
consume(TokenType.LBRACKET);
258-
indices.add(expression());
259-
consume(TokenType.RBRACKET);
260-
} while(lookMatch(0, TokenType.LBRACKET));
261-
return new ArrayAccessExpression(variable, indices);
262-
}
263-
264-
private ArrayAccessExpression object() {
265-
// object.field1.field2
266-
// Syntaxic sugar for object["field1"]["field2"]
267-
final String variable = consume(TokenType.WORD).getText();
268-
final List<Expression> indices = new ArrayList<>();
269-
while (match(TokenType.DOT)) {
270-
final String fieldName = consume(TokenType.WORD).getText();
271-
final Expression key = new ValueExpression(fieldName);
272-
indices.add(key);
273-
}
274-
return new ArrayAccessExpression(variable, indices);
275-
}
276-
277254
private MatchExpression match() {
278255
// match expression {
279256
// case pattern1: result1
@@ -563,9 +540,11 @@ private Expression primary() {
563540
}
564541

565542
private Expression variable() {
543+
// function(...
566544
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) {
567545
return function(new ValueExpression(consume(TokenType.WORD).getText()));
568546
}
547+
569548
final Expression qualifiedNameExpr = qualifiedName();
570549
if (qualifiedNameExpr != null) {
571550
// variable(args) || arr["key"](args) || obj.key(args)
@@ -585,17 +564,35 @@ private Expression variable() {
585564
}
586565

587566
private Expression qualifiedName() {
567+
// var || var.key[index].key2
588568
final Token current = get(0);
589-
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LBRACKET)) {
590-
return element();
569+
if (!match(TokenType.WORD)) return null;
570+
571+
final List<Expression> indices = variableSuffix();
572+
if ((indices == null) || indices.isEmpty()) {
573+
return new VariableExpression(current.getText());
591574
}
592-
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.DOT)) {
593-
return object();
575+
return new ContainerAccessExpression(current.getText(), indices);
576+
}
577+
578+
private List<Expression> variableSuffix() {
579+
// .key1.arr1[expr1][expr2].key2
580+
if (!lookMatch(0, TokenType.DOT) && !lookMatch(0, TokenType.LBRACKET)) {
581+
return null;
594582
}
595-
if (match(TokenType.WORD)) {
596-
return new VariableExpression(current.getText());
583+
final List<Expression> indices = new ArrayList<>();
584+
while (lookMatch(0, TokenType.DOT) || lookMatch(0, TokenType.LBRACKET)) {
585+
if (match(TokenType.DOT)) {
586+
final String fieldName = consume(TokenType.WORD).getText();
587+
final Expression key = new ValueExpression(fieldName);
588+
indices.add(key);
589+
}
590+
if (match(TokenType.LBRACKET)) {
591+
indices.add(expression());
592+
consume(TokenType.RBRACKET);
593+
}
597594
}
598-
return null;
595+
return indices;
599596
}
600597

601598
private Expression value() {

src/com/annimon/ownlang/parser/ast/ArrayAssignmentStatement.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/com/annimon/ownlang/parser/ast/ArrayAccessExpression.java renamed to src/com/annimon/ownlang/parser/ast/ContainerAccessExpression.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,53 @@
88
*
99
* @author aNNiMON
1010
*/
11-
public final class ArrayAccessExpression implements Expression {
11+
public final class ContainerAccessExpression implements Expression {
1212

1313
public final String variable;
1414
public final List<Expression> indices;
1515

16-
public ArrayAccessExpression(String variable, List<Expression> indices) {
16+
public ContainerAccessExpression(String variable, List<Expression> indices) {
1717
this.variable = variable;
1818
this.indices = indices;
1919
}
2020

2121
@Override
2222
public Value eval() {
23-
Value container = Variables.get(variable);
24-
if (container.type() == Types.ARRAY) {
25-
final int lastIndex = (int) lastIndex().asNumber();
26-
return getArray().get(lastIndex);
27-
}
28-
return getMap().get(lastIndex());
29-
}
30-
31-
public ArrayValue getArray() {
32-
ArrayValue array = consumeArray(Variables.get(variable));
33-
final int last = indices.size() - 1;
34-
for (int i = 0; i < last; i++) {
35-
final int index = (int) index(i).asNumber();
36-
array = consumeArray( array.get(index) );
23+
final Value container = getContainer();
24+
final Value lastIndex = lastIndex();
25+
switch (container.type()) {
26+
case Types.ARRAY:
27+
final int arrayIndex = (int) lastIndex.asNumber();
28+
return ((ArrayValue) container).get(arrayIndex);
29+
30+
case Types.MAP:
31+
return ((MapValue) container).get(lastIndex);
32+
33+
default:
34+
throw new TypeException("Array or map expected");
3735
}
38-
return array;
3936
}
4037

41-
public MapValue getMap() {
42-
MapValue map = consumeMap(Variables.get(variable));
38+
public Value getContainer() {
39+
Value container = Variables.get(variable);
4340
final int last = indices.size() - 1;
4441
for (int i = 0; i < last; i++) {
45-
map = consumeMap( map.get(index(i)) );
42+
final Value index = index(i);
43+
switch (container.type()) {
44+
case Types.ARRAY:
45+
final int arrayIndex = (int) index.asNumber();
46+
container = ((ArrayValue) container).get(arrayIndex);
47+
break;
48+
49+
case Types.MAP:
50+
container = ((MapValue) container).get(index);
51+
break;
52+
53+
default:
54+
throw new TypeException("Array or map expected");
55+
}
4656
}
47-
return map;
57+
return container;
4858
}
4959

5060
public Value lastIndex() {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.annimon.ownlang.parser.ast;
2+
3+
import com.annimon.ownlang.exceptions.TypeException;
4+
import com.annimon.ownlang.lib.ArrayValue;
5+
import com.annimon.ownlang.lib.MapValue;
6+
import com.annimon.ownlang.lib.Types;
7+
import com.annimon.ownlang.lib.Value;
8+
9+
/**
10+
*
11+
* @author aNNiMON
12+
*/
13+
public final class ContainerAssignmentStatement implements Statement {
14+
15+
public final ContainerAccessExpression containerExpr;
16+
public final Expression expression;
17+
18+
public ContainerAssignmentStatement(ContainerAccessExpression array, Expression expression) {
19+
this.containerExpr = array;
20+
this.expression = expression;
21+
}
22+
23+
@Override
24+
public void execute() {
25+
final Value container = containerExpr.getContainer();
26+
final Value lastIndex = containerExpr.lastIndex();
27+
switch (container.type()) {
28+
case Types.ARRAY:
29+
final int arrayIndex = (int) lastIndex.asNumber();
30+
((ArrayValue) container).set(arrayIndex, expression.eval());
31+
return;
32+
33+
case Types.MAP:
34+
((MapValue) container).set(lastIndex, expression.eval());
35+
return;
36+
37+
default:
38+
throw new TypeException("Array or map expected. Got " + container.type());
39+
}
40+
}
41+
42+
@Override
43+
public void accept(Visitor visitor) {
44+
visitor.visit(this);
45+
}
46+
47+
@Override
48+
public String toString() {
49+
return String.format("%s = %s", containerExpr, expression);
50+
}
51+
}

src/com/annimon/ownlang/parser/ast/Visitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
*/
77
public interface Visitor {
88

9-
void visit(ArrayAccessExpression s);
10-
void visit(ArrayAssignmentStatement s);
119
void visit(ArrayExpression s);
1210
void visit(AssignmentStatement s);
1311
void visit(BinaryExpression s);
1412
void visit(BlockStatement s);
1513
void visit(BreakStatement s);
1614
void visit(ConditionalExpression s);
15+
void visit(ContainerAccessExpression s);
16+
void visit(ContainerAssignmentStatement s);
1717
void visit(ContinueStatement s);
1818
void visit(DoWhileStatement s);
1919
void visit(DestructuringAssignmentStatement s);

src/com/annimon/ownlang/parser/visitors/AbstractVisitor.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,6 @@
1010
*/
1111
public abstract class AbstractVisitor implements Visitor {
1212

13-
@Override
14-
public void visit(ArrayAccessExpression s) {
15-
for (Expression index : s.indices) {
16-
index.accept(this);
17-
}
18-
}
19-
20-
@Override
21-
public void visit(ArrayAssignmentStatement s) {
22-
s.array.accept(this);
23-
s.expression.accept(this);
24-
}
25-
2613
@Override
2714
public void visit(ArrayExpression s) {
2815
for (Expression index : s.elements) {
@@ -57,6 +44,19 @@ public void visit(ConditionalExpression s) {
5744
s.expr1.accept(this);
5845
s.expr2.accept(this);
5946
}
47+
48+
@Override
49+
public void visit(ContainerAccessExpression s) {
50+
for (Expression index : s.indices) {
51+
index.accept(this);
52+
}
53+
}
54+
55+
@Override
56+
public void visit(ContainerAssignmentStatement s) {
57+
s.containerExpr.accept(this);
58+
s.expression.accept(this);
59+
}
6060

6161
@Override
6262
public void visit(ContinueStatement s) {

src/com/annimon/ownlang/parser/visitors/VariablePrinter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
public final class VariablePrinter extends AbstractVisitor {
1010

1111
@Override
12-
public void visit(ArrayAccessExpression s) {
12+
public void visit(AssignmentStatement s) {
1313
super.visit(s);
1414
System.out.println(s.variable);
1515
}
1616

1717
@Override
18-
public void visit(AssignmentStatement s) {
18+
public void visit(ContainerAccessExpression s) {
1919
super.visit(s);
2020
System.out.println(s.variable);
2121
}

0 commit comments

Comments
 (0)