mirror of
https://github.com/janet-lang/janet
synced 2024-11-25 01:37:19 +00:00
Add errorhandling helper functions and macros for writing c functions.
This commit is contained in:
parent
344fa031b2
commit
10934bcfb9
@ -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])) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user