mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Улучшен доступ к вложенным контейнерам
This commit is contained in:
parent
9536c7f5b0
commit
32d40d9d04
@ -197,3 +197,11 @@ echo(var1, var2)
|
||||
|
||||
extract(, , var4) = arr
|
||||
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]
|
||||
|
@ -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<Expression> 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<Expression> 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,18 +564,36 @@ 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<Expression> indices = variableSuffix();
|
||||
if ((indices == null) || indices.isEmpty()) {
|
||||
return new VariableExpression(current.getText());
|
||||
}
|
||||
return new ContainerAccessExpression(current.getText(), indices);
|
||||
}
|
||||
|
||||
private List<Expression> variableSuffix() {
|
||||
// .key1.arr1[expr1][expr2].key2
|
||||
if (!lookMatch(0, TokenType.DOT) && !lookMatch(0, TokenType.LBRACKET)) {
|
||||
return null;
|
||||
}
|
||||
final List<Expression> 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() {
|
||||
final Token current = get(0);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<Expression> indices;
|
||||
|
||||
public ArrayAccessExpression(String variable, List<Expression> indices) {
|
||||
public ContainerAccessExpression(String variable, List<Expression> 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) );
|
||||
}
|
||||
return array;
|
||||
}
|
||||
final Value index = index(i);
|
||||
switch (container.type()) {
|
||||
case Types.ARRAY:
|
||||
final int arrayIndex = (int) index.asNumber();
|
||||
container = ((ArrayValue) container).get(arrayIndex);
|
||||
break;
|
||||
|
||||
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)) );
|
||||
case Types.MAP:
|
||||
container = ((MapValue) container).get(index);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new TypeException("Array or map expected");
|
||||
}
|
||||
return map;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
public Value lastIndex() {
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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) {
|
||||
@ -58,6 +45,19 @@ public abstract class AbstractVisitor implements Visitor {
|
||||
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) {
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user