mirror of
https://github.com/neovim/neovim.git
synced 2025-09-20 10:18:18 +00:00
390 lines
14 KiB
C
390 lines
14 KiB
C
#ifndef NVIM_VIML_PARSER_EXPRESSIONS_H
|
||
#define NVIM_VIML_PARSER_EXPRESSIONS_H
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
|
||
#include "nvim/types.h"
|
||
#include "nvim/viml/parser/parser.h"
|
||
#include "nvim/eval/typval.h"
|
||
|
||
// Defines whether to ignore case:
|
||
// == kCCStrategyUseOption
|
||
// ==# kCCStrategyMatchCase
|
||
// ==? kCCStrategyIgnoreCase
|
||
typedef enum {
|
||
kCCStrategyUseOption = 0, // 0 for xcalloc
|
||
kCCStrategyMatchCase = '#',
|
||
kCCStrategyIgnoreCase = '?',
|
||
} ExprCaseCompareStrategy;
|
||
|
||
/// Lexer token type
|
||
typedef enum {
|
||
kExprLexInvalid = 0, ///< Invalid token, indicaten an error.
|
||
kExprLexMissing, ///< Missing token, for use in parser.
|
||
kExprLexSpacing, ///< Spaces, tabs, newlines, etc.
|
||
kExprLexEOC, ///< End of command character: NL, |, just end of stream.
|
||
|
||
kExprLexQuestion, ///< Question mark, for use in ternary.
|
||
kExprLexColon, ///< Colon, for use in ternary.
|
||
kExprLexOr, ///< Logical or operator.
|
||
kExprLexAnd, ///< Logical and operator.
|
||
kExprLexComparison, ///< One of the comparison operators.
|
||
kExprLexPlus, ///< Plus sign.
|
||
kExprLexMinus, ///< Minus sign.
|
||
kExprLexDot, ///< Dot: either concat or subscript, also part of the float.
|
||
kExprLexMultiplication, ///< Multiplication, division or modulo operator.
|
||
|
||
kExprLexNot, ///< Not: !.
|
||
|
||
kExprLexNumber, ///< Integer number literal, or part of a float.
|
||
kExprLexSingleQuotedString, ///< Single quoted string literal.
|
||
kExprLexDoubleQuotedString, ///< Double quoted string literal.
|
||
kExprLexOption, ///< &optionname option value.
|
||
kExprLexRegister, ///< @r register value.
|
||
kExprLexEnv, ///< Environment $variable value.
|
||
kExprLexPlainIdentifier, ///< Identifier without scope: `abc`, `foo#bar`.
|
||
|
||
kExprLexBracket, ///< Bracket, either opening or closing.
|
||
kExprLexFigureBrace, ///< Figure brace, either opening or closing.
|
||
kExprLexParenthesis, ///< Parenthesis, either opening or closing.
|
||
kExprLexComma, ///< Comma.
|
||
kExprLexArrow, ///< Arrow, like from lambda expressions.
|
||
kExprLexAssignment, ///< Assignment: `=` or `{op}=`.
|
||
// XXX When modifying this enum you need to also modify eltkn_type_tab in
|
||
// expressions.c and tests and, possibly, viml_pexpr_repr_token.
|
||
} LexExprTokenType;
|
||
|
||
typedef enum {
|
||
kExprCmpEqual, ///< Equality, unequality.
|
||
kExprCmpMatches, ///< Matches regex, not matches regex.
|
||
kExprCmpGreater, ///< `>` or `<=`
|
||
kExprCmpGreaterOrEqual, ///< `>=` or `<`.
|
||
kExprCmpIdentical, ///< `is` or `isnot`
|
||
} ExprComparisonType;
|
||
|
||
/// All possible option scopes
|
||
typedef enum {
|
||
kExprOptScopeUnspecified = 0,
|
||
kExprOptScopeGlobal = 'g',
|
||
kExprOptScopeLocal = 'l',
|
||
} ExprOptScope;
|
||
|
||
/// All possible assignment types: `=` and `{op}=`.
|
||
typedef enum {
|
||
kExprAsgnPlain = 0, ///< Plain assignment: `=`.
|
||
kExprAsgnAdd, ///< Assignment augmented with addition: `+=`.
|
||
kExprAsgnSubtract, ///< Assignment augmented with subtraction: `-=`.
|
||
kExprAsgnConcat, ///< Assignment augmented with concatenation: `.=`.
|
||
} ExprAssignmentType;
|
||
|
||
#define EXPR_OPT_SCOPE_LIST \
|
||
((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;
|
||
size_t len;
|
||
LexExprTokenType type;
|
||
union {
|
||
struct {
|
||
ExprComparisonType type; ///< Comparison type.
|
||
ExprCaseCompareStrategy ccs; ///< Case comparison strategy.
|
||
bool inv; ///< True if comparison is to be inverted.
|
||
} cmp; ///< For kExprLexComparison.
|
||
|
||
struct {
|
||
enum {
|
||
kExprLexMulMul, ///< Real multiplication.
|
||
kExprLexMulDiv, ///< Division.
|
||
kExprLexMulMod, ///< Modulo.
|
||
} type; ///< Multiplication type.
|
||
} mul; ///< For kExprLexMultiplication.
|
||
|
||
struct {
|
||
bool closing; ///< True if bracket/etc is a closing one.
|
||
} brc; ///< For brackets/braces/parenthesis.
|
||
|
||
struct {
|
||
int name; ///< Register name, may be -1 if name not present.
|
||
} reg; ///< For kExprLexRegister.
|
||
|
||
struct {
|
||
bool closed; ///< True if quote was closed.
|
||
} str; ///< For kExprLexSingleQuotedString and kExprLexDoubleQuotedString.
|
||
|
||
struct {
|
||
const char *name; ///< Option name start.
|
||
size_t len; ///< Option name length.
|
||
ExprOptScope scope; ///< Option scope: &l:, &g: or not specified.
|
||
} opt; ///< Option properties.
|
||
|
||
struct {
|
||
ExprVarScope scope; ///< Scope character or 0 if not present.
|
||
bool autoload; ///< Has autoload characters.
|
||
} var; ///< For kExprLexPlainIdentifier
|
||
|
||
struct {
|
||
LexExprTokenType type; ///< Suggested type for parsing incorrect code.
|
||
const char *msg; ///< Error message.
|
||
} err; ///< For kExprLexInvalid
|
||
|
||
struct {
|
||
union {
|
||
float_T floating;
|
||
uvarnumber_T integer;
|
||
} val; ///< Number value.
|
||
uint8_t base; ///< Base: 2, 8, 10 or 16.
|
||
bool is_float; ///< True if number is a floating-point.
|
||
} num; ///< For kExprLexNumber
|
||
|
||
struct {
|
||
ExprAssignmentType type;
|
||
} ass; ///< For kExprLexAssignment
|
||
} data; ///< Additional data, if needed.
|
||
} LexExprToken;
|
||
|
||
typedef enum {
|
||
/// If set, “pointer” to the current byte in pstate will not be shifted
|
||
kELFlagPeek = (1 << 0),
|
||
/// Determines whether scope is allowed to come before the identifier
|
||
kELFlagForbidScope = (1 << 1),
|
||
/// Determines whether floating-point numbers are allowed
|
||
///
|
||
/// I.e. whether dot is a decimal point separator or is not a part of
|
||
/// a number at all.
|
||
kELFlagAllowFloat = (1 << 2),
|
||
/// Determines whether `is` and `isnot` are seen as comparison operators
|
||
///
|
||
/// If set they are supposed to be just regular identifiers.
|
||
kELFlagIsNotCmp = (1 << 3),
|
||
/// Determines whether EOC tokens are allowed
|
||
///
|
||
/// If set then it will yield Invalid token with E15 in place of EOC one if
|
||
/// “EOC” is something like "|". It is fine with emitting EOC at the end of
|
||
/// string still, with or without this flag set.
|
||
kELFlagForbidEOC = (1 << 4),
|
||
// XXX Whenever you add a new flag, alter klee_assume() statement in
|
||
// viml_expressions_lexer.c.
|
||
} LexExprFlags;
|
||
|
||
/// Expression AST node type
|
||
typedef enum {
|
||
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,
|
||
/// Plain dictionary key, for use with kExprNodeConcatOrSubscript
|
||
kExprNodePlainKey,
|
||
/// Complex identifier: variable/function name with curly braces
|
||
kExprNodeComplexIdentifier,
|
||
/// Figure brace expression which is not yet known
|
||
///
|
||
/// May resolve to any of kExprNodeDictLiteral, kExprNodeLambda or
|
||
/// kExprNodeCurlyBracesIdentifier.
|
||
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,
|
||
/// 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,
|
||
kExprNodeInteger, ///< Integral number.
|
||
kExprNodeFloat, ///< Floating-point number.
|
||
kExprNodeSingleQuotedString,
|
||
kExprNodeDoubleQuotedString,
|
||
kExprNodeOr,
|
||
kExprNodeAnd,
|
||
kExprNodeUnaryMinus,
|
||
kExprNodeBinaryMinus,
|
||
kExprNodeNot,
|
||
kExprNodeMultiplication,
|
||
kExprNodeDivision,
|
||
kExprNodeMod,
|
||
kExprNodeOption,
|
||
kExprNodeEnvironment,
|
||
kExprNodeAssignment,
|
||
// XXX When modifying this list also modify east_node_type_tab both in parser
|
||
// and in tests, and you most likely will also have to alter list of
|
||
// highlight groups stored in highlight_init_cmdline variable.
|
||
} ExprASTNodeType;
|
||
|
||
typedef struct expr_ast_node ExprASTNode;
|
||
|
||
/// Structure representing one AST node
|
||
struct expr_ast_node {
|
||
ExprASTNodeType type; ///< Node type.
|
||
/// Node children: e.g. for 1 + 2 nodes 1 and 2 will be children of +.
|
||
ExprASTNode *children;
|
||
/// Next node: e.g. for 1 + 2 child nodes 1 and 2 are put into a single-linked
|
||
/// list: `(+)->children` references only node 1, node 2 is in
|
||
/// `(+)->children->next`.
|
||
ExprASTNode *next;
|
||
ParserPosition start;
|
||
size_t len;
|
||
union {
|
||
struct {
|
||
int name; ///< Register name, may be -1 if name not present.
|
||
} reg; ///< For kExprNodeRegister.
|
||
struct {
|
||
/// Which nodes UnknownFigure can’t possibly represent.
|
||
struct {
|
||
/// True if UnknownFigure may actually represent dictionary literal.
|
||
bool allow_dict;
|
||
/// True if UnknownFigure may actually represent lambda.
|
||
bool allow_lambda;
|
||
/// True if UnknownFigure may actually be part of curly braces name.
|
||
bool allow_ident;
|
||
} type_guesses;
|
||
/// Highlight chunk index, used for rehighlighting if needed
|
||
size_t opening_hl_idx;
|
||
} fig; ///< For kExprNodeUnknownFigure.
|
||
struct {
|
||
ExprVarScope scope; ///< Scope character or 0 if not present.
|
||
/// Actual identifier without scope.
|
||
///
|
||
/// Points to inside parser reader state.
|
||
const char *ident;
|
||
size_t ident_len; ///< Actual identifier length.
|
||
} var; ///< For kExprNodePlainIdentifier and kExprNodePlainKey.
|
||
struct {
|
||
bool got_colon; ///< True if colon was seen.
|
||
} ter; ///< For kExprNodeTernaryValue.
|
||
struct {
|
||
ExprComparisonType type; ///< Comparison type.
|
||
ExprCaseCompareStrategy ccs; ///< Case comparison strategy.
|
||
bool inv; ///< True if comparison is to be inverted.
|
||
} cmp; ///< For kExprNodeComparison.
|
||
struct {
|
||
uvarnumber_T value;
|
||
} num; ///< For kExprNodeInteger.
|
||
struct {
|
||
float_T value;
|
||
} flt; ///< For kExprNodeFloat.
|
||
struct {
|
||
char *value;
|
||
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.
|
||
struct {
|
||
ExprAssignmentType type;
|
||
} ass; ///< For kExprNodeAssignment
|
||
} data;
|
||
};
|
||
|
||
enum {
|
||
/// Allow multiple expressions in a row: e.g. for :echo
|
||
///
|
||
/// Parser will still parse only one of them though.
|
||
kExprFlagsMulti = (1 << 0),
|
||
/// Allow NL, NUL and bar to be EOC
|
||
///
|
||
/// When parsing expressions input by user bar is assumed to be a binary
|
||
/// operator and other two are spacings.
|
||
kExprFlagsDisallowEOC = (1 << 1),
|
||
/// Parse :let argument
|
||
///
|
||
/// That mean that top level node must be an assignment and first nodes
|
||
/// belong to lvalues.
|
||
kExprFlagsParseLet = (1 << 2),
|
||
// XXX whenever you add a new flag, alter klee_assume() statement in
|
||
// viml_expressions_parser.c, nvim_parse_expression() flags parsing
|
||
// alongside with its documentation and flag sets in check_parsing()
|
||
// function in expressions parser functional and unit tests.
|
||
} ExprParserFlags;
|
||
|
||
/// AST error definition
|
||
typedef struct {
|
||
/// Error message. Must contain a single printf format atom: %.*s.
|
||
const char *msg;
|
||
/// Error message argument: points to the location of the error.
|
||
const char *arg;
|
||
/// Message argument length: length till the end of string.
|
||
int arg_len;
|
||
} ExprASTError;
|
||
|
||
/// Structure representing complety AST for one expression
|
||
typedef struct {
|
||
/// When AST is not correct this message will be printed.
|
||
///
|
||
/// Uses `emsgf(msg, arg_len, arg);`, `msg` is assumed to contain only `%.*s`.
|
||
ExprASTError err;
|
||
/// Root node of the AST.
|
||
ExprASTNode *root;
|
||
} ExprAST;
|
||
|
||
/// Array mapping ExprASTNodeType to maximum amount of children node may have
|
||
extern const uint8_t node_maxchildren[];
|
||
|
||
/// Array mapping ExprASTNodeType values to their stringified versions
|
||
extern const char *const east_node_type_tab[];
|
||
|
||
/// Array mapping ExprComparisonType values to their stringified versions
|
||
extern const char *const eltkn_cmp_type_tab[];
|
||
|
||
/// Array mapping ExprCaseCompareStrategy values to their stringified versions
|
||
extern const char *const ccs_tab[];
|
||
|
||
/// Array mapping ExprAssignmentType values to their stringified versions
|
||
extern const char *const expr_asgn_type_tab[];
|
||
|
||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||
# include "viml/parser/expressions.h.generated.h"
|
||
#endif
|
||
|
||
#endif // NVIM_VIML_PARSER_EXPRESSIONS_H
|