mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Добавлено больше операторов присвоения
This commit is contained in:
parent
802927e06e
commit
135ecf8b7d
10
program.own
10
program.own
@ -221,3 +221,13 @@ 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]
|
||||||
|
@ -47,6 +47,19 @@ public final class Lexer {
|
|||||||
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);
|
||||||
|
|
||||||
OPERATORS.put("&&", TokenType.AMPAMP);
|
OPERATORS.put("&&", TokenType.AMPAMP);
|
||||||
|
@ -18,6 +18,24 @@ 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,24 +352,26 @@ 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);
|
|
||||||
final ContainerAccessExpression containerExpr = (ContainerAccessExpression) qualifiedNameExpr;
|
|
||||||
return new ContainerAssignmentExpression(containerExpr, expression());
|
|
||||||
}
|
|
||||||
pos = position;
|
pos = position;
|
||||||
|
|
||||||
return null;
|
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() {
|
||||||
Expression result = logicalOr();
|
Expression result = logicalOr();
|
||||||
|
|
||||||
|
@ -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, // >>>
|
||||||
|
10
src/com/annimon/ownlang/parser/ast/Accessible.java
Normal file
10
src/com/annimon/ownlang/parser/ast/Accessible.java
Normal 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);
|
||||||
|
}
|
@ -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) {
|
public AssignmentExpression(BinaryExpression.Operator operation, Accessible target, Expression expr) {
|
||||||
this.variable = variable;
|
this.operation = operation;
|
||||||
this.expression = expression;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,6 +26,10 @@ public final class ValueExpression implements Expression {
|
|||||||
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() {
|
||||||
return value;
|
return value;
|
||||||
|
@ -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,10 +18,21 @@ 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) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
final String variable = ((VariableExpression) s.target).name;
|
||||||
|
if (Variables.isExists(variable)) {
|
||||||
throw new RuntimeException("Cannot assign value to constant");
|
throw new RuntimeException("Cannot assign value to constant");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user