mirror of
https://github.com/neovim/neovim.git
synced 2025-10-06 18:06:30 +00:00

Instead of declaring an enum, this creates a global variable. As gcc10 uses -fno-common by default, global variables declared with the same name more than once is not allowed anymore revealing this issue. Each time this header is included, we define the enum name as a global variable. See also https://bugzilla.redhat.com/show_bug.cgi?id=1799680
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 ExprParserFlags {
|
||
/// 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.
|
||
};
|
||
|
||
/// 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
|