summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriamcheeseman <[email protected]>2026-04-14 12:47:56 -0400
committeriamcheeseman <[email protected]>2026-04-14 12:47:56 -0400
commit968a7292f0b88f9485f4511e48acbee36cf71036 (patch)
tree1b0f5c68774c81a939b8c408c33517f53aae5518
parentca004156cbb1c525900f444994112fc17b71d63d (diff)
microscript: add c functions
-rw-r--r--uscript/uscript.c7
-rw-r--r--uscript/uscript.h4
-rw-r--r--uscript/val.c33
-rw-r--r--uscript/val.h13
-rw-r--r--uscript/vm.c63
-rw-r--r--uscript/vm.h2
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;
};