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

◆ ADD_IDENT

#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.

◆ ADD_OP_NODE

#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.

◆ ADD_VALUE_IF_MISSING

#define ADD_VALUE_IF_MISSING (   msg)
Value:
do { \
if (want_node == kENodeValue) { \
ERROR_FROM_TOKEN_AND_MSG(cur_token, (msg)); \
NEW_NODE_WITH_CUR_POS((*top_node_p), kExprNodeMissing); \
(*top_node_p)->len = 0; \
want_node = kENodeOperator; \
} \
} while (0)

Record missing value: for things like "* 5"

Parameters
[in]msgError message.

◆ ADDSTR

#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)

◆ BRACKET

#define BRACKET (   typ,
  opning,
  clsing 
)
Value:
case opning: \
case clsing: { \
ret.type = typ; \
ret.data.brc.closing = (schar == clsing); \
break; \
}

◆ CHAR

#define CHAR (   typ,
  ch 
)
Value:
case ch: { \
ret.type = typ; \
break; \
}

◆ CHAR_OR_ASSIGN

#define CHAR_OR_ASSIGN (   ch,
  ch_type,
  ass_type 
)
Value:
case ch: { \
if (pline.size > 1 && pline.data[1] == '=') { \
ret.len++; \
ret.type = kExprLexAssignment; \
ret.data.ass.type = ass_type; \
} else { \
ret.type = ch_type; \
} \
break; \
}

◆ CHARREG

#define CHARREG (   typ,
  cond 
)
Value:
do { \
ret.type = typ; \
for (; (ret.len < pline.size \
&& cond(pline.data[ret.len])) \
; ret.len++) { \
} \
} while (0)

◆ ERROR_FROM_NODE_AND_MSG

#define ERROR_FROM_NODE_AND_MSG (   node,
  msg 
)
Value:
do { \
is_invalid = true; \
east_set_error(pstate, &ast.err, msg, node->start); \
} while (0)

Like ERROR_FROM_TOKEN_AND_MSG, but gets position from a node.

◆ ERROR_FROM_TOKEN

#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.

◆ ERROR_FROM_TOKEN_AND_MSG

#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)

Set error from the given token and given message.

◆ EXP_VAL_COLON

#define EXP_VAL_COLON   "E15: Expected value, got colon: %.*s"

◆ GET_CCS

#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)

◆ HL

#define HL (   g)    (is_invalid ? "NvimInvalid" #g : "Nvim" #g)

Get highlight group name.

◆ HL_ASGN

#define HL_ASGN (   asgn,
  hl 
)    case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }

◆ HL_CUR_TOKEN

#define HL_CUR_TOKEN (   g)
Value:
viml_parser_highlight(pstate, cur_token.start, cur_token.len, \
HL(g))

Highlight current token with the given group.

◆ ISCTRL

#define ISCTRL (   schar)    (schar < ' ')

◆ ISWORD_OR_AUTOLOAD

#define ISWORD_OR_AUTOLOAD (   x)    (ascii_isident(x) || (x) == AUTOLOAD_CHAR)

◆ MAY_HAVE_NEXT_EXPR

#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.

◆ MUL

#define MUL (   mul_type,
  ch 
)
Value:
case ch: { \
ret.type = kExprLexMultiplication; \
ret.data.mul.type = mul_type; \
break; \
}

◆ MUL_OP

#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; \
}

◆ NEW_NODE

#define NEW_NODE (   type)    viml_pexpr_new_node(type)

Allocate new node, saving some values.

◆ NEW_NODE_WITH_CUR_POS

#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)

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.

◆ OP_MISSING

#define OP_MISSING
Value:
do { \
if (flags & kExprFlagsMulti && MAY_HAVE_NEXT_EXPR) { \
/* 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")); \
NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeOpMissing); \
cur_node->len = 0; \
ADD_OP_NODE(cur_node); \
goto viml_pexpr_parse_process_token; \
} \
} while (0)

Record missing operator: for things like

:echo @a @a

(allowed) or

:echo (@a @a)

(parsed as OpMissing(, )).

◆ OPTNAMEMISS

#define OPTNAMEMISS (   ret)
Value:
do { \
ret.type = kExprLexInvalid; \
ret.data.err.type = kExprLexOption; \
ret.data.err.msg = _("E112: Option name missing: %.*s"); \
} while (0)

◆ POS_FROM_TOKEN

#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.

◆ SELECT_FIGURE_BRACE_TYPE

#define SELECT_FIGURE_BRACE_TYPE (   node,
  new_type,
  hl 
)
Value:
do { \
ExprASTNode *const node_ = (node); \
assert(node_->type == kExprNodeUnknownFigure \
|| 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)

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.

◆ SIMPLE_B_OP

#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); \
HL_CUR_TOKEN(op); \
ADD_OP_NODE(cur_node); \
break; \
}

◆ SIMPLE_UB_OP

#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; \
}

◆ SINGLE_CHAR_ESC

#define SINGLE_CHAR_ESC (   ch,
  real_ch 
)
Value:
case ch: { \
*v_p++ = real_ch; \
p++; \
break; \
}

◆ TKNARGS

#define TKNARGS (   tkn_type,
  ... 
)
Value:
case tkn_type: { \
ADDSTR(__VA_ARGS__); \
break; \
}

◆ vim_str2nr

#define vim_str2nr (   s,
  ... 
)    vim_str2nr((const char_u *)(s), __VA_ARGS__)

VimL expression parser.

Enumeration Type Documentation

◆ ExprASTParseType

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)

◆ ExprOpAssociativity

Operator associativity.

Enumerator
kEOpAssNo 

Not associative / not applicable.

kEOpAssLeft 

Left associativity.

kEOpAssRight 

Right associativity.

Function Documentation

◆ kvec_withinit_t() [1/2]

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.

◆ kvec_withinit_t() [2/2]

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, …

◆ viml_pexpr_free_ast()

void viml_pexpr_free_ast ( ExprAST  ast)

Free memory occupied by AST

Parameters
astAST stack to free.

◆ viml_pexpr_next_token()

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.

◆ viml_pexpr_parse()

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.

◆ viml_pexpr_repr_token()

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

◆ ass

◆ ccs_tab

const char* const ccs_tab[]
Initial value:
= {
[kCCStrategyUseOption] = "UseOption",
[kCCStrategyMatchCase] = "MatchCase",
[kCCStrategyIgnoreCase] = "IgnoreCase",
}

Array mapping ExprCaseCompareStrategy values to their stringified versions.

◆ east_node_type_tab

const char* const east_node_type_tab[]

Array mapping ExprASTNodeType values to their stringified versions.

◆ eltkn_cmp_type_tab

const char* const eltkn_cmp_type_tab[]
Initial value:
= {
[kExprCmpEqual] = "Equal",
[kExprCmpMatches] = "Matches",
[kExprCmpGreater] = "Greater",
[kExprCmpGreaterOrEqual] = "GreaterOrEqual",
[kExprCmpIdentical] = "Identical",
}

Array mapping ExprComparisonType values to their stringified versions.

◆ expr_asgn_type_tab

const char* const expr_asgn_type_tab[]
Initial value:
= {
[kExprAsgnPlain] = "Plain",
[kExprAsgnAdd] = "Add",
[kExprAsgnSubtract] = "Subtract",
[kExprAsgnConcat] = "Concat",
}

Array mapping ExprAssignmentType values to their stringified versions.

◆ ExprASTWantedNode

ExprASTWantedNode

◆ ExprOpLvl

ExprOpLvl

◆ lvl

ExprOpLvl lvl

◆ node_maxchildren

const uint8_t node_maxchildren[]

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

_
#define _(x)
Definition: gettext.h:20
MAY_HAVE_NEXT_EXPR
#define MAY_HAVE_NEXT_EXPR
Definition: expressions.c:1411
p
char_u * p
Definition: eval.c:2013
ExprCaseCompareStrategy
ExprCaseCompareStrategy
Definition: expressions.h:16
kExprLexAssignment
@ kExprLexAssignment
Assignment: = or {op}=.
Definition: expressions.h:54
kExprCmpEqual
@ kExprCmpEqual
Equality, unequality.
Definition: expressions.h:60
kExprFlagsMulti
@ kExprFlagsMulti
Definition: expressions.h:333
kExprLexSpacing
@ kExprLexSpacing
Spaces, tabs, newlines, etc.
Definition: expressions.h:26
ret
const int ret
Definition: eval.c:722
kCCStrategyIgnoreCase
@ kCCStrategyIgnoreCase
Definition: expressions.h:19
kExprAsgnAdd
@ kExprAsgnAdd
Assignment augmented with addition: +=.
Definition: expressions.h:77
kExprCmpGreaterOrEqual
@ kExprCmpGreaterOrEqual
>= or <.
Definition: expressions.h:63
kCCStrategyMatchCase
@ kCCStrategyMatchCase
Definition: expressions.h:18
kExprCmpGreater
@ kExprCmpGreater
> or <=
Definition: expressions.h:62
kExprCmpMatches
@ kExprCmpMatches
Matches regex, not matches regex.
Definition: expressions.h:61
kExprCmpIdentical
@ kExprCmpIdentical
is or isnot
Definition: expressions.h:64
kExprAsgnConcat
@ kExprAsgnConcat
Assignment augmented with concatenation: .=.
Definition: expressions.h:79
msg
err msg
Definition: helpers.c:1039
kExprLexOption
@ kExprLexOption
&optionname option value.
Definition: expressions.h:44
kExprNodeMissing
@ kExprNodeMissing
Definition: expressions.h:194
HL
#define HL(g)
Get highlight group name.
Definition: expressions.c:1371
kExprAsgnPlain
@ kExprAsgnPlain
Plain assignment: =.
Definition: expressions.h:76
kExprAsgnSubtract
@ kExprAsgnSubtract
Assignment augmented with subtraction: -=.
Definition: expressions.h:78
kExprNodeOpMissing
@ kExprNodeOpMissing
Definition: expressions.h:195
snprintf
snprintf((char *) pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat)
kExprLexMultiplication
@ kExprLexMultiplication
Multiplication, division or modulo operator.
Definition: expressions.h:37
kExprLexInvalid
@ kExprLexInvalid
Invalid token, indicaten an error.
Definition: expressions.h:24
kCCStrategyUseOption
@ kCCStrategyUseOption
Definition: expressions.h:17
NULL
return NULL
Definition: eval.c:10355
NEW_NODE
#define NEW_NODE(type)
Allocate new node, saving some values.
Definition: expressions.c:1379
kExprNodeUnknownFigure
@ kExprNodeUnknownFigure
Definition: expressions.h:218