diff options
| author | dundargoc <33953936+dundargoc@users.noreply.github.com> | 2021-09-18 18:34:23 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-18 09:34:23 -0700 |
| commit | 51a98aa0c2fe3231a0ffc8a78189bc6fafd6abf6 (patch) | |
| tree | b0a582d67883864eda3231bce45dc7c159cbe97f /src/nvim/viml/parser | |
| parent | 6cad86fffdb91d3997a707ff6adb0b5991587b3e (diff) | |
| download | rneovim-51a98aa0c2fe3231a0ffc8a78189bc6fafd6abf6.tar.gz rneovim-51a98aa0c2fe3231a0ffc8a78189bc6fafd6abf6.tar.bz2 rneovim-51a98aa0c2fe3231a0ffc8a78189bc6fafd6abf6.zip | |
refactor: format #15702
Diffstat (limited to 'src/nvim/viml/parser')
| -rw-r--r-- | src/nvim/viml/parser/expressions.c | 3267 |
1 files changed, 1623 insertions, 1644 deletions
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c index 967d656dc5..c2aa923c49 100644 --- a/src/nvim/viml/parser/expressions.c +++ b/src/nvim/viml/parser/expressions.c @@ -50,20 +50,19 @@ // 7. 'isident' no longer applies to environment variables, they always include // ASCII alphanumeric characters and underscore and nothing except this. +#include <assert.h> #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/assert.h" -#include "nvim/lib/kvec.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" @@ -143,10 +142,8 @@ typedef enum { /// numbers are not supported. /// @param[in] exponent Exponent to scale by. /// @param[in] exponent_negative True if exponent is negative. -static inline float_T scale_number(const float_T num, - const uint8_t base, - const uvarnumber_T exponent, - const bool exponent_negative) +static inline float_T scale_number(const float_T num, const uint8_t base, + const uvarnumber_T exponent, const bool exponent_negative) FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_CONST { if (num == 0 || exponent == 0) { @@ -200,7 +197,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) if (ret.len < pline.size \ && strchr("?#", pline.data[ret.len]) != NULL) { \ ret.data.cmp.ccs = \ - (ExprCaseCompareStrategy)pline.data[ret.len]; \ + (ExprCaseCompareStrategy)pline.data[ret.len]; \ ret.len++; \ } else { \ ret.data.cmp.ccs = kCCStrategyUseOption; \ @@ -209,12 +206,12 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) switch (schar) { // Paired brackets. #define BRACKET(typ, opning, clsing) \ - case opning: \ - case clsing: { \ - ret.type = typ; \ - ret.data.brc.closing = (schar == clsing); \ - break; \ - } +case opning: \ +case clsing: { \ + ret.type = typ; \ + ret.data.brc.closing = (schar == clsing); \ + break; \ +} BRACKET(kExprLexParenthesis, '(', ')') BRACKET(kExprLexBracket, '[', ']') BRACKET(kExprLexFigureBrace, '{', '}') @@ -222,10 +219,10 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) // Single character tokens without data. #define CHAR(typ, ch) \ - case ch: { \ - ret.type = typ; \ - break; \ - } +case ch: { \ + ret.type = typ; \ + break; \ +} CHAR(kExprLexQuestion, '?') CHAR(kExprLexColon, ':') CHAR(kExprLexComma, ',') @@ -233,198 +230,265 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) // Multiplication/division/modulo. #define MUL(mul_type, ch) \ - case ch: { \ - ret.type = kExprLexMultiplication; \ - ret.data.mul.type = mul_type; \ - break; \ - } +case ch: { \ + ret.type = kExprLexMultiplication; \ + ret.data.mul.type = mul_type; \ + break; \ +} MUL(kExprLexMulMul, '*') MUL(kExprLexMulDiv, '/') MUL(kExprLexMulMod, '%') #undef MUL #define CHARREG(typ, cond) \ - do { \ - ret.type = typ; \ - for (; (ret.len < pline.size \ - && cond(pline.data[ret.len])) \ - ; ret.len++) { \ - } \ - } while (0) - - // Whitespace. - case ' ': - case TAB: { - CHARREG(kExprLexSpacing, ascii_iswhite); - break; - } - - // Control character, except for NUL, NL and TAB. - case Ctrl_A: case Ctrl_B: case Ctrl_C: case Ctrl_D: case Ctrl_E: - case Ctrl_F: case Ctrl_G: case Ctrl_H: + do { \ + ret.type = typ; \ + for (; (ret.len < pline.size \ + && cond(pline.data[ret.len])) \ + ; ret.len++) { \ + } \ + } while (0) - case Ctrl_K: case Ctrl_L: case Ctrl_M: case Ctrl_N: case Ctrl_O: - case Ctrl_P: case Ctrl_Q: case Ctrl_R: case Ctrl_S: case Ctrl_T: - case Ctrl_U: case Ctrl_V: case Ctrl_W: case Ctrl_X: case Ctrl_Y: - case Ctrl_Z: { + // Whitespace. + case ' ': + case TAB: + CHARREG(kExprLexSpacing, ascii_iswhite); + break; + + // Control character, except for NUL, NL and TAB. + case Ctrl_A: + case Ctrl_B: + case Ctrl_C: + case Ctrl_D: + case Ctrl_E: + case Ctrl_F: + case Ctrl_G: + case Ctrl_H: + + case Ctrl_K: + case Ctrl_L: + case Ctrl_M: + case Ctrl_N: + case Ctrl_O: + case Ctrl_P: + case Ctrl_Q: + case Ctrl_R: + case Ctrl_S: + case Ctrl_T: + case Ctrl_U: + case Ctrl_V: + case Ctrl_W: + case Ctrl_X: + case Ctrl_Y: + case Ctrl_Z: #define ISCTRL(schar) (schar < ' ') - CHARREG(kExprLexInvalid, ISCTRL); - ret.data.err.type = kExprLexSpacing; - ret.data.err.msg = - _("E15: Invalid control character present in input: %.*s"); - break; + CHARREG(kExprLexInvalid, ISCTRL); + ret.data.err.type = kExprLexSpacing; + ret.data.err.msg = + _("E15: Invalid control character present in input: %.*s"); + break; #undef ISCTRL - } - // Number. - case '0': case '1': case '2': case '3': case '4': case '5': case '6': - case '7': case '8': case '9': { - ret.data.num.is_float = false; - ret.data.num.base = 10; - size_t frac_start = 0; - size_t exp_start = 0; - size_t frac_end = 0; - bool exp_negative = false; - CHARREG(kExprLexNumber, ascii_isdigit); - if (flags & kELFlagAllowFloat) { - const LexExprToken non_float_ret = ret; + // Number. + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + ret.data.num.is_float = false; + ret.data.num.base = 10; + size_t frac_start = 0; + size_t exp_start = 0; + size_t frac_end = 0; + bool exp_negative = false; + CHARREG(kExprLexNumber, ascii_isdigit); + if (flags & kELFlagAllowFloat) { + const LexExprToken non_float_ret = ret; + if (pline.size > ret.len + 1 + && pline.data[ret.len] == '.' + && ascii_isdigit(pline.data[ret.len + 1])) { + ret.len++; + frac_start = ret.len; + frac_end = ret.len; + ret.data.num.is_float = true; + for (; ret.len < pline.size && ascii_isdigit(pline.data[ret.len]) + ; ret.len++) { + // A small optimization: trailing zeroes in fractional part do not + // add anything to significand, so it is useless to include them in + // frac_end. + if (pline.data[ret.len] != '0') { + frac_end = ret.len + 1; + } + } if (pline.size > ret.len + 1 - && pline.data[ret.len] == '.' - && ascii_isdigit(pline.data[ret.len + 1])) { + && (pline.data[ret.len] == 'e' + || pline.data[ret.len] == 'E') + && ((pline.size > ret.len + 2 + && (pline.data[ret.len + 1] == '+' + || pline.data[ret.len + 1] == '-') + && ascii_isdigit(pline.data[ret.len + 2])) + || ascii_isdigit(pline.data[ret.len + 1]))) { ret.len++; - frac_start = ret.len; - frac_end = ret.len; - ret.data.num.is_float = true; - for (; ret.len < pline.size && ascii_isdigit(pline.data[ret.len]) - ; ret.len++) { - // A small optimization: trailing zeroes in fractional part do not - // add anything to significand, so it is useless to include them in - // frac_end. - if (pline.data[ret.len] != '0') { - frac_end = ret.len + 1; - } - } - if (pline.size > ret.len + 1 - && (pline.data[ret.len] == 'e' - || pline.data[ret.len] == 'E') - && ((pline.size > ret.len + 2 - && (pline.data[ret.len + 1] == '+' - || pline.data[ret.len + 1] == '-') - && ascii_isdigit(pline.data[ret.len + 2])) - || ascii_isdigit(pline.data[ret.len + 1]))) { + if (pline.data[ret.len] == '+' + || (exp_negative = (pline.data[ret.len] == '-'))) { ret.len++; - if (pline.data[ret.len] == '+' - || (exp_negative = (pline.data[ret.len] == '-'))) { - ret.len++; - } - exp_start = ret.len; - CHARREG(kExprLexNumber, ascii_isdigit); } - } - if (pline.size > ret.len - && (pline.data[ret.len] == '.' - || ASCII_ISALPHA(pline.data[ret.len]))) { - ret = non_float_ret; + exp_start = ret.len; + CHARREG(kExprLexNumber, ascii_isdigit); } } - // TODO(ZyX-I): detect overflows - if (ret.data.num.is_float) { - // Vim used to use string2float here which in turn uses strtod(). There - // are two problems with this approach: - // 1. strtod() is locale-dependent. Not sure how it is worked around so - // that I do not see relevant bugs, but it still does not look like - // a good idea. - // 2. strtod() does not accept length argument. - // - // The below variant of parsing floats was recognized as acceptable - // because it is basically how uClibc does the thing: it generates - // a number ignoring decimal point (but recording its position), then - // uses recorded position to scale number down when processing exponent. - float_T significand_part = 0; - uvarnumber_T exp_part = 0; - const size_t frac_size = (size_t)(frac_end - frac_start); - for (size_t i = 0; i < frac_end; i++) { - if (i == frac_start - 1) { - continue; - } - significand_part = significand_part * 10 + (pline.data[i] - '0'); - } - if (exp_start) { - vim_str2nr(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part, - (int)(ret.len - exp_start), false); + if (pline.size > ret.len + && (pline.data[ret.len] == '.' + || ASCII_ISALPHA(pline.data[ret.len]))) { + ret = non_float_ret; + } + } + // TODO(ZyX-I): detect overflows + if (ret.data.num.is_float) { + // Vim used to use string2float here which in turn uses strtod(). There + // are two problems with this approach: + // 1. strtod() is locale-dependent. Not sure how it is worked around so + // that I do not see relevant bugs, but it still does not look like + // a good idea. + // 2. strtod() does not accept length argument. + // + // The below variant of parsing floats was recognized as acceptable + // because it is basically how uClibc does the thing: it generates + // a number ignoring decimal point (but recording its position), then + // uses recorded position to scale number down when processing exponent. + float_T significand_part = 0; + uvarnumber_T exp_part = 0; + const size_t frac_size = (size_t)(frac_end - frac_start); + for (size_t i = 0; i < frac_end; i++) { + if (i == frac_start - 1) { + continue; } - if (exp_negative) { - exp_part += frac_size; + significand_part = significand_part * 10 + (pline.data[i] - '0'); + } + if (exp_start) { + vim_str2nr(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part, + (int)(ret.len - exp_start), false); + } + if (exp_negative) { + exp_part += frac_size; + } else { + if (exp_part < frac_size) { + exp_negative = true; + exp_part = frac_size - exp_part; } else { - if (exp_part < frac_size) { - exp_negative = true; - exp_part = frac_size - exp_part; - } else { - exp_part -= frac_size; - } + exp_part -= frac_size; } - ret.data.num.val.floating = scale_number(significand_part, 10, exp_part, - exp_negative); - } else { - int len; - int prep; - vim_str2nr(pline.data, &prep, &len, STR2NR_ALL, NULL, - &ret.data.num.val.integer, (int)pline.size, false); - ret.len = (size_t)len; - const uint8_t bases[] = { - [0] = 10, - ['0'] = 8, - ['x'] = 16, ['X'] = 16, - ['b'] = 2, ['B'] = 2, - }; - ret.data.num.base = bases[prep]; } - break; + ret.data.num.val.floating = scale_number(significand_part, 10, exp_part, + exp_negative); + } else { + int len; + int prep; + vim_str2nr(pline.data, &prep, &len, STR2NR_ALL, NULL, + &ret.data.num.val.integer, (int)pline.size, false); + ret.len = (size_t)len; + const uint8_t bases[] = { + [0] = 10, + ['0'] = 8, + ['x'] = 16, ['X'] = 16, + ['b'] = 2, ['B'] = 2, + }; + ret.data.num.base = bases[prep]; } + break; + } #define ISWORD_OR_AUTOLOAD(x) \ - (ascii_isident(x) || (x) == AUTOLOAD_CHAR) - - // Environment variable. - case '$': { - CHARREG(kExprLexEnv, ascii_isident); - break; - } - - // Normal variable/function name. - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': - case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': - case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': - case 'v': case 'w': case 'x': case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': - case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': - case 'V': case 'W': case 'X': case 'Y': case 'Z': - case '_': { - ret.data.var.scope = 0; - ret.data.var.autoload = false; - CHARREG(kExprLexPlainIdentifier, ascii_isident); - // "is" and "isnot" operators. - if (!(flags & kELFlagIsNotCmp) - && ((ret.len == 2 && memcmp(pline.data, "is", 2) == 0) - || (ret.len == 5 && memcmp(pline.data, "isnot", 5) == 0))) { - ret.type = kExprLexComparison; - ret.data.cmp.type = kExprCmpIdentical; - ret.data.cmp.inv = (ret.len == 5); - GET_CCS(ret, pline); + (ascii_isident(x) || (x) == AUTOLOAD_CHAR) + + // Environment variable. + case '$': + CHARREG(kExprLexEnv, ascii_isident); + break; + + // Normal variable/function name. + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '_': + ret.data.var.scope = 0; + ret.data.var.autoload = false; + CHARREG(kExprLexPlainIdentifier, ascii_isident); + // "is" and "isnot" operators. + if (!(flags & kELFlagIsNotCmp) + && ((ret.len == 2 && memcmp(pline.data, "is", 2) == 0) + || (ret.len == 5 && memcmp(pline.data, "isnot", 5) == 0))) { + ret.type = kExprLexComparison; + ret.data.cmp.type = kExprCmpIdentical; + ret.data.cmp.inv = (ret.len == 5); + GET_CCS(ret, pline); // Scope: `s:`, etc. - } else if (ret.len == 1 - && pline.size > 1 - && memchr(EXPR_VAR_SCOPE_LIST, schar, - sizeof(EXPR_VAR_SCOPE_LIST)) != NULL - && pline.data[ret.len] == ':' - && !(flags & kELFlagForbidScope)) { - ret.len++; - ret.data.var.scope = (ExprVarScope)schar; - CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD); - ret.data.var.autoload = ( - memchr(pline.data + 2, AUTOLOAD_CHAR, ret.len - 2) - != NULL); + } else if (ret.len == 1 + && pline.size > 1 + && memchr(EXPR_VAR_SCOPE_LIST, schar, + sizeof(EXPR_VAR_SCOPE_LIST)) != NULL + && pline.data[ret.len] == ':' + && !(flags & kELFlagForbidScope)) { + ret.len++; + ret.data.var.scope = (ExprVarScope)schar; + CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD); + ret.data.var.autoload = ( + memchr(pline.data + 2, AUTOLOAD_CHAR, ret.len - 2) + != NULL); // Previous CHARREG stopped at autoload character in order to make it // possible to detect `is#`. Continue now with autoload characters // included. @@ -432,221 +496,213 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags) // Warning: there is ambiguity for the lexer: `is#Foo(1)` is a call of // function `is#Foo()`, `1is#Foo(1)` is a comparison `1 is# Foo(1)`. This // needs to be resolved on the higher level where context is available. - } else if (pline.size > ret.len - && pline.data[ret.len] == AUTOLOAD_CHAR) { - ret.data.var.autoload = true; - CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD); - } - break; + } else if (pline.size > ret.len + && pline.data[ret.len] == AUTOLOAD_CHAR) { + ret.data.var.autoload = true; + CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD); } + break; #undef ISWORD_OR_AUTOLOAD #undef CHARREG - // Option. - case '&': { + // Option. + case '&': { #define OPTNAMEMISS(ret) \ - do { \ - ret.type = kExprLexInvalid; \ - ret.data.err.type = kExprLexOption; \ - ret.data.err.msg = _("E112: Option name missing: %.*s"); \ - } while (0) - if (pline.size > 1 && pline.data[1] == '&') { - ret.type = kExprLexAnd; - ret.len++; - break; + do { \ + ret.type = kExprLexInvalid; \ + ret.data.err.type = kExprLexOption; \ + ret.data.err.msg = _("E112: Option name missing: %.*s"); \ + } while (0) + if (pline.size > 1 && pline.data[1] == '&') { + ret.type = kExprLexAnd; + ret.len++; + break; + } + if (pline.size == 1 || !ASCII_ISALPHA(pline.data[1])) { + OPTNAMEMISS(ret); + break; + } + ret.type = kExprLexOption; + if (pline.size > 2 + && pline.data[2] == ':' + && memchr(EXPR_OPT_SCOPE_LIST, pline.data[1], + sizeof(EXPR_OPT_SCOPE_LIST)) != NULL) { + ret.len += 2; + ret.data.opt.scope = (ExprOptScope)pline.data[1]; + ret.data.opt.name = pline.data + 3; + } else { + ret.data.opt.scope = kExprOptScopeUnspecified; + ret.data.opt.name = pline.data + 1; + } + const char *p = ret.data.opt.name; + const char *const e = pline.data + pline.size; + if (e - p >= 4 && p[0] == 't' && p[1] == '_') { + ret.data.opt.len = 4; + ret.len += 4; + } else { + for (; p < e && ASCII_ISALPHA(*p); p++) { } - if (pline.size == 1 || !ASCII_ISALPHA(pline.data[1])) { + ret.data.opt.len = (size_t)(p - ret.data.opt.name); + if (ret.data.opt.len == 0) { OPTNAMEMISS(ret); - break; - } - ret.type = kExprLexOption; - if (pline.size > 2 - && pline.data[2] == ':' - && memchr(EXPR_OPT_SCOPE_LIST, pline.data[1], - sizeof(EXPR_OPT_SCOPE_LIST)) != NULL) { - ret.len += 2; - ret.data.opt.scope = (ExprOptScope)pline.data[1]; - ret.data.opt.name = pline.data + 3; } else { - ret.data.opt.scope = kExprOptScopeUnspecified; - ret.data.opt.name = pline.data + 1; - } - const char *p = ret.data.opt.name; - const char *const e = pline.data + pline.size; - if (e - p >= 4 && p[0] == 't' && p[1] == '_') { - ret.data.opt.len = 4; - ret.len += 4; - } else { - for (; p < e && ASCII_ISALPHA(*p); p++) { - } - ret.data.opt.len = (size_t)(p - ret.data.opt.name); - if (ret.data.opt.len == 0) { - OPTNAMEMISS(ret); - } else { - ret.len += ret.data.opt.len; - } + ret.len += ret.data.opt.len; } - break; -#undef OPTNAMEMISS } + break; +#undef OPTNAMEMISS + } - // Register. - case '@': { - ret.type = kExprLexRegister; - if (pline.size > 1) { - ret.len++; - ret.data.reg.name = (uint8_t)pline.data[1]; - } else { - ret.data.reg.name = -1; - } - break; + // Register. + case '@': + ret.type = kExprLexRegister; + if (pline.size > 1) { + ret.len++; + ret.data.reg.name = (uint8_t)pline.data[1]; + } else { + ret.data.reg.name = -1; } - - // Single quoted string. - case '\'': { - ret.type = kExprLexSingleQuotedString; - ret.data.str.closed = false; - for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) { - if (pline.data[ret.len] == '\'') { - if (ret.len + 1 < pline.size && pline.data[ret.len + 1] == '\'') { - ret.len++; - } else { - ret.data.str.closed = true; - } + break; + + // Single quoted string. + case '\'': + ret.type = kExprLexSingleQuotedString; + ret.data.str.closed = false; + for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) { + if (pline.data[ret.len] == '\'') { + if (ret.len + 1 < pline.size && pline.data[ret.len + 1] == '\'') { + ret.len++; + } else { + ret.data.str.closed = true; } } - break; } - - // Double quoted string. - case '"': { - ret.type = kExprLexDoubleQuotedString; - ret.data.str.closed = false; - for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) { - if (pline.data[ret.len] == '\\') { - if (ret.len + 1 < pline.size) { - ret.len++; - } - } else if (pline.data[ret.len] == '"') { - ret.data.str.closed = true; + break; + + // Double quoted string. + case '"': + ret.type = kExprLexDoubleQuotedString; + ret.data.str.closed = false; + for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) { + if (pline.data[ret.len] == '\\') { + if (ret.len + 1 < pline.size) { + ret.len++; } + } else if (pline.data[ret.len] == '"') { + ret.data.str.closed = true; } - break; } - - // Unary not, (un)equality and regex (not) match comparison operators. - case '!': - case '=': { - if (pline.size == 1) { - ret.type = (schar == '!' ? kExprLexNot : kExprLexAssignment); - ret.data.ass.type = kExprAsgnPlain; - break; - } - ret.type = kExprLexComparison; - ret.data.cmp.inv = (schar == '!'); - if (pline.data[1] == '=') { - ret.data.cmp.type = kExprCmpEqual; - ret.len++; - } else if (pline.data[1] == '~') { - ret.data.cmp.type = kExprCmpMatches; - ret.len++; - } else if (schar == '!') { - ret.type = kExprLexNot; - } else { - ret.type = kExprLexAssignment; - ret.data.ass.type = kExprAsgnPlain; - } - GET_CCS(ret, pline); + break; + + // Unary not, (un)equality and regex (not) match comparison operators. + case '!': + case '=': + if (pline.size == 1) { + ret.type = (schar == '!' ? kExprLexNot : kExprLexAssignment); + ret.data.ass.type = kExprAsgnPlain; break; } - - // Less/greater [or equal to] comparison operators. - case '>': - case '<': { - ret.type = kExprLexComparison; - const bool haseqsign = (pline.size > 1 && pline.data[1] == '='); - if (haseqsign) { - ret.len++; - } - GET_CCS(ret, pline); - ret.data.cmp.inv = (schar == '<'); - ret.data.cmp.type = ((ret.data.cmp.inv ^ haseqsign) + ret.type = kExprLexComparison; + ret.data.cmp.inv = (schar == '!'); + if (pline.data[1] == '=') { + ret.data.cmp.type = kExprCmpEqual; + ret.len++; + } else if (pline.data[1] == '~') { + ret.data.cmp.type = kExprCmpMatches; + ret.len++; + } else if (schar == '!') { + ret.type = kExprLexNot; + } else { + ret.type = kExprLexAssignment; + ret.data.ass.type = kExprAsgnPlain; + } + GET_CCS(ret, pline); + break; + + // Less/greater [or equal to] comparison operators. + case '>': + case '<': { + ret.type = kExprLexComparison; + const bool haseqsign = (pline.size > 1 && pline.data[1] == '='); + if (haseqsign) { + ret.len++; + } + GET_CCS(ret, pline); + ret.data.cmp.inv = (schar == '<'); + ret.data.cmp.type = ((ret.data.cmp.inv ^ haseqsign) ? kExprCmpGreaterOrEqual : kExprCmpGreater); - break; - } + break; + } - // Minus sign, arrow from lambdas or augmented assignment. - case '-': { - if (pline.size > 1 && pline.data[1] == '>') { - ret.len++; - ret.type = kExprLexArrow; - } else if (pline.size > 1 && pline.data[1] == '=') { - ret.len++; - ret.type = kExprLexAssignment; - ret.data.ass.type = kExprAsgnSubtract; - } else { - ret.type = kExprLexMinus; - } - break; + // Minus sign, arrow from lambdas or augmented assignment. + case '-': { + if (pline.size > 1 && pline.data[1] == '>') { + ret.len++; + ret.type = kExprLexArrow; + } else if (pline.size > 1 && pline.data[1] == '=') { + ret.len++; + ret.type = kExprLexAssignment; + ret.data.ass.type = kExprAsgnSubtract; + } else { + ret.type = kExprLexMinus; } + break; + } // Sign or augmented assignment. #define CHAR_OR_ASSIGN(ch, ch_type, ass_type) \ - 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; \ - } +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; \ +} CHAR_OR_ASSIGN('+', kExprLexPlus, kExprAsgnAdd) CHAR_OR_ASSIGN('.', kExprLexDot, kExprAsgnConcat) #undef CHAR_OR_ASSIGN - // Expression end because Ex command ended. - case NUL: - case NL: { - if (flags & kELFlagForbidEOC) { - ret.type = kExprLexInvalid; - ret.data.err.msg = _("E15: Unexpected EOC character: %.*s"); - ret.data.err.type = kExprLexSpacing; - } else { - ret.type = kExprLexEOC; - } - break; - } - - case '|': { - if (pline.size >= 2 && pline.data[ret.len] == '|') { - // "||" is or. - ret.len++; - ret.type = kExprLexOr; - } else if (flags & kELFlagForbidEOC) { - // Note: `<C-r>=1 | 2<CR>` actually yields 1 in Vim without any - // errors. This will be changed here. - ret.type = kExprLexInvalid; - ret.data.err.msg = _("E15: Unexpected EOC character: %.*s"); - ret.data.err.type = kExprLexOr; - } else { - ret.type = kExprLexEOC; - } - break; + // Expression end because Ex command ended. + case NUL: + case NL: + if (flags & kELFlagForbidEOC) { + ret.type = kExprLexInvalid; + ret.data.err.msg = _("E15: Unexpected EOC character: %.*s"); + ret.data.err.type = kExprLexSpacing; + } else { + ret.type = kExprLexEOC; } - - // Everything else is not valid. - default: { - ret.len = (size_t)utfc_ptr2len_len((const char_u *)pline.data, - (int)pline.size); + break; + + case '|': + if (pline.size >= 2 && pline.data[ret.len] == '|') { + // "||" is or. + ret.len++; + ret.type = kExprLexOr; + } else if (flags & kELFlagForbidEOC) { + // Note: `<C-r>=1 | 2<CR>` actually yields 1 in Vim without any + // errors. This will be changed here. ret.type = kExprLexInvalid; - ret.data.err.type = kExprLexPlainIdentifier; - ret.data.err.msg = _("E15: Unidentified character: %.*s"); - break; + ret.data.err.msg = _("E15: Unexpected EOC character: %.*s"); + ret.data.err.type = kExprLexOr; + } else { + ret.type = kExprLexEOC; } + break; + + // Everything else is not valid. + default: + ret.len = (size_t)utfc_ptr2len_len((const char_u *)pline.data, + (int)pline.size); + ret.type = kExprLexInvalid; + ret.data.err.type = kExprLexPlainIdentifier; + ret.data.err.msg = _("E15: Unidentified character: %.*s"); + break; } #undef GET_CCS viml_pexpr_next_token_adv_return: @@ -737,8 +793,7 @@ static const char *const eltkn_opt_scope_tab[] = { /// /// @return Token represented in a string form, in a static buffer (overwritten /// on each call). -const char *viml_pexpr_repr_token(const ParserState *const pstate, - const LexExprToken token, +const char *viml_pexpr_repr_token(const ParserState *const pstate, const LexExprToken token, size_t *const ret_size) FUNC_ATTR_WARN_UNUSED_RESULT { @@ -756,10 +811,10 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate, eltkn_type_tab[token.type]); switch (token.type) { #define TKNARGS(tkn_type, ...) \ - case tkn_type: { \ - ADDSTR(__VA_ARGS__); \ - break; \ - } +case tkn_type: { \ + ADDSTR(__VA_ARGS__); \ + break; \ +} TKNARGS(kExprLexComparison, "(type=%s,ccs=%s,inv=%i)", eltkn_cmp_type_tab[token.data.cmp.type], ccs_tab[token.data.cmp.ccs], @@ -769,7 +824,7 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate, TKNARGS(kExprLexAssignment, "(type=%s)", expr_asgn_type_tab[token.data.ass.type]) TKNARGS(kExprLexRegister, "(name=%s)", intchar2str(token.data.reg.name)) - case kExprLexDoubleQuotedString: + case kExprLexDoubleQuotedString: TKNARGS(kExprLexSingleQuotedString, "(closed=%i)", (int)token.data.str.closed) TKNARGS(kExprLexOption, "(scope=%s,name=%.*s)", @@ -785,19 +840,17 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate, ? (double)token.data.num.val.floating : (double)token.data.num.val.integer)) TKNARGS(kExprLexInvalid, "(msg=%s)", token.data.err.msg) - default: { - // No additional arguments. - break; - } + default: + // No additional arguments. + break; #undef TKNARGS } if (pstate == NULL) { ADDSTR("::%zu", token.len); } else { *p++ = ':'; - memmove( - p, &pstate->reader.lines.items[token.start.line].data[token.start.col], - token.len); + memmove(p, &pstate->reader.lines.items[token.start.line].data[token.start.col], + token.len); p += token.len; *p = NUL; } @@ -886,9 +939,8 @@ static const char *intchar2str(const int ch) #include <stdio.h> REAL_FATTR_UNUSED -static inline void viml_pexpr_debug_print_ast_node( - const ExprASTNode *const *const eastnode_p, - const char *const prefix) +static inline void viml_pexpr_debug_print_ast_node(const ExprASTNode *const *const eastnode_p, + const char *const prefix) { if (*eastnode_p == NULL) { fprintf(stderr, "%s %p : NULL\n", prefix, (void *)eastnode_p); @@ -901,35 +953,33 @@ static inline void viml_pexpr_debug_print_ast_node( } REAL_FATTR_UNUSED -static inline void viml_pexpr_debug_print_ast_stack( - const ExprASTStack *const ast_stack, - const char *const msg) +static inline void viml_pexpr_debug_print_ast_stack(const ExprASTStack *const ast_stack, + const char *const msg) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE { fprintf(stderr, "\n%sstack: %zu:\n", msg, kv_size(*ast_stack)); for (size_t i = 0; i < kv_size(*ast_stack); i++) { - viml_pexpr_debug_print_ast_node( - (const ExprASTNode *const *)kv_A(*ast_stack, i), - "-"); + viml_pexpr_debug_print_ast_node((const ExprASTNode *const *)kv_A(*ast_stack, i), + "-"); } } REAL_FATTR_UNUSED -static inline void viml_pexpr_debug_print_token( - const ParserState *const pstate, const LexExprToken token) +static inline void viml_pexpr_debug_print_token(const ParserState *const pstate, + const LexExprToken token) FUNC_ATTR_ALWAYS_INLINE { fprintf(stderr, "\ntkn: %s\n", viml_pexpr_repr_token(pstate, token, NULL)); } #define PSTACK(msg) \ - viml_pexpr_debug_print_ast_stack(&ast_stack, #msg) + viml_pexpr_debug_print_ast_stack(&ast_stack, #msg) #define PSTACK_P(msg) \ - viml_pexpr_debug_print_ast_stack(ast_stack, #msg) + viml_pexpr_debug_print_ast_stack(ast_stack, #msg) #define PNODE_P(eastnode_p, msg) \ - viml_pexpr_debug_print_ast_node((const E |