mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
viml/parser/expressions: Add support for the dot operator and numbers
This commit is contained in:
parent
163792e9b9
commit
21a5ce033c
@ -915,7 +915,8 @@ static inline void viml_pexpr_debug_print_token(
|
|||||||
//
|
//
|
||||||
// NVimUnaryPlus -> NVimUnaryOperator
|
// NVimUnaryPlus -> NVimUnaryOperator
|
||||||
// NVimBinaryPlus -> NVimBinaryOperator
|
// NVimBinaryPlus -> NVimBinaryOperator
|
||||||
// NVimConcatOrSubscript -> NVimBinaryOperator
|
// NVimConcat -> NVimBinaryOperator
|
||||||
|
// NVimConcatOrSubscript -> NVimConcat
|
||||||
//
|
//
|
||||||
// NVimRegister -> SpecialChar
|
// NVimRegister -> SpecialChar
|
||||||
// NVimNumber -> Number
|
// NVimNumber -> Number
|
||||||
@ -971,6 +972,7 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
|
|||||||
[kExprNodeUnknownFigure] = kEOpLvlParens,
|
[kExprNodeUnknownFigure] = kEOpLvlParens,
|
||||||
[kExprNodeLambda] = kEOpLvlParens,
|
[kExprNodeLambda] = kEOpLvlParens,
|
||||||
[kExprNodeDictLiteral] = kEOpLvlParens,
|
[kExprNodeDictLiteral] = kEOpLvlParens,
|
||||||
|
[kExprNodeListLiteral] = kEOpLvlParens,
|
||||||
|
|
||||||
[kExprNodeArrow] = kEOpLvlArrow,
|
[kExprNodeArrow] = kEOpLvlArrow,
|
||||||
|
|
||||||
@ -985,17 +987,21 @@ static const ExprOpLvl node_type_to_op_lvl[] = {
|
|||||||
[kExprNodeComparison] = kEOpLvlComparison,
|
[kExprNodeComparison] = kEOpLvlComparison,
|
||||||
|
|
||||||
[kExprNodeBinaryPlus] = kEOpLvlAddition,
|
[kExprNodeBinaryPlus] = kEOpLvlAddition,
|
||||||
|
[kExprNodeConcat] = kEOpLvlAddition,
|
||||||
|
|
||||||
[kExprNodeUnaryPlus] = kEOpLvlUnary,
|
[kExprNodeUnaryPlus] = kEOpLvlUnary,
|
||||||
|
|
||||||
|
[kExprNodeConcatOrSubscript] = kEOpLvlSubscript,
|
||||||
[kExprNodeSubscript] = kEOpLvlSubscript,
|
[kExprNodeSubscript] = kEOpLvlSubscript,
|
||||||
|
|
||||||
[kExprNodeCurlyBracesIdentifier] = kEOpLvlComplexIdentifier,
|
[kExprNodeCurlyBracesIdentifier] = kEOpLvlComplexIdentifier,
|
||||||
|
|
||||||
[kExprNodeComplexIdentifier] = kEOpLvlValue,
|
[kExprNodeComplexIdentifier] = kEOpLvlValue,
|
||||||
[kExprNodePlainIdentifier] = kEOpLvlValue,
|
[kExprNodePlainIdentifier] = kEOpLvlValue,
|
||||||
|
[kExprNodePlainKey] = kEOpLvlValue,
|
||||||
[kExprNodeRegister] = kEOpLvlValue,
|
[kExprNodeRegister] = kEOpLvlValue,
|
||||||
[kExprNodeListLiteral] = kEOpLvlValue,
|
[kExprNodeInteger] = kEOpLvlValue,
|
||||||
|
[kExprNodeFloat] = kEOpLvlValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ExprOpAssociativity node_type_to_op_ass[] = {
|
static const ExprOpAssociativity node_type_to_op_ass[] = {
|
||||||
@ -1008,6 +1014,7 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
|
|||||||
[kExprNodeUnknownFigure] = kEOpAssLeft,
|
[kExprNodeUnknownFigure] = kEOpAssLeft,
|
||||||
[kExprNodeLambda] = kEOpAssNo,
|
[kExprNodeLambda] = kEOpAssNo,
|
||||||
[kExprNodeDictLiteral] = kEOpAssNo,
|
[kExprNodeDictLiteral] = kEOpAssNo,
|
||||||
|
[kExprNodeListLiteral] = kEOpAssNo,
|
||||||
|
|
||||||
// Does not really matter.
|
// Does not really matter.
|
||||||
[kExprNodeArrow] = kEOpAssNo,
|
[kExprNodeArrow] = kEOpAssNo,
|
||||||
@ -1030,17 +1037,21 @@ static const ExprOpAssociativity node_type_to_op_ass[] = {
|
|||||||
[kExprNodeComparison] = kEOpAssRight,
|
[kExprNodeComparison] = kEOpAssRight,
|
||||||
|
|
||||||
[kExprNodeBinaryPlus] = kEOpAssLeft,
|
[kExprNodeBinaryPlus] = kEOpAssLeft,
|
||||||
|
[kExprNodeConcat] = kEOpAssLeft,
|
||||||
|
|
||||||
[kExprNodeUnaryPlus] = kEOpAssNo,
|
[kExprNodeUnaryPlus] = kEOpAssNo,
|
||||||
|
|
||||||
|
[kExprNodeConcatOrSubscript] = kEOpAssLeft,
|
||||||
[kExprNodeSubscript] = kEOpAssLeft,
|
[kExprNodeSubscript] = kEOpAssLeft,
|
||||||
|
|
||||||
[kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
|
[kExprNodeCurlyBracesIdentifier] = kEOpAssLeft,
|
||||||
|
|
||||||
[kExprNodeComplexIdentifier] = kEOpAssLeft,
|
[kExprNodeComplexIdentifier] = kEOpAssLeft,
|
||||||
[kExprNodePlainIdentifier] = kEOpAssNo,
|
[kExprNodePlainIdentifier] = kEOpAssNo,
|
||||||
|
[kExprNodePlainKey] = kEOpAssNo,
|
||||||
[kExprNodeRegister] = kEOpAssNo,
|
[kExprNodeRegister] = kEOpAssNo,
|
||||||
[kExprNodeListLiteral] = kEOpAssNo,
|
[kExprNodeInteger] = kEOpAssNo,
|
||||||
|
[kExprNodeFloat] = kEOpAssNo,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Get AST node priority level
|
/// Get AST node priority level
|
||||||
@ -1420,10 +1431,20 @@ ExprAST viml_pexpr_parse(ParserState *const pstate, const int flags)
|
|||||||
[kENodeArgument] = kELFlagIsNotCmp,
|
[kENodeArgument] = kELFlagIsNotCmp,
|
||||||
[kENodeArgumentSeparator] = kELFlagForbidScope,
|
[kENodeArgumentSeparator] = kELFlagForbidScope,
|
||||||
};
|
};
|
||||||
// FIXME Determine when (not) to allow floating-point numbers.
|
const bool is_concat_or_subscript = (
|
||||||
|
want_node == kENodeValue
|
||||||
|
&& kv_size(ast_stack) > 1
|
||||||
|
&& (*kv_Z(ast_stack, 1))->type == kExprNodeConcatOrSubscript);
|
||||||
const int lexer_additional_flags = (
|
const int lexer_additional_flags = (
|
||||||
kELFlagPeek
|
kELFlagPeek
|
||||||
| ((flags & kExprFlagsDisallowEOC) ? kELFlagForbidEOC : 0));
|
| ((flags & kExprFlagsDisallowEOC) ? kELFlagForbidEOC : 0)
|
||||||
|
| ((want_node == kENodeValue
|
||||||
|
&& (kv_size(ast_stack) == 1
|
||||||
|
|| ((*kv_Z(ast_stack, 1))->type != kExprNodeConcat
|
||||||
|
&& ((*kv_Z(ast_stack, 1))->type
|
||||||
|
!= kExprNodeConcatOrSubscript))))
|
||||||
|
? kELFlagAllowFloat
|
||||||
|
: 0));
|
||||||
LexExprToken cur_token = viml_pexpr_next_token(
|
LexExprToken cur_token = viml_pexpr_next_token(
|
||||||
pstate, want_node_to_lexer_flags[want_node] | lexer_additional_flags);
|
pstate, want_node_to_lexer_flags[want_node] | lexer_additional_flags);
|
||||||
if (cur_token.type == kExprLexEOC) {
|
if (cur_token.type == kExprLexEOC) {
|
||||||
@ -1456,11 +1477,42 @@ viml_pexpr_parse_process_token:
|
|||||||
ExprASTNode *cur_node = NULL;
|
ExprASTNode *cur_node = NULL;
|
||||||
assert((want_node == kENodeValue || want_node == kENodeArgument)
|
assert((want_node == kENodeValue || want_node == kENodeArgument)
|
||||||
== (*top_node_p == NULL));
|
== (*top_node_p == NULL));
|
||||||
|
// Note: in Vim whether expression "cond?d.a:2" is valid depends both on
|
||||||
|
// "cond" and whether "d" is a dictionary: expression is valid if condition
|
||||||
|
// is true and "d" is a dictionary (with "a" key or it will complain about
|
||||||
|
// missing one, but this is not relevant); if any of the requirements is
|
||||||
|
// broken then this thing is parsed as "d . a:2" yielding missing colon
|
||||||
|
// error. This parser does not allow such ambiguity, especially because it
|
||||||
|
// simply can’t: whether "d" is a dictionary is not known at the parsing
|
||||||
|
// time.
|
||||||
|
//
|
||||||
|
// Here example will always contain a concat with "a:2" sucking colon,
|
||||||
|
// making expression invalid both because there is no longer a spare colon
|
||||||
|
// for ternary and because concatenating dictionary with anything is not
|
||||||
|
// valid. There are more cases when this will make a difference though.
|
||||||
|
const bool node_is_key = (
|
||||||
|
is_concat_or_subscript
|
||||||
|
&& (cur_token.type == kExprLexPlainIdentifier
|
||||||
|
? (!cur_token.data.var.autoload
|
||||||
|
&& cur_token.data.var.scope == 0)
|
||||||
|
: (cur_token.type == kExprLexNumber))
|
||||||
|
&& prev_token.type != kExprLexSpacing);
|
||||||
|
if (is_concat_or_subscript && !node_is_key) {
|
||||||
|
// Note: in Vim "d. a" (this is the reason behind `prev_token.type !=
|
||||||
|
// kExprLexSpacing` part of the condition) as well as any other "d.{expr}"
|
||||||
|
// where "{expr}" does not look like a key is invalid whenever "d" happens
|
||||||
|
// to be a dictionary. Since parser has no idea whether preceding
|
||||||
|
// expression is actually a dictionary it can’t outright reject anything,
|
||||||
|
// so it turns kExprNodeConcatOrSubscript into kExprNodeConcat instead,
|
||||||
|
// which will yield different errors then Vim does in a number of
|
||||||
|
// circumstances, and in any case runtime and not parse time errors.
|
||||||
|
(*kv_Z(ast_stack, 1))->type = kExprNodeConcat;
|
||||||
|
}
|
||||||
if ((want_node == kENodeArgumentSeparator
|
if ((want_node == kENodeArgumentSeparator
|
||||||
&& tok_type != kExprLexComma
|
&& tok_type != kExprLexComma
|
||||||
&& tok_type != kExprLexArrow)
|
&& tok_type != kExprLexArrow)
|
||||||
|| (want_node == kENodeArgument
|
|| (want_node == kENodeArgument
|
||||||
&& !(tok_type == kExprLexPlainIdentifier
|
&& !(cur_token.type == kExprLexPlainIdentifier
|
||||||
&& cur_token.data.var.scope == 0
|
&& cur_token.data.var.scope == 0
|
||||||
&& !cur_token.data.var.autoload)
|
&& !cur_token.data.var.autoload)
|
||||||
&& tok_type != kExprLexArrow)) {
|
&& tok_type != kExprLexArrow)) {
|
||||||
@ -1844,7 +1896,10 @@ viml_pexpr_parse_figure_brace_closing_error:
|
|||||||
want_node = (want_node == kENodeArgument
|
want_node = (want_node == kENodeArgument
|
||||||
? kENodeArgumentSeparator
|
? kENodeArgumentSeparator
|
||||||
: kENodeOperator);
|
: kENodeOperator);
|
||||||
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainIdentifier);
|
NEW_NODE_WITH_CUR_POS(cur_node,
|
||||||
|
(node_is_key
|
||||||
|
? kExprNodePlainKey
|
||||||
|
: kExprNodePlainIdentifier));
|
||||||
cur_node->data.var.scope = cur_token.data.var.scope;
|
cur_node->data.var.scope = cur_token.data.var.scope;
|
||||||
const size_t scope_shift = (cur_token.data.var.scope == 0
|
const size_t scope_shift = (cur_token.data.var.scope == 0
|
||||||
? 0
|
? 0
|
||||||
@ -1854,6 +1909,7 @@ viml_pexpr_parse_figure_brace_closing_error:
|
|||||||
cur_node->data.var.ident_len = cur_token.len - scope_shift;
|
cur_node->data.var.ident_len = cur_token.len - scope_shift;
|
||||||
*top_node_p = cur_node;
|
*top_node_p = cur_node;
|
||||||
if (scope_shift) {
|
if (scope_shift) {
|
||||||
|
assert(!node_is_key);
|
||||||
viml_parser_highlight(pstate, cur_token.start, 1,
|
viml_parser_highlight(pstate, cur_token.start, 1,
|
||||||
HL(IdentifierScope));
|
HL(IdentifierScope));
|
||||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
|
viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
|
||||||
@ -1863,7 +1919,9 @@ viml_pexpr_parse_figure_brace_closing_error:
|
|||||||
viml_parser_highlight(pstate, shifted_pos(cur_token.start,
|
viml_parser_highlight(pstate, shifted_pos(cur_token.start,
|
||||||
scope_shift),
|
scope_shift),
|
||||||
cur_token.len - scope_shift,
|
cur_token.len - scope_shift,
|
||||||
HL(Identifier));
|
(node_is_key
|
||||||
|
? HL(IdentifierKey)
|
||||||
|
: HL(Identifier)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cur_token.data.var.scope == 0) {
|
if (cur_token.data.var.scope == 0) {
|
||||||
@ -1882,6 +1940,40 @@ viml_pexpr_parse_figure_brace_closing_error:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kExprLexNumber: {
|
||||||
|
if (want_node != kENodeValue) {
|
||||||
|
OP_MISSING;
|
||||||
|
}
|
||||||
|
if (node_is_key) {
|
||||||
|
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainKey);
|
||||||
|
cur_node->data.var.ident = pline.data + cur_token.start.col;
|
||||||
|
cur_node->data.var.ident_len = cur_token.len;
|
||||||
|
HL_CUR_TOKEN(IdentifierKey);
|
||||||
|
} else if (cur_token.data.num.is_float) {
|
||||||
|
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeFloat);
|
||||||
|
cur_node->data.flt.value = cur_token.data.num.val.floating;
|
||||||
|
HL_CUR_TOKEN(Float);
|
||||||
|
} else {
|
||||||
|
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeInteger);
|
||||||
|
cur_node->data.num.value = cur_token.data.num.val.integer;
|
||||||
|
HL_CUR_TOKEN(Number);
|
||||||
|
}
|
||||||
|
want_node = kENodeOperator;
|
||||||
|
*top_node_p = cur_node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kExprLexDot: {
|
||||||
|
ADD_VALUE_IF_MISSING(_("E15: Unexpected dot: %.*s"));
|
||||||
|
if (prev_token.type == kExprLexSpacing) {
|
||||||
|
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeConcat);
|
||||||
|
HL_CUR_TOKEN(Concat);
|
||||||
|
} else {
|
||||||
|
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeConcatOrSubscript);
|
||||||
|
HL_CUR_TOKEN(ConcatOrSubscript);
|
||||||
|
}
|
||||||
|
ADD_OP_NODE(cur_node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case kExprLexParenthesis: {
|
case kExprLexParenthesis: {
|
||||||
if (cur_token.data.brc.closing) {
|
if (cur_token.data.brc.closing) {
|
||||||
if (want_node == kENodeValue) {
|
if (want_node == kENodeValue) {
|
||||||
|
@ -166,6 +166,8 @@ typedef enum {
|
|||||||
/// Looks like "string", "g:Foo", etc: consists from a single
|
/// Looks like "string", "g:Foo", etc: consists from a single
|
||||||
/// kExprLexPlainIdentifier token.
|
/// kExprLexPlainIdentifier token.
|
||||||
kExprNodePlainIdentifier = 'i',
|
kExprNodePlainIdentifier = 'i',
|
||||||
|
/// Plain dictionary key, for use with kExprNodeConcatOrSubscript
|
||||||
|
kExprNodePlainKey = 'k',
|
||||||
/// Complex identifier: variable/function name with curly braces
|
/// Complex identifier: variable/function name with curly braces
|
||||||
kExprNodeComplexIdentifier = 'I',
|
kExprNodeComplexIdentifier = 'I',
|
||||||
/// Figure brace expression which is not yet known
|
/// Figure brace expression which is not yet known
|
||||||
@ -180,6 +182,19 @@ typedef enum {
|
|||||||
kExprNodeColon = ':', ///< Colon “operator”.
|
kExprNodeColon = ':', ///< Colon “operator”.
|
||||||
kExprNodeArrow = '>', ///< Arrow “operator”.
|
kExprNodeArrow = '>', ///< Arrow “operator”.
|
||||||
kExprNodeComparison = '=', ///< Various comparison operators.
|
kExprNodeComparison = '=', ///< Various comparison operators.
|
||||||
|
/// Concat operator
|
||||||
|
///
|
||||||
|
/// To be only used in cases when it is known for sure it is not a subscript.
|
||||||
|
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.
|
||||||
} ExprASTNodeType;
|
} ExprASTNodeType;
|
||||||
|
|
||||||
typedef struct expr_ast_node ExprASTNode;
|
typedef struct expr_ast_node ExprASTNode;
|
||||||
@ -219,7 +234,7 @@ struct expr_ast_node {
|
|||||||
/// Points to inside parser reader state.
|
/// Points to inside parser reader state.
|
||||||
const char *ident;
|
const char *ident;
|
||||||
size_t ident_len; ///< Actual identifier length.
|
size_t ident_len; ///< Actual identifier length.
|
||||||
} var; ///< For kExprNodePlainIdentifier.
|
} var; ///< For kExprNodePlainIdentifier and kExprNodePlainKey.
|
||||||
struct {
|
struct {
|
||||||
bool got_colon; ///< True if colon was seen.
|
bool got_colon; ///< True if colon was seen.
|
||||||
} ter; ///< For kExprNodeTernaryValue.
|
} ter; ///< For kExprNodeTernaryValue.
|
||||||
@ -228,6 +243,12 @@ struct expr_ast_node {
|
|||||||
ExprCaseCompareStrategy ccs; ///< Case comparison strategy.
|
ExprCaseCompareStrategy ccs; ///< Case comparison strategy.
|
||||||
bool inv; ///< True if comparison is to be inverted.
|
bool inv; ///< True if comparison is to be inverted.
|
||||||
} cmp; ///< For kExprNodeComparison.
|
} cmp; ///< For kExprNodeComparison.
|
||||||
|
struct {
|
||||||
|
uvarnumber_T value;
|
||||||
|
} num; ///< For kExprNodeInteger.
|
||||||
|
struct {
|
||||||
|
float_T value;
|
||||||
|
} flt; ///< For kExprNodeFloat.
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ make_enum_conv_tab(lib, {
|
|||||||
'kExprNodeNested',
|
'kExprNodeNested',
|
||||||
'kExprNodeCall',
|
'kExprNodeCall',
|
||||||
'kExprNodePlainIdentifier',
|
'kExprNodePlainIdentifier',
|
||||||
|
'kExprNodePlainKey',
|
||||||
'kExprNodeComplexIdentifier',
|
'kExprNodeComplexIdentifier',
|
||||||
'kExprNodeUnknownFigure',
|
'kExprNodeUnknownFigure',
|
||||||
'kExprNodeLambda',
|
'kExprNodeLambda',
|
||||||
@ -86,6 +87,10 @@ make_enum_conv_tab(lib, {
|
|||||||
'kExprNodeColon',
|
'kExprNodeColon',
|
||||||
'kExprNodeArrow',
|
'kExprNodeArrow',
|
||||||
'kExprNodeComparison',
|
'kExprNodeComparison',
|
||||||
|
'kExprNodeConcat',
|
||||||
|
'kExprNodeConcatOrSubscript',
|
||||||
|
'kExprNodeInteger',
|
||||||
|
'kExprNodeFloat',
|
||||||
}, '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)
|
||||||
@ -118,6 +123,9 @@ local function eastnode2lua(pstate, eastnode, checked_nodes)
|
|||||||
typ = typ .. ('(scope=%s,ident=%s)'):format(
|
typ = typ .. ('(scope=%s,ident=%s)'):format(
|
||||||
tostring(intchar2lua(eastnode.data.var.scope)),
|
tostring(intchar2lua(eastnode.data.var.scope)),
|
||||||
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
|
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
|
||||||
|
elseif typ == 'PlainKey' then
|
||||||
|
typ = typ .. ('(key=%s)'):format(
|
||||||
|
ffi.string(eastnode.data.var.ident, eastnode.data.var.ident_len))
|
||||||
elseif (typ == 'UnknownFigure' or typ == 'DictLiteral'
|
elseif (typ == 'UnknownFigure' or typ == 'DictLiteral'
|
||||||
or typ == 'CurlyBracesIdentifier' or typ == 'Lambda') then
|
or typ == 'CurlyBracesIdentifier' or typ == 'Lambda') then
|
||||||
typ = typ .. ('(%s)'):format(
|
typ = typ .. ('(%s)'):format(
|
||||||
@ -128,6 +136,10 @@ local function eastnode2lua(pstate, eastnode, checked_nodes)
|
|||||||
typ = typ .. ('(type=%s,inv=%u,ccs=%s)'):format(
|
typ = typ .. ('(type=%s,inv=%u,ccs=%s)'):format(
|
||||||
conv_cmp_type(eastnode.data.cmp.type), eastnode.data.cmp.inv and 1 or 0,
|
conv_cmp_type(eastnode.data.cmp.type), eastnode.data.cmp.inv and 1 or 0,
|
||||||
conv_ccs(eastnode.data.cmp.ccs))
|
conv_ccs(eastnode.data.cmp.ccs))
|
||||||
|
elseif typ == 'Integer' then
|
||||||
|
typ = typ .. ('(val=%u)'):format(tonumber(eastnode.data.num.value))
|
||||||
|
elseif typ == 'Float' then
|
||||||
|
typ = typ .. ('(val=%e)'):format(tonumber(eastnode.data.flt.value))
|
||||||
end
|
end
|
||||||
ret_str = typ .. ':' .. ret_str
|
ret_str = typ .. ':' .. ret_str
|
||||||
local can_simplify = true
|
local can_simplify = true
|
||||||
@ -190,6 +202,8 @@ end)
|
|||||||
|
|
||||||
describe('Expressions parser', function()
|
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
|
||||||
|
|
||||||
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)
|
||||||
@ -3649,4 +3663,284 @@ describe('Expressions parser', function()
|
|||||||
hl('Identifier', 'b', 1),
|
hl('Identifier', 'b', 1),
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
itp('works with concat/subscript', function()
|
||||||
|
check_parsing('.', 0, {
|
||||||
|
-- 0
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:0:.',
|
||||||
|
children = {
|
||||||
|
'Missing:0:0:',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err = {
|
||||||
|
arg = '.',
|
||||||
|
msg = 'E15: Unexpected dot: %.*s',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('InvalidConcatOrSubscript', '.'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('a.', 0, {
|
||||||
|
-- 01
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:1:.',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:0:a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err = {
|
||||||
|
arg = '',
|
||||||
|
msg = 'E15: Expected value, got EOC: %.*s',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Identifier', 'a'),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('a.b', 0, {
|
||||||
|
-- 012
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:1:.',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:0:a',
|
||||||
|
'PlainKey(key=b):0:2:b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Identifier', 'a'),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', 'b'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('1.2', 0, {
|
||||||
|
-- 012
|
||||||
|
ast = {
|
||||||
|
'Float(val=1.200000e+00):0:0:1.2',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Float', '1.2'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('1.2 + 1.3e-5', 0, {
|
||||||
|
-- 012345678901
|
||||||
|
-- 0 1
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'BinaryPlus:0:3: +',
|
||||||
|
children = {
|
||||||
|
'Float(val=1.200000e+00):0:0:1.2',
|
||||||
|
'Float(val=1.300000e-05):0:5: 1.3e-5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Float', '1.2'),
|
||||||
|
hl('BinaryPlus', '+', 1),
|
||||||
|
hl('Float', '1.3e-5', 1),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('a . 1.2 + 1.3e-5', 0, {
|
||||||
|
-- 0123456789012345
|
||||||
|
-- 0 1
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'BinaryPlus:0:7: +',
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
'Concat:0:1: .',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:0:a',
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:5:.',
|
||||||
|
children = {
|
||||||
|
'Integer(val=1):0:3: 1',
|
||||||
|
'PlainKey(key=2):0:6:2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'Float(val=1.300000e-05):0:9: 1.3e-5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Identifier', 'a'),
|
||||||
|
hl('Concat', '.', 1),
|
||||||
|
hl('Number', '1', 1),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '2'),
|
||||||
|
hl('BinaryPlus', '+', 1),
|
||||||
|
hl('Float', '1.3e-5', 1),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('1.3e-5 + 1.2 . a', 0, {
|
||||||
|
-- 0123456789012345
|
||||||
|
-- 0 1
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'Concat:0:12: .',
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
'BinaryPlus:0:6: +',
|
||||||
|
children = {
|
||||||
|
'Float(val=1.300000e-05):0:0:1.3e-5',
|
||||||
|
'Float(val=1.200000e+00):0:8: 1.2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:14: a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Float', '1.3e-5'),
|
||||||
|
hl('BinaryPlus', '+', 1),
|
||||||
|
hl('Float', '1.2', 1),
|
||||||
|
hl('Concat', '.', 1),
|
||||||
|
hl('Identifier', 'a', 1),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('1.3e-5 + a . 1.2', 0, {
|
||||||
|
-- 0123456789012345
|
||||||
|
-- 0 1
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'Concat:0:10: .',
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
'BinaryPlus:0:6: +',
|
||||||
|
children = {
|
||||||
|
'Float(val=1.300000e-05):0:0:1.3e-5',
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:8: a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:14:.',
|
||||||
|
children = {
|
||||||
|
'Integer(val=1):0:12: 1',
|
||||||
|
'PlainKey(key=2):0:15:2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Float', '1.3e-5'),
|
||||||
|
hl('BinaryPlus', '+', 1),
|
||||||
|
hl('Identifier', 'a', 1),
|
||||||
|
hl('Concat', '.', 1),
|
||||||
|
hl('Number', '1', 1),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '2'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('1.2.3', 0, {
|
||||||
|
-- 01234
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:3:.',
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:1:.',
|
||||||
|
children = {
|
||||||
|
'Integer(val=1):0:0:1',
|
||||||
|
'PlainKey(key=2):0:2:2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'PlainKey(key=3):0:4:3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Number', '1'),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '2'),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '3'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('a.1.2', 0, {
|
||||||
|
-- 01234
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:3:.',
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:1:.',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:0:a',
|
||||||
|
'PlainKey(key=1):0:2:1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'PlainKey(key=2):0:4:2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Identifier', 'a'),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '1'),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '2'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('a . 1.2', 0, {
|
||||||
|
-- 0123456
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'Concat:0:1: .',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:0:a',
|
||||||
|
{
|
||||||
|
'ConcatOrSubscript:0:5:.',
|
||||||
|
children = {
|
||||||
|
'Integer(val=1):0:3: 1',
|
||||||
|
'PlainKey(key=2):0:6:2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('Identifier', 'a'),
|
||||||
|
hl('Concat', '.', 1),
|
||||||
|
hl('Number', '1', 1),
|
||||||
|
hl('ConcatOrSubscript', '.'),
|
||||||
|
hl('IdentifierKey', '2'),
|
||||||
|
})
|
||||||
|
|
||||||
|
check_parsing('+a . +b', 0, {
|
||||||
|
-- 0123456
|
||||||
|
ast = {
|
||||||
|
{
|
||||||
|
'Concat:0:2: .',
|
||||||
|
children = {
|
||||||
|
{
|
||||||
|
'UnaryPlus:0:0:+',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=a):0:1:a',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'UnaryPlus:0:4: +',
|
||||||
|
children = {
|
||||||
|
'PlainIdentifier(scope=0,ident=b):0:6:b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
hl('UnaryPlus', '+'),
|
||||||
|
hl('Identifier', 'a'),
|
||||||
|
hl('Concat', '.', 1),
|
||||||
|
hl('UnaryPlus', '+', 1),
|
||||||
|
hl('Identifier', 'b'),
|
||||||
|
})
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user