picrin/lib/pair.c

669 lines
12 KiB
C
Raw Normal View History

2014-08-25 00:38:09 -04:00
/**
* See Copyright Notice in picrin.h
*/
#include "picrin.h"
2016-02-20 10:58:58 -05:00
#include "picrin/extra.h"
2016-02-20 11:13:16 -05:00
#include "picrin/private/object.h"
2014-08-25 00:38:09 -04:00
pic_value
pic_cons(pic_state *pic, pic_value car, pic_value cdr)
{
2016-02-21 06:32:00 -05:00
struct pair *pair;
2014-08-25 00:38:09 -04:00
2016-02-21 06:32:00 -05:00
pair = (struct pair *)pic_obj_alloc(pic, sizeof(struct pair), PIC_TYPE_PAIR);
2014-08-25 00:38:09 -04:00
pair->car = car;
pair->cdr = cdr;
return pic_obj_value(pair);
}
2016-02-18 12:29:40 -05:00
pic_value
pic_car(pic_state *pic, pic_value obj)
{
if (! pic_pair_p(pic, obj)) {
2016-02-22 14:03:42 -05:00
pic_error(pic, "car: pair required", 1, obj);
2016-02-18 12:29:40 -05:00
}
2016-02-19 08:09:06 -05:00
return pic_pair_ptr(pic, obj)->car;
2016-02-18 12:29:40 -05:00
}
pic_value
pic_cdr(pic_state *pic, pic_value obj)
{
if (! pic_pair_p(pic, obj)) {
2016-02-22 14:03:42 -05:00
pic_error(pic, "cdr: pair required", 1, obj);
2016-02-18 12:29:40 -05:00
}
2016-02-19 08:09:06 -05:00
return pic_pair_ptr(pic, obj)->cdr;
2016-02-18 12:29:40 -05:00
}
2014-08-25 00:38:09 -04:00
void
pic_set_car(pic_state *pic, pic_value obj, pic_value val)
{
if (! pic_pair_p(pic, obj)) {
2016-02-22 14:03:42 -05:00
pic_error(pic, "pair required", 0);
2014-08-25 00:38:09 -04:00
}
2016-02-19 08:09:06 -05:00
pic_pair_ptr(pic, obj)->car = val;
2014-08-25 00:38:09 -04:00
}
void
pic_set_cdr(pic_state *pic, pic_value obj, pic_value val)
{
if (! pic_pair_p(pic, obj)) {
2016-02-22 14:03:42 -05:00
pic_error(pic, "pair required", 0);
2014-08-25 00:38:09 -04:00
}
2016-02-19 08:09:06 -05:00
pic_pair_ptr(pic, obj)->cdr = val;
2014-08-25 00:38:09 -04:00
}
2016-02-18 12:29:40 -05:00
pic_value
pic_caar(pic_state *pic, pic_value v)
{
return pic_car(pic, pic_car(pic, v));
}
pic_value
pic_cadr(pic_state *pic, pic_value v)
{
return pic_car(pic, pic_cdr(pic, v));
}
pic_value
pic_cdar(pic_state *pic, pic_value v)
{
return pic_cdr(pic, pic_car(pic, v));
}
pic_value
pic_cddr(pic_state *pic, pic_value v)
{
return pic_cdr(pic, pic_cdr(pic, v));
}
2014-08-25 00:38:09 -04:00
bool
pic_list_p(pic_state *pic, pic_value obj)
2014-08-25 00:38:09 -04:00
{
pic_value local, rapid;
int i;
/* Floyd's cycle-finding algorithm. */
local = rapid = obj;
while (true) {
/* advance rapid fast-forward; runs 2x faster than local */
for (i = 0; i < 2; ++i) {
if (pic_pair_p(pic, rapid)) {
2016-02-19 08:09:06 -05:00
rapid = pic_pair_ptr(pic, rapid)->cdr;
2014-08-25 00:38:09 -04:00
}
else {
return pic_nil_p(pic, rapid);
2014-08-25 00:38:09 -04:00
}
}
/* advance local */
2016-02-19 08:09:06 -05:00
local = pic_pair_ptr(pic, local)->cdr;
2014-08-25 00:38:09 -04:00
if (pic_eq_p(pic, local, rapid)) {
2014-08-25 00:38:09 -04:00
return false;
}
}
}
pic_value
2016-02-18 12:29:40 -05:00
pic_make_list(pic_state *pic, int n, pic_value *argv)
2014-08-25 00:38:09 -04:00
{
2016-02-18 12:29:40 -05:00
pic_value list;
int i;
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
list = pic_nil_value(pic);
for (i = n - 1; i >= 0; --i) {
list = pic_cons(pic, argv[i], list);
}
return list;
2014-08-25 00:38:09 -04:00
}
pic_value
2016-02-18 12:29:40 -05:00
pic_list(pic_state *pic, int n, ...)
2014-08-25 00:38:09 -04:00
{
2016-02-18 12:29:40 -05:00
va_list ap;
pic_value list;
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
va_start(ap, n);
list = pic_vlist(pic, n, ap);
va_end(ap);
return list;
2014-08-25 00:38:09 -04:00
}
pic_value
2016-02-18 12:29:40 -05:00
pic_vlist(pic_state *pic, int n, va_list ap)
2014-08-25 00:38:09 -04:00
{
2016-02-18 12:29:40 -05:00
pic_value *argv = pic_alloca(pic, sizeof(pic_value) * n);
int i;
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
for (i = 0; i < n; ++i) {
argv[i] = va_arg(ap, pic_value);
}
return pic_make_list(pic, n, argv);
2014-08-25 00:38:09 -04:00
}
pic_value
2016-02-18 12:29:40 -05:00
pic_list_ref(pic_state *pic, pic_value list, int i)
2014-08-25 00:38:09 -04:00
{
2016-02-18 12:29:40 -05:00
return pic_car(pic, pic_list_tail(pic, list, i));
2014-08-25 00:38:09 -04:00
}
2016-02-18 12:29:40 -05:00
void
pic_list_set(pic_state *pic, pic_value list, int i, pic_value obj)
2014-08-25 00:38:09 -04:00
{
2016-02-19 08:09:06 -05:00
pic_pair_ptr(pic, pic_list_tail(pic, list, i))->car = obj;
2014-08-25 00:38:09 -04:00
}
pic_value
2016-02-18 12:29:40 -05:00
pic_list_tail(pic_state *pic, pic_value list, int i)
2014-08-25 00:38:09 -04:00
{
2016-02-18 12:29:40 -05:00
while (i-- > 0) {
list = pic_cdr(pic, list);
2014-08-25 00:38:09 -04:00
}
return list;
}
2015-08-26 05:16:33 -04:00
int
2014-08-25 00:38:09 -04:00
pic_length(pic_state *pic, pic_value obj)
{
2015-08-26 05:16:33 -04:00
int c = 0;
2014-08-25 00:38:09 -04:00
while (! pic_nil_p(pic, obj)) {
2014-08-25 00:38:09 -04:00
obj = pic_cdr(pic, obj);
++c;
}
return c;
}
pic_value
pic_reverse(pic_state *pic, pic_value list)
{
2016-02-19 02:17:13 -05:00
size_t ai = pic_enter(pic);
2015-01-22 05:28:31 -05:00
pic_value v, acc, it;
2014-08-25 00:38:09 -04:00
acc = pic_nil_value(pic);
2015-01-22 05:28:31 -05:00
pic_for_each(v, list, it) {
2014-08-25 00:38:09 -04:00
acc = pic_cons(pic, v, acc);
2016-02-19 02:17:13 -05:00
pic_leave(pic, ai);
pic_protect(pic, acc);
2014-08-25 00:38:09 -04:00
}
return acc;
}
pic_value
pic_append(pic_state *pic, pic_value xs, pic_value ys)
{
2016-02-19 02:17:13 -05:00
size_t ai = pic_enter(pic);
2015-01-22 05:28:31 -05:00
pic_value x, it;
2014-08-25 00:38:09 -04:00
xs = pic_reverse(pic, xs);
2015-01-22 05:28:31 -05:00
pic_for_each (x, xs, it) {
2014-08-25 00:38:09 -04:00
ys = pic_cons(pic, x, ys);
2016-02-19 02:17:13 -05:00
pic_leave(pic, ai);
pic_protect(pic, xs);
pic_protect(pic, ys);
2014-08-25 00:38:09 -04:00
}
return ys;
}
static pic_value
pic_pair_pair_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_bool_value(pic, pic_pair_p(pic, v));
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_cons(pic_state *pic)
{
pic_value v,w;
pic_get_args(pic, "oo", &v, &w);
return pic_cons(pic, v, w);
}
static pic_value
pic_pair_car(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_car(pic, v);
}
static pic_value
pic_pair_cdr(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_cdr(pic, v);
}
static pic_value
pic_pair_caar(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_caar(pic, v);
}
static pic_value
pic_pair_cadr(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_cadr(pic, v);
}
static pic_value
pic_pair_cdar(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_cdar(pic, v);
}
static pic_value
pic_pair_cddr(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_cddr(pic, v);
}
static pic_value
pic_pair_set_car(pic_state *pic)
{
pic_value v,w;
pic_get_args(pic, "oo", &v, &w);
2014-09-16 12:07:25 -04:00
pic_set_car(pic, v, w);
2014-08-25 00:38:09 -04:00
return pic_undef_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_set_cdr(pic_state *pic)
{
pic_value v,w;
pic_get_args(pic, "oo", &v, &w);
2014-09-16 12:07:25 -04:00
pic_set_cdr(pic, v, w);
2014-08-25 00:38:09 -04:00
return pic_undef_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_null_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_bool_value(pic, pic_nil_p(pic, v));
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_list_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_bool_value(pic, pic_list_p(pic, v));
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_make_list(pic_state *pic)
{
2016-02-18 12:29:40 -05:00
int k, i;
pic_value list, fill = pic_undef_value(pic);
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
pic_get_args(pic, "i|o", &k, &fill);
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
list = pic_nil_value(pic);
for (i = 0; i < k; ++i) {
list = pic_cons(pic, fill, list);
}
return list;
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_list(pic_state *pic)
{
2015-08-26 06:04:27 -04:00
int argc;
2014-08-25 00:38:09 -04:00
pic_value *argv;
pic_get_args(pic, "*", &argc, &argv);
2016-02-18 12:29:40 -05:00
return pic_make_list(pic, argc, argv);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_length(pic_state *pic)
{
pic_value list;
pic_get_args(pic, "o", &list);
return pic_int_value(pic, pic_length(pic, list));
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_append(pic_state *pic)
{
2015-08-26 06:04:27 -04:00
int argc;
2014-08-25 00:38:09 -04:00
pic_value *args, list;
pic_get_args(pic, "*", &argc, &args);
if (argc == 0) {
return pic_nil_value(pic);
2014-08-25 00:38:09 -04:00
}
list = args[--argc];
while (argc-- > 0) {
list = pic_append(pic, args[argc], list);
}
return list;
}
static pic_value
pic_pair_reverse(pic_state *pic)
{
pic_value list;
pic_get_args(pic, "o", &list);
return pic_reverse(pic, list);
}
static pic_value
pic_pair_list_tail(pic_state *pic)
{
pic_value list;
2015-08-26 06:04:27 -04:00
int i;
2014-08-25 00:38:09 -04:00
2015-08-26 06:04:27 -04:00
pic_get_args(pic, "oi", &list, &i);
2014-08-25 00:38:09 -04:00
return pic_list_tail(pic, list, i);
}
static pic_value
pic_pair_list_ref(pic_state *pic)
{
pic_value list;
2015-08-26 06:04:27 -04:00
int i;
2014-08-25 00:38:09 -04:00
2015-08-26 06:04:27 -04:00
pic_get_args(pic, "oi", &list, &i);
2014-08-25 00:38:09 -04:00
return pic_list_ref(pic, list, i);
}
static pic_value
pic_pair_list_set(pic_state *pic)
{
pic_value list, obj;
2015-08-26 06:04:27 -04:00
int i;
2014-08-25 00:38:09 -04:00
2015-08-26 06:04:27 -04:00
pic_get_args(pic, "oio", &list, &i, &obj);
2014-08-25 00:38:09 -04:00
pic_list_set(pic, list, i, obj);
return pic_undef_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_list_copy(pic_state *pic)
{
2016-02-18 12:29:40 -05:00
pic_value list, head, tail, tmp;
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
pic_get_args(pic, "o", &list);
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
head = tail = pic_nil_value(pic);
while (pic_pair_p(pic, list)) {
tmp = pic_list(pic, 1, pic_car(pic, list));
if (! pic_nil_p(pic, tail)) {
pic_set_cdr(pic, tail, tmp);
}
tail = tmp;
if (pic_nil_p(pic, head)) {
head = tail;
}
list = pic_cdr(pic, list);
}
if (pic_nil_p(pic, tail)) {
return list;
}
pic_set_cdr(pic, tail, list);
return head;
2014-08-25 00:38:09 -04:00
}
2014-09-13 05:51:20 -04:00
static pic_value
pic_pair_map(pic_state *pic)
{
2015-08-26 06:04:27 -04:00
int argc, i;
2016-02-19 10:03:16 -05:00
pic_value proc, *args, *arg_list, ret;
2014-09-13 05:51:20 -04:00
pic_get_args(pic, "l*", &proc, &argc, &args);
2015-02-04 09:05:34 -05:00
if (argc == 0)
2016-02-22 14:03:42 -05:00
pic_error(pic, "map: wrong number of arguments (1 for at least 2)", 0);
2015-02-04 09:05:34 -05:00
2016-02-14 03:14:33 -05:00
arg_list = pic_alloca(pic, sizeof(pic_value) * argc);
ret = pic_nil_value(pic);
2014-09-13 05:51:20 -04:00
do {
2014-09-27 07:15:47 -04:00
for (i = 0; i < argc; ++i) {
if (! pic_pair_p(pic, args[i])) {
2014-09-13 05:51:20 -04:00
break;
}
2016-02-14 03:14:33 -05:00
arg_list[i] = pic_car(pic, args[i]);
2014-09-13 05:51:20 -04:00
args[i] = pic_cdr(pic, args[i]);
}
2015-02-04 09:05:34 -05:00
2014-09-27 07:15:47 -04:00
if (i != argc) {
2014-09-13 05:51:20 -04:00
break;
2014-09-27 07:15:47 -04:00
}
2016-02-14 03:14:33 -05:00
pic_push(pic, pic_apply(pic, proc, i, arg_list), ret);
2014-09-13 05:51:20 -04:00
} while (1);
return pic_reverse(pic, ret);
}
static pic_value
pic_pair_for_each(pic_state *pic)
{
2015-08-26 06:04:27 -04:00
int argc, i;
2016-02-19 10:03:16 -05:00
pic_value proc, *args, *arg_list;
2014-09-13 05:51:20 -04:00
pic_get_args(pic, "l*", &proc, &argc, &args);
2016-02-14 03:14:33 -05:00
arg_list = pic_alloca(pic, sizeof(pic_value) * argc);
2014-09-13 05:51:20 -04:00
do {
2014-09-27 07:15:47 -04:00
for (i = 0; i < argc; ++i) {
if (! pic_pair_p(pic, args[i])) {
2014-09-13 05:51:20 -04:00
break;
}
2016-02-14 03:14:33 -05:00
arg_list[i] = pic_car(pic, args[i]);
2014-09-13 05:51:20 -04:00
args[i] = pic_cdr(pic, args[i]);
}
2014-09-27 07:15:47 -04:00
if (i != argc) {
2014-09-13 05:51:20 -04:00
break;
2014-09-27 07:15:47 -04:00
}
2016-02-14 03:14:33 -05:00
pic_apply(pic, proc, i, arg_list);
2014-09-13 05:51:20 -04:00
} while (1);
return pic_undef_value(pic);
2014-09-13 05:51:20 -04:00
}
2014-08-25 00:38:09 -04:00
static pic_value
pic_pair_memq(pic_state *pic)
{
pic_value key, list;
pic_get_args(pic, "oo", &key, &list);
2016-02-18 12:29:40 -05:00
while (! pic_nil_p(pic, list)) {
if (pic_eq_p(pic, key, pic_car(pic, list))) {
return list;
}
list = pic_cdr(pic, list);
}
return pic_false_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_memv(pic_state *pic)
{
pic_value key, list;
pic_get_args(pic, "oo", &key, &list);
2016-02-18 12:29:40 -05:00
while (! pic_nil_p(pic, list)) {
if (pic_eqv_p(pic, key, pic_car(pic, list))) {
return list;
}
list = pic_cdr(pic, list);
}
return pic_false_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_member(pic_state *pic)
{
2016-02-20 01:34:49 -05:00
pic_value key, list, proc;
int n;
2014-08-25 00:38:09 -04:00
2016-02-20 01:34:49 -05:00
n = pic_get_args(pic, "oo|l", &key, &list, &proc);
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
while (! pic_nil_p(pic, list)) {
2016-02-20 01:34:49 -05:00
if (n == 2) {
2016-02-18 12:29:40 -05:00
if (pic_equal_p(pic, key, pic_car(pic, list)))
return list;
} else {
if (! pic_false_p(pic, pic_call(pic, proc, 2, key, pic_car(pic, list))))
2016-02-18 12:29:40 -05:00
return list;
}
list = pic_cdr(pic, list);
}
return pic_false_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_assq(pic_state *pic)
{
2016-02-18 12:29:40 -05:00
pic_value key, alist, cell;
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
pic_get_args(pic, "oo", &key, &alist);
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
while (! pic_nil_p(pic, alist)) {
cell = pic_car(pic, alist);
if (pic_eq_p(pic, key, pic_car(pic, cell))) {
return cell;
}
alist = pic_cdr(pic, alist);
}
return pic_false_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_assv(pic_state *pic)
{
2016-02-18 12:29:40 -05:00
pic_value key, alist, cell;
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
pic_get_args(pic, "oo", &key, &alist);
2014-08-25 00:38:09 -04:00
2016-02-18 12:29:40 -05:00
while (! pic_nil_p(pic, alist)) {
cell = pic_car(pic, alist);
if (pic_eqv_p(pic, key, pic_car(pic, cell))) {
return cell;
}
alist = pic_cdr(pic, alist);
}
return pic_false_value(pic);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_pair_assoc(pic_state *pic)
{
2016-02-20 01:34:49 -05:00
pic_value key, alist, proc, cell;
int n;
2016-02-18 12:29:40 -05:00
2016-02-20 01:34:49 -05:00
n = pic_get_args(pic, "oo|l", &key, &alist, &proc);
2016-02-18 12:29:40 -05:00
while (! pic_nil_p(pic, alist)) {
cell = pic_car(pic, alist);
2016-02-20 01:34:49 -05:00
if (n == 2) {
2016-02-18 12:29:40 -05:00
if (pic_equal_p(pic, key, pic_car(pic, cell)))
return cell;
} else {
if (! pic_false_p(pic, pic_call(pic, proc, 2, key, pic_car(pic, cell))))
2016-02-18 12:29:40 -05:00
return cell;
}
alist = pic_cdr(pic, alist);
}
return pic_false_value(pic);
2014-08-25 00:38:09 -04:00
}
void
pic_init_pair(pic_state *pic)
{
2015-07-01 17:17:27 -04:00
pic_defun(pic, "pair?", pic_pair_pair_p);
pic_defun(pic, "cons", pic_pair_cons);
pic_defun(pic, "car", pic_pair_car);
pic_defun(pic, "cdr", pic_pair_cdr);
pic_defun(pic, "null?", pic_pair_null_p);
2015-06-04 00:53:41 -04:00
2014-08-31 22:37:52 -04:00
pic_defun(pic, "set-car!", pic_pair_set_car);
pic_defun(pic, "set-cdr!", pic_pair_set_cdr);
pic_defun(pic, "caar", pic_pair_caar);
pic_defun(pic, "cadr", pic_pair_cadr);
pic_defun(pic, "cdar", pic_pair_cdar);
pic_defun(pic, "cddr", pic_pair_cddr);
pic_defun(pic, "list?", pic_pair_list_p);
pic_defun(pic, "make-list", pic_pair_make_list);
pic_defun(pic, "list", pic_pair_list);
pic_defun(pic, "length", pic_pair_length);
pic_defun(pic, "append", pic_pair_append);
pic_defun(pic, "reverse", pic_pair_reverse);
pic_defun(pic, "list-tail", pic_pair_list_tail);
pic_defun(pic, "list-ref", pic_pair_list_ref);
pic_defun(pic, "list-set!", pic_pair_list_set);
pic_defun(pic, "list-copy", pic_pair_list_copy);
2014-09-13 05:51:20 -04:00
pic_defun(pic, "map", pic_pair_map);
pic_defun(pic, "for-each", pic_pair_for_each);
2014-08-31 22:37:52 -04:00
pic_defun(pic, "memq", pic_pair_memq);
pic_defun(pic, "memv", pic_pair_memv);
pic_defun(pic, "member", pic_pair_member);
pic_defun(pic, "assq", pic_pair_assq);
pic_defun(pic, "assv", pic_pair_assv);
pic_defun(pic, "assoc", pic_pair_assoc);
2014-08-25 00:38:09 -04:00
}