Data Structures | Macros | Enumerations | Functions | Variables
expressions.c File Reference
#include <stdbool.h>
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include "nvim/vim.h"
#include "nvim/memory.h"
#include "nvim/types.h"
#include "nvim/charset.h"
#include "nvim/ascii.h"
#include "nvim/lib/kvec.h"
#include "nvim/eval/typval.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"

Data Structures

struct  StringShift
 

Macros

#define vim_str2nr(s, ...)   vim_str2nr((const char_u *)(s), __VA_ARGS__)
 VimL expression parser. More...
 
#define AUTOLOAD_CHAR   '#'
 Character used as a separator in autoload function/variable names. More...
 
#define GET_CCS(ret, pline)
 
#define BRACKET(typ, opning, clsing)
 
#define CHAR(typ, ch)
 
#define MUL(mul_type, ch)
 
#define CHARREG(typ, cond)
 
#define ISCTRL(schar)   (schar < ' ')
 
#define ISWORD_OR_AUTOLOAD(x)   (ascii_isident(x) || (x) == AUTOLOAD_CHAR)
 
#define OPTNAMEMISS(ret)
 
#define CHAR_OR_ASSIGN(ch, ch_type, ass_type)
 
#define ADDSTR(...)
 
#define TKNARGS(tkn_type, ...)
 
#define HL(g)   (is_invalid ? "NvimInvalid" #g : "Nvim" #g)
 Get highlight group name. More...
 
#define HL_CUR_TOKEN(g)
 Highlight current token with the given group. More...
 
#define NEW_NODE(type)   viml_pexpr_new_node(type)
 Allocate new node, saving some values. More...
 
#define POS_FROM_TOKEN(cur_node, cur_token)
 
#define NEW_NODE_WITH_CUR_POS(cur_node, typ)
 
#define MAY_HAVE_NEXT_EXPR   (kv_size(ast_stack) == 1)
 
#define ADD_OP_NODE(cur_node)
 
#define OP_MISSING
 
#define ADD_VALUE_IF_MISSING(msg)
 
#define ERROR_FROM_TOKEN_AND_MSG(cur_token, msg)
 Set error from the given token and given message. More...
 
#define ERROR_FROM_NODE_AND_MSG(node, msg)
 Like ERROR_FROM_TOKEN_AND_MSG, but gets position from a node. More...
 
#define ERROR_FROM_TOKEN(cur_token)   ERROR_FROM_TOKEN_AND_MSG(cur_token, cur_token.data.err.msg)
 Set error from the given kExprLexInvalid token. More...
 
#define SELECT_FIGURE_BRACE_TYPE(node, new_type, hl)
 
#define ADD_IDENT(new_ident_node_code, hl)
 
#define SINGLE_CHAR_ESC(ch, real_ch)
 
#define SIMPLE_UB_OP(op)
 
#define SIMPLE_B_OP(op, msg)
 
#define MUL_OP(lex_op_tail, node_op_tail)
 
#define EXP_VAL_COLON   "E15: Expected value, got colon: %.*s"
 
#define HL_ASGN(asgn, hl)   case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }
 

Enumerations

enum  ExprASTParseType { kEPTExpr = 0, kEPTLambdaArguments, kEPTAssignment, kEPTSingleAssignment }
 Parse type: what is being parsed currently. More...
 
enum  ExprOpAssociativity { kEOpAssNo = 'n', kEOpAssLeft = 'l', kEOpAssRight = 'r' }
 Operator associativity. More...
 

Functions

typedef kvec_withinit_t (ExprASTNode **, 16)
 Which nodes may be wanted. More...
 
typedef kvec_withinit_t (ExprASTParseType, 4)
 Operator priority level. More...
 
LexExprToken viml_pexpr_next_token (ParserState *const pstate, const int flags) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
 
const char * viml_pexpr_repr_token (const ParserState *const pstate, const LexExprToken token, size_t *const ret_size) FUNC_ATTR_WARN_UNUSED_RESULT
 
void viml_pexpr_free_ast (ExprAST ast)
 
ExprAST viml_pexpr_parse (ParserState *const pstate, const int flags) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
 

Variables

 ExprASTWantedNode
 
 ExprOpLvl
 
const char *const eltkn_cmp_type_tab []
 Array mapping ExprComparisonType values to their stringified versions. More...
 
const char *const expr_asgn_type_tab []
 Array mapping ExprAssignmentType values to their stringified versions. More...
 
const char *const ccs_tab []
 Array mapping ExprCaseCompareStrategy values to their stringified versions. More...
 
const char *const east_node_type_tab []
 Array mapping ExprASTNodeType values to their stringified versions. More...
 
const uint8_t node_maxchildren []
 Array mapping ExprASTNodeType to maximum amount of children node may have. More...
 

Macro Definition Documentation

#define ADD_IDENT (   new_ident_node_code,
  hl 
)

Add identifier which should constitute complex identifier node

This one is to be called only in case want_node is kENodeOperator.

Parameters
new_ident_node_codeCode used to create a new identifier node and update want_node and ast_stack, without a trailing semicolon.
hlHighlighting name to use, passed as an argument to HL.
#define ADD_OP_NODE (   cur_node)
Value:
is_invalid |= !viml_pexpr_handle_bop(pstate, &ast_stack, cur_node, \
&want_node, &ast.err)

Add operator node

Parameters
[in]cur_nodeNode to add.
#define ADD_VALUE_IF_MISSING (   msg)
Value:
do { \
if (want_node == kENodeValue) { \
(*top_node_p)->len = 0; \
want_node = kENodeOperator; \
} \
} while (0)
if(len)
Definition: encode.c:222
#define ERROR_FROM_TOKEN_AND_MSG(cur_token, msg)
Set error from the given token and given message.
Definition: expressions.c:1441
#define NEW_NODE_WITH_CUR_POS(cur_node, typ)
Definition: expressions.c:1357
Definition: expressions.h:194
err msg
Definition: helpers.c:1417

Record missing value: for things like "* 5"

Parameters
[in]msgError message.
#define ADDSTR (   ...)
Value:
do { \
p += snprintf(p, (size_t)(sizeof(ret) - (size_t)(p - ret)), __VA_ARGS__); \
if (p >= e) { \
goto viml_pexpr_repr_token_end; \
} \
} while (0)
if(len)
Definition: encode.c:222
int int ret
Definition: eval.c:20314
char_u * p
Definition: eval.c:2063
#define AUTOLOAD_CHAR   '#'

Character used as a separator in autoload function/variable names.

#define BRACKET (   typ,
  opning,
  clsing 
)
Value:
case opning: \
case clsing: { \
ret.type = typ; \
ret.data.brc.closing = (schar == clsing); \
break; \
}
int int ret
Definition: eval.c:20314
#define CHAR (   typ,
  ch 
)
Value:
case ch: { \
ret.type = typ; \
break; \
}
int int ret
Definition: eval.c:20314
#define CHAR_OR_ASSIGN (   ch,
  ch_type,
  ass_type 
)
Value:
case ch: { \
if (pline.size > 1 && pline.data[1] == '=') { \
ret.len++; \
ret.data.ass.type = ass_type; \
} else { \
ret.type = ch_type; \
} \
break; \
}
if(len)
Definition: encode.c:222
int int ret
Definition: eval.c:20314
Assignment: = or {op}=.
Definition: expressions.h:54
#define CHARREG (   typ,
  cond 
)
Value:
do { \
ret.type = typ; \
for (; (ret.len < pline.size \
&& cond(pline.data[ret.len])) \
; ret.len++) { \
} \
} while (0)
int int ret
Definition: eval.c:20314
for(size_t i=1;i< ARRAY_SIZE(argv);i++)
Definition: typval.c:1215
#define ERROR_FROM_NODE_AND_MSG (   node,
  msg 
)
Value:
do { \
is_invalid = true; \
east_set_error(pstate, &ast.err, msg, node->start); \
} while (0)
err msg
Definition: helpers.c:1417

Like ERROR_FROM_TOKEN_AND_MSG, but gets position from a node.

#define ERROR_FROM_TOKEN (   cur_token)    ERROR_FROM_TOKEN_AND_MSG(cur_token, cur_token.data.err.msg)

Set error from the given kExprLexInvalid token.

#define ERROR_FROM_TOKEN_AND_MSG (   cur_token,
  msg 
)
Value:
do { \
is_invalid = true; \
east_set_error(pstate, &ast.err, msg, cur_token.start); \
} while (0)
err msg
Definition: helpers.c:1417

Set error from the given token and given message.

#define EXP_VAL_COLON   "E15: Expected value, got colon: %.*s"
#define GET_CCS (   ret,
  pline 
)
Value:
do { \
if (ret.len < pline.size \
&& strchr("?#", pline.data[ret.len]) != NULL) { \
ret.data.cmp.ccs = \
(ExprCaseCompareStrategy)pline.data[ret.len]; \
ret.len++; \
} else { \
ret.data.cmp.ccs = kCCStrategyUseOption; \
} \
} while (0)
if(len)
Definition: encode.c:222
int int ret
Definition: eval.c:20314
return NULL
Definition: eval.c:23050
ExprCaseCompareStrategy
Definition: expressions.h:16
Definition: expressions.h:17
#define HL (   g)    (is_invalid ? "NvimInvalid" #g : "Nvim" #g)

Get highlight group name.

#define HL_ASGN (   asgn,
  hl 
)    case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }
#define HL_CUR_TOKEN (   g)
Value:
viml_parser_highlight(pstate, cur_token.start, cur_token.len, \
HL(g))
#define HL(g)
Get highlight group name.
Definition: expressions.c:1330

Highlight current token with the given group.

#define ISCTRL (   schar)    (schar < ' ')
#define ISWORD_OR_AUTOLOAD (   x)    (ascii_isident(x) || (x) == AUTOLOAD_CHAR)
#define MAY_HAVE_NEXT_EXPR   (kv_size(ast_stack) == 1)

Check whether it is possible to have next expression after current

For :echo: :echo @a @a is a valid expression. :echo (@a @a) is not.

#define MUL (   mul_type,
  ch 
)
Value:
case ch: { \
ret.data.mul.type = mul_type; \
break; \
}
int int ret
Definition: eval.c:20314
Multiplication, division or modulo operator.
Definition: expressions.h:37
#define MUL_OP (   lex_op_tail,
  node_op_tail 
)
Value:
case kExprLexMul##lex_op_tail: { \
NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##node_op_tail); \
HL_CUR_TOKEN(node_op_tail); \
break; \
}
#define HL_CUR_TOKEN(g)
Highlight current token with the given group.
Definition: expressions.c:1333
#define NEW_NODE_WITH_CUR_POS(cur_node, typ)
Definition: expressions.c:1357
#define NEW_NODE (   type)    viml_pexpr_new_node(type)

Allocate new node, saving some values.

#define NEW_NODE_WITH_CUR_POS (   cur_node,
  typ 
)
Value:
do { \
(cur_node) = NEW_NODE(typ); \
POS_FROM_TOKEN((cur_node), cur_token); \
if (prev_token.type == kExprLexSpacing) { \
(cur_node)->start = prev_token.start; \
(cur_node)->len += prev_token.len; \
} \
} while (0)
if(len)
Definition: encode.c:222
#define NEW_NODE(type)
Allocate new node, saving some values.
Definition: expressions.c:1338
Spaces, tabs, newlines, etc.
Definition: expressions.h:26
#define POS_FROM_TOKEN(cur_node, cur_token)
Definition: expressions.c:1345

Allocate new node and set its position from the current token

If previous token happened to contain spacing then it will be included.

Parameters
cur_nodeVariable to save allocated node to.
typNode type.
#define OP_MISSING
Value:
do { \
/* Multiple expressions allowed, return without calling */ \
/* viml_parser_advance(). */ \
goto viml_pexpr_parse_end; \
} else { \
assert(*top_node_p != NULL); \
ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Missing operator: %.*s")); \
cur_node->len = 0; \
ADD_OP_NODE(cur_node); \
goto viml_pexpr_parse_process_token; \
} \
} while (0)
#define _(x)
Definition: gettext.h:20
if(len)
Definition: encode.c:222
return NULL
Definition: eval.c:23050
#define ERROR_FROM_TOKEN_AND_MSG(cur_token, msg)
Set error from the given token and given message.
Definition: expressions.c:1441
Definition: expressions.h:195
Definition: expressions.h:333
#define NEW_NODE_WITH_CUR_POS(cur_node, typ)
Definition: expressions.c:1357
assert(len >=0)
#define ADD_OP_NODE(cur_node)
Definition: expressions.c:1376
#define MAY_HAVE_NEXT_EXPR
Definition: expressions.c:1370

Record missing operator: for things like

:echo @a @a

(allowed) or

:echo (@a @a)

(parsed as OpMissing(, )).

#define OPTNAMEMISS (   ret)
Value:
do { \
ret.data.err.type = kExprLexOption; \
ret.data.err.msg = _("E112: Option name missing: %.*s"); \
} while (0)
#define _(x)
Definition: gettext.h:20
int int ret
Definition: eval.c:20314
&optionname option value.
Definition: expressions.h:44
Invalid token, indicaten an error.
Definition: expressions.h:24
#define POS_FROM_TOKEN (   cur_node,
  cur_token 
)
Value:
do { \
(cur_node)->start = cur_token.start; \
(cur_node)->len = cur_token.len; \
} while (0)

Set position of the given node to position from the given token

Parameters
cur_nodeNode to modify.
cur_tokenToken to set position from.
#define SELECT_FIGURE_BRACE_TYPE (   node,
  new_type,
  hl 
)
Value:
do { \
ExprASTNode *const node_ = (node); \
|| node_->type == kExprNode##new_type); \
node_->type = kExprNode##new_type; \
if (pstate->colors) { \
kv_A(*pstate->colors, node_->data.fig.opening_hl_idx).group = \
HL(hl); \
} \
} while (0)
#define HL(g)
Get highlight group name.
Definition: expressions.c:1330
if(len)
Definition: encode.c:222
assert(len >=0)
#define kv_A(v, i)
Definition: kvec.h:66
struct expr_ast_node ExprASTNode
Definition: expressions.h:257
Definition: expressions.h:218

Select figure brace type, altering highlighting as well if needed

Parameters
[out]nodeNode to modify type.
[in]new_typeNew type, one of ExprASTNodeType values without kExprNode prefix.
[in]hlCorresponding highlighting, passed as an argument to HL.
#define SIMPLE_B_OP (   op,
  msg 
)
Value:
case kExprLex##op: { \
ADD_VALUE_IF_MISSING(_("E15: Unexpected " msg ": %.*s")); \
NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##op); \
ADD_OP_NODE(cur_node); \
break; \
}
#define _(x)
Definition: gettext.h:20
#define HL_CUR_TOKEN(g)
Highlight current token with the given group.
Definition: expressions.c:1333
#define NEW_NODE_WITH_CUR_POS(cur_node, typ)
Definition: expressions.c:1357
err msg
Definition: helpers.c:1417
#define ADD_OP_NODE(cur_node)
Definition: expressions.c:1376
#define ADD_VALUE_IF_MISSING(msg)
Definition: expressions.c:1408
#define SIMPLE_UB_OP (   op)
Value:
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; \
}
if(len)
Definition: encode.c:222
#define HL_CUR_TOKEN(g)
Highlight current token with the given group.
Definition: expressions.c:1333
#define NEW_NODE_WITH_CUR_POS(cur_node, typ)
Definition: expressions.c:1357
#define kvi_push(v, x)
Definition: kvec.h:199
#define ADD_OP_NODE(cur_node)
Definition: expressions.c:1376
#define SINGLE_CHAR_ESC (   ch,
  real_ch 
)
Value:
case ch: { \
*v_p++ = real_ch; \
p++; \
break; \
}
char_u * p
Definition: eval.c:2063
#define TKNARGS (   tkn_type,
  ... 
)
Value:
case tkn_type: { \
ADDSTR(__VA_ARGS__); \
break; \
}
#define ADDSTR(...)
#define vim_str2nr (   s,
  ... 
)    vim_str2nr((const char_u *)(s), __VA_ARGS__)

VimL expression parser.

Enumeration Type Documentation

Parse type: what is being parsed currently.

Enumerator
kEPTExpr 

Parsing regular VimL expression.

kEPTLambdaArguments 

Parsing lambda arguments

Just like parsing function arguments, but it is valid to be ended with an arrow only.

kEPTAssignment 

Assignment: parsing for :let.

kEPTSingleAssignment 

Single assignment: used when lists are not allowed (i.e. when nesting)

Operator associativity.

Enumerator
kEOpAssNo 

Not associative / not applicable.

kEOpAssLeft 

Left associativity.

kEOpAssRight 

Right associativity.

Function Documentation

typedef kvec_withinit_t ( ExprASTNode **  ,
16   
)

Which nodes may be wanted.

Operators: function call, subscripts, binary operators, …

For unrestricted expressions.

Values: literals, variables, nested expressions, unary operators.

For unrestricted expressions as well, implies that top item in AST stack points to NULL.

typedef kvec_withinit_t ( ExprASTParseType  ,
 
)

Operator priority level.

< Addition, subtraction and concatenation.

< Multiplication, division and modulo.

< Unary operations: not, minus, plus.

< Subscripts.

< Values: literals, variables, nested expressions, …

void viml_pexpr_free_ast ( ExprAST  ast)

Free memory occupied by AST

Parameters
astAST stack to free.
LexExprToken viml_pexpr_next_token ( ParserState *const  pstate,
const int  flags 
)

Get next token for the VimL expression input

Parameters
pstateParser state.
[in]flagsFlags,
See also
LexExprFlags.
Returns
Next token.
ExprAST viml_pexpr_parse ( ParserState *const  pstate,
const int  flags 
)

Parse one VimL expression

Parameters
pstateParser state.
[in]flagsAdditional flags, see ExprParserFlags
Returns
Parsed AST.
const char* viml_pexpr_repr_token ( const ParserState *const  pstate,
const LexExprToken  token,
size_t *const  ret_size 
)

Represent token as a string

Intended for testing and debugging purposes.

Parameters
[in]pstateParser state, needed to get token string from it. May be NULL, in which case in place of obtaining part of the string represented by token only token length is returned.
[in]tokenToken to represent.
[out]ret_sizeReturn string size, for cases like NULs inside a string. May be NULL.
Returns
Token represented in a string form, in a static buffer (overwritten on each call).

Variable Documentation

const char* const ccs_tab[]
Initial value:
= {
[kCCStrategyUseOption] = "UseOption",
[kCCStrategyMatchCase] = "MatchCase",
[kCCStrategyIgnoreCase] = "IgnoreCase",
}
Definition: expressions.h:18
Definition: expressions.h:19
Definition: expressions.h:17

Array mapping ExprCaseCompareStrategy values to their stringified versions.

const char* const east_node_type_tab[]

Array mapping ExprASTNodeType values to their stringified versions.

const char* const eltkn_cmp_type_tab[]
Initial value:
= {
[kExprCmpEqual] = "Equal",
[kExprCmpMatches] = "Matches",
[kExprCmpGreater] = "Greater",
[kExprCmpGreaterOrEqual] = "GreaterOrEqual",
[kExprCmpIdentical] = "Identical",
}
Matches regex, not matches regex.
Definition: expressions.h:61
> or <=
Definition: expressions.h:62
>= or <.
Definition: expressions.h:63
Equality, unequality.
Definition: expressions.h:60
is or isnot
Definition: expressions.h:64

Array mapping ExprComparisonType values to their stringified versions.

const char* const expr_asgn_type_tab[]
Initial value:
= {
[kExprAsgnPlain] = "Plain",
[kExprAsgnAdd] = "Add",
[kExprAsgnSubtract] = "Subtract",
[kExprAsgnConcat] = "Concat",
}
Assignment augmented with concatenation: .=.
Definition: expressions.h:79
Assignment augmented with subtraction: -=.
Definition: expressions.h:78
Assignment augmented with addition: +=.
Definition: expressions.h:77
Plain assignment: =.
Definition: expressions.h:76

Array mapping ExprAssignmentType values to their stringified versions.

ExprASTWantedNode
ExprOpLvl
ExprOpLvl lvl
const uint8_t node_maxchildren[]

Array mapping ExprASTNodeType to maximum amount of children node may have.