mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Добавлен оператор объединения с null
This commit is contained in:
parent
2e439d73b5
commit
0bd2aa10d5
@ -83,6 +83,7 @@ public final class Lexer {
|
||||
OPERATORS.put("**", TokenType.STARSTAR);
|
||||
OPERATORS.put("^^", TokenType.CARETCARET);
|
||||
OPERATORS.put("?:", TokenType.QUESTIONCOLON);
|
||||
OPERATORS.put("??", TokenType.QUESTIONQUESTION);
|
||||
}
|
||||
|
||||
private static final Map<String, TokenType> KEYWORDS;
|
||||
|
@ -473,7 +473,7 @@ public final class Parser {
|
||||
}
|
||||
|
||||
private Expression ternary() {
|
||||
Expression result = logicalOr();
|
||||
Expression result = nullCoalesce();
|
||||
|
||||
if (match(TokenType.QUESTION)) {
|
||||
final Expression trueExpr = expression();
|
||||
@ -487,6 +487,20 @@ public final class Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Expression nullCoalesce() {
|
||||
Expression result = logicalOr();
|
||||
|
||||
while (true) {
|
||||
if (match(TokenType.QUESTIONQUESTION)) {
|
||||
result = new ConditionalExpression(ConditionalExpression.Operator.NULL_COALESCE, result, expression());
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Expression logicalOr() {
|
||||
Expression result = logicalAnd();
|
||||
|
||||
|
@ -69,6 +69,7 @@ public enum TokenType {
|
||||
DOTDOT, // ..
|
||||
STARSTAR, // **
|
||||
QUESTIONCOLON, // ?:
|
||||
QUESTIONQUESTION, // ??
|
||||
|
||||
TILDE, // ~
|
||||
CARET, // ^
|
||||
|
@ -21,7 +21,9 @@ public final class ConditionalExpression implements Expression {
|
||||
GTEQ(">="),
|
||||
|
||||
AND("&&"),
|
||||
OR("||");
|
||||
OR("||"),
|
||||
|
||||
NULL_COALESCE("??");
|
||||
|
||||
private final String name;
|
||||
|
||||
@ -45,15 +47,22 @@ public final class ConditionalExpression implements Expression {
|
||||
|
||||
@Override
|
||||
public Value eval() {
|
||||
final Value value1 = expr1.eval();
|
||||
switch (operation) {
|
||||
case AND: return NumberValue.fromBoolean(
|
||||
(value1.asInt() != 0) && (expr2.eval().asInt() != 0) );
|
||||
case OR: return NumberValue.fromBoolean(
|
||||
(value1.asInt() != 0) || (expr2.eval().asInt() != 0) );
|
||||
case AND:
|
||||
return NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0));
|
||||
case OR:
|
||||
return NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0));
|
||||
|
||||
case NULL_COALESCE:
|
||||
return nullCoalesce();
|
||||
|
||||
default:
|
||||
return NumberValue.fromBoolean(evalAndCompare());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean evalAndCompare() {
|
||||
final Value value1 = expr1.eval();
|
||||
final Value value2 = expr2.eval();
|
||||
|
||||
double number1, number2;
|
||||
@ -65,20 +74,39 @@ public final class ConditionalExpression implements Expression {
|
||||
number2 = 0;
|
||||
}
|
||||
|
||||
boolean result;
|
||||
switch (operation) {
|
||||
case EQUALS: result = number1 == number2; break;
|
||||
case NOT_EQUALS: result = number1 != number2; break;
|
||||
case EQUALS: return number1 == number2;
|
||||
case NOT_EQUALS: return number1 != number2;
|
||||
|
||||
case LT: result = number1 < number2; break;
|
||||
case LTEQ: result = number1 <= number2; break;
|
||||
case GT: result = number1 > number2; break;
|
||||
case GTEQ: result = number1 >= number2; break;
|
||||
case LT: return number1 < number2;
|
||||
case LTEQ: return number1 <= number2;
|
||||
case GT: return number1 > number2;
|
||||
case GTEQ: return number1 >= number2;
|
||||
|
||||
default:
|
||||
throw new OperationIsNotSupportedException(operation);
|
||||
}
|
||||
return NumberValue.fromBoolean(result);
|
||||
}
|
||||
|
||||
private Value nullCoalesce() {
|
||||
Value value1;
|
||||
try {
|
||||
value1 = expr1.eval();
|
||||
} catch (NullPointerException npe) {
|
||||
value1 = null;
|
||||
}
|
||||
if (value1 == null) {
|
||||
return expr2.eval();
|
||||
}
|
||||
return value1;
|
||||
}
|
||||
|
||||
private int expr1AsInt() {
|
||||
return expr1.eval().asInt();
|
||||
}
|
||||
|
||||
private int expr2AsInt() {
|
||||
return expr2.eval().asInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
27
src/test/resources/expressions/nullCoalesce.own
Normal file
27
src/test/resources/expressions/nullCoalesce.own
Normal file
@ -0,0 +1,27 @@
|
||||
def testZero() {
|
||||
assertEquals(0, 0 ?? 1)
|
||||
x = 0
|
||||
assertEquals(0, x ?? 2)
|
||||
}
|
||||
|
||||
def testObject() {
|
||||
obj = {"a": 12}
|
||||
assertEquals(12, obj.a ?? 10)
|
||||
}
|
||||
|
||||
def testObjectMissingKey() {
|
||||
obj = {"a": 12}
|
||||
assertEquals(10, obj.test ?? 10)
|
||||
}
|
||||
|
||||
def testNestedObjects() {
|
||||
obj = {"a": {"b": 12}}
|
||||
assertEquals(12, obj.a.b ?? 10)
|
||||
}
|
||||
|
||||
def testNestedObjectsMissingKey() {
|
||||
obj = {"a": {"b": 12}}
|
||||
assertEquals(1, obj.test ?? 1)
|
||||
assertEquals(2, obj.a.test ?? 2)
|
||||
assertEquals(3, obj.test1.test2 ?? 3)
|
||||
}
|
Loading…
Reference in New Issue
Block a user