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

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

@ -221,3 +221,13 @@ println funcWithOptionalArgs("*", 10, "<!")
v1 = v2 = v3 = v4 = 5
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

@ -47,6 +47,19 @@ public final class Lexer {
OPERATORS.put("<=", TokenType.LTEQ);
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.AMPAMP);

View File

@ -18,6 +18,24 @@ public final class Parser {
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 int size;
@ -334,24 +352,26 @@ public final class Parser {
}
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 Expression qualifiedNameExpr = qualifiedName();
if (lookMatch(0, TokenType.EQ) && (qualifiedNameExpr instanceof ContainerAccessExpression)) {
consume(TokenType.EQ);
final ContainerAccessExpression containerExpr = (ContainerAccessExpression) qualifiedNameExpr;
return new ContainerAssignmentExpression(containerExpr, expression());
}
final Expression targetExpr = qualifiedName();
if ((targetExpr == null) || !(targetExpr instanceof Accessible)) {
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() {
Expression result = logicalOr();

View File

@ -33,6 +33,7 @@ public enum TokenType {
STAR, // *
SLASH, // /
PERCENT,// %
EQ, // =
EQEQ, // ==
EXCL, // !
@ -42,6 +43,19 @@ public enum TokenType {
GT, // >
GTEQ, // >=
PLUSEQ, // +=
MINUSEQ, // -=
STAREQ, // *=
SLASHEQ, // /=
PERCENTEQ, // %=
AMPEQ, // &=
CARETEQ, // ^=
BAREQ, // |=
COLONCOLONEQ, // ::=
LTLTEQ, // <<=
GTGTEQ, // >>=
GTGTGTEQ, // >>>=
LTLT, // <<
GTGT, // >>
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;
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 String variable;
public final Accessible target;
public final BinaryExpression.Operator operation;
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
public Value eval() {
final Value result = expression.eval();
Variables.set(variable, result);
return result;
if (operation == null) {
// Simple assignment
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
@ -31,6 +36,7 @@ public final class AssignmentExpression implements Expression {
@Override
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
*/
public final class ContainerAccessExpression implements Expression {
public final class ContainerAccessExpression implements Expression, Accessible {
public final String variable;
public final List<Expression> indices;
@ -20,6 +20,11 @@ public final class ContainerAccessExpression implements Expression {
@Override
public Value eval() {
return get();
}
@Override
public Value get() {
final Value container = getContainer();
final Value lastIndex = lastIndex();
switch (container.type()) {
@ -31,7 +36,26 @@ public final class ContainerAccessExpression implements Expression {
return ((MapValue) container).get(lastIndex);
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

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

View File

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

View File

@ -13,7 +13,6 @@ public interface Visitor {
void visit(BreakStatement s);
void visit(ConditionalExpression s);
void visit(ContainerAccessExpression s);
void visit(ContainerAssignmentExpression s);
void visit(ContinueStatement s);
void visit(DoWhileStatement 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
public void visit(ContinueStatement s) {
}

View File

@ -12,8 +12,11 @@ public final class AssignValidator extends AbstractVisitor {
@Override
public void visit(AssignmentExpression s) {
super.visit(s);
if (Variables.isExists(s.variable)) {
if (s.target instanceof VariableExpression) {
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
public void visit(AssignmentExpression s) {
super.visit(s);
System.out.println(s.variable);
System.out.println(s.target);
}
@Override