diff options
Diffstat (limited to 'uscript')
| -rw-r--r-- | uscript/uscript.c | 7 | ||||
| -rw-r--r-- | uscript/uscript.h | 4 | ||||
| -rw-r--r-- | uscript/val.c | 33 | ||||
| -rw-r--r-- | uscript/val.h | 13 | ||||
| -rw-r--r-- | uscript/vm.c | 63 | ||||
| -rw-r--r-- | uscript/vm.h | 2 |
6 files changed, 107 insertions, 15 deletions
diff --git a/uscript/uscript.c b/uscript/uscript.c index 2b32110..ee02f15 100644 --- a/uscript/uscript.c +++ b/uscript/uscript.c @@ -37,3 +37,10 @@ int us_declare_global(const char *name) { return declare_global(copy_str(name, -1)); } + +void us_set_cfunc(const char *c_name, us_cfunc_sig c, int argc) +{ + struct us_str *name = copy_str(c_name, -1); + int global = declare_global(name); + set_global(global, wrap_cfunc(create_cfunc(name, c, argc))); +} diff --git a/uscript/uscript.h b/uscript/uscript.h index 74958e5..a7efced 100644 --- a/uscript/uscript.h +++ b/uscript/uscript.h @@ -3,6 +3,8 @@ struct us_func; +typedef void (*us_cfunc_sig)(int argc); + void us_init(void); void us_deinit(void); @@ -11,4 +13,6 @@ void us_load_src(const char *src); void us_exec(struct us_func *func); +void us_set_cfunc(const char *c_name, us_cfunc_sig c, int argc); + #endif // __USCRIPT_LANG_H__ diff --git a/uscript/val.c b/uscript/val.c index 77f7753..f204e20 100644 --- a/uscript/val.c +++ b/uscript/val.c @@ -68,6 +68,16 @@ struct us_func *create_func(struct us_proto *proto) return func; } +struct us_cfunc *create_cfunc(struct us_str *name, us_cfunc_sig func, int argc) +{ + struct us_cfunc *cfunc = mem_alloc(sizeof(struct us_cfunc)); + cfunc->name = name; + cfunc->c = func; + cfunc->argc = argc; + init_obj(wrap_cfunc(cfunc), &cfunc->header); + return cfunc; +} + struct us_upval *create_upval(struct us_val *val) { struct us_upval *upval = mem_alloc(sizeof(struct us_upval)); @@ -106,6 +116,7 @@ void free_val(struct us_val v) mem_free(func); break; } + case VAL_CFUNC: case VAL_UPVAL: mem_free(get_obj(v)); break; @@ -140,6 +151,7 @@ bool vals_eql(struct us_val a, struct us_val b) } case VAL_ARR: case VAL_FUNC: + case VAL_CFUNC: case VAL_UPVAL: case VAL_PROTO: return get_obj(a) == get_obj(b); } @@ -219,6 +231,27 @@ char *val_to_str(struct us_val v, int *len_out) } case VAL_FUNC: return val_to_str(wrap_proto(get_func(v)->proto), len_out); + case VAL_CFUNC: { + const struct us_cfunc *cfunc = get_cfunc(v); + int len = snprintf( + NULL, + 0, + STR_FUNC_FMT, + cfunc->name->chars, + (void*)cfunc + ); + char *str = mem_alloc(sizeof(char) * (len + 1)); + snprintf( + str, + len + 1, + STR_FUNC_FMT, + cfunc->name->chars, + (void*)cfunc + ); + if (len_out) + *len_out = len; + return str; + } case VAL_UPVAL: return val_to_str(*get_upval(v)->loc, len_out); } diff --git a/uscript/val.h b/uscript/val.h index 4789973..5140fc2 100644 --- a/uscript/val.h +++ b/uscript/val.h @@ -2,6 +2,7 @@ #define __USCRIPT_VAL_H__ #include "common.h" +#include "uscript.h" #define create_num(n) ((struct us_val){.type=VAL_NUM, .dat={.number=(n)}}) #define create_bool(b) ((struct us_val){.type=VAL_BOOL, .dat={.boolean=(b)}}) @@ -10,6 +11,7 @@ #define wrap_arr(o) ((struct us_val){.type=VAL_ARR, .dat={.arr=(o)}}) #define wrap_proto(o) ((struct us_val){.type=VAL_PROTO, .dat={.proto=(o)}}) #define wrap_func(o) ((struct us_val){.type=VAL_FUNC, .dat={.func=(o)}}) +#define wrap_cfunc(o) ((struct us_val){.type=VAL_CFUNC, .dat={.cfunc=(o)}}) #define wrap_upval(o) ((struct us_val){.type=VAL_UPVAL, .dat={.upval=(o)}}) #define get_num(v) (v.dat.number) @@ -19,6 +21,7 @@ #define get_arr(v) (v.dat.arr) #define get_proto(v) (v.dat.proto) #define get_func(v) (v.dat.func) +#define get_cfunc(v) (v.dat.cfunc) #define get_upval(v) (v.dat.upval) #define val_is_obj(v) (v.type >= VAL_STR) @@ -35,6 +38,7 @@ enum val_type { VAL_ARR, VAL_PROTO, VAL_FUNC, + VAL_CFUNC, VAL_UPVAL, }; @@ -48,6 +52,7 @@ struct us_val { struct us_arr *arr; struct us_proto *proto; struct us_func *func; + struct us_cfunc *cfunc; struct us_upval *upval; } dat; }; @@ -81,6 +86,13 @@ struct us_proto { u8 nconstants; }; +struct us_cfunc { + struct us_obj header; + us_cfunc_sig c; + const struct us_str *name; + int argc; +}; + struct us_func { struct us_obj header; struct us_proto *proto; @@ -99,6 +111,7 @@ struct us_str *copy_str(const char *chars, int len); struct us_arr *create_arr(void); struct us_proto *create_proto(struct us_str *name); struct us_func *create_func(struct us_proto *proto); +struct us_cfunc *create_cfunc(struct us_str *name, us_cfunc_sig func, int argc); struct us_upval *create_upval(struct us_val *val); void free_val(struct us_val v); diff --git a/uscript/vm.c b/uscript/vm.c index 363912a..c01bb0f 100644 --- a/uscript/vm.c +++ b/uscript/vm.c @@ -76,12 +76,59 @@ void close_upvals(struct us_val *to) vm.open_upvals = upval; } + +static +void call_val(struct us_val callee, int argc) +{ + switch (callee.type) { + case VAL_FUNC: { + struct us_func *func = get_func(callee); + if (argc != func->proto->argc) { + log_fatal( + 1, + "wrong number of arguments to '%s()' (%d/%d)", + func->proto->name->chars, + argc, + func->proto->argc + ); + } + us_exec(func); + break; + } + case VAL_CFUNC: { + struct us_cfunc *cfunc = get_cfunc(callee); + if (argc != cfunc->argc) { + log_fatal( + 1, + "wrong number of arguments to '%s()' (%d/%d)", + cfunc->name->chars, + argc, + cfunc->argc + ); + } + + vm.cf++; + vm.cf->func = wrap_cfunc(cfunc); + vm.cf->stackbot = vm.stacktop - argc; + cfunc->c(argc); + struct us_val ret_val = vm_pop(); + vm.stacktop = vm.cf->stackbot - 1; + vm.cf--; + vm_push(ret_val); + break; + } + default: + log_fatal(1, "cannot call that value"); + break; + } +} + void us_exec(struct us_func *func) { #define read_byte() (func->proto->bytecode[++i]) #define read_const() (func->proto->constants[read_byte()]) vm.cf++; - vm.cf->func = func; + vm.cf->func = wrap_func(func); vm.cf->stackbot = vm.stacktop - func->proto->argc; for (int i = 0; i < da_len(func->proto->bytecode); i++) { @@ -344,19 +391,7 @@ void us_exec(struct us_func *func) case BC_CALL: { int argc = read_byte(); struct us_val callee = vm.stacktop[-argc - 1]; - if (callee.type != VAL_FUNC) - log_fatal(1, "can only call functions"); - struct us_func *func = get_func(callee); - if (argc != func->proto->argc) { - log_fatal( - 1, - "wrong number of arguments to '%s()' (%d/%d)", - func->proto->name->chars, - argc, - func->proto->argc - ); - } - us_exec(func); + call_val(callee, argc); break; } case BC_RET: { diff --git a/uscript/vm.h b/uscript/vm.h index 2911d01..cf9aa60 100644 --- a/uscript/vm.h +++ b/uscript/vm.h @@ -20,7 +20,7 @@ enum bytecode { }; struct call_frame { - struct us_func *func; + struct us_val func; struct us_val *stackbot; }; |
