aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/viml/parser/expressions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/viml/parser/expressions.c')
-rw-r--r--src/nvim/viml/parser/expressions.c369
1 files changed, 250 insertions, 119 deletions
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 3f30fe2a0e..75fcb17bf6 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -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 },
+
+ // Colons are not eligible for chaining, so nobody cares about associativity.
+ [kExprNodeColon] = { kEOpLvlColon, kEOpAssNo },
+
+ [kExprNodeTernary] = { kEOpLvlTernary, kEOpAssRight },
- [kExprNodeTernary] = kEOpAssRight,
+ [kExprNodeOr] = { kEOpLvlOr, kEOpAssLeft },
- [kExprNodeTernaryValue] = kEOpAssRight,
+ [kExprNodeAnd] = { kEOpLvlAnd, kEOpAssLeft },
- [kExprNodeComparison] = kEOpAssRight,
+ [kExprNodeTernaryValue] = { kEOpLvlTernaryValue, kEOpAssRight },
- [kExprNodeBinaryPlus] = kEOpAssLeft,
- [kExprNodeConcat] = kEOpAssLeft,
+ [kExprNodeComparison] = { kEOpLvlComparison, kEOpAssRight },
- [kExprNodeUnaryPlus] = kEOpAssNo,
+ [kExprNodeBinaryPlus] = { kEOpLvlAddition, kEOpAssLeft },
+ [kExprNodeBinaryMinus] = { kEOpLvlAddition, kEOpAssLeft },
+ [kExprNodeConcat] = { kEOpLvlAddition, kEOpAssLeft },
- [kExprNodeConcatOrSubscript] = kEOpAssLeft,
+ [kExprNodeMultiplication] = { kEOpLvlMultiplication, kEOpAssLeft },
+ [kExprNodeDivision] = { kEOpLvlMultiplication, kEOpAssLeft },
+ [kExprNodeMod] = { kEOpLvlMultiplication, kEOpAssLeft },
- [kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
+ [kExprNodeUnaryPlus] = { kEOpLvlUnary, kEOpAssNo },
+ [kExprNodeUnaryMinus] = { kEOpLvlUnary, kEOpAssNo },
+ [kExprNodeNot] = { kEOpLvlUnary, kEOpAssNo },
- [kExprNodeComplexIdentifier] = kEOpAssLeft,
- [kExprNodePlainIdentifier] = kEOpAssNo,
- [kExprNodePlainKey] = kEOpAssNo,
- [kExprNodeRegister] = kEOpAssNo,
- [kExprNodeInteger] = kEOpAssNo,
- [kExprNodeFloat] = 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
}
}
}