From ed1f406102738812fafa5e49ee131fe06c177687 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 13 Oct 2021 16:44:17 +0200 Subject: Add a lot of primitive types --- src/bootstrap/primitives.c | 900 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 900 insertions(+) create mode 100644 src/bootstrap/primitives.c (limited to 'src/bootstrap/primitives.c') diff --git a/src/bootstrap/primitives.c b/src/bootstrap/primitives.c new file mode 100644 index 0000000..8369fa8 --- /dev/null +++ b/src/bootstrap/primitives.c @@ -0,0 +1,900 @@ +Object * +eval(Environment* env, Object *root) { + switch (root->type) { + case OBJ_TYPE_FIXNUM: + case OBJ_TYPE_BOOL: + case OBJ_TYPE_NIL: + case OBJ_TYPE_STRING: { + return root; + } break; + case OBJ_TYPE_SYMBOL: { + Object *val = env_lookup(env, root); + if (val == obj_err) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_SYMBOL_NOT_FOUND, + }); + return obj_err; + } + return val; + } break; + case OBJ_TYPE_PAIR: { + if (root->car->type == OBJ_TYPE_SYMBOL) { + Object *val = env_lookup(env, root->car); + if (val == obj_err) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_SYMBOL_NOT_FOUND, + }); + return obj_err; + } + if (val->type == OBJ_TYPE_PROCEDURE) { + return val->proc(env, root->cdr); + } + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_OBJ_NOT_CALLABLE, + }); + return obj_err; + } + } break; + default: { + break; + } break; + } + + printf("DING\n"); + display(root); + printf("\nTYPE: %d\n", root->type); + + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_UNKNOWN_OBJ_TYPE, + }); + return obj_err; +} + +Object * +proc_quote(Environment *env, Object *obj) { + (void)env; + return obj->car; +} + +// +// Arithmetic procedures. +// + +Object * +proc_sum(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t tot = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + tot += car->fixnum; + obj = obj->cdr; + } + return make_fixnum(tot); +} + +Object * +proc_sub(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t tot = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + tot -= car->fixnum; + obj = obj->cdr; + } + return make_fixnum(tot); +} + +Object * +proc_mul(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t tot = car->fixnum; + while (obj != obj_nil) { + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + tot *= car->fixnum; + obj = obj->cdr; + } + return make_fixnum(tot); +} + +Object * +proc_div(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t tot = car->fixnum; + while (obj != obj_nil) { + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (car->fixnum == 0) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_DIVISION_BY_ZERO, + }); + return obj_err; + } + tot /= car->fixnum; + obj = obj->cdr; + } + return make_fixnum(tot); +} + +Object * +proc_mod(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t tot = car->fixnum; + while (obj != obj_nil) { + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (car->fixnum == 0) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_DIVISION_BY_ZERO, + }); + return obj_err; + } + tot %= car->fixnum; + obj = obj->cdr; + } + return make_fixnum(tot); +} + +// +// Display/Evaluation procedues. +// + +Object * +proc_display(Environment *env, Object *obj) { + display(eval(env, obj->car)); + return obj_nil; +} + +Object * +proc_print(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_STRING) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + StringView scanner = (StringView) { + .start = car->string, + .n = car->string_n, + }; + while (scanner.n != 0) { + char c = sv_next(&scanner); + if (c == '\\' && sv_peek(&scanner) == 'n') { + putchar('\n'); + sv_next(&scanner); + continue; + } + if (c == '\\' && sv_peek(&scanner) == '"') { + putchar('"'); + sv_next(&scanner); + continue; + } + putchar(c); + } + return obj_nil; +} + +Object * +proc_newline(Environment *env, Object *obj) { + printf("\n"); + (void)env; + (void)obj; + return obj_nil; +} + +// +// Type info procedures. +// + +Object * +proc_is_boolean(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return (obj == obj_true || obj == obj_false) ? obj_true : obj_false; +} + +Object * +proc_is_nil(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj == obj_nil ? obj_true : obj_false; +} + +Object * +proc_is_symbol(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj->type == OBJ_TYPE_SYMBOL ? obj_true : obj_false; +} + +Object * +proc_is_string(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj->type == OBJ_TYPE_STRING ? obj_true : obj_false; +} + +Object * +proc_is_fixnum(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj->type == OBJ_TYPE_FIXNUM ? obj_true : obj_false; +} + +Object * +proc_is_pair(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj->type == OBJ_TYPE_PAIR ? obj_true : obj_false; +} + +Object * +proc_is_procedure(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj->type == OBJ_TYPE_PROCEDURE ? obj_true : obj_false; +} + +// +// Boolean/conditional procedures. +// + +Object * +proc_not(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + return obj == obj_false ? obj_true : obj_false; +} + +Object * +proc_and(Environment *env, Object *obj) { + while (obj != obj_nil) { + if (proc_not(env, obj) == obj_true) { + return obj_false; + } + obj = obj->cdr; + } + return obj_true; +} + +Object * +proc_or(Environment *env, Object *obj) { + while (obj != obj_nil) { + if (proc_not(env, obj) == obj_false) { + return obj_true; + } + obj = obj->cdr; + } + return obj_false; +} + +Object * +proc_if(Environment *env, Object *obj) { + if (obj == obj_nil || obj->cdr == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = obj->car; + Object *cdr = obj->cdr; + Object *clause = eval(env, car); + if (obj == obj_err) { + return obj_err; + } + if (clause == obj_true) { + return eval(env, cdr->car); + } + if (obj->cdr->cdr != obj_nil) { + return eval(env, cdr->cdr->car); + } + + return obj_nil; +} + +Object * +proc_cond(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + + if (obj->car->type != OBJ_TYPE_PAIR) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // TODO: review this, the cdr->car could cause issues? + while (obj != obj_nil) { + Object *clause = obj->car; + Object *result = eval(env, clause->car); + if (result == obj_err) { + return obj_err; + } + if (result == obj_true) { + return eval(env, clause->cdr->car); + } + obj = obj->cdr; + } + return obj_nil; +} + +Object * +proc_num_less_than(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t prev = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (prev >= car->fixnum) { + return obj_false; + } + prev = car->fixnum; + obj = obj->cdr; + } + return obj_true; +} + +Object * +proc_num_greater_than(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t prev = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (prev <= car->fixnum) { + return obj_false; + } + prev = car->fixnum; + obj = obj->cdr; + } + return obj_true; +} + +Object * +proc_num_lesseq_than(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t prev = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (prev > car->fixnum) { + return obj_false; + } + prev = car->fixnum; + obj = obj->cdr; + } + return obj_true; +} + +Object * +proc_num_greatereq_than(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t prev = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (prev < car->fixnum) { + return obj_false; + } + prev = car->fixnum; + obj = obj->cdr; + } + return obj_true; +} + +Object * +proc_num_equal(Environment *env, Object *obj) { + // First argument. + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + Object *car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + // Traverse the list. + obj = obj->cdr; + ssize_t prev = car->fixnum; + while (obj != obj_nil) { + car = eval(env, obj->car); + if (car == obj_err) { + return obj_err; + } + if (car->type != OBJ_TYPE_FIXNUM) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + if (prev != car->fixnum) { + return obj_false; + } + prev = car->fixnum; + obj = obj->cdr; + } + return obj_true; +} + +// +// List operation procedures. +// + +Object * +proc_car(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + if (obj->type != OBJ_TYPE_PAIR) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + return obj->car; +} + +Object * +proc_cdr(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + obj = eval(env, obj->car); + if (obj == obj_err) { + return obj_err; + } + if (obj->type != OBJ_TYPE_PAIR) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + return obj->cdr; +} + +Object * +proc_cons(Environment *env, Object *obj) { + if (obj == obj_nil || obj->cdr == obj_nil) { + fprintf(stderr, "error: not enough arguments\n"); + return obj_nil; + } + Object *a = eval(env, obj->car); + Object *b = eval(env, obj->cdr->car); + return make_pair(a, b); +} + +Object * +proc_list(Environment *env, Object *obj) { + if (obj == obj_nil) { + return obj_nil; + } + Object *head = make_pair(eval(env, obj->car), obj_nil); + Object *curr = head; + obj = obj->cdr; + while (obj != obj_nil) { + curr->cdr = make_pair(eval(env, obj->car), obj_nil); + curr = curr->cdr; + obj = obj->cdr; + } + return head; +} + +// +// Polymorphic procedures. +// + +//Object * +//proc_equal(Object *args) { +// // TODO: stub +// (void) args; +// return NULL; +//} + +//// TODO: fixnum left/right shift, mask, invert +//// TODO: implement and test missing procedures +//// TODO: add primitives for type transforms: string->symbol, symbol->string, etc +//// TODO: properly implement nested environments +//// TODO: implement support for quotes and semi-quotes +//// TODO: LAMBDA +//// TODO: let +//// TODO: better error handling? +//// TODO: Revise all instances where we are returning an object, since currently +//// we may be returning a pointer to an object instead of a new one. Check also +//// on eval function and everytime we do make_xxx(obj). -- cgit v1.2.1