Присваивание как выражение

This commit is contained in:
Victor 2016-02-13 18:46:41 +02:00
parent cb07629f06
commit 802927e06e
8 changed files with 59 additions and 32 deletions

View File

@ -217,4 +217,7 @@ def funcWithOptionalArgs(str, count = 5, prefix = "<", suffix = ">") = prefix +
println funcWithOptionalArgs("*") println funcWithOptionalArgs("*")
println funcWithOptionalArgs("+", 2) println funcWithOptionalArgs("+", 2)
println funcWithOptionalArgs("*", 10, "<!") println funcWithOptionalArgs("*", 10, "<!")
v1 = v2 = v3 = v4 = 5
echo(v1, v2, v3, v4)

View File

@ -87,9 +87,6 @@ public final class Parser {
if (match(TokenType.MATCH)) { if (match(TokenType.MATCH)) {
return new ExprStatement(match()); return new ExprStatement(match());
} }
if (match(TokenType.EXTRACT)) {
return destructuringAssignment();
}
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) { if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) {
return new ExprStatement(function(qualifiedName())); return new ExprStatement(function(qualifiedName()));
} }
@ -97,17 +94,12 @@ public final class Parser {
} }
private Statement assignmentStatement() { private Statement assignmentStatement() {
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.EQ)) { if (match(TokenType.EXTRACT)) {
final String variable = consume(TokenType.WORD).getText(); return destructuringAssignment();
consume(TokenType.EQ);
return new AssignmentStatement(variable, expression());
} }
final Expression assignment = assignmentStrict();
final Expression qualifiedNameExpr = qualifiedName(); if (assignment != null) {
if (lookMatch(0, TokenType.EQ) && (qualifiedNameExpr instanceof ContainerAccessExpression)) { return new ExprStatement(assignment);
consume(TokenType.EQ);
final ContainerAccessExpression containerExpr = (ContainerAccessExpression) qualifiedNameExpr;
return new ContainerAssignmentStatement(containerExpr, expression());
} }
throw new ParseException("Unknown statement: " + get(0)); throw new ParseException("Unknown statement: " + get(0));
} }
@ -330,9 +322,36 @@ public final class Parser {
} }
private Expression expression() { private Expression expression() {
return assignment();
}
private Expression assignment() {
final Expression assignment = assignmentStrict();
if (assignment != null) {
return assignment;
}
return ternary(); return ternary();
} }
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());
}
pos = position;
return null;
}
private Expression ternary() { private Expression ternary() {
Expression result = logicalOr(); Expression result = logicalOr();

View File

@ -7,20 +7,21 @@ import com.annimon.ownlang.lib.Variables;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class AssignmentStatement implements Statement { public final class AssignmentExpression implements Expression {
public final String variable; public final String variable;
public final Expression expression; public final Expression expression;
public AssignmentStatement(String variable, Expression expression) { public AssignmentExpression(String variable, Expression expression) {
this.variable = variable; this.variable = variable;
this.expression = expression; this.expression = expression;
} }
@Override @Override
public void execute() { public Value eval() {
final Value result = expression.eval(); final Value result = expression.eval();
Variables.set(variable, result); Variables.set(variable, result);
return result;
} }
@Override @Override

View File

@ -10,29 +10,33 @@ import com.annimon.ownlang.lib.Value;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class ContainerAssignmentStatement implements Statement { public final class ContainerAssignmentExpression implements Expression {
public final ContainerAccessExpression containerExpr; public final ContainerAccessExpression containerExpr;
public final Expression expression; public final Expression expression;
public ContainerAssignmentStatement(ContainerAccessExpression array, Expression expression) { public ContainerAssignmentExpression(ContainerAccessExpression array, Expression expression) {
this.containerExpr = array; this.containerExpr = array;
this.expression = expression; this.expression = expression;
} }
@Override @Override
public void execute() { public Value eval() {
final Value container = containerExpr.getContainer(); final Value container = containerExpr.getContainer();
final Value lastIndex = containerExpr.lastIndex(); final Value lastIndex = containerExpr.lastIndex();
switch (container.type()) { switch (container.type()) {
case Types.ARRAY: case Types.ARRAY: {
final Value result = expression.eval();
final int arrayIndex = (int) lastIndex.asNumber(); final int arrayIndex = (int) lastIndex.asNumber();
((ArrayValue) container).set(arrayIndex, expression.eval()); ((ArrayValue) container).set(arrayIndex, result);
return; return result;
}
case Types.MAP: case Types.MAP: {
((MapValue) container).set(lastIndex, expression.eval()); final Value result = expression.eval();
return; ((MapValue) container).set(lastIndex, result);
return result;
}
default: default:
throw new TypeException("Array or map expected. Got " + container.type()); throw new TypeException("Array or map expected. Got " + container.type());

View File

@ -7,13 +7,13 @@ package com.annimon.ownlang.parser.ast;
public interface Visitor { public interface Visitor {
void visit(ArrayExpression s); void visit(ArrayExpression s);
void visit(AssignmentStatement s); void visit(AssignmentExpression s);
void visit(BinaryExpression s); void visit(BinaryExpression s);
void visit(BlockStatement s); void visit(BlockStatement s);
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(ContainerAssignmentStatement 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

@ -18,7 +18,7 @@ public abstract class AbstractVisitor implements Visitor {
} }
@Override @Override
public void visit(AssignmentStatement s) { public void visit(AssignmentExpression s) {
s.expression.accept(this); s.expression.accept(this);
} }
@ -53,7 +53,7 @@ public abstract class AbstractVisitor implements Visitor {
} }
@Override @Override
public void visit(ContainerAssignmentStatement s) { public void visit(ContainerAssignmentExpression s) {
s.containerExpr.accept(this); s.containerExpr.accept(this);
s.expression.accept(this); s.expression.accept(this);
} }

View File

@ -10,7 +10,7 @@ import com.annimon.ownlang.parser.ast.*;
public final class AssignValidator extends AbstractVisitor { public final class AssignValidator extends AbstractVisitor {
@Override @Override
public void visit(AssignmentStatement s) { public void visit(AssignmentExpression s) {
super.visit(s); super.visit(s);
if (Variables.isExists(s.variable)) { if (Variables.isExists(s.variable)) {
throw new RuntimeException("Cannot assign value to constant"); throw new RuntimeException("Cannot assign value to constant");

View File

@ -9,7 +9,7 @@ import com.annimon.ownlang.parser.ast.*;
public final class VariablePrinter extends AbstractVisitor { public final class VariablePrinter extends AbstractVisitor {
@Override @Override
public void visit(AssignmentStatement s) { public void visit(AssignmentExpression s) {
super.visit(s); super.visit(s);
System.out.println(s.variable); System.out.println(s.variable);
} }