mirror of
https://github.com/neovim/neovim.git
synced 2025-09-15 07:48:18 +00:00
viml/parser/expressions: Add support for subscript and list literals
This commit is contained in:
@@ -905,6 +905,10 @@ static inline void viml_pexpr_debug_print_token(
|
|||||||
// NVimDict -> Delimiter
|
// NVimDict -> Delimiter
|
||||||
// NVimCurly -> Delimiter
|
// NVimCurly -> Delimiter
|
||||||
//
|
//
|
||||||
|
// NVimList -> Delimiter
|
||||||
|
// NVimSubscript -> Delimiter
|
||||||
|
// NVimSubscriptColon -> NVimSubscript
|
||||||
|
//
|
||||||
// NVimIdentifier -> Identifier
|
// NVimIdentifier -> Identifier
|
||||||
// NVimIdentifierScope -> NVimIdentifier
|
// NVimIdentifierScope -> NVimIdentifier
|
||||||
// NVimIdentifierScopeDelimiter -> NVimIdentifier
|
// NVimIdentifierScopeDelimiter -> NVimIdentifier
|
||||||
@@ -945,6 +949,9 @@ static inline void viml_pexpr_debug_print_token(
|
|||||||
// NVimInvalidNumber -> NVimInvalidValue
|
// NVimInvalidNumber -> NVimInvalidValue
|
||||||
// NVimInvalidFloat -> NVimInvalidValue
|
// NVimInvalidFloat -> NVimInvalidValue
|
||||||
// NVimInvalidIdentifierKey -> NVimInvalidIdentifier
|
// NVimInvalidIdentifierKey -> NVimInvalidIdentifier
|
||||||
|
// NVimInvalidList -> NVimInvalidDelimiter
|
||||||
|
// NVimInvalidSubscript -> NVimInvalidDelimiter
|
||||||
|
// NVimInvalidSubscriptColon -> NVimInvalidSubscript
|
||||||
|
|
||||||
/// Allocate a new node and set some of the values
|
/// Allocate a new node and set some of the values
|
||||||
///
|
///
|
||||||
@@ -965,9 +972,10 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
|
|||||||
[kExprNodeOpMissing] = kEOpLvlMultiplication,
|
[kExprNodeOpMissing] = kEOpLvlMultiplication,
|
||||||
|
|
||||||
[kExprNodeNested] = kEOpLvlParens,
|
[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.
|
// kEOpLvlParens when it comes to inside the parenthesis.
|
||||||
[kExprNodeCall] = kEOpLvlParens,
|
[kExprNodeCall] = kEOpLvlParens,
|
||||||
|
[kExprNodeSubscript] = kEOpLvlParens,
|
||||||
|
|
||||||
[kExprNodeUnknownFigure] = kEOpLvlParens,
|
[kExprNodeUnknownFigure] = kEOpLvlParens,
|
||||||
[kExprNodeLambda] = kEOpLvlParens,
|
[kExprNodeLambda] = kEOpLvlParens,
|
||||||
@@ -992,7 +1000,6 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
|
|||||||
[kExprNodeUnaryPlus] = kEOpLvlUnary,
|
[kExprNodeUnaryPlus] = kEOpLvlUnary,
|
||||||
|
|
||||||
[kExprNodeConcatOrSubscript] = kEOpLvlSubscript,
|
[kExprNodeConcatOrSubscript] = kEOpLvlSubscript,
|
||||||
[kExprNodeSubscript] = kEOpLvlSubscript,
|
|
||||||
|
|
||||||
[kExprNodeCurlyBracesIdentifier] = kEOpLvlComplexIdentifier,
|
[kExprNodeCurlyBracesIdentifier] = kEOpLvlComplexIdentifier,
|
||||||
|
|
||||||
@@ -1010,6 +1017,7 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
|
|||||||
|
|
||||||
[kExprNodeNested] = kEOpAssNo,
|
[kExprNodeNested] = kEOpAssNo,
|
||||||
[kExprNodeCall] = kEOpAssNo,
|
[kExprNodeCall] = kEOpAssNo,
|
||||||
|
[kExprNodeSubscript] = kEOpAssNo,
|
||||||
|
|
||||||
[kExprNodeUnknownFigure] = kEOpAssLeft,
|
[kExprNodeUnknownFigure] = kEOpAssLeft,
|
||||||
[kExprNodeLambda] = kEOpAssNo,
|
[kExprNodeLambda] = kEOpAssNo,
|
||||||
@@ -1042,7 +1050,6 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
|
|||||||
[kExprNodeUnaryPlus] = kEOpAssNo,
|
[kExprNodeUnaryPlus] = kEOpAssNo,
|
||||||
|
|
||||||
[kExprNodeConcatOrSubscript] = kEOpAssLeft,
|
[kExprNodeConcatOrSubscript] = kEOpAssLeft,
|
||||||
[kExprNodeSubscript] = kEOpAssLeft,
|
|
||||||
|
|
||||||
[kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
|
[kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
|
||||||
|
|
||||||
@@ -1105,12 +1112,14 @@ static bool viml_pexpr_handle_bop(const ParserState *const pstate,
|
|||||||
ExprOpLvl top_node_lvl;
|
ExprOpLvl top_node_lvl;
|
||||||
ExprOpAssociativity top_node_ass;
|
ExprOpAssociativity top_node_ass;
|
||||||
assert(kv_size(*ast_stack));
|
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
|
? kEOpLvlSubscript
|
||||||
: node_lvl(*bop_node));
|
: node_lvl(*bop_node));
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const ExprOpAssociativity bop_node_ass = (
|
const ExprOpAssociativity bop_node_ass = (
|
||||||
bop_node->type == kExprNodeCall
|
(bop_node->type == kExprNodeCall
|
||||||
|
|| bop_node->type == kExprNodeSubscript)
|
||||||
? kEOpAssLeft
|
? kEOpAssLeft
|
||||||
: node_ass(*bop_node));
|
: node_ass(*bop_node));
|
||||||
#endif
|
#endif
|
||||||
@@ -1214,8 +1223,8 @@ static inline ParserPosition shifted_pos(const ParserPosition pos,
|
|||||||
/// @param cur_token Token to set position from.
|
/// @param cur_token Token to set position from.
|
||||||
#define POS_FROM_TOKEN(cur_node, cur_token) \
|
#define POS_FROM_TOKEN(cur_node, cur_token) \
|
||||||
do { \
|
do { \
|
||||||
cur_node->start = cur_token.start; \
|
(cur_node)->start = cur_token.start; \
|
||||||
cur_node->len = cur_token.len; \
|
(cur_node)->len = cur_token.len; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/// Allocate new node and set its position from the current token
|
/// 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.
|
/// @param typ Node type.
|
||||||
#define NEW_NODE_WITH_CUR_POS(cur_node, typ) \
|
#define NEW_NODE_WITH_CUR_POS(cur_node, typ) \
|
||||||
do { \
|
do { \
|
||||||
cur_node = NEW_NODE(typ); \
|
(cur_node) = NEW_NODE(typ); \
|
||||||
POS_FROM_TOKEN(cur_node, cur_token); \
|
POS_FROM_TOKEN((cur_node), cur_token); \
|
||||||
if (prev_token.type == kExprLexSpacing) { \
|
if (prev_token.type == kExprLexSpacing) { \
|
||||||
cur_node->start = prev_token.start; \
|
(cur_node)->start = prev_token.start; \
|
||||||
cur_node->len += prev_token.len; \
|
(cur_node)->len += prev_token.len; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -1280,9 +1289,8 @@ static inline ParserPosition shifted_pos(const ParserPosition pos,
|
|||||||
do { \
|
do { \
|
||||||
if (want_node == kENodeValue) { \
|
if (want_node == kENodeValue) { \
|
||||||
ERROR_FROM_TOKEN_AND_MSG(cur_token, (msg)); \
|
ERROR_FROM_TOKEN_AND_MSG(cur_token, (msg)); \
|
||||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeMissing); \
|
NEW_NODE_WITH_CUR_POS((*top_node_p), kExprNodeMissing); \
|
||||||
cur_node->len = 0; \
|
(*top_node_p)->len = 0; \
|
||||||
*top_node_p = cur_node; \
|
|
||||||
want_node = kENodeOperator; \
|
want_node = kENodeOperator; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -1658,13 +1666,14 @@ viml_pexpr_parse_invalid_comma:
|
|||||||
HL_CUR_TOKEN(Comma);
|
HL_CUR_TOKEN(Comma);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#define EXP_VAL_COLON "E15: Expected value, got colon: %.*s"
|
||||||
case kExprLexColon: {
|
case kExprLexColon: {
|
||||||
ADD_VALUE_IF_MISSING(_("E15: Expected value, got colon: %.*s"));
|
|
||||||
if (kv_size(ast_stack) < 2) {
|
if (kv_size(ast_stack) < 2) {
|
||||||
goto viml_pexpr_parse_invalid_colon;
|
goto viml_pexpr_parse_invalid_colon;
|
||||||
}
|
}
|
||||||
bool is_ternary = false;
|
bool is_ternary = false;
|
||||||
bool can_be_ternary = true;
|
bool can_be_ternary = true;
|
||||||
|
bool is_subscript = false;
|
||||||
for (size_t i = 1; i < kv_size(ast_stack); i++) {
|
for (size_t i = 1; i < kv_size(ast_stack); i++) {
|
||||||
ExprASTNode *const *const eastnode_p =
|
ExprASTNode *const *const eastnode_p =
|
||||||
(ExprASTNode *const *)kv_Z(ast_stack, i);
|
(ExprASTNode *const *)kv_Z(ast_stack, i);
|
||||||
@@ -1683,6 +1692,7 @@ viml_pexpr_parse_invalid_comma:
|
|||||||
}
|
}
|
||||||
is_ternary = true;
|
is_ternary = true;
|
||||||
(*eastnode_p)->data.ter.got_colon = true;
|
(*eastnode_p)->data.ter.got_colon = true;
|
||||||
|
ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
|
||||||
assert((*eastnode_p)->children != NULL);
|
assert((*eastnode_p)->children != NULL);
|
||||||
assert((*eastnode_p)->children->next == NULL);
|
assert((*eastnode_p)->children->next == NULL);
|
||||||
kvi_push(ast_stack, &(*eastnode_p)->children->next);
|
kvi_push(ast_stack, &(*eastnode_p)->children->next);
|
||||||
@@ -1690,14 +1700,18 @@ viml_pexpr_parse_invalid_comma:
|
|||||||
} else if (eastnode_type == kExprNodeUnknownFigure) {
|
} else if (eastnode_type == kExprNodeUnknownFigure) {
|
||||||
SELECT_FIGURE_BRACE_TYPE(*eastnode_p, DictLiteral, Dict);
|
SELECT_FIGURE_BRACE_TYPE(*eastnode_p, DictLiteral, Dict);
|
||||||
break;
|
break;
|
||||||
} else if (eastnode_type == kExprNodeDictLiteral
|
} else if (eastnode_type == kExprNodeDictLiteral) {
|
||||||
|| eastnode_type == kExprNodeSubscript) {
|
break;
|
||||||
|
} else if (eastnode_type == kExprNodeSubscript) {
|
||||||
|
is_subscript = true;
|
||||||
|
can_be_ternary = false;
|
||||||
|
assert(!is_ternary);
|
||||||
break;
|
break;
|
||||||
} else if (eastnode_type == kExprNodeColon) {
|
} else if (eastnode_type == kExprNodeColon) {
|
||||||
goto viml_pexpr_parse_invalid_colon;
|
goto viml_pexpr_parse_invalid_colon;
|
||||||
} else if (eastnode_lvl >= kEOpLvlTernaryValue) {
|
} else if (eastnode_lvl >= kEOpLvlTernaryValue) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if (eastnode_lvl > kEOpLvlComma) {
|
} else if (eastnode_lvl >= kEOpLvlComma) {
|
||||||
can_be_ternary = false;
|
can_be_ternary = false;
|
||||||
} else {
|
} else {
|
||||||
viml_pexpr_parse_invalid_colon:
|
viml_pexpr_parse_invalid_colon:
|
||||||
@@ -1711,16 +1725,122 @@ viml_pexpr_parse_invalid_colon:
|
|||||||
goto viml_pexpr_parse_invalid_colon;
|
goto viml_pexpr_parse_invalid_colon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_ternary) {
|
if (is_subscript) {
|
||||||
HL_CUR_TOKEN(TernaryColon);
|
assert(kv_size(ast_stack) > 1);
|
||||||
} else {
|
// 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);
|
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
|
||||||
ADD_OP_NODE(cur_node);
|
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;
|
want_node = kENodeValue;
|
||||||
break;
|
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: {
|
case kExprLexFigureBrace: {
|
||||||
if (cur_token.data.brc.closing) {
|
if (cur_token.data.brc.closing) {
|
||||||
ExprASTNode **new_top_node_p = NULL;
|
ExprASTNode **new_top_node_p = NULL;
|
||||||
|
@@ -91,6 +91,8 @@ make_enum_conv_tab(lib, {
|
|||||||
'kExprNodeConcatOrSubscript',
|
'kExprNodeConcatOrSubscript',
|
||||||
'kExprNodeInteger',
|
'kExprNodeInteger',
|
||||||
'kExprNodeFloat',
|
'kExprNodeFloat',
|
||||||
|
'kExprNodeSingleQuotedString',
|
||||||
|
'kExprNodeDoubleQuotedString',
|
||||||
}, 'kExprNode', function(ret) east_node_type_tab = ret end)
|
}, 'kExprNode', function(ret) east_node_type_tab = ret end)
|
||||||
|
|
||||||
local function conv_east_node_type(typ)
|
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)
|
local function check_parsing(str, flags, exp_ast, exp_highlighting_fs)
|
||||||
flags = flags or 0
|
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 pstate = new_pstate({str})
|
||||||
local east = lib.viml_pexpr_parse(pstate, flags)
|
local east = lib.viml_pexpr_parse(pstate, flags)
|
||||||
local ast = east2lua(pstate, east)
|
local ast = east2lua(pstate, east)
|
||||||
@@ -4016,4 +4022,531 @@ describe('Expressions parser', function()
|
|||||||
hl('Identifier', 'b'),
|
hl('Identifier', 'b'),
|
||||||
})
|
})
|
||||||
end)
|
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)
|
end)
|
||||||
|
Reference in New Issue
Block a user