#include #include #include #include #include "lib.h" #include "state.h" #include "val.h" #include "util.h" #include "mem.h" static Val fn_clock(State *S, int nargs, Val *args) { return VAL_NUM((double)clock() / CLOCKS_PER_SEC); } static Val fn_write(State *S, int nargs, Val *args) { CHECK(nargs>0, "need 1 arg to write"); for (int i = 0; i < nargs; i++) print_val(args[i]); return VAL_NIL; } static Val fn_say(State *S, int nargs, Val *args) { CHECK(nargs>0, "need 1 arg to say"); for (int i = 0; i < nargs; i++) println_val(args[i]); return VAL_NIL; } static uint8_t num_to_u8(Val v) { CHECK(IS_NUM(v), "can't convert non-num to u8"); return (uint8_t)AS_NUM(v); } static Val fn_writebytes(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need exactly 1 arg to writebytes"); CHECK(IS_ARR(args[0]), "need array arg to writebytes"); ObjArr *a = AS_ARR(args[0]); uint8_t *buf = malloc(1 * a->len); for (int i = 0; i < a->len; i++) { buf[i] = num_to_u8(a->d[i]); } fwrite(buf, 1, a->len, stdout); return VAL_NIL; } static Val fn_readstring(State *S, int nargs, Val *args){ CHECK(nargs == 1, "need exactly 1 arg to readstring"); CHECK(IS_STRING(args[0]), "need string arg to readstring"); FILE *f = fopen(AS_CSTRING(args[0]), "r"); CHECK(f != NULL, "io error (fopen)"); fseek(f, 0L, SEEK_END); long flen = ftell(f); char *buf = NEW_ARR(S, char, flen+1); rewind(f); fread(buf, 1, flen, f); CHECK(!ferror(f), "file error"); buf[flen] = '\0'; return VAL_OBJ(objstring_take(S, buf, flen)); } // lists static Val fn_arr(State *S, int nargs, Val *args) { CHECK(nargs == 0, "need 0 args to arr"); ObjArr *o = objarr_new(S); return VAL_OBJ(o); } static Val fn_append(State *S, int nargs, Val *args) { CHECK(nargs == 2, "need 2 args to append!"); CHECK(IS_ARR(args[0]), "can only append to arr"); ObjArr *a = AS_ARR(args[0]); objarr_append(S, a, args[1]); return args[0]; } static Val fn_delete(State *S, int nargs, Val *args) { CHECK(nargs == 2, "need 2 args to delete!"); CHECK(IS_ARR(args[0]), "can only delete from arr"); CHECK(IS_NUM(args[1]), "can only delete using num index"); ObjArr *a = AS_ARR(args[0]); size_t ix = (size_t)AS_NUM(args[1]); objarr_delete(S, a, ix); return args[0]; } static Val fn_len(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need 1 arg to len"); CHECK(IS_ARR(args[0]), "can only take length of arr"); ObjArr *a = AS_ARR(args[0]); return VAL_NUM(a->len); } static Val fn_pend(State *S, int nargs, Val *args) { CHECK(nargs > 0, "need at least 1 arg to ,"); ObjArr *a = objarr_new(S); for (int i = 0; i < nargs; i++) { Val v = args[i]; if (!IS_ARR(v)) objarr_append(S, a, v); else { ObjArr *b = AS_ARR(v); for (int j = 0; j < b->len; j++) objarr_append(S, a, b->d[j]); } } return VAL_OBJ(a); } // strings static Val fn_spend(State *S, int nargs, Val *args) { size_t len = 0; for (int i = 0; i < nargs; i++) { CHECK(IS_STRING(args[i]), "can only spend strings"); len += AS_STRING(args[i])->len; } char *new = NEW_ARR(S, char, len+1); char *cur = new; for (int i = 0; i < nargs; i++) { ObjString *s = AS_STRING(args[i]); memcpy(cur, s->d, s->len); cur += s->len; } return VAL_OBJ(objstring_take(S, new, len)); } static Val fn_spendsplat(State *S, int nargs, Val *args) { CHECK(nargs==1, "need exactly 1 arg for spendsplat"); CHECK(IS_ARR(args[0]), "need arr arg for spendsplat"); ObjArr *a = AS_ARR(args[0]); return fn_spend(S, a->len, a->d); } static Val fn_ssplit(State *S, int nargs, Val *args) { CHECK(nargs==2,"need exactly 2 args for ssplit"); CHECK(IS_STRING(args[0]) && IS_STRING(args[1]), "need two strings for ssplit"); ObjString *delim = AS_STRING(args[0]); ObjString *text = AS_STRING(args[1]); CHECK(delim->len == 1, "need length-1 delimiter"); char delimc = delim->d[0]; ObjArr *out = objarr_new(S); int start = 0; for (int i = 0; i <= text->len; i++) { if (text->d[i] == delimc || i == text->len) { ObjString *new = objstring_copy(S, &text->d[start], i-start); objarr_append(S, out, VAL_OBJ(new)); start = i + 1; } } return VAL_OBJ(out); } static Val fn_schars_ascii(State *S, int nargs, Val *args) { CHECK(nargs==1, "need exactly 1 args for schars-ascii"); CHECK(IS_STRING(args[0]), "need string arg for schars-ascii"); ObjString *s = AS_STRING(args[0]); ObjArr *a = objarr_new(S); for (int i = 0; i < s->len; i++) objarr_append(S, a, VAL_OBJ(objstring_copy(S, &s->d[i], 1))); return VAL_OBJ(a); } // math static Val fn_sin(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need exactly 1 arg for sin"); CHECK(IS_NUM(args[0]), "need num for sin"); double x = AS_NUM(args[0]); return VAL_NUM(sin(x)); } static Val fn_cos(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need exactly 1 arg for cos"); CHECK(IS_NUM(args[0]), "need num for cos"); double x = AS_NUM(args[0]); return VAL_NUM(cos(x)); } static Val fn_ceil(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need exactly 1 arg for ceil"); CHECK(IS_NUM(args[0]), "need num for ceil"); double x = AS_NUM(args[0]); return VAL_NUM(ceil(x)); } static Val fn_floor(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need exactly 1 arg for floor"); CHECK(IS_NUM(args[0]), "need num for floor"); double x = AS_NUM(args[0]); return VAL_NUM(floor(x)); } static Val fn_abs(State *S, int nargs, Val *args) { CHECK(nargs == 1, "need exactly 1 arg for abs"); CHECK(IS_NUM(args[0]), "need num for abs"); double x = AS_NUM(args[0]); return VAL_NUM(abs(x)); } typedef struct { char *name; CFunc func; } BuiltinFunc; static BuiltinFunc builtin_funcs[] = { { "clock", fn_clock }, { "say", fn_say }, { "write", fn_write }, { "writebytes", fn_writebytes }, { "readstring", fn_readstring }, { "arr", fn_arr }, { "append!", fn_append }, { "delete!", fn_delete }, { "#", fn_len }, { ",", fn_pend }, { "s,", fn_spend }, { "s,@", fn_spendsplat }, { "ssplit", fn_ssplit }, { "schars-ascii", fn_schars_ascii }, { "sin", fn_sin }, { "cos", fn_cos }, { "ceil", fn_ceil }, { "floor", fn_floor }, { "abs", fn_abs }, { 0 }, }; void load_stdlib(State *S) { for (BuiltinFunc *b = builtin_funcs; b->name != NULL; b++) { ObjString *oname = objstring_copy_cstr(S, b->name); ht_put(S, &S->globals, oname, VAL_CFUNC(b->func)); } }