Add errorhandling helper functions and macros for writing c functions.

This commit is contained in:
Calvin Rose 2018-04-28 18:10:57 -04:00
parent 344fa031b2
commit 10934bcfb9
6 changed files with 154 additions and 39 deletions

View File

@ -106,19 +106,22 @@ Dst dst_array_peek(DstArray *array) {
/* C Functions */
static int cfun_pop(DstArgs args) {
if (args.n != 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
dst_fixarity(args, 1);
dst_check(args, 0, DST_ARRAY);
return dst_return(args, dst_array_pop(dst_unwrap_array(args.v[0])));
}
static int cfun_peek(DstArgs args) {
if (args.n != 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
dst_fixarity(args, 1);
dst_check(args, 0, DST_ARRAY);
return dst_return(args, dst_array_peek(dst_unwrap_array(args.v[0])));
}
static int cfun_push(DstArgs args) {
DstArray *array;
int32_t newcount;
if (args.n < 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
dst_minarity(args, 1);
dst_check(args, 0, DST_ARRAY);
array = dst_unwrap_array(args.v[0]);
newcount = array->count - 1 + args.n;
dst_array_ensure(array, newcount);
@ -129,8 +132,9 @@ static int cfun_push(DstArgs args) {
static int cfun_setcount(DstArgs args) {
int32_t newcount;
if (args.n != 2 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
if (!dst_checktype(args.v[1], DST_INTEGER)) return dst_throw(args, "expected positive integer");
dst_fixarity(args, 2);
dst_check(args, 0, DST_ARRAY);
dst_check(args, 1, DST_INTEGER);
newcount = dst_unwrap_integer(args.v[1]);
if (newcount < 0) return dst_throw(args, "expected positive integer");
dst_array_setcount(dst_unwrap_array(args.v[0]), newcount);
@ -139,8 +143,9 @@ static int cfun_setcount(DstArgs args) {
static int cfun_ensure(DstArgs args) {
int32_t newcount;
if (args.n != 2 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
if (!dst_checktype(args.v[1], DST_INTEGER)) return dst_throw(args, "expected positive integer");
dst_fixarity(args, 2);
dst_check(args, 0, DST_ARRAY);
dst_check(args, 1, DST_INTEGER);
newcount = dst_unwrap_integer(args.v[1]);
if (newcount < 0) return dst_throw(args, "expected positive integer");
dst_array_ensure(dst_unwrap_array(args.v[0]), newcount);
@ -152,7 +157,10 @@ static int cfun_slice(DstArgs args) {
int32_t len;
DstArray *ret;
int32_t start, end;
if (args.n < 1 || !dst_seq_view(args.v[0], &vals, &len)) return dst_throw(args, "expected array/tuple");
dst_minarity(args, 1);
dst_maxarity(args, 3);
if (!dst_seq_view(args.v[0], &vals, &len))
return dst_throw(args, "expected array|tuple");
/* Get start */
if (args.n < 2) {
start = 0;
@ -187,7 +195,8 @@ static int cfun_slice(DstArgs args) {
static int cfun_concat(DstArgs args) {
int32_t i;
DstArray *array;
if (args.n < 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
dst_minarity(args, 1);
dst_check(args, 0, DST_ARRAY);
array = dst_unwrap_array(args.v[0]);
for (i = 1; i < args.n; i++) {
switch (dst_type(args.v[i])) {

View File

@ -97,6 +97,10 @@ int dst_buffer_push_bytes(DstBuffer *buffer, const uint8_t *string, int32_t leng
return 0;
}
int dst_buffer_push_string(DstBuffer *buffer, const uint8_t *string) {
return dst_buffer_push_bytes(buffer, string, dst_string_length(string));
}
/* Push a single byte to the buffer */
int dst_buffer_push_u8(DstBuffer *buffer, uint8_t byte) {
if (dst_buffer_extra(buffer, 1)) return -1;

View File

@ -127,7 +127,7 @@ int dst_core_struct(DstArgs args) {
}
int dst_core_gensym(DstArgs args) {
if (args.n > 1) return dst_throw(args, "expected one argument");
dst_maxarity(args, 1);
if (args.n == 0) {
return dst_return(args, dst_wrap_symbol(dst_symbol_gen(NULL, 0)));
} else {
@ -137,14 +137,14 @@ int dst_core_gensym(DstArgs args) {
}
int dst_core_length(DstArgs args) {
if (args.n != 1) return dst_throw(args, "expected at least 1 argument");
dst_checkmany(args, 0, DST_TFLAG_LENGTHABLE);
return dst_return(args, dst_wrap_integer(dst_length(args.v[0])));
}
int dst_core_get(DstArgs args) {
int32_t i;
Dst ds;
if (args.n < 1) return dst_throw(args, "expected at least 1 argument");
dst_minarity(args, 1);
ds = args.v[0];
for (i = 1; i < args.n; i++) {
ds = dst_get(ds, args.v[i]);
@ -155,15 +155,15 @@ int dst_core_get(DstArgs args) {
}
int dst_core_rawget(DstArgs args) {
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
if (!dst_checktype(args.v[0], DST_TABLE)) return dst_throw(args, "expected table");
dst_fixarity(args, 2);
dst_check(args, 0, DST_TABLE);
return dst_return(args, dst_table_rawget(dst_unwrap_table(args.v[0]), args.v[1]));
}
int dst_core_getproto(DstArgs args) {
DstTable *t;
if (args.n != 1) return dst_throw(args, "expected 1 argument");
if (!dst_checktype(args.v[0], DST_TABLE)) return dst_throw(args, "expected table");
dst_fixarity(args, 1);
dst_check(args, 0, DST_TABLE);
t = dst_unwrap_table(args.v[0]);
return dst_return(args, t->proto
? dst_wrap_table(t->proto)
@ -171,10 +171,9 @@ int dst_core_getproto(DstArgs args) {
}
int dst_core_setproto(DstArgs args) {
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
if (!dst_checktype(args.v[0], DST_TABLE)) return dst_throw(args, "expected table");
if (!dst_checktype(args.v[1], DST_TABLE) && !dst_checktype(args.v[1], DST_NIL))
return dst_throw(args, "expected table");
dst_fixarity(args, 2);
dst_check(args, 0, DST_TABLE);
dst_checkmany(args, 1, DST_TFLAG_TABLE | DST_TFLAG_NIL);
dst_unwrap_table(args.v[0])->proto = dst_checktype(args.v[1], DST_TABLE)
? dst_unwrap_table(args.v[1])
: NULL;
@ -184,7 +183,7 @@ int dst_core_setproto(DstArgs args) {
int dst_core_put(DstArgs args) {
Dst ds, key, value;
DstArgs subargs = args;
if (args.n < 3) return dst_throw(args, "expected at least 3 arguments");
dst_minarity(args, 3);
subargs.n -= 2;
if (dst_core_get(subargs)) return 1;
ds = *args.ret;
@ -201,20 +200,23 @@ int dst_core_gccollect(DstArgs args) {
}
int dst_core_gcsetinterval(DstArgs args) {
if (args.n < 1 ||
!dst_checktype(args.v[0], DST_INTEGER) ||
dst_unwrap_integer(args.v[0]) < 0)
int32_t val;
dst_fixarity(args, 1);
dst_check(args, 0, DST_INTEGER);
val = dst_unwrap_integer(args.v[0]);
if (val < 0)
return dst_throw(args, "expected non-negative integer");
dst_vm_gc_interval = dst_unwrap_integer(args.v[0]);
return dst_return(args, dst_wrap_integer(dst_vm_gc_interval));
dst_vm_gc_interval = val;
return dst_return(args, args.v[0]);
}
int dst_core_gcinterval(DstArgs args) {
dst_fixarity(args, 0);
return dst_return(args, dst_wrap_integer(dst_vm_gc_interval));
}
int dst_core_type(DstArgs args) {
if (args.n != 1) return dst_throw(args, "expected 1 argument");
dst_fixarity(args, 1);
if (dst_checktype(args.v[0], DST_ABSTRACT)) {
return dst_return(args, dst_csymbolv(dst_abstract_type(dst_unwrap_abstract(args.v[0]))->name));
} else {
@ -225,20 +227,19 @@ int dst_core_type(DstArgs args) {
int dst_core_next(DstArgs args) {
Dst ds;
const DstKV *kv;
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
dst_fixarity(args, 2);
dst_checkmany(args, 0, DST_TFLAG_DICTIONARY);
ds = args.v[0];
if (dst_checktype(ds, DST_TABLE)) {
DstTable *t = dst_unwrap_table(ds);
kv = dst_checktype(args.v[1], DST_NIL)
? NULL
: dst_table_find(t, args.v[1]);
} else if (dst_checktype(ds, DST_STRUCT)) {
} else {
const DstKV *st = dst_unwrap_struct(ds);
kv = dst_checktype(args.v[1], DST_NIL)
? NULL
: dst_struct_find(st, args.v[1]);
} else {
return dst_throw(args, "expected table/struct");
}
kv = dst_next(ds, kv);
if (kv) {
@ -248,7 +249,7 @@ int dst_core_next(DstArgs args) {
}
int dst_core_hash(DstArgs args) {
if (args.n != 1) return dst_throw(args, "expected 1 argument");
dst_fixarity(args, 1);
return dst_return(args, dst_wrap_integer(dst_hash(args.v[0])));
}
@ -256,8 +257,10 @@ int dst_core_string_slice(DstArgs args) {
const uint8_t *data;
int32_t len, start, end;
const uint8_t *ret;
if (args.n < 1 || !dst_chararray_view(args.v[0], &data, &len))
return dst_throw(args, "expected buffer/string");
dst_minarity(args, 1);
dst_maxarity(args, 3);
if (!dst_chararray_view(args.v[0], &data, &len))
return dst_throw(args, "expected buffer|string|symbol");
/* Get start */
if (args.n < 2) {
start = 0;

View File

@ -205,3 +205,48 @@ 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) {
DstType actual = n < args.n ? dst_type(args.v[n]) : DST_NIL;
const uint8_t *message = dst_formatc(
"bad argument #%d, expected %t, got %t",
n,
expected,
actual);
return dst_throwv(args, dst_wrap_string(message));
}
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));
i = 0;
while (expected) {
if (1 & expected) {
if (first) {
first = 0;
} else {
dst_buffer_push_u8(&buf, '|');
}
dst_buffer_push_cstring(&buf, dst_type_names[i] + 1);
}
i++;
expected >>= 1;
}
dst_buffer_push_cstring(&buf, ", got ");
dst_buffer_push_cstring(&buf, dst_type_names[actual] + 1);
message = dst_string(buf.data, buf.count);
dst_buffer_deinit(&buf);
return dst_throwv(args, dst_wrap_string(message));
}
int dst_arity_err(DstArgs args, int32_t n, const char *prefix) {
return dst_throwv(args,
dst_wrap_string(dst_formatc(
"expected %s%d argument%s, got %d",
prefix, n, n == 1 ? "" : "s", args.n)));
}

View File

@ -53,6 +53,7 @@ void dst_buffer_deinit(DstBuffer *buffer);
void dst_buffer_ensure(DstBuffer *buffer, int32_t capacity);
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);
int dst_buffer_push_cstring(DstBuffer *buffer, const char *cstring);
int dst_buffer_push_u8(DstBuffer *buffer, uint8_t x);
int dst_buffer_push_u16(DstBuffer *buffer, uint16_t x);
@ -180,11 +181,6 @@ void dst_deinit(void);
Dst dst_run(DstFiber *fiber);
Dst dst_resume(DstFiber *fiber, int32_t argn, const Dst *argv);
/* C Function helpers */
#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)
/* Env helpers */
void dst_env_def(DstTable *env, const char *name, Dst val);
void dst_env_var(DstTable *env, const char *name, Dst val);
@ -195,6 +191,35 @@ DstTable *dst_env_arg(DstArgs args);
/* STL */
DstTable *dst_stl_env(void);
/* C Function helpers */
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);
#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)
#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))\
return dst_arity_err(A, N, "at least "); } while (0)
#define dst_fixarity(A, N) do { if ((A).n != (N))\
return dst_arity_err(A, N, ""); } while (0)
#define dst_check(A, N, T) do {\
if ((A).n > (N)) {\
if (!dst_checktype((A).v[(N)], (T))) return dst_type_err(A, N, T);\
} else {\
if ((T) != DST_NIL) return dst_type_err(A, N, T);\
}\
} while (0)
#define dst_checkmany(A, N, TS) do {\
if ((A).n > (N)) {\
DstType t = dst_type((A).v[(N)]);\
if (!((1 << t) & (TS))) return dst_typemany_err(A, N, TS);\
} else {\
if (!((TS) & DST_NIL)) return dst_type_err(A, N, TS);\
}\
} while (0)
#ifdef __cplusplus
}
#endif

View File

@ -78,6 +78,35 @@ typedef enum DstType {
DST_ABSTRACT
} DstType;
#define DST_COUNT_TYPES (DST_ABSTRACT + 1)
/* Type flags */
#define DST_TFLAG_NIL (1 << DST_NIL)
#define DST_TFLAG_FALSE (1 << DST_FALSE)
#define DST_TFLAG_TRUE (1 << DST_TRUE)
#define DST_TFLAG_FIBER (1 << DST_FIBER)
#define DST_TFLAG_INTEGER (1 << DST_INTEGER)
#define DST_TFLAG_REAL (1 << DST_REAL)
#define DST_TFLAG_STRING (1 << DST_STRING)
#define DST_TFLAG_SYMBOL (1 << DST_SYMBOL)
#define DST_TFLAG_ARRAY (1 << DST_ARRAY)
#define DST_TFLAG_TUPLE (1 << DST_TUPLE)
#define DST_TFLAG_TABLE (1 << DST_TABLE)
#define DST_TFLAG_STRUCT (1 << DST_STRUCT)
#define DST_TFLAG_BUFFER (1 << DST_BUFFER)
#define DST_TFLAG_FUNCTION (1 << DST_FUNCTION)
#define DST_TFLAG_CFUNCTION (1 << DST_CFUNCTION)
#define DST_TFLAG_ABSTRACT (1 << DST_ABSTRACT)
/* Some abstractions */
#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_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)
/* We provide two possible implemenations of Dsts. The preferred
* nanboxing approach, and the standard C version. Code in the rest of the
* application must interact through exposed interface. */