mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44: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.STARSTAR);
|
||||||
OPERATORS.put("^^", TokenType.CARETCARET);
|
OPERATORS.put("^^", TokenType.CARETCARET);
|
||||||
OPERATORS.put("?:", TokenType.QUESTIONCOLON);
|
OPERATORS.put("?:", TokenType.QUESTIONCOLON);
|
||||||
|
OPERATORS.put("??", TokenType.QUESTIONQUESTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<String, TokenType> KEYWORDS;
|
private static final Map<String, TokenType> KEYWORDS;
|
||||||
|
@ -473,7 +473,7 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Expression ternary() {
|
private Expression ternary() {
|
||||||
Expression result = logicalOr();
|
Expression result = nullCoalesce();
|
||||||
|
|
||||||
if (match(TokenType.QUESTION)) {
|
if (match(TokenType.QUESTION)) {
|
||||||
final Expression trueExpr = expression();
|
final Expression trueExpr = expression();
|
||||||
@ -487,6 +487,20 @@ public final class Parser {
|
|||||||
return result;
|
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() {
|
private Expression logicalOr() {
|
||||||
Expression result = logicalAnd();
|
Expression result = logicalAnd();
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ public enum TokenType {
|
|||||||
DOTDOT, // ..
|
DOTDOT, // ..
|
||||||
STARSTAR, // **
|
STARSTAR, // **
|
||||||
QUESTIONCOLON, // ?:
|
QUESTIONCOLON, // ?:
|
||||||
|
QUESTIONQUESTION, // ??
|
||||||
|
|
||||||
TILDE, // ~
|
TILDE, // ~
|
||||||
CARET, // ^
|
CARET, // ^
|
||||||
|
@ -21,7 +21,9 @@ public final class ConditionalExpression implements Expression {
|
|||||||
GTEQ(">="),
|
GTEQ(">="),
|
||||||
|
|
||||||
AND("&&"),
|
AND("&&"),
|
||||||
OR("||");
|
OR("||"),
|
||||||
|
|
||||||
|
NULL_COALESCE("??");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
@ -45,15 +47,22 @@ public final class ConditionalExpression implements Expression {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value eval() {
|
public Value eval() {
|
||||||
final Value value1 = expr1.eval();
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case AND: return NumberValue.fromBoolean(
|
case AND:
|
||||||
(value1.asInt() != 0) && (expr2.eval().asInt() != 0) );
|
return NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0));
|
||||||
case OR: return NumberValue.fromBoolean(
|
case OR:
|
||||||
(value1.asInt() != 0) || (expr2.eval().asInt() != 0) );
|
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();
|
final Value value2 = expr2.eval();
|
||||||
|
|
||||||
double number1, number2;
|
double number1, number2;
|
||||||
@ -65,20 +74,39 @@ public final class ConditionalExpression implements Expression {
|
|||||||
number2 = 0;
|
number2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result;
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case EQUALS: result = number1 == number2; break;
|
case EQUALS: return number1 == number2;
|
||||||
case NOT_EQUALS: result = number1 != number2; break;
|
case NOT_EQUALS: return number1 != number2;
|
||||||
|
|
||||||
case LT: result = number1 < number2; break;
|
case LT: return number1 < number2;
|
||||||
case LTEQ: result = number1 <= number2; break;
|
case LTEQ: return number1 <= number2;
|
||||||
case GT: result = number1 > number2; break;
|
case GT: return number1 > number2;
|
||||||
case GTEQ: result = number1 >= number2; break;
|
case GTEQ: return number1 >= number2;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new OperationIsNotSupportedException(operation);
|
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
|
@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