keithlisp/native_funs.c

702 lines
19 KiB
C

#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_lisp_fun(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);
}