Добавлено больше операторов присвоения

This commit is contained in:
Victor 2016-02-13 21:57:42 +02:00
parent 802927e06e
commit 135ecf8b7d
14 changed files with 146 additions and 93 deletions

View File

@ -220,4 +220,14 @@ println funcWithOptionalArgs("+", 2)
println funcWithOptionalArgs("*", 10, "<!") println funcWithOptionalArgs("*", 10, "<!")
v1 = v2 = v3 = v4 = 5 v1 = v2 = v3 = v4 = 5
echo(v1, v2, v3, v4) echo(v1, v2, v3, v4)
x = 5
x += 10
x *= 2
println x
xarr = [0, 5, 2]
xarr[0] += xarr[1]
xarr[0] *= xarr[2]
println xarr[0]

View File

@ -46,6 +46,19 @@ public final class Lexer {
OPERATORS.put("!=", TokenType.EXCLEQ); OPERATORS.put("!=", TokenType.EXCLEQ);
OPERATORS.put("<=", TokenType.LTEQ); OPERATORS.put("<=", TokenType.LTEQ);
OPERATORS.put(">=", TokenType.GTEQ); OPERATORS.put(">=", TokenType.GTEQ);
OPERATORS.put("+=", TokenType.PLUSEQ);
OPERATORS.put("-=", TokenType.MINUSEQ);
OPERATORS.put("*=", TokenType.STAREQ);
OPERATORS.put("/=", TokenType.SLASHEQ);
OPERATORS.put("%=", TokenType.PERCENTEQ);
OPERATORS.put("&=", TokenType.AMPEQ);
OPERATORS.put("^=", TokenType.CARETEQ);
OPERATORS.put("|=", TokenType.BAREQ);
OPERATORS.put("::=", TokenType.COLONCOLONEQ);
OPERATORS.put("<<=", TokenType.LTLTEQ);
OPERATORS.put(">>=", TokenType.GTGTEQ);
OPERATORS.put(">>>=", TokenType.GTGTGTEQ);
OPERATORS.put("::", TokenType.COLONCOLON); OPERATORS.put("::", TokenType.COLONCOLON);

View File

@ -17,6 +17,24 @@ import java.util.Map;
public final class Parser { public final class Parser {
private static final Token EOF = new Token(TokenType.EOF, "", -1, -1); private static final Token EOF = new Token(TokenType.EOF, "", -1, -1);
private static final Map<TokenType, BinaryExpression.Operator> assignOperator;
static {
assignOperator = new HashMap<>(BinaryExpression.Operator.values().length + 1);
assignOperator.put(TokenType.EQ, null);
assignOperator.put(TokenType.PLUSEQ, BinaryExpression.Operator.ADD);
assignOperator.put(TokenType.MINUSEQ, BinaryExpression.Operator.SUBTRACT);
assignOperator.put(TokenType.STAREQ, BinaryExpression.Operator.MULTIPLY);
assignOperator.put(TokenType.SLASHEQ, BinaryExpression.Operator.DIVIDE);
assignOperator.put(TokenType.PERCENTEQ, BinaryExpression.Operator.REMAINDER);
assignOperator.put(TokenType.AMPEQ, BinaryExpression.Operator.AND);
assignOperator.put(TokenType.CARETEQ, BinaryExpression.Operator.XOR);
assignOperator.put(TokenType.BAREQ, BinaryExpression.Operator.OR);
assignOperator.put(TokenType.COLONCOLONEQ, BinaryExpression.Operator.PUSH);
assignOperator.put(TokenType.LTLTEQ, BinaryExpression.Operator.LSHIFT);
assignOperator.put(TokenType.GTGTEQ, BinaryExpression.Operator.RSHIFT);
assignOperator.put(TokenType.GTGTGTEQ, BinaryExpression.Operator.URSHIFT);
}
private final List<Token> tokens; private final List<Token> tokens;
private final int size; private final int size;
@ -334,22 +352,24 @@ public final class Parser {
} }
private Expression assignmentStrict() { private Expression assignmentStrict() {
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.EQ)) {
final String variable = consume(TokenType.WORD).getText();
consume(TokenType.EQ);
return new AssignmentExpression(variable, expression());
}
final int position = pos; final int position = pos;
final Expression qualifiedNameExpr = qualifiedName(); final Expression targetExpr = qualifiedName();
if (lookMatch(0, TokenType.EQ) && (qualifiedNameExpr instanceof ContainerAccessExpression)) { if ((targetExpr == null) || !(targetExpr instanceof Accessible)) {
consume(TokenType.EQ); pos = position;
final ContainerAccessExpression containerExpr = (ContainerAccessExpression) qualifiedNameExpr; return null;
return new ContainerAssignmentExpression(containerExpr, expression());
} }
pos = position;
return null; final TokenType currentType = get(0).getType();
if (!assignOperator.containsKey(currentType)) {
pos = position;
return null;
}
match(currentType);
final BinaryExpression.Operator op = assignOperator.get(currentType);
final Expression expression = expression();
return new AssignmentExpression(op, (Accessible) targetExpr, expression);
} }
private Expression ternary() { private Expression ternary() {

View File

@ -33,6 +33,7 @@ public enum TokenType {
STAR, // * STAR, // *
SLASH, // / SLASH, // /
PERCENT,// % PERCENT,// %
EQ, // = EQ, // =
EQEQ, // == EQEQ, // ==
EXCL, // ! EXCL, // !
@ -42,6 +43,19 @@ public enum TokenType {
GT, // > GT, // >
GTEQ, // >= GTEQ, // >=
PLUSEQ, // +=
MINUSEQ, // -=
STAREQ, // *=
SLASHEQ, // /=
PERCENTEQ, // %=
AMPEQ, // &=
CARETEQ, // ^=
BAREQ, // |=
COLONCOLONEQ, // ::=
LTLTEQ, // <<=
GTGTEQ, // >>=
GTGTGTEQ, // >>>=
LTLT, // << LTLT, // <<
GTGT, // >> GTGT, // >>
GTGTGT, // >>> GTGTGT, // >>>

View File

@ -0,0 +1,10 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.Value;
public interface Accessible {
Value get();
Value set(Value value);
}

View File

@ -1,7 +1,6 @@
package com.annimon.ownlang.parser.ast; package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
/** /**
* *
@ -9,19 +8,25 @@ import com.annimon.ownlang.lib.Variables;
*/ */
public final class AssignmentExpression implements Expression { public final class AssignmentExpression implements Expression {
public final String variable; public final Accessible target;
public final BinaryExpression.Operator operation;
public final Expression expression; public final Expression expression;
public AssignmentExpression(String variable, Expression expression) {
this.variable = variable;
this.expression = expression;
}
public AssignmentExpression(BinaryExpression.Operator operation, Accessible target, Expression expr) {
this.operation = operation;
this.target = target;
this.expression = expr;
}
@Override @Override
public Value eval() { public Value eval() {
final Value result = expression.eval(); if (operation == null) {
Variables.set(variable, result); // Simple assignment
return result; return target.set(expression.eval());
}
final Expression expr1 = new ValueExpression(target.get());
final Expression expr2 = new ValueExpression(expression.eval());
return target.set(new BinaryExpression(operation, expr1, expr2).eval());
} }
@Override @Override
@ -31,6 +36,7 @@ public final class AssignmentExpression implements Expression {
@Override @Override
public String toString() { public String toString() {
return String.format("%s = %s", variable, expression); final String op = (operation == null) ? "" : operation.toString();
return String.format("%s %s= %s", target, op, expression);
} }
} }

View File

@ -8,7 +8,7 @@ import java.util.List;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class ContainerAccessExpression implements Expression { public final class ContainerAccessExpression implements Expression, Accessible {
public final String variable; public final String variable;
public final List<Expression> indices; public final List<Expression> indices;
@ -20,6 +20,11 @@ public final class ContainerAccessExpression implements Expression {
@Override @Override
public Value eval() { public Value eval() {
return get();
}
@Override
public Value get() {
final Value container = getContainer(); final Value container = getContainer();
final Value lastIndex = lastIndex(); final Value lastIndex = lastIndex();
switch (container.type()) { switch (container.type()) {
@ -31,7 +36,26 @@ public final class ContainerAccessExpression implements Expression {
return ((MapValue) container).get(lastIndex); return ((MapValue) container).get(lastIndex);
default: default:
throw new TypeException("Array or map expected"); throw new TypeException("Array or map expected. Got " + container.type());
}
}
@Override
public Value set(Value value) {
final Value container = getContainer();
final Value lastIndex = lastIndex();
switch (container.type()) {
case Types.ARRAY:
final int arrayIndex = (int) lastIndex.asNumber();
((ArrayValue) container).set(arrayIndex, value);
return value;
case Types.MAP:
((MapValue) container).set(lastIndex, value);
return value;
default:
throw new TypeException("Array or map expected. Got " + container.type());
} }
} }

View File

@ -1,55 +0,0 @@
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 ContainerAssignmentExpression implements Expression {
public final ContainerAccessExpression containerExpr;
public final Expression expression;
public ContainerAssignmentExpression(ContainerAccessExpression array, Expression expression) {
this.containerExpr = array;
this.expression = expression;
}
@Override
public Value eval() {
final Value container = containerExpr.getContainer();
final Value lastIndex = containerExpr.lastIndex();
switch (container.type()) {
case Types.ARRAY: {
final Value result = expression.eval();
final int arrayIndex = (int) lastIndex.asNumber();
((ArrayValue) container).set(arrayIndex, result);
return result;
}
case Types.MAP: {
final Value result = expression.eval();
((MapValue) container).set(lastIndex, result);
return result;
}
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);
}
}

View File

@ -25,6 +25,10 @@ public final class ValueExpression implements Expression {
public ValueExpression(Function value) { public ValueExpression(Function value) {
this.value = new FunctionValue(value); this.value = new FunctionValue(value);
} }
public ValueExpression(Value value) {
this.value = value;
}
@Override @Override
public Value eval() { public Value eval() {

View File

@ -8,7 +8,7 @@ import com.annimon.ownlang.lib.Variables;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class VariableExpression implements Expression { public final class VariableExpression implements Expression, Accessible {
public final String name; public final String name;
@ -18,9 +18,20 @@ public final class VariableExpression implements Expression {
@Override @Override
public Value eval() { public Value eval() {
return get();
}
@Override
public Value get() {
if (!Variables.isExists(name)) throw new VariableDoesNotExistsException(name); if (!Variables.isExists(name)) throw new VariableDoesNotExistsException(name);
return Variables.get(name); return Variables.get(name);
} }
@Override
public Value set(Value value) {
Variables.set(name, value);
return value;
}
@Override @Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {

View File

@ -13,7 +13,6 @@ public interface Visitor {
void visit(BreakStatement s); void visit(BreakStatement s);
void visit(ConditionalExpression s); void visit(ConditionalExpression s);
void visit(ContainerAccessExpression s); void visit(ContainerAccessExpression s);
void visit(ContainerAssignmentExpression s);
void visit(ContinueStatement s); void visit(ContinueStatement s);
void visit(DoWhileStatement s); void visit(DoWhileStatement s);
void visit(DestructuringAssignmentStatement s); void visit(DestructuringAssignmentStatement s);

View File

@ -52,12 +52,6 @@ public abstract class AbstractVisitor implements Visitor {
} }
} }
@Override
public void visit(ContainerAssignmentExpression s) {
s.containerExpr.accept(this);
s.expression.accept(this);
}
@Override @Override
public void visit(ContinueStatement s) { public void visit(ContinueStatement s) {
} }

View File

@ -12,8 +12,11 @@ public final class AssignValidator extends AbstractVisitor {
@Override @Override
public void visit(AssignmentExpression s) { public void visit(AssignmentExpression s) {
super.visit(s); super.visit(s);
if (Variables.isExists(s.variable)) { if (s.target instanceof VariableExpression) {
throw new RuntimeException("Cannot assign value to constant"); final String variable = ((VariableExpression) s.target).name;
if (Variables.isExists(variable)) {
throw new RuntimeException("Cannot assign value to constant");
}
} }
} }
} }

View File

@ -11,7 +11,7 @@ public final class VariablePrinter extends AbstractVisitor {
@Override @Override
public void visit(AssignmentExpression s) { public void visit(AssignmentExpression s) {
super.visit(s); super.visit(s);
System.out.println(s.variable); System.out.println(s.target);
} }
@Override @Override