diff options
author | ZyX <kp-pav@yandex.ru> | 2017-10-06 01:19:43 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2017-10-15 19:13:50 +0300 |
commit | 163792e9b9854fe046ada3233dec0fd0f6c55737 (patch) | |
tree | 2cb7739324748a54f609881f0870431cc7e5617a /test/symbolic | |
parent | 0bc4e2237960712426da3774c1430f5874c49aea (diff) | |
download | rneovim-163792e9b9854fe046ada3233dec0fd0f6c55737.tar.gz rneovim-163792e9b9854fe046ada3233dec0fd0f6c55737.tar.bz2 rneovim-163792e9b9854fe046ada3233dec0fd0f6c55737.zip |
viml/parser/expressions: Make lexer parse numbers, support non-decimal
Diffstat (limited to 'test/symbolic')
-rw-r--r-- | test/symbolic/klee/nvim/charset.c | 165 | ||||
-rw-r--r-- | test/symbolic/klee/viml_expressions_lexer.c | 6 |
2 files changed, 170 insertions, 1 deletions
diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c index a40488920e..409d7d443c 100644 --- a/test/symbolic/klee/nvim/charset.c +++ b/test/symbolic/klee/nvim/charset.c @@ -3,8 +3,173 @@ #include "nvim/ascii.h" #include "nvim/macros.h" #include "nvim/charset.h" +#include "nvim/eval/typval.h" +#include "nvim/vim.h" bool vim_isIDc(int c) { return ASCII_ISALNUM(c); } + +int hex2nr(int c) +{ + if ((c >= 'a') && (c <= 'f')) { + return c - 'a' + 10; + } + + if ((c >= 'A') && (c <= 'F')) { + return c - 'A' + 10; + } + return c - '0'; +} + +void vim_str2nr(const char_u *const start, int *const prep, int *const len, + const int what, varnumber_T *const nptr, + uvarnumber_T *const unptr, const int maxlen) +{ + const char_u *ptr = start; + int pre = 0; // default is decimal + bool negative = false; + uvarnumber_T un = 0; + + if (ptr[0] == '-') { + negative = true; + ptr++; + } + + // Recognize hex, octal and bin. + if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9') + && (maxlen == 0 || maxlen > 1)) { + pre = ptr[1]; + + if ((what & STR2NR_HEX) + && ((pre == 'X') || (pre == 'x')) + && ascii_isxdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) { + // hexadecimal + ptr += 2; + } else if ((what & STR2NR_BIN) + && ((pre == 'B') || (pre == 'b')) + && ascii_isbdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) { + // binary + ptr += 2; + } else { + // decimal or octal, default is decimal + pre = 0; + + if (what & STR2NR_OCT) { + // Don't interpret "0", "08" or "0129" as octal. + for (int n = 1; ascii_isdigit(ptr[n]); ++n) { + if (ptr[n] > '7') { + // can't be octal + pre = 0; + break; + } + if (ptr[n] >= '0') { + // assume octal + pre = '0'; + } + if (n == maxlen) { + break; + } + } + } + } + } + + // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. + int n = 1; + if ((pre == 'B') || (pre == 'b') || what == STR2NR_BIN + STR2NR_FORCE) { + // bin + if (pre != 0) { + n += 2; // skip over "0b" + } + while ('0' <= *ptr && *ptr <= '1') { + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 2) { + un = 2 * un + (uvarnumber_T)(*ptr - '0'); + } else { + un = UVARNUMBER_MAX; + } + ptr++; + if (n++ == maxlen) { + break; + } + } + } else if ((pre == '0') || what == STR2NR_OCT + STR2NR_FORCE) { + // octal + while ('0' <= *ptr && *ptr <= '7') { + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 8) { + un = 8 * un + (uvarnumber_T)(*ptr - '0'); + } else { + un = UVARNUMBER_MAX; + } + ptr++; + if (n++ == maxlen) { + break; + } + } + } else if ((pre == 'X') || (pre == 'x') + || what == STR2NR_HEX + STR2NR_FORCE) { + // hex + if (pre != 0) { + n += 2; // skip over "0x" + } + while (ascii_isxdigit(*ptr)) { + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 16) { + un = 16 * un + (uvarnumber_T)hex2nr(*ptr); + } else { + un = UVARNUMBER_MAX; + } + ptr++; + if (n++ == maxlen) { + break; + } + } + } else { + // decimal + while (ascii_isdigit(*ptr)) { + // avoid ubsan error for overflow + if (un < UVARNUMBER_MAX / 10) { + un = 10 * un + (uvarnumber_T)(*ptr - '0'); + } else { + un = UVARNUMBER_MAX; + } + ptr++; + if (n++ == maxlen) { + break; + } + } + } + + if (prep != NULL) { + *prep = pre; + } + + if (len != NULL) { + *len = (int)(ptr - start); + } + + if (nptr != NULL) { + if (negative) { // account for leading '-' for decimal numbers + // avoid ubsan error for overflow + if (un > VARNUMBER_MAX) { + *nptr = VARNUMBER_MIN; + } else { + *nptr = -(varnumber_T)un; + } + } else { + if (un > VARNUMBER_MAX) { + un = VARNUMBER_MAX; + } + *nptr = (varnumber_T)un; + } + } + + if (unptr != NULL) { + *unptr = un; + } +} diff --git a/test/symbolic/klee/viml_expressions_lexer.c b/test/symbolic/klee/viml_expressions_lexer.c index 67f3eb7faa..cddc1cb2f1 100644 --- a/test/symbolic/klee/viml_expressions_lexer.c +++ b/test/symbolic/klee/viml_expressions_lexer.c @@ -2,6 +2,7 @@ # include <klee/klee.h> #else # include <string.h> +# include <stdio.h> #endif #include <stddef.h> #include <stdint.h> @@ -56,7 +57,7 @@ int main(const int argc, const char *const *const argv, .data = &input[shift], .size = sizeof(input) - shift, #else - .data = (const char *)&argv[1], + .data = (const char *)argv[1], .size = strlen(argv[1]), #endif .allocated = false, @@ -97,4 +98,7 @@ int main(const int argc, const char *const *const argv, } assert(allocated_memory == 0); assert(ever_allocated_memory == 0); +#ifndef USE_KLEE + fprintf(stderr, "tkn: %s\n", viml_pexpr_repr_token(&pstate, token, NULL)); +#endif } |