#ifndef __USCRIPT_VAL_H__ #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)}}) #define create_nada() ((struct us_val){.type=VAL_NADA, .dat={.number=0}}) #define wrap_str(o) ((struct us_val){.type=VAL_STR, .dat={.str=(o)}}) #define wrap_arr(o) ((struct us_val){.type=VAL_ARR, .dat={.arr=(o)}}) #define wrap_map(o) ((struct us_val){.type=VAL_MAP, .dat={.map=(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) #define get_bool(v) (v.dat.boolean) #define get_obj(v) (v.dat.obj) #define get_str(v) (v.dat.str) #define get_arr(v) (v.dat.arr) #define get_map(v) (v.dat.map) #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) #define proto_add_byte(func, op) da_append(u8, &(func)->bytecode, op) #define cfunc_add_upval(c, v) da_append(struct us_val, &c->upvals, v) #define cfunc_set_upval(c, i, v) (c->upvals[i] = (v)) #define cfunc_get_upval(c, i) (c->upvals[i]) enum val_type { VAL_NUM, VAL_BOOL, VAL_NADA, // Do not place any new object types before VAL_STR. Object types are // detected by doing a comparison with VAL_STR. See val_is_obj(). VAL_STR, VAL_ARR, VAL_MAP, VAL_PROTO, VAL_FUNC, VAL_CFUNC, VAL_UPVAL, }; struct us_val { enum val_type type; union { double number; bool boolean; struct us_obj *obj; struct us_str *str; struct us_arr *arr; struct us_map *map; struct us_proto *proto; struct us_func *func; struct us_cfunc *cfunc; struct us_upval *upval; } dat; }; struct us_obj { // We don't need the object header for now; it will be useful in the // future, though. u8 _placeholder; }; struct us_str { struct us_obj header; char *chars; size_t len; }; struct us_arr { struct us_obj header; struct us_val *e; // dyn_arr }; struct us_map_kv { struct us_val key; struct us_val val; }; struct us_map { struct us_obj header; struct us_map_kv *e; struct us_val locked; int len; int cap; }; struct us_proto { struct us_obj header; const struct us_str *name; struct us_val constants[UINT8_MAX]; u8 *bytecode; // dyn_arr int *lines; // dyn_arr int *upval_locs; int upvalc; int argc; bool is_variadic; u8 nconstants; }; struct us_cfunc { struct us_obj header; us_cfunc_sig c; const struct us_str *name; struct us_val *upvals; int argc; }; struct us_func { struct us_obj header; struct us_proto *proto; struct us_upval **upvals; }; struct us_upval { struct us_obj header; struct us_val *loc; struct us_val closed; struct us_upval *next; }; struct us_str *take_str(char *chars, int len); struct us_str *copy_str(const char *chars, int len); struct us_arr *create_arr(void); struct us_map *create_map(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); void proto_add_const(struct us_proto *func, struct us_val v); bool vals_eql(struct us_val a, struct us_val b); char *val_to_str(struct us_val v, int *len_out); bool val_as_bool(struct us_val v); #endif // __USCRIPT_VAL_H__