diff --git a/CMakeLists.txt b/CMakeLists.txt index d16080c4..7674ff90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ src/core/math.c src/core/native.c src/core/os.c src/core/string.c +src/core/strtod.c src/core/struct.c src/core/symcache.c src/core/table.c @@ -83,7 +84,6 @@ src/mainclient/line.h set(PARSER_SOURCES src/parser/ast.c src/parser/parse.c -src/parser/strtod.c ) set(TESTLIB_SOURCES diff --git a/src/compiler/stl.c b/src/compiler/stl.c index b89ef8b8..abd06413 100644 --- a/src/compiler/stl.c +++ b/src/compiler/stl.c @@ -37,8 +37,12 @@ static const DstReg cfuns[] = { {"string", dst_core_string}, {"symbol", dst_core_symbol}, {"buffer", dst_core_buffer}, + {"format", dst_core_format}, {"table", dst_core_table}, {"array", dst_core_array}, + {"scan-number", dst_core_scannumber}, + {"scan-integer", dst_core_scaninteger}, + {"scan-real", dst_core_scanreal}, {"tuple", dst_core_tuple}, {"struct", dst_core_struct}, {"buffer", dst_core_buffer}, diff --git a/src/core/array.c b/src/core/array.c index f5afef6e..c54e6e70 100644 --- a/src/core/array.c +++ b/src/core/array.c @@ -218,15 +218,20 @@ static int cfun_concat(DstArgs args) { return dst_return(args, args.v[0]); } +static const DstReg cfuns[] = { + {"array-pop", cfun_pop}, + {"array-peek", cfun_peek}, + {"array-push", cfun_push}, + {"array-setcount", cfun_setcount}, + {"array-ensure", cfun_ensure}, + {"array-slice", cfun_slice}, + {"array-concat", cfun_concat}, + {NULL, NULL} +}; + /* Load the array module */ int dst_lib_array(DstArgs args) { DstTable *env = dst_env_arg(args); - dst_env_def(env, "array-pop", dst_wrap_cfunction(cfun_pop)); - dst_env_def(env, "array-peek", dst_wrap_cfunction(cfun_peek)); - dst_env_def(env, "array-push", dst_wrap_cfunction(cfun_push)); - dst_env_def(env, "array-setcount", dst_wrap_cfunction(cfun_setcount)); - dst_env_def(env, "array-ensure", dst_wrap_cfunction(cfun_ensure)); - dst_env_def(env, "array-slice", dst_wrap_cfunction(cfun_slice)); - dst_env_def(env, "array-concat", dst_wrap_cfunction(cfun_concat)); + dst_env_cfuns(env, cfuns); return 0; } diff --git a/src/core/corelib.c b/src/core/corelib.c index df0e5b09..a059e054 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -95,6 +95,82 @@ int dst_core_buffer(DstArgs args) { return dst_return(args, dst_wrap_buffer(b)); } +int dst_core_format(DstArgs args) { + const uint8_t *format; + int32_t i, len, n; + DstBuffer buf; + dst_minarity(args, 1); + dst_arg_bytes(format, len, args, 0); + n = 1; + dst_buffer_init(&buf, len); + for (i = 0; i < len; i++) { + uint8_t c = format[i]; + if (c != '%') { + dst_buffer_push_u8(&buf, c); + } else { + if (++i == len) break; + c = format[i]; + switch (c) { + default: + dst_buffer_push_u8(&buf, c); + break; + case 's': + { + if (n >= args.n) goto noarg; + dst_buffer_push_string(&buf, dst_to_string(args.v[n++])); + break; + } + } + } + } + *args.ret = dst_wrap_string(dst_string(buf.data, buf.count)); + dst_buffer_deinit(&buf); + return 0; +noarg: + dst_buffer_deinit(&buf); + return dst_throw(args, "not enough arguments to format"); +} + +int dst_core_scannumber(DstArgs args) { + const uint8_t *data; + Dst x; + int32_t len; + dst_fixarity(args, 1); + dst_arg_bytes(data, len, args, 0); + x = dst_scan_number(data, len); + if (!dst_checktype(x, DST_INTEGER) && !dst_checktype(x, DST_REAL)) { + return dst_throw(args, "error parsing number"); + } + return dst_return(args, x); +} + +int dst_core_scaninteger(DstArgs args) { + const uint8_t *data; + int32_t len, ret; + int err = 0; + dst_fixarity(args, 1); + dst_arg_bytes(data, len, args, 0); + ret = dst_scan_integer(data, len, &err); + if (err) { + return dst_throw(args, "error parsing integer"); + } + return dst_return(args, dst_wrap_integer(ret)); +} + +int dst_core_scanreal(DstArgs args) { + const uint8_t *data; + int32_t len; + double ret; + int err = 0; + dst_fixarity(args, 1); + dst_arg_bytes(data, len, args, 0); + ret = dst_scan_real(data, len, &err); + if (err) { + return dst_throw(args, "error parsing real"); + } + return dst_return(args, dst_wrap_real(ret)); +} + int dst_core_tuple(DstArgs args) { return dst_return(args, dst_wrap_tuple(dst_tuple_n(args.v, args.n))); } @@ -137,7 +213,7 @@ int dst_core_gensym(DstArgs args) { } int dst_core_length(DstArgs args) { - dst_checkmany(args, 0, DST_TFLAG_LENGTHABLE); + dst_fixarity(args, 1); return dst_return(args, dst_wrap_integer(dst_length(args.v[0]))); } diff --git a/src/parser/strtod.c b/src/core/strtod.c similarity index 98% rename from src/parser/strtod.c rename to src/core/strtod.c index bfb21f65..b94e64aa 100644 --- a/src/parser/strtod.c +++ b/src/core/strtod.c @@ -211,7 +211,7 @@ static struct DstScanRes dst_scan_impl( /* underscores are ignored - can be used for separator */ } else { int digit = digit_lookup[*str & 0x7F]; - if (digit >= res.base) goto error; + if (*str > 127 || digit >= res.base) goto error; if (res.seenpoint) res.ex--; if (res.mant > 0x00ffffffffffffff) res.ex++; @@ -242,7 +242,7 @@ static struct DstScanRes dst_scan_impl( while (str < end && *str == '0') str++; while (str < end && ee < (INT32_MAX / 40)) { int digit = digit_lookup[*str & 0x7F]; - if (digit >= res.base) goto error; + if (*str > 127 || digit >= res.base) goto error; ee = res.base * ee + digit; str++; seenadigit = 1; diff --git a/src/include/dst/dst.h b/src/include/dst/dst.h index 60e64b6e..8bb29efa 100644 --- a/src/include/dst/dst.h +++ b/src/include/dst/dst.h @@ -36,6 +36,11 @@ extern "C" { #include "dsttypes.h" +/* Number scanning */ +Dst dst_scan_number(const uint8_t *src, int32_t len); +int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err); +double dst_scan_real(const uint8_t *str, int32_t len, int *err); + /* Array functions */ DstArray *dst_array(int32_t capacity); DstArray *dst_array_init(DstArray *array, int32_t capacity); @@ -250,6 +255,13 @@ int dst_typeabstract_err(DstArgs args, int32_t n, DstAbstractType *at); dst_check(A, N, TYPE);\ DEST = dst_unwrap_##NAME((A).v[(N)]); } while (0) +#define dst_arg_bytes(DESTBYTES, DESTLEN, A, N) do {\ + if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_BYTES);\ + if (dst_chararray_view((A).v[(N)], &(DESTBYTES), &(DESTLEN))) {\ + dst_typemany_err(A, N, DST_TFLAG_BYTES);\ + }\ +} while (0) + #define dst_arg_fiber(DEST, A, N) _dst_arg(DST_FIBER, fiber, DEST, A, N) #define dst_arg_integer(DEST, A, N) _dst_arg(DST_INTEGER, integer, DEST, A, N) #define dst_arg_real(DEST, A, N) _dst_arg(DST_REAL, real, DEST, A, N) diff --git a/src/include/dst/dstcorelib.h b/src/include/dst/dstcorelib.h index 838d362a..9b9473a2 100644 --- a/src/include/dst/dstcorelib.h +++ b/src/include/dst/dstcorelib.h @@ -84,6 +84,10 @@ int dst_core_describe(DstArgs args); int dst_core_string(DstArgs args); int dst_core_symbol(DstArgs args); int dst_core_buffer(DstArgs args); +int dst_core_format(DstArgs args); +int dst_core_scannumber(DstArgs args); +int dst_core_scaninteger(DstArgs args); +int dst_core_scanreal(DstArgs args); int dst_core_tuple(DstArgs args); int dst_core_array(DstArgs args); int dst_core_table(DstArgs args); diff --git a/src/include/dst/dstparse.h b/src/include/dst/dstparse.h index 7d7ef0d9..c9e08d6a 100644 --- a/src/include/dst/dstparse.h +++ b/src/include/dst/dstparse.h @@ -38,11 +38,6 @@ Dst dst_ast_unwrap(Dst x); typedef struct DstParseState DstParseState; typedef struct DstParser DstParser; -/* Number scanning */ -Dst dst_scan_number(const uint8_t *src, int32_t len); -int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err); -double dst_scan_real(const uint8_t *str, int32_t len, int *err); - enum DstParserStatus { DST_PARSE_ROOT, DST_PARSE_ERROR, diff --git a/src/include/dst/dsttypes.h b/src/include/dst/dsttypes.h index 022120eb..fed092d9 100644 --- a/src/include/dst/dsttypes.h +++ b/src/include/dst/dsttypes.h @@ -102,7 +102,7 @@ typedef enum DstType { #define DST_TFLAG_BOOLEAN (DST_TFLAG_TRUE | DST_TFLAG_FALSE) #define DST_TFLAG_NUMBER (DST_TFLAG_REAL | DST_TFLAG_INTEGER) #define DST_TFLAG_CALLABLE (DST_TFLAG_FUNCTION | DST_TFLAG_CFUNCTION) -#define DST_TFLAG_CHARS (DST_TFLAG_STRING | DST_TFLAG_SYMBOL | DST_TFLAG_BUFFER) +#define DST_TFLAG_BYTES (DST_TFLAG_STRING | DST_TFLAG_SYMBOL | DST_TFLAG_BUFFER) #define DST_TFLAG_INDEXED (DST_TFLAG_ARRAY | DST_TFLAG_TUPLE) #define DST_TFLAG_DICTIONARY (DST_TFLAG_TABLE | DST_TFLAG_STRUCT) #define DST_TFLAG_LENGTHABLE (DST_TFLAG_CHARS | DST_TFLAG_INDEXED | DST_TFLAG_DICTIONARY) diff --git a/src/parser/parse.c b/src/parser/parse.c index 8956a8aa..244fc199 100644 --- a/src/parser/parse.c +++ b/src/parser/parse.c @@ -86,7 +86,7 @@ The table contains 256 bits, where each bit is 1 if the corresponding ascci code is a symbol char, and 0 if not. The upper characters are also considered symbol chars and are then checked for utf-8 compliance. */ -static uint32_t symchars[8] = { +static const uint32_t symchars[8] = { 0x00000000, 0xF7ffec72, 0xd7ffffff, 0x57fffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; @@ -703,49 +703,6 @@ static int cfun_node(DstArgs args) { return dst_return(args, dst_wrap_tuple(dst_tuple_end(tup))); } -static int cfun_parsenumber(DstArgs args) { - const uint8_t *data; - Dst x; - int32_t len; - if (args.n != 1) return dst_throw(args, "expected string or buffer"); - if (!dst_chararray_view(args.v[0], &data, &len)) - return dst_throw(args, "expected string or buffer"); - x = dst_scan_number(data, len); - if (!dst_checktype(x, DST_INTEGER) && !dst_checktype(x, DST_REAL)) { - return dst_throw(args, "error parsing number"); - } - return dst_return(args, x); -} - -static int cfun_parseint(DstArgs args) { - const uint8_t *data; - int32_t len, ret; - int err = 0; - if (args.n != 1) return dst_throw(args, "expected string or buffer"); - if (!dst_chararray_view(args.v[0], &data, &len)) - return dst_throw(args, "expected string or buffer"); - ret = dst_scan_integer(data, len, &err); - if (err) { - return dst_throw(args, "error parsing integer"); - } - return dst_return(args, dst_wrap_integer(ret)); -} - -static int cfun_parsereal(DstArgs args) { - const uint8_t *data; - int32_t len; - double ret; - int err = 0; - if (args.n != 1) return dst_throw(args, "expected string or buffer"); - if (!dst_chararray_view(args.v[0], &data, &len)) - return dst_throw(args, "expected string or buffer"); - ret = dst_scan_real(data, len, &err); - if (err) { - return dst_throw(args, "error parsing real"); - } - return dst_return(args, dst_wrap_real(ret)); -} - static const DstReg cfuns[] = { {"parser", cfun_parser}, {"parser-produce", cfun_produce}, @@ -757,9 +714,6 @@ static const DstReg cfuns[] = { {"ast-unwrap1", cfun_unwrap1}, {"ast-wrap", cfun_wrap}, {"ast-node", cfun_node}, - {"parse-number", cfun_parsenumber}, - {"parse-int", cfun_parseint}, - {"parse-real", cfun_parsereal}, {NULL, NULL} };