#include "native_funs.h" void lispf_add(lisp_cons* cons, lisp_value* value) { long _int = 0; float _float = 0.0f; bool is_float = false; while (cons != NULL) { if (!is_float) { if (cons->car.type == LISP_T_INT) _int += cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) { _float = (float) _int; is_float = true; _float += cons->car.value._float; } } else { if (cons->car.type == LISP_T_INT) _float += cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) _float += cons->car.value._float; } cons = cons->cdr.value.cons; } if (is_float) { value->type = LISP_T_FLOAT; value->value._float = _float; } else { value->type = LISP_T_INT; value->value._int = _int; } } void lispf_sub(lisp_cons* cons, lisp_value* value) { long _int = 0; float _float = 0.0f; bool is_float = false; if (cons->car.type == LISP_T_FLOAT) { _float = cons->car.value._float; is_float = true; } else if (cons->car.type == LISP_T_INT) { _int = cons->car.value._int; } else { value->type = LISP_T_CONS; value->value.cons = NULL; return; } if (cons->cdr.value.cons == NULL) { if (is_float) { value->type = LISP_T_FLOAT; value->value._float = -_float; } else { value->type = LISP_T_INT; value->value._int = -_int; } return; } else cons = cons->cdr.value.cons; while (cons != NULL) { if (!is_float) { if (cons->car.type == LISP_T_INT) _int -= cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) { _float = (float) _int; is_float = true; _float -= cons->car.value._float; } } else { if (cons->car.type == LISP_T_INT) _float -= cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) _float -= cons->car.value._float; } cons = cons->cdr.value.cons; } if (is_float) { value->type = LISP_T_FLOAT; value->value._float = _float; } else { value->type = LISP_T_INT; value->value._int = _int; } } void lispf_mul(lisp_cons* cons, lisp_value* value) { long _int = 1; float _float = 1; bool is_float = false; while (cons != NULL) { if (!is_float) { if (cons->car.type == LISP_T_INT) _int *= cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) { _float = (float) _int; is_float = true; _float *= cons->car.value._float; } } else { if (cons->car.type == LISP_T_INT) _float *= cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) _float *= cons->car.value._float; } cons = cons->cdr.value.cons; } if (is_float) { value->type = LISP_T_FLOAT; value->value._float = _float; } else { value->type = LISP_T_INT; value->value._int = _int; } } void lispf_div(lisp_cons* cons, lisp_value* value) { float _float = 0; if (cons->car.type == LISP_T_FLOAT) _float = cons->car.value._float; else if (cons->car.type == LISP_T_INT) _float = cons->car.value._int; else { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { if (cons->car.type == LISP_T_INT) _float /= cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) _float /= cons->car.value._float; cons = cons->cdr.value.cons; } value->type = LISP_T_FLOAT; value->value._float = _float; } void lispf_intdiv(lisp_cons* cons, lisp_value* value) { long _int = 0; if (cons->car.type == LISP_T_FLOAT) _int = cons->car.value._float; else if (cons->car.type == LISP_T_INT) _int = cons->car.value._int; else { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { if (cons->car.type == LISP_T_INT) _int /= cons->car.value._int; else if (cons->car.type == LISP_T_FLOAT) _int /= cons->car.value._float; cons = cons->cdr.value.cons; } value->type = LISP_T_INT; value->value._int = _int; } void lispf_not(lisp_cons* cons, lisp_value* value) { if (lisp_is_nil(cons->car)) { value->type = LISP_T_ATOM; value->value.atom = atom_t; } else { value->type = LISP_T_CONS; value->value.cons = NULL; } } void lispf_or(lisp_cons* cons, lisp_value* value) { while (cons != NULL) { if (!lisp_is_nil(cons->car)) { *value = cons->car; return; } cons = cons->cdr.value.cons; } value->type = LISP_T_CONS; value->value.cons = NULL; } void lispf_and(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = NULL; while (cons != NULL) { *value = cons->car; if (lisp_is_nil(cons->car)) return; cons = cons->cdr.value.cons; } } void lispf_eq(lisp_cons* cons, lisp_value* value) { lisp_value cmp_value = cons->car; cons = cons->cdr.value.cons; while (cons != NULL) { if (!lisp_is_equal(cmp_value, cons->car)) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; } value->type = LISP_T_ATOM; value->value.atom = atom_t; } void lispf_num_eq(lisp_cons* cons, lisp_value* value) { lisp_value cmp_value = cons->car; if (cmp_value.type != LISP_T_INT && cmp_value.type != LISP_T_FLOAT) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { bool cmp = false; if (cons->car.type == LISP_T_INT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int == cons->car.value._int); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float == cons->car.value._int); } else if (cons->car.type == LISP_T_FLOAT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int == cons->car.value._float); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float == cons->car.value._float); } if (!cmp) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; } *value = cmp_value; } void lispf_num_lt(lisp_cons* cons, lisp_value* value) { lisp_value cmp_value = cons->car; if (cmp_value.type != LISP_T_INT && cmp_value.type != LISP_T_FLOAT) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { bool cmp = false; if (cons->car.type == LISP_T_INT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int < cons->car.value._int); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float < cons->car.value._int); } else if (cons->car.type == LISP_T_FLOAT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int < cons->car.value._float); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float < cons->car.value._float); } if (!cmp) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cmp_value = cons->car; cons = cons->cdr.value.cons; } *value = cmp_value; } void lispf_num_gt(lisp_cons* cons, lisp_value* value) { lisp_value cmp_value = cons->car; if (cmp_value.type != LISP_T_INT && cmp_value.type != LISP_T_FLOAT) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { bool cmp = false; if (cons->car.type == LISP_T_INT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int > cons->car.value._int); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float > cons->car.value._int); } else if (cons->car.type == LISP_T_FLOAT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int > cons->car.value._float); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float > cons->car.value._float); } if (!cmp) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cmp_value = cons->car; cons = cons->cdr.value.cons; } *value = cmp_value; } void lispf_num_le(lisp_cons* cons, lisp_value* value) { lisp_value cmp_value = cons->car; if (cmp_value.type != LISP_T_INT && cmp_value.type != LISP_T_FLOAT) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { bool cmp = false; if (cons->car.type == LISP_T_INT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int <= cons->car.value._int); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float <= cons->car.value._int); } else if (cons->car.type == LISP_T_FLOAT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int <= cons->car.value._float); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float <= cons->car.value._float); } if (!cmp) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cmp_value = cons->car; cons = cons->cdr.value.cons; } *value = cmp_value; } void lispf_num_ge(lisp_cons* cons, lisp_value* value) { lisp_value cmp_value = cons->car; if (cmp_value.type != LISP_T_INT && cmp_value.type != LISP_T_FLOAT) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cons = cons->cdr.value.cons; while (cons != NULL) { bool cmp = false; if (cons->car.type == LISP_T_INT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int >= cons->car.value._int); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float >= cons->car.value._int); } else if (cons->car.type == LISP_T_FLOAT) { if (cmp_value.type == LISP_T_INT) cmp = (cmp_value.value._int >= cons->car.value._float); else if (cmp_value.type == LISP_T_FLOAT) cmp = (cmp_value.value._float >= cons->car.value._float); } if (!cmp) { value->type = LISP_T_CONS; value->value.cons = NULL; return; } cmp_value = cons->car; cons = cons->cdr.value.cons; } *value = cmp_value; } void lispf_cons(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = dbg_malloc(sizeof(lisp_cons)); value->value.cons->car = cons->car; value->value.cons->cdr = cons->cdr.value.cons->car; } void lispf_car(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_CONS || lisp_is_nil(cons->car)) return; *value = cons->car.value.cons->car; } void lispf_cdr(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_CONS || lisp_is_nil(cons->car)) return; *value = cons->car.value.cons->cdr; } void lispf_rplaca(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_CONS || lisp_is_nil(cons->car)) return; cons->car.value.cons->car = cons->cdr.value.cons->car; *value = cons->car; } void lispf_rplacd(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_CONS || lisp_is_nil(cons->car)) return; cons->car.value.cons->cdr = cons->cdr.value.cons->car; *value = cons->car; } void lispf_list(lisp_cons* cons, lisp_value* value) { lisp_cons* head = NULL; lisp_cons* tail = NULL; while (cons != NULL) { lisp_cons* element = dbg_malloc(sizeof(lisp_cons)); element->car = cons->car; element->cdr.type = LISP_T_CONS; element->cdr.value.cons = NULL; if (head == NULL) head = element; if (tail != NULL) tail->cdr.value.cons = element; tail = element; cons = cons->cdr.value.cons; } value->type = LISP_T_CONS; value->value.cons = head; } void lispf_length(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_CONS) return; lisp_cons* head = cons->car.value.cons; value->type = LISP_T_INT; value->value._int = 0; while (head != NULL) { value->value._int++; if (head->cdr.type != LISP_T_CONS) head = NULL; else head = head->cdr.value.cons; } } void lispf_nth(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_INT) return; int index = cons->car.value._int; if (index < 0) { // index is negative, call lispf_length lisp_value temp; lispf_length(cons->cdr.value.cons, &temp); index += temp.value._int; } lisp_cons* head = cons->cdr.value.cons->car.value.cons; if (head == NULL) return; while (index > 0) { head = head->cdr.value.cons; if (head == NULL) return; index--; } *value = head->car; } void lispf_nthcdr(lisp_cons* cons, lisp_value* value) { if (cons->car.type != LISP_T_INT) return; int index = cons->car.value._int; if (index < 0) { // index is negative, call lispf_length lisp_value temp; lispf_length(cons->cdr.value.cons, &temp); index += temp.value._int; } lisp_cons* head = cons->cdr.value.cons->car.value.cons; if (head == NULL) return; while (index > 0) { head = head->cdr.value.cons; if (head == NULL) return; index--; } value->type = LISP_T_CONS; value->value.cons = head; } void lispf_append(lisp_cons* cons, lisp_value* value) { lisp_cons* head = NULL; lisp_cons* tail = NULL; while (cons != NULL) { if (cons->cdr.value.cons == NULL && cons->car.type != LISP_T_CONS) { tail->cdr = cons->car; break; } else { lisp_cons* subcons = cons->car.value.cons; while (subcons != NULL) { lisp_cons* element = dbg_malloc(sizeof(lisp_cons)); element->car = subcons->car; element->cdr.type = LISP_T_CONS; element->cdr.value.cons = NULL; if (head == NULL) head = element; if (tail != NULL) tail->cdr.value.cons = element; tail = element; subcons = subcons->cdr.value.cons; } cons = cons->cdr.value.cons; } } value->type = LISP_T_CONS; value->value.cons = head; } void lispf_push(lisp_cons* cons, lisp_value* value) { lisp_cons* list = cons->car.value.cons; lisp_value item = cons->cdr.value.cons->car; value->type = LISP_T_CONS; value->value.cons = dbg_malloc(sizeof(lisp_cons)); value->value.cons->car = item; value->value.cons->cdr.type = LISP_T_CONS; value->value.cons->cdr.value.cons = list; } void lispf_assoc(lisp_cons* cons, lisp_value* value) { lisp_cons* alist = cons->car.value.cons; lisp_value key = cons->cdr.value.cons->car; value->type = LISP_T_CONS; value->value.cons = lisp_alist_get(alist, key); } void lispf_rassoc(lisp_cons* cons, lisp_value* value) { lisp_cons* alist = cons->car.value.cons; lisp_value cdr_key = cons->cdr.value.cons->car; value->type = LISP_T_CONS; while (alist != NULL) { if (alist->car.type != LISP_T_CONS || alist->car.value.cons == NULL) goto next; value->value.cons = alist->car.value.cons; if (lisp_is_equal(value->value.cons->cdr, cdr_key)) return; next: if (alist->cdr.type == LISP_T_CONS) alist = alist->cdr.value.cons; else alist = NULL; } } void lispf_alist_put(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = cons->car.value.cons; lisp_value key = cons->cdr.value.cons->car; lisp_value new_value = cons->cdr.value.cons->cdr.value.cons->car; lisp_cons* pair = dbg_malloc(sizeof(lisp_cons)); pair->car = key; pair->cdr = new_value; lisp_cons* old_pair = lisp_alist_put(&value->value.cons, pair); } void lispf_type_of(lisp_cons* cons, lisp_value* value) { if (lisp_is_nil(cons->car)) { return; } value->type = LISP_T_ATOM; switch (cons->car.type) { case LISP_T_CONS: value->value.atom = atom_cons; break; case LISP_T_ATOM: value->value.atom = atom_atom; break; case LISP_T_INT: value->value.atom = atom_int; break; case LISP_T_FLOAT: value->value.atom = atom_float; break; case LISP_T_STRING: value->value.atom = atom_string; break; case LISP_T_FUNPTR: value->value.atom = atom_native_fun; break; } } void lispf_addr_of(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_INT; value->value._int = (long) cons->car.value.cons; } void lispf_set(lisp_cons* cons, lisp_value* value) { // extract key and value lisp_value key = cons->car; *value = cons->cdr.value.cons->car; lisp_cons** pairptr = lisp_alist_getptr(syms_alist, key); if (pairptr != NULL) { // just overwrite cdr, don't make a new pair (*pairptr)->cdr = *value; return; } // create cons pair for new var lisp_cons* pair = dbg_malloc(sizeof(lisp_cons)); pair->car = key; pair->cdr = *value; // add to alist lisp_cons* new_alist = dbg_malloc(sizeof(lisp_cons)); new_alist->car.type = LISP_T_CONS; new_alist->car.value.cons = pair; new_alist->cdr.type = LISP_T_CONS; new_alist->cdr.value.cons = syms_alist; syms_alist = new_alist; } void lispf_unset(lisp_cons* cons, lisp_value* value) { lisp_cons* pair = lisp_alist_del(&syms_alist, cons->car); if (pair == NULL) return; *value = pair->cdr; dbg_free(pair); } void lispf_fun(lisp_cons* cons, lisp_value* value) { lisp_cons* pair = lisp_alist_get(funs_alist, cons->car); if (pair == NULL) return; *value = pair->cdr; } void lispf_print(lisp_cons* cons, lisp_value* value) { while (cons != NULL) { if (cons->car.type == LISP_T_STRING) lisp_string_print(cons->car.value.string); else print_value(cons->car); cons = cons->cdr.value.cons; if (cons != NULL) printf(" "); } printf("\n"); } void lispf_internals_syms_alist(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = syms_alist; } void lispf_internals_funs_alist(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = funs_alist; } void lispf_internals_atoms_alist(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = atoms_alist; } void lispf_internals_fun_set(lisp_cons* cons, lisp_value* value) { value->type = LISP_T_CONS; value->value.cons = lisp_defun(cons->car.value.atom, cons->cdr.value.cons->car.value.cons); } void init_native_funs() { // arithmetic lisp_defun_native(lisp_string_create("+"), &lispf_add); lisp_defun_native(lisp_string_create("-"), &lispf_sub); lisp_defun_native(lisp_string_create("*"), &lispf_mul); lisp_defun_native(lisp_string_create("/"), &lispf_div); lisp_defun_native(lisp_string_create("int/"), &lispf_intdiv); // boolean logic lisp_defun_native(lisp_string_create("not"), &lispf_not); lisp_defun_native(lisp_string_create("or"), &lispf_or); lisp_defun_native(lisp_string_create("and"), &lispf_and); // comparison lisp_defun_native(lisp_string_create("eq"), &lispf_eq); lisp_defun_native(lisp_string_create("="), &lispf_num_eq); lisp_defun_native(lisp_string_create("<"), &lispf_num_lt); lisp_defun_native(lisp_string_create(">"), &lispf_num_gt); lisp_defun_native(lisp_string_create("<="), &lispf_num_le); lisp_defun_native(lisp_string_create(">="), &lispf_num_ge); // data structures lisp_defun_native(lisp_string_create("cons"), &lispf_cons); lisp_defun_native(lisp_string_create("car"), &lispf_car); lisp_defun_native(lisp_string_create("cdr"), &lispf_cdr); lisp_defun_native(lisp_string_create("rplaca"), &lispf_rplaca); lisp_defun_native(lisp_string_create("rplacd"), &lispf_rplacd); lisp_defun_native(lisp_string_create("list"), &lispf_list); lisp_defun_native(lisp_string_create("length"), &lispf_length); lisp_defun_native(lisp_string_create("nth"), &lispf_nth); lisp_defun_native(lisp_string_create("nthcdr"), &lispf_nthcdr); lisp_defun_native(lisp_string_create("append"), &lispf_append); lisp_defun_native(lisp_string_create("push"), &lispf_push); lisp_defun_native(lisp_string_create("assoc"), &lispf_assoc); lisp_defun_native(lisp_string_create("rassoc"), &lispf_rassoc); lisp_defun_native(lisp_string_create("alist-put"), &lispf_alist_put); // etc lisp_defun_native(lisp_string_create("type-of"), &lispf_type_of); lisp_defun_native(lisp_string_create("addr-of"), &lispf_addr_of); lisp_defun_native(lisp_string_create("set"), &lispf_set); lisp_defun_native(lisp_string_create("unset!"), &lispf_unset); lisp_defun_native(lisp_string_create("fun"), &lispf_fun); lisp_defun_native(lisp_string_create("print"), &lispf_print); // internals lisp_defun_native(lisp_string_create("syms-alist!"), &lispf_internals_syms_alist); lisp_defun_native(lisp_string_create("funs-alist!"), &lispf_internals_funs_alist); lisp_defun_native(lisp_string_create("atoms-alist!"), &lispf_internals_atoms_alist); lisp_defun_native(lisp_string_create("fun-set!"), &lispf_internals_fun_set); }