aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/viml/parser/expressions.c87
-rw-r--r--src/nvim/viml/parser/expressions.h6
-rw-r--r--test/unit/viml/expressions/parser_spec.lua651
3 files changed, 705 insertions, 39 deletions
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index c283241cb4..41c77c5c88 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -46,6 +46,7 @@ typedef enum {
kEOpLvlArrow,
kEOpLvlComma,
kEOpLvlColon,
+ kEOpLvlTernaryValue,
kEOpLvlTernary,
kEOpLvlOr,
kEOpLvlAnd,
@@ -770,7 +771,8 @@ static inline void viml_pexpr_debug_print_token(
// NVimUnaryOperator -> NVimOperator
// NVimBinaryOperator -> NVimOperator
// NVimComparisonOperator -> NVimOperator
-// NVimTernaryOperator -> NVimOperator
+// NVimTernary -> NVimOperator
+// NVimTernaryColon -> NVimTernary
//
// NVimParenthesis -> Delimiter
//
@@ -790,7 +792,8 @@ static inline void viml_pexpr_debug_print_token(
//
// NVimInvalidComma -> NVimInvalidDelimiter
// NVimInvalidSpacing -> NVimInvalid
-// NVimInvalidTernaryOperator -> NVimInvalidOperator
+// NVimInvalidTernary -> NVimInvalidOperator
+// NVimInvalidTernaryColon -> NVimInvalidTernary
// NVimInvalidRegister -> NVimInvalidValue
// NVimInvalidClosingBracket -> NVimInvalidDelimiter
// NVimInvalidSpacing -> NVimInvalid
@@ -823,30 +826,6 @@ static inline ExprASTNode *viml_pexpr_new_node(const ExprASTNodeType type)
return ret;
}
-typedef enum {
- kEOpLvlInvalid = 0,
- kEOpLvlComplexIdentifier,
- kEOpLvlParens,
- kEOpLvlArrow,
- kEOpLvlComma,
- kEOpLvlColon,
- kEOpLvlTernary,
- kEOpLvlOr,
- kEOpLvlAnd,
- kEOpLvlComparison,
- kEOpLvlAddition, ///< Addition, subtraction and concatenation.
- kEOpLvlMultiplication, ///< Multiplication, division and modulo.
- kEOpLvlUnary, ///< Unary operations: not, minus, plus.
- kEOpLvlSubscript, ///< Subscripts.
- kEOpLvlValue, ///< Values: literals, variables, nested expressions, …
-} ExprOpLvl;
-
-typedef enum {
- kEOpAssNo= 'n', ///< Not associative / not applicable.
- kEOpAssLeft = 'l', ///< Left associativity.
- kEOpAssRight = 'r', ///< Right associativity.
-} ExprOpAssociativity;
-
static const ExprOpLvl node_type_to_op_lvl[] = {
[kExprNodeMissing] = kEOpLvlInvalid,
[kExprNodeOpMissing] = kEOpLvlMultiplication,
@@ -868,6 +847,8 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
[kExprNodeTernary] = kEOpLvlTernary,
+ [kExprNodeTernaryValue] = kEOpLvlTernaryValue,
+
[kExprNodeBinaryPlus] = kEOpLvlAddition,
[kExprNodeUnaryPlus] = kEOpLvlUnary,
@@ -907,7 +888,9 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
// about associativity, only about order of execution.
[kExprNodeComma] = kEOpAssRight,
- [kExprNodeTernary] = kEOpAssNo,
+ [kExprNodeTernary] = kEOpAssRight,
+
+ [kExprNodeTernaryValue] = kEOpAssRight,
[kExprNodeBinaryPlus] = kEOpAssLeft,
@@ -1450,9 +1433,20 @@ viml_pexpr_parse_invalid_comma:
const ExprOpLvl eastnode_lvl = node_lvl(**eastnode_p);
STATIC_ASSERT(kEOpLvlTernary > kEOpLvlComma,
"Unexpected operator priorities");
- if (can_be_ternary && eastnode_lvl == kEOpLvlTernary) {
- assert(eastnode_type == kExprNodeTernary);
+ if (can_be_ternary && eastnode_type == kExprNodeTernaryValue
+ && !(*eastnode_p)->data.ter.got_colon) {
+ kv_drop(ast_stack, i);
+ (*eastnode_p)->start = cur_token.start;
+ (*eastnode_p)->len = cur_token.len;
+ if (prev_token.type == kExprLexSpacing) {
+ (*eastnode_p)->start = prev_token.start;
+ (*eastnode_p)->len += prev_token.len;
+ }
is_ternary = true;
+ (*eastnode_p)->data.ter.got_colon = true;
+ assert((*eastnode_p)->children != NULL);
+ assert((*eastnode_p)->children->next == NULL);
+ kvi_push(ast_stack, &(*eastnode_p)->children->next);
break;
} else if (eastnode_type == kExprNodeUnknownFigure) {
SELECT_FIGURE_BRACE_TYPE(*eastnode_p, DictLiteral, Dict);
@@ -1460,7 +1454,7 @@ viml_pexpr_parse_invalid_comma:
} else if (eastnode_type == kExprNodeDictLiteral
|| eastnode_type == kExprNodeComma) {
break;
- } else if (eastnode_lvl > kEOpLvlTernary) {
+ } else if (eastnode_lvl >= kEOpLvlTernaryValue) {
// Do nothing
} else if (eastnode_lvl > kEOpLvlComma) {
can_be_ternary = false;
@@ -1476,11 +1470,11 @@ viml_pexpr_parse_invalid_colon:
goto viml_pexpr_parse_invalid_colon;
}
}
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
- viml_pexpr_handle_bop(&ast_stack, cur_node, &want_node);
if (is_ternary) {
HL_CUR_TOKEN(TernaryColon);
} else {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
+ viml_pexpr_handle_bop(&ast_stack, cur_node, &want_node);
HL_CUR_TOKEN(Colon);
}
want_node = kENodeValue;
@@ -1683,8 +1677,6 @@ viml_pexpr_parse_figure_brace_closing_error:
cur_token.len - scope_shift,
HL(Identifier));
}
- // FIXME: Actually, g{foo}g:foo is valid: "1?g{foo}g:foo" is like
- // "g{foo}g" and not an error.
} else {
if (cur_token.data.var.scope == 0) {
ADD_IDENT(
@@ -1792,6 +1784,21 @@ viml_pexpr_parse_no_paren_closing_error: {}
}
break;
}
+ case kExprLexQuestion: {
+ ADD_VALUE_IF_MISSING(_("E15: Expected value, got question mark: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeTernary);
+ viml_pexpr_handle_bop(&ast_stack, cur_node, &want_node);
+ HL_CUR_TOKEN(Ternary);
+ ExprASTNode *ter_val_node;
+ NEW_NODE_WITH_CUR_POS(ter_val_node, kExprNodeTernaryValue);
+ ter_val_node->data.ter.got_colon = false;
+ assert(cur_node->children != NULL);
+ assert(cur_node->children->next == NULL);
+ assert(kv_last(ast_stack) == &cur_node->children->next);
+ *kv_last(ast_stack) = ter_val_node;
+ kvi_push(ast_stack, &ter_val_node->children);
+ break;
+ }
}
viml_pexpr_parse_cycle_end:
prev_token = cur_token;
@@ -1815,6 +1822,7 @@ viml_pexpr_parse_end:
const ExprASTNode *const cur_node = (*kv_pop(ast_stack));
// This should only happen when want_node == kENodeValue.
assert(cur_node != NULL);
+ // TODO(ZyX-I): Rehighlight as invalid?
switch (cur_node->type) {
case kExprNodeOpMissing:
case kExprNodeMissing: {
@@ -1822,7 +1830,6 @@ viml_pexpr_parse_end:
break;
}
case kExprNodeCall: {
- // TODO(ZyX-I): Rehighlight as invalid?
east_set_error(
&ast, pstate,
_("E116: Missing closing parenthesis for function call: %.*s"),
@@ -1830,7 +1837,6 @@ viml_pexpr_parse_end:
break;
}
case kExprNodeNested: {
- // TODO(ZyX-I): Rehighlight as invalid?
east_set_error(
&ast, pstate,
_("E110: Missing closing parenthesis for nested expression"
@@ -1844,6 +1850,15 @@ viml_pexpr_parse_end:
// It is OK to see these in the stack.
break;
}
+ case kExprNodeTernaryValue: {
+ if (!cur_node->data.ter.got_colon) {
+ // Actually Vim throws E109 in more cases.
+ east_set_error(
+ &ast, pstate, _("E109: Missing ':' after '?': %.*s"),
+ cur_node->start);
+ }
+ break;
+ }
// TODO(ZyX-I): handle other values
}
}
diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h
index 01a51e4eda..cf0907850a 100644
--- a/src/nvim/viml/parser/expressions.h
+++ b/src/nvim/viml/parser/expressions.h
@@ -145,6 +145,7 @@ typedef enum {
kExprNodeMissing = 'X',
kExprNodeOpMissing = '_',
kExprNodeTernary = '?', ///< Ternary operator.
+ kExprNodeTernaryValue = 'C', ///< Ternary operator, colon.
kExprNodeRegister = '@', ///< Register.
kExprNodeSubscript = 's', ///< Subscript.
kExprNodeListLiteral = 'l', ///< List literal.
@@ -209,7 +210,10 @@ struct expr_ast_node {
/// Points to inside parser reader state.
const char *ident;
size_t ident_len; ///< Actual identifier length.
- } var;
+ } var; ///< For kExprNodePlainIdentifier.
+ struct {
+ bool got_colon; ///< True if colon was seen.
+ } ter; ///< For kExprNodeTernaryValue.
} data;
};
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index 1f734c3c2a..ea37d64662 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -66,6 +66,7 @@ make_enum_conv_tab(lib, {
'kExprNodeMissing',
'kExprNodeOpMissing',
'kExprNodeTernary',
+ 'kExprNodeTernaryValue',
'kExprNodeRegister',
'kExprNodeSubscript',
'kExprNodeListLiteral',
@@ -2489,6 +2490,652 @@ describe('Expressions parser', function()
hl('Dict', '}'),
})
end)
- -- FIXME: Test sequence of arrows inside and outside lambdas.
- -- FIXME: Test autoload character and scope in lambda arguments.
+ itp('works with ternary operator', function()
+ check_parsing('a ? b : c', 0, {
+ -- 012345678
+ ast = {
+ {
+ 'Ternary:0:1: ?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'TernaryValue:0:5: :',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:3: b',
+ 'PlainIdentifier(scope=0,ident=c):0:7: c',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Ternary', '?', 1),
+ hl('Identifier', 'b', 1),
+ hl('TernaryColon', ':', 1),
+ hl('Identifier', 'c', 1),
+ })
+ check_parsing('@a?@b?@c:@d:@e', 0, {
+ -- 01234567890123
+ -- 0 1
+ ast = {
+ {
+ 'Ternary:0:2:?',
+ children = {
+ 'Register(name=a):0:0:@a',
+ {
+ 'TernaryValue:0:11::',
+ children = {
+ {
+ 'Ternary:0:5:?',
+ children = {
+ 'Register(name=b):0:3:@b',
+ {
+ 'TernaryValue:0:8::',
+ children = {
+ 'Register(name=c):0:6:@c',
+ 'Register(name=d):0:9:@d',
+ },
+ },
+ },
+ },
+ 'Register(name=e):0:12:@e',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Register', '@a'),
+ hl('Ternary', '?'),
+ hl('Register', '@b'),
+ hl('Ternary', '?'),
+ hl('Register', '@c'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@d'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@e'),
+ })
+ check_parsing('@a?@b:@c?@d:@e', 0, {
+ -- 01234567890123
+ -- 0 1
+ ast = {
+ {
+ 'Ternary:0:2:?',
+ children = {
+ 'Register(name=a):0:0:@a',
+ {
+ 'TernaryValue:0:5::',
+ children = {
+ 'Register(name=b):0:3:@b',
+ {
+ 'Ternary:0:8:?',
+ children = {
+ 'Register(name=c):0:6:@c',
+ {
+ 'TernaryValue:0:11::',
+ children = {
+ 'Register(name=d):0:9:@d',
+ 'Register(name=e):0:12:@e',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Register', '@a'),
+ hl('Ternary', '?'),
+ hl('Register', '@b'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@c'),
+ hl('Ternary', '?'),
+ hl('Register', '@d'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@e'),
+ })
+ check_parsing('@a?@b?@c?@d:@e?@f:@g:@h?@i:@j:@k', 0, {
+ -- 01234567890123456789012345678901
+ -- 0 1 2 3
+ ast = {
+ {
+ 'Ternary:0:2:?',
+ children = {
+ 'Register(name=a):0:0:@a',
+ {
+ 'TernaryValue:0:29::',
+ children = {
+ {
+ 'Ternary:0:5:?',
+ children = {
+ 'Register(name=b):0:3:@b',
+ {
+ 'TernaryValue:0:20::',
+ children = {
+ {
+ 'Ternary:0:8:?',
+ children = {
+ 'Register(name=c):0:6:@c',
+ {
+ 'TernaryValue:0:11::',
+ children = {
+ 'Register(name=d):0:9:@d',
+ {
+ 'Ternary:0:14:?',
+ children = {
+ 'Register(name=e):0:12:@e',
+ {
+ 'TernaryValue:0:17::',
+ children = {
+ 'Register(name=f):0:15:@f',
+ 'Register(name=g):0:18:@g',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ 'Ternary:0:23:?',
+ children = {
+ 'Register(name=h):0:21:@h',
+ {
+ 'TernaryValue:0:26::',
+ children = {
+ 'Register(name=i):0:24:@i',
+ 'Register(name=j):0:27:@j',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ 'Register(name=k):0:30:@k',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Register', '@a'),
+ hl('Ternary', '?'),
+ hl('Register', '@b'),
+ hl('Ternary', '?'),
+ hl('Register', '@c'),
+ hl('Ternary', '?'),
+ hl('Register', '@d'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@e'),
+ hl('Ternary', '?'),
+ hl('Register', '@f'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@g'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@h'),
+ hl('Ternary', '?'),
+ hl('Register', '@i'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@j'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@k'),
+ })
+ check_parsing('?', 0, {
+ -- 0
+ ast = {
+ {
+ 'Ternary:0:0:?',
+ children = {
+ 'Missing:0:0:',
+ 'TernaryValue:0:0:?',
+ },
+ },
+ },
+ err = {
+ arg = '?',
+ msg = 'E15: Expected value, got question mark: %.*s',
+ },
+ }, {
+ hl('InvalidTernary', '?'),
+ })
+
+ check_parsing('?:', 0, {
+ -- 01
+ ast = {
+ {
+ 'Ternary:0:0:?',
+ children = {
+ 'Missing:0:0:',
+ {
+ 'TernaryValue:0:1::',
+ children = {
+ 'Missing:0:1:',
+ },
+ },
+ },
+ },
+ },
+ err = {
+ arg = '?:',
+ msg = 'E15: Expected value, got question mark: %.*s',
+ },
+ }, {
+ hl('InvalidTernary', '?'),
+ hl('InvalidTernaryColon', ':'),
+ })
+
+ check_parsing('?::', 0, {
+ -- 012
+ ast = {
+ {
+ 'Colon:0:2::',
+ children = {
+ {
+ 'Ternary:0:0:?',
+ children = {
+ 'Missing:0:0:',
+ {
+ 'TernaryValue:0:1::',
+ children = {
+ 'Missing:0:1:',
+ 'Missing:0:2:',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ err = {
+ arg = '?::',
+ msg = 'E15: Expected value, got question mark: %.*s',
+ },
+ }, {
+ hl('InvalidTernary', '?'),
+ hl('InvalidTernaryColon', ':'),
+ hl('InvalidColon', ':'),
+ })
+
+ check_parsing('a?b', 0, {
+ -- 012
+ ast = {
+ {
+ 'Ternary:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'TernaryValue:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:2:b',
+ },
+ },
+ },
+ },
+ },
+ err = {
+ arg = '?b',
+ msg = 'E109: Missing \':\' after \'?\': %.*s',
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Ternary', '?'),
+ hl('Identifier', 'b'),
+ })
+ check_parsing('a?b:', 0, {
+ -- 0123
+ ast = {
+ {
+ 'Ternary:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'TernaryValue:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=b,ident=):0:2:b:',
+ },
+ },
+ },
+ },
+ },
+ err = {
+ arg = '?b:',
+ msg = 'E109: Missing \':\' after \'?\': %.*s',
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Ternary', '?'),
+ hl('IdentifierScope', 'b'),
+ hl('IdentifierScopeDelimiter', ':'),
+ })
+
+ check_parsing('a?b::c', 0, {
+ -- 012345
+ ast = {
+ {
+ 'Ternary:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'TernaryValue:0:4::',
+ children = {
+ 'PlainIdentifier(scope=b,ident=):0:2:b:',
+ 'PlainIdentifier(scope=0,ident=c):0:5:c',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Ternary', '?'),
+ hl('IdentifierScope', 'b'),
+ hl('IdentifierScopeDelimiter', ':'),
+ hl('TernaryColon', ':'),
+ hl('Identifier', 'c'),
+ })
+
+ check_parsing('a?b :', 0, {
+ -- 01234
+ ast = {
+ {
+ 'Ternary:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'TernaryValue:0:3: :',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:2:b',
+ },
+ },
+ },
+ },
+ },
+ err = {
+ arg = '',
+ msg = 'E15: Expected value, got EOC: %.*s',
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Ternary', '?'),
+ hl('Identifier', 'b'),
+ hl('TernaryColon', ':', 1),
+ })
+
+ check_parsing('(@a?@b:@c)?@d:@e', 0, {
+ -- 0123456789012345
+ -- 0 1
+ ast = {
+ {
+ 'Ternary:0:10:?',
+ children = {
+ {
+ 'Nested:0:0:(',
+ children = {
+ {
+ 'Ternary:0:3:?',
+ children = {
+ 'Register(name=a):0:1:@a',
+ {
+ 'TernaryValue:0:6::',
+ children = {
+ 'Register(name=b):0:4:@b',
+ 'Register(name=c):0:7:@c',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ 'TernaryValue:0:13::',
+ children = {
+ 'Register(name=d):0:11:@d',
+ 'Register(name=e):0:14:@e',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('NestingParenthesis', '('),
+ hl('Register', '@a'),
+ hl('Ternary', '?'),
+ hl('Register', '@b'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@c'),
+ hl('NestingParenthesis', ')'),
+ hl('Ternary', '?'),
+ hl('Register', '@d'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@e'),
+ })
+
+ check_parsing('(@a?@b:@c)?(@d?@e:@f):(@g?@h:@i)', 0, {
+ -- 01234567890123456789012345678901
+ -- 0 1 2 3
+ ast = {
+ {
+ 'Ternary:0:10:?',
+ children = {
+ {
+ 'Nested:0:0:(',
+ children = {
+ {
+ 'Ternary:0:3:?',
+ children = {
+ 'Register(name=a):0:1:@a',
+ {
+ 'TernaryValue:0:6::',
+ children = {
+ 'Register(name=b):0:4:@b',
+ 'Register(name=c):0:7:@c',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ 'TernaryValue:0:21::',
+ children = {
+ {
+ 'Nested:0:11:(',
+ children = {
+ {
+ 'Ternary:0:14:?',
+ children = {
+ 'Register(name=d):0:12:@d',
+ {
+ 'TernaryValue:0:17::',
+ children = {
+ 'Register(name=e):0:15:@e',
+ 'Register(name=f):0:18:@f',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ 'Nested:0:22:(',
+ children = {
+ {
+ 'Ternary:0:25:?',
+ children = {
+ 'Register(name=g):0:23:@g',
+ {
+ 'TernaryValue:0:28::',
+ children = {
+ 'Register(name=h):0:26:@h',
+ 'Register(name=i):0:29:@i',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('NestingParenthesis', '('),
+ hl('Register', '@a'),
+ hl('Ternary', '?'),
+ hl('Register', '@b'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@c'),
+ hl('NestingParenthesis', ')'),
+ hl('Ternary', '?'),
+ hl('NestingParenthesis', '('),
+ hl('Register', '@d'),
+ hl('Ternary', '?'),
+ hl('Register', '@e'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@f'),
+ hl('NestingParenthesis', ')'),
+ hl('TernaryColon', ':'),
+ hl('NestingParenthesis', '('),
+ hl('Register', '@g'),
+ hl('Ternary', '?'),
+ hl('Register', '@h'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@i'),
+ hl('NestingParenthesis', ')'),
+ })
+
+ check_parsing('(@a?@b:@c)?@d?@e:@f:@g?@h:@i', 0, {
+ -- 0123456789012345678901234567
+ -- 0 1 2
+ ast = {
+ {
+ 'Ternary:0:10:?',
+ children = {
+ {
+ 'Nested:0:0:(',
+ children = {
+ {
+ 'Ternary:0:3:?',
+ children = {
+ 'Register(name=a):0:1:@a',
+ {
+ 'TernaryValue:0:6::',
+ children = {
+ 'Register(name=b):0:4:@b',
+ 'Register(name=c):0:7:@c',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ 'TernaryValue:0:19::',
+ children = {
+ {
+ 'Ternary:0:13:?',
+ children = {
+ 'Register(name=d):0:11:@d',
+ {
+ 'TernaryValue:0:16::',
+ children = {
+ 'Register(name=e):0:14:@e',
+ 'Register(name=f):0:17:@f',
+ },
+ },
+ },
+ },
+ {
+ 'Ternary:0:22:?',
+ children = {
+ 'Register(name=g):0:20:@g',
+ {
+ 'TernaryValue:0:25::',
+ children = {
+ 'Register(name=h):0:23:@h',
+ 'Register(name=i):0:26:@i',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('NestingParenthesis', '('),
+ hl('Register', '@a'),
+ hl('Ternary', '?'),
+ hl('Register', '@b'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@c'),
+ hl('NestingParenthesis', ')'),
+ hl('Ternary', '?'),
+ hl('Register', '@d'),
+ hl('Ternary', '?'),
+ hl('Register', '@e'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@f'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@g'),
+ hl('Ternary', '?'),
+ hl('Register', '@h'),
+ hl('TernaryColon', ':'),
+ hl('Register', '@i'),
+ })
+ check_parsing('a?b{cdef}g:h', 0, {
+ -- 012345678901
+ -- 0 1
+ ast = {
+ {
+ 'Ternary:0:1:?',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'TernaryValue:0:10::',
+ children = {
+ {
+ 'ComplexIdentifier:0:3:',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:2:b',
+ {
+ 'ComplexIdentifier:0:9:',
+ children = {
+ {
+ 'CurlyBracesIdentifier(--i):0:3:{',
+ children = {
+ 'PlainIdentifier(scope=0,ident=cdef):0:4:cdef',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=g):0:9:g',
+ },
+ },
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=h):0:11:h',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Ternary', '?'),
+ hl('Identifier', 'b'),
+ hl('Curly', '{'),
+ hl('Identifier', 'cdef'),
+ hl('Curly', '}'),
+ hl('Identifier', 'g'),
+ hl('TernaryColon', ':'),
+ hl('Identifier', 'h'),
+ })
+ end)
end)