mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
viml/parser/expressions: Finish parser
Note: formatc.lua was unable to swallow some newer additions to ExprASTNodeType (specifically `kExprNodeOr = '|'` and probably something else), so all `= …` were dropped: in any case they only were there in order to not bother updating viml_pexpr_debug_print_ast_node and since it is now known all nodes which will be present it is not much of an issue.
This commit is contained in:
parent
af38cea133
commit
fa3cfc0dd5
@ -361,11 +361,12 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
|
||||
// Scope: `s:`, etc.
|
||||
} else if (ret.len == 1
|
||||
&& pline.size > 1
|
||||
&& strchr("sgvbwtla", schar) != NULL
|
||||
&& memchr(EXPR_VAR_SCOPE_LIST, schar,
|
||||
sizeof(EXPR_VAR_SCOPE_LIST)) != NULL
|
||||
&& pline.data[ret.len] == ':'
|
||||
&& !(flags & kELFlagForbidScope)) {
|
||||
ret.len++;
|
||||
ret.data.var.scope = schar;
|
||||
ret.data.var.scope = (ExprVarScope)schar;
|
||||
CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD);
|
||||
ret.data.var.autoload = (
|
||||
memchr(pline.data + 2, AUTOLOAD_CHAR, ret.len - 2)
|
||||
@ -408,14 +409,13 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
|
||||
ret.type = kExprLexOption;
|
||||
if (pline.size > 2
|
||||
&& pline.data[2] == ':'
|
||||
&& strchr("gl", pline.data[1]) != NULL) {
|
||||
&& memchr(EXPR_OPT_SCOPE_LIST, pline.data[1],
|
||||
sizeof(EXPR_OPT_SCOPE_LIST)) != NULL) {
|
||||
ret.len += 2;
|
||||
ret.data.opt.scope = (pline.data[1] == 'g'
|
||||
? kExprLexOptGlobal
|
||||
: kExprLexOptLocal);
|
||||
ret.data.opt.scope = (ExprOptScope)pline.data[1];
|
||||
ret.data.opt.name = pline.data + 3;
|
||||
} else {
|
||||
ret.data.opt.scope = kExprLexOptUnspecified;
|
||||
ret.data.opt.scope = kExprOptScopeUnspecified;
|
||||
ret.data.opt.name = pline.data + 1;
|
||||
}
|
||||
const char *p = ret.data.opt.name;
|
||||
@ -637,9 +637,9 @@ static const char *const eltkn_mul_type_tab[] = {
|
||||
};
|
||||
|
||||
static const char *const eltkn_opt_scope_tab[] = {
|
||||
[kExprLexOptUnspecified] = "Unspecified",
|
||||
[kExprLexOptGlobal] = "Global",
|
||||
[kExprLexOptLocal] = "Local",
|
||||
[kExprOptScopeUnspecified] = "Unspecified",
|
||||
[kExprOptScopeGlobal] = "Global",
|
||||
[kExprOptScopeLocal] = "Local",
|
||||
};
|
||||
|
||||
/// Represent `int` character as a string
|
||||
@ -990,67 +990,25 @@ static inline ExprASTNode *viml_pexpr_new_node(const ExprASTNodeType type)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const ExprOpLvl node_type_to_op_lvl[] = {
|
||||
[kExprNodeMissing] = kEOpLvlInvalid,
|
||||
[kExprNodeOpMissing] = kEOpLvlMultiplication,
|
||||
static struct {
|
||||
ExprOpLvl lvl;
|
||||
ExprOpAssociativity ass;
|
||||
} node_type_to_node_props[] = {
|
||||
[kExprNodeMissing] = { kEOpLvlInvalid, kEOpAssNo, },
|
||||
[kExprNodeOpMissing] = { kEOpLvlMultiplication, kEOpAssNo },
|
||||
|
||||
[kExprNodeNested] = kEOpLvlParens,
|
||||
[kExprNodeNested] = { kEOpLvlParens, kEOpAssNo },
|
||||
// Note: below nodes are kEOpLvlSubscript for “binary operator” itself, but
|
||||
// kEOpLvlParens when it comes to inside the parenthesis.
|
||||
[kExprNodeCall] = kEOpLvlParens,
|
||||
[kExprNodeSubscript] = kEOpLvlParens,
|
||||
[kExprNodeCall] = { kEOpLvlParens, kEOpAssNo },
|
||||
[kExprNodeSubscript] = { kEOpLvlParens, kEOpAssNo },
|
||||
|
||||
[kExprNodeUnknownFigure] = kEOpLvlParens,
|
||||
[kExprNodeLambda] = kEOpLvlParens,
|
||||
[kExprNodeDictLiteral] = kEOpLvlParens,
|
||||
[kExprNodeListLiteral] = kEOpLvlParens,
|
||||
[kExprNodeUnknownFigure] = { kEOpLvlParens, kEOpAssLeft },
|
||||
[kExprNodeLambda] = { kEOpLvlParens, kEOpAssNo },
|
||||
[kExprNodeDictLiteral] = { kEOpLvlParens, kEOpAssNo },
|
||||
[kExprNodeListLiteral] = { kEOpLvlParens, kEOpAssNo },
|
||||
|
||||
[kExprNodeArrow] = kEOpLvlArrow,
|
||||
|
||||
[kExprNodeComma] = kEOpLvlComma,
|
||||
|
||||
[kExprNodeColon] = kEOpLvlColon,
|
||||
|
||||
[kExprNodeTernary] = kEOpLvlTernary,
|
||||
|
||||
[kExprNodeTernaryValue] = kEOpLvlTernaryValue,
|
||||
|
||||
[kExprNodeComparison] = kEOpLvlComparison,
|
||||
|
||||
[kExprNodeBinaryPlus] = kEOpLvlAddition,
|
||||
[kExprNodeConcat] = kEOpLvlAddition,
|
||||
|
||||
[kExprNodeUnaryPlus] = kEOpLvlUnary,
|
||||
|
||||
[kExprNodeConcatOrSubscript] = kEOpLvlSubscript,
|
||||
|
||||
[kExprNodeCurlyBracesIdentifier] = kEOpLvlComplexIdentifier,
|
||||
|
||||
[kExprNodeComplexIdentifier] = kEOpLvlValue,
|
||||
[kExprNodePlainIdentifier] = kEOpLvlValue,
|
||||
[kExprNodePlainKey] = kEOpLvlValue,
|
||||
[kExprNodeRegister] = kEOpLvlValue,
|
||||
[kExprNodeInteger] = kEOpLvlValue,
|
||||
[kExprNodeFloat] = kEOpLvlValue,
|
||||
};
|
||||
|
||||
static const ExprOpAssociativity node_type_to_op_ass[] = {
|
||||
[kExprNodeMissing] = kEOpAssNo,
|
||||
[kExprNodeOpMissing] = kEOpAssNo,
|
||||
|
||||
[kExprNodeNested] = kEOpAssNo,
|
||||
[kExprNodeCall] = kEOpAssNo,
|
||||
[kExprNodeSubscript] = kEOpAssNo,
|
||||
|
||||
[kExprNodeUnknownFigure] = kEOpAssLeft,
|
||||
[kExprNodeLambda] = kEOpAssNo,
|
||||
[kExprNodeDictLiteral] = kEOpAssNo,
|
||||
[kExprNodeListLiteral] = kEOpAssNo,
|
||||
|
||||
// Does not really matter.
|
||||
[kExprNodeArrow] = kEOpAssNo,
|
||||
|
||||
[kExprNodeColon] = kEOpAssNo,
|
||||
[kExprNodeArrow] = { kEOpLvlArrow, kEOpAssNo },
|
||||
|
||||
// Right associativity for comma because this means easier access to arguments
|
||||
// list, etc: for "[a, b, c, d]" you can access "a" in one step if it is
|
||||
@ -1059,29 +1017,48 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
|
||||
// traverse all three comma() structures. And with comma operator (including
|
||||
// actual comma operator from C which is not present in VimL) nobody cares
|
||||
// about associativity, only about order of execution.
|
||||
[kExprNodeComma] = kEOpAssRight,
|
||||
[kExprNodeComma] = { kEOpLvlComma, kEOpAssRight },
|
||||
|
||||
[kExprNodeTernary] = kEOpAssRight,
|
||||
// Colons are not eligible for chaining, so nobody cares about associativity.
|
||||
[kExprNodeColon] = { kEOpLvlColon, kEOpAssNo },
|
||||
|
||||
[kExprNodeTernaryValue] = kEOpAssRight,
|
||||
[kExprNodeTernary] = { kEOpLvlTernary, kEOpAssRight },
|
||||
|
||||
[kExprNodeComparison] = kEOpAssRight,
|
||||
[kExprNodeOr] = { kEOpLvlOr, kEOpAssLeft },
|
||||
|
||||
[kExprNodeBinaryPlus] = kEOpAssLeft,
|
||||
[kExprNodeConcat] = kEOpAssLeft,
|
||||
[kExprNodeAnd] = { kEOpLvlAnd, kEOpAssLeft },
|
||||
|
||||
[kExprNodeUnaryPlus] = kEOpAssNo,
|
||||
[kExprNodeTernaryValue] = { kEOpLvlTernaryValue, kEOpAssRight },
|
||||
|
||||
[kExprNodeConcatOrSubscript] = kEOpAssLeft,
|
||||
[kExprNodeComparison] = { kEOpLvlComparison, kEOpAssRight },
|
||||
|
||||
[kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
|
||||
[kExprNodeBinaryPlus] = { kEOpLvlAddition, kEOpAssLeft },
|
||||
[kExprNodeBinaryMinus] = { kEOpLvlAddition, kEOpAssLeft },
|
||||
[kExprNodeConcat] = { kEOpLvlAddition, kEOpAssLeft },
|
||||
|
||||
[kExprNodeComplexIdentifier] = kEOpAssLeft,
|
||||
[kExprNodePlainIdentifier] = kEOpAssNo,
|
||||
[kExprNodePlainKey] = kEOpAssNo,
|
||||
[kExprNodeRegister] = kEOpAssNo,
|
||||
[kExprNodeInteger] = kEOpAssNo,
|
||||
[kExprNodeFloat] = kEOpAssNo,
|
||||
[kExprNodeMultiplication] = { kEOpLvlMultiplication, kEOpAssLeft },
|
||||
[kExprNodeDivision] = { kEOpLvlMultiplication, kEOpAssLeft },
|
||||
[kExprNodeMod] = { kEOpLvlMultiplication, kEOpAssLeft },
|
||||
|
||||
[kExprNodeUnaryPlus] = { kEOpLvlUnary, kEOpAssNo },
|
||||
[kExprNodeUnaryMinus] = { kEOpLvlUnary, kEOpAssNo },
|
||||
[kExprNodeNot] = { kEOpLvlUnary, kEOpAssNo },
|
||||
|
||||
[kExprNodeConcatOrSubscript] = { kEOpLvlSubscript, kEOpAssLeft },
|
||||
|
||||
[kExprNodeCurlyBracesIdentifier] = { kEOpLvlComplexIdentifier, kEOpAssLeft },
|
||||
|
||||
[kExprNodeComplexIdentifier] = { kEOpLvlValue, kEOpAssLeft },
|
||||
|
||||
[kExprNodePlainIdentifier] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodePlainKey] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeRegister] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeInteger] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeFloat] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeDoubleQuotedString] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeSingleQuotedString] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeOption] = { kEOpLvlValue, kEOpAssNo },
|
||||
[kExprNodeEnvironment] = { kEOpLvlValue, kEOpAssNo },
|
||||
};
|
||||
|
||||
/// Get AST node priority level
|
||||
@ -1094,7 +1071,7 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
|
||||
static inline ExprOpLvl node_lvl(const ExprASTNode node)
|
||||
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return node_type_to_op_lvl[node.type];
|
||||
return node_type_to_node_props[node.type].lvl;
|
||||
}
|
||||
|
||||
/// Get AST node associativity, to be used for operator nodes primary
|
||||
@ -1107,7 +1084,7 @@ static inline ExprOpLvl node_lvl(const ExprASTNode node)
|
||||
static inline ExprOpAssociativity node_ass(const ExprASTNode node)
|
||||
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
return node_type_to_op_ass[node.type];
|
||||
return node_type_to_node_props[node.type].ass;
|
||||
}
|
||||
|
||||
/// Handle binary operator
|
||||
@ -1837,7 +1814,7 @@ viml_pexpr_parse_process_token:
|
||||
is_concat_or_subscript
|
||||
&& (cur_token.type == kExprLexPlainIdentifier
|
||||
? (!cur_token.data.var.autoload
|
||||
&& cur_token.data.var.scope == 0)
|
||||
&& cur_token.data.var.scope == kExprVarScopeMissing)
|
||||
: (cur_token.type == kExprLexNumber))
|
||||
&& prev_token.type != kExprLexSpacing);
|
||||
if (is_concat_or_subscript && !node_is_key) {
|
||||
@ -1856,7 +1833,7 @@ viml_pexpr_parse_process_token:
|
||||
&& tok_type != kExprLexArrow)
|
||||
|| (want_node == kENodeArgument
|
||||
&& !(cur_token.type == kExprLexPlainIdentifier
|
||||
&& cur_token.data.var.scope == 0
|
||||
&& cur_token.data.var.scope == kExprVarScopeMissing
|
||||
&& !cur_token.data.var.autoload)
|
||||
&& tok_type != kExprLexArrow)) {
|
||||
lambda_node->data.fig.type_guesses.allow_lambda = false;
|
||||
@ -1885,6 +1862,8 @@ viml_pexpr_parse_process_token:
|
||||
|| want_node == kENodeArgumentSeparator
|
||||
|| want_node == kENodeArgument);
|
||||
switch (tok_type) {
|
||||
case kExprLexMissing:
|
||||
case kExprLexSpacing:
|
||||
case kExprLexEOC: {
|
||||
assert(false);
|
||||
}
|
||||
@ -1894,31 +1873,111 @@ viml_pexpr_parse_process_token:
|
||||
goto viml_pexpr_parse_process_token;
|
||||
}
|
||||
case kExprLexRegister: {
|
||||
if (want_node == kENodeValue) {
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeRegister);
|
||||
cur_node->data.reg.name = cur_token.data.reg.name;
|
||||
*top_node_p = cur_node;
|
||||
want_node = kENodeOperator;
|
||||
HL_CUR_TOKEN(Register);
|
||||
} else {
|
||||
if (want_node == kENodeOperator) {
|
||||
// Register in operator position: e.g. @a @a
|
||||
OP_MISSING;
|
||||
}
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeRegister);
|
||||
cur_node->data.reg.name = cur_token.data.reg.name;
|
||||
*top_node_p = cur_node;
|
||||
want_node = kENodeOperator;
|
||||
HL_CUR_TOKEN(Register);
|
||||
break;
|
||||
}
|
||||
case kExprLexPlus: {
|
||||
if (want_node == kENodeValue) {
|
||||
// Value level: assume unary plus
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnaryPlus);
|
||||
*top_node_p = cur_node;
|
||||
kvi_push(ast_stack, &cur_node->children);
|
||||
HL_CUR_TOKEN(UnaryPlus);
|
||||
} else {
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeBinaryPlus);
|
||||
ADD_OP_NODE(cur_node);
|
||||
HL_CUR_TOKEN(BinaryPlus);
|
||||
#define SIMPLE_UB_OP(op) \
|
||||
case kExprLex##op: { \
|
||||
if (want_node == kENodeValue) { \
|
||||
/* Value level: assume unary operator. */ \
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnary##op); \
|
||||
*top_node_p = cur_node; \
|
||||
kvi_push(ast_stack, &cur_node->children); \
|
||||
HL_CUR_TOKEN(Unary##op); \
|
||||
} else { \
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeBinary##op); \
|
||||
ADD_OP_NODE(cur_node); \
|
||||
HL_CUR_TOKEN(Binary##op); \
|
||||
} \
|
||||
want_node = kENodeValue; \
|
||||
break; \
|
||||
}
|
||||
SIMPLE_UB_OP(Plus)
|
||||
SIMPLE_UB_OP(Minus)
|
||||
#undef SIMPLE_UB_OP
|
||||
#define SIMPLE_B_OP(op, msg) \
|
||||
case kExprLex##op: { \
|
||||
ADD_VALUE_IF_MISSING(_("E15: Unexpected " msg ": %.*s")); \
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##op); \
|
||||
HL_CUR_TOKEN(op); \
|
||||
ADD_OP_NODE(cur_node); \
|
||||
break; \
|
||||
}
|
||||
SIMPLE_B_OP(Or, "or operator")
|
||||
SIMPLE_B_OP(And, "and operator")
|
||||
#undef SIMPLE_B_OP
|
||||
case kExprLexMultiplication: {
|
||||
ADD_VALUE_IF_MISSING(
|
||||
_("E15: Unexpected multiplication-like operator: %.*s"));
|
||||
switch (cur_token.data.mul.type) {
|
||||
#define MUL_OP(lex_op_tail, node_op_tail) \
|
||||
case kExprLexMul##lex_op_tail: { \
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##node_op_tail); \
|
||||
HL_CUR_TOKEN(node_op_tail); \
|
||||
break; \
|
||||
}
|
||||
MUL_OP(Mul, Multiplication)
|
||||
MUL_OP(Div, Division)
|
||||
MUL_OP(Mod, Mod)
|
||||
#undef MUL_OP
|
||||
}
|
||||
want_node = kENodeValue;
|
||||
ADD_OP_NODE(cur_node);
|
||||
break;
|
||||
}
|
||||
case kExprLexOption: {
|
||||
if (want_node == kENodeOperator) {
|
||||
OP_MISSING;
|
||||
}
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeOption);
|
||||
cur_node->data.opt.ident = cur_token.data.opt.name;
|
||||
cur_node->data.opt.ident_len = cur_token.data.opt.len;
|
||||
cur_node->data.opt.scope = cur_token.data.opt.scope;
|
||||
*top_node_p = cur_node;
|
||||
want_node = kENodeOperator;
|
||||
viml_parser_highlight(pstate, cur_token.start, 1, HL(OptionSigil));
|
||||
const size_t scope_shift = (
|
||||
cur_token.data.opt.scope == kExprOptScopeUnspecified ? 0 : 2);
|
||||
if (scope_shift) {
|
||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
|
||||
HL(OptionScope));
|
||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start, 2), 1,
|
||||
HL(OptionScopeDelimiter));
|
||||
}
|
||||
viml_parser_highlight(
|
||||
pstate, shifted_pos(cur_token.start, scope_shift + 1),
|
||||
cur_token.len - scope_shift + 1, HL(Option));
|
||||
break;
|
||||
}
|
||||
case kExprLexEnv: {
|
||||
if (want_node == kENodeOperator) {
|
||||
OP_MISSING;
|
||||
}
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeEnvironment);
|
||||
cur_node->data.env.ident = pline.data + cur_token.start.col + 1;
|
||||
cur_node->data.env.ident_len = cur_token.len - 1;
|
||||
*top_node_p = cur_node;
|
||||
want_node = kENodeOperator;
|
||||
viml_parser_highlight(pstate, cur_token.start, 1, HL(EnvironmentSigil));
|
||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1),
|
||||
cur_token.len - 1, HL(Environment));
|
||||
break;
|
||||
}
|
||||
case kExprLexNot: {
|
||||
if (want_node == kENodeOperator) {
|
||||
OP_MISSING;
|
||||
}
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeNot);
|
||||
*top_node_p = cur_node;
|
||||
kvi_push(ast_stack, &cur_node->children);
|
||||
HL_CUR_TOKEN(Not);
|
||||
break;
|
||||
}
|
||||
case kExprLexComparison: {
|
||||
@ -2359,9 +2418,8 @@ viml_pexpr_parse_figure_brace_closing_error:
|
||||
? kExprNodePlainKey
|
||||
: kExprNodePlainIdentifier));
|
||||
cur_node->data.var.scope = cur_token.data.var.scope;
|
||||
const size_t scope_shift = (cur_token.data.var.scope == 0
|
||||
? 0
|
||||
: 2);
|
||||
const size_t scope_shift = (
|
||||
cur_token.data.var.scope == kExprVarScopeMissing ? 0 : 2);
|
||||
cur_node->data.var.ident = (pline.data + cur_token.start.col
|
||||
+ scope_shift);
|
||||
cur_node->data.var.ident_len = cur_token.len - scope_shift;
|
||||
@ -2373,16 +2431,14 @@ viml_pexpr_parse_figure_brace_closing_error:
|
||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
|
||||
HL(IdentifierScopeDelimiter));
|
||||
}
|
||||
if (scope_shift < cur_token.len) {
|
||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start,
|
||||
scope_shift),
|
||||
cur_token.len - scope_shift,
|
||||
(node_is_key
|
||||
? HL(IdentifierKey)
|
||||
: HL(Identifier)));
|
||||
}
|
||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start,
|
||||
scope_shift),
|
||||
cur_token.len - scope_shift,
|
||||
(node_is_key
|
||||
? HL(IdentifierKey)
|
||||
: HL(Identifier)));
|
||||
} else {
|
||||
if (cur_token.data.var.scope == 0) {
|
||||
if (cur_token.data.var.scope == kExprVarScopeMissing) {
|
||||
ADD_IDENT(
|
||||
do {
|
||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainIdentifier);
|
||||
@ -2606,9 +2662,85 @@ viml_pexpr_parse_end:
|
||||
cur_node->start);
|
||||
break;
|
||||
}
|
||||
case kExprNodeBinaryPlus:
|
||||
case kExprNodeListLiteral: {
|
||||
// For whatever reason "[1" yields "E696: Missing comma in list" error
|
||||
// in Vim while "[1," yields E697.
|
||||
east_set_error(
|
||||
pstate, &ast.err,
|
||||
_("E697: Missing end of List ']': %.*s"),
|
||||
cur_node->start);
|
||||
break;
|
||||
}
|
||||
case kExprNodeDictLiteral: {
|
||||
// Same problem like with list literal with E722 (missing comma) vs
|
||||
// E723, but additionally just "{" yields only E15.
|
||||
east_set_error(
|
||||
pstate, &ast.err,
|
||||
_("E723: Missing end of Dictionary '}': %.*s"),
|
||||
cur_node->start);
|
||||
break;
|
||||
}
|
||||
case kExprNodeUnknownFigure: {
|
||||
east_set_error(
|
||||
pstate, &ast.err,
|
||||
_("E15: Missing closing figure brace: %.*s"),
|
||||
cur_node->start);
|
||||
break;
|
||||
}
|
||||
case kExprNodeLambda: {
|
||||
east_set_error(
|
||||
pstate, &ast.err,
|
||||
_("E15: Missing closing figure brace for lambda: %.*s"),
|
||||
cur_node->start);
|
||||
break;
|
||||
}
|
||||
case kExprNodeCurlyBracesIdentifier: {
|
||||
// Until trailing "}" it is impossible to distinguish curly braces
|
||||
// identifier and dictionary, so it must not appear in the stack like
|
||||
// this.
|
||||
assert(false);
|
||||
}
|
||||
case kExprNodeInteger:
|
||||
case kExprNodeFloat:
|
||||
case kExprNodeSingleQuotedString:
|
||||
case kExprNodeDoubleQuotedString:
|
||||
case kExprNodeOption:
|
||||
case kExprNodeEnvironment:
|
||||
case kExprNodeRegister:
|
||||
case kExprNodePlainIdentifier:
|
||||
case kExprNodePlainKey: {
|
||||
// These are plain values and not containers, for them it should only
|
||||
// be possible to show up in the topmost stack element, but it was
|
||||
// unconditionally popped at the start.
|
||||
assert(false);
|
||||
}
|
||||
case kExprNodeComma:
|
||||
case kExprNodeColon:
|
||||
case kExprNodeArrow: {
|
||||
// It is actually only valid inside something else, but everything
|
||||
// where one of the above is valid requires to be closed and thus is
|
||||
// to be caught later.
|
||||
break;
|
||||
}
|
||||
case kExprNodeConcatOrSubscript:
|
||||
case kExprNodeComplexIdentifier:
|
||||
case kExprNodeSubscript: {
|
||||
// FIXME: Investigate whether above are OK to be present in the stack.
|
||||
break;
|
||||
}
|
||||
case kExprNodeMod:
|
||||
case kExprNodeDivision:
|
||||
case kExprNodeMultiplication:
|
||||
case kExprNodeNot:
|
||||
case kExprNodeAnd:
|
||||
case kExprNodeOr:
|
||||
case kExprNodeConcat:
|
||||
case kExprNodeComparison:
|
||||
case kExprNodeUnaryMinus:
|
||||
case kExprNodeUnaryPlus:
|
||||
case kExprNodeRegister: {
|
||||
case kExprNodeBinaryMinus:
|
||||
case kExprNodeTernary:
|
||||
case kExprNodeBinaryPlus: {
|
||||
// It is OK to see these in the stack.
|
||||
break;
|
||||
}
|
||||
@ -2621,7 +2753,6 @@ viml_pexpr_parse_end:
|
||||
}
|
||||
break;
|
||||
}
|
||||
// TODO(ZyX-I): handle other values
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,36 @@ typedef enum {
|
||||
kExprCmpIdentical, ///< `is` or `isnot`
|
||||
} ExprComparisonType;
|
||||
|
||||
/// All possible option scopes
|
||||
typedef enum {
|
||||
kExprOptScopeUnspecified = 0,
|
||||
kExprOptScopeGlobal = 'g',
|
||||
kExprOptScopeLocal = 'l',
|
||||
} ExprOptScope;
|
||||
|
||||
#define EXPR_OPT_SCOPE_LIST \
|
||||
((char *)(char[]){ kExprOptScopeGlobal, kExprOptScopeLocal })
|
||||
|
||||
/// All possible variable scopes
|
||||
typedef enum {
|
||||
kExprVarScopeMissing = 0,
|
||||
kExprVarScopeScript = 's',
|
||||
kExprVarScopeGlobal = 'g',
|
||||
kExprVarScopeVim = 'v',
|
||||
kExprVarScopeBuffer = 'b',
|
||||
kExprVarScopeWindow = 'w',
|
||||
kExprVarScopeTabpage = 't',
|
||||
kExprVarScopeLocal = 'l',
|
||||
kExprVarScopeArguments = 'a',
|
||||
} ExprVarScope;
|
||||
|
||||
#define EXPR_VAR_SCOPE_LIST \
|
||||
((char[]) { \
|
||||
kExprVarScopeScript, kExprVarScopeGlobal, kExprVarScopeVim, \
|
||||
kExprVarScopeBuffer, kExprVarScopeWindow, kExprVarScopeTabpage, \
|
||||
kExprVarScopeLocal, kExprVarScopeBuffer, kExprVarScopeArguments, \
|
||||
})
|
||||
|
||||
/// Lexer token
|
||||
typedef struct {
|
||||
ParserPosition start;
|
||||
@ -96,15 +126,11 @@ typedef struct {
|
||||
struct {
|
||||
const char *name; ///< Option name start.
|
||||
size_t len; ///< Option name length.
|
||||
enum {
|
||||
kExprLexOptUnspecified = 0,
|
||||
kExprLexOptGlobal = 1,
|
||||
kExprLexOptLocal = 2,
|
||||
} scope; ///< Option scope: &l:, &g: or not specified.
|
||||
ExprOptScope scope; ///< Option scope: &l:, &g: or not specified.
|
||||
} opt; ///< Option properties.
|
||||
|
||||
struct {
|
||||
int scope; ///< Scope character or 0 if not present.
|
||||
ExprVarScope scope; ///< Scope character or 0 if not present.
|
||||
bool autoload; ///< Has autoload characters.
|
||||
} var; ///< For kExprLexPlainIdentifier
|
||||
|
||||
@ -150,53 +176,63 @@ typedef enum {
|
||||
|
||||
/// Expression AST node type
|
||||
typedef enum {
|
||||
kExprNodeMissing = 'X',
|
||||
kExprNodeOpMissing = '_',
|
||||
kExprNodeTernary = '?', ///< Ternary operator.
|
||||
kExprNodeTernaryValue = 'C', ///< Ternary operator, colon.
|
||||
kExprNodeRegister = '@', ///< Register.
|
||||
kExprNodeSubscript = 's', ///< Subscript.
|
||||
kExprNodeListLiteral = 'l', ///< List literal.
|
||||
kExprNodeUnaryPlus = 'p',
|
||||
kExprNodeBinaryPlus = '+',
|
||||
kExprNodeNested = 'e', ///< Nested parenthesised expression.
|
||||
kExprNodeCall = 'c', ///< Function call.
|
||||
kExprNodeMissing = 0,
|
||||
kExprNodeOpMissing,
|
||||
kExprNodeTernary, ///< Ternary operator.
|
||||
kExprNodeTernaryValue, ///< Ternary operator, colon.
|
||||
kExprNodeRegister, ///< Register.
|
||||
kExprNodeSubscript, ///< Subscript.
|
||||
kExprNodeListLiteral, ///< List literal.
|
||||
kExprNodeUnaryPlus,
|
||||
kExprNodeBinaryPlus,
|
||||
kExprNodeNested, ///< Nested parenthesised expression.
|
||||
kExprNodeCall, ///< Function call.
|
||||
/// Plain identifier: simple variable/function name
|
||||
///
|
||||
/// Looks like "string", "g:Foo", etc: consists from a single
|
||||
/// kExprLexPlainIdentifier token.
|
||||
kExprNodePlainIdentifier = 'i',
|
||||
kExprNodePlainIdentifier,
|
||||
/// Plain dictionary key, for use with kExprNodeConcatOrSubscript
|
||||
kExprNodePlainKey = 'k',
|
||||
kExprNodePlainKey,
|
||||
/// Complex identifier: variable/function name with curly braces
|
||||
kExprNodeComplexIdentifier = 'I',
|
||||
kExprNodeComplexIdentifier,
|
||||
/// Figure brace expression which is not yet known
|
||||
///
|
||||
/// May resolve to any of kExprNodeDictLiteral, kExprNodeLambda or
|
||||
/// kExprNodeCurlyBracesIdentifier.
|
||||
kExprNodeUnknownFigure = '{',
|
||||
kExprNodeLambda = '\\', ///< Lambda.
|
||||
kExprNodeDictLiteral = 'd', ///< Dictionary literal.
|
||||
kExprNodeCurlyBracesIdentifier= '}', ///< Part of the curly braces name.
|
||||
kExprNodeComma = ',', ///< Comma “operator”.
|
||||
kExprNodeColon = ':', ///< Colon “operator”.
|
||||
kExprNodeArrow = '>', ///< Arrow “operator”.
|
||||
kExprNodeComparison = '=', ///< Various comparison operators.
|
||||
kExprNodeUnknownFigure,
|
||||
kExprNodeLambda, ///< Lambda.
|
||||
kExprNodeDictLiteral, ///< Dictionary literal.
|
||||
kExprNodeCurlyBracesIdentifier, ///< Part of the curly braces name.
|
||||
kExprNodeComma, ///< Comma “operator”.
|
||||
kExprNodeColon, ///< Colon “operator”.
|
||||
kExprNodeArrow, ///< Arrow “operator”.
|
||||
kExprNodeComparison, ///< Various comparison operators.
|
||||
/// Concat operator
|
||||
///
|
||||
/// To be only used in cases when it is known for sure it is not a subscript.
|
||||
kExprNodeConcat = '.',
|
||||
kExprNodeConcat,
|
||||
/// Concat or subscript operator
|
||||
///
|
||||
/// For cases when it is not obvious whether expression is a concat or
|
||||
/// a subscript. May only have either number or plain identifier as the second
|
||||
/// child. To make it easier to avoid curly braces in place of
|
||||
/// kExprNodePlainIdentifier node kExprNodePlainKey is used.
|
||||
kExprNodeConcatOrSubscript = 'S',
|
||||
kExprNodeInteger = '0', ///< Integral number.
|
||||
kExprNodeFloat = '1', ///< Floating-point number.
|
||||
kExprNodeSingleQuotedString = '\'',
|
||||
kExprNodeDoubleQuotedString = '"',
|
||||
kExprNodeConcatOrSubscript,
|
||||
kExprNodeInteger, ///< Integral number.
|
||||
kExprNodeFloat, ///< Floating-point number.
|
||||
kExprNodeSingleQuotedString,
|
||||
kExprNodeDoubleQuotedString,
|
||||
kExprNodeOr,
|
||||
kExprNodeAnd,
|
||||
kExprNodeUnaryMinus,
|
||||
kExprNodeBinaryMinus,
|
||||
kExprNodeNot,
|
||||
kExprNodeMultiplication,
|
||||
kExprNodeDivision,
|
||||
kExprNodeMod,
|
||||
kExprNodeOption,
|
||||
kExprNodeEnvironment,
|
||||
} ExprASTNodeType;
|
||||
|
||||
typedef struct expr_ast_node ExprASTNode;
|
||||
@ -230,7 +266,7 @@ struct expr_ast_node {
|
||||
size_t opening_hl_idx;
|
||||
} fig; ///< For kExprNodeUnknownFigure.
|
||||
struct {
|
||||
int scope; ///< Scope character or 0 if not present.
|
||||
ExprVarScope scope; ///< Scope character or 0 if not present.
|
||||
/// Actual identifier without scope.
|
||||
///
|
||||
/// Points to inside parser reader state.
|
||||
@ -256,6 +292,15 @@ struct expr_ast_node {
|
||||
size_t size;
|
||||
} str; ///< For kExprNodeSingleQuotedString and
|
||||
///< kExprNodeDoubleQuotedString.
|
||||
struct {
|
||||
const char *ident; ///< Option name start.
|
||||
size_t ident_len; ///< Option name length.
|
||||
ExprOptScope scope; ///< Option scope: &l:, &g: or not specified.
|
||||
} opt; ///< For kExprNodeOption.
|
||||
struct {
|
||||
const char *ident; ///< Environment variable name start.
|
||||
size_t ident_len; ///< Environment variable name length.
|
||||
} env; ///< For kExprNodeEnvironment.
|
||||
} data;
|
||||
};
|
||||
|
||||
|
@ -173,7 +173,7 @@ static inline void viml_parser_highlight(ParserState *const pstate,
|
||||
const size_t len,
|
||||
const char *const group)
|
||||
{
|
||||
if (pstate->colors == NULL) {
|
||||
if (pstate->colors == NULL || len == 0) {
|
||||
return;
|
||||
}
|
||||
// TODO(ZyX-I): May do some assert() sanitizing here.
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "nvim/charset.c"
|
||||
#include "nvim/garray.c"
|
||||
#include "nvim/gettext.c"
|
||||
#include "nvim/keymap.c"
|
||||
#include "nvim/viml/parser/expressions.c"
|
||||
|
||||
#define INPUT_SIZE 7
|
||||
|
@ -62,9 +62,9 @@ child_call_once(function()
|
||||
}
|
||||
|
||||
eltkn_opt_scope_tab = {
|
||||
[tonumber(lib.kExprLexOptUnspecified)] = 'Unspecified',
|
||||
[tonumber(lib.kExprLexOptGlobal)] = 'Global',
|
||||
[tonumber(lib.kExprLexOptLocal)] = 'Local',
|
||||
[tonumber(lib.kExprOptScopeUnspecified)] = 'Unspecified',
|
||||
[tonumber(lib.kExprOptScopeGlobal)] = 'Global',
|
||||
[tonumber(lib.kExprOptScopeLocal)] = 'Local',
|
||||
}
|
||||
end)
|
||||
|
||||
|
@ -93,6 +93,16 @@ make_enum_conv_tab(lib, {
|
||||
'kExprNodeFloat',
|
||||
'kExprNodeSingleQuotedString',
|
||||
'kExprNodeDoubleQuotedString',
|
||||
'kExprNodeOr',
|
||||
'kExprNodeAnd',
|
||||
'kExprNodeUnaryMinus',
|
||||
'kExprNodeBinaryMinus',
|
||||
'kExprNodeNot',
|
||||
'kExprNodeMultiplication',
|
||||
'kExprNodeDivision',
|
||||
'kExprNodeMod',
|
||||
'kExprNodeOption',
|
||||
'kExprNodeEnvironment',
|
||||
}, 'kExprNode', function(ret) east_node_type_tab = ret end)
|
||||
|
||||
local function conv_east_node_type(typ)
|
||||
@ -149,6 +159,15 @@ local function eastnode2lua(pstate, eastnode, checked_nodes)
|
||||
local s = ffi.string(eastnode.data.str.value, eastnode.data.str.size)
|
||||
typ = format_string('%s(val=%q)', typ, s)
|
||||
end
|
||||
elseif typ == 'Option' then
|
||||
typ = ('%s(scope=%s,ident=%s)'):format(
|
||||
typ,
|
||||
tostring(intchar2lua(eastnode.data.opt.scope)),
|
||||
ffi.string(eastnode.data.opt.ident, eastnode.data.opt.ident_len))
|
||||
elseif typ == 'Environment' then
|
||||
typ = ('%s(ident=%s)'):format(
|
||||
typ,
|
||||
ffi.string(eastnode.data.env.ident, eastnode.data.env.ident_len))
|
||||
end
|
||||
ret_str = typ .. ':' .. ret_str
|
||||
local can_simplify = true
|
||||
|
@ -5,6 +5,7 @@ local cimport = helpers.cimport
|
||||
local kvi_new = helpers.kvi_new
|
||||
local kvi_init = helpers.kvi_init
|
||||
local conv_enum = helpers.conv_enum
|
||||
local child_call_once = helpers.child_call_once
|
||||
local make_enum_conv_tab = helpers.make_enum_conv_tab
|
||||
|
||||
local lib = cimport('./src/nvim/viml/parser/expressions.h')
|
||||
|
Loading…
Reference in New Issue
Block a user