diff --git a/Makefile b/Makefile index d57c5050..f82352da 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ BINDIR=$(PREFIX)/bin # TODO - when api is finalized, only export public symbols instead of using rdynamic # which exports all symbols. -CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -rdynamic -s -O3 +CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -rdynamic -s -O2 CLIBS=-lm -ldl PREFIX=/usr/local DST_TARGET=dst diff --git a/src/core/array.c b/src/core/array.c index f8afeabc..f5afef6e 100644 --- a/src/core/array.c +++ b/src/core/array.c @@ -23,7 +23,7 @@ #include #include "gc.h" -/* Iniializes an array */ +/* Initializes an array */ DstArray *dst_array_init(DstArray *array, int32_t capacity) { Dst *data = NULL; if (capacity > 0) { @@ -67,7 +67,7 @@ void dst_array_setcount(DstArray *array, int32_t count) { return; if (count > array->count) { int32_t i; - dst_array_ensure(array, count + 1); + dst_array_ensure(array, count); for (i = array->count; i < count; i++) { array->data[i] = dst_wrap_nil(); } diff --git a/src/core/buffer.c b/src/core/buffer.c index b287ab76..7329b61e 100644 --- a/src/core/buffer.c +++ b/src/core/buffer.c @@ -62,6 +62,18 @@ void dst_buffer_ensure(DstBuffer *buffer, int32_t capacity) { buffer->capacity = capacity; } +/* Ensure that the buffer has enough internal capacity */ +void dst_buffer_setcount(DstBuffer *buffer, int32_t count) { + if (count < 0) + return; + if (count > buffer->count) { + int32_t oldcount = buffer->count; + dst_buffer_ensure(buffer, count); + memset(buffer->data + oldcount, 0, count - oldcount); + } + buffer->count = count; +} + /* Adds capacity for enough extra bytes to the buffer. Ensures that the * next n bytes pushed to the buffer will not cause a reallocation */ int dst_buffer_extra(DstBuffer *buffer, int32_t n) { @@ -148,11 +160,13 @@ int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x) { static int cfun_u8(DstArgs args) { int32_t i; DstBuffer *buffer; - if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer"); - buffer = dst_unwrap_buffer(args.v[0]); + dst_minarity(args, 1); + dst_arg_buffer(buffer, args, 0); for (i = 1; i < args.n; i++) { - if (!dst_checktype(args.v[i], DST_INTEGER)) return dst_throw(args, "expected integer"); - if (dst_buffer_push_u8(buffer, (uint8_t) (dst_unwrap_integer(args.v[i]) & 0xFF))) return dst_throw(args, "buffer overflow"); + int32_t integer; + dst_arg_integer(integer, args, i); + if (dst_buffer_push_u8(buffer, (uint8_t) (integer & 0xFF))) + return dst_throw(args, "buffer overflow"); } return dst_return(args, args.v[0]); } @@ -160,11 +174,13 @@ static int cfun_u8(DstArgs args) { static int cfun_int(DstArgs args) { int32_t i; DstBuffer *buffer; - if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer"); - buffer = dst_unwrap_buffer(args.v[0]); + dst_minarity(args, 1); + dst_arg_buffer(buffer, args, 0); for (i = 1; i < args.n; i++) { - if (!dst_checktype(args.v[i], DST_INTEGER)) return dst_throw(args, "expected integer"); - if (dst_buffer_push_u32(buffer, (uint32_t) dst_unwrap_integer(args.v[i]))) return dst_throw(args, "buffer overflow"); + int32_t integer; + dst_arg_integer(integer, args, i); + if (dst_buffer_push_u32(buffer, (uint32_t) integer)) + return dst_throw(args, "buffer overflow"); } return dst_return(args, args.v[0]); } @@ -172,38 +188,37 @@ static int cfun_int(DstArgs args) { static int cfun_chars(DstArgs args) { int32_t i; DstBuffer *buffer; - if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer"); - buffer = dst_unwrap_buffer(args.v[0]); + dst_minarity(args, 1); + dst_arg_buffer(buffer, args, 0); for (i = 1; i < args.n; i++) { int32_t len; const uint8_t *str; - if (!dst_chararray_view(args.v[i], &str, &len)) return dst_throw(args, "expected string/buffer"); - if (dst_buffer_push_bytes(buffer, str, len)) return dst_throw(args, "buffer overflow"); + if (!dst_chararray_view(args.v[i], &str, &len)) + return dst_throw(args, "expected string|symbol|buffer"); + if (dst_buffer_push_bytes(buffer, str, len)) + return dst_throw(args, "buffer overflow"); } return dst_return(args, args.v[0]); } static int cfun_clear(DstArgs args) { DstBuffer *buffer; - if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer"); - buffer = dst_unwrap_buffer(args.v[0]); + dst_fixarity(args, 1); + dst_arg_buffer(buffer, args, 0); buffer->count = 0; return dst_return(args, args.v[0]); } static int cfun_popn(DstArgs args) { DstBuffer *buffer; - int32_t i; - if (args.n < 2 - || !dst_checktype(args.v[0], DST_BUFFER) - || !dst_checktype(args.v[1], DST_INTEGER)) return dst_throw(args, "expected buffer and integer"); - buffer = dst_unwrap_buffer(args.v[0]); - i = dst_unwrap_integer(args.v[1]); - if (i < 0) return dst_throw(args, "expected positive integer"); - if (buffer->count < i) { + int32_t n; + dst_fixarity(args, 2); + dst_arg_buffer(buffer, args, 0); + dst_arg_integer(n, args, 1); + if (buffer->count < n) { buffer->count = 0; } else { - buffer->count -= i; + buffer->count -= n; } return dst_return(args, args.v[0]); } diff --git a/src/core/fiber.c b/src/core/fiber.c index bab9262f..9279d51e 100644 --- a/src/core/fiber.c +++ b/src/core/fiber.c @@ -259,17 +259,16 @@ void dst_fiber_popframe(DstFiber *fiber) { static int cfun_fiber(DstArgs args) { DstFiber *fiber; - if (args.n < 1) return dst_throw(args, "expected at least 1 argument"); - if (!dst_checktype(args.v[0], DST_FUNCTION)) - return dst_throw(args, "expected a function"); + dst_fixarity(args, 1); + dst_check(args, 0, DST_FUNCTION); fiber = dst_fiber(dst_unwrap_function(args.v[0]), 64); return dst_return(args, dst_wrap_fiber(fiber)); } static int cfun_status(DstArgs args) { const char *status = ""; - if (args.n != 1) return dst_throw(args, "expected 1 argument"); - if (!dst_checktype(args.v[0], DST_FIBER)) return dst_throw(args, "expected fiber"); + dst_fixarity(args, 1); + dst_check(args, 0, DST_FIBER); switch(dst_unwrap_fiber(args.v[0])->status) { case DST_FIBER_PENDING: status = ":pending"; @@ -330,8 +329,8 @@ static Dst doframe(DstStackFrame *frame) { static int cfun_stack(DstArgs args) { DstFiber *fiber; DstArray *array; - if (args.n != 1) return dst_throw(args, "expected 1 argument"); - if (!dst_checktype(args.v[0], DST_FIBER)) return dst_throw(args, "expected fiber"); + dst_fixarity(args, 1); + dst_check(args, 0, DST_FIBER); fiber = dst_unwrap_fiber(args.v[0]); array = dst_array(0); { diff --git a/src/core/io.c b/src/core/io.c index 91020273..b21961c5 100644 --- a/src/core/io.c +++ b/src/core/io.c @@ -84,16 +84,16 @@ static int checkflags(const uint8_t *str, int32_t len) { static IOFile *checkfile(DstArgs args, int32_t n) { IOFile *iof; if (n >= args.n) { - *args.ret = dst_cstringv("expected core.file"); + *args.ret = dst_cstringv("expected core.file"); return NULL; } if (!dst_checktype(args.v[n], DST_ABSTRACT)) { - *args.ret = dst_cstringv("expected core.file"); + *args.ret = dst_cstringv("expected core.file"); return NULL; } iof = (IOFile *) dst_unwrap_abstract(args.v[n]); if (dst_abstract_type(iof) != &dst_io_filetype) { - *args.ret = dst_cstringv("expected core.file"); + *args.ret = dst_cstringv("expected core.file"); return NULL; } return iof; @@ -105,11 +105,11 @@ static DstBuffer *checkbuffer(DstArgs args, int32_t n, int optional) { return dst_buffer(0); } if (n >= args.n) { - *args.ret = dst_cstringv("expected buffer"); + *args.ret = dst_cstringv("expected buffer"); return NULL; } if (!dst_checktype(args.v[n], DST_BUFFER)) { - *args.ret = dst_cstringv("expected buffer"); + *args.ret = dst_cstringv("expected buffer"); return NULL; } return dst_unwrap_abstract(args.v[n]); @@ -141,8 +141,9 @@ static int dst_io_fopen(DstArgs args) { int32_t modelen; FILE *f; int flags; - if (args.n < 1 || args.n > 2) return dst_throw(args, "expected 1 or 2 arguments"); - if (!dst_checktype(args.v[0], DST_STRING)) return dst_throw(args, "expected string filename"); + dst_minarity(args, 1); + dst_maxarity(args, 2); + dst_check(args, 0, DST_STRING); fname = dst_unwrap_string(args.v[0]); if (args.n == 2) { if (!dst_checktype(args.v[1], DST_STRING) && diff --git a/src/core/util.c b/src/core/util.c index 7be8290b..cdd66d7e 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -206,13 +206,20 @@ int dst_hashtable_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap) return 0; } -int dst_type_err(DstArgs args, int32_t n, DstType expected) { +/* Get actual type name of a value for debugging purposes */ +static const char *typestr(DstArgs args, int32_t n) { DstType actual = n < args.n ? dst_type(args.v[n]) : DST_NIL; + return (actual == DST_ABSTRACT) + ? dst_abstract_type(dst_unwrap_abstract(args.v[n]))->name + : dst_type_names[actual]; +} + +int dst_type_err(DstArgs args, int32_t n, DstType expected) { const uint8_t *message = dst_formatc( - "bad argument #%d, expected %t, got %t", + "bad argument #%d, expected %t, got %s", n, expected, - actual); + typestr(args, n)); return dst_throwv(args, dst_wrap_string(message)); } @@ -220,7 +227,6 @@ int dst_typemany_err(DstArgs args, int32_t n, int expected) { int i; int first = 1; const uint8_t *message; - DstType actual = n < args.n ? dst_type(args.v[n]) : DST_NIL; DstBuffer buf; dst_buffer_init(&buf, 20); dst_buffer_push_string(&buf, dst_formatc("bad argument #%d, expected ", n)); @@ -238,7 +244,7 @@ int dst_typemany_err(DstArgs args, int32_t n, int expected) { expected >>= 1; } dst_buffer_push_cstring(&buf, ", got "); - dst_buffer_push_cstring(&buf, dst_type_names[actual] + 1); + dst_buffer_push_cstring(&buf, typestr(args, n)); message = dst_string(buf.data, buf.count); dst_buffer_deinit(&buf); return dst_throwv(args, dst_wrap_string(message)); @@ -250,3 +256,10 @@ int dst_arity_err(DstArgs args, int32_t n, const char *prefix) { "expected %s%d argument%s, got %d", prefix, n, n == 1 ? "" : "s", args.n))); } + +int dst_typeabstract_err(DstArgs args, int32_t n, DstAbstractType *at) { + return dst_throwv(args, + dst_wrap_string(dst_formatc( + "bad argument #%d, expected %t, got %s", + n, at->name, typestr(args, n)))); +} diff --git a/src/core/value.c b/src/core/value.c index d9a04134..6367c7f3 100644 --- a/src/core/value.c +++ b/src/core/value.c @@ -151,10 +151,8 @@ int dst_compare(Dst x, Dst y) { return dst_unwrap_string(x) > dst_unwrap_string(y) ? 1 : -1; } } - } else if (dst_type(x) < dst_type(y)) { - return -1; - } - return 1; + } + return (dst_type(x) < dst_type(y)) ? -1 : 1; } /* Get a value out af an associated data structure. For invalid @@ -200,19 +198,36 @@ Dst dst_get(Dst ds, Dst key) { * error message, and NULL if no error. */ void dst_put(Dst ds, Dst key, Dst value) { switch (dst_type(ds)) { - case DST_ARRAY: - if (dst_checktype(key, DST_INTEGER) && - dst_unwrap_integer(key) >= 0 && - dst_unwrap_integer(key) < dst_unwrap_array(ds)->count) - dst_unwrap_array(ds)->data[dst_unwrap_integer(key)] = value; + case DST_ARRAY: + { + int32_t index; + DstArray *array = dst_unwrap_array(ds); + if (!dst_checktype(key, DST_INTEGER) || dst_unwrap_integer(key) < 0) + return; + index = dst_unwrap_integer(key); + if (index == INT32_MAX) return; + if (index >= array->count) { + dst_array_setcount(array, index + 1); + } + array->data[index]= value; return; + } case DST_BUFFER: - if (dst_checktype(key, DST_INTEGER) && - dst_checktype(value, DST_INTEGER) && - dst_unwrap_integer(key) >= 0 && - dst_unwrap_integer(key) < dst_unwrap_buffer(ds)->count) - dst_unwrap_buffer(ds)->data[dst_unwrap_integer(key)] = dst_unwrap_integer(value); + { + int32_t index; + DstBuffer *buffer = dst_unwrap_buffer(ds); + if (!dst_checktype(key, DST_INTEGER) || dst_unwrap_integer(key) < 0) + return; + index = dst_unwrap_integer(key); + if (index == INT32_MAX) return; + if (!dst_checktype(value, DST_INTEGER)) + return; + if (index >= buffer->count) { + dst_buffer_setcount(buffer, index + 1); + } + buffer->data[index] = (uint8_t) (dst_unwrap_integer(value) & 0xFF); return; + } case DST_TABLE: dst_table_put(dst_unwrap_table(ds), key, value); return; diff --git a/src/exported.list b/src/exported.list deleted file mode 100644 index bd0591b6..00000000 --- a/src/exported.list +++ /dev/null @@ -1,240 +0,0 @@ -{ -dst_array; -dst_array_init; -dst_array_deinit; -dst_array_ensure; -dst_array_setcount; -dst_array_push; -dst_array_pop; -dst_array_peek; - -dst_buffer; -dst_buffer_init; -dst_buffer_deinit; -dst_buffer_ensure; -dst_buffer_extra; -dst_buffer_push_bytes; -dst_buffer_push_cstring; -dst_buffer_push_u8; -dst_buffer_push_u16; -dst_buffer_push_u32; -dst_buffer_push_u64; - -dst_tuple_begin; -dst_tuple_end; -dst_tuple_n; -dst_tuple_equal; -dst_tuple_compare; - -dst_string_begin; -dst_string_end; -dst_string; -dst_cstring; -dst_string_compare; -dst_string_equal; -dst_string_equalconst; -dst_string_unique; -dst_cstring_unique; -dst_description; -dst_to_string; -dst_to_zerostring; -dst_formatc; -dst_puts; - -dst_symbol; -dst_symbol_from_string; -dst_csymbol; -dst_symbol_gen; - -dst_struct_begin; -dst_struct_put; -dst_struct_end; -dst_struct_get; -dst_struct_next; -dst_struct_to_table; -dst_struct_equal; -dst_struct_compare; -dst_struct_find; - -dst_table; -dst_table_init; -dst_table_deinit; -dst_table_get; -dst_table_rawget; -dst_table_remove; -dst_table_put; -dst_table_next; -dst_table_to_struct; -dst_table_merge_table; -dst_table_merge_struct; -dst_table_find; - -dst_fiber; - -dst_seq_view; -dst_chararray_view; -dst_hashtable_view; - -dst_abstract; - -dst_native; - -dst_mark; -dst_sweep; -dst_collect; -dst_clear_memory; -dst_gcroot; -dst_gcunroot; -dst_gcunrootall; -dst_gclock; -dst_gcunlock; - -dst_funcdef_alloc; -dst_thunk; -dst_verify; -dst_quick_asm; - -dst_equals; -dst_hash; -dst_compare; -dst_get; -dst_put; -dst_next; -dst_length; -dst_getindex; -dst_setindex; -dst_cstrcmp; - -dst_init; -dst_deinit; -dst_run; -dst_resume; - -dst_env_def; -dst_env_var; -dst_env_cfuns; -dst_env_resolve; -dst_env_arg; - -dst_stl_env; - -dst_asm; -dst_disasm; -dst_asm_decode_instruction; -dst_asm_cfun; -dst_disasm_cfun; - -dst_lib_asm; - -dst_compile; - -dst_compile_cfun; -dst_lib_compile; - -dst_stl_env; - -dst_dobytes; -dst_dostring; - -dst_core_native; - -dst_int; -dst_real; -dst_add; -dst_subtract; -dst_multiply; -dst_divide; -dst_modulo; -dst_rand; -dst_srand; -dst_strict_equal; -dst_strict_notequal; -dst_ascending; -dst_descending; -dst_notdescending; -dst_notascending; -dst_numeric_eq; -dst_numeric_neq; -dst_numeric_gt; -dst_numeric_lt; -dst_numeric_gte; -dst_numeric_lte; -dst_bor; -dst_band; -dst_bxor; -dst_bnot; -dst_lshift; -dst_rshift; -dst_lshiftu; -dst_not; - -dst_cos; -dst_sin; -dst_tan; -dst_acos; -dst_asin; -dst_atan; -dst_exp; -dst_log; -dst_log10; -dst_sqrt; -dst_floor; -dst_ceil; -dst_pow; - -dst_core_print; -dst_core_describe; -dst_core_string; -dst_core_symbol; -dst_core_buffer; -dst_core_tuple; -dst_core_array; -dst_core_table; -dst_core_struct; -dst_core_buffer; -dst_core_gensym; -dst_core_length; -dst_core_get; -dst_core_rawget; -dst_core_getproto; -dst_core_setproto; -dst_core_put; -dst_core_type; -dst_core_next; -dst_core_hash; -dst_core_string_slice; - -dst_core_gccollect; -dst_core_gcsetinterval; -dst_core_gcinterval; - -dst_lib_io; -dst_lib_math; -dst_lib_array; -dst_lib_tuple; -dst_lib_buffer; -dst_lib_table; -dst_lib_fiber; -dst_lib_os; - -dst_ast_wrap; -dst_ast_node; -dst_ast_unwrap1; -dst_ast_unwrap; - -dst_scan_number; -dst_scan_integer; -dst_scan_real; - -dst_parser_init; -dst_parser_deinit; -dst_parser_consume; -dst_parser_status; -dst_parser_produce; -dst_parser_error; - -dst_parse_cfun; - -dst_lib_parse; - -}; diff --git a/src/include/dst/dst.h b/src/include/dst/dst.h index 033c9947..1f937e6d 100644 --- a/src/include/dst/dst.h +++ b/src/include/dst/dst.h @@ -51,6 +51,7 @@ DstBuffer *dst_buffer(int32_t capacity); DstBuffer *dst_buffer_init(DstBuffer *buffer, int32_t capacity); void dst_buffer_deinit(DstBuffer *buffer); void dst_buffer_ensure(DstBuffer *buffer, int32_t capacity); +void dst_buffer_setcount(DstBuffer *buffer, int32_t count); int dst_buffer_extra(DstBuffer *buffer, int32_t n); int dst_buffer_push_bytes(DstBuffer *buffer, const uint8_t *string, int32_t len); int dst_buffer_push_string(DstBuffer *buffer, const uint8_t *string); @@ -195,9 +196,12 @@ DstTable *dst_stl_env(void); int dst_arity_err(DstArgs args, int32_t n, const char *prefix); int dst_type_err(DstArgs args, int32_t n, DstType expected); int dst_typemany_err(DstArgs args, int32_t n, int expected); +int dst_typeabstract_err(DstArgs args, int32_t n, DstAbstractType *at); #define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1) #define dst_throwv(a, v) (*((a).ret) = (v), 1) #define dst_return(a, v) (*((a).ret) = (v), 0) + +/* Early exit macros */ #define dst_maxarity(A, N) do { if ((A).n > (N))\ return dst_arity_err(A, N, "at most "); } while (0) #define dst_minarity(A, N) do { if ((A).n < (N))\ @@ -220,6 +224,53 @@ int dst_typemany_err(DstArgs args, int32_t n, int expected); }\ } while (0) +#define dst_checkabstract(A, N, AT) do {\ + if ((A).n <= (N) || !dst_checktype() {\ + Dst x = (A).v[(N)];\ + if (!dst_checktype(x, DST_ABSTRACT) ||\ + dst_abstract_type(dst_unwrap_abstract(x)) != (AT))\ + return dst_typeabstract_err(A, N, AT);\ + } else {\ + return dst_typeabstract_err(A, N, AT);\ + }\ +} while (0) + +#define dst_arg_abstract(DEST, A, N, AT) do {\ + dst_checkabstract(A, N, AT);\ + DEST = dst_unwrap_abstract((A).v[(N)]);\ +} while (0) + +#define dst_arg_integer(DEST, A, N) do { \ + dst_check(A, N, DST_INTEGER);\ + DEST = dst_unwrap_integer((A).v[(N)]); } while (0) + +#define dst_arg_real(DEST, A, N) do { \ + dst_check(A, N, DST_REAL);\ + DEST = dst_unwrap_real((A).v[(N)]); } while (0) + +#define dst_arg_number(DEST, A, N) do { \ + if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_NUMBER);\ + Dst val = (A).v[(N)];\ + if (dst_checktype(val, DST_REAL)) { DEST = dst_unwrap_real(val); }\ + else if (dst_checktype(val, DST_INTEGER)) { DEST = (double) dst_unwrap_integer(val); }\ + else dst_typemany_err(A, N, DST_TFLAG_NUMBER); } while (0) + +#define dst_arg_boolean(DEST, A, N) do { \ + dst_checkmany(A, N, DST_TFLAG_TRUE | DST_TFLAG_FALSE);\ + DEST = dst_unwrap_boolean((A).v[(N)]); } while (0) + +#define dst_arg_string(DEST, A, N) do { \ + dst_check(A, N, DST_STRING);\ + DEST = dst_unwrap_string((A).v[(N)]); } while (0) + +#define dst_arg_symbol(DEST, A, N) do { \ + dst_check(A, N, DST_SYMBOL);\ + DEST = dst_unwrap_string((A).v[(N)]); } while (0) + +#define dst_arg_buffer(DEST, A, N) do { \ + dst_check(A, N, DST_BUFFER);\ + DEST = dst_unwrap_buffer((A).v[(N)]); } while (0) + #ifdef __cplusplus } #endif