aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-10-08 02:17:05 +0300
committerZyX <kp-pav@yandex.ru>2017-10-15 19:13:51 +0300
commitbd3a4166b25a64dbe406be09b3140955cf694477 (patch)
tree746adca70dd26c1b089747da8e479d4617946b22
parente45e519495832e3d1d0fde1e32723d4140c5fc65 (diff)
downloadrneovim-bd3a4166b25a64dbe406be09b3140955cf694477.tar.gz
rneovim-bd3a4166b25a64dbe406be09b3140955cf694477.tar.bz2
rneovim-bd3a4166b25a64dbe406be09b3140955cf694477.zip
viml/parser/expressions: Add support for subscript and list literals
-rw-r--r--src/nvim/viml/parser/expressions.c164
-rw-r--r--test/unit/viml/expressions/parser_spec.lua533
2 files changed, 675 insertions, 22 deletions
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index fffae8833d..0613cc66d5 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -905,6 +905,10 @@ static inline void viml_pexpr_debug_print_token(
// NVimDict -> Delimiter
// NVimCurly -> Delimiter
//
+// NVimList -> Delimiter
+// NVimSubscript -> Delimiter
+// NVimSubscriptColon -> NVimSubscript
+//
// NVimIdentifier -> Identifier
// NVimIdentifierScope -> NVimIdentifier
// NVimIdentifierScopeDelimiter -> NVimIdentifier
@@ -945,6 +949,9 @@ static inline void viml_pexpr_debug_print_token(
// NVimInvalidNumber -> NVimInvalidValue
// NVimInvalidFloat -> NVimInvalidValue
// NVimInvalidIdentifierKey -> NVimInvalidIdentifier
+// NVimInvalidList -> NVimInvalidDelimiter
+// NVimInvalidSubscript -> NVimInvalidDelimiter
+// NVimInvalidSubscriptColon -> NVimInvalidSubscript
/// Allocate a new node and set some of the values
///
@@ -965,9 +972,10 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
[kExprNodeOpMissing] = kEOpLvlMultiplication,
[kExprNodeNested] = kEOpLvlParens,
- // Note: it is kEOpLvlSubscript for “binary operator” itself, but
+ // Note: below nodes are kEOpLvlSubscript for “binary operator” itself, but
// kEOpLvlParens when it comes to inside the parenthesis.
[kExprNodeCall] = kEOpLvlParens,
+ [kExprNodeSubscript] = kEOpLvlParens,
[kExprNodeUnknownFigure] = kEOpLvlParens,
[kExprNodeLambda] = kEOpLvlParens,
@@ -992,7 +1000,6 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
[kExprNodeUnaryPlus] = kEOpLvlUnary,
[kExprNodeConcatOrSubscript] = kEOpLvlSubscript,
- [kExprNodeSubscript] = kEOpLvlSubscript,
[kExprNodeCurlyBracesIdentifier] = kEOpLvlComplexIdentifier,
@@ -1010,6 +1017,7 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
[kExprNodeNested] = kEOpAssNo,
[kExprNodeCall] = kEOpAssNo,
+ [kExprNodeSubscript] = kEOpAssNo,
[kExprNodeUnknownFigure] = kEOpAssLeft,
[kExprNodeLambda] = kEOpAssNo,
@@ -1042,7 +1050,6 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
[kExprNodeUnaryPlus] = kEOpAssNo,
[kExprNodeConcatOrSubscript] = kEOpAssLeft,
- [kExprNodeSubscript] = kEOpAssLeft,
[kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
@@ -1105,12 +1112,14 @@ static bool viml_pexpr_handle_bop(const ParserState *const pstate,
ExprOpLvl top_node_lvl;
ExprOpAssociativity top_node_ass;
assert(kv_size(*ast_stack));
- const ExprOpLvl bop_node_lvl = (bop_node->type == kExprNodeCall
+ const ExprOpLvl bop_node_lvl = ((bop_node->type == kExprNodeCall
+ || bop_node->type == kExprNodeSubscript)
? kEOpLvlSubscript
: node_lvl(*bop_node));
#ifndef NDEBUG
const ExprOpAssociativity bop_node_ass = (
- bop_node->type == kExprNodeCall
+ (bop_node->type == kExprNodeCall
+ || bop_node->type == kExprNodeSubscript)
? kEOpAssLeft
: node_ass(*bop_node));
#endif
@@ -1214,8 +1223,8 @@ static inline ParserPosition shifted_pos(const ParserPosition pos,
/// @param cur_token Token to set position from.
#define POS_FROM_TOKEN(cur_node, cur_token) \
do { \
- cur_node->start = cur_token.start; \
- cur_node->len = cur_token.len; \
+ (cur_node)->start = cur_token.start; \
+ (cur_node)->len = cur_token.len; \
} while (0)
/// Allocate new node and set its position from the current token
@@ -1226,11 +1235,11 @@ static inline ParserPosition shifted_pos(const ParserPosition pos,
/// @param typ Node type.
#define NEW_NODE_WITH_CUR_POS(cur_node, typ) \
do { \
- cur_node = NEW_NODE(typ); \
- POS_FROM_TOKEN(cur_node, cur_token); \
+ (cur_node) = NEW_NODE(typ); \
+ POS_FROM_TOKEN((cur_node), cur_token); \
if (prev_token.type == kExprLexSpacing) { \
- cur_node->start = prev_token.start; \
- cur_node->len += prev_token.len; \
+ (cur_node)->start = prev_token.start; \
+ (cur_node)->len += prev_token.len; \
} \
} while (0)
@@ -1280,9 +1289,8 @@ static inline ParserPosition shifted_pos(const ParserPosition pos,
do { \
if (want_node == kENodeValue) { \
ERROR_FROM_TOKEN_AND_MSG(cur_token, (msg)); \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeMissing); \
- cur_node->len = 0; \
- *top_node_p = cur_node; \
+ NEW_NODE_WITH_CUR_POS((*top_node_p), kExprNodeMissing); \
+ (*top_node_p)->len = 0; \
want_node = kENodeOperator; \
} \
} while (0)
@@ -1658,13 +1666,14 @@ viml_pexpr_parse_invalid_comma:
HL_CUR_TOKEN(Comma);
break;
}
+#define EXP_VAL_COLON "E15: Expected value, got colon: %.*s"
case kExprLexColon: {
- ADD_VALUE_IF_MISSING(_("E15: Expected value, got colon: %.*s"));
if (kv_size(ast_stack) < 2) {
goto viml_pexpr_parse_invalid_colon;
}
bool is_ternary = false;
bool can_be_ternary = true;
+ bool is_subscript = false;
for (size_t i = 1; i < kv_size(ast_stack); i++) {
ExprASTNode *const *const eastnode_p =
(ExprASTNode *const *)kv_Z(ast_stack, i);
@@ -1683,6 +1692,7 @@ viml_pexpr_parse_invalid_comma:
}
is_ternary = true;
(*eastnode_p)->data.ter.got_colon = true;
+ ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
assert((*eastnode_p)->children != NULL);
assert((*eastnode_p)->children->next == NULL);
kvi_push(ast_stack, &(*eastnode_p)->children->next);
@@ -1690,14 +1700,18 @@ viml_pexpr_parse_invalid_comma:
} else if (eastnode_type == kExprNodeUnknownFigure) {
SELECT_FIGURE_BRACE_TYPE(*eastnode_p, DictLiteral, Dict);
break;
- } else if (eastnode_type == kExprNodeDictLiteral
- || eastnode_type == kExprNodeSubscript) {
+ } else if (eastnode_type == kExprNodeDictLiteral) {
+ break;
+ } else if (eastnode_type == kExprNodeSubscript) {
+ is_subscript = true;
+ can_be_ternary = false;
+ assert(!is_ternary);
break;
} else if (eastnode_type == kExprNodeColon) {
goto viml_pexpr_parse_invalid_colon;
} else if (eastnode_lvl >= kEOpLvlTernaryValue) {
// Do nothing
- } else if (eastnode_lvl > kEOpLvlComma) {
+ } else if (eastnode_lvl >= kEOpLvlComma) {
can_be_ternary = false;
} else {
viml_pexpr_parse_invalid_colon:
@@ -1711,16 +1725,122 @@ viml_pexpr_parse_invalid_colon:
goto viml_pexpr_parse_invalid_colon;
}
}
- if (is_ternary) {
- HL_CUR_TOKEN(TernaryColon);
- } else {
+ if (is_subscript) {
+ assert(kv_size(ast_stack) > 1);
+ // Colon immediately following subscript start: it is empty subscript
+ // part like a[:2].
+ if (want_node == kENodeValue
+ && (*kv_Z(ast_stack, 1))->type == kExprNodeSubscript) {
+ NEW_NODE_WITH_CUR_POS(*top_node_p, kExprNodeMissing);
+ (*top_node_p)->len = 0;
+ want_node = kENodeOperator;
+ } else {
+ ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
+ }
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(Colon);
+ HL_CUR_TOKEN(SubscriptColon);
+ } else {
+ ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
+ if (is_ternary) {
+ HL_CUR_TOKEN(TernaryColon);
+ } else {
+ ADD_OP_NODE(cur_node);
+ HL_CUR_TOKEN(Colon);
+ }
}
want_node = kENodeValue;
break;
}
+#undef EXP_VAL_COLON
+ case kExprLexBracket: {
+ if (cur_token.data.brc.closing) {
+ ExprASTNode **new_top_node_p = NULL;
+ // Always drop the topmost value:
+ //
+ // 1. When want_node != kENodeValue topmost item on stack is
+ // a *finished* left operand, which may as well be "{@a}" which
+ // needs not be finished again.
+ // 2. Otherwise it is pointing to NULL what nobody wants.
+ kv_drop(ast_stack, 1);
+ if (!kv_size(ast_stack)) {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral);
+ cur_node->len = 0;
+ if (want_node != kENodeValue) {
+ cur_node->children = *top_node_p;
+ }
+ *top_node_p = cur_node;
+ goto viml_pexpr_parse_bracket_closing_error;
+ }
+ if (want_node == kENodeValue) {
+ // It is OK to want value if
+ //
+ // 1. It is empty list literal, in which case top node will be
+ // ListLiteral.
+ // 2. It is list literal with trailing comma, in which case top node
+ // will be that comma.
+ // 3. It is subscript with colon, but without one of the values:
+ // e.g. "a[:]", "a[1:]", top node will be colon in this case.
+ if ((*kv_last(ast_stack))->type != kExprNodeListLiteral
+ && (*kv_last(ast_stack))->type != kExprNodeComma
+ && (*kv_last(ast_stack))->type != kExprNodeColon) {
+ ERROR_FROM_TOKEN_AND_MSG(
+ cur_token,
+ _("E15: Expected value, got closing bracket: %.*s"));
+ }
+ } else {
+ if (!kv_size(ast_stack)) {
+ new_top_node_p = top_node_p;
+ goto viml_pexpr_parse_bracket_closing_error;
+ }
+ }
+ do {
+ new_top_node_p = kv_pop(ast_stack);
+ } while (kv_size(ast_stack)
+ && (new_top_node_p == NULL
+ || ((*new_top_node_p)->type != kExprNodeListLiteral
+ && (*new_top_node_p)->type != kExprNodeSubscript)));
+ ExprASTNode *new_top_node = *new_top_node_p;
+ switch (new_top_node->type) {
+ case kExprNodeListLiteral: {
+ HL_CUR_TOKEN(List);
+ break;
+ }
+ case kExprNodeSubscript: {
+ HL_CUR_TOKEN(Subscript);
+ break;
+ }
+ default: {
+viml_pexpr_parse_bracket_closing_error:
+ assert(!kv_size(ast_stack));
+ ERROR_FROM_TOKEN_AND_MSG(
+ cur_token, _("E15: Unexpected closing figure brace: %.*s"));
+ HL_CUR_TOKEN(List);
+ break;
+ }
+ }
+ kvi_push(ast_stack, new_top_node_p);
+ want_node = kENodeOperator;
+ } else {
+ if (want_node == kENodeValue) {
+ // Value means list literal.
+ HL_CUR_TOKEN(List);
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral);
+ *top_node_p = cur_node;
+ kvi_push(ast_stack, &cur_node->children);
+ want_node = kENodeValue;
+ } else {
+ if (prev_token.type == kExprLexSpacing) {
+ OP_MISSING;
+ }
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeSubscript);
+ ADD_OP_NODE(cur_node);
+ HL_CUR_TOKEN(Subscript);
+ }
+ }
+ break;
+ }
case kExprLexFigureBrace: {
if (cur_token.data.brc.closing) {
ExprASTNode **new_top_node_p = NULL;
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index 46e3328184..41261cf7c9 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -91,6 +91,8 @@ make_enum_conv_tab(lib, {
'kExprNodeConcatOrSubscript',
'kExprNodeInteger',
'kExprNodeFloat',
+ 'kExprNodeSingleQuotedString',
+ 'kExprNodeDoubleQuotedString',
}, 'kExprNode', function(ret) east_node_type_tab = ret end)
local function conv_east_node_type(typ)
@@ -204,6 +206,10 @@ describe('Expressions parser', function()
local function check_parsing(str, flags, exp_ast, exp_highlighting_fs)
flags = flags or 0
+ if os.getenv('NVIM_TEST_PARSER_SPEC_PRINT_TEST_CASE') == '1' then
+ print(str, flags)
+ end
+
local pstate = new_pstate({str})
local east = lib.viml_pexpr_parse(pstate, flags)
local ast = east2lua(pstate, east)
@@ -4016,4 +4022,531 @@ describe('Expressions parser', function()
hl('Identifier', 'b'),
})
end)
+ itp('works with bracket subscripts', function()
+ check_parsing(':', 0, {
+ -- 0
+ ast = {
+ {
+ 'Colon:0:0::',
+ children = {
+ 'Missing:0:0:',
+ },
+ },
+ },
+ err = {
+ arg = ':',
+ msg = 'E15: Colon outside of dictionary or ternary operator: %.*s',
+ },
+ }, {
+ hl('InvalidColon', ':'),
+ })
+ check_parsing('a[]', 0, {
+ -- 012
+ ast = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ },
+ },
+ },
+ err = {
+ arg = ']',
+ msg = 'E15: Expected value, got closing bracket: %.*s',
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('InvalidSubscript', ']'),
+ })
+ check_parsing('a[b:]', 0, {
+ -- 01234
+ ast = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ 'PlainIdentifier(scope=b,ident=):0:2:b:',
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('IdentifierScope', 'b'),
+ hl('IdentifierScopeDelimiter', ':'),
+ hl('Subscript', ']'),
+ })
+
+ check_parsing('a[b:c]', 0, {
+ -- 012345
+ ast = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ 'PlainIdentifier(scope=b,ident=c):0:2:b:c',
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('IdentifierScope', 'b'),
+ hl('IdentifierScopeDelimiter', ':'),
+ hl('Identifier', 'c'),
+ hl('Subscript', ']'),
+ })
+ check_parsing('a[b : c]', 0, {
+ -- 01234567
+ ast = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'Colon:0:3: :',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:2:b',
+ 'PlainIdentifier(scope=0,ident=c):0:5: c',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('Identifier', 'b'),
+ hl('SubscriptColon', ':', 1),
+ hl('Identifier', 'c', 1),
+ hl('Subscript', ']'),
+ })
+
+ check_parsing('a[: b]', 0, {
+ -- 012345
+ ast = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'Colon:0:2::',
+ children = {
+ 'Missing:0:2:',
+ 'PlainIdentifier(scope=0,ident=b):0:3: b',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('SubscriptColon', ':'),
+ hl('Identifier', 'b', 1),
+ hl('Subscript', ']'),
+ })
+
+ check_parsing('a[b :]', 0, {
+ -- 012345
+ ast = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ {
+ 'Colon:0:3: :',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:2:b',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('Identifier', 'b'),
+ hl('SubscriptColon', ':', 1),
+ hl('Subscript', ']'),
+ })
+ check_parsing('a[b][c][d](e)(f)(g)', 0, {
+ -- 0123456789012345678
+ -- 0 1
+ ast = {
+ {
+ 'Call:0:16:(',
+ children = {
+ {
+ 'Call:0:13:(',
+ children = {
+ {
+ 'Call:0:10:(',
+ children = {
+ {
+ 'Subscript:0:7:[',
+ children = {
+ {
+ 'Subscript:0:4:[',
+ children = {
+ {
+ 'Subscript:0:1:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ 'PlainIdentifier(scope=0,ident=b):0:2:b',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=c):0:5:c',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=d):0:8:d',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=e):0:11:e',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=f):0:14:f',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=g):0:17:g',
+ },
+ },
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('Subscript', '['),
+ hl('Identifier', 'b'),
+ hl('Subscript', ']'),
+ hl('Subscript', '['),
+ hl('Identifier', 'c'),
+ hl('Subscript', ']'),
+ hl('Subscript', '['),
+ hl('Identifier', 'd'),
+ hl('Subscript', ']'),
+ hl('CallingParenthesis', '('),
+ hl('Identifier', 'e'),
+ hl('CallingParenthesis', ')'),
+ hl('CallingParenthesis', '('),
+ hl('Identifier', 'f'),
+ hl('CallingParenthesis', ')'),
+ hl('CallingParenthesis', '('),
+ hl('Identifier', 'g'),
+ hl('CallingParenthesis', ')'),
+ })
+ check_parsing('{a}{b}{c}[d][e][f]', 0, {
+ -- 012345678901234567
+ -- 0 1
+ ast = {
+ {
+ 'Subscript:0:15:[',
+ children = {
+ {
+ 'Subscript:0:12:[',
+ children = {
+ {
+ 'Subscript:0:9:[',
+ children = {
+ {
+ 'ComplexIdentifier:0:3:',
+ children = {
+ {
+ 'CurlyBracesIdentifier(-di):0:0:{',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:1:a',
+ },
+ },
+ {
+ 'ComplexIdentifier:0:6:',
+ children = {
+ {
+ 'CurlyBracesIdentifier(--i):0:3:{',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:4:b',
+ },
+ },
+ {
+ 'CurlyBracesIdentifier(--i):0:6:{',
+ children = {
+ 'PlainIdentifier(scope=0,ident=c):0:7:c',
+ },
+ },
+ },
+ },
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=d):0:10:d',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=e):0:13:e',
+ },
+ },
+ 'PlainIdentifier(scope=0,ident=f):0:16:f',
+ },
+ },
+ },
+ }, {
+ hl('Curly', '{'),
+ hl('Identifier', 'a'),
+ hl('Curly', '}'),
+ hl('Curly', '{'),
+ hl('Identifier', 'b'),
+ hl('Curly', '}'),
+ hl('Curly', '{'),
+ hl('Identifier', 'c'),
+ hl('Curly', '}'),
+ hl('Subscript', '['),
+ hl('Identifier', 'd'),
+ hl('Subscript', ']'),
+ hl('Subscript', '['),
+ hl('Identifier', 'e'),
+ hl('Subscript', ']'),
+ hl('Subscript', '['),
+ hl('Identifier', 'f'),
+ hl('Subscript', ']'),
+ })
+ end)
+ itp('supports list literals', function()
+ check_parsing('[]', 0, {
+ -- 01
+ ast = {
+ 'ListLiteral:0:0:[',
+ },
+ }, {
+ hl('List', '['),
+ hl('List', ']'),
+ })
+
+ check_parsing('[a]', 0, {
+ -- 012
+ ast = {
+ {
+ 'ListLiteral:0:0:[',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:1:a',
+ },
+ },
+ },
+ }, {
+ hl('List', '['),
+ hl('Identifier', 'a'),
+ hl('List', ']'),
+ })
+
+ check_parsing('[a, b]', 0, {
+ -- 012345
+ ast = {
+ {
+ 'ListLiteral:0:0:[',
+ children = {
+ {
+ 'Comma:0:2:,',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:1:a',
+ 'PlainIdentifier(scope=0,ident=b):0:3: b',
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('List', '['),
+ hl('Identifier', 'a'),
+ hl('Comma', ','),
+ hl('Identifier', 'b', 1),
+ hl('List', ']'),
+ })
+
+ check_parsing('[a, b, c]', 0, {
+ -- 012345678
+ ast = {
+ {
+ 'ListLiteral:0:0:[',
+ children = {
+ {
+ 'Comma:0:2:,',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:1:a',
+ {
+ 'Comma:0:5:,',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:3: b',
+ 'PlainIdentifier(scope=0,ident=c):0:6: c',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('List', '['),
+ hl('Identifier', 'a'),
+ hl('Comma', ','),
+ hl('Identifier', 'b', 1),
+ hl('Comma', ','),
+ hl('Identifier', 'c', 1),
+ hl('List', ']'),
+ })
+
+ check_parsing('[a, b, c, ]', 0, {
+ -- 01234567890
+ -- 0 1
+ ast = {
+ {
+ 'ListLiteral:0:0:[',
+ children = {
+ {
+ 'Comma:0:2:,',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:1:a',
+ {
+ 'Comma:0:5:,',
+ children = {
+ 'PlainIdentifier(scope=0,ident=b):0:3: b',
+ {
+ 'Comma:0:8:,',
+ children = {
+ 'PlainIdentifier(scope=0,ident=c):0:6: c',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }, {
+ hl('List', '['),
+ hl('Identifier', 'a'),
+ hl('Comma', ','),
+ hl('Identifier', 'b', 1),
+ hl('Comma', ','),
+ hl('Identifier', 'c', 1),
+ hl('Comma', ','),
+ hl('List', ']', 1),
+ })
+
+ check_parsing('[a : b, c : d]', 0, {
+ -- 01234567890123
+ -- 0 1
+ ast = {
+ {
+ 'ListLiteral:0:0:[',
+ children = {
+ {
+ 'Comma:0:6:,',
+ children = {
+ {
+ 'Colon:0:2: :',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:1:a',
+ 'PlainIdentifier(scope=0,ident=b):0:4: b',
+ },
+ },
+ {
+ 'Colon:0:9: :',
+ children = {
+ 'PlainIdentifier(scope=0,ident=c):0:7: c',
+ 'PlainIdentifier(scope=0,ident=d):0:11: d',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ err = {
+ arg = ': b, c : d]',
+ msg = 'E15: Colon outside of dictionary or ternary operator: %.*s',
+ },
+ }, {
+ hl('List', '['),
+ hl('Identifier', 'a'),
+ hl('InvalidColon', ':', 1),
+ hl('Identifier', 'b', 1),
+ hl('Comma', ','),
+ hl('Identifier', 'c', 1),
+ hl('InvalidColon', ':', 1),
+ hl('Identifier', 'd', 1),
+ hl('List', ']'),
+ })
+
+ check_parsing(']', 0, {
+ -- 0
+ ast = {
+ 'ListLiteral:0:0:',
+ },
+ err = {
+ arg = ']',
+ msg = 'E15: Unexpected closing figure brace: %.*s',
+ },
+ }, {
+ hl('InvalidList', ']'),
+ })
+
+ check_parsing('a]', 0, {
+ -- 01
+ ast = {
+ {
+ 'ListLiteral:0:1:',
+ children = {
+ 'PlainIdentifier(scope=0,ident=a):0:0:a',
+ },
+ },
+ },
+ err = {
+ arg = ']',
+ msg = 'E15: Unexpected closing figure brace: %.*s',
+ },
+ }, {
+ hl('Identifier', 'a'),
+ hl('InvalidList', ']'),
+ })
+
+ check_parsing('[] []', 0, {
+ -- 01234
+ ast = {
+ {
+ 'OpMissing:0:2:',
+ children = {
+ 'ListLiteral:0:0:[',
+ 'ListLiteral:0:2: [',
+ },
+ },
+ },
+ err = {
+ arg = '[]',
+ msg = 'E15: Missing operator: %.*s',
+ },
+ }, {
+ hl('List', '['),
+ hl('List', ']'),
+ hl('InvalidSpacing', ' '),
+ hl('List', '['),
+ hl('List', ']'),
+ })
+
+ check_parsing('[][]', 0, {
+ -- 0123
+ ast = {
+ {
+ 'Subscript:0:2:[',
+ children = {
+ 'ListLiteral:0:0:[',
+ },
+ },
+ },
+ err = {
+ arg = ']',
+ msg = 'E15: Expected value, got closing bracket: %.*s',
+ },
+ }, {
+ hl('List', '['),
+ hl('List', ']'),
+ hl('Subscript', '['),
+ hl('InvalidSubscript', ']'),
+ })
+ end)
end)