Merge pull request #237 from picrin-scheme/submodule2subtree
Control benz under git subtree rather than git submodule
This commit is contained in:
commit
1e91fc08a5
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "extlib/benz"]
|
||||
path = extlib/benz
|
||||
url = git://github.com/picrin-scheme/benz.git
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 569b1ace02e6a066b21f94dff23c4e01b8748bf0
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
# Benz
|
||||
|
||||
Benz is a super tiny scheme interpreter intended to be embedded in other applications such as game engine and network server. It provides a subset language of R7RS with several useful extensions. By default, Benz just contains some C files and headers and this README file. In embedding, you only need to copy the files into the project and add `include` dir to the include path.
|
||||
|
||||
Originally, Benz used to be the core component of [Picrin Scheme](https://github.com/picrin-scheme/picrin). They are currently maintained at separate repositories.
|
||||
|
||||
## Example
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
#include "picrin.h"
|
||||
|
||||
/* Simple REPL program */
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
pic_state *pic;
|
||||
pic_value expr;
|
||||
|
||||
pic = pic_open(argc, argv, NULL);
|
||||
|
||||
while (1) {
|
||||
printf("> ");
|
||||
|
||||
expr = pic_read(pic, pic_stdin(pic));
|
||||
|
||||
if (pic_eof_p(expr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
pic_printf(pic, "~s\n", pic_eval(pic, expr, pic->lib));
|
||||
}
|
||||
|
||||
pic_close(pic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## More Example
|
||||
|
||||
Function binding is also easy. `pic_defun` defines a scheme procedure converting from a C function. In the native function, callee arguments can be taken with `pic_get_args`. `pic_get_args` gets arguments according to the format string. If actual arguments does not match a number or incompatible types, it will raise an exception.
|
||||
|
||||
```c
|
||||
#include "picrin.h"
|
||||
|
||||
int fact(int i) {
|
||||
return i == 1 ? 1 : i * fact(i - 1);
|
||||
}
|
||||
|
||||
pic_value factorial(pic_state *pic) {
|
||||
int i;
|
||||
|
||||
pic_get_args(pic, "i", &i);
|
||||
|
||||
return pic_int_value(fact(i));
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
pic_state *pic = pic_open(argc, argv, NULL);
|
||||
|
||||
pic_defun(pic, "fact", factorial); /* define fact procedure */
|
||||
|
||||
pic_load_cstr(pic, "(display (fact 10))");
|
||||
|
||||
pic_close(pic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Language
|
||||
|
||||
All procedures and syntaces are exported from a single library named `(picrin base)`. The complete list is found at https://gist.github.com/wasabiz/344d802a2340d1f734b7 .
|
||||
|
||||
### call/cc
|
||||
|
||||
Full continuation has many problems in embbeding into applications. By default, Benz's call/cc operator does not support continuation that can handle re-entering (it only supports escape continuations). To remove this restriction, please use an add-on provided from [Picrin Scheme's repository](https://github.com/picrin-scheme/picrin/tree/master/contrib/03.callcc).
|
||||
|
||||
### Strings
|
||||
|
||||
Benz utilize rope data structure to implement string type. Thanks to the implementation, string-append is guaranteed to be done in a constant time (so do string-copy, when ascii-only mode is enabled). In return for that, strings in benz are immutable by default. It does not provide mutation API (string-set!, string-copy! and string-fill! in R7RS). This restriction can be also removed with an add-on in [Picrin Scheme's repository](https://github.com/picrin-scheme/picrin/tree/master/contrib/03.mutable-string).
|
||||
|
||||
### Dictionaries
|
||||
|
||||
Dictionary is a hash table object. Its equivalence is tested with equal? procedure.
|
||||
|
||||
### Attribute
|
||||
|
||||
Benz has an facility to get or set metadata to any heap object.
|
||||
|
||||
## Authors
|
||||
|
||||
See https://github.com/picrin-scheme/benz and https://github.com/picrin-scheme/picrin for details.
|
||||
|
||||
## LICENSE
|
||||
|
||||
Copyright (c) 2013-2014 Yuichi Nishiwaki and other picrin contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#include "picrin.h"
|
||||
#include "picrin/dict.h"
|
||||
|
||||
struct pic_dict *
|
||||
pic_attr(pic_state *pic, pic_value obj)
|
||||
{
|
||||
xh_entry *e;
|
||||
|
||||
if (pic_vtype(obj) != PIC_VTYPE_HEAP) {
|
||||
pic_errorf(pic, "attribute: expected heap object, but got immediate value ~s", obj);
|
||||
}
|
||||
|
||||
e = xh_get_ptr(&pic->attrs, pic_ptr(obj));
|
||||
if (e == NULL) {
|
||||
struct pic_dict *dict = pic_make_dict(pic);
|
||||
|
||||
e = xh_put_ptr(&pic->attrs, pic_ptr(obj), &dict);
|
||||
|
||||
assert(dict == xh_val(e, struct pic_dict *));
|
||||
}
|
||||
return xh_val(e, struct pic_dict *);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_attr_ref(pic_state *pic, pic_value obj, const char *key)
|
||||
{
|
||||
return pic_dict_ref(pic, pic_attr(pic, obj), pic_sym_value(pic_intern_cstr(pic, key)));
|
||||
}
|
||||
|
||||
void
|
||||
pic_attr_set(pic_state *pic, pic_value obj, const char *key, pic_value v)
|
||||
{
|
||||
pic_dict_set(pic, pic_attr(pic, obj), pic_sym_value(pic_intern_cstr(pic, key)), v);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_attr_attribute(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
|
||||
pic_get_args(pic, "o", &obj);
|
||||
|
||||
return pic_obj_value(pic_attr(pic, obj));
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_attr(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "attribute", pic_attr_attribute);
|
||||
}
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/blob.h"
|
||||
#include "picrin/pair.h"
|
||||
|
||||
struct pic_blob *
|
||||
pic_make_blob(pic_state *pic, size_t len)
|
||||
{
|
||||
struct pic_blob *bv;
|
||||
|
||||
bv = (struct pic_blob *)pic_obj_alloc(pic, sizeof(struct pic_blob), PIC_TT_BLOB);
|
||||
bv->data = pic_alloc(pic, len);
|
||||
bv->len = len;
|
||||
return bv;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_blob_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector(pic_state *pic)
|
||||
{
|
||||
pic_value *argv;
|
||||
size_t argc, i;
|
||||
pic_blob *blob;
|
||||
unsigned char *data;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
blob = pic_make_blob(pic, argc);
|
||||
|
||||
data = blob->data;
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], int);
|
||||
|
||||
if (pic_int(argv[i]) < 0 || pic_int(argv[i]) > 255) {
|
||||
pic_errorf(pic, "byte out of range");
|
||||
}
|
||||
|
||||
*data++ = (unsigned char)pic_int(argv[i]);
|
||||
}
|
||||
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_make_bytevector(pic_state *pic)
|
||||
{
|
||||
pic_blob *blob;
|
||||
size_t k, i;
|
||||
int b = 0;
|
||||
|
||||
pic_get_args(pic, "k|i", &k, &b);
|
||||
|
||||
if (b < 0 || b > 255)
|
||||
pic_errorf(pic, "byte out of range");
|
||||
|
||||
blob = pic_make_blob(pic, k);
|
||||
for (i = 0; i < k; ++i) {
|
||||
blob->data[i] = (unsigned char)b;
|
||||
}
|
||||
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_length(pic_state *pic)
|
||||
{
|
||||
struct pic_blob *bv;
|
||||
|
||||
pic_get_args(pic, "b", &bv);
|
||||
|
||||
return pic_size_value(bv->len);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_u8_ref(pic_state *pic)
|
||||
{
|
||||
struct pic_blob *bv;
|
||||
int k;
|
||||
|
||||
pic_get_args(pic, "bi", &bv, &k);
|
||||
|
||||
return pic_int_value(bv->data[k]);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_u8_set(pic_state *pic)
|
||||
{
|
||||
struct pic_blob *bv;
|
||||
int k, v;
|
||||
|
||||
pic_get_args(pic, "bii", &bv, &k, &v);
|
||||
|
||||
if (v < 0 || v > 255)
|
||||
pic_errorf(pic, "byte out of range");
|
||||
|
||||
bv->data[k] = (unsigned char)v;
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_copy_i(pic_state *pic)
|
||||
{
|
||||
pic_blob *to, *from;
|
||||
int n;
|
||||
size_t at, start, end;
|
||||
|
||||
n = pic_get_args(pic, "bkb|kk", &to, &at, &from, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 3:
|
||||
start = 0;
|
||||
case 4:
|
||||
end = from->len;
|
||||
}
|
||||
|
||||
if (to == from && (start <= at && at < end)) {
|
||||
/* copy in reversed order */
|
||||
at += end - start;
|
||||
while (start < end) {
|
||||
to->data[--at] = from->data[--end];
|
||||
}
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
while (start < end) {
|
||||
to->data[at++] = from->data[start++];
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_copy(pic_state *pic)
|
||||
{
|
||||
pic_blob *from, *to;
|
||||
int n;
|
||||
size_t start, end, i = 0;
|
||||
|
||||
n = pic_get_args(pic, "b|kk", &from, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = from->len;
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
pic_errorf(pic, "make-bytevector: end index must not be less than start index");
|
||||
}
|
||||
|
||||
to = pic_make_blob(pic, end - start);
|
||||
while (start < end) {
|
||||
to->data[i++] = from->data[start++];
|
||||
}
|
||||
|
||||
return pic_obj_value(to);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_append(pic_state *pic)
|
||||
{
|
||||
size_t argc, i, j, len;
|
||||
pic_value *argv;
|
||||
pic_blob *blob;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], blob);
|
||||
len += pic_blob_ptr(argv[i])->len;
|
||||
}
|
||||
|
||||
blob = pic_make_blob(pic, len);
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
for (j = 0; j < pic_blob_ptr(argv[i])->len; ++j) {
|
||||
blob->data[len + j] = pic_blob_ptr(argv[i])->data[j];
|
||||
}
|
||||
len += pic_blob_ptr(argv[i])->len;
|
||||
}
|
||||
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_list_to_bytevector(pic_state *pic)
|
||||
{
|
||||
pic_blob *blob;
|
||||
unsigned char *data;
|
||||
pic_value list, e;
|
||||
|
||||
pic_get_args(pic, "o", &list);
|
||||
|
||||
blob = pic_make_blob(pic, pic_length(pic, list));
|
||||
|
||||
data = blob->data;
|
||||
|
||||
pic_for_each (e, list) {
|
||||
pic_assert_type(pic, e, int);
|
||||
|
||||
if (pic_int(e) < 0 || pic_int(e) > 255)
|
||||
pic_errorf(pic, "byte out of range");
|
||||
|
||||
*data++ = (unsigned char)pic_int(e);
|
||||
}
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_blob_bytevector_to_list(pic_state *pic)
|
||||
{
|
||||
pic_blob *blob;
|
||||
pic_value list;
|
||||
int n;
|
||||
size_t start, end, i;
|
||||
|
||||
n = pic_get_args(pic, "b|kk", &blob, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = blob->len;
|
||||
}
|
||||
|
||||
list = pic_nil_value();
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
pic_push(pic, pic_int_value(blob->data[i]), list);
|
||||
}
|
||||
return pic_reverse(pic, list);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_blob(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "bytevector?", pic_blob_bytevector_p);
|
||||
pic_defun(pic, "bytevector", pic_blob_bytevector);
|
||||
pic_defun(pic, "make-bytevector", pic_blob_make_bytevector);
|
||||
pic_defun(pic, "bytevector-length", pic_blob_bytevector_length);
|
||||
pic_defun(pic, "bytevector-u8-ref", pic_blob_bytevector_u8_ref);
|
||||
pic_defun(pic, "bytevector-u8-set!", pic_blob_bytevector_u8_set);
|
||||
pic_defun(pic, "bytevector-copy!", pic_blob_bytevector_copy_i);
|
||||
pic_defun(pic, "bytevector-copy", pic_blob_bytevector_copy);
|
||||
pic_defun(pic, "bytevector-append", pic_blob_bytevector_append);
|
||||
pic_defun(pic, "bytevector->list", pic_blob_bytevector_to_list);
|
||||
pic_defun(pic, "list->bytevector", pic_blob_list_to_bytevector);
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/vector.h"
|
||||
#include "picrin/blob.h"
|
||||
#include "picrin/string.h"
|
||||
|
||||
static bool
|
||||
str_equal_p(struct pic_string *str1, struct pic_string *str2)
|
||||
{
|
||||
return pic_strcmp(str1, str2) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
blob_equal_p(struct pic_blob *blob1, struct pic_blob *blob2)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (blob1->len != blob2->len) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < blob1->len; ++i) {
|
||||
if (blob1->data[i] != blob2->data[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
internal_equal_p(pic_state *pic, pic_value x, pic_value y, size_t depth, xhash *ht)
|
||||
{
|
||||
pic_value local = pic_nil_value();
|
||||
size_t c;
|
||||
|
||||
if (depth > 10) {
|
||||
if (depth > 200) {
|
||||
pic_errorf(pic, "Stack overflow in equal\n");
|
||||
}
|
||||
if (pic_pair_p(x) || pic_vec_p(x)) {
|
||||
if (xh_get_ptr(ht, pic_obj_ptr(x)) != NULL) {
|
||||
return true; /* `x' was seen already. */
|
||||
} else {
|
||||
xh_put_ptr(ht, pic_obj_ptr(x), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
|
||||
LOOP:
|
||||
|
||||
if (pic_eqv_p(x, y))
|
||||
return true;
|
||||
|
||||
if (pic_type(x) != pic_type(y))
|
||||
return false;
|
||||
|
||||
switch (pic_type(x)) {
|
||||
case PIC_TT_STRING:
|
||||
return str_equal_p(pic_str_ptr(x), pic_str_ptr(y));
|
||||
|
||||
case PIC_TT_BLOB:
|
||||
return blob_equal_p(pic_blob_ptr(x), pic_blob_ptr(y));
|
||||
|
||||
case PIC_TT_PAIR: {
|
||||
if (pic_nil_p(local)) {
|
||||
local = x;
|
||||
}
|
||||
if (internal_equal_p(pic, pic_car(pic, x), pic_car(pic, y), depth + 1, ht)) {
|
||||
x = pic_cdr(pic, x);
|
||||
y = pic_cdr(pic, y);
|
||||
|
||||
c++;
|
||||
|
||||
if (c == 2) {
|
||||
c = 0;
|
||||
local = pic_cdr(pic, local);
|
||||
if (pic_eq_p(local, x)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
goto LOOP;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case PIC_TT_VECTOR: {
|
||||
size_t i;
|
||||
struct pic_vector *u, *v;
|
||||
|
||||
u = pic_vec_ptr(x);
|
||||
v = pic_vec_ptr(y);
|
||||
|
||||
if (u->len != v->len) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < u->len; ++i) {
|
||||
if (! internal_equal_p(pic, u->data[i], v->data[i], depth + 1, ht))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
pic_equal_p(pic_state *pic, pic_value x, pic_value y){
|
||||
xhash ht;
|
||||
|
||||
xh_init_ptr(&ht, 0);
|
||||
|
||||
return internal_equal_p(pic, x, y, 0, &ht);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_bool_eq_p(pic_state *pic)
|
||||
{
|
||||
pic_value x, y;
|
||||
|
||||
pic_get_args(pic, "oo", &x, &y);
|
||||
|
||||
return pic_bool_value(pic_eq_p(x, y));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_bool_eqv_p(pic_state *pic)
|
||||
{
|
||||
pic_value x, y;
|
||||
|
||||
pic_get_args(pic, "oo", &x, &y);
|
||||
|
||||
return pic_bool_value(pic_eqv_p(x, y));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_bool_equal_p(pic_state *pic)
|
||||
{
|
||||
pic_value x, y;
|
||||
|
||||
pic_get_args(pic, "oo", &x, &y);
|
||||
|
||||
return pic_bool_value(pic_equal_p(pic, x, y));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_bool_not(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_false_p(v) ? pic_true_value() : pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_bool_boolean_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return (pic_true_p(v) || pic_false_p(v)) ? pic_true_value() : pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_bool_boolean_eq_p(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (! (pic_true_p(argv[i]) || pic_false_p(argv[i]))) {
|
||||
return pic_false_value();
|
||||
}
|
||||
if (! pic_eq_p(argv[i], argv[0])) {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
return pic_true_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_bool(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "eq?", pic_bool_eq_p);
|
||||
pic_defun(pic, "eqv?", pic_bool_eqv_p);
|
||||
pic_defun(pic, "equal?", pic_bool_equal_p);
|
||||
|
||||
pic_defun(pic, "not", pic_bool_not);
|
||||
pic_defun(pic, "boolean?", pic_bool_boolean_p);
|
||||
pic_defun(pic, "boolean=?", pic_bool_boolean_eq_p);
|
||||
}
|
||||
|
|
@ -0,0 +1,769 @@
|
|||
#if 0
|
||||
|
||||
=pod
|
||||
/*
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
||||
my $src = <<'EOL';
|
||||
|
||||
(define-library (picrin base)
|
||||
|
||||
(define (memoize f)
|
||||
"memoize on symbols"
|
||||
(define cache (make-dictionary))
|
||||
(lambda (sym)
|
||||
(call-with-values (lambda () (dictionary-ref cache sym))
|
||||
(lambda (value exists)
|
||||
(if exists
|
||||
value
|
||||
(begin
|
||||
(define val (f sym))
|
||||
(dictionary-set! cache sym val)
|
||||
val))))))
|
||||
|
||||
(define (er-macro-transformer f)
|
||||
(lambda (expr use-env mac-env)
|
||||
|
||||
(define rename
|
||||
(memoize
|
||||
(lambda (sym)
|
||||
(make-identifier sym mac-env))))
|
||||
|
||||
(define (compare x y)
|
||||
(if (not (symbol? x))
|
||||
#f
|
||||
(if (not (symbol? y))
|
||||
#f
|
||||
(identifier=? use-env x use-env y))))
|
||||
|
||||
(f expr rename compare)))
|
||||
|
||||
(define-syntax syntax-error
|
||||
(er-macro-transformer
|
||||
(lambda (expr rename compare)
|
||||
(apply error (cdr expr)))))
|
||||
|
||||
(define-syntax define-auxiliary-syntax
|
||||
(er-macro-transformer
|
||||
(lambda (expr r c)
|
||||
(list (r 'define-syntax) (cadr expr)
|
||||
(list (r 'lambda) '_
|
||||
(list (r 'error) "invalid use of auxiliary syntax"))))))
|
||||
|
||||
(define-auxiliary-syntax else)
|
||||
(define-auxiliary-syntax =>)
|
||||
(define-auxiliary-syntax unquote)
|
||||
(define-auxiliary-syntax unquote-splicing)
|
||||
|
||||
(define-syntax let
|
||||
(er-macro-transformer
|
||||
(lambda (expr r compare)
|
||||
(if (symbol? (cadr expr))
|
||||
(begin
|
||||
(define name (car (cdr expr)))
|
||||
(define bindings (car (cdr (cdr expr))))
|
||||
(define body (cdr (cdr (cdr expr))))
|
||||
(list (r 'let) '()
|
||||
(list (r 'define) name
|
||||
(cons (r 'lambda) (cons (map car bindings) body)))
|
||||
(cons name (map cadr bindings))))
|
||||
(begin
|
||||
(set! bindings (cadr expr))
|
||||
(set! body (cddr expr))
|
||||
(cons (cons (r 'lambda) (cons (map car bindings) body))
|
||||
(map cadr bindings)))))))
|
||||
|
||||
(define-syntax cond
|
||||
(er-macro-transformer
|
||||
(lambda (expr r compare)
|
||||
(let ((clauses (cdr expr)))
|
||||
(if (null? clauses)
|
||||
#f
|
||||
(begin
|
||||
(define clause (car clauses))
|
||||
(if (compare (r 'else) (car clause))
|
||||
(cons (r 'begin) (cdr clause))
|
||||
(if (if (>= (length clause) 2)
|
||||
(compare (r '=>) (list-ref clause 1))
|
||||
#f)
|
||||
(list (r 'let) (list (list (r 'x) (car clause)))
|
||||
(list (r 'if) (r 'x)
|
||||
(list (list-ref clause 2) (r 'x))
|
||||
(cons (r 'cond) (cdr clauses))))
|
||||
(list (r 'if) (car clause)
|
||||
(cons (r 'begin) (cdr clause))
|
||||
(cons (r 'cond) (cdr clauses)))))))))))
|
||||
|
||||
(define-syntax and
|
||||
(er-macro-transformer
|
||||
(lambda (expr r compare)
|
||||
(let ((exprs (cdr expr)))
|
||||
(cond
|
||||
((null? exprs)
|
||||
#t)
|
||||
((= (length exprs) 1)
|
||||
(car exprs))
|
||||
(else
|
||||
(list (r 'let) (list (list (r 'it) (car exprs)))
|
||||
(list (r 'if) (r 'it)
|
||||
(cons (r 'and) (cdr exprs))
|
||||
(r 'it)))))))))
|
||||
|
||||
(define-syntax or
|
||||
(er-macro-transformer
|
||||
(lambda (expr r compare)
|
||||
(let ((exprs (cdr expr)))
|
||||
(cond
|
||||
((null? exprs)
|
||||
#t)
|
||||
((= (length exprs) 1)
|
||||
(car exprs))
|
||||
(else
|
||||
(list (r 'let) (list (list (r 'it) (car exprs)))
|
||||
(list (r 'if) (r 'it)
|
||||
(r 'it)
|
||||
(cons (r 'or) (cdr exprs))))))))))
|
||||
|
||||
(define-syntax quasiquote
|
||||
(er-macro-transformer
|
||||
(lambda (form rename compare)
|
||||
|
||||
(define (quasiquote? form)
|
||||
(and (pair? form) (compare (car form) (rename 'quasiquote))))
|
||||
|
||||
(define (unquote? form)
|
||||
(and (pair? form) (compare (car form) (rename 'unquote))))
|
||||
|
||||
(define (unquote-splicing? form)
|
||||
(and (pair? form) (pair? (car form))
|
||||
(compare (car (car form)) (rename 'unquote-splicing))))
|
||||
|
||||
(define (qq depth expr)
|
||||
(cond
|
||||
;; unquote
|
||||
((unquote? expr)
|
||||
(if (= depth 1)
|
||||
(car (cdr expr))
|
||||
(list (rename 'list)
|
||||
(list (rename 'quote) (rename 'unquote))
|
||||
(qq (- depth 1) (car (cdr expr))))))
|
||||
;; unquote-splicing
|
||||
((unquote-splicing? expr)
|
||||
(if (= depth 1)
|
||||
(list (rename 'append)
|
||||
(car (cdr (car expr)))
|
||||
(qq depth (cdr expr)))
|
||||
(list (rename 'cons)
|
||||
(list (rename 'list)
|
||||
(list (rename 'quote) (rename 'unquote-splicing))
|
||||
(qq (- depth 1) (car (cdr (car expr)))))
|
||||
(qq depth (cdr expr)))))
|
||||
;; quasiquote
|
||||
((quasiquote? expr)
|
||||
(list (rename 'list)
|
||||
(list (rename 'quote) (rename 'quasiquote))
|
||||
(qq (+ depth 1) (car (cdr expr)))))
|
||||
;; list
|
||||
((pair? expr)
|
||||
(list (rename 'cons)
|
||||
(qq depth (car expr))
|
||||
(qq depth (cdr expr))))
|
||||
;; vector
|
||||
((vector? expr)
|
||||
(list (rename 'list->vector) (qq depth (vector->list expr))))
|
||||
;; simple datum
|
||||
(else
|
||||
(list (rename 'quote) expr))))
|
||||
|
||||
(let ((x (cadr form)))
|
||||
(qq 1 x)))))
|
||||
|
||||
(define-syntax let*
|
||||
(er-macro-transformer
|
||||
(lambda (form r compare)
|
||||
(let ((bindings (cadr form))
|
||||
(body (cddr form)))
|
||||
(if (null? bindings)
|
||||
`(,(r 'let) () ,@body)
|
||||
`(,(r 'let) ((,(caar bindings)
|
||||
,@(cdar bindings)))
|
||||
(,(r 'let*) (,@(cdr bindings))
|
||||
,@body)))))))
|
||||
|
||||
(define-syntax letrec*
|
||||
(er-macro-transformer
|
||||
(lambda (form r compare)
|
||||
(let ((bindings (cadr form))
|
||||
(body (cddr form)))
|
||||
(let ((vars (map (lambda (v) `(,v #f)) (map car bindings)))
|
||||
(initials (map (lambda (v) `(,(r 'set!) ,@v)) bindings)))
|
||||
`(,(r 'let) (,@vars)
|
||||
,@initials
|
||||
,@body))))))
|
||||
|
||||
(define-syntax letrec
|
||||
(er-macro-transformer
|
||||
(lambda (form rename compare)
|
||||
`(,(rename 'letrec*) ,@(cdr form)))))
|
||||
|
||||
(define-syntax let*-values
|
||||
(er-macro-transformer
|
||||
(lambda (form r c)
|
||||
(let ((formals (cadr form)))
|
||||
(if (null? formals)
|
||||
`(,(r 'let) () ,@(cddr form))
|
||||
`(,(r 'call-with-values) (,(r 'lambda) () ,@(cdar formals))
|
||||
(,(r 'lambda) (,@(caar formals))
|
||||
(,(r 'let*-values) (,@(cdr formals))
|
||||
,@(cddr form)))))))))
|
||||
|
||||
(define-syntax let-values
|
||||
(er-macro-transformer
|
||||
(lambda (form r c)
|
||||
`(,(r 'let*-values) ,@(cdr form)))))
|
||||
|
||||
(define-syntax define-values
|
||||
(er-macro-transformer
|
||||
(lambda (form r compare)
|
||||
(let ((formal (cadr form))
|
||||
(exprs (cddr form)))
|
||||
`(,(r 'begin)
|
||||
,@(let loop ((formal formal))
|
||||
(if (not (pair? formal))
|
||||
(if (symbol? formal)
|
||||
`((,(r 'define) ,formal #f))
|
||||
'())
|
||||
`((,(r 'define) ,(car formal) #f) . ,(loop (cdr formal)))))
|
||||
(,(r 'call-with-values) (,(r 'lambda) () ,@exprs)
|
||||
(,(r 'lambda) ,(r 'args)
|
||||
,@(let loop ((formal formal) (args (r 'args)))
|
||||
(if (not (pair? formal))
|
||||
(if (symbol? formal)
|
||||
`((,(r 'set!) ,formal ,args))
|
||||
'())
|
||||
`((,(r 'set!) ,(car formal) (,(r 'car) ,args))
|
||||
,@(loop (cdr formal) `(,(r 'cdr) ,args))))))))))))
|
||||
|
||||
(define-syntax do
|
||||
(er-macro-transformer
|
||||
(lambda (form r compare)
|
||||
(let ((bindings (car (cdr form)))
|
||||
(finish (car (cdr (cdr form))))
|
||||
(body (cdr (cdr (cdr form)))))
|
||||
`(,(r 'let) ,(r 'loop) ,(map (lambda (x)
|
||||
(list (car x) (cadr x)))
|
||||
bindings)
|
||||
(,(r 'if) ,(car finish)
|
||||
(,(r 'begin) ,@(cdr finish))
|
||||
(,(r 'begin) ,@body
|
||||
(,(r 'loop) ,@(map (lambda (x)
|
||||
(if (null? (cddr x))
|
||||
(car x)
|
||||
(car (cddr x))))
|
||||
bindings)))))))))
|
||||
|
||||
(define-syntax when
|
||||
(er-macro-transformer
|
||||
(lambda (expr rename compare)
|
||||
(let ((test (cadr expr))
|
||||
(body (cddr expr)))
|
||||
`(,(rename 'if) ,test
|
||||
(,(rename 'begin) ,@body)
|
||||
#f)))))
|
||||
|
||||
(define-syntax unless
|
||||
(er-macro-transformer
|
||||
(lambda (expr rename compare)
|
||||
(let ((test (cadr expr))
|
||||
(body (cddr expr)))
|
||||
`(,(rename 'if) ,test
|
||||
#f
|
||||
(,(rename 'begin) ,@body))))))
|
||||
|
||||
(define-syntax case
|
||||
(er-macro-transformer
|
||||
(lambda (expr r compare)
|
||||
(let ((key (cadr expr))
|
||||
(clauses (cddr expr)))
|
||||
`(,(r 'let) ((,(r 'key) ,key))
|
||||
,(let loop ((clauses clauses))
|
||||
(if (null? clauses)
|
||||
#f
|
||||
(begin
|
||||
(define clause (car clauses))
|
||||
`(,(r 'if) ,(if (compare (r 'else) (car clause))
|
||||
'#t
|
||||
`(,(r 'or)
|
||||
,@(map (lambda (x)
|
||||
`(,(r 'eqv?) ,(r 'key) (,(r 'quote) ,x)))
|
||||
(car clause))))
|
||||
,(if (compare (r '=>) (list-ref clause 1))
|
||||
`(,(list-ref clause 2) ,(r 'key))
|
||||
`(,(r 'begin) ,@(cdr clause)))
|
||||
,(loop (cdr clauses)))))))))))
|
||||
|
||||
(define (dynamic-bind parameters values body)
|
||||
(let* ((old-bindings
|
||||
(current-dynamic-environment))
|
||||
(binding
|
||||
(let ((dict (dictionary)))
|
||||
(for-each
|
||||
(lambda (parameter value)
|
||||
(dictionary-set! dict parameter (list (parameter value #f))))
|
||||
parameters
|
||||
values)
|
||||
dict))
|
||||
(new-bindings
|
||||
(cons binding old-bindings)))
|
||||
(dynamic-wind
|
||||
(lambda () (current-dynamic-environment new-bindings))
|
||||
body
|
||||
(lambda () (current-dynamic-environment old-bindings)))))
|
||||
|
||||
(define-syntax parameterize
|
||||
(er-macro-transformer
|
||||
(lambda (form r compare)
|
||||
(let ((formal (cadr form))
|
||||
(body (cddr form)))
|
||||
`(,(r 'dynamic-bind)
|
||||
(list ,@(map car formal))
|
||||
(list ,@(map cadr formal))
|
||||
(,(r 'lambda) () ,@body))))))
|
||||
|
||||
(define-syntax letrec-syntax
|
||||
(er-macro-transformer
|
||||
(lambda (form r c)
|
||||
(let ((formal (car (cdr form)))
|
||||
(body (cdr (cdr form))))
|
||||
`(let ()
|
||||
,@(map (lambda (x)
|
||||
`(,(r 'define-syntax) ,(car x) ,(cadr x)))
|
||||
formal)
|
||||
,@body)))))
|
||||
|
||||
(define-syntax let-syntax
|
||||
(er-macro-transformer
|
||||
(lambda (form r c)
|
||||
`(,(r 'letrec-syntax) ,@(cdr form)))))
|
||||
|
||||
(export let let* letrec letrec*
|
||||
let-values let*-values define-values
|
||||
quasiquote unquote unquote-splicing
|
||||
and or
|
||||
cond case else =>
|
||||
do when unless
|
||||
parameterize
|
||||
let-syntax letrec-syntax
|
||||
syntax-error))
|
||||
|
||||
EOL
|
||||
|
||||
open IN, "./boot.c";
|
||||
my @data = <IN>;
|
||||
close IN;
|
||||
|
||||
open STDOUT, ">", "./boot.c";
|
||||
|
||||
foreach (@data) {
|
||||
print;
|
||||
last if $_ eq "#---END---\n";
|
||||
}
|
||||
|
||||
print "\n#endif\n\n";
|
||||
|
||||
print <<EOL;
|
||||
const char pic_boot[] =
|
||||
EOL
|
||||
|
||||
my @lines = split /\n/, $src;
|
||||
|
||||
foreach (@lines) {
|
||||
s/\\/\\\\/g;
|
||||
s/"/\\"/g;
|
||||
print "\"$_\\n\"\n";
|
||||
}
|
||||
|
||||
=pod
|
||||
*/
|
||||
=cut
|
||||
|
||||
print <<EOL;
|
||||
;
|
||||
|
||||
#if 0
|
||||
Local Variables:
|
||||
mode: scheme
|
||||
End:
|
||||
|
||||
=cut
|
||||
#endif
|
||||
EOL
|
||||
|
||||
=pod
|
||||
|
||||
#---END---
|
||||
|
||||
#endif
|
||||
|
||||
const char pic_boot[] =
|
||||
"\n"
|
||||
"(define-library (picrin base)\n"
|
||||
"\n"
|
||||
" (define (memoize f)\n"
|
||||
" \"memoize on symbols\"\n"
|
||||
" (define cache (make-dictionary))\n"
|
||||
" (lambda (sym)\n"
|
||||
" (call-with-values (lambda () (dictionary-ref cache sym))\n"
|
||||
" (lambda (value exists)\n"
|
||||
" (if exists\n"
|
||||
" value\n"
|
||||
" (begin\n"
|
||||
" (define val (f sym))\n"
|
||||
" (dictionary-set! cache sym val)\n"
|
||||
" val))))))\n"
|
||||
"\n"
|
||||
" (define (er-macro-transformer f)\n"
|
||||
" (lambda (expr use-env mac-env)\n"
|
||||
"\n"
|
||||
" (define rename\n"
|
||||
" (memoize\n"
|
||||
" (lambda (sym)\n"
|
||||
" (make-identifier sym mac-env))))\n"
|
||||
"\n"
|
||||
" (define (compare x y)\n"
|
||||
" (if (not (symbol? x))\n"
|
||||
" #f\n"
|
||||
" (if (not (symbol? y))\n"
|
||||
" #f\n"
|
||||
" (identifier=? use-env x use-env y))))\n"
|
||||
"\n"
|
||||
" (f expr rename compare)))\n"
|
||||
"\n"
|
||||
" (define-syntax syntax-error\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr rename compare)\n"
|
||||
" (apply error (cdr expr)))))\n"
|
||||
"\n"
|
||||
" (define-syntax define-auxiliary-syntax\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr r c)\n"
|
||||
" (list (r 'define-syntax) (cadr expr)\n"
|
||||
" (list (r 'lambda) '_\n"
|
||||
" (list (r 'error) \"invalid use of auxiliary syntax\"))))))\n"
|
||||
"\n"
|
||||
" (define-auxiliary-syntax else)\n"
|
||||
" (define-auxiliary-syntax =>)\n"
|
||||
" (define-auxiliary-syntax unquote)\n"
|
||||
" (define-auxiliary-syntax unquote-splicing)\n"
|
||||
"\n"
|
||||
" (define-syntax let\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr r compare)\n"
|
||||
" (if (symbol? (cadr expr))\n"
|
||||
" (begin\n"
|
||||
" (define name (car (cdr expr)))\n"
|
||||
" (define bindings (car (cdr (cdr expr))))\n"
|
||||
" (define body (cdr (cdr (cdr expr))))\n"
|
||||
" (list (r 'let) '()\n"
|
||||
" (list (r 'define) name\n"
|
||||
" (cons (r 'lambda) (cons (map car bindings) body)))\n"
|
||||
" (cons name (map cadr bindings))))\n"
|
||||
" (begin\n"
|
||||
" (set! bindings (cadr expr))\n"
|
||||
" (set! body (cddr expr))\n"
|
||||
" (cons (cons (r 'lambda) (cons (map car bindings) body))\n"
|
||||
" (map cadr bindings)))))))\n"
|
||||
"\n"
|
||||
" (define-syntax cond\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr r compare)\n"
|
||||
" (let ((clauses (cdr expr)))\n"
|
||||
" (if (null? clauses)\n"
|
||||
" #f\n"
|
||||
" (begin\n"
|
||||
" (define clause (car clauses))\n"
|
||||
" (if (compare (r 'else) (car clause))\n"
|
||||
" (cons (r 'begin) (cdr clause))\n"
|
||||
" (if (if (>= (length clause) 2)\n"
|
||||
" (compare (r '=>) (list-ref clause 1))\n"
|
||||
" #f)\n"
|
||||
" (list (r 'let) (list (list (r 'x) (car clause)))\n"
|
||||
" (list (r 'if) (r 'x)\n"
|
||||
" (list (list-ref clause 2) (r 'x))\n"
|
||||
" (cons (r 'cond) (cdr clauses))))\n"
|
||||
" (list (r 'if) (car clause)\n"
|
||||
" (cons (r 'begin) (cdr clause))\n"
|
||||
" (cons (r 'cond) (cdr clauses)))))))))))\n"
|
||||
"\n"
|
||||
" (define-syntax and\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr r compare)\n"
|
||||
" (let ((exprs (cdr expr)))\n"
|
||||
" (cond\n"
|
||||
" ((null? exprs)\n"
|
||||
" #t)\n"
|
||||
" ((= (length exprs) 1)\n"
|
||||
" (car exprs))\n"
|
||||
" (else\n"
|
||||
" (list (r 'let) (list (list (r 'it) (car exprs)))\n"
|
||||
" (list (r 'if) (r 'it)\n"
|
||||
" (cons (r 'and) (cdr exprs))\n"
|
||||
" (r 'it)))))))))\n"
|
||||
"\n"
|
||||
" (define-syntax or\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr r compare)\n"
|
||||
" (let ((exprs (cdr expr)))\n"
|
||||
" (cond\n"
|
||||
" ((null? exprs)\n"
|
||||
" #t)\n"
|
||||
" ((= (length exprs) 1)\n"
|
||||
" (car exprs))\n"
|
||||
" (else\n"
|
||||
" (list (r 'let) (list (list (r 'it) (car exprs)))\n"
|
||||
" (list (r 'if) (r 'it)\n"
|
||||
" (r 'it)\n"
|
||||
" (cons (r 'or) (cdr exprs))))))))))\n"
|
||||
"\n"
|
||||
" (define-syntax quasiquote\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form rename compare)\n"
|
||||
"\n"
|
||||
" (define (quasiquote? form)\n"
|
||||
" (and (pair? form) (compare (car form) (rename 'quasiquote))))\n"
|
||||
"\n"
|
||||
" (define (unquote? form)\n"
|
||||
" (and (pair? form) (compare (car form) (rename 'unquote))))\n"
|
||||
"\n"
|
||||
" (define (unquote-splicing? form)\n"
|
||||
" (and (pair? form) (pair? (car form))\n"
|
||||
" (compare (car (car form)) (rename 'unquote-splicing))))\n"
|
||||
"\n"
|
||||
" (define (qq depth expr)\n"
|
||||
" (cond\n"
|
||||
" ;; unquote\n"
|
||||
" ((unquote? expr)\n"
|
||||
" (if (= depth 1)\n"
|
||||
" (car (cdr expr))\n"
|
||||
" (list (rename 'list)\n"
|
||||
" (list (rename 'quote) (rename 'unquote))\n"
|
||||
" (qq (- depth 1) (car (cdr expr))))))\n"
|
||||
" ;; unquote-splicing\n"
|
||||
" ((unquote-splicing? expr)\n"
|
||||
" (if (= depth 1)\n"
|
||||
" (list (rename 'append)\n"
|
||||
" (car (cdr (car expr)))\n"
|
||||
" (qq depth (cdr expr)))\n"
|
||||
" (list (rename 'cons)\n"
|
||||
" (list (rename 'list)\n"
|
||||
" (list (rename 'quote) (rename 'unquote-splicing))\n"
|
||||
" (qq (- depth 1) (car (cdr (car expr)))))\n"
|
||||
" (qq depth (cdr expr)))))\n"
|
||||
" ;; quasiquote\n"
|
||||
" ((quasiquote? expr)\n"
|
||||
" (list (rename 'list)\n"
|
||||
" (list (rename 'quote) (rename 'quasiquote))\n"
|
||||
" (qq (+ depth 1) (car (cdr expr)))))\n"
|
||||
" ;; list\n"
|
||||
" ((pair? expr)\n"
|
||||
" (list (rename 'cons)\n"
|
||||
" (qq depth (car expr))\n"
|
||||
" (qq depth (cdr expr))))\n"
|
||||
" ;; vector\n"
|
||||
" ((vector? expr)\n"
|
||||
" (list (rename 'list->vector) (qq depth (vector->list expr))))\n"
|
||||
" ;; simple datum\n"
|
||||
" (else\n"
|
||||
" (list (rename 'quote) expr))))\n"
|
||||
"\n"
|
||||
" (let ((x (cadr form)))\n"
|
||||
" (qq 1 x)))))\n"
|
||||
"\n"
|
||||
" (define-syntax let*\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r compare)\n"
|
||||
" (let ((bindings (cadr form))\n"
|
||||
" (body (cddr form)))\n"
|
||||
" (if (null? bindings)\n"
|
||||
" `(,(r 'let) () ,@body)\n"
|
||||
" `(,(r 'let) ((,(caar bindings)\n"
|
||||
" ,@(cdar bindings)))\n"
|
||||
" (,(r 'let*) (,@(cdr bindings))\n"
|
||||
" ,@body)))))))\n"
|
||||
"\n"
|
||||
" (define-syntax letrec*\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r compare)\n"
|
||||
" (let ((bindings (cadr form))\n"
|
||||
" (body (cddr form)))\n"
|
||||
" (let ((vars (map (lambda (v) `(,v #f)) (map car bindings)))\n"
|
||||
" (initials (map (lambda (v) `(,(r 'set!) ,@v)) bindings)))\n"
|
||||
" `(,(r 'let) (,@vars)\n"
|
||||
" ,@initials\n"
|
||||
" ,@body))))))\n"
|
||||
"\n"
|
||||
" (define-syntax letrec\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form rename compare)\n"
|
||||
" `(,(rename 'letrec*) ,@(cdr form)))))\n"
|
||||
"\n"
|
||||
" (define-syntax let*-values\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r c)\n"
|
||||
" (let ((formals (cadr form)))\n"
|
||||
" (if (null? formals)\n"
|
||||
" `(,(r 'let) () ,@(cddr form))\n"
|
||||
" `(,(r 'call-with-values) (,(r 'lambda) () ,@(cdar formals))\n"
|
||||
" (,(r 'lambda) (,@(caar formals))\n"
|
||||
" (,(r 'let*-values) (,@(cdr formals))\n"
|
||||
" ,@(cddr form)))))))))\n"
|
||||
"\n"
|
||||
" (define-syntax let-values\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r c)\n"
|
||||
" `(,(r 'let*-values) ,@(cdr form)))))\n"
|
||||
"\n"
|
||||
" (define-syntax define-values\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r compare)\n"
|
||||
" (let ((formal (cadr form))\n"
|
||||
" (exprs (cddr form)))\n"
|
||||
" `(,(r 'begin)\n"
|
||||
" ,@(let loop ((formal formal))\n"
|
||||
" (if (not (pair? formal))\n"
|
||||
" (if (symbol? formal)\n"
|
||||
" `((,(r 'define) ,formal #f))\n"
|
||||
" '())\n"
|
||||
" `((,(r 'define) ,(car formal) #f) . ,(loop (cdr formal)))))\n"
|
||||
" (,(r 'call-with-values) (,(r 'lambda) () ,@exprs)\n"
|
||||
" (,(r 'lambda) ,(r 'args)\n"
|
||||
" ,@(let loop ((formal formal) (args (r 'args)))\n"
|
||||
" (if (not (pair? formal))\n"
|
||||
" (if (symbol? formal)\n"
|
||||
" `((,(r 'set!) ,formal ,args))\n"
|
||||
" '())\n"
|
||||
" `((,(r 'set!) ,(car formal) (,(r 'car) ,args))\n"
|
||||
" ,@(loop (cdr formal) `(,(r 'cdr) ,args))))))))))))\n"
|
||||
"\n"
|
||||
" (define-syntax do\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r compare)\n"
|
||||
" (let ((bindings (car (cdr form)))\n"
|
||||
" (finish (car (cdr (cdr form))))\n"
|
||||
" (body (cdr (cdr (cdr form)))))\n"
|
||||
" `(,(r 'let) ,(r 'loop) ,(map (lambda (x)\n"
|
||||
" (list (car x) (cadr x)))\n"
|
||||
" bindings)\n"
|
||||
" (,(r 'if) ,(car finish)\n"
|
||||
" (,(r 'begin) ,@(cdr finish))\n"
|
||||
" (,(r 'begin) ,@body\n"
|
||||
" (,(r 'loop) ,@(map (lambda (x)\n"
|
||||
" (if (null? (cddr x))\n"
|
||||
" (car x)\n"
|
||||
" (car (cddr x))))\n"
|
||||
" bindings)))))))))\n"
|
||||
"\n"
|
||||
" (define-syntax when\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr rename compare)\n"
|
||||
" (let ((test (cadr expr))\n"
|
||||
" (body (cddr expr)))\n"
|
||||
" `(,(rename 'if) ,test\n"
|
||||
" (,(rename 'begin) ,@body)\n"
|
||||
" #f)))))\n"
|
||||
"\n"
|
||||
" (define-syntax unless\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr rename compare)\n"
|
||||
" (let ((test (cadr expr))\n"
|
||||
" (body (cddr expr)))\n"
|
||||
" `(,(rename 'if) ,test\n"
|
||||
" #f\n"
|
||||
" (,(rename 'begin) ,@body))))))\n"
|
||||
"\n"
|
||||
" (define-syntax case\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (expr r compare)\n"
|
||||
" (let ((key (cadr expr))\n"
|
||||
" (clauses (cddr expr)))\n"
|
||||
" `(,(r 'let) ((,(r 'key) ,key))\n"
|
||||
" ,(let loop ((clauses clauses))\n"
|
||||
" (if (null? clauses)\n"
|
||||
" #f\n"
|
||||
" (begin\n"
|
||||
" (define clause (car clauses))\n"
|
||||
" `(,(r 'if) ,(if (compare (r 'else) (car clause))\n"
|
||||
" '#t\n"
|
||||
" `(,(r 'or)\n"
|
||||
" ,@(map (lambda (x)\n"
|
||||
" `(,(r 'eqv?) ,(r 'key) (,(r 'quote) ,x)))\n"
|
||||
" (car clause))))\n"
|
||||
" ,(if (compare (r '=>) (list-ref clause 1))\n"
|
||||
" `(,(list-ref clause 2) ,(r 'key))\n"
|
||||
" `(,(r 'begin) ,@(cdr clause)))\n"
|
||||
" ,(loop (cdr clauses)))))))))))\n"
|
||||
"\n"
|
||||
" (define (dynamic-bind parameters values body)\n"
|
||||
" (let* ((old-bindings\n"
|
||||
" (current-dynamic-environment))\n"
|
||||
" (binding\n"
|
||||
" (let ((dict (dictionary)))\n"
|
||||
" (for-each\n"
|
||||
" (lambda (parameter value)\n"
|
||||
" (dictionary-set! dict parameter (list (parameter value #f))))\n"
|
||||
" parameters\n"
|
||||
" values)\n"
|
||||
" dict))\n"
|
||||
" (new-bindings\n"
|
||||
" (cons binding old-bindings)))\n"
|
||||
" (dynamic-wind\n"
|
||||
" (lambda () (current-dynamic-environment new-bindings))\n"
|
||||
" body\n"
|
||||
" (lambda () (current-dynamic-environment old-bindings)))))\n"
|
||||
"\n"
|
||||
" (define-syntax parameterize\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r compare)\n"
|
||||
" (let ((formal (cadr form))\n"
|
||||
" (body (cddr form)))\n"
|
||||
" `(,(r 'dynamic-bind)\n"
|
||||
" (list ,@(map car formal))\n"
|
||||
" (list ,@(map cadr formal))\n"
|
||||
" (,(r 'lambda) () ,@body))))))\n"
|
||||
"\n"
|
||||
" (define-syntax letrec-syntax\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r c)\n"
|
||||
" (let ((formal (car (cdr form)))\n"
|
||||
" (body (cdr (cdr form))))\n"
|
||||
" `(let ()\n"
|
||||
" ,@(map (lambda (x)\n"
|
||||
" `(,(r 'define-syntax) ,(car x) ,(cadr x)))\n"
|
||||
" formal)\n"
|
||||
" ,@body)))))\n"
|
||||
"\n"
|
||||
" (define-syntax let-syntax\n"
|
||||
" (er-macro-transformer\n"
|
||||
" (lambda (form r c)\n"
|
||||
" `(,(r 'letrec-syntax) ,@(cdr form)))))\n"
|
||||
"\n"
|
||||
" (export let let* letrec letrec*\n"
|
||||
" let-values let*-values define-values\n"
|
||||
" quasiquote unquote unquote-splicing\n"
|
||||
" and or\n"
|
||||
" cond case else =>\n"
|
||||
" do when unless\n"
|
||||
" parameterize\n"
|
||||
" let-syntax letrec-syntax\n"
|
||||
" syntax-error))\n"
|
||||
;
|
||||
|
||||
#if 0
|
||||
Local Variables:
|
||||
mode: scheme
|
||||
End:
|
||||
|
||||
=cut
|
||||
#endif
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
|
||||
static pic_value
|
||||
pic_char_char_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_char_p(v) ? pic_true_value() : pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_char_char_to_integer(pic_state *pic)
|
||||
{
|
||||
char c;
|
||||
|
||||
pic_get_args(pic, "c", &c);
|
||||
|
||||
return pic_int_value(c);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_char_integer_to_char(pic_state *pic)
|
||||
{
|
||||
int i;
|
||||
|
||||
pic_get_args(pic, "i", &i);
|
||||
|
||||
if (i < 0 || i > 127) {
|
||||
pic_errorf(pic, "integer->char: integer out of char range: %d", i);
|
||||
}
|
||||
|
||||
return pic_char_value((char)i);
|
||||
}
|
||||
|
||||
#define DEFINE_CHAR_CMP(op, name) \
|
||||
static pic_value \
|
||||
pic_char_##name##_p(pic_state *pic) \
|
||||
{ \
|
||||
size_t argc, i; \
|
||||
pic_value *argv; \
|
||||
char c, d; \
|
||||
\
|
||||
pic_get_args(pic, "cc*", &c, &d, &argc, &argv); \
|
||||
\
|
||||
if (! (c op d)) \
|
||||
return pic_false_value(); \
|
||||
\
|
||||
for (i = 0; i < argc; ++i) { \
|
||||
c = d; \
|
||||
if (pic_char_p(argv[i])) \
|
||||
d = pic_char(argv[i]); \
|
||||
else \
|
||||
pic_errorf(pic, #op ": char required"); \
|
||||
\
|
||||
if (! (c op d)) \
|
||||
return pic_false_value(); \
|
||||
} \
|
||||
\
|
||||
return pic_true_value(); \
|
||||
}
|
||||
|
||||
DEFINE_CHAR_CMP(==, eq)
|
||||
DEFINE_CHAR_CMP(<, lt)
|
||||
DEFINE_CHAR_CMP(>, gt)
|
||||
DEFINE_CHAR_CMP(<=, le)
|
||||
DEFINE_CHAR_CMP(>=, ge)
|
||||
|
||||
void
|
||||
pic_init_char(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "char?", pic_char_char_p);
|
||||
pic_defun(pic, "char->integer", pic_char_char_to_integer);
|
||||
pic_defun(pic, "integer->char", pic_char_integer_to_char);
|
||||
pic_defun(pic, "char=?", pic_char_eq_p);
|
||||
pic_defun(pic, "char<?", pic_char_lt_p);
|
||||
pic_defun(pic, "char>?", pic_char_gt_p);
|
||||
pic_defun(pic, "char<=?", pic_char_le_p);
|
||||
pic_defun(pic, "char>=?", pic_char_ge_p);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,286 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/cont.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/data.h"
|
||||
#include "picrin/error.h"
|
||||
|
||||
void
|
||||
pic_wind(pic_state *pic, struct pic_winder *here, struct pic_winder *there)
|
||||
{
|
||||
if (here == there)
|
||||
return;
|
||||
|
||||
if (here->depth < there->depth) {
|
||||
pic_wind(pic, here, there->prev);
|
||||
pic_apply0(pic, there->in);
|
||||
}
|
||||
else {
|
||||
pic_apply0(pic, there->out);
|
||||
pic_wind(pic, here->prev, there);
|
||||
}
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_dynamic_wind(pic_state *pic, struct pic_proc *in, struct pic_proc *thunk, struct pic_proc *out)
|
||||
{
|
||||
struct pic_winder *here;
|
||||
pic_value val;
|
||||
|
||||
if (in != NULL) {
|
||||
pic_apply0(pic, in); /* enter */
|
||||
}
|
||||
|
||||
here = pic->wind;
|
||||
pic->wind = pic_alloc(pic, sizeof(struct pic_winder));
|
||||
pic->wind->prev = here;
|
||||
pic->wind->depth = here->depth + 1;
|
||||
pic->wind->in = in;
|
||||
pic->wind->out = out;
|
||||
|
||||
val = pic_apply0(pic, thunk);
|
||||
|
||||
pic->wind = here;
|
||||
|
||||
if (out != NULL) {
|
||||
pic_apply0(pic, out); /* exit */
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
pic_save_point(pic_state *pic, struct pic_escape *escape)
|
||||
{
|
||||
escape->valid = true;
|
||||
|
||||
/* save runtime context */
|
||||
escape->wind = pic->wind;
|
||||
escape->sp_offset = pic->sp - pic->stbase;
|
||||
escape->ci_offset = pic->ci - pic->cibase;
|
||||
escape->xp_offset = pic->xp - pic->xpbase;
|
||||
escape->arena_idx = pic->arena_idx;
|
||||
escape->ip = pic->ip;
|
||||
|
||||
escape->results = pic_undef_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_load_point(pic_state *pic, struct pic_escape *escape)
|
||||
{
|
||||
if (! escape->valid) {
|
||||
pic_errorf(pic, "calling dead escape continuation");
|
||||
}
|
||||
|
||||
pic_wind(pic, pic->wind, escape->wind);
|
||||
|
||||
/* load runtime context */
|
||||
pic->wind = escape->wind;
|
||||
pic->sp = pic->stbase + escape->sp_offset;
|
||||
pic->ci = pic->cibase + escape->ci_offset;
|
||||
pic->xp = pic->xpbase + escape->xp_offset;
|
||||
pic->arena_idx = escape->arena_idx;
|
||||
pic->ip = escape->ip;
|
||||
|
||||
escape->valid = false;
|
||||
}
|
||||
|
||||
noreturn static pic_value
|
||||
escape_call(pic_state *pic)
|
||||
{
|
||||
size_t argc;
|
||||
pic_value *argv;
|
||||
struct pic_data *e;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
e = pic_data_ptr(pic_attr_ref(pic, pic_obj_value(pic_get_proc(pic)), "@@escape"));
|
||||
|
||||
pic_load_point(pic, e->data);
|
||||
|
||||
longjmp(((struct pic_escape *)e->data)->jmp, 1);
|
||||
}
|
||||
|
||||
struct pic_proc *
|
||||
pic_make_econt(pic_state *pic, struct pic_escape *escape)
|
||||
{
|
||||
static const pic_data_type escape_type = { "escape", pic_free, NULL };
|
||||
struct pic_proc *cont;
|
||||
struct pic_data *e;
|
||||
|
||||
cont = pic_make_proc(pic, escape_call, "<escape-procedure>");
|
||||
|
||||
e = pic_data_alloc(pic, &escape_type, escape);
|
||||
|
||||
/* save the escape continuation in proc */
|
||||
pic_attr_set(pic, pic_obj_value(cont), "@@escape", pic_obj_value(e));
|
||||
|
||||
return cont;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_escape(pic_state *pic, struct pic_proc *proc)
|
||||
{
|
||||
struct pic_escape *escape = pic_alloc(pic, sizeof(struct pic_escape));
|
||||
|
||||
pic_save_point(pic, escape);
|
||||
|
||||
if (setjmp(escape->jmp)) {
|
||||
return pic_values_by_list(pic, escape->results);
|
||||
}
|
||||
else {
|
||||
pic_value val;
|
||||
|
||||
val = pic_apply1(pic, proc, pic_obj_value(pic_make_econt(pic, escape)));
|
||||
|
||||
escape->valid = false;
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values0(pic_state *pic)
|
||||
{
|
||||
return pic_values_by_list(pic, pic_nil_value());
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values1(pic_state *pic, pic_value arg1)
|
||||
{
|
||||
return pic_values_by_list(pic, pic_list1(pic, arg1));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values2(pic_state *pic, pic_value arg1, pic_value arg2)
|
||||
{
|
||||
return pic_values_by_list(pic, pic_list2(pic, arg1, arg2));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values3(pic_state *pic, pic_value arg1, pic_value arg2, pic_value arg3)
|
||||
{
|
||||
return pic_values_by_list(pic, pic_list3(pic, arg1, arg2, arg3));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values4(pic_state *pic, pic_value arg1, pic_value arg2, pic_value arg3, pic_value arg4)
|
||||
{
|
||||
return pic_values_by_list(pic, pic_list4(pic, arg1, arg2, arg3, arg4));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values5(pic_state *pic, pic_value arg1, pic_value arg2, pic_value arg3, pic_value arg4, pic_value arg5)
|
||||
{
|
||||
return pic_values_by_list(pic, pic_list5(pic, arg1, arg2, arg3, arg4, arg5));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values_by_array(pic_state *pic, size_t argc, pic_value *argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic->sp[i] = argv[i];
|
||||
}
|
||||
pic->ci->retc = (int)argc;
|
||||
|
||||
return argc == 0 ? pic_none_value() : pic->sp[0];
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_values_by_list(pic_state *pic, pic_value list)
|
||||
{
|
||||
pic_value v;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
pic_for_each (v, list) {
|
||||
pic->sp[i++] = v;
|
||||
}
|
||||
pic->ci->retc = i;
|
||||
|
||||
return pic_nil_p(list) ? pic_none_value() : pic->sp[0];
|
||||
}
|
||||
|
||||
size_t
|
||||
pic_receive(pic_state *pic, size_t n, pic_value *argv)
|
||||
{
|
||||
pic_callinfo *ci;
|
||||
size_t i, retc;
|
||||
|
||||
/* take info from discarded frame */
|
||||
ci = pic->ci + 1;
|
||||
retc = (size_t)ci->retc;
|
||||
|
||||
for (i = 0; i < retc && i < n; ++i) {
|
||||
argv[i] = ci->fp[i];
|
||||
}
|
||||
|
||||
return retc;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_cont_callcc(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *cb;
|
||||
|
||||
pic_get_args(pic, "l", &cb);
|
||||
|
||||
return pic_escape(pic, cb);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_cont_dynamic_wind(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *in, *thunk, *out;
|
||||
|
||||
pic_get_args(pic, "lll", &in, &thunk, &out);
|
||||
|
||||
return pic_dynamic_wind(pic, in, thunk, out);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_cont_values(pic_state *pic)
|
||||
{
|
||||
size_t argc;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
return pic_values_by_array(pic, argc, argv);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_cont_call_with_values(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *producer, *consumer;
|
||||
size_t argc;
|
||||
pic_value args[256];
|
||||
|
||||
pic_get_args(pic, "ll", &producer, &consumer);
|
||||
|
||||
pic_apply(pic, producer, pic_nil_value());
|
||||
|
||||
argc = pic_receive(pic, 256, args);
|
||||
|
||||
return pic_apply_trampoline(pic, consumer, pic_list_by_array(pic, argc, args));
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_cont(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "call-with-current-continuation", pic_cont_callcc);
|
||||
pic_defun(pic, "call/cc", pic_cont_callcc);
|
||||
pic_defun(pic, "dynamic-wind", pic_cont_dynamic_wind);
|
||||
pic_defun(pic, "values", pic_cont_values);
|
||||
pic_defun(pic, "call-with-values", pic_cont_call_with_values);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#include "picrin.h"
|
||||
#include "picrin/data.h"
|
||||
|
||||
struct pic_data *
|
||||
pic_data_alloc(pic_state *pic, const pic_data_type *type, void *userdata)
|
||||
{
|
||||
struct pic_data *data;
|
||||
|
||||
data = (struct pic_data *)pic_obj_alloc(pic, sizeof(struct pic_data), PIC_TT_DATA);
|
||||
data->type = type;
|
||||
data->data = userdata;
|
||||
xh_init_str(&data->storage, sizeof(pic_value));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/error.h"
|
||||
#include "picrin/proc.h"
|
||||
|
||||
pic_str *
|
||||
pic_get_backtrace(pic_state *pic)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_callinfo *ci;
|
||||
pic_str *trace;
|
||||
|
||||
trace = pic_make_str(pic, NULL, 0);
|
||||
|
||||
for (ci = pic->ci; ci != pic->cibase; --ci) {
|
||||
struct pic_proc *proc = pic_proc_ptr(ci->fp[0]);
|
||||
|
||||
trace = pic_strcat(pic, trace, pic_make_str_cstr(pic, " at "));
|
||||
trace = pic_strcat(pic, trace, pic_make_str_cstr(pic, pic_symbol_name(pic, pic_proc_name(proc))));
|
||||
|
||||
if (pic_proc_func_p(proc)) {
|
||||
trace = pic_strcat(pic, trace, pic_make_str_cstr(pic, " (native function)\n"));
|
||||
} else if (pic_proc_irep_p(proc)) {
|
||||
trace = pic_strcat(pic, trace, pic_make_str_cstr(pic, " (unknown location)\n")); /* TODO */
|
||||
}
|
||||
}
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, pic_obj_value(trace));
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
void
|
||||
pic_print_backtrace(pic_state *pic)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_str *trace;
|
||||
|
||||
assert(! pic_undef_p(pic->err));
|
||||
|
||||
if (! pic_error_p(pic->err)) {
|
||||
trace = pic_format(pic, "raised: ~s", pic->err);
|
||||
} else {
|
||||
struct pic_error *e;
|
||||
|
||||
e = pic_error_ptr(pic->err);
|
||||
if (e->type != pic_intern_cstr(pic, "")) {
|
||||
trace = pic_format(pic, "~s ", pic_sym_value(e->type));
|
||||
} else {
|
||||
trace = pic_make_str(pic, NULL, 0);
|
||||
}
|
||||
trace = pic_strcat(pic, trace, pic_format(pic, "error: ~s", pic_obj_value(e->msg)));
|
||||
|
||||
/* TODO: print error irritants */
|
||||
|
||||
trace = pic_strcat(pic, trace, pic_make_str(pic, "\n", 1));
|
||||
trace = pic_strcat(pic, trace, e->stack);
|
||||
}
|
||||
|
||||
/* print! */
|
||||
xfprintf(xstderr, "%s", pic_str_cstr(trace));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
}
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/dict.h"
|
||||
#include "picrin/cont.h"
|
||||
#include "picrin/pair.h"
|
||||
|
||||
static int
|
||||
xh_value_hash(const void *key, void *data)
|
||||
{
|
||||
union { double f; int i; } u;
|
||||
pic_value val = *(pic_value *)key;
|
||||
int hash, vtype;
|
||||
|
||||
UNUSED(data);
|
||||
|
||||
vtype = pic_vtype(val);
|
||||
|
||||
switch (vtype) {
|
||||
default:
|
||||
hash = 0;
|
||||
break;
|
||||
case PIC_VTYPE_SYMBOL:
|
||||
hash = pic_sym(val);
|
||||
break;
|
||||
case PIC_VTYPE_FLOAT:
|
||||
u.f = pic_float(val);
|
||||
hash = u.i;
|
||||
break;
|
||||
case PIC_VTYPE_INT:
|
||||
hash = pic_int(val);
|
||||
break;
|
||||
case PIC_VTYPE_HEAP:
|
||||
hash = (int)(intptr_t)pic_ptr(val);
|
||||
break;
|
||||
}
|
||||
|
||||
return hash + vtype;
|
||||
}
|
||||
|
||||
static int
|
||||
xh_value_equal(const void *key1, const void *key2, void *pic)
|
||||
{
|
||||
return pic_equal_p(pic, *(pic_value *)key1, *(pic_value *)key2);
|
||||
}
|
||||
|
||||
static void
|
||||
xh_init_value(pic_state *pic, xhash *x)
|
||||
{
|
||||
xh_init_(x, sizeof(pic_value), sizeof(pic_value), xh_value_hash, xh_value_equal, pic);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_value(xhash *x, pic_value key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_value(xhash *x, pic_value key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_value(xhash *x, pic_value key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
struct pic_dict *
|
||||
pic_make_dict(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
|
||||
dict = (struct pic_dict *)pic_obj_alloc(pic, sizeof(struct pic_dict), PIC_TT_DICT);
|
||||
xh_init_value(pic, &dict->hash);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_dict_ref(pic_state *pic, struct pic_dict *dict, pic_value key)
|
||||
{
|
||||
xh_entry *e;
|
||||
|
||||
e = xh_get_value(&dict->hash, key);
|
||||
if (! e) {
|
||||
pic_errorf(pic, "element not found for a key: ~s", key);
|
||||
}
|
||||
return xh_val(e, pic_value);
|
||||
}
|
||||
|
||||
void
|
||||
pic_dict_set(pic_state *pic, struct pic_dict *dict, pic_value key, pic_value val)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
xh_put_value(&dict->hash, key, &val);
|
||||
}
|
||||
|
||||
size_t
|
||||
pic_dict_size(pic_state *pic, struct pic_dict *dict)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
return dict->hash.count;
|
||||
}
|
||||
|
||||
bool
|
||||
pic_dict_has(pic_state *pic, struct pic_dict *dict, pic_value key)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
return xh_get_value(&dict->hash, key) != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pic_dict_del(pic_state *pic, struct pic_dict *dict, pic_value key)
|
||||
{
|
||||
if (xh_get_value(&dict->hash, key) == NULL) {
|
||||
pic_errorf(pic, "no slot named ~s found in dictionary", key);
|
||||
}
|
||||
|
||||
xh_del_value(&dict->hash, key);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_make_dictionary(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
dict = pic_make_dict(pic);
|
||||
|
||||
return pic_obj_value(dict);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value *argv;
|
||||
size_t argc, i;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
dict = pic_make_dict(pic);
|
||||
|
||||
for (i = 0; i < argc; i += 2) {
|
||||
pic_dict_set(pic, dict, argv[i], argv[i+1]);
|
||||
}
|
||||
|
||||
return pic_obj_value(dict);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_p(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
|
||||
pic_get_args(pic, "o", &obj);
|
||||
|
||||
return pic_bool_value(pic_dict_p(obj));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_ref(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value key;
|
||||
|
||||
pic_get_args(pic, "do", &dict, &key);
|
||||
|
||||
if (pic_dict_has(pic, dict, key)) {
|
||||
return pic_values2(pic, pic_dict_ref(pic, dict, key), pic_true_value());
|
||||
} else {
|
||||
return pic_values2(pic, pic_none_value(), pic_false_value());
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_set(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value key, val;
|
||||
|
||||
pic_get_args(pic, "doo", &dict, &key, &val);
|
||||
|
||||
pic_dict_set(pic, dict, key, val);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_del(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value key;
|
||||
|
||||
pic_get_args(pic, "do", &dict, &key);
|
||||
|
||||
pic_dict_del(pic, dict, key);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_size(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
|
||||
pic_get_args(pic, "d", &dict);
|
||||
|
||||
return pic_size_value(pic_dict_size(pic, dict));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_to_alist(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value item, alist = pic_nil_value();
|
||||
xh_entry *it;
|
||||
|
||||
pic_get_args(pic, "d", &dict);
|
||||
|
||||
for (it = xh_begin(&dict->hash); it != NULL; it = xh_next(it)) {
|
||||
item = pic_cons(pic, xh_key(it, pic_value), xh_val(it, pic_value));
|
||||
pic_push(pic, item, alist);
|
||||
}
|
||||
|
||||
return pic_reverse(pic, alist);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_alist_to_dictionary(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value alist, e;
|
||||
|
||||
pic_get_args(pic, "o", &alist);
|
||||
|
||||
dict = pic_make_dict(pic);
|
||||
|
||||
pic_for_each (e, pic_reverse(pic, alist)) {
|
||||
pic_dict_set(pic, dict, pic_car(pic, e), pic_cdr(pic, e));
|
||||
}
|
||||
|
||||
return pic_obj_value(dict);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_dictionary_to_plist(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value plist = pic_nil_value();
|
||||
xh_entry *it;
|
||||
|
||||
pic_get_args(pic, "d", &dict);
|
||||
|
||||
for (it = xh_begin(&dict->hash); it != NULL; it = xh_next(it)) {
|
||||
pic_push(pic, xh_key(it, pic_value), plist);
|
||||
pic_push(pic, xh_val(it, pic_value), plist);
|
||||
}
|
||||
|
||||
return pic_reverse(pic, plist);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_dict_plist_to_dictionary(pic_state *pic)
|
||||
{
|
||||
struct pic_dict *dict;
|
||||
pic_value plist, e;
|
||||
|
||||
pic_get_args(pic, "o", &plist);
|
||||
|
||||
dict = pic_make_dict(pic);
|
||||
|
||||
for (e = pic_reverse(pic, plist); ! pic_nil_p(e); e = pic_cddr(pic, e)) {
|
||||
pic_dict_set(pic, dict, pic_cadr(pic, e), pic_car(pic, e));
|
||||
}
|
||||
|
||||
return pic_obj_value(dict);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_dict(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "make-dictionary", pic_dict_make_dictionary);
|
||||
pic_defun(pic, "dictionary?", pic_dict_dictionary_p);
|
||||
pic_defun(pic, "dictionary", pic_dict_dictionary);
|
||||
pic_defun(pic, "dictionary-ref", pic_dict_dictionary_ref);
|
||||
pic_defun(pic, "dictionary-set!", pic_dict_dictionary_set);
|
||||
pic_defun(pic, "dictionary-delete!", pic_dict_dictionary_del);
|
||||
pic_defun(pic, "dictionary-size", pic_dict_dictionary_size);
|
||||
pic_defun(pic, "dictionary->alist", pic_dict_dictionary_to_alist);
|
||||
pic_defun(pic, "alist->dictionary", pic_dict_alist_to_dictionary);
|
||||
pic_defun(pic, "dictionary->plist", pic_dict_dictionary_to_plist);
|
||||
pic_defun(pic, "plist->dictionary", pic_dict_plist_to_dictionary);
|
||||
}
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/cont.h"
|
||||
#include "picrin/data.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/error.h"
|
||||
|
||||
void
|
||||
pic_panic(pic_state *pic, const char *msg)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
fprintf(stderr, "abort: %s\n", msg);
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
pic_warnf(pic_state *pic, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
pic_value err_line;
|
||||
|
||||
va_start(ap, fmt);
|
||||
err_line = pic_xvformat(pic, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, "warn: %s\n", pic_str_cstr(pic_str_ptr(pic_car(pic, err_line))));
|
||||
}
|
||||
|
||||
void
|
||||
pic_errorf(pic_state *pic, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
pic_value err_line, irrs;
|
||||
const char *msg;
|
||||
|
||||
va_start(ap, fmt);
|
||||
err_line = pic_xvformat(pic, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
msg = pic_str_cstr(pic_str_ptr(pic_car(pic, err_line)));
|
||||
irrs = pic_cdr(pic, err_line);
|
||||
|
||||
pic_error(pic, msg, irrs);
|
||||
}
|
||||
|
||||
const char *
|
||||
pic_errmsg(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
|
||||
assert(! pic_undef_p(pic->err));
|
||||
|
||||
if (! pic_error_p(pic->err)) {
|
||||
str = pic_format(pic, "~s", pic->err);
|
||||
} else {
|
||||
str = pic_error_ptr(pic->err)->msg;
|
||||
}
|
||||
|
||||
return pic_str_cstr(str);
|
||||
}
|
||||
|
||||
noreturn static pic_value
|
||||
native_exception_handler(pic_state *pic)
|
||||
{
|
||||
pic_value err;
|
||||
struct pic_proc *cont;
|
||||
|
||||
pic_get_args(pic, "o", &err);
|
||||
|
||||
pic->err = err;
|
||||
|
||||
cont = pic_proc_ptr(pic_attr_ref(pic, pic_obj_value(pic_get_proc(pic)), "@@escape"));
|
||||
|
||||
pic_apply1(pic, cont, pic_false_value());
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void
|
||||
pic_push_try(pic_state *pic, struct pic_escape *escape)
|
||||
{
|
||||
struct pic_proc *cont, *handler;
|
||||
size_t xp_len;
|
||||
ptrdiff_t xp_offset;
|
||||
|
||||
cont = pic_make_econt(pic, escape);
|
||||
|
||||
handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)");
|
||||
|
||||
pic_attr_set(pic, pic_obj_value(handler), "@@escape", pic_obj_value(cont));
|
||||
|
||||
if (pic->xp >= pic->xpend) {
|
||||
xp_len = (size_t)(pic->xpend - pic->xpbase) * 2;
|
||||
xp_offset = pic->xp - pic->xpbase;
|
||||
pic->xpbase = pic_realloc(pic, pic->xpbase, sizeof(struct pic_proc *) * xp_len);
|
||||
pic->xp = pic->xpbase + xp_offset;
|
||||
pic->xpend = pic->xpbase + xp_len;
|
||||
}
|
||||
|
||||
*pic->xp++ = handler;
|
||||
}
|
||||
|
||||
void
|
||||
pic_pop_try(pic_state *pic)
|
||||
{
|
||||
pic_value cont, escape;
|
||||
|
||||
assert(pic->xp > pic->xpbase);
|
||||
|
||||
cont = pic_attr_ref(pic, pic_obj_value(*--pic->xp), "@@escape");
|
||||
|
||||
assert(pic_proc_p(cont));
|
||||
|
||||
escape = pic_attr_ref(pic, cont, "@@escape");
|
||||
|
||||
assert(pic_data_p(escape));
|
||||
|
||||
((struct pic_escape *)pic_data_ptr(escape)->data)->valid = false;
|
||||
}
|
||||
|
||||
struct pic_error *
|
||||
pic_make_error(pic_state *pic, pic_sym type, const char *msg, pic_value irrs)
|
||||
{
|
||||
struct pic_error *e;
|
||||
pic_str *stack;
|
||||
|
||||
stack = pic_get_backtrace(pic);
|
||||
|
||||
e = (struct pic_error *)pic_obj_alloc(pic, sizeof(struct pic_error), PIC_TT_ERROR);
|
||||
e->type = type;
|
||||
e->msg = pic_make_str_cstr(pic, msg);
|
||||
e->irrs = irrs;
|
||||
e->stack = stack;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_raise_continuable(pic_state *pic, pic_value err)
|
||||
{
|
||||
struct pic_proc *handler;
|
||||
pic_value v;
|
||||
|
||||
if (pic->xp == pic->xpbase) {
|
||||
pic_panic(pic, "no exception handler registered");
|
||||
}
|
||||
|
||||
handler = *--pic->xp;
|
||||
|
||||
pic_gc_protect(pic, pic_obj_value(handler));
|
||||
|
||||
v = pic_apply1(pic, handler, err);
|
||||
|
||||
*pic->xp++ = handler;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
noreturn void
|
||||
pic_raise(pic_state *pic, pic_value err)
|
||||
{
|
||||
pic_value val;
|
||||
|
||||
val = pic_raise_continuable(pic, err);
|
||||
|
||||
pic_pop_try(pic);
|
||||
|
||||
pic_errorf(pic, "error handler returned with ~s on error ~s", val, err);
|
||||
}
|
||||
|
||||
noreturn void
|
||||
pic_throw(pic_state *pic, pic_sym type, const char *msg, pic_value irrs)
|
||||
{
|
||||
struct pic_error *e;
|
||||
|
||||
e = pic_make_error(pic, type, msg, irrs);
|
||||
|
||||
pic_raise(pic, pic_obj_value(e));
|
||||
}
|
||||
|
||||
noreturn void
|
||||
pic_error(pic_state *pic, const char *msg, pic_value irrs)
|
||||
{
|
||||
pic_throw(pic, pic_intern_cstr(pic, ""), msg, irrs);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_with_exception_handler(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *handler, *thunk;
|
||||
pic_value val;
|
||||
size_t xp_len;
|
||||
ptrdiff_t xp_offset;
|
||||
|
||||
pic_get_args(pic, "ll", &handler, &thunk);
|
||||
|
||||
if (pic->xp >= pic->xpend) {
|
||||
xp_len = (size_t)(pic->xpend - pic->xpbase) * 2;
|
||||
xp_offset = pic->xp - pic->xpbase;
|
||||
pic->xpbase = pic_realloc(pic, pic->xpbase, sizeof(struct pic_proc *) * xp_len);
|
||||
pic->xp = pic->xpbase + xp_offset;
|
||||
pic->xpend = pic->xpbase + xp_len;
|
||||
}
|
||||
|
||||
*pic->xp++ = handler;
|
||||
|
||||
val = pic_apply0(pic, thunk);
|
||||
|
||||
--pic->xp;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
noreturn static pic_value
|
||||
pic_error_raise(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
pic_raise(pic, v);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_raise_continuable(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_raise_continuable(pic, v);
|
||||
}
|
||||
|
||||
noreturn static pic_value
|
||||
pic_error_error(pic_state *pic)
|
||||
{
|
||||
const char *str;
|
||||
size_t argc;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "z*", &str, &argc, &argv);
|
||||
|
||||
pic_error(pic, str, pic_list_by_array(pic, argc, argv));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_make_error_object(pic_state *pic)
|
||||
{
|
||||
struct pic_error *e;
|
||||
pic_sym type;
|
||||
pic_str *msg;
|
||||
size_t argc;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "ms*", &type, &msg, &argc, &argv);
|
||||
|
||||
e = pic_make_error(pic, type, pic_str_cstr(msg), pic_list_by_array(pic, argc, argv));
|
||||
|
||||
return pic_obj_value(e);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_error_object_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_error_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_error_object_message(pic_state *pic)
|
||||
{
|
||||
struct pic_error *e;
|
||||
|
||||
pic_get_args(pic, "e", &e);
|
||||
|
||||
return pic_obj_value(e->msg);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_error_object_irritants(pic_state *pic)
|
||||
{
|
||||
struct pic_error *e;
|
||||
|
||||
pic_get_args(pic, "e", &e);
|
||||
|
||||
return e->irrs;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_error_error_object_type(pic_state *pic)
|
||||
{
|
||||
struct pic_error *e;
|
||||
|
||||
pic_get_args(pic, "e", &e);
|
||||
|
||||
return pic_sym_value(e->type);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_error(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "with-exception-handler", pic_error_with_exception_handler);
|
||||
pic_defun(pic, "raise", pic_error_raise);
|
||||
pic_defun(pic, "raise-continuable", pic_error_raise_continuable);
|
||||
pic_defun(pic, "error", pic_error_error);
|
||||
pic_defun(pic, "make-error-object", pic_error_make_error_object);
|
||||
pic_defun(pic, "error-object?", pic_error_error_object_p);
|
||||
pic_defun(pic, "error-object-message", pic_error_error_object_message);
|
||||
pic_defun(pic, "error-object-irritants", pic_error_error_object_irritants);
|
||||
pic_defun(pic, "error-object-type", pic_error_error_object_type);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/macro.h"
|
||||
|
||||
pic_value
|
||||
pic_eval(pic_state *pic, pic_value program, struct pic_lib *lib)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
|
||||
proc = pic_compile(pic, program, lib);
|
||||
|
||||
return pic_apply(pic, proc, pic_nil_value());
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_eval_eval(pic_state *pic)
|
||||
{
|
||||
pic_value program, spec;
|
||||
struct pic_lib *lib;
|
||||
|
||||
pic_get_args(pic, "oo", &program, &spec);
|
||||
|
||||
lib = pic_find_library(pic, spec);
|
||||
if (lib == NULL) {
|
||||
pic_errorf(pic, "no library found: ~s", spec);
|
||||
}
|
||||
return pic_eval(pic, program, lib);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_eval(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "eval", pic_eval_eval);
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/error.h"
|
||||
|
||||
static noreturn void
|
||||
file_error(pic_state *pic, const char *msg)
|
||||
{
|
||||
pic_throw(pic, pic->sFILE, msg, pic_nil_value());
|
||||
}
|
||||
|
||||
static pic_value
|
||||
generic_open_file(pic_state *pic, const char *fname, char *mode, short flags)
|
||||
{
|
||||
struct pic_port *port;
|
||||
xFILE *file;
|
||||
|
||||
file = xfopen(fname, mode);
|
||||
if (! file) {
|
||||
file_error(pic, "could not open file");
|
||||
}
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port), PIC_TT_PORT);
|
||||
port->file = file;
|
||||
port->flags = flags;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
|
||||
return pic_obj_value(port);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_file_open_input_file(pic_state *pic)
|
||||
{
|
||||
static const short flags = PIC_PORT_IN | PIC_PORT_TEXT;
|
||||
char *fname;
|
||||
|
||||
pic_get_args(pic, "z", &fname);
|
||||
|
||||
return generic_open_file(pic, fname, "r", flags);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_file_open_binary_input_file(pic_state *pic)
|
||||
{
|
||||
static const short flags = PIC_PORT_IN | PIC_PORT_BINARY;
|
||||
char *fname;
|
||||
|
||||
pic_get_args(pic, "z", &fname);
|
||||
|
||||
return generic_open_file(pic, fname, "rb", flags);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_file_open_output_file(pic_state *pic)
|
||||
{
|
||||
static const short flags = PIC_PORT_OUT | PIC_PORT_TEXT;
|
||||
char *fname;
|
||||
|
||||
pic_get_args(pic, "z", &fname);
|
||||
|
||||
return generic_open_file(pic, fname, "w", flags);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_file_open_binary_output_file(pic_state *pic)
|
||||
{
|
||||
static const short flags = PIC_PORT_OUT | PIC_PORT_BINARY;
|
||||
char *fname;
|
||||
|
||||
pic_get_args(pic, "z", &fname);
|
||||
|
||||
return generic_open_file(pic, fname, "wb", flags);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_file_exists_p(pic_state *pic)
|
||||
{
|
||||
char *fname;
|
||||
FILE *fp;
|
||||
|
||||
pic_get_args(pic, "z", &fname);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
return pic_true_value();
|
||||
} else {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_file_delete(pic_state *pic)
|
||||
{
|
||||
char *fname;
|
||||
|
||||
pic_get_args(pic, "z", &fname);
|
||||
|
||||
if (remove(fname) != 0) {
|
||||
file_error(pic, "file cannot be deleted");
|
||||
}
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_file(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "open-input-file", pic_file_open_input_file);
|
||||
pic_defun(pic, "open-binary-input-file", pic_file_open_binary_input_file);
|
||||
pic_defun(pic, "open-output-file", pic_file_open_output_file);
|
||||
pic_defun(pic, "open-binary-output-file", pic_file_open_binary_output_file);
|
||||
pic_defun(pic, "file-exists?", pic_file_exists_p);
|
||||
pic_defun(pic, "delete-file", pic_file_delete);
|
||||
}
|
||||
|
|
@ -0,0 +1,853 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/gc.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/vector.h"
|
||||
#include "picrin/irep.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/blob.h"
|
||||
#include "picrin/cont.h"
|
||||
#include "picrin/error.h"
|
||||
#include "picrin/macro.h"
|
||||
#include "picrin/lib.h"
|
||||
#include "picrin/data.h"
|
||||
#include "picrin/dict.h"
|
||||
#include "picrin/record.h"
|
||||
#include "picrin/read.h"
|
||||
|
||||
#if GC_DEBUG
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
union header {
|
||||
struct {
|
||||
union header *ptr;
|
||||
size_t size;
|
||||
unsigned int mark : 1;
|
||||
} s;
|
||||
long alignment[4];
|
||||
};
|
||||
|
||||
struct heap_page {
|
||||
union header *basep, *endp;
|
||||
struct heap_page *next;
|
||||
};
|
||||
|
||||
struct pic_heap {
|
||||
union header base, *freep;
|
||||
struct heap_page *pages;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
heap_init(struct pic_heap *heap)
|
||||
{
|
||||
heap->base.s.ptr = &heap->base;
|
||||
heap->base.s.size = 0; /* not 1, since it must never be used for allocation */
|
||||
heap->base.s.mark = PIC_GC_UNMARK;
|
||||
|
||||
heap->freep = &heap->base;
|
||||
heap->pages = NULL;
|
||||
|
||||
#if GC_DEBUG
|
||||
printf("freep = %p\n", (void *)heap->freep);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct pic_heap *
|
||||
pic_heap_open()
|
||||
{
|
||||
struct pic_heap *heap;
|
||||
|
||||
heap = (struct pic_heap *)calloc(1, sizeof(struct pic_heap));
|
||||
heap_init(heap);
|
||||
return heap;
|
||||
}
|
||||
|
||||
void
|
||||
pic_heap_close(struct pic_heap *heap)
|
||||
{
|
||||
struct heap_page *page;
|
||||
|
||||
while (heap->pages) {
|
||||
page = heap->pages;
|
||||
heap->pages = heap->pages->next;
|
||||
free(page);
|
||||
}
|
||||
}
|
||||
|
||||
static void gc_free(pic_state *, union header *);
|
||||
|
||||
static void
|
||||
add_heap_page(pic_state *pic)
|
||||
{
|
||||
union header *up, *np;
|
||||
struct heap_page *page;
|
||||
size_t nu;
|
||||
|
||||
#if GC_DEBUG
|
||||
puts("adding heap page!");
|
||||
#endif
|
||||
|
||||
nu = (PIC_HEAP_PAGE_SIZE + sizeof(union header) - 1) / sizeof(union header) + 1;
|
||||
|
||||
up = (union header *)pic_calloc(pic, 1 + nu + 1, sizeof(union header));
|
||||
up->s.size = nu + 1;
|
||||
up->s.mark = PIC_GC_UNMARK;
|
||||
gc_free(pic, up);
|
||||
|
||||
np = up + 1;
|
||||
np->s.size = nu;
|
||||
np->s.ptr = up->s.ptr;
|
||||
up->s.size = 1;
|
||||
up->s.ptr = np;
|
||||
|
||||
page = (struct heap_page *)pic_alloc(pic, sizeof(struct heap_page));
|
||||
page->basep = up;
|
||||
page->endp = up + nu + 1;
|
||||
page->next = pic->heap->pages;
|
||||
|
||||
pic->heap->pages = page;
|
||||
}
|
||||
|
||||
static void *
|
||||
alloc(void *ptr, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (ptr) {
|
||||
return realloc(ptr, size);
|
||||
} else {
|
||||
return malloc(size);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
pic_alloc(pic_state *pic, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = alloc(NULL, size);
|
||||
if (ptr == NULL && size > 0) {
|
||||
pic_panic(pic, "memory exhausted");
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
pic_realloc(pic_state *pic, void *ptr, size_t size)
|
||||
{
|
||||
ptr = alloc(ptr, size);
|
||||
if (ptr == NULL && size > 0) {
|
||||
pic_panic(pic, "memory exhausted");
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
pic_calloc(pic_state *pic, size_t count, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
size *= count;
|
||||
ptr = alloc(NULL, size);
|
||||
if (ptr == NULL && size > 0) {
|
||||
pic_panic(pic, "memory exhausted");
|
||||
}
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void
|
||||
pic_free(pic_state *pic, void *ptr)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
gc_protect(pic_state *pic, struct pic_object *obj)
|
||||
{
|
||||
if (pic->arena_idx >= pic->arena_size) {
|
||||
pic->arena_size = pic->arena_size * 2 + 1;
|
||||
pic->arena = pic_realloc(pic, pic->arena, sizeof(struct pic_object *) * pic->arena_size);
|
||||
}
|
||||
pic->arena[pic->arena_idx++] = obj;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_gc_protect(pic_state *pic, pic_value v)
|
||||
{
|
||||
struct pic_object *obj;
|
||||
|
||||
if (pic_vtype(v) != PIC_VTYPE_HEAP) {
|
||||
return v;
|
||||
}
|
||||
obj = pic_obj_ptr(v);
|
||||
|
||||
gc_protect(pic, obj);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t
|
||||
pic_gc_arena_preserve(pic_state *pic)
|
||||
{
|
||||
return pic->arena_idx;
|
||||
}
|
||||
|
||||
void
|
||||
pic_gc_arena_restore(pic_state *pic, size_t state)
|
||||
{
|
||||
pic->arena_idx = state;
|
||||
}
|
||||
|
||||
static void *
|
||||
gc_alloc(pic_state *pic, size_t size)
|
||||
{
|
||||
union header *freep, *p, *prevp;
|
||||
size_t nunits;
|
||||
|
||||
#if GC_DEBUG
|
||||
assert(size > 0);
|
||||
#endif
|
||||
|
||||
nunits = (size + sizeof(union header) - 1) / sizeof(union header) + 1;
|
||||
|
||||
prevp = freep = pic->heap->freep;
|
||||
for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr) {
|
||||
if (p->s.size >= nunits)
|
||||
break;
|
||||
if (p == freep) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if GC_DEBUG
|
||||
{
|
||||
unsigned char *c;
|
||||
size_t s, i, j;
|
||||
if (p->s.size == nunits) {
|
||||
c = (unsigned char *)(p + p->s.size - nunits + 1);
|
||||
s = nunits - 1;
|
||||
} else {
|
||||
c = (unsigned char *)(p + p->s.size - nunits);
|
||||
s = nunits;
|
||||
}
|
||||
|
||||
for (i = 0; i < s; ++i) {
|
||||
for (j = 0; j < sizeof(union header); ++j) {
|
||||
assert(c[i * sizeof(union header) + j] == 0xAA);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p->s.size == nunits) {
|
||||
prevp->s.ptr = p->s.ptr;
|
||||
}
|
||||
else {
|
||||
p->s.size -= nunits;
|
||||
p += p->s.size;
|
||||
p->s.size = nunits;
|
||||
}
|
||||
pic->heap->freep = prevp;
|
||||
|
||||
p->s.mark = PIC_GC_UNMARK;
|
||||
|
||||
#if GC_DEBUG
|
||||
memset(p+1, 0, sizeof(union header) * (nunits - 1));
|
||||
p->s.ptr = (union header *)0xcafebabe;
|
||||
#endif
|
||||
|
||||
return (void *)(p + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
gc_free(pic_state *pic, union header *bp)
|
||||
{
|
||||
union header *freep, *p;
|
||||
|
||||
#if GC_DEBUG
|
||||
assert(bp != NULL);
|
||||
assert(bp->s.size > 1);
|
||||
#endif
|
||||
|
||||
#if GC_DEBUG
|
||||
memset(bp + 1, 0xAA, (bp->s.size - 1) * sizeof(union header));
|
||||
#endif
|
||||
|
||||
freep = pic->heap->freep;
|
||||
for (p = freep; ! (bp > p && bp < p->s.ptr); p = p->s.ptr) {
|
||||
if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bp + bp->s.size == p->s.ptr) {
|
||||
bp->s.size += p->s.ptr->s.size;
|
||||
bp->s.ptr = p->s.ptr->s.ptr;
|
||||
|
||||
#if GC_DEBUG
|
||||
memset(p->s.ptr, 0xAA, sizeof(union header));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
bp->s.ptr = p->s.ptr;
|
||||
}
|
||||
if (p + p->s.size == bp && p->s.size > 1) {
|
||||
p->s.size += bp->s.size;
|
||||
p->s.ptr = bp->s.ptr;
|
||||
|
||||
#if GC_DEBUG
|
||||
memset(bp, 0xAA, sizeof(union header));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
p->s.ptr = bp;
|
||||
}
|
||||
pic->heap->freep = p;
|
||||
}
|
||||
|
||||
static void gc_mark(pic_state *, pic_value);
|
||||
static void gc_mark_object(pic_state *pic, struct pic_object *obj);
|
||||
|
||||
static bool
|
||||
gc_is_marked(union header *p)
|
||||
{
|
||||
return p->s.mark == PIC_GC_MARK;
|
||||
}
|
||||
|
||||
static bool
|
||||
gc_obj_is_marked(struct pic_object *obj)
|
||||
{
|
||||
union header *p;
|
||||
|
||||
p = ((union header *)obj) - 1;
|
||||
|
||||
return gc_is_marked(p);
|
||||
}
|
||||
|
||||
static void
|
||||
gc_unmark(union header *p)
|
||||
{
|
||||
p->s.mark = PIC_GC_UNMARK;
|
||||
}
|
||||
|
||||
static void
|
||||
gc_mark_winder(pic_state *pic, struct pic_winder *wind)
|
||||
{
|
||||
if (wind->prev) {
|
||||
gc_mark_object(pic, (struct pic_object *)wind->prev);
|
||||
}
|
||||
if (wind->in) {
|
||||
gc_mark_object(pic, (struct pic_object *)wind->in);
|
||||
}
|
||||
if (wind->out) {
|
||||
gc_mark_object(pic, (struct pic_object *)wind->out);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gc_mark_object(pic_state *pic, struct pic_object *obj)
|
||||
{
|
||||
union header *p;
|
||||
|
||||
p = ((union header *)obj) - 1;
|
||||
|
||||
if (gc_is_marked(p))
|
||||
return;
|
||||
p->s.mark = PIC_GC_MARK;
|
||||
|
||||
switch (obj->tt) {
|
||||
case PIC_TT_PAIR: {
|
||||
gc_mark(pic, ((struct pic_pair *)obj)->car);
|
||||
gc_mark(pic, ((struct pic_pair *)obj)->cdr);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_ENV: {
|
||||
struct pic_env *env = (struct pic_env *)obj;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < env->regc; ++i) {
|
||||
gc_mark(pic, env->regs[i]);
|
||||
}
|
||||
if (env->up) {
|
||||
gc_mark_object(pic, (struct pic_object *)env->up);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_PROC: {
|
||||
struct pic_proc *proc = (struct pic_proc *)obj;
|
||||
if (proc->env) {
|
||||
gc_mark_object(pic, (struct pic_object *)proc->env);
|
||||
}
|
||||
if (pic_proc_irep_p(proc)) {
|
||||
gc_mark_object(pic, (struct pic_object *)proc->u.irep);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_PORT: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_ERROR: {
|
||||
struct pic_error *err = (struct pic_error *)obj;
|
||||
gc_mark_object(pic,(struct pic_object *)err->msg);
|
||||
gc_mark(pic, err->irrs);
|
||||
gc_mark_object(pic, (struct pic_object *)err->stack);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_STRING: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_VECTOR: {
|
||||
size_t i;
|
||||
for (i = 0; i < ((struct pic_vector *)obj)->len; ++i) {
|
||||
gc_mark(pic, ((struct pic_vector *)obj)->data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_BLOB: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_MACRO: {
|
||||
struct pic_macro *mac = (struct pic_macro *)obj;
|
||||
|
||||
if (mac->proc) {
|
||||
gc_mark_object(pic, (struct pic_object *)mac->proc);
|
||||
}
|
||||
if (mac->senv) {
|
||||
gc_mark_object(pic, (struct pic_object *)mac->senv);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_SENV: {
|
||||
struct pic_senv *senv = (struct pic_senv *)obj;
|
||||
|
||||
if (senv->up) {
|
||||
gc_mark_object(pic, (struct pic_object *)senv->up);
|
||||
}
|
||||
gc_mark(pic, senv->defer);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_LIB: {
|
||||
struct pic_lib *lib = (struct pic_lib *)obj;
|
||||
gc_mark(pic, lib->name);
|
||||
gc_mark_object(pic, (struct pic_object *)lib->env);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_IREP: {
|
||||
struct pic_irep *irep = (struct pic_irep *)obj;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < irep->ilen; ++i) {
|
||||
gc_mark_object(pic, (struct pic_object *)irep->irep[i]);
|
||||
}
|
||||
for (i = 0; i < irep->plen; ++i) {
|
||||
gc_mark(pic, irep->pool[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_DATA: {
|
||||
struct pic_data *data = (struct pic_data *)obj;
|
||||
xh_entry *it;
|
||||
|
||||
for (it = xh_begin(&data->storage); it != NULL; it = xh_next(it)) {
|
||||
gc_mark(pic, xh_val(it, pic_value));
|
||||
}
|
||||
if (data->type->mark) {
|
||||
data->type->mark(pic, data->data, gc_mark);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_DICT: {
|
||||
struct pic_dict *dict = (struct pic_dict *)obj;
|
||||
xh_entry *it;
|
||||
|
||||
for (it = xh_begin(&dict->hash); it != NULL; it = xh_next(it)) {
|
||||
gc_mark(pic, xh_key(it, pic_value));
|
||||
gc_mark(pic, xh_val(it, pic_value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_RECORD: {
|
||||
struct pic_record *rec = (struct pic_record *)obj;
|
||||
xh_entry *it;
|
||||
|
||||
for (it = xh_begin(&rec->hash); it != NULL; it = xh_next(it)) {
|
||||
gc_mark(pic, xh_val(it, pic_value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PIC_TT_NIL:
|
||||
case PIC_TT_BOOL:
|
||||
case PIC_TT_FLOAT:
|
||||
case PIC_TT_INT:
|
||||
case PIC_TT_SYMBOL:
|
||||
case PIC_TT_CHAR:
|
||||
case PIC_TT_EOF:
|
||||
case PIC_TT_UNDEF:
|
||||
pic_panic(pic, "logic flaw");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gc_mark(pic_state *pic, pic_value v)
|
||||
{
|
||||
struct pic_object *obj;
|
||||
|
||||
if (pic_vtype(v) != PIC_VTYPE_HEAP)
|
||||
return;
|
||||
obj = pic_obj_ptr(v);
|
||||
|
||||
gc_mark_object(pic, obj);
|
||||
}
|
||||
|
||||
static void
|
||||
gc_mark_trie(pic_state *pic, struct pic_trie *trie)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof trie->table / sizeof(struct pic_trie *); ++i) {
|
||||
if (trie->table[i] != NULL) {
|
||||
gc_mark_trie(pic, trie->table[i]);
|
||||
}
|
||||
}
|
||||
if (trie->proc != NULL) {
|
||||
gc_mark_object(pic, (struct pic_object *)trie->proc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gc_mark_phase(pic_state *pic)
|
||||
{
|
||||
pic_value *stack;
|
||||
pic_callinfo *ci;
|
||||
struct pic_proc **xhandler;
|
||||
size_t j;
|
||||
xh_entry *it;
|
||||
struct pic_object *obj;
|
||||
|
||||
/* winder */
|
||||
if (pic->wind) {
|
||||
gc_mark_winder(pic, pic->wind);
|
||||
}
|
||||
|
||||
/* stack */
|
||||
for (stack = pic->stbase; stack != pic->sp; ++stack) {
|
||||
gc_mark(pic, *stack);
|
||||
}
|
||||
|
||||
/* callinfo */
|
||||
for (ci = pic->ci; ci != pic->cibase; --ci) {
|
||||
if (ci->env) {
|
||||
gc_mark_object(pic, (struct pic_object *)ci->env);
|
||||
}
|
||||
}
|
||||
|
||||
/* exception handlers */
|
||||
for (xhandler = pic->xpbase; xhandler != pic->xp; ++xhandler) {
|
||||
gc_mark_object(pic, (struct pic_object *)*xhandler);
|
||||
}
|
||||
|
||||
/* arena */
|
||||
for (j = 0; j < pic->arena_idx; ++j) {
|
||||
gc_mark_object(pic, pic->arena[j]);
|
||||
}
|
||||
|
||||
/* global variables */
|
||||
for (it = xh_begin(&pic->globals); it != NULL; it = xh_next(it)) {
|
||||
gc_mark(pic, xh_val(it, pic_value));
|
||||
}
|
||||
|
||||
/* macro objects */
|
||||
for (it = xh_begin(&pic->macros); it != NULL; it = xh_next(it)) {
|
||||
gc_mark_object(pic, xh_val(it, struct pic_object *));
|
||||
}
|
||||
|
||||
/* error object */
|
||||
gc_mark(pic, pic->err);
|
||||
|
||||
/* features */
|
||||
gc_mark(pic, pic->features);
|
||||
|
||||
/* readers */
|
||||
gc_mark_trie(pic, pic->reader->trie);
|
||||
|
||||
/* library table */
|
||||
gc_mark(pic, pic->libs);
|
||||
|
||||
/* standard I/O ports */
|
||||
if (pic->xSTDIN) {
|
||||
gc_mark_object(pic, (struct pic_object *)pic->xSTDIN);
|
||||
}
|
||||
if (pic->xSTDOUT) {
|
||||
gc_mark_object(pic, (struct pic_object *)pic->xSTDOUT);
|
||||
}
|
||||
if (pic->xSTDERR) {
|
||||
gc_mark_object(pic, (struct pic_object *)pic->xSTDERR);
|
||||
}
|
||||
|
||||
/* attributes */
|
||||
do {
|
||||
j = 0;
|
||||
|
||||
for (it = xh_begin(&pic->attrs); it != NULL; it = xh_next(it)) {
|
||||
if (gc_obj_is_marked(xh_key(it, struct pic_object *))) {
|
||||
obj = (struct pic_object *)xh_val(it, struct pic_dict *);
|
||||
if (! gc_obj_is_marked(obj)) {
|
||||
gc_mark_object(pic, obj);
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (j > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gc_finalize_object(pic_state *pic, struct pic_object *obj)
|
||||
{
|
||||
#if GC_DEBUG
|
||||
printf("* finalizing object: %s", pic_type_repr(pic_type(pic_obj_value(obj))));
|
||||
// pic_debug(pic, pic_obj_value(obj));
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
switch (obj->tt) {
|
||||
case PIC_TT_PAIR: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_ENV: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_PROC: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_VECTOR: {
|
||||
pic_free(pic, ((struct pic_vector *)obj)->data);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_BLOB: {
|
||||
pic_free(pic, ((struct pic_blob *)obj)->data);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_STRING: {
|
||||
XROPE_DECREF(((struct pic_string *)obj)->rope);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_PORT: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_ERROR: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_SENV: {
|
||||
struct pic_senv *senv = (struct pic_senv *)obj;
|
||||
xh_destroy(&senv->map);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_MACRO: {
|
||||
break;
|
||||
}
|
||||
case PIC_TT_LIB: {
|
||||
struct pic_lib *lib = (struct pic_lib *)obj;
|
||||
xh_destroy(&lib->exports);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_IREP: {
|
||||
struct pic_irep *irep = (struct pic_irep *)obj;
|
||||
pic_free(pic, irep->code);
|
||||
pic_free(pic, irep->irep);
|
||||
pic_free(pic, irep->pool);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_DATA: {
|
||||
struct pic_data *data = (struct pic_data *)obj;
|
||||
data->type->dtor(pic, data->data);
|
||||
xh_destroy(&data->storage);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_DICT: {
|
||||
struct pic_dict *dict = (struct pic_dict *)obj;
|
||||
xh_destroy(&dict->hash);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_RECORD: {
|
||||
struct pic_record *rec = (struct pic_record *)obj;
|
||||
xh_destroy(&rec->hash);
|
||||
break;
|
||||
}
|
||||
case PIC_TT_NIL:
|
||||
case PIC_TT_BOOL:
|
||||
case PIC_TT_FLOAT:
|
||||
case PIC_TT_INT:
|
||||
case PIC_TT_SYMBOL:
|
||||
case PIC_TT_CHAR:
|
||||
case PIC_TT_EOF:
|
||||
case PIC_TT_UNDEF:
|
||||
pic_panic(pic, "logic flaw");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gc_sweep_page(pic_state *pic, struct heap_page *page)
|
||||
{
|
||||
#if GC_DEBUG
|
||||
static union header *NIL = (union header *)0xdeadbeef;
|
||||
#else
|
||||
static union header *NIL = NULL;
|
||||
#endif
|
||||
union header *bp, *p, *s = NIL, *t = NIL;
|
||||
|
||||
#if GC_DEBUG
|
||||
int c = 0;
|
||||
#endif
|
||||
|
||||
for (bp = page->basep; ; bp = bp->s.ptr) {
|
||||
for (p = bp + bp->s.size; p != bp->s.ptr; p += p->s.size) {
|
||||
if (p == page->endp) {
|
||||
goto escape;
|
||||
}
|
||||
if (! gc_is_marked(p)) {
|
||||
if (s == NIL) {
|
||||
s = p;
|
||||
}
|
||||
else {
|
||||
t->s.ptr = p;
|
||||
}
|
||||
t = p;
|
||||
t->s.ptr = NIL; /* For dead objects we can safely reuse ptr field */
|
||||
}
|
||||
gc_unmark(p);
|
||||
}
|
||||
}
|
||||
escape:
|
||||
|
||||
/* free! */
|
||||
while (s != NIL) {
|
||||
t = s->s.ptr;
|
||||
gc_finalize_object(pic, (struct pic_object *)(s + 1));
|
||||
gc_free(pic, s);
|
||||
s = t;
|
||||
|
||||
#if GC_DEBUG
|
||||
c++;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if GC_DEBUG
|
||||
printf("freed objects count: %d\n", c);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
gc_sweep_phase(pic_state *pic)
|
||||
{
|
||||
struct heap_page *page = pic->heap->pages;
|
||||
xh_entry *it, *next;
|
||||
|
||||
do {
|
||||
for (it = xh_begin(&pic->attrs); it != NULL; it = next) {
|
||||
next = xh_next(it);
|
||||
if (! gc_obj_is_marked(xh_key(it, struct pic_object *))) {
|
||||
xh_del_ptr(&pic->attrs, xh_key(it, struct pic_object *));
|
||||
}
|
||||
}
|
||||
} while (it != NULL);
|
||||
|
||||
while (page) {
|
||||
gc_sweep_page(pic, page);
|
||||
page = page->next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pic_gc_run(pic_state *pic)
|
||||
{
|
||||
#if GC_DEBUG
|
||||
struct heap_page *page;
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
puts("gc run!");
|
||||
#endif
|
||||
|
||||
gc_mark_phase(pic);
|
||||
gc_sweep_phase(pic);
|
||||
|
||||
#if GC_DEBUG
|
||||
for (page = pic->heap->pages; page; page = page->next) {
|
||||
union header *bp, *p;
|
||||
unsigned char *c;
|
||||
|
||||
for (bp = page->basep; ; bp = bp->s.ptr) {
|
||||
for (c = (unsigned char *)(bp+1); c != (unsigned char *)(bp + bp->s.size); ++c) {
|
||||
assert(*c == 0xAA);
|
||||
}
|
||||
for (p = bp + bp->s.size; p != bp->s.ptr; p += p->s.size) {
|
||||
if (p == page->endp) {
|
||||
/* if (page->next) */
|
||||
/* assert(bp->s.ptr == page->next->basep); */
|
||||
/* else */
|
||||
/* assert(bp->s.ptr == &pic->heap->base); */
|
||||
goto escape;
|
||||
}
|
||||
assert(! gc_is_marked(p));
|
||||
}
|
||||
}
|
||||
escape:
|
||||
((void)0);
|
||||
}
|
||||
|
||||
puts("not error on heap found! gc successfully finished");
|
||||
#endif
|
||||
}
|
||||
|
||||
struct pic_object *
|
||||
pic_obj_alloc_unsafe(pic_state *pic, size_t size, enum pic_tt tt)
|
||||
{
|
||||
struct pic_object *obj;
|
||||
|
||||
#if GC_DEBUG
|
||||
printf("*allocating: %s\n", pic_type_repr(tt));
|
||||
#endif
|
||||
|
||||
#if GC_STRESS
|
||||
pic_gc_run(pic);
|
||||
#endif
|
||||
|
||||
obj = (struct pic_object *)gc_alloc(pic, size);
|
||||
if (obj == NULL) {
|
||||
pic_gc_run(pic);
|
||||
obj = (struct pic_object *)gc_alloc(pic, size);
|
||||
if (obj == NULL) {
|
||||
add_heap_page(pic);
|
||||
obj = (struct pic_object *)gc_alloc(pic, size);
|
||||
if (obj == NULL)
|
||||
pic_panic(pic, "GC memory exhausted");
|
||||
}
|
||||
}
|
||||
obj->tt = tt;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct pic_object *
|
||||
pic_obj_alloc(pic_state *pic, size_t size, enum pic_tt tt)
|
||||
{
|
||||
struct pic_object *obj;
|
||||
|
||||
obj = pic_obj_alloc_unsafe(pic, size, tt);
|
||||
|
||||
gc_protect(pic, obj);
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* Copyright (c) 2013-2014 Yuichi Nishiwaki and other picrin contributors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_H
|
||||
#define PICRIN_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "picrin/xvect.h"
|
||||
#include "picrin/xhash.h"
|
||||
#include "picrin/xfile.h"
|
||||
#include "picrin/xrope.h"
|
||||
|
||||
#include "picrin/config.h"
|
||||
#include "picrin/util.h"
|
||||
#include "picrin/value.h"
|
||||
|
||||
typedef struct pic_code pic_code;
|
||||
|
||||
struct pic_winder {
|
||||
struct pic_proc *in;
|
||||
struct pic_proc *out;
|
||||
int depth;
|
||||
struct pic_winder *prev;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int argc, retc;
|
||||
pic_code *ip;
|
||||
pic_value *fp;
|
||||
struct pic_env *env;
|
||||
int regc;
|
||||
pic_value *regs;
|
||||
struct pic_env *up;
|
||||
} pic_callinfo;
|
||||
|
||||
typedef struct {
|
||||
int argc;
|
||||
char **argv, **envp;
|
||||
|
||||
struct pic_winder *wind;
|
||||
|
||||
pic_value *sp;
|
||||
pic_value *stbase, *stend;
|
||||
|
||||
pic_callinfo *ci;
|
||||
pic_callinfo *cibase, *ciend;
|
||||
|
||||
struct pic_proc **xp;
|
||||
struct pic_proc **xpbase, **xpend;
|
||||
|
||||
pic_code *ip;
|
||||
|
||||
struct pic_lib *lib;
|
||||
|
||||
pic_sym sDEFINE, sLAMBDA, sIF, sBEGIN, sQUOTE, sSETBANG;
|
||||
pic_sym sQUASIQUOTE, sUNQUOTE, sUNQUOTE_SPLICING;
|
||||
pic_sym sDEFINE_SYNTAX, sIMPORT, sEXPORT;
|
||||
pic_sym sDEFINE_LIBRARY, sIN_LIBRARY;
|
||||
pic_sym sCOND_EXPAND, sAND, sOR, sELSE, sLIBRARY;
|
||||
pic_sym sONLY, sRENAME, sPREFIX, sEXCEPT;
|
||||
pic_sym sCONS, sCAR, sCDR, sNILP;
|
||||
pic_sym sADD, sSUB, sMUL, sDIV, sMINUS;
|
||||
pic_sym sEQ, sLT, sLE, sGT, sGE, sNOT;
|
||||
pic_sym sREAD, sFILE;
|
||||
|
||||
pic_sym rDEFINE, rLAMBDA, rIF, rBEGIN, rQUOTE, rSETBANG;
|
||||
pic_sym rDEFINE_SYNTAX, rIMPORT, rEXPORT;
|
||||
pic_sym rDEFINE_LIBRARY, rIN_LIBRARY;
|
||||
pic_sym rCOND_EXPAND;
|
||||
|
||||
struct pic_lib *PICRIN_BASE;
|
||||
struct pic_lib *PICRIN_USER;
|
||||
|
||||
pic_value features;
|
||||
|
||||
xhash syms; /* name to symbol */
|
||||
xhash sym_names; /* symbol to name */
|
||||
int sym_cnt;
|
||||
int uniq_sym_cnt;
|
||||
|
||||
xhash globals;
|
||||
xhash macros;
|
||||
pic_value libs;
|
||||
xhash attrs;
|
||||
|
||||
struct pic_reader *reader;
|
||||
|
||||
struct pic_heap *heap;
|
||||
struct pic_object **arena;
|
||||
size_t arena_size, arena_idx;
|
||||
|
||||
struct pic_port *xSTDIN, *xSTDOUT, *xSTDERR;
|
||||
|
||||
pic_value err;
|
||||
|
||||
char *native_stack_start;
|
||||
} pic_state;
|
||||
|
||||
typedef pic_value (*pic_func_t)(pic_state *);
|
||||
|
||||
void *pic_alloc(pic_state *, size_t);
|
||||
#define pic_malloc(pic,size) pic_alloc(pic,size) /* obsoleted */
|
||||
void *pic_realloc(pic_state *, void *, size_t);
|
||||
void *pic_calloc(pic_state *, size_t, size_t);
|
||||
struct pic_object *pic_obj_alloc(pic_state *, size_t, enum pic_tt);
|
||||
struct pic_object *pic_obj_alloc_unsafe(pic_state *, size_t, enum pic_tt);
|
||||
void pic_free(pic_state *, void *);
|
||||
|
||||
void pic_gc_run(pic_state *);
|
||||
pic_value pic_gc_protect(pic_state *, pic_value);
|
||||
size_t pic_gc_arena_preserve(pic_state *);
|
||||
void pic_gc_arena_restore(pic_state *, size_t);
|
||||
#define pic_void(exec) \
|
||||
pic_void_(GENSYM(ai), exec)
|
||||
#define pic_void_(ai,exec) do { \
|
||||
size_t ai = pic_gc_arena_preserve(pic); \
|
||||
exec; \
|
||||
pic_gc_arena_restore(pic, ai); \
|
||||
} while (0)
|
||||
|
||||
pic_state *pic_open(int argc, char *argv[], char **envp);
|
||||
void pic_close(pic_state *);
|
||||
|
||||
void pic_add_feature(pic_state *, const char *);
|
||||
|
||||
void pic_define(pic_state *, const char *, pic_value);
|
||||
void pic_define_noexport(pic_state *, const char *, pic_value);
|
||||
void pic_defun(pic_state *, const char *, pic_func_t);
|
||||
|
||||
struct pic_proc *pic_make_var(pic_state *, pic_value, struct pic_proc *);
|
||||
void pic_defvar(pic_state *, const char *, pic_value, struct pic_proc *);
|
||||
|
||||
struct pic_proc *pic_get_proc(pic_state *);
|
||||
int pic_get_args(pic_state *, const char *, ...);
|
||||
|
||||
bool pic_eq_p(pic_value, pic_value);
|
||||
bool pic_eqv_p(pic_value, pic_value);
|
||||
bool pic_equal_p(pic_state *, pic_value, pic_value);
|
||||
|
||||
pic_sym pic_intern(pic_state *, const char *, size_t);
|
||||
pic_sym pic_intern_str(pic_state *, pic_str *);
|
||||
pic_sym pic_intern_cstr(pic_state *, const char *);
|
||||
const char *pic_symbol_name(pic_state *, pic_sym);
|
||||
pic_sym pic_gensym(pic_state *, pic_sym);
|
||||
pic_sym pic_ungensym(pic_state *, pic_sym);
|
||||
bool pic_interned_p(pic_state *, pic_sym);
|
||||
|
||||
pic_value pic_read(pic_state *, struct pic_port *);
|
||||
pic_value pic_read_cstr(pic_state *, const char *);
|
||||
|
||||
void pic_load(pic_state *, const char *);
|
||||
void pic_load_cstr(pic_state *, const char *);
|
||||
|
||||
pic_value pic_funcall(pic_state *pic, struct pic_lib *, const char *, pic_list);
|
||||
pic_value pic_ref(pic_state *, struct pic_lib *, const char *);
|
||||
void pic_set(pic_state *, struct pic_lib *, const char *, pic_value);
|
||||
|
||||
pic_value pic_apply(pic_state *, struct pic_proc *, pic_value);
|
||||
pic_value pic_apply0(pic_state *, struct pic_proc *);
|
||||
pic_value pic_apply1(pic_state *, struct pic_proc *, pic_value);
|
||||
pic_value pic_apply2(pic_state *, struct pic_proc *, pic_value, pic_value);
|
||||
pic_value pic_apply3(pic_state *, struct pic_proc *, pic_value, pic_value, pic_value);
|
||||
pic_value pic_apply4(pic_state *, struct pic_proc *, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_apply5(pic_state *, struct pic_proc *, pic_value, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_apply_trampoline(pic_state *, struct pic_proc *, pic_value);
|
||||
pic_value pic_eval(pic_state *, pic_value, struct pic_lib *);
|
||||
struct pic_proc *pic_compile(pic_state *, pic_value, struct pic_lib *);
|
||||
pic_value pic_macroexpand(pic_state *, pic_value, struct pic_lib *);
|
||||
|
||||
void pic_in_library(pic_state *, pic_value);
|
||||
struct pic_lib *pic_open_library(pic_state *, pic_value);
|
||||
struct pic_lib *pic_find_library(pic_state *, pic_value);
|
||||
|
||||
#define pic_deflibrary(pic, spec) \
|
||||
pic_deflibrary_helper_(pic, GENSYM(i), GENSYM(prev_lib), spec)
|
||||
#define pic_deflibrary_helper_(pic, i, prev_lib, spec) \
|
||||
for (int i = 0; ! i; ) \
|
||||
for (struct pic_lib *prev_lib; ! i; ) \
|
||||
for ((prev_lib = pic->lib), pic_open_library(pic, pic_read_cstr(pic, spec)), pic_in_library(pic, pic_read_cstr(pic, spec)); ! i++; pic->lib = prev_lib)
|
||||
|
||||
void pic_import(pic_state *, pic_value);
|
||||
void pic_import_library(pic_state *, struct pic_lib *);
|
||||
void pic_export(pic_state *, pic_sym);
|
||||
|
||||
noreturn void pic_panic(pic_state *, const char *);
|
||||
noreturn void pic_errorf(pic_state *, const char *, ...);
|
||||
void pic_warnf(pic_state *, const char *, ...);
|
||||
const char *pic_errmsg(pic_state *);
|
||||
pic_str *pic_get_backtrace(pic_state *);
|
||||
void pic_print_backtrace(pic_state *);
|
||||
|
||||
/* obsoleted */
|
||||
static inline void pic_warn(pic_state *pic, const char *msg)
|
||||
{
|
||||
pic_warnf(pic, msg);
|
||||
}
|
||||
|
||||
struct pic_dict *pic_attr(pic_state *, pic_value);
|
||||
pic_value pic_attr_ref(pic_state *, pic_value, const char *);
|
||||
void pic_attr_set(pic_state *, pic_value, const char *, pic_value);
|
||||
|
||||
struct pic_port *pic_stdin(pic_state *);
|
||||
struct pic_port *pic_stdout(pic_state *);
|
||||
struct pic_port *pic_stderr(pic_state *);
|
||||
|
||||
pic_value pic_write(pic_state *, pic_value); /* returns given obj */
|
||||
pic_value pic_fwrite(pic_state *, pic_value, xFILE *);
|
||||
void pic_printf(pic_state *, const char *, ...);
|
||||
pic_value pic_display(pic_state *, pic_value);
|
||||
pic_value pic_fdisplay(pic_state *, pic_value, xFILE *);
|
||||
/* obsoleted macros */
|
||||
#define pic_debug(pic,obj) pic_write(pic,obj)
|
||||
#define pic_fdebug(pic,obj,file) pic_fwrite(pic,obj,file)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_BLOB_H
|
||||
#define PICRIN_BLOB_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_blob {
|
||||
PIC_OBJECT_HEADER
|
||||
unsigned char *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
#define pic_blob_p(v) (pic_type(v) == PIC_TT_BLOB)
|
||||
#define pic_blob_ptr(v) ((struct pic_blob *)pic_ptr(v))
|
||||
|
||||
struct pic_blob *pic_make_blob(pic_state *, size_t);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
/** switch normal VM and direct threaded VM */
|
||||
/* #define PIC_DIRECT_THREADED_VM 1 */
|
||||
|
||||
/** switch internal value representation */
|
||||
/* #define PIC_NAN_BOXING 1 */
|
||||
|
||||
/** treat false value as none */
|
||||
/* #define PIC_NONE_IS_FALSE 1 */
|
||||
|
||||
/** initial memory size (to be dynamically extended if necessary) */
|
||||
/* #define PIC_ARENA_SIZE 1000 */
|
||||
|
||||
/* #define PIC_HEAP_PAGE_SIZE 10000 */
|
||||
|
||||
/* #define PIC_STACK_SIZE 1024 */
|
||||
|
||||
/* #define PIC_RESCUE_SIZE 30 */
|
||||
|
||||
/* #define PIC_SYM_POOL_SIZE 128 */
|
||||
|
||||
/* #define PIC_IREP_SIZE 8 */
|
||||
|
||||
/* #define PIC_POOL_SIZE 8 */
|
||||
|
||||
/* #define PIC_ISEQ_SIZE 1024 */
|
||||
|
||||
/** enable all debug flags */
|
||||
/* #define DEBUG 1 */
|
||||
|
||||
/** auxiliary debug flags */
|
||||
/* #define GC_STRESS 1 */
|
||||
/* #define VM_DEBUG 1 */
|
||||
/* #define GC_DEBUG 1 */
|
||||
/* #define GC_DEBUG_DETAIL 1 */
|
||||
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
# error please activate c99 features
|
||||
#endif
|
||||
|
||||
#ifndef PIC_DIRECT_THREADED_VM
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define PIC_DIRECT_THREADED_VM 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PIC_NAN_BOXING
|
||||
# if __x86_64__ && __STDC_VERSION__ >= 201112L
|
||||
# define PIC_NAN_BOXING 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PIC_NONE_IS_FALSE
|
||||
# define PIC_NONE_IS_FALSE 1
|
||||
#endif
|
||||
|
||||
#ifndef PIC_ARENA_SIZE
|
||||
# define PIC_ARENA_SIZE 1000
|
||||
#endif
|
||||
|
||||
#ifndef PIC_HEAP_PAGE_SIZE
|
||||
# define PIC_HEAP_PAGE_SIZE 10000
|
||||
#endif
|
||||
|
||||
#ifndef PIC_STACK_SIZE
|
||||
# define PIC_STACK_SIZE 1024
|
||||
#endif
|
||||
|
||||
#ifndef PIC_RESCUE_SIZE
|
||||
# define PIC_RESCUE_SIZE 30
|
||||
#endif
|
||||
|
||||
#ifndef PIC_SYM_POOL_SIZE
|
||||
# define PIC_SYM_POOL_SIZE 128
|
||||
#endif
|
||||
|
||||
#ifndef PIC_IREP_SIZE
|
||||
# define PIC_IREP_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef PIC_POOL_SIZE
|
||||
# define PIC_POOL_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef PIC_ISEQ_SIZE
|
||||
# define PIC_ISEQ_SIZE 1024
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
# define GC_STRESS 0
|
||||
# define VM_DEBUG 1
|
||||
# define GC_DEBUG 0
|
||||
# define GC_DEBUG_DETAIL 0
|
||||
#endif
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_CONT_H
|
||||
#define PICRIN_CONT_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_escape {
|
||||
jmp_buf jmp;
|
||||
|
||||
bool valid;
|
||||
|
||||
struct pic_winder *wind;
|
||||
|
||||
ptrdiff_t sp_offset;
|
||||
ptrdiff_t ci_offset;
|
||||
ptrdiff_t xp_offset;
|
||||
size_t arena_idx;
|
||||
|
||||
pic_code *ip;
|
||||
|
||||
pic_value results;
|
||||
};
|
||||
|
||||
void pic_save_point(pic_state *, struct pic_escape *);
|
||||
void pic_load_point(pic_state *, struct pic_escape *);
|
||||
|
||||
struct pic_proc *pic_make_econt(pic_state *, struct pic_escape *);
|
||||
|
||||
void pic_wind(pic_state *, struct pic_winder *, struct pic_winder *);
|
||||
pic_value pic_dynamic_wind(pic_state *, struct pic_proc *, struct pic_proc *, struct pic_proc *);
|
||||
|
||||
pic_value pic_values0(pic_state *);
|
||||
pic_value pic_values1(pic_state *, pic_value);
|
||||
pic_value pic_values2(pic_state *, pic_value, pic_value);
|
||||
pic_value pic_values3(pic_state *, pic_value, pic_value, pic_value);
|
||||
pic_value pic_values4(pic_state *, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_values5(pic_state *, pic_value, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_values_by_array(pic_state *, size_t, pic_value *);
|
||||
pic_value pic_values_by_list(pic_state *, pic_value);
|
||||
size_t pic_receive(pic_state *, size_t, pic_value *);
|
||||
|
||||
pic_value pic_escape(pic_state *, struct pic_proc *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_DATA_H
|
||||
#define PICRIN_DATA_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const char *type_name;
|
||||
void (*dtor)(pic_state *, void *);
|
||||
void (*mark)(pic_state *, void *, void (*)(pic_state *, pic_value));
|
||||
} pic_data_type;
|
||||
|
||||
struct pic_data {
|
||||
PIC_OBJECT_HEADER
|
||||
const pic_data_type *type;
|
||||
xhash storage; /* const char * to pic_value table */
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define pic_data_p(o) (pic_type(o) == PIC_TT_DATA)
|
||||
#define pic_data_ptr(o) ((struct pic_data *)pic_ptr(o))
|
||||
|
||||
static inline bool pic_data_type_p(const pic_value obj, const pic_data_type *type) {
|
||||
return pic_data_p(obj) && pic_data_ptr(obj)->type == type;
|
||||
}
|
||||
|
||||
struct pic_data *pic_data_alloc(pic_state *, const pic_data_type *, void *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_DICT_H
|
||||
#define PICRIN_DICT_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_dict {
|
||||
PIC_OBJECT_HEADER
|
||||
xhash hash;
|
||||
};
|
||||
|
||||
#define pic_dict_p(v) (pic_type(v) == PIC_TT_DICT)
|
||||
#define pic_dict_ptr(v) ((struct pic_dict *)pic_ptr(v))
|
||||
|
||||
struct pic_dict *pic_make_dict(pic_state *);
|
||||
|
||||
pic_value pic_dict_ref(pic_state *, struct pic_dict *, pic_value);
|
||||
void pic_dict_set(pic_state *, struct pic_dict *, pic_value, pic_value);
|
||||
void pic_dict_del(pic_state *, struct pic_dict *, pic_value);
|
||||
size_t pic_dict_size(pic_state *, struct pic_dict *);
|
||||
bool pic_dict_has(pic_state *, struct pic_dict *, pic_value);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_ERROR_H
|
||||
#define PICRIN_ERROR_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "picrin/cont.h"
|
||||
|
||||
struct pic_error {
|
||||
PIC_OBJECT_HEADER
|
||||
pic_sym type;
|
||||
pic_str *msg;
|
||||
pic_value irrs;
|
||||
pic_str *stack;
|
||||
};
|
||||
|
||||
#define pic_error_p(v) (pic_type(v) == PIC_TT_ERROR)
|
||||
#define pic_error_ptr(v) ((struct pic_error *)pic_ptr(v))
|
||||
|
||||
struct pic_error *pic_make_error(pic_state *, pic_sym, const char *, pic_list);
|
||||
|
||||
/* do not return from try block! */
|
||||
|
||||
#define pic_try \
|
||||
pic_try_(GENSYM(escape))
|
||||
#define pic_try_(escape) \
|
||||
struct pic_escape *escape = pic_alloc(pic, sizeof(struct pic_escape)); \
|
||||
pic_save_point(pic, escape); \
|
||||
if (setjmp(escape->jmp) == 0) { \
|
||||
pic_push_try(pic, escape); \
|
||||
do
|
||||
#define pic_catch \
|
||||
while (0); \
|
||||
pic_pop_try(pic); \
|
||||
} else
|
||||
|
||||
void pic_push_try(pic_state *, struct pic_escape *);
|
||||
void pic_pop_try(pic_state *);
|
||||
|
||||
pic_value pic_raise_continuable(pic_state *, pic_value);
|
||||
noreturn void pic_raise(pic_state *, pic_value);
|
||||
noreturn void pic_throw(pic_state *, pic_sym, const char *, pic_list);
|
||||
noreturn void pic_error(pic_state *, const char *, pic_list);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_GC_H
|
||||
#define PICRIN_GC_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PIC_GC_UNMARK 0
|
||||
#define PIC_GC_MARK 1
|
||||
|
||||
struct pic_heap;
|
||||
|
||||
struct pic_heap *pic_heap_open();
|
||||
void pic_heap_close(struct pic_heap *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_IREP_H
|
||||
#define PICRIN_IREP_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum pic_opcode {
|
||||
OP_NOP,
|
||||
OP_POP,
|
||||
OP_PUSHNIL,
|
||||
OP_PUSHTRUE,
|
||||
OP_PUSHFALSE,
|
||||
OP_PUSHINT,
|
||||
OP_PUSHCHAR,
|
||||
OP_PUSHCONST,
|
||||
OP_GREF,
|
||||
OP_GSET,
|
||||
OP_LREF,
|
||||
OP_LSET,
|
||||
OP_CREF,
|
||||
OP_CSET,
|
||||
OP_JMP,
|
||||
OP_JMPIF,
|
||||
OP_NOT,
|
||||
OP_CALL,
|
||||
OP_TAILCALL,
|
||||
OP_RET,
|
||||
OP_LAMBDA,
|
||||
OP_CONS,
|
||||
OP_CAR,
|
||||
OP_CDR,
|
||||
OP_NILP,
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_MINUS,
|
||||
OP_EQ,
|
||||
OP_LT,
|
||||
OP_LE,
|
||||
OP_STOP
|
||||
};
|
||||
|
||||
struct pic_code {
|
||||
enum pic_opcode insn;
|
||||
union {
|
||||
int i;
|
||||
char c;
|
||||
struct {
|
||||
int depth;
|
||||
int idx;
|
||||
} r;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct pic_irep {
|
||||
PIC_OBJECT_HEADER
|
||||
pic_sym name;
|
||||
pic_code *code;
|
||||
int argc, localc, capturec;
|
||||
bool varg;
|
||||
struct pic_irep **irep;
|
||||
pic_value *pool;
|
||||
size_t clen, ilen, plen;
|
||||
};
|
||||
|
||||
pic_value pic_analyze(pic_state *, pic_value);
|
||||
struct pic_irep *pic_codegen(pic_state *, pic_value);
|
||||
|
||||
static inline void
|
||||
pic_dump_code(pic_code c)
|
||||
{
|
||||
printf("[%2d] ", c.insn);
|
||||
switch (c.insn) {
|
||||
case OP_NOP:
|
||||
puts("OP_NOP");
|
||||
break;
|
||||
case OP_POP:
|
||||
puts("OP_POP");
|
||||
break;
|
||||
case OP_PUSHNIL:
|
||||
puts("OP_PUSHNIL");
|
||||
break;
|
||||
case OP_PUSHTRUE:
|
||||
puts("OP_PUSHTRUE");
|
||||
break;
|
||||
case OP_PUSHFALSE:
|
||||
puts("OP_PUSHFALSE");
|
||||
break;
|
||||
case OP_PUSHINT:
|
||||
printf("OP_PUSHINT\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_PUSHCHAR:
|
||||
printf("OP_PUSHCHAR\t%c\n", c.u.c);
|
||||
break;
|
||||
case OP_PUSHCONST:
|
||||
printf("OP_PUSHCONST\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_GREF:
|
||||
printf("OP_GREF\t%i\n", c.u.i);
|
||||
break;
|
||||
case OP_GSET:
|
||||
printf("OP_GSET\t%i\n", c.u.i);
|
||||
break;
|
||||
case OP_LREF:
|
||||
printf("OP_LREF\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_LSET:
|
||||
printf("OP_LSET\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_CREF:
|
||||
printf("OP_CREF\t%d\t%d\n", c.u.r.depth, c.u.r.idx);
|
||||
break;
|
||||
case OP_CSET:
|
||||
printf("OP_CSET\t%d\t%d\n", c.u.r.depth, c.u.r.idx);
|
||||
break;
|
||||
case OP_JMP:
|
||||
printf("OP_JMP\t%x\n", c.u.i);
|
||||
break;
|
||||
case OP_JMPIF:
|
||||
printf("OP_JMPIF\t%x\n", c.u.i);
|
||||
break;
|
||||
case OP_NOT:
|
||||
puts("OP_NOT");
|
||||
break;
|
||||
case OP_CALL:
|
||||
printf("OP_CALL\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_TAILCALL:
|
||||
printf("OP_TAILCALL\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_RET:
|
||||
printf("OP_RET\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_LAMBDA:
|
||||
printf("OP_LAMBDA\t%d\n", c.u.i);
|
||||
break;
|
||||
case OP_CONS:
|
||||
puts("OP_CONS");
|
||||
break;
|
||||
case OP_CAR:
|
||||
puts("OP_CAR");
|
||||
break;
|
||||
case OP_NILP:
|
||||
puts("OP_NILP");
|
||||
break;
|
||||
case OP_CDR:
|
||||
puts("OP_CDR");
|
||||
break;
|
||||
case OP_ADD:
|
||||
puts("OP_ADD");
|
||||
break;
|
||||
case OP_SUB:
|
||||
puts("OP_SUB");
|
||||
break;
|
||||
case OP_MUL:
|
||||
puts("OP_MUL");
|
||||
break;
|
||||
case OP_DIV:
|
||||
puts("OP_DIV");
|
||||
break;
|
||||
case OP_MINUS:
|
||||
puts("OP_MINUS");
|
||||
break;
|
||||
case OP_EQ:
|
||||
puts("OP_EQ");
|
||||
break;
|
||||
case OP_LT:
|
||||
puts("OP_LT");
|
||||
break;
|
||||
case OP_LE:
|
||||
puts("OP_LE");
|
||||
break;
|
||||
case OP_STOP:
|
||||
puts("OP_STOP");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
pic_dump_irep(struct pic_irep *irep)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
printf("## irep %p\n", (void *)irep);
|
||||
printf("[clen = %zd, argc = %d, localc = %d, capturec = %d]\n", irep->clen, irep->argc, irep->localc, irep->capturec);
|
||||
for (i = 0; i < irep->clen; ++i) {
|
||||
printf("%02x ", i);
|
||||
pic_dump_code(irep->code[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < irep->ilen; ++i) {
|
||||
pic_dump_irep(irep->irep[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_LIB_H
|
||||
#define PICRIN_LIB_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_lib {
|
||||
PIC_OBJECT_HEADER
|
||||
pic_value name;
|
||||
struct pic_senv *env;
|
||||
xhash exports;
|
||||
};
|
||||
|
||||
#define pic_lib_ptr(o) ((struct pic_lib *)pic_ptr(o))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_MACRO_H
|
||||
#define PICRIN_MACRO_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_senv {
|
||||
PIC_OBJECT_HEADER
|
||||
xhash map;
|
||||
pic_value defer;
|
||||
struct pic_senv *up;
|
||||
};
|
||||
|
||||
struct pic_macro {
|
||||
PIC_OBJECT_HEADER
|
||||
struct pic_proc *proc;
|
||||
struct pic_senv *senv;
|
||||
};
|
||||
|
||||
#define pic_macro_p(v) (pic_type(v) == PIC_TT_MACRO)
|
||||
#define pic_macro_ptr(v) ((struct pic_macro *)pic_ptr(v))
|
||||
|
||||
#define pic_senv_p(v) (pic_type(v) == PIC_TT_SENV)
|
||||
#define pic_senv_ptr(v) ((struct pic_senv *)pic_ptr(v))
|
||||
|
||||
struct pic_senv *pic_null_syntactic_environment(pic_state *);
|
||||
|
||||
bool pic_identifier_p(pic_state *pic, pic_value obj);
|
||||
bool pic_identifier_eq_p(pic_state *, struct pic_senv *, pic_sym, struct pic_senv *, pic_sym);
|
||||
|
||||
struct pic_senv *pic_make_senv(pic_state *, struct pic_senv *);
|
||||
|
||||
pic_sym pic_add_rename(pic_state *, struct pic_senv *, pic_sym);
|
||||
bool pic_find_rename(pic_state *, struct pic_senv *, pic_sym, pic_sym * /* = NULL */);
|
||||
void pic_put_rename(pic_state *, struct pic_senv *, pic_sym, pic_sym);
|
||||
|
||||
void pic_define_syntactic_keyword(pic_state *, struct pic_senv *, pic_sym, pic_sym);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_PAIR_H
|
||||
#define PICRIN_PAIR_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_pair {
|
||||
PIC_OBJECT_HEADER
|
||||
pic_value car;
|
||||
pic_value cdr;
|
||||
};
|
||||
|
||||
#define pic_pair_p(v) (pic_type(v) == PIC_TT_PAIR)
|
||||
#define pic_pair_ptr(o) ((struct pic_pair *)pic_ptr(o))
|
||||
|
||||
static inline pic_value
|
||||
pic_car(pic_state *pic, pic_value obj)
|
||||
{
|
||||
struct pic_pair *pair;
|
||||
|
||||
if (! pic_pair_p(obj)) {
|
||||
pic_errorf(pic, "pair required, but got ~s", obj);
|
||||
}
|
||||
pair = pic_pair_ptr(obj);
|
||||
|
||||
return pair->car;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_cdr(pic_state *pic, pic_value obj)
|
||||
{
|
||||
struct pic_pair *pair;
|
||||
|
||||
if (! pic_pair_p(obj)) {
|
||||
pic_errorf(pic, "pair required, but got ~s", obj);
|
||||
}
|
||||
pair = pic_pair_ptr(obj);
|
||||
|
||||
return pair->cdr;
|
||||
}
|
||||
|
||||
pic_value pic_cons(pic_state *, pic_value, pic_value);
|
||||
void pic_set_car(pic_state *, pic_value, pic_value);
|
||||
void pic_set_cdr(pic_state *, pic_value, pic_value);
|
||||
|
||||
bool pic_list_p(pic_value);
|
||||
pic_value pic_list1(pic_state *, pic_value);
|
||||
pic_value pic_list2(pic_state *, pic_value, pic_value);
|
||||
pic_value pic_list3(pic_state *, pic_value, pic_value, pic_value);
|
||||
pic_value pic_list4(pic_state *, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_list5(pic_state *, pic_value, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_list6(pic_state *, pic_value, pic_value, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_list7(pic_state *, pic_value, pic_value, pic_value, pic_value, pic_value, pic_value, pic_value);
|
||||
pic_value pic_list_by_array(pic_state *, size_t, pic_value *);
|
||||
pic_value pic_make_list(pic_state *, size_t, pic_value);
|
||||
|
||||
#define pic_for_each(var, list) \
|
||||
pic_for_each_helper_(var, GENSYM(tmp), list)
|
||||
#define pic_for_each_helper_(var, tmp, list) \
|
||||
for (pic_value tmp = (list); \
|
||||
pic_nil_p(tmp) ? false : ((var = pic_car(pic, tmp)), true); \
|
||||
tmp = pic_cdr(pic, tmp))
|
||||
|
||||
#define pic_push(pic, item, place) (place = pic_cons(pic, item, place))
|
||||
#define pic_pop(pic, place) (place = pic_cdr(pic, place))
|
||||
|
||||
size_t pic_length(pic_state *, pic_value);
|
||||
pic_value pic_reverse(pic_state *, pic_value);
|
||||
pic_value pic_append(pic_state *, pic_value, pic_value);
|
||||
|
||||
pic_value pic_memq(pic_state *, pic_value key, pic_value list);
|
||||
pic_value pic_memv(pic_state *, pic_value key, pic_value list);
|
||||
pic_value pic_member(pic_state *, pic_value key, pic_value list, struct pic_proc * /* = NULL */);
|
||||
|
||||
pic_value pic_assq(pic_state *, pic_value key, pic_value assoc);
|
||||
pic_value pic_assv(pic_state *, pic_value key, pic_value assoc);
|
||||
pic_value pic_assoc(pic_state *, pic_value key, pic_value assoc, struct pic_proc * /* = NULL */);
|
||||
|
||||
pic_value pic_acons(pic_state *, pic_value key, pic_value val, pic_value assoc);
|
||||
|
||||
pic_value pic_caar(pic_state *, pic_value);
|
||||
pic_value pic_cadr(pic_state *, pic_value);
|
||||
pic_value pic_cdar(pic_state *, pic_value);
|
||||
pic_value pic_cddr(pic_state *, pic_value);
|
||||
|
||||
pic_value pic_list_tail(pic_state *, pic_value, size_t);
|
||||
pic_value pic_list_ref(pic_state *, pic_value, size_t);
|
||||
void pic_list_set(pic_state *, pic_value, size_t, pic_value);
|
||||
pic_value pic_list_copy(pic_state *, pic_value);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_PORT_H
|
||||
#define PICRIN_PORT_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum pic_port_flag {
|
||||
PIC_PORT_IN = 1,
|
||||
PIC_PORT_OUT = 2,
|
||||
PIC_PORT_TEXT = 4,
|
||||
PIC_PORT_BINARY = 8,
|
||||
};
|
||||
|
||||
enum pic_port_status {
|
||||
PIC_PORT_OPEN,
|
||||
PIC_PORT_CLOSE,
|
||||
};
|
||||
|
||||
struct pic_port {
|
||||
PIC_OBJECT_HEADER
|
||||
xFILE *file;
|
||||
int flags;
|
||||
int status;
|
||||
};
|
||||
|
||||
#define pic_port_p(v) (pic_type(v) == PIC_TT_PORT)
|
||||
#define pic_port_ptr(v) ((struct pic_port *)pic_ptr(v))
|
||||
|
||||
pic_value pic_eof_object();
|
||||
|
||||
struct pic_port *pic_open_input_string(pic_state *, const char *);
|
||||
struct pic_port *pic_open_output_string(pic_state *);
|
||||
struct pic_string *pic_get_output_string(pic_state *, struct pic_port *);
|
||||
|
||||
void pic_close_port(pic_state *pic, struct pic_port *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_PROC_H
|
||||
#define PICRIN_PROC_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* native C function */
|
||||
struct pic_func {
|
||||
pic_func_t f;
|
||||
pic_sym name;
|
||||
};
|
||||
|
||||
struct pic_env {
|
||||
PIC_OBJECT_HEADER
|
||||
pic_value *regs;
|
||||
int regc;
|
||||
struct pic_env *up;
|
||||
pic_value storage[];
|
||||
};
|
||||
|
||||
struct pic_proc {
|
||||
PIC_OBJECT_HEADER
|
||||
char kind;
|
||||
union {
|
||||
struct pic_func func;
|
||||
struct pic_irep *irep;
|
||||
} u;
|
||||
struct pic_env *env;
|
||||
};
|
||||
|
||||
#define PIC_PROC_KIND_FUNC 1
|
||||
#define PIC_PROC_KIND_IREP 2
|
||||
|
||||
#define pic_proc_func_p(proc) ((proc)->kind == PIC_PROC_KIND_FUNC)
|
||||
#define pic_proc_irep_p(proc) ((proc)->kind == PIC_PROC_KIND_IREP)
|
||||
|
||||
#define pic_proc_p(o) (pic_type(o) == PIC_TT_PROC)
|
||||
#define pic_proc_ptr(o) ((struct pic_proc *)pic_ptr(o))
|
||||
|
||||
#define pic_env_p(o) (pic_type(o) == PIC_TT_ENV)
|
||||
#define pic_env_ptr(o) ((struct pic_env *)pic_ptr(o))
|
||||
|
||||
struct pic_proc *pic_make_proc(pic_state *, pic_func_t, const char *);
|
||||
struct pic_proc *pic_make_proc_irep(pic_state *, struct pic_irep *, struct pic_env *);
|
||||
|
||||
pic_sym pic_proc_name(struct pic_proc *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_READ_H
|
||||
#define PICRIN_READ_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum pic_typecase {
|
||||
PIC_CASE_DEFAULT,
|
||||
PIC_CASE_FOLD,
|
||||
};
|
||||
|
||||
struct pic_trie {
|
||||
struct pic_trie *table[256];
|
||||
struct pic_proc *proc;
|
||||
};
|
||||
|
||||
struct pic_reader {
|
||||
short typecase;
|
||||
xhash labels;
|
||||
struct pic_trie *trie;
|
||||
};
|
||||
|
||||
void pic_init_reader(pic_state *);
|
||||
|
||||
void pic_define_reader(pic_state *, const char *, pic_func_t);
|
||||
|
||||
struct pic_trie *pic_make_trie(pic_state *);
|
||||
void pic_trie_delete(pic_state *, struct pic_trie *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_RECORD_H
|
||||
#define PICRIN_RECORD_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_record {
|
||||
PIC_OBJECT_HEADER
|
||||
xhash hash;
|
||||
};
|
||||
|
||||
#define pic_record_p(v) (pic_type(v) == PIC_TT_RECORD)
|
||||
#define pic_record_ptr(v) ((struct pic_record *)pic_ptr(v))
|
||||
|
||||
struct pic_record *pic_make_record(pic_state *, pic_value);
|
||||
|
||||
pic_value pic_record_type(pic_state *, struct pic_record *);
|
||||
pic_value pic_record_ref(pic_state *, struct pic_record *, pic_sym);
|
||||
void pic_record_set(pic_state *, struct pic_record *, pic_sym, pic_value);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_STRING_H
|
||||
#define PICRIN_STRING_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_string {
|
||||
PIC_OBJECT_HEADER
|
||||
xrope *rope;
|
||||
};
|
||||
|
||||
#define pic_str_p(v) (pic_type(v) == PIC_TT_STRING)
|
||||
#define pic_str_ptr(o) ((struct pic_string *)pic_ptr(o))
|
||||
|
||||
pic_str *pic_make_str(pic_state *, const char * /* nullable */, size_t);
|
||||
pic_str *pic_make_str_cstr(pic_state *, const char *);
|
||||
pic_str *pic_make_str_fill(pic_state *, size_t, char);
|
||||
|
||||
size_t pic_strlen(pic_str *);
|
||||
char pic_str_ref(pic_state *, pic_str *, size_t);
|
||||
|
||||
pic_str *pic_strcat(pic_state *, pic_str *, pic_str *);
|
||||
pic_str *pic_substr(pic_state *, pic_str *, size_t, size_t);
|
||||
int pic_strcmp(pic_str *, pic_str *);
|
||||
|
||||
const char *pic_str_cstr(pic_str *);
|
||||
|
||||
pic_str *pic_format(pic_state *, const char *, ...);
|
||||
pic_str *pic_vformat(pic_state *, const char *, va_list);
|
||||
void pic_vfformat(pic_state *, xFILE *, const char *, va_list);
|
||||
|
||||
pic_value pic_xformat(pic_state *, const char *, ...);
|
||||
pic_value pic_xvformat(pic_state *, const char *, va_list);
|
||||
pic_value pic_xvfformat(pic_state *, xFILE *, const char *, va_list);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_UTIL_H
|
||||
#define PICRIN_UTIL_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
# include <stdnoreturn.h>
|
||||
#elif __GNUC__ || __clang__
|
||||
# define noreturn __attribute__((noreturn))
|
||||
#else
|
||||
# define noreturn
|
||||
#endif
|
||||
|
||||
#define FALLTHROUGH ((void)0)
|
||||
#define UNUSED(v) ((void)(v))
|
||||
|
||||
#define GENSYM2_(x,y) G##x##_##y##__
|
||||
#define GENSYM1_(x,y) GENSYM2_(x,y)
|
||||
#if defined(__COUNTER__)
|
||||
# define GENSYM(x) GENSYM1_(__COUNTER__,x)
|
||||
#else
|
||||
# define GENSYM(x) GENSYM1_(__LINE__,x)
|
||||
#endif
|
||||
|
||||
#if GCC_VERSION >= 40500 || __clang__
|
||||
# define UNREACHABLE() (__builtin_unreachable())
|
||||
#else
|
||||
# include <assert.h>
|
||||
# define UNREACHABLE() (assert(false))
|
||||
#endif
|
||||
|
||||
#define SWAP(type,a,b) \
|
||||
SWAP_HELPER_(type,GENSYM(tmp),a,b)
|
||||
#define SWAP_HELPER_(type,tmp,a,b) \
|
||||
do { \
|
||||
type tmp = (a); \
|
||||
(a) = (b); \
|
||||
(b) = tmp; \
|
||||
} while (0)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,534 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_VALUE_H
|
||||
#define PICRIN_VALUE_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* pic_sym is just an alias of int.
|
||||
*/
|
||||
|
||||
typedef int pic_sym;
|
||||
|
||||
/**
|
||||
* `undef` values never seen from user-end: that is,
|
||||
* it's used only for repsenting internal special state
|
||||
*/
|
||||
|
||||
enum pic_vtype {
|
||||
PIC_VTYPE_NIL = 1,
|
||||
PIC_VTYPE_TRUE,
|
||||
PIC_VTYPE_FALSE,
|
||||
PIC_VTYPE_UNDEF,
|
||||
PIC_VTYPE_FLOAT,
|
||||
PIC_VTYPE_INT,
|
||||
PIC_VTYPE_SYMBOL,
|
||||
PIC_VTYPE_CHAR,
|
||||
PIC_VTYPE_EOF,
|
||||
PIC_VTYPE_HEAP
|
||||
};
|
||||
|
||||
#if PIC_NAN_BOXING
|
||||
|
||||
/**
|
||||
* value representation by nan-boxing:
|
||||
* float : FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF
|
||||
* ptr : 111111111111TTTT PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP
|
||||
* int : 1111111111110110 0000000000000000 IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII
|
||||
* sym : 1111111111110111 0000000000000000 SSSSSSSSSSSSSSSS SSSSSSSSSSSSSSSS
|
||||
* char : 1111111111111000 0000000000000000 CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC
|
||||
*/
|
||||
|
||||
typedef uint64_t pic_value;
|
||||
|
||||
#define pic_ptr(v) ((void *)(0xfffffffffffful & (v)))
|
||||
#define pic_init_value(v,vtype) (v = (0xfff0000000000000ul | ((uint64_t)(vtype) << 48)))
|
||||
|
||||
static inline enum pic_vtype
|
||||
pic_vtype(pic_value v)
|
||||
{
|
||||
return 0xfff0 >= (v >> 48) ? PIC_VTYPE_FLOAT : ((v >> 48) & 0xf);
|
||||
}
|
||||
|
||||
static inline double
|
||||
pic_float(pic_value v)
|
||||
{
|
||||
union { double f; uint64_t i; } u;
|
||||
u.i = v;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pic_int(pic_value v)
|
||||
{
|
||||
union { int i; unsigned u; } u;
|
||||
u.u = v & 0xfffffffful;
|
||||
return u.i;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pic_sym(pic_value v)
|
||||
{
|
||||
union { int i; unsigned u; } u;
|
||||
u.u = v & 0xfffffffful;
|
||||
return u.i;
|
||||
}
|
||||
|
||||
#define pic_char(v) ((v) & 0xfffffffful)
|
||||
|
||||
#else
|
||||
|
||||
typedef struct {
|
||||
enum pic_vtype type;
|
||||
union {
|
||||
void *data;
|
||||
double f;
|
||||
int i;
|
||||
pic_sym sym;
|
||||
char c;
|
||||
} u;
|
||||
} pic_value;
|
||||
|
||||
#define pic_ptr(v) ((v).u.data)
|
||||
#define pic_vtype(v) ((v).type)
|
||||
#define pic_init_value(v,vtype) ((v).type = (vtype), (v).u.data = NULL)
|
||||
|
||||
#define pic_float(v) ((v).u.f)
|
||||
#define pic_int(v) ((v).u.i)
|
||||
#define pic_sym(v) ((v).u.sym)
|
||||
#define pic_char(v) ((v).u.c)
|
||||
|
||||
#endif
|
||||
|
||||
enum pic_tt {
|
||||
/* immediate */
|
||||
PIC_TT_NIL,
|
||||
PIC_TT_BOOL,
|
||||
PIC_TT_FLOAT,
|
||||
PIC_TT_INT,
|
||||
PIC_TT_SYMBOL,
|
||||
PIC_TT_CHAR,
|
||||
PIC_TT_EOF,
|
||||
PIC_TT_UNDEF,
|
||||
/* heap */
|
||||
PIC_TT_PAIR,
|
||||
PIC_TT_STRING,
|
||||
PIC_TT_VECTOR,
|
||||
PIC_TT_BLOB,
|
||||
PIC_TT_PROC,
|
||||
PIC_TT_PORT,
|
||||
PIC_TT_ERROR,
|
||||
PIC_TT_ENV,
|
||||
PIC_TT_SENV,
|
||||
PIC_TT_MACRO,
|
||||
PIC_TT_LIB,
|
||||
PIC_TT_IREP,
|
||||
PIC_TT_DATA,
|
||||
PIC_TT_DICT,
|
||||
PIC_TT_RECORD,
|
||||
};
|
||||
|
||||
#define PIC_OBJECT_HEADER \
|
||||
enum pic_tt tt;
|
||||
|
||||
struct pic_object {
|
||||
PIC_OBJECT_HEADER
|
||||
};
|
||||
|
||||
struct pic_pair;
|
||||
struct pic_string;
|
||||
struct pic_vector;
|
||||
struct pic_blob;
|
||||
|
||||
struct pic_proc;
|
||||
struct pic_port;
|
||||
struct pic_error;
|
||||
|
||||
/* set aliases to basic types */
|
||||
typedef pic_value pic_list;
|
||||
typedef struct pic_pair pic_pair;
|
||||
typedef struct pic_string pic_str;
|
||||
typedef struct pic_vector pic_vec;
|
||||
typedef struct pic_blob pic_blob;
|
||||
|
||||
#define pic_obj_p(v) (pic_vtype(v) == PIC_VTYPE_HEAP)
|
||||
#define pic_obj_ptr(v) ((struct pic_object *)pic_ptr(v))
|
||||
|
||||
#define pic_nil_p(v) (pic_vtype(v) == PIC_VTYPE_NIL)
|
||||
#define pic_true_p(v) (pic_vtype(v) == PIC_VTYPE_TRUE)
|
||||
#define pic_false_p(v) (pic_vtype(v) == PIC_VTYPE_FALSE)
|
||||
#define pic_undef_p(v) (pic_vtype(v) == PIC_VTYPE_UNDEF)
|
||||
#define pic_float_p(v) (pic_vtype(v) == PIC_VTYPE_FLOAT)
|
||||
#define pic_int_p(v) (pic_vtype(v) == PIC_VTYPE_INT)
|
||||
#define pic_sym_p(v) (pic_vtype(v) == PIC_VTYPE_SYMBOL)
|
||||
#define pic_char_p(v) (pic_vtype(v) == PIC_VTYPE_CHAR)
|
||||
#define pic_eof_p(v) (pic_vtype(v) == PIC_VTYPE_EOF)
|
||||
|
||||
#define pic_test(v) (! pic_false_p(v))
|
||||
|
||||
static inline enum pic_tt pic_type(pic_value);
|
||||
static inline const char *pic_type_repr(enum pic_tt);
|
||||
|
||||
#define pic_assert_type(pic, v, type) \
|
||||
if (! pic_##type##_p(v)) { \
|
||||
pic_errorf(pic, "expected " #type ", but got ~s", v); \
|
||||
}
|
||||
|
||||
static inline bool pic_valid_int(double);
|
||||
|
||||
static inline pic_value pic_nil_value();
|
||||
static inline pic_value pic_true_value();
|
||||
static inline pic_value pic_false_value();
|
||||
static inline pic_value pic_bool_value(bool);
|
||||
static inline pic_value pic_undef_value();
|
||||
static inline pic_value pic_obj_value(void *);
|
||||
static inline pic_value pic_float_value(double);
|
||||
static inline pic_value pic_int_value(int);
|
||||
static inline pic_value pic_size_value(size_t);
|
||||
static inline pic_value pic_sym_value(pic_sym);
|
||||
static inline pic_value pic_char_value(char c);
|
||||
static inline pic_value pic_none_value();
|
||||
|
||||
#define pic_symbol_value(sym) pic_sym_value(sym)
|
||||
|
||||
static inline bool pic_eq_p(pic_value, pic_value);
|
||||
static inline bool pic_eqv_p(pic_value, pic_value);
|
||||
|
||||
static inline enum pic_tt
|
||||
pic_type(pic_value v)
|
||||
{
|
||||
switch (pic_vtype(v)) {
|
||||
case PIC_VTYPE_NIL:
|
||||
return PIC_TT_NIL;
|
||||
case PIC_VTYPE_TRUE:
|
||||
return PIC_TT_BOOL;
|
||||
case PIC_VTYPE_FALSE:
|
||||
return PIC_TT_BOOL;
|
||||
case PIC_VTYPE_UNDEF:
|
||||
return PIC_TT_UNDEF;
|
||||
case PIC_VTYPE_FLOAT:
|
||||
return PIC_TT_FLOAT;
|
||||
case PIC_VTYPE_INT:
|
||||
return PIC_TT_INT;
|
||||
case PIC_VTYPE_SYMBOL:
|
||||
return PIC_TT_SYMBOL;
|
||||
case PIC_VTYPE_CHAR:
|
||||
return PIC_TT_CHAR;
|
||||
case PIC_VTYPE_EOF:
|
||||
return PIC_TT_EOF;
|
||||
case PIC_VTYPE_HEAP:
|
||||
return ((struct pic_object *)pic_ptr(v))->tt;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
pic_type_repr(enum pic_tt tt)
|
||||
{
|
||||
switch (tt) {
|
||||
case PIC_TT_NIL:
|
||||
return "nil";
|
||||
case PIC_TT_BOOL:
|
||||
return "boolean";
|
||||
case PIC_TT_FLOAT:
|
||||
return "float";
|
||||
case PIC_TT_INT:
|
||||
return "int";
|
||||
case PIC_TT_SYMBOL:
|
||||
return "symbol";
|
||||
case PIC_TT_CHAR:
|
||||
return "char";
|
||||
case PIC_TT_EOF:
|
||||
return "eof";
|
||||
case PIC_TT_UNDEF:
|
||||
return "undef";
|
||||
case PIC_TT_PAIR:
|
||||
return "pair";
|
||||
case PIC_TT_STRING:
|
||||
return "string";
|
||||
case PIC_TT_VECTOR:
|
||||
return "vector";
|
||||
case PIC_TT_BLOB:
|
||||
return "blob";
|
||||
case PIC_TT_PORT:
|
||||
return "port";
|
||||
case PIC_TT_ERROR:
|
||||
return "error";
|
||||
case PIC_TT_ENV:
|
||||
return "env";
|
||||
case PIC_TT_PROC:
|
||||
return "proc";
|
||||
case PIC_TT_SENV:
|
||||
return "senv";
|
||||
case PIC_TT_MACRO:
|
||||
return "macro";
|
||||
case PIC_TT_LIB:
|
||||
return "lib";
|
||||
case PIC_TT_IREP:
|
||||
return "irep";
|
||||
case PIC_TT_DATA:
|
||||
return "data";
|
||||
case PIC_TT_DICT:
|
||||
return "dict";
|
||||
case PIC_TT_RECORD:
|
||||
return "record";
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pic_valid_int(double v)
|
||||
{
|
||||
return INT_MIN <= v && v <= INT_MAX;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_nil_value()
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_NIL);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_true_value()
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_TRUE);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_false_value()
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_FALSE);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_bool_value(bool b)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, b ? PIC_VTYPE_TRUE : PIC_VTYPE_FALSE);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_size_value(size_t s)
|
||||
{
|
||||
if (sizeof(unsigned) < sizeof(size_t)) {
|
||||
if (s > (size_t)INT_MAX) {
|
||||
return pic_float_value(s);
|
||||
}
|
||||
}
|
||||
return pic_int_value((int)s);
|
||||
}
|
||||
|
||||
#if PIC_NAN_BOXING
|
||||
|
||||
static inline pic_value
|
||||
pic_obj_value(void *ptr)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_HEAP);
|
||||
v |= 0xfffffffffffful & (uint64_t)ptr;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_float_value(double f)
|
||||
{
|
||||
union { double f; uint64_t i; } u;
|
||||
|
||||
if (f != f) {
|
||||
return 0x7ff8000000000000ul;
|
||||
} else {
|
||||
u.f = f;
|
||||
return u.i;
|
||||
}
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_int_value(int i)
|
||||
{
|
||||
union { int i; unsigned u; } u;
|
||||
pic_value v;
|
||||
|
||||
u.i = i;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_INT);
|
||||
v |= u.u;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_symbol_value(pic_sym sym)
|
||||
{
|
||||
union { int i; unsigned u; } u;
|
||||
pic_value v;
|
||||
|
||||
u.i = sym;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_SYMBOL);
|
||||
v |= u.u;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_char_value(char c)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_CHAR);
|
||||
v |= c;
|
||||
return v;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline pic_value
|
||||
pic_obj_value(void *ptr)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_HEAP);
|
||||
v.u.data = ptr;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_float_value(double f)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_FLOAT);
|
||||
v.u.f = f;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_int_value(int i)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_INT);
|
||||
v.u.i = i;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_symbol_value(pic_sym sym)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_SYMBOL);
|
||||
v.u.sym = sym;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_char_value(char c)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_CHAR);
|
||||
v.u.c = c;
|
||||
return v;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline pic_value
|
||||
pic_undef_value()
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_UNDEF);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline pic_value
|
||||
pic_none_value()
|
||||
{
|
||||
#if PIC_NONE_IS_FALSE
|
||||
return pic_false_value();
|
||||
#else
|
||||
# error enable PIC_NONE_IS_FALSE
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PIC_NAN_BOXING
|
||||
|
||||
static inline bool
|
||||
pic_eq_p(pic_value x, pic_value y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pic_eqv_p(pic_value x, pic_value y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline bool
|
||||
pic_eq_p(pic_value x, pic_value y)
|
||||
{
|
||||
if (pic_type(x) != pic_type(y))
|
||||
return false;
|
||||
|
||||
switch (pic_type(x)) {
|
||||
case PIC_TT_NIL:
|
||||
return true;
|
||||
case PIC_TT_BOOL:
|
||||
return pic_vtype(x) == pic_vtype(y);
|
||||
case PIC_TT_SYMBOL:
|
||||
return pic_sym(x) == pic_sym(y);
|
||||
default:
|
||||
return pic_ptr(x) == pic_ptr(y);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
pic_eqv_p(pic_value x, pic_value y)
|
||||
{
|
||||
if (pic_type(x) != pic_type(y))
|
||||
return false;
|
||||
|
||||
switch (pic_type(x)) {
|
||||
case PIC_TT_NIL:
|
||||
return true;
|
||||
case PIC_TT_BOOL:
|
||||
return pic_vtype(x) == pic_vtype(y);
|
||||
case PIC_TT_SYMBOL:
|
||||
return pic_sym(x) == pic_sym(y);
|
||||
case PIC_TT_FLOAT:
|
||||
return pic_float(x) == pic_float(y);
|
||||
case PIC_TT_INT:
|
||||
return pic_int(x) == pic_int(y);
|
||||
default:
|
||||
return pic_ptr(x) == pic_ptr(y);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#ifndef PICRIN_VECTOR_H
|
||||
#define PICRIN_VECTOR_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pic_vector {
|
||||
PIC_OBJECT_HEADER
|
||||
pic_value *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
#define pic_vec_p(v) (pic_type(v) == PIC_TT_VECTOR)
|
||||
#define pic_vec_ptr(o) ((struct pic_vector *)pic_ptr(o))
|
||||
|
||||
struct pic_vector *pic_make_vec(pic_state *, size_t);
|
||||
struct pic_vector *pic_make_vec_from_list(pic_state *, pic_value);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,584 @@
|
|||
#ifndef XFILE_H
|
||||
#define XFILE_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int ungot;
|
||||
int flags;
|
||||
/* operators */
|
||||
struct {
|
||||
void *cookie;
|
||||
int (*read)(void *, char *, int);
|
||||
int (*write)(void *, const char *, int);
|
||||
long (*seek)(void *, long, int);
|
||||
int (*flush)(void *);
|
||||
int (*close)(void *);
|
||||
} vtable;
|
||||
} xFILE;
|
||||
|
||||
/* generic file constructor */
|
||||
static inline xFILE *xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *));
|
||||
|
||||
/* resource aquisition */
|
||||
static inline xFILE *xfpopen(FILE *);
|
||||
static inline xFILE *xmopen();
|
||||
static inline xFILE *xfopen(const char *, const char *);
|
||||
static inline int xfclose(xFILE *);
|
||||
|
||||
/* buffer management */
|
||||
static inline int xfflush(xFILE *);
|
||||
|
||||
/* direct IO with buffering */
|
||||
static inline size_t xfread(void *, size_t, size_t, xFILE *);
|
||||
static inline size_t xfwrite(const void *, size_t, size_t, xFILE *);
|
||||
|
||||
/* indicator positioning */
|
||||
static inline long xfseek(xFILE *, long offset, int whence);
|
||||
static inline long xftell(xFILE *);
|
||||
static inline void xrewind(xFILE *);
|
||||
|
||||
/* stream status */
|
||||
static inline void xclearerr(xFILE *);
|
||||
static inline int xfeof(xFILE *);
|
||||
static inline int xferror(xFILE *);
|
||||
|
||||
/* character IO */
|
||||
static inline int xfgetc(xFILE *);
|
||||
static inline char *xfgets(char *, int, xFILE *);
|
||||
static inline int xfputc(int, xFILE *);
|
||||
static inline int xfputs(const char *, xFILE *);
|
||||
static inline int xgetc(xFILE *);
|
||||
static inline int xgetchar(void);
|
||||
static inline int xputc(int, xFILE *);
|
||||
static inline int xputchar(int);
|
||||
static inline int xputs(const char *);
|
||||
static inline int xungetc(int, xFILE *);
|
||||
|
||||
/* formatted I/O */
|
||||
static inline int xprintf(const char *, ...);
|
||||
static inline int xfprintf(xFILE *, const char *, ...);
|
||||
static inline int xvfprintf(xFILE *, const char *, va_list);
|
||||
|
||||
/* standard I/O */
|
||||
#define xstdin (xstdin_())
|
||||
#define xstdout (xstdout_())
|
||||
#define xstderr (xstderr_())
|
||||
|
||||
|
||||
/* private */
|
||||
|
||||
#define XF_EOF 1
|
||||
#define XF_ERR 2
|
||||
|
||||
static inline xFILE *
|
||||
xfunopen(void *cookie, int (*read)(void *, char *, int), int (*write)(void *, const char *, int), long (*seek)(void *, long, int), int (*flush)(void *), int (*close)(void *))
|
||||
{
|
||||
xFILE *file;
|
||||
|
||||
file = (xFILE *)malloc(sizeof(xFILE));
|
||||
if (! file) {
|
||||
return NULL;
|
||||
}
|
||||
file->ungot = -1;
|
||||
file->flags = 0;
|
||||
/* set vtable */
|
||||
file->vtable.cookie = cookie;
|
||||
file->vtable.read = read;
|
||||
file->vtable.write = write;
|
||||
file->vtable.seek = seek;
|
||||
file->vtable.flush = flush;
|
||||
file->vtable.close = close;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Derieved xFILE Classes
|
||||
*/
|
||||
|
||||
static inline int
|
||||
xf_file_read(void *cookie, char *ptr, int size)
|
||||
{
|
||||
FILE *file = cookie;
|
||||
int r;
|
||||
|
||||
r = (int)fread(ptr, 1, (size_t)size, file);
|
||||
if (r < size && ferror(file)) {
|
||||
return -1;
|
||||
}
|
||||
if (r == 0 && feof(file)) {
|
||||
clearerr(file);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xf_file_write(void *cookie, const char *ptr, int size)
|
||||
{
|
||||
FILE *file = cookie;
|
||||
int r;
|
||||
|
||||
r = (int)fwrite(ptr, 1, (size_t)size, file);
|
||||
if (r < size) {
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline long
|
||||
xf_file_seek(void *cookie, long pos, int whence)
|
||||
{
|
||||
return fseek(cookie, pos, whence);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xf_file_flush(void *cookie)
|
||||
{
|
||||
return fflush(cookie);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xf_file_close(void *cookie)
|
||||
{
|
||||
return fclose(cookie);
|
||||
}
|
||||
|
||||
static inline xFILE *
|
||||
xfpopen(FILE *fp)
|
||||
{
|
||||
xFILE *file;
|
||||
|
||||
file = xfunopen(fp, xf_file_read, xf_file_write, xf_file_seek, xf_file_flush, xf_file_close);
|
||||
if (! file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
#define XF_FILE_VTABLE xf_file_read, xf_file_write, xf_file_seek, xf_file_flush, xf_file_close
|
||||
|
||||
static inline xFILE *
|
||||
xstdin_()
|
||||
{
|
||||
static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } };
|
||||
|
||||
if (! x.vtable.cookie) {
|
||||
x.vtable.cookie = stdin;
|
||||
}
|
||||
return &x;
|
||||
}
|
||||
|
||||
static inline xFILE *
|
||||
xstdout_()
|
||||
{
|
||||
static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } };
|
||||
|
||||
if (! x.vtable.cookie) {
|
||||
x.vtable.cookie = stdout;
|
||||
}
|
||||
return &x;
|
||||
}
|
||||
|
||||
static inline xFILE *
|
||||
xstderr_()
|
||||
{
|
||||
static xFILE x = { -1, 0, { NULL, XF_FILE_VTABLE } };
|
||||
|
||||
if (! x.vtable.cookie) {
|
||||
x.vtable.cookie = stderr;
|
||||
}
|
||||
return &x;
|
||||
}
|
||||
|
||||
struct xf_membuf {
|
||||
char *buf;
|
||||
long pos, end, capa;
|
||||
};
|
||||
|
||||
static inline int
|
||||
xf_mem_read(void *cookie, char *ptr, int size)
|
||||
{
|
||||
struct xf_membuf *mem;
|
||||
|
||||
mem = (struct xf_membuf *)cookie;
|
||||
|
||||
if (size > (int)(mem->end - mem->pos))
|
||||
size = (int)(mem->end - mem->pos);
|
||||
memcpy(ptr, mem->buf + mem->pos, size);
|
||||
mem->pos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xf_mem_write(void *cookie, const char *ptr, int size)
|
||||
{
|
||||
struct xf_membuf *mem;
|
||||
|
||||
mem = (struct xf_membuf *)cookie;
|
||||
|
||||
if (mem->pos + size >= mem->capa) {
|
||||
mem->capa = (mem->pos + size) * 2;
|
||||
mem->buf = realloc(mem->buf, (size_t)mem->capa);
|
||||
}
|
||||
memcpy(mem->buf + mem->pos, ptr, size);
|
||||
mem->pos += size;
|
||||
if (mem->end < mem->pos)
|
||||
mem->end = mem->pos;
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline long
|
||||
xf_mem_seek(void *cookie, long pos, int whence)
|
||||
{
|
||||
struct xf_membuf *mem;
|
||||
|
||||
mem = (struct xf_membuf *)cookie;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
mem->pos = pos;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
mem->pos += pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
mem->pos = mem->end + pos;
|
||||
break;
|
||||
}
|
||||
|
||||
return mem->pos;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xf_mem_flush(void *cookie)
|
||||
{
|
||||
(void)cookie;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xf_mem_close(void *cookie)
|
||||
{
|
||||
struct xf_membuf *mem;
|
||||
|
||||
mem = (struct xf_membuf *)cookie;
|
||||
free(mem->buf);
|
||||
free(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline xFILE *
|
||||
xmopen()
|
||||
{
|
||||
struct xf_membuf *mem;
|
||||
|
||||
mem = (struct xf_membuf *)malloc(sizeof(struct xf_membuf));
|
||||
mem->buf = (char *)malloc(BUFSIZ);
|
||||
mem->pos = 0;
|
||||
mem->end = 0;
|
||||
mem->capa = BUFSIZ;
|
||||
|
||||
return xfunopen(mem, xf_mem_read, xf_mem_write, xf_mem_seek, xf_mem_flush, xf_mem_close);
|
||||
}
|
||||
|
||||
#undef XF_FILE_VTABLE
|
||||
|
||||
static inline xFILE *
|
||||
xfopen(const char *filename, const char *mode)
|
||||
{
|
||||
FILE *fp;
|
||||
xFILE *file;
|
||||
|
||||
fp = fopen(filename, mode);
|
||||
if (! fp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file = xfpopen(fp);
|
||||
if (! file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfclose(xFILE *file)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = file->vtable.close(file->vtable.cookie);
|
||||
if (r == EOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfflush(xFILE *file)
|
||||
{
|
||||
return file->vtable.flush(file->vtable.cookie);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xfread(void *ptr, size_t block, size_t nitems, xFILE *file)
|
||||
{
|
||||
char *dst = (char *)ptr;
|
||||
char buf[block];
|
||||
size_t i, offset;
|
||||
int n;
|
||||
|
||||
for (i = 0; i < nitems; ++i) {
|
||||
offset = 0;
|
||||
if (file->ungot != -1 && block > 0) {
|
||||
buf[0] = (char)file->ungot;
|
||||
offset += 1;
|
||||
file->ungot = -1;
|
||||
}
|
||||
while (offset < block) {
|
||||
n = file->vtable.read(file->vtable.cookie, buf + offset, (int)(block - offset));
|
||||
if (n < 0) {
|
||||
file->flags |= XF_ERR;
|
||||
goto exit;
|
||||
}
|
||||
if (n == 0) {
|
||||
file->flags |= XF_EOF;
|
||||
goto exit;
|
||||
}
|
||||
offset += (unsigned)n;
|
||||
}
|
||||
memcpy(dst, buf, block);
|
||||
dst += block;
|
||||
}
|
||||
|
||||
exit:
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xfwrite(const void *ptr, size_t block, size_t nitems, xFILE *file)
|
||||
{
|
||||
char *dst = (char *)ptr;
|
||||
size_t i, offset;
|
||||
int n;
|
||||
|
||||
for (i = 0; i < nitems; ++i) {
|
||||
offset = 0;
|
||||
while (offset < block) {
|
||||
n = file->vtable.write(file->vtable.cookie, dst + offset, (int)(block - offset));
|
||||
if (n < 0) {
|
||||
file->flags |= XF_ERR;
|
||||
goto exit;
|
||||
}
|
||||
offset += (unsigned)n;
|
||||
}
|
||||
dst += block;
|
||||
}
|
||||
|
||||
exit:
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline long
|
||||
xfseek(xFILE *file, long offset, int whence)
|
||||
{
|
||||
file->ungot = -1;
|
||||
return file->vtable.seek(file->vtable.cookie, offset, whence);
|
||||
}
|
||||
|
||||
static inline long
|
||||
xftell(xFILE *file)
|
||||
{
|
||||
return xfseek(file, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xrewind(xFILE *file)
|
||||
{
|
||||
xfseek(file, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xclearerr(xFILE *file)
|
||||
{
|
||||
file->flags = 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfeof(xFILE *file)
|
||||
{
|
||||
return file->flags & XF_EOF;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xferror(xFILE *file)
|
||||
{
|
||||
return file->flags & XF_ERR;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfgetc(xFILE *file)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
xfread(buf, 1, 1, file);
|
||||
|
||||
if (xfeof(file) || xferror(file)) {
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
static inline int
|
||||
xgetc(xFILE *file)
|
||||
{
|
||||
return xfgetc(file);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
xfgets(char *str, int size, xFILE *file)
|
||||
{
|
||||
int c = EOF, i;
|
||||
|
||||
for (i = 0; i < size - 1 && c != '\n'; ++i) {
|
||||
if ((c = xfgetc(file)) == EOF) {
|
||||
break;
|
||||
}
|
||||
str[i] = (char)c;
|
||||
}
|
||||
if (i == 0 && c == EOF) {
|
||||
return NULL;
|
||||
}
|
||||
if (xferror(file)) {
|
||||
return NULL;
|
||||
}
|
||||
str[i] = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xungetc(int c, xFILE *file)
|
||||
{
|
||||
file->ungot = c;
|
||||
if (c != EOF) {
|
||||
file->flags &= ~XF_EOF;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xgetchar(void)
|
||||
{
|
||||
return xfgetc(xstdin);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfputc(int c, xFILE *file)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
buf[0] = (char)c;
|
||||
xfwrite(buf, 1, 1, file);
|
||||
|
||||
if (xferror(file)) {
|
||||
return EOF;
|
||||
}
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
static inline int
|
||||
xputc(int c, xFILE *file)
|
||||
{
|
||||
return xfputc(c, file);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xputchar(int c)
|
||||
{
|
||||
return xfputc(c, xstdout);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfputs(const char *str, xFILE *file)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(str);
|
||||
xfwrite(str, len, 1, file);
|
||||
|
||||
if (xferror(file)) {
|
||||
return EOF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xputs(const char *s)
|
||||
{
|
||||
return xfputs(s, xstdout);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = xvfprintf(xstdout, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfprintf(xFILE *stream, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = xvfprintf(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xvfprintf(xFILE *stream, const char *fmt, va_list ap)
|
||||
{
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
{
|
||||
char buf[vsnprintf(NULL, 0, fmt, ap2)];
|
||||
|
||||
vsnprintf(buf, sizeof buf + 1, fmt, ap);
|
||||
|
||||
if (xfwrite(buf, sizeof buf, 1, stream) < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_end(ap2);
|
||||
return (int)(sizeof buf);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,427 @@
|
|||
#ifndef XHASH_H
|
||||
#define XHASH_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 by Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* simple object to object hash table */
|
||||
|
||||
#define XHASH_INIT_SIZE 11
|
||||
#define XHASH_RESIZE_RATIO 0.75
|
||||
|
||||
#define XHASH_ALIGNMENT 3 /* quad word alignment */
|
||||
#define XHASH_MASK (~(size_t)((1 << XHASH_ALIGNMENT) - 1))
|
||||
#define XHASH_ALIGN(i) ((((i) - 1) & XHASH_MASK) + (1 << XHASH_ALIGNMENT))
|
||||
|
||||
typedef struct xh_entry {
|
||||
struct xh_entry *next;
|
||||
int hash;
|
||||
struct xh_entry *fw, *bw;
|
||||
const void *key;
|
||||
void *val;
|
||||
} xh_entry;
|
||||
|
||||
#define xh_key(e,type) (*(type *)((e)->key))
|
||||
#define xh_val(e,type) (*(type *)((e)->val))
|
||||
|
||||
typedef int (*xh_hashf)(const void *, void *);
|
||||
typedef int (*xh_equalf)(const void *, const void *, void *);
|
||||
|
||||
typedef struct xhash {
|
||||
xh_entry **buckets;
|
||||
size_t size, count, kwidth, vwidth;
|
||||
size_t koffset, voffset;
|
||||
xh_hashf hashf;
|
||||
xh_equalf equalf;
|
||||
xh_entry *head, *tail;
|
||||
void *data;
|
||||
} xhash;
|
||||
|
||||
/** Protected Methods:
|
||||
* static inline void xh_init_(xhash *x, size_t, size_t, xh_hashf, xh_equalf, void *);
|
||||
* static inline xh_entry *xh_get_(xhash *x, const void *key);
|
||||
* static inline xh_entry *xh_put_(xhash *x, const void *key, void *val);
|
||||
* static inline void xh_del_(xhash *x, const void *key);
|
||||
*/
|
||||
|
||||
/* string map */
|
||||
static inline void xh_init_str(xhash *x, size_t width);
|
||||
static inline xh_entry *xh_get_str(xhash *x, const char *key);
|
||||
static inline xh_entry *xh_put_str(xhash *x, const char *key, void *);
|
||||
static inline void xh_del_str(xhash *x, const char *key);
|
||||
|
||||
/* object map */
|
||||
static inline void xh_init_ptr(xhash *x, size_t width);
|
||||
static inline xh_entry *xh_get_ptr(xhash *x, const void *key);
|
||||
static inline xh_entry *xh_put_ptr(xhash *x, const void *key, void *);
|
||||
static inline void xh_del_ptr(xhash *x, const void *key);
|
||||
|
||||
/* int map */
|
||||
static inline void xh_init_int(xhash *x, size_t width);
|
||||
static inline xh_entry *xh_get_int(xhash *x, int key);
|
||||
static inline xh_entry *xh_put_int(xhash *x, int key, void *);
|
||||
static inline void xh_del_int(xhash *x, int key);
|
||||
|
||||
static inline size_t xh_size(xhash *x);
|
||||
static inline void xh_clear(xhash *x);
|
||||
static inline void xh_destroy(xhash *x);
|
||||
|
||||
static inline xh_entry *xh_begin(xhash *x);
|
||||
static inline xh_entry *xh_next(xh_entry *e);
|
||||
|
||||
|
||||
static inline void
|
||||
xh_bucket_realloc(xhash *x, size_t newsize)
|
||||
{
|
||||
x->size = newsize;
|
||||
x->buckets = realloc(x->buckets, (x->size + 1) * sizeof(xh_entry *));
|
||||
memset(x->buckets, 0, (x->size + 1) * sizeof(xh_entry *));
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_(xhash *x, size_t kwidth, size_t vwidth, xh_hashf hashf, xh_equalf equalf, void *data)
|
||||
{
|
||||
x->size = 0;
|
||||
x->buckets = NULL;
|
||||
x->count = 0;
|
||||
x->kwidth = kwidth;
|
||||
x->vwidth = vwidth;
|
||||
x->koffset = XHASH_ALIGN(sizeof(xh_entry));
|
||||
x->voffset = XHASH_ALIGN(sizeof(xh_entry)) + XHASH_ALIGN(kwidth);
|
||||
x->hashf = hashf;
|
||||
x->equalf = equalf;
|
||||
x->head = NULL;
|
||||
x->tail = NULL;
|
||||
x->data = data;
|
||||
|
||||
xh_bucket_realloc(x, XHASH_INIT_SIZE);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_(xhash *x, const void *key)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e;
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
for (e = x->buckets[idx]; e; e = e->next) {
|
||||
if (e->hash == hash && x->equalf(key, e->key, x->data))
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_resize_(xhash *x, size_t newsize)
|
||||
{
|
||||
xhash y;
|
||||
xh_entry *it;
|
||||
size_t idx;
|
||||
|
||||
xh_init_(&y, x->kwidth, x->vwidth, x->hashf, x->equalf, x->data);
|
||||
xh_bucket_realloc(&y, newsize);
|
||||
|
||||
for (it = xh_begin(x); it != NULL; it = xh_next(it)) {
|
||||
idx = ((unsigned)it->hash) % y.size;
|
||||
/* reuse entry object */
|
||||
it->next = y.buckets[idx];
|
||||
y.buckets[idx] = it;
|
||||
y.count++;
|
||||
}
|
||||
|
||||
y.head = x->head;
|
||||
y.tail = x->tail;
|
||||
|
||||
free(x->buckets);
|
||||
|
||||
/* copy all members from y to x */
|
||||
memcpy(x, &y, sizeof(xhash));
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_(xhash *x, const void *key, void *val)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e;
|
||||
|
||||
if ((e = xh_get_(x, key))) {
|
||||
memcpy(e->val, val, x->vwidth);
|
||||
return e;
|
||||
}
|
||||
|
||||
if (x->count + 1 > x->size * XHASH_RESIZE_RATIO) {
|
||||
xh_resize_(x, x->size * 2 + 1);
|
||||
}
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
e = malloc(x->voffset + x->vwidth);
|
||||
e->next = x->buckets[idx];
|
||||
e->hash = hash;
|
||||
e->key = ((char *)e) + x->koffset;
|
||||
e->val = ((char *)e) + x->voffset;
|
||||
memcpy((void *)e->key, key, x->kwidth);
|
||||
memcpy(e->val, val, x->vwidth);
|
||||
|
||||
if (x->head == NULL) {
|
||||
x->head = x->tail = e;
|
||||
e->fw = e->bw = NULL;
|
||||
} else {
|
||||
x->tail->bw = e;
|
||||
e->fw = x->tail;
|
||||
e->bw = NULL;
|
||||
x->tail = e;
|
||||
}
|
||||
|
||||
x->count++;
|
||||
|
||||
return x->buckets[idx] = e;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_(xhash *x, const void *key)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *p, *q, *r;
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
if (x->buckets[idx]->hash == hash && x->equalf(key, x->buckets[idx]->key, x->data)) {
|
||||
q = x->buckets[idx];
|
||||
if (q->fw == NULL) {
|
||||
x->head = q->bw;
|
||||
} else {
|
||||
q->fw->bw = q->bw;
|
||||
}
|
||||
if (q->bw == NULL) {
|
||||
x->tail = q->fw;
|
||||
} else {
|
||||
q->bw->fw = q->fw;
|
||||
}
|
||||
r = q->next;
|
||||
free(q);
|
||||
x->buckets[idx] = r;
|
||||
}
|
||||
else {
|
||||
for (p = x->buckets[idx]; ; p = p->next) {
|
||||
if (p->next->hash == hash && x->equalf(key, p->next->key, x->data))
|
||||
break;
|
||||
}
|
||||
q = p->next;
|
||||
if (q->fw == NULL) {
|
||||
x->head = q->bw;
|
||||
} else {
|
||||
q->fw->bw = q->bw;
|
||||
}
|
||||
if (q->bw == NULL) {
|
||||
x->tail = q->fw;
|
||||
} else {
|
||||
q->bw->fw = q->fw;
|
||||
}
|
||||
r = q->next;
|
||||
free(q);
|
||||
p->next = r;
|
||||
}
|
||||
|
||||
x->count--;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xh_size(xhash *x)
|
||||
{
|
||||
return x->count;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_clear(xhash *x)
|
||||
{
|
||||
size_t i;
|
||||
xh_entry *e, *d;
|
||||
|
||||
for (i = 0; i < x->size; ++i) {
|
||||
e = x->buckets[i];
|
||||
while (e) {
|
||||
d = e->next;
|
||||
free(e);
|
||||
e = d;
|
||||
}
|
||||
x->buckets[i] = NULL;
|
||||
}
|
||||
|
||||
x->head = x->tail = NULL;
|
||||
x->count = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_destroy(xhash *x)
|
||||
{
|
||||
xh_clear(x);
|
||||
free(x->buckets);
|
||||
}
|
||||
|
||||
/* string map */
|
||||
|
||||
static inline int
|
||||
xh_str_hash(const void *key, void *data)
|
||||
{
|
||||
const char *str = *(const char **)key;
|
||||
int hash = 0;
|
||||
|
||||
(void)data;
|
||||
|
||||
while (*str) {
|
||||
hash = hash * 31 + *str++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_str_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return strcmp(*(const char **)key1, *(const char **)key2) == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_str(xhash *x, size_t width)
|
||||
{
|
||||
xh_init_(x, sizeof(const char *), width, xh_str_hash, xh_str_equal, NULL);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_str(xhash *x, const char *key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_str(xhash *x, const char *key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_str(xhash *x, const char *key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/* object map */
|
||||
|
||||
static inline int
|
||||
xh_ptr_hash(const void *key, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return (int)(size_t)*(const void **)key;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_ptr_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
return *(const void **)key1 == *(const void **)key2;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_ptr(xhash *x, size_t width)
|
||||
{
|
||||
xh_init_(x, sizeof(const void *), width, xh_ptr_hash, xh_ptr_equal, NULL);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_ptr(xhash *x, const void *key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_ptr(xhash *x, const void *key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_ptr(xhash *x, const void *key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/* int map */
|
||||
|
||||
static inline int
|
||||
xh_int_hash(const void *key, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return *(int *)key;
|
||||
}
|
||||
|
||||
static inline int
|
||||
xh_int_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return *(int *)key1 == *(int *)key2;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_init_int(xhash *x, size_t width)
|
||||
{
|
||||
xh_init_(x, sizeof(int), width, xh_int_hash, xh_int_equal, NULL);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_get_int(xhash *x, int key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_put_int(xhash *x, int key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xh_del_int(xhash *x, int key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/** iteration */
|
||||
|
||||
static inline xh_entry *
|
||||
xh_begin(xhash *x)
|
||||
{
|
||||
return x->head;
|
||||
}
|
||||
|
||||
static inline xh_entry *
|
||||
xh_next(xh_entry *e)
|
||||
{
|
||||
return e->bw;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,329 @@
|
|||
#ifndef XROPE_H__
|
||||
#define XROPE_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* public APIs */
|
||||
|
||||
typedef struct xrope xrope;
|
||||
|
||||
/**
|
||||
* | name | frees buffer? | end with NULL? | complexity | misc
|
||||
* | ---- | ---- | ---- | ---- | ---
|
||||
* | xr_new_cstr | no | yes | O(1) | xr_new(_lit)
|
||||
* | xr_new_imbed | no | no | O(1) |
|
||||
* | xr_new_move | yes | yes | O(1) |
|
||||
* | xr_new_copy | yes | no | O(n) |
|
||||
*/
|
||||
|
||||
#define xr_new(cstr) xr_new_cstr(cstr, strlen(cstr))
|
||||
#define xr_new_lit(cstr) xr_new_cstr(cstr, sizeof(cstr) - 1)
|
||||
static inline xrope *xr_new_cstr(const char *, size_t);
|
||||
static inline xrope *xr_new_imbed(const char *, size_t);
|
||||
static inline xrope *xr_new_move(const char *, size_t);
|
||||
static inline xrope *xr_new_copy(const char *, size_t);
|
||||
|
||||
static inline void XROPE_INCREF(xrope *);
|
||||
static inline void XROPE_DECREF(xrope *);
|
||||
|
||||
static inline size_t xr_len(xrope *);
|
||||
static inline char xr_at(xrope *, size_t);
|
||||
static inline xrope *xr_cat(xrope *, xrope *);
|
||||
static inline xrope *xr_sub(xrope *, size_t, size_t);
|
||||
static inline const char *xr_cstr(xrope *); /* returns NULL-terminated string */
|
||||
|
||||
|
||||
/* impl */
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int refcnt;
|
||||
size_t len;
|
||||
char autofree, zeroterm;
|
||||
} xr_chunk;
|
||||
|
||||
#define XR_CHUNK_INCREF(c) do { \
|
||||
(c)->refcnt++; \
|
||||
} while (0)
|
||||
|
||||
#define XR_CHUNK_DECREF(c) do { \
|
||||
xr_chunk *c__ = (c); \
|
||||
if (! --c__->refcnt) { \
|
||||
if (c__->autofree) \
|
||||
free(c__->str); \
|
||||
free(c__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct xrope {
|
||||
int refcnt;
|
||||
size_t weight;
|
||||
xr_chunk *chunk;
|
||||
size_t offset;
|
||||
struct xrope *left, *right;
|
||||
};
|
||||
|
||||
static inline void
|
||||
XROPE_INCREF(xrope *x) {
|
||||
x->refcnt++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
XROPE_DECREF(xrope *x) {
|
||||
if (! --x->refcnt) {
|
||||
if (x->chunk) {
|
||||
XR_CHUNK_DECREF(x->chunk);
|
||||
free(x);
|
||||
return;
|
||||
}
|
||||
XROPE_DECREF(x->left);
|
||||
XROPE_DECREF(x->right);
|
||||
free(x);
|
||||
}
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_cstr(const char *cstr, size_t len)
|
||||
{
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = (char *)cstr;
|
||||
c->len = len;
|
||||
c->autofree = 0;
|
||||
c->zeroterm = 1;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_imbed(const char *str, size_t len)
|
||||
{
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = (char *)str;
|
||||
c->len = len;
|
||||
c->autofree = 0;
|
||||
c->zeroterm = 0;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_move(const char *cstr, size_t len)
|
||||
{
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = (char *)cstr;
|
||||
c->len = len;
|
||||
c->autofree = 1;
|
||||
c->zeroterm = 1;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_new_copy(const char *str, size_t len)
|
||||
{
|
||||
char *buf;
|
||||
xr_chunk *c;
|
||||
xrope *x;
|
||||
|
||||
buf = (char *)malloc(len + 1);
|
||||
buf[len] = '\0';
|
||||
memcpy(buf, str, len);
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->str = buf;
|
||||
c->len = len;
|
||||
c->autofree = 1;
|
||||
c->zeroterm = 1;
|
||||
|
||||
x = (xrope *)malloc(sizeof(xrope));
|
||||
x->refcnt = 1;
|
||||
x->left = NULL;
|
||||
x->right = NULL;
|
||||
x->weight = c->len;
|
||||
x->offset = 0;
|
||||
x->chunk = c;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xr_len(xrope *x)
|
||||
{
|
||||
return x->weight;
|
||||
}
|
||||
|
||||
static inline char
|
||||
xr_at(xrope *x, size_t i)
|
||||
{
|
||||
if (x->weight <= i) {
|
||||
return -1;
|
||||
}
|
||||
if (x->chunk) {
|
||||
return x->chunk->str[x->offset + i];
|
||||
}
|
||||
return (i < x->left->weight)
|
||||
? xr_at(x->left, i)
|
||||
: xr_at(x->right, i - x->left->weight);
|
||||
}
|
||||
|
||||
static inline xrope *
|
||||
xr_cat(xrope *x, xrope *y)
|
||||
{
|
||||
xrope *z;
|
||||
|
||||
z = (xrope *)malloc(sizeof(xrope));
|
||||
z->refcnt = 1;
|
||||
z->left = x;
|
||||
z->right = y;
|
||||
z->weight = x->weight + y->weight;
|
||||
z->offset = 0;
|
||||
z->chunk = NULL;
|
||||
|
||||
XROPE_INCREF(x);
|
||||
XROPE_INCREF(y);
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
static inline struct xrope *
|
||||
xr_sub(xrope *x, size_t i, size_t j)
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= x->weight);
|
||||
|
||||
if (i == 0 && x->weight == j) {
|
||||
XROPE_INCREF(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x->chunk) {
|
||||
xrope *y;
|
||||
|
||||
y = (xrope *)malloc(sizeof(xrope));
|
||||
y->refcnt = 1;
|
||||
y->left = NULL;
|
||||
y->right = NULL;
|
||||
y->weight = j - i;
|
||||
y->offset = x->offset + i;
|
||||
y->chunk = x->chunk;
|
||||
|
||||
XR_CHUNK_INCREF(x->chunk);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
if (j <= x->left->weight) {
|
||||
return xr_sub(x->left, i, j);
|
||||
}
|
||||
else if (x->left->weight <= i) {
|
||||
return xr_sub(x->right, i - x->left->weight, j - x->left->weight);
|
||||
}
|
||||
else {
|
||||
xrope *r, *l;
|
||||
|
||||
l = xr_sub(x->left, i, x->left->weight);
|
||||
r = xr_sub(x->right, 0, j - x->left->weight);
|
||||
x = xr_cat(l, r);
|
||||
|
||||
XROPE_DECREF(l);
|
||||
XROPE_DECREF(r);
|
||||
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xr_fold(xrope *x, xr_chunk *c, size_t offset)
|
||||
{
|
||||
if (x->chunk) {
|
||||
memcpy(c->str + offset, x->chunk->str + x->offset, x->weight);
|
||||
XR_CHUNK_DECREF(x->chunk);
|
||||
|
||||
x->chunk = c;
|
||||
x->offset = offset;
|
||||
XR_CHUNK_INCREF(c);
|
||||
return;
|
||||
}
|
||||
xr_fold(x->left, c, offset);
|
||||
xr_fold(x->right, c, offset + x->left->weight);
|
||||
|
||||
XROPE_DECREF(x->left);
|
||||
XROPE_DECREF(x->right);
|
||||
x->left = x->right = NULL;
|
||||
x->chunk = c;
|
||||
x->offset = offset;
|
||||
XR_CHUNK_INCREF(c);
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
xr_cstr(xrope *x)
|
||||
{
|
||||
xr_chunk *c;
|
||||
|
||||
if (x->chunk && x->offset == 0 && x->weight == x->chunk->len && x->chunk->zeroterm) {
|
||||
return x->chunk->str; /* reuse cached chunk */
|
||||
}
|
||||
|
||||
c = (xr_chunk *)malloc(sizeof(xr_chunk));
|
||||
c->refcnt = 1;
|
||||
c->len = x->weight;
|
||||
c->autofree = 1;
|
||||
c->zeroterm = 1;
|
||||
c->str = (char *)malloc(c->len + 1);
|
||||
c->str[c->len] = '\0';
|
||||
|
||||
xr_fold(x, c, 0);
|
||||
|
||||
XR_CHUNK_DECREF(c);
|
||||
return c->str;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
#ifndef XVECT_H__
|
||||
#define XVECT_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 by Yuichi Nishiwaki <yuichi@idylls.jp>
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct xvect {
|
||||
char *data;
|
||||
size_t size, mask, head, tail, width;
|
||||
} xvect;
|
||||
|
||||
static inline void xv_init(xvect *, size_t);
|
||||
static inline void xv_destroy(xvect *);
|
||||
|
||||
static inline size_t xv_size(xvect *);
|
||||
|
||||
static inline void xv_reserve(xvect *, size_t);
|
||||
static inline void xv_shrink(xvect *, size_t);
|
||||
|
||||
static inline void *xv_get(xvect *, size_t);
|
||||
static inline void xv_set(xvect *, size_t, void *);
|
||||
|
||||
static inline void xv_push(xvect *, void *);
|
||||
static inline void *xv_pop(xvect *);
|
||||
|
||||
static inline void *xv_shift(xvect *);
|
||||
static inline void xv_unshift(xvect *, void *);
|
||||
|
||||
static inline void xv_splice(xvect *, size_t, size_t);
|
||||
static inline void xv_insert(xvect *, size_t, void *);
|
||||
|
||||
static inline void
|
||||
xv_init(xvect *x, size_t width)
|
||||
{
|
||||
x->data = NULL;
|
||||
x->width = width;
|
||||
x->size = 0;
|
||||
x->mask = (size_t)-1;
|
||||
x->head = 0;
|
||||
x->tail = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_destroy(xvect *x)
|
||||
{
|
||||
free(x->data);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xv_size(xvect *x)
|
||||
{
|
||||
return x->tail < x->head
|
||||
? x->tail + x->size - x->head
|
||||
: x->tail - x->head;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
xv_round2(size_t x)
|
||||
{
|
||||
x -= 1;
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
x |= (x >> 32);
|
||||
x++;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_rotate(xvect *x)
|
||||
{
|
||||
if (x->tail < x->head) {
|
||||
char buf[x->size * x->width];
|
||||
|
||||
/* perform rotation */
|
||||
memcpy(buf, x->data, sizeof buf);
|
||||
memcpy(x->data, buf + x->head * x->width, (x->size - x->head) * x->width);
|
||||
memcpy(x->data + (x->size - x->head) * x->width, buf, x->tail * x->width);
|
||||
x->tail = x->size - x->head + x->tail;
|
||||
x->head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_adjust(xvect *x, size_t size)
|
||||
{
|
||||
size = xv_round2(size);
|
||||
if (size != x->size) {
|
||||
xv_rotate(x);
|
||||
x->data = realloc(x->data, size * x->width);
|
||||
x->size = size;
|
||||
x->mask = size - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_reserve(xvect *x, size_t mincapa)
|
||||
{
|
||||
if (x->size < mincapa + 1) {
|
||||
xv_adjust(x, mincapa + 1); /* capa == size - 1 */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_shrink(xvect *x, size_t maxcapa)
|
||||
{
|
||||
if (x->size > maxcapa + 1) {
|
||||
xv_adjust(x, maxcapa + 1); /* capa == size - 1 */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *
|
||||
xv_get(xvect *x, size_t i)
|
||||
{
|
||||
assert(i < xv_size(x));
|
||||
|
||||
return x->data + ((x->head + i) & x->mask) * x->width;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_set(xvect *x, size_t i, void *src)
|
||||
{
|
||||
memcpy(xv_get(x, i), src, x->width);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_push(xvect *x, void *src)
|
||||
{
|
||||
xv_reserve(x, xv_size(x) + 1);
|
||||
x->tail = (x->tail + 1) & x->mask;
|
||||
xv_set(x, xv_size(x) - 1, src);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
xv_pop(xvect *x)
|
||||
{
|
||||
void *dat;
|
||||
|
||||
assert(xv_size(x) >= 1);
|
||||
|
||||
dat = xv_get(x, xv_size(x) - 1);
|
||||
x->tail = (x->tail - 1) & x->mask;
|
||||
return dat;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
xv_shift(xvect *x)
|
||||
{
|
||||
void *dat;
|
||||
|
||||
assert(xv_size(x) >= 1);
|
||||
|
||||
dat = xv_get(x, 0);
|
||||
x->head = (x->head + 1) & x->mask;
|
||||
return dat;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_unshift(xvect *x, void *src)
|
||||
{
|
||||
xv_reserve(x, xv_size(x) + 1);
|
||||
x->head = (x->head - 1) & x->mask;
|
||||
xv_set(x, 0, src);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_splice(xvect *x, size_t i, size_t j)
|
||||
{
|
||||
assert(i <= j && j < xv_size(x));
|
||||
|
||||
xv_rotate(x);
|
||||
memmove(xv_get(x, i), xv_get(x, j), (xv_size(x) - j) * x->width);
|
||||
x->tail = (x->tail - j + i) & x->mask;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xv_insert(xvect *x, size_t i, void *src)
|
||||
{
|
||||
assert(i <= xv_size(x));
|
||||
|
||||
xv_reserve(x, xv_size(x) + 1);
|
||||
xv_rotate(x);
|
||||
x->tail = (x->tail + 1) & x->mask;
|
||||
|
||||
if (xv_size(x) - 1 != i) {
|
||||
memmove(xv_get(x, i + 1), xv_get(x, i), (xv_size(x) - 1 - i) * x->width);
|
||||
}
|
||||
xv_set(x, i, src);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/lib.h"
|
||||
#include "picrin/macro.h"
|
||||
#include "picrin/error.h"
|
||||
|
||||
void
|
||||
pic_add_feature(pic_state *pic, const char *feature)
|
||||
{
|
||||
pic_push(pic, pic_sym_value(pic_intern_cstr(pic, feature)), pic->features);
|
||||
}
|
||||
|
||||
void pic_init_bool(pic_state *);
|
||||
void pic_init_pair(pic_state *);
|
||||
void pic_init_port(pic_state *);
|
||||
void pic_init_number(pic_state *);
|
||||
void pic_init_time(pic_state *);
|
||||
void pic_init_system(pic_state *);
|
||||
void pic_init_file(pic_state *);
|
||||
void pic_init_proc(pic_state *);
|
||||
void pic_init_symbol(pic_state *);
|
||||
void pic_init_vector(pic_state *);
|
||||
void pic_init_blob(pic_state *);
|
||||
void pic_init_cont(pic_state *);
|
||||
void pic_init_char(pic_state *);
|
||||
void pic_init_error(pic_state *);
|
||||
void pic_init_str(pic_state *);
|
||||
void pic_init_macro(pic_state *);
|
||||
void pic_init_var(pic_state *);
|
||||
void pic_init_load(pic_state *);
|
||||
void pic_init_write(pic_state *);
|
||||
void pic_init_read(pic_state *);
|
||||
void pic_init_dict(pic_state *);
|
||||
void pic_init_record(pic_state *);
|
||||
void pic_init_eval(pic_state *);
|
||||
void pic_init_lib(pic_state *);
|
||||
void pic_init_attr(pic_state *);
|
||||
|
||||
extern const char pic_boot[];
|
||||
|
||||
static void
|
||||
pic_init_features(pic_state *pic)
|
||||
{
|
||||
pic_add_feature(pic, "picrin");
|
||||
pic_add_feature(pic, "ieee-float");
|
||||
|
||||
#if _POSIX_SOURCE
|
||||
pic_add_feature(pic, "posix");
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
pic_add_feature(pic, "windows");
|
||||
#endif
|
||||
|
||||
#if __unix__
|
||||
pic_add_feature(pic, "unix");
|
||||
#endif
|
||||
#if __gnu_linux__
|
||||
pic_add_feature(pic, "gnu-linux");
|
||||
#endif
|
||||
#if __FreeBSD__
|
||||
pic_add_feature(pic, "freebsd");
|
||||
#endif
|
||||
|
||||
#if __i386__
|
||||
pic_add_feature(pic, "i386");
|
||||
#elif __x86_64__
|
||||
pic_add_feature(pic, "x86-64");
|
||||
#elif __ppc__
|
||||
pic_add_feature(pic, "ppc");
|
||||
#elif __sparc__
|
||||
pic_add_feature(pic, "sparc");
|
||||
#endif
|
||||
|
||||
#if __ILP32__
|
||||
pic_add_feature(pic, "ilp32");
|
||||
#elif __LP64__
|
||||
pic_add_feature(pic, "lp64");
|
||||
#endif
|
||||
|
||||
#if defined(__BYTE_ORDER__)
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
pic_add_feature(pic, "little-endian");
|
||||
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
pic_add_feature(pic, "big-endian");
|
||||
# endif
|
||||
#else
|
||||
# if __LITTLE_ENDIAN__
|
||||
pic_add_feature(pic, "little-endian");
|
||||
# elif __BIG_ENDIAN__
|
||||
pic_add_feature(pic, "big-endian");
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DONE pic_gc_arena_restore(pic, ai);
|
||||
|
||||
void
|
||||
pic_init_core(pic_state *pic)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
|
||||
pic_init_features(pic);
|
||||
|
||||
pic_deflibrary (pic, "(picrin base)") {
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE, pic->rDEFINE);
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sSETBANG, pic->rSETBANG);
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sQUOTE, pic->rQUOTE);
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sLAMBDA, pic->rLAMBDA);
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sIF, pic->rIF);
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sBEGIN, pic->rBEGIN);
|
||||
pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE_SYNTAX, pic->rDEFINE_SYNTAX);
|
||||
|
||||
pic_init_bool(pic); DONE;
|
||||
pic_init_pair(pic); DONE;
|
||||
pic_init_port(pic); DONE;
|
||||
pic_init_number(pic); DONE;
|
||||
pic_init_time(pic); DONE;
|
||||
pic_init_system(pic); DONE;
|
||||
pic_init_file(pic); DONE;
|
||||
pic_init_proc(pic); DONE;
|
||||
pic_init_symbol(pic); DONE;
|
||||
pic_init_vector(pic); DONE;
|
||||
pic_init_blob(pic); DONE;
|
||||
pic_init_cont(pic); DONE;
|
||||
pic_init_char(pic); DONE;
|
||||
pic_init_error(pic); DONE;
|
||||
pic_init_str(pic); DONE;
|
||||
pic_init_macro(pic); DONE;
|
||||
pic_init_var(pic); DONE;
|
||||
pic_init_load(pic); DONE;
|
||||
pic_init_write(pic); DONE;
|
||||
pic_init_read(pic); DONE;
|
||||
pic_init_dict(pic); DONE;
|
||||
pic_init_record(pic); DONE;
|
||||
pic_init_eval(pic); DONE;
|
||||
pic_init_lib(pic); DONE;
|
||||
pic_init_attr(pic); DONE;
|
||||
|
||||
pic_load_cstr(pic, pic_boot);
|
||||
}
|
||||
|
||||
pic_import_library(pic, pic->PICRIN_BASE);
|
||||
}
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/lib.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/macro.h"
|
||||
#include "picrin/error.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/proc.h"
|
||||
|
||||
struct pic_lib *
|
||||
pic_open_library(pic_state *pic, pic_value name)
|
||||
{
|
||||
struct pic_lib *lib;
|
||||
struct pic_senv *senv;
|
||||
|
||||
if ((lib = pic_find_library(pic, name)) != NULL) {
|
||||
|
||||
#if DEBUG
|
||||
printf("* reopen library: ");
|
||||
pic_debug(pic, name);
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
senv = pic_null_syntactic_environment(pic);
|
||||
|
||||
lib = (struct pic_lib *)pic_obj_alloc(pic, sizeof(struct pic_lib), PIC_TT_LIB);
|
||||
lib->env = senv;
|
||||
lib->name = name;
|
||||
xh_init_int(&lib->exports, sizeof(pic_sym));
|
||||
|
||||
/* register! */
|
||||
pic->libs = pic_acons(pic, name, pic_obj_value(lib), pic->libs);
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
void
|
||||
pic_in_library(pic_state *pic, pic_value spec)
|
||||
{
|
||||
struct pic_lib *lib;
|
||||
|
||||
lib = pic_find_library(pic, spec);
|
||||
if (! lib) {
|
||||
pic_errorf(pic, "library not found: ~a", spec);
|
||||
}
|
||||
pic->lib = lib;
|
||||
}
|
||||
|
||||
struct pic_lib *
|
||||
pic_find_library(pic_state *pic, pic_value spec)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
v = pic_assoc(pic, spec, pic->libs, NULL);
|
||||
if (pic_false_p(v)) {
|
||||
return NULL;
|
||||
}
|
||||
return pic_lib_ptr(pic_cdr(pic, v));
|
||||
}
|
||||
|
||||
static void
|
||||
import_table(pic_state *pic, pic_value spec, xhash *imports)
|
||||
{
|
||||
struct pic_lib *lib;
|
||||
xhash table;
|
||||
pic_value val;
|
||||
pic_sym sym, id, tag;
|
||||
xh_entry *it;
|
||||
|
||||
xh_init_int(&table, sizeof(pic_sym));
|
||||
|
||||
if (pic_pair_p(spec) && pic_sym_p(pic_car(pic, spec))) {
|
||||
|
||||
tag = pic_sym(pic_car(pic, spec));
|
||||
|
||||
if (tag == pic->sONLY) {
|
||||
import_table(pic, pic_cadr(pic, spec), &table);
|
||||
pic_for_each (val, pic_cddr(pic, spec)) {
|
||||
xh_put_int(imports, pic_sym(val), &xh_val(xh_get_int(&table, pic_sym(val)), pic_sym));
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
if (tag == pic->sRENAME) {
|
||||
import_table(pic, pic_cadr(pic, spec), imports);
|
||||
pic_for_each (val, pic_cddr(pic, spec)) {
|
||||
id = xh_val(xh_get_int(imports, pic_sym(pic_car(pic, val))), pic_sym);
|
||||
xh_del_int(imports, pic_sym(pic_car(pic, val)));
|
||||
xh_put_int(imports, pic_sym(pic_cadr(pic, val)), &id);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
if (tag == pic->sPREFIX) {
|
||||
import_table(pic, pic_cadr(pic, spec), &table);
|
||||
for (it = xh_begin(&table); it != NULL; it = xh_next(it)) {
|
||||
val = pic_list_ref(pic, spec, 2);
|
||||
sym = pic_intern_str(pic, pic_format(pic, "~s~s", val, pic_sym_value(xh_key(it, pic_sym))));
|
||||
xh_put_int(imports, sym, &xh_val(it, pic_sym));
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
if (tag == pic->sEXCEPT) {
|
||||
import_table(pic, pic_cadr(pic, spec), imports);
|
||||
pic_for_each (val, pic_cddr(pic, spec)) {
|
||||
xh_del_int(imports, pic_sym(val));
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
lib = pic_find_library(pic, spec);
|
||||
if (! lib) {
|
||||
pic_errorf(pic, "library not found: ~a", spec);
|
||||
}
|
||||
for (it = xh_begin(&lib->exports); it != NULL; it = xh_next(it)) {
|
||||
xh_put_int(imports, xh_key(it, pic_sym), &xh_val(it, pic_sym));
|
||||
}
|
||||
|
||||
exit:
|
||||
xh_destroy(&table);
|
||||
}
|
||||
|
||||
static void
|
||||
import(pic_state *pic, pic_value spec)
|
||||
{
|
||||
xhash imports;
|
||||
xh_entry *it;
|
||||
|
||||
xh_init_int(&imports, sizeof(pic_sym)); /* pic_sym to pic_sym */
|
||||
|
||||
import_table(pic, spec, &imports);
|
||||
|
||||
for (it = xh_begin(&imports); it != NULL; it = xh_next(it)) {
|
||||
|
||||
#if DEBUG
|
||||
printf("* importing %s as %s\n", pic_symbol_name(pic, xh_key(it, pic_sym)), pic_symbol_name(pic, xh_val(it, pic_sym)));
|
||||
#endif
|
||||
|
||||
pic_put_rename(pic, pic->lib->env, xh_key(it, pic_sym), xh_val(it, pic_sym));
|
||||
}
|
||||
|
||||
xh_destroy(&imports);
|
||||
}
|
||||
|
||||
static void
|
||||
export(pic_state *pic, pic_value spec)
|
||||
{
|
||||
const pic_sym sRENAME = pic_intern_cstr(pic, "rename");
|
||||
pic_value a, b;
|
||||
pic_sym rename;
|
||||
|
||||
if (pic_sym_p(spec)) { /* (export a) */
|
||||
a = b = spec;
|
||||
} else { /* (export (rename a b)) */
|
||||
if (! pic_list_p(spec))
|
||||
goto fail;
|
||||
if (! (pic_length(pic, spec) == 3))
|
||||
goto fail;
|
||||
if (! pic_eq_p(pic_car(pic, spec), pic_sym_value(sRENAME)))
|
||||
goto fail;
|
||||
if (! pic_sym_p(a = pic_list_ref(pic, spec, 1)))
|
||||
goto fail;
|
||||
if (! pic_sym_p(b = pic_list_ref(pic, spec, 2)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! pic_find_rename(pic, pic->lib->env, pic_sym(a), &rename)) {
|
||||
pic_errorf(pic, "export: symbol not defined %s", pic_symbol_name(pic, pic_sym(a)));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
printf("* exporting %s as %s\n", pic_symbol_name(pic, pic_sym(b)), pic_symbol_name(pic, rename));
|
||||
#endif
|
||||
|
||||
xh_put_int(&pic->lib->exports, pic_sym(b), &rename);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
pic_errorf(pic, "illegal export spec: ~s", spec);
|
||||
}
|
||||
|
||||
void
|
||||
pic_import(pic_state *pic, pic_value spec)
|
||||
{
|
||||
import(pic, spec);
|
||||
}
|
||||
|
||||
void
|
||||
pic_import_library(pic_state *pic, struct pic_lib *lib)
|
||||
{
|
||||
import(pic, lib->name);
|
||||
}
|
||||
|
||||
void
|
||||
pic_export(pic_state *pic, pic_sym sym)
|
||||
{
|
||||
export(pic, pic_sym_value(sym));
|
||||
}
|
||||
|
||||
static bool
|
||||
condexpand(pic_state *pic, pic_value clause)
|
||||
{
|
||||
pic_sym tag;
|
||||
pic_value c, feature;
|
||||
|
||||
if (pic_eq_p(clause, pic_sym_value(pic->sELSE))) {
|
||||
return true;
|
||||
}
|
||||
if (pic_sym_p(clause)) {
|
||||
pic_for_each (feature, pic->features) {
|
||||
if(pic_eq_p(feature, clause))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! (pic_pair_p(clause) && pic_sym_p(pic_car(pic, clause)))) {
|
||||
pic_errorf(pic, "invalid 'cond-expand' clause ~s", clause);
|
||||
} else {
|
||||
tag = pic_sym(pic_car(pic, clause));
|
||||
}
|
||||
|
||||
if (tag == pic->sLIBRARY) {
|
||||
return pic_find_library(pic, pic_list_ref(pic, clause, 1)) != NULL;
|
||||
}
|
||||
if (tag == pic->sNOT) {
|
||||
return ! condexpand(pic, pic_list_ref(pic, clause, 1));
|
||||
}
|
||||
if (tag == pic->sAND) {
|
||||
pic_for_each (c, pic_cdr(pic, clause)) {
|
||||
if (! condexpand(pic, c))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (tag == pic->sOR) {
|
||||
pic_for_each (c, pic_cdr(pic, clause)) {
|
||||
if (condexpand(pic, c))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pic_errorf(pic, "unknown 'cond-expand' directive ~s", clause);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_lib_condexpand(pic_state *pic)
|
||||
{
|
||||
pic_value *clauses;
|
||||
size_t argc, i;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &clauses);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (condexpand(pic, pic_car(pic, clauses[i]))) {
|
||||
return pic_cons(pic, pic_sym_value(pic->rBEGIN), pic_cdr(pic, clauses[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_lib_import(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
import(pic, argv[i]);
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_lib_export(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
export(pic, argv[i]);
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_lib_define_library(pic_state *pic)
|
||||
{
|
||||
struct pic_lib *prev = pic->lib;
|
||||
size_t argc, i;
|
||||
pic_value spec, *argv;
|
||||
|
||||
pic_get_args(pic, "o*", &spec, &argc, &argv);
|
||||
|
||||
pic_open_library(pic, spec);
|
||||
|
||||
pic_try {
|
||||
pic_in_library(pic, spec);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_void(pic_eval(pic, argv[i], pic->lib));
|
||||
}
|
||||
|
||||
pic_in_library(pic, prev->name);
|
||||
}
|
||||
pic_catch {
|
||||
pic_in_library(pic, prev->name); /* restores pic->lib even if an error occurs */
|
||||
pic_raise(pic, pic->err);
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_lib_in_library(pic_state *pic)
|
||||
{
|
||||
pic_value spec;
|
||||
|
||||
pic_get_args(pic, "o", &spec);
|
||||
|
||||
pic_in_library(pic, spec);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_lib(pic_state *pic)
|
||||
{
|
||||
void pic_defmacro(pic_state *, pic_sym, pic_sym, pic_func_t);
|
||||
|
||||
pic_defmacro(pic, pic->sCOND_EXPAND, pic->rCOND_EXPAND, pic_lib_condexpand);
|
||||
pic_defmacro(pic, pic->sIMPORT, pic->rIMPORT, pic_lib_import);
|
||||
pic_defmacro(pic, pic->sEXPORT, pic->rEXPORT, pic_lib_export);
|
||||
pic_defmacro(pic, pic->sDEFINE_LIBRARY, pic->rDEFINE_LIBRARY, pic_lib_define_library);
|
||||
pic_defmacro(pic, pic->sIN_LIBRARY, pic->rIN_LIBRARY, pic_lib_in_library);
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/error.h"
|
||||
|
||||
static void
|
||||
pic_load_port(pic_state *pic, struct pic_port *port)
|
||||
{
|
||||
pic_value form;
|
||||
|
||||
pic_try {
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
|
||||
while (! pic_eof_p(form = pic_read(pic, port))) {
|
||||
pic_eval(pic, form, pic->lib);
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
}
|
||||
}
|
||||
pic_catch {
|
||||
pic_errorf(pic, "load error: %s", pic_errmsg(pic));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pic_load_cstr(pic_state *pic, const char *src)
|
||||
{
|
||||
struct pic_port *port = pic_open_input_string(pic, src);
|
||||
|
||||
pic_load_port(pic, port);
|
||||
|
||||
pic_close_port(pic, port);
|
||||
}
|
||||
|
||||
void
|
||||
pic_load(pic_state *pic, const char *filename)
|
||||
{
|
||||
struct pic_port *port;
|
||||
xFILE *file;
|
||||
|
||||
file = xfopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
pic_errorf(pic, "could not open file: %s", filename);
|
||||
}
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port), PIC_TT_PORT);
|
||||
port->file = file;
|
||||
port->flags = PIC_PORT_IN | PIC_PORT_TEXT;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
|
||||
pic_load_port(pic, port);
|
||||
|
||||
pic_close_port(pic, port);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_load_load(pic_state *pic)
|
||||
{
|
||||
pic_value envid;
|
||||
char *fn;
|
||||
|
||||
pic_get_args(pic, "z|o", &fn, &envid);
|
||||
|
||||
pic_load(pic, fn);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_load(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "load", pic_load_load);
|
||||
}
|
||||
|
|
@ -0,0 +1,506 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/macro.h"
|
||||
#include "picrin/lib.h"
|
||||
#include "picrin/error.h"
|
||||
#include "picrin/dict.h"
|
||||
#include "picrin/cont.h"
|
||||
|
||||
pic_sym
|
||||
pic_add_rename(pic_state *pic, struct pic_senv *senv, pic_sym sym)
|
||||
{
|
||||
pic_sym rename;
|
||||
|
||||
rename = pic_gensym(pic, sym);
|
||||
pic_put_rename(pic, senv, sym, rename);
|
||||
return rename;
|
||||
}
|
||||
|
||||
void
|
||||
pic_put_rename(pic_state *pic, struct pic_senv *senv, pic_sym sym, pic_sym rename)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
xh_put_int(&senv->map, sym, &rename);
|
||||
}
|
||||
|
||||
bool
|
||||
pic_find_rename(pic_state *pic, struct pic_senv *senv, pic_sym sym, pic_sym *rename)
|
||||
{
|
||||
xh_entry *e;
|
||||
|
||||
UNUSED(pic);
|
||||
|
||||
if ((e = xh_get_int(&senv->map, sym)) == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (rename != NULL) {
|
||||
*rename = xh_val(e, pic_sym);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
define_macro(pic_state *pic, pic_sym rename, struct pic_proc *proc, struct pic_senv *senv)
|
||||
{
|
||||
struct pic_macro *mac;
|
||||
|
||||
mac = (struct pic_macro *)pic_obj_alloc(pic, sizeof(struct pic_macro), PIC_TT_MACRO);
|
||||
mac->senv = senv;
|
||||
mac->proc = proc;
|
||||
|
||||
xh_put_int(&pic->macros, rename, &mac);
|
||||
}
|
||||
|
||||
static struct pic_macro *
|
||||
find_macro(pic_state *pic, pic_sym rename)
|
||||
{
|
||||
xh_entry *e;
|
||||
|
||||
if ((e = xh_get_int(&pic->macros, rename)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return xh_val(e, struct pic_macro *);
|
||||
}
|
||||
|
||||
static pic_sym
|
||||
make_identifier(pic_state *pic, pic_sym sym, struct pic_senv *senv)
|
||||
{
|
||||
pic_sym rename;
|
||||
|
||||
while (true) {
|
||||
if (pic_find_rename(pic, senv, sym, &rename)) {
|
||||
return rename;
|
||||
}
|
||||
if (! senv->up)
|
||||
break;
|
||||
senv = senv->up;
|
||||
}
|
||||
if (! pic_interned_p(pic, sym)) {
|
||||
return sym;
|
||||
}
|
||||
else {
|
||||
return pic_gensym(pic, sym);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value macroexpand(pic_state *, pic_value, struct pic_senv *);
|
||||
static pic_value macroexpand_lambda(pic_state *, pic_value, struct pic_senv *);
|
||||
|
||||
static pic_value
|
||||
macroexpand_symbol(pic_state *pic, pic_sym sym, struct pic_senv *senv)
|
||||
{
|
||||
return pic_sym_value(make_identifier(pic, sym, senv));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_quote(pic_state *pic, pic_value expr)
|
||||
{
|
||||
return pic_cons(pic, pic_sym_value(pic->rQUOTE), pic_cdr(pic, expr));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_list(pic_state *pic, pic_value obj, struct pic_senv *senv)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value x, head, tail;
|
||||
|
||||
if (pic_pair_p(obj)) {
|
||||
head = macroexpand(pic, pic_car(pic, obj), senv);
|
||||
tail = macroexpand_list(pic, pic_cdr(pic, obj), senv);
|
||||
x = pic_cons(pic, head, tail);
|
||||
} else {
|
||||
x = macroexpand(pic, obj, senv);
|
||||
}
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_defer(pic_state *pic, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
pic_value skel = pic_list1(pic, pic_none_value()); /* (#<none>) */
|
||||
|
||||
pic_push(pic, pic_cons(pic, expr, skel), senv->defer);
|
||||
|
||||
return skel;
|
||||
}
|
||||
|
||||
static void
|
||||
macroexpand_deferred(pic_state *pic, struct pic_senv *senv)
|
||||
{
|
||||
pic_value defer, val, src, dst;
|
||||
|
||||
pic_for_each (defer, pic_reverse(pic, senv->defer)) {
|
||||
src = pic_car(pic, defer);
|
||||
dst = pic_cdr(pic, defer);
|
||||
|
||||
val = macroexpand_lambda(pic, src, senv);
|
||||
|
||||
/* copy */
|
||||
pic_pair_ptr(dst)->car = pic_car(pic, val);
|
||||
pic_pair_ptr(dst)->cdr = pic_cdr(pic, val);
|
||||
}
|
||||
|
||||
senv->defer = pic_nil_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_lambda(pic_state *pic, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
pic_value formal, body;
|
||||
struct pic_senv *in;
|
||||
pic_value a;
|
||||
|
||||
if (pic_length(pic, expr) < 2) {
|
||||
pic_errorf(pic, "syntax error");
|
||||
}
|
||||
|
||||
in = pic_make_senv(pic, senv);
|
||||
|
||||
for (a = pic_cadr(pic, expr); pic_pair_p(a); a = pic_cdr(pic, a)) {
|
||||
pic_value v = pic_car(pic, a);
|
||||
|
||||
if (! pic_sym_p(v)) {
|
||||
pic_errorf(pic, "syntax error");
|
||||
}
|
||||
pic_add_rename(pic, in, pic_sym(v));
|
||||
}
|
||||
if (pic_sym_p(a)) {
|
||||
pic_add_rename(pic, in, pic_sym(a));
|
||||
}
|
||||
else if (! pic_nil_p(a)) {
|
||||
pic_errorf(pic, "syntax error");
|
||||
}
|
||||
|
||||
formal = macroexpand_list(pic, pic_cadr(pic, expr), in);
|
||||
body = macroexpand_list(pic, pic_cddr(pic, expr), in);
|
||||
|
||||
macroexpand_deferred(pic, in);
|
||||
|
||||
return pic_cons(pic, pic_sym_value(pic->rLAMBDA), pic_cons(pic, formal, body));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_define(pic_state *pic, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
pic_sym sym, rename;
|
||||
pic_value var, val;
|
||||
|
||||
while (pic_length(pic, expr) >= 2 && pic_pair_p(pic_cadr(pic, expr))) {
|
||||
var = pic_car(pic, pic_cadr(pic, expr));
|
||||
val = pic_cdr(pic, pic_cadr(pic, expr));
|
||||
|
||||
expr = pic_list3(pic, pic_sym_value(pic->rDEFINE), var, pic_cons(pic, pic_sym_value(pic->rLAMBDA), pic_cons(pic, val, pic_cddr(pic, expr))));
|
||||
}
|
||||
|
||||
if (pic_length(pic, expr) != 3) {
|
||||
pic_errorf(pic, "syntax error");
|
||||
}
|
||||
|
||||
var = pic_cadr(pic, expr);
|
||||
if (! pic_sym_p(var)) {
|
||||
pic_errorf(pic, "binding to non-symbol object");
|
||||
}
|
||||
sym = pic_sym(var);
|
||||
if (! pic_find_rename(pic, senv, sym, &rename)) {
|
||||
rename = pic_add_rename(pic, senv, sym);
|
||||
}
|
||||
val = macroexpand(pic, pic_list_ref(pic, expr, 2), senv);
|
||||
|
||||
return pic_list3(pic, pic_sym_value(pic->rDEFINE), pic_sym_value(rename), val);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_defsyntax(pic_state *pic, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
pic_value var, val;
|
||||
pic_sym sym, rename;
|
||||
|
||||
if (pic_length(pic, expr) != 3) {
|
||||
pic_errorf(pic, "syntax error");
|
||||
}
|
||||
|
||||
var = pic_cadr(pic, expr);
|
||||
if (! pic_sym_p(var)) {
|
||||
pic_errorf(pic, "binding to non-symbol object");
|
||||
}
|
||||
sym = pic_sym(var);
|
||||
if (! pic_find_rename(pic, senv, sym, &rename)) {
|
||||
rename = pic_add_rename(pic, senv, sym);
|
||||
} else {
|
||||
pic_warnf(pic, "redefining syntax variable: ~s", pic_sym_value(sym));
|
||||
}
|
||||
|
||||
val = pic_cadr(pic, pic_cdr(pic, expr));
|
||||
|
||||
pic_try {
|
||||
val = pic_eval(pic, val, pic->lib);
|
||||
} pic_catch {
|
||||
pic_errorf(pic, "macroexpand error while definition: %s", pic_errmsg(pic));
|
||||
}
|
||||
|
||||
if (! pic_proc_p(val)) {
|
||||
pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var);
|
||||
}
|
||||
|
||||
define_macro(pic, rename, pic_proc_ptr(val), senv);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_macro(pic_state *pic, struct pic_macro *mac, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
pic_value v, args;
|
||||
|
||||
#if DEBUG
|
||||
puts("before expand-1:");
|
||||
pic_debug(pic, expr);
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
if (mac->senv == NULL) { /* legacy macro */
|
||||
args = pic_cdr(pic, expr);
|
||||
} else {
|
||||
args = pic_list3(pic, expr, pic_obj_value(senv), pic_obj_value(mac->senv));
|
||||
}
|
||||
|
||||
pic_try {
|
||||
v = pic_apply(pic, mac->proc, args);
|
||||
} pic_catch {
|
||||
pic_errorf(pic, "macroexpand error while application: %s", pic_errmsg(pic));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
puts("after expand-1:");
|
||||
pic_debug(pic, v);
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand_node(pic_state *pic, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
switch (pic_type(expr)) {
|
||||
case PIC_TT_SYMBOL: {
|
||||
return macroexpand_symbol(pic, pic_sym(expr), senv);
|
||||
}
|
||||
case PIC_TT_PAIR: {
|
||||
pic_value car;
|
||||
struct pic_macro *mac;
|
||||
|
||||
if (! pic_list_p(expr)) {
|
||||
pic_errorf(pic, "cannot macroexpand improper list: ~s", expr);
|
||||
}
|
||||
|
||||
car = macroexpand(pic, pic_car(pic, expr), senv);
|
||||
if (pic_sym_p(car)) {
|
||||
pic_sym tag = pic_sym(car);
|
||||
|
||||
if (tag == pic->rDEFINE_SYNTAX) {
|
||||
return macroexpand_defsyntax(pic, expr, senv);
|
||||
}
|
||||
else if (tag == pic->rLAMBDA) {
|
||||
return macroexpand_defer(pic, expr, senv);
|
||||
}
|
||||
else if (tag == pic->rDEFINE) {
|
||||
return macroexpand_define(pic, expr, senv);
|
||||
}
|
||||
else if (tag == pic->rQUOTE) {
|
||||
return macroexpand_quote(pic, expr);
|
||||
}
|
||||
|
||||
if ((mac = find_macro(pic, tag)) != NULL) {
|
||||
return macroexpand_node(pic, macroexpand_macro(pic, mac, expr, senv), senv);
|
||||
}
|
||||
}
|
||||
|
||||
return pic_cons(pic, car, macroexpand_list(pic, pic_cdr(pic, expr), senv));
|
||||
}
|
||||
default:
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value v;
|
||||
|
||||
#if DEBUG
|
||||
printf("[macroexpand] expanding... ");
|
||||
pic_debug(pic, expr);
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
v = macroexpand_node(pic, expr, senv);
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_macroexpand(pic_state *pic, pic_value expr, struct pic_lib *lib)
|
||||
{
|
||||
struct pic_lib *prev;
|
||||
pic_value v;
|
||||
|
||||
#if DEBUG
|
||||
puts("before expand:");
|
||||
pic_debug(pic, expr);
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
/* change library for macro-expansion time processing */
|
||||
prev = pic->lib;
|
||||
pic->lib = lib;
|
||||
|
||||
lib->env->defer = pic_nil_value(); /* the last expansion could fail and leave defer field old */
|
||||
|
||||
v = macroexpand(pic, expr, lib->env);
|
||||
|
||||
macroexpand_deferred(pic, lib->env);
|
||||
|
||||
pic->lib = prev;
|
||||
|
||||
#if DEBUG
|
||||
puts("after expand:");
|
||||
pic_debug(pic, v);
|
||||
puts("");
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct pic_senv *
|
||||
pic_make_senv(pic_state *pic, struct pic_senv *up)
|
||||
{
|
||||
struct pic_senv *senv;
|
||||
|
||||
senv = (struct pic_senv *)pic_obj_alloc(pic, sizeof(struct pic_senv), PIC_TT_SENV);
|
||||
senv->up = up;
|
||||
senv->defer = pic_nil_value();
|
||||
xh_init_int(&senv->map, sizeof(pic_sym));
|
||||
|
||||
return senv;
|
||||
}
|
||||
|
||||
struct pic_senv *
|
||||
pic_null_syntactic_environment(pic_state *pic)
|
||||
{
|
||||
struct pic_senv *senv;
|
||||
|
||||
senv = pic_make_senv(pic, NULL);
|
||||
|
||||
pic_define_syntactic_keyword(pic, senv, pic->sDEFINE_LIBRARY, pic->rDEFINE_LIBRARY);
|
||||
pic_define_syntactic_keyword(pic, senv, pic->sIMPORT, pic->rIMPORT);
|
||||
pic_define_syntactic_keyword(pic, senv, pic->sEXPORT, pic->rEXPORT);
|
||||
pic_define_syntactic_keyword(pic, senv, pic->sIN_LIBRARY, pic->rIN_LIBRARY);
|
||||
pic_define_syntactic_keyword(pic, senv, pic->sCOND_EXPAND, pic->rCOND_EXPAND);
|
||||
|
||||
return senv;
|
||||
}
|
||||
|
||||
void
|
||||
pic_define_syntactic_keyword(pic_state *pic, struct pic_senv *senv, pic_sym sym, pic_sym rsym)
|
||||
{
|
||||
pic_put_rename(pic, senv, sym, rsym);
|
||||
|
||||
if (pic->lib && pic->lib->env == senv) {
|
||||
pic_export(pic, sym);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pic_defmacro(pic_state *pic, pic_sym name, pic_sym id, pic_func_t func)
|
||||
{
|
||||
pic_put_rename(pic, pic->lib->env, name, id);
|
||||
|
||||
/* symbol registration */
|
||||
define_macro(pic, id, pic_make_proc(pic, func, pic_symbol_name(pic, name)), NULL);
|
||||
|
||||
/* auto export! */
|
||||
pic_export(pic, name);
|
||||
}
|
||||
|
||||
bool
|
||||
pic_identifier_p(pic_state *pic, pic_value obj)
|
||||
{
|
||||
return pic_sym_p(obj) && ! pic_interned_p(pic, pic_sym(obj));
|
||||
}
|
||||
|
||||
bool
|
||||
pic_identifier_eq_p(pic_state *pic, struct pic_senv *env1, pic_sym sym1, struct pic_senv *env2, pic_sym sym2)
|
||||
{
|
||||
pic_sym a, b;
|
||||
|
||||
a = make_identifier(pic, sym1, env1);
|
||||
if (a != make_identifier(pic, sym1, env1)) {
|
||||
a = sym1;
|
||||
}
|
||||
|
||||
b = make_identifier(pic, sym2, env2);
|
||||
if (b != make_identifier(pic, sym2, env2)) {
|
||||
b = sym2;
|
||||
}
|
||||
|
||||
return pic_eq_p(pic_sym_value(a), pic_sym_value(b));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_macro_identifier_p(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
|
||||
pic_get_args(pic, "o", &obj);
|
||||
|
||||
return pic_bool_value(pic_identifier_p(pic, obj));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_macro_make_identifier(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
pic_sym sym;
|
||||
|
||||
pic_get_args(pic, "mo", &sym, &obj);
|
||||
|
||||
pic_assert_type(pic, obj, senv);
|
||||
|
||||
return pic_sym_value(make_identifier(pic, sym, pic_senv_ptr(obj)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_macro_identifier_eq_p(pic_state *pic)
|
||||
{
|
||||
pic_sym sym1, sym2;
|
||||
pic_value env1, env2;
|
||||
|
||||
pic_get_args(pic, "omom", &env1, &sym1, &env2, &sym2);
|
||||
|
||||
pic_assert_type(pic, env1, senv);
|
||||
pic_assert_type(pic, env2, senv);
|
||||
|
||||
return pic_bool_value(pic_identifier_eq_p(pic, pic_senv_ptr(env1), sym1, pic_senv_ptr(env2), sym2));
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_macro(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "identifier?", pic_macro_identifier_p);
|
||||
pic_defun(pic, "identifier=?", pic_macro_identifier_eq_p);
|
||||
pic_defun(pic, "make-identifier", pic_macro_make_identifier);
|
||||
}
|
||||
|
|
@ -0,0 +1,647 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/cont.h"
|
||||
|
||||
/**
|
||||
* Returns the length of string representing val.
|
||||
* radix is between 2 and 36 (inclusive).
|
||||
* No error checks are performed in this function.
|
||||
*/
|
||||
static int
|
||||
number_string_length(int val, int radix)
|
||||
{
|
||||
long long v = val; /* in case val == INT_MIN */
|
||||
int count = 0;
|
||||
if (val == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (val < 0) {
|
||||
v = - v;
|
||||
count = 1;
|
||||
}
|
||||
while (v > 0) {
|
||||
++count;
|
||||
v /= radix;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representing val.
|
||||
* radix is between 2 and 36 (inclusive).
|
||||
* This function overwrites buffer and stores the result.
|
||||
* No error checks are performed in this function. It is caller's responsibility to avoid buffer-overrun.
|
||||
*/
|
||||
static void
|
||||
number_string(int val, int radix, int length, char *buffer) {
|
||||
const char digits[37] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
long long v = val;
|
||||
int i;
|
||||
if (val == 0) {
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '\0';
|
||||
return;
|
||||
}
|
||||
if (val < 0) {
|
||||
buffer[0] = '-';
|
||||
v = -v;
|
||||
}
|
||||
|
||||
for(i = length - 1; v > 0; --i) {
|
||||
buffer[i] = digits[v % radix];
|
||||
v /= radix;
|
||||
}
|
||||
buffer[length] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_real_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_float_p(v) || pic_int_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_integer_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_int_p(v)) {
|
||||
return pic_true_value();
|
||||
}
|
||||
if (pic_float_p(v)) {
|
||||
double f = pic_float(v);
|
||||
|
||||
if (isinf(f)) {
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
if (f == round(f)) {
|
||||
return pic_true_value();
|
||||
}
|
||||
}
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_exact_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_int_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_inexact_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_float_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_finite_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_int_p(v))
|
||||
return pic_true_value();
|
||||
if (pic_float_p(v) && ! (isinf(pic_float(v)) || isnan(pic_float(v))))
|
||||
return pic_true_value();
|
||||
else
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_infinite_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_float_p(v) && isinf(pic_float(v)))
|
||||
return pic_true_value();
|
||||
else
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_nan_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_float_p(v) && isnan(pic_float(v)))
|
||||
return pic_true_value();
|
||||
else
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
#define DEFINE_ARITH_CMP(op, name) \
|
||||
static pic_value \
|
||||
pic_number_##name(pic_state *pic) \
|
||||
{ \
|
||||
size_t argc, i; \
|
||||
pic_value *argv; \
|
||||
double f,g; \
|
||||
\
|
||||
pic_get_args(pic, "ff*", &f, &g, &argc, &argv); \
|
||||
\
|
||||
if (! (f op g)) \
|
||||
return pic_false_value(); \
|
||||
\
|
||||
for (i = 0; i < argc; ++i) { \
|
||||
f = g; \
|
||||
if (pic_float_p(argv[i])) \
|
||||
g = pic_float(argv[i]); \
|
||||
else if (pic_int_p(argv[i])) \
|
||||
g = pic_int(argv[i]); \
|
||||
else \
|
||||
pic_errorf(pic, #op ": number required"); \
|
||||
\
|
||||
if (! (f op g)) \
|
||||
return pic_false_value(); \
|
||||
} \
|
||||
\
|
||||
return pic_true_value(); \
|
||||
}
|
||||
|
||||
DEFINE_ARITH_CMP(==, eq)
|
||||
DEFINE_ARITH_CMP(<, lt)
|
||||
DEFINE_ARITH_CMP(>, gt)
|
||||
DEFINE_ARITH_CMP(<=, le)
|
||||
DEFINE_ARITH_CMP(>=, ge)
|
||||
|
||||
#define DEFINE_ARITH_OP(op, name, unit) \
|
||||
static pic_value \
|
||||
pic_number_##name(pic_state *pic) \
|
||||
{ \
|
||||
size_t argc, i; \
|
||||
pic_value *argv; \
|
||||
double f; \
|
||||
bool e = true; \
|
||||
\
|
||||
pic_get_args(pic, "*", &argc, &argv); \
|
||||
\
|
||||
f = unit; \
|
||||
for (i = 0; i < argc; ++i) { \
|
||||
if (pic_int_p(argv[i])) { \
|
||||
f op##= pic_int(argv[i]); \
|
||||
} \
|
||||
else if (pic_float_p(argv[i])) { \
|
||||
e = false; \
|
||||
f op##= pic_float(argv[i]); \
|
||||
} \
|
||||
else { \
|
||||
pic_errorf(pic, #op ": number required"); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return e ? pic_int_value((int)f) : pic_float_value(f); \
|
||||
}
|
||||
|
||||
DEFINE_ARITH_OP(+, add, 0)
|
||||
DEFINE_ARITH_OP(*, mul, 1)
|
||||
|
||||
#define DEFINE_ARITH_INV_OP(op, name, unit, exact) \
|
||||
static pic_value \
|
||||
pic_number_##name(pic_state *pic) \
|
||||
{ \
|
||||
size_t argc, i; \
|
||||
pic_value *argv; \
|
||||
double f; \
|
||||
bool e; \
|
||||
\
|
||||
pic_get_args(pic, "F*", &f, &e, &argc, &argv); \
|
||||
\
|
||||
e = e && exact; \
|
||||
\
|
||||
if (argc == 0) { \
|
||||
f = unit op f; \
|
||||
} \
|
||||
for (i = 0; i < argc; ++i) { \
|
||||
if (pic_int_p(argv[i])) { \
|
||||
f op##= pic_int(argv[i]); \
|
||||
} \
|
||||
else if (pic_float_p(argv[i])) { \
|
||||
e = false; \
|
||||
f op##= pic_float(argv[i]); \
|
||||
} \
|
||||
else { \
|
||||
pic_errorf(pic, #op ": number required"); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return e ? pic_int_value((int)f) : pic_float_value(f); \
|
||||
}
|
||||
|
||||
DEFINE_ARITH_INV_OP(-, sub, 0, true)
|
||||
DEFINE_ARITH_INV_OP(/, div, 1, false)
|
||||
|
||||
static pic_value
|
||||
pic_number_abs(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
bool e;
|
||||
|
||||
pic_get_args(pic, "F", &f, &e);
|
||||
|
||||
if (e) {
|
||||
return pic_int_value(abs((int)f));
|
||||
}
|
||||
else {
|
||||
return pic_float_value(fabs(f));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_floor2(pic_state *pic)
|
||||
{
|
||||
int i, j;
|
||||
bool e1, e2;
|
||||
|
||||
pic_get_args(pic, "II", &i, &e1, &j, &e2);
|
||||
|
||||
if (e1 && e2) {
|
||||
int k;
|
||||
|
||||
k = (i < 0 && j < 0) || (0 <= i && 0 <= j)
|
||||
? i / j
|
||||
: (i / j) - 1;
|
||||
|
||||
return pic_values2(pic, pic_int_value(k), pic_int_value(i - k * j));
|
||||
}
|
||||
else {
|
||||
double q, r;
|
||||
|
||||
q = floor((double)i/j);
|
||||
r = i - j * q;
|
||||
return pic_values2(pic, pic_float_value(q), pic_float_value(r));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_trunc2(pic_state *pic)
|
||||
{
|
||||
int i, j;
|
||||
bool e1, e2;
|
||||
|
||||
pic_get_args(pic, "II", &i, &e1, &j, &e2);
|
||||
|
||||
if (e1 && e2) {
|
||||
return pic_values2(pic, pic_int_value(i/j), pic_int_value(i - (i/j) * j));
|
||||
}
|
||||
else {
|
||||
double q, r;
|
||||
|
||||
q = trunc((double)i/j);
|
||||
r = i - j * q;
|
||||
|
||||
return pic_values2(pic, pic_float_value(q), pic_float_value(r));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_floor(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
bool e;
|
||||
|
||||
pic_get_args(pic, "F", &f, &e);
|
||||
|
||||
if (e) {
|
||||
return pic_int_value((int)f);
|
||||
}
|
||||
else {
|
||||
return pic_float_value(floor(f));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_ceil(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
bool e;
|
||||
|
||||
pic_get_args(pic, "F", &f, &e);
|
||||
|
||||
if (e) {
|
||||
return pic_int_value((int)f);
|
||||
}
|
||||
else {
|
||||
return pic_float_value(ceil(f));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_trunc(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
bool e;
|
||||
|
||||
pic_get_args(pic, "F", &f, &e);
|
||||
|
||||
if (e) {
|
||||
return pic_int_value((int)f);
|
||||
}
|
||||
else {
|
||||
return pic_float_value(trunc(f));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_round(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
bool e;
|
||||
|
||||
pic_get_args(pic, "F", &f, &e);
|
||||
|
||||
if (e) {
|
||||
return pic_int_value((int)f);
|
||||
}
|
||||
else {
|
||||
return pic_float_value(round(f));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_exp(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
return pic_float_value(exp(f));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_log(pic_state *pic)
|
||||
{
|
||||
double f,g;
|
||||
int argc;
|
||||
|
||||
argc = pic_get_args(pic, "f|f", &f, &g);
|
||||
if (argc == 1) {
|
||||
return pic_float_value(log(f));
|
||||
}
|
||||
else {
|
||||
return pic_float_value(log(f) / log(g));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_sin(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
f = sin(f);
|
||||
return pic_float_value(f);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_cos(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
f = cos(f);
|
||||
return pic_float_value(f);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_tan(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
f = tan(f);
|
||||
return pic_float_value(f);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_acos(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
f = acos(f);
|
||||
return pic_float_value(f);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_asin(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
f = asin(f);
|
||||
return pic_float_value(f);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_atan(pic_state *pic)
|
||||
{
|
||||
double f,g;
|
||||
int argc;
|
||||
|
||||
argc = pic_get_args(pic, "f|f", &f, &g);
|
||||
if (argc == 1) {
|
||||
f = atan(f);
|
||||
return pic_float_value(f);
|
||||
}
|
||||
else {
|
||||
return pic_float_value(atan2(f,g));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_sqrt(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
|
||||
return pic_float_value(sqrt(f));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_expt(pic_state *pic)
|
||||
{
|
||||
double f, g, h;
|
||||
bool e1, e2;
|
||||
|
||||
pic_get_args(pic, "FF", &f, &e1, &g, &e2);
|
||||
|
||||
h = pow(f, g);
|
||||
if (e1 && e2) {
|
||||
if (h <= INT_MAX) {
|
||||
return pic_int_value((int)h);
|
||||
}
|
||||
}
|
||||
return pic_float_value(h);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_inexact(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
|
||||
return pic_float_value(f);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_exact(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
|
||||
pic_get_args(pic, "f", &f);
|
||||
|
||||
return pic_int_value((int)(round(f)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_number_to_string(pic_state *pic)
|
||||
{
|
||||
double f;
|
||||
bool e;
|
||||
int radix = 10;
|
||||
|
||||
pic_get_args(pic, "F|i", &f, &e, &radix);
|
||||
|
||||
if (radix < 2 || radix > 36) {
|
||||
pic_errorf(pic, "number->string: invalid radix %d (between 2 and 36, inclusive)", radix);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
int ival = (int) f;
|
||||
int ilen = number_string_length(ival, radix);
|
||||
char buf[ilen + 1];
|
||||
|
||||
number_string(ival, radix, ilen, buf);
|
||||
|
||||
return pic_obj_value(pic_make_str(pic, buf, sizeof buf - 1));
|
||||
}
|
||||
else {
|
||||
char buf[snprintf(NULL, 0, "%f", f) + 1];
|
||||
|
||||
snprintf(buf, sizeof buf, "%f", f);
|
||||
|
||||
return pic_obj_value(pic_make_str(pic, buf, sizeof buf - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_number_string_to_number(pic_state *pic)
|
||||
{
|
||||
const char *str;
|
||||
int radix = 10;
|
||||
long num;
|
||||
char *eptr;
|
||||
double flo;
|
||||
|
||||
pic_get_args(pic, "z|i", &str, &radix);
|
||||
|
||||
num = strtol(str, &eptr, radix);
|
||||
if (*eptr == '\0') {
|
||||
return pic_valid_int(num)
|
||||
? pic_int_value((int)num)
|
||||
: pic_float_value(num);
|
||||
}
|
||||
|
||||
flo = strtod(str, &eptr);
|
||||
if (*eptr == '\0') {
|
||||
return pic_float_value(flo);
|
||||
}
|
||||
|
||||
pic_errorf(pic, "invalid string given: %s", str);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_number(pic_state *pic)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
|
||||
pic_defun(pic, "number?", pic_number_real_p);
|
||||
pic_defun(pic, "complex?", pic_number_real_p);
|
||||
pic_defun(pic, "real?", pic_number_real_p);
|
||||
pic_defun(pic, "rational?", pic_number_real_p);
|
||||
pic_defun(pic, "integer?", pic_number_integer_p);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "exact?", pic_number_exact_p);
|
||||
pic_defun(pic, "inexact?", pic_number_inexact_p);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "=", pic_number_eq);
|
||||
pic_defun(pic, "<", pic_number_lt);
|
||||
pic_defun(pic, ">", pic_number_gt);
|
||||
pic_defun(pic, "<=", pic_number_le);
|
||||
pic_defun(pic, ">=", pic_number_ge);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "+", pic_number_add);
|
||||
pic_defun(pic, "-", pic_number_sub);
|
||||
pic_defun(pic, "*", pic_number_mul);
|
||||
pic_defun(pic, "/", pic_number_div);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "floor/", pic_number_floor2);
|
||||
pic_defun(pic, "truncate/", pic_number_trunc2);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "floor", pic_number_floor);
|
||||
pic_defun(pic, "ceiling", pic_number_ceil);
|
||||
pic_defun(pic, "truncate", pic_number_trunc);
|
||||
pic_defun(pic, "round", pic_number_round);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "inexact", pic_number_inexact);
|
||||
pic_defun(pic, "exact", pic_number_exact);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "finite?", pic_number_finite_p);
|
||||
pic_defun(pic, "infinite?", pic_number_infinite_p);
|
||||
pic_defun(pic, "nan?", pic_number_nan_p);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "abs", pic_number_abs);
|
||||
pic_defun(pic, "sqrt", pic_number_sqrt);
|
||||
pic_defun(pic, "expt", pic_number_expt);
|
||||
pic_defun(pic, "exp", pic_number_exp);
|
||||
pic_defun(pic, "log", pic_number_log);
|
||||
pic_defun(pic, "sin", pic_number_sin);
|
||||
pic_defun(pic, "cos", pic_number_cos);
|
||||
pic_defun(pic, "tan", pic_number_tan);
|
||||
pic_defun(pic, "acos", pic_number_acos);
|
||||
pic_defun(pic, "asin", pic_number_asin);
|
||||
pic_defun(pic, "atan", pic_number_atan);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
pic_defun(pic, "number->string", pic_number_number_to_string);
|
||||
pic_defun(pic, "string->number", pic_number_string_to_number);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
}
|
||||
|
|
@ -0,0 +1,792 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
|
||||
pic_value
|
||||
pic_cons(pic_state *pic, pic_value car, pic_value cdr)
|
||||
{
|
||||
struct pic_pair *pair;
|
||||
|
||||
pair = (struct pic_pair *)pic_obj_alloc(pic, sizeof(struct pic_pair), PIC_TT_PAIR);
|
||||
pair->car = car;
|
||||
pair->cdr = cdr;
|
||||
|
||||
return pic_obj_value(pair);
|
||||
}
|
||||
|
||||
void
|
||||
pic_set_car(pic_state *pic, pic_value obj, pic_value val)
|
||||
{
|
||||
struct pic_pair *pair;
|
||||
|
||||
if (! pic_pair_p(obj)) {
|
||||
pic_errorf(pic, "pair required");
|
||||
}
|
||||
pair = pic_pair_ptr(obj);
|
||||
|
||||
pair->car = val;
|
||||
}
|
||||
|
||||
void
|
||||
pic_set_cdr(pic_state *pic, pic_value obj, pic_value val)
|
||||
{
|
||||
struct pic_pair *pair;
|
||||
|
||||
if (! pic_pair_p(obj)) {
|
||||
pic_errorf(pic, "pair required");
|
||||
}
|
||||
pair = pic_pair_ptr(obj);
|
||||
|
||||
pair->cdr = val;
|
||||
}
|
||||
|
||||
bool
|
||||
pic_list_p(pic_value obj)
|
||||
{
|
||||
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(rapid)) {
|
||||
rapid = pic_pair_ptr(rapid)->cdr;
|
||||
}
|
||||
else {
|
||||
return pic_nil_p(rapid);
|
||||
}
|
||||
}
|
||||
|
||||
/* advance local */
|
||||
local = pic_pair_ptr(local)->cdr;
|
||||
|
||||
if (pic_eq_p(local, rapid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list1(pic_state *pic, pic_value obj1)
|
||||
{
|
||||
return pic_cons(pic, obj1, pic_nil_value());
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list2(pic_state *pic, pic_value obj1, pic_value obj2)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value val;
|
||||
|
||||
val = pic_cons(pic, obj1, pic_list1(pic, obj2));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list3(pic_state *pic, pic_value obj1, pic_value obj2, pic_value obj3)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value val;
|
||||
|
||||
val = pic_cons(pic, obj1, pic_list2(pic, obj2, obj3));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list4(pic_state *pic, pic_value obj1, pic_value obj2, pic_value obj3, pic_value obj4)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value val;
|
||||
|
||||
val = pic_cons(pic, obj1, pic_list3(pic, obj2, obj3, obj4));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list5(pic_state *pic, pic_value obj1, pic_value obj2, pic_value obj3, pic_value obj4, pic_value obj5)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value val;
|
||||
|
||||
val = pic_cons(pic, obj1, pic_list4(pic, obj2, obj3, obj4, obj5));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list6(pic_state *pic, pic_value obj1, pic_value obj2, pic_value obj3, pic_value obj4, pic_value obj5, pic_value obj6)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value val;
|
||||
|
||||
val = pic_cons(pic, obj1, pic_list5(pic, obj2, obj3, obj4, obj5, obj6));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list7(pic_state *pic, pic_value obj1, pic_value obj2, pic_value obj3, pic_value obj4, pic_value obj5, pic_value obj6, pic_value obj7)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value val;
|
||||
|
||||
val = pic_cons(pic, obj1, pic_list6(pic, obj2, obj3, obj4, obj5, obj6, obj7));
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list_by_array(pic_state *pic, size_t c, pic_value *vs)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
v = pic_nil_value();
|
||||
while (c--) {
|
||||
v = pic_cons(pic, vs[c], v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_make_list(pic_state *pic, size_t k, pic_value fill)
|
||||
{
|
||||
pic_value list;
|
||||
size_t i;
|
||||
|
||||
list = pic_nil_value();
|
||||
for (i = 0; i < k; ++i) {
|
||||
list = pic_cons(pic, fill, list);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
size_t
|
||||
pic_length(pic_state *pic, pic_value obj)
|
||||
{
|
||||
size_t c = 0;
|
||||
|
||||
if (! pic_list_p(obj)) {
|
||||
pic_errorf(pic, "length: expected list, but got ~s", obj);
|
||||
}
|
||||
|
||||
while (! pic_nil_p(obj)) {
|
||||
obj = pic_cdr(pic, obj);
|
||||
++c;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_reverse(pic_state *pic, pic_value list)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value v, acc;
|
||||
|
||||
acc = pic_nil_value();
|
||||
pic_for_each(v, list) {
|
||||
acc = pic_cons(pic, v, acc);
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, acc);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_append(pic_state *pic, pic_value xs, pic_value ys)
|
||||
{
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
pic_value x;
|
||||
|
||||
xs = pic_reverse(pic, xs);
|
||||
pic_for_each (x, xs) {
|
||||
ys = pic_cons(pic, x, ys);
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, xs);
|
||||
pic_gc_protect(pic, ys);
|
||||
}
|
||||
return ys;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_memq(pic_state *pic, pic_value key, pic_value list)
|
||||
{
|
||||
enter:
|
||||
|
||||
if (pic_nil_p(list))
|
||||
return pic_false_value();
|
||||
|
||||
if (pic_eq_p(key, pic_car(pic, list)))
|
||||
return list;
|
||||
|
||||
list = pic_cdr(pic, list);
|
||||
goto enter;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_memv(pic_state *pic, pic_value key, pic_value list)
|
||||
{
|
||||
enter:
|
||||
|
||||
if (pic_nil_p(list))
|
||||
return pic_false_value();
|
||||
|
||||
if (pic_eqv_p(key, pic_car(pic, list)))
|
||||
return list;
|
||||
|
||||
list = pic_cdr(pic, list);
|
||||
goto enter;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_member(pic_state *pic, pic_value key, pic_value list, struct pic_proc *compar)
|
||||
{
|
||||
enter:
|
||||
|
||||
if (pic_nil_p(list))
|
||||
return pic_false_value();
|
||||
|
||||
if (compar == NULL) {
|
||||
if (pic_equal_p(pic, key, pic_car(pic, list)))
|
||||
return list;
|
||||
} else {
|
||||
if (pic_test(pic_apply2(pic, compar, key, pic_car(pic, list))))
|
||||
return list;
|
||||
}
|
||||
|
||||
list = pic_cdr(pic, list);
|
||||
goto enter;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_assq(pic_state *pic, pic_value key, pic_value assoc)
|
||||
{
|
||||
pic_value cell;
|
||||
|
||||
enter:
|
||||
|
||||
if (pic_nil_p(assoc))
|
||||
return pic_false_value();
|
||||
|
||||
cell = pic_car(pic, assoc);
|
||||
if (pic_eq_p(key, pic_car(pic, cell)))
|
||||
return cell;
|
||||
|
||||
assoc = pic_cdr(pic, assoc);
|
||||
goto enter;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_assv(pic_state *pic, pic_value key, pic_value assoc)
|
||||
{
|
||||
pic_value cell;
|
||||
|
||||
enter:
|
||||
|
||||
if (pic_nil_p(assoc))
|
||||
return pic_false_value();
|
||||
|
||||
cell = pic_car(pic, assoc);
|
||||
if (pic_eqv_p(key, pic_car(pic, cell)))
|
||||
return cell;
|
||||
|
||||
assoc = pic_cdr(pic, assoc);
|
||||
goto enter;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_assoc(pic_state *pic, pic_value key, pic_value assoc, struct pic_proc *compar)
|
||||
{
|
||||
pic_value cell;
|
||||
|
||||
enter:
|
||||
|
||||
if (pic_nil_p(assoc))
|
||||
return pic_false_value();
|
||||
|
||||
cell = pic_car(pic, assoc);
|
||||
if (compar == NULL) {
|
||||
if (pic_equal_p(pic, key, pic_car(pic, cell)))
|
||||
return cell;
|
||||
} else {
|
||||
if (pic_test(pic_apply2(pic, compar, key, pic_car(pic, cell))))
|
||||
return cell;
|
||||
}
|
||||
|
||||
assoc = pic_cdr(pic, assoc);
|
||||
goto enter;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_acons(pic_state *pic, pic_value key, pic_value val, pic_value assoc)
|
||||
{
|
||||
return pic_cons(pic, pic_cons(pic, key, val), assoc);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list_tail(pic_state *pic, pic_value list, size_t i)
|
||||
{
|
||||
while (i-- > 0) {
|
||||
list = pic_cdr(pic, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list_ref(pic_state *pic, pic_value list, size_t i)
|
||||
{
|
||||
return pic_car(pic, pic_list_tail(pic, list, i));
|
||||
}
|
||||
|
||||
void
|
||||
pic_list_set(pic_state *pic, pic_value list, size_t i, pic_value obj)
|
||||
{
|
||||
pic_pair_ptr(pic_list_tail(pic, list, i))->car = obj;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_list_copy(pic_state *pic, pic_value obj)
|
||||
{
|
||||
if (pic_pair_p(obj)) {
|
||||
return pic_cons(pic, pic_car(pic, obj), pic_list_copy(pic, pic_cdr(pic, obj)));
|
||||
}
|
||||
else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_pair_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_pair_p(v));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
pic_set_car(pic, v, w);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_set_cdr(pic_state *pic)
|
||||
{
|
||||
pic_value v,w;
|
||||
|
||||
pic_get_args(pic, "oo", &v, &w);
|
||||
|
||||
pic_set_cdr(pic, v, w);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_null_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_nil_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_list_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_list_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_make_list(pic_state *pic)
|
||||
{
|
||||
size_t i;
|
||||
pic_value fill = pic_none_value();
|
||||
|
||||
pic_get_args(pic, "k|o", &i, &fill);
|
||||
|
||||
return pic_make_list(pic, i, fill);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_list(pic_state *pic)
|
||||
{
|
||||
size_t argc;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
return pic_list_by_array(pic, argc, argv);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_length(pic_state *pic)
|
||||
{
|
||||
pic_value list;
|
||||
|
||||
pic_get_args(pic, "o", &list);
|
||||
|
||||
return pic_size_value(pic_length(pic, list));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_append(pic_state *pic)
|
||||
{
|
||||
size_t argc;
|
||||
pic_value *args, list;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &args);
|
||||
|
||||
if (argc == 0) {
|
||||
return pic_nil_value();
|
||||
}
|
||||
|
||||
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;
|
||||
size_t i;
|
||||
|
||||
pic_get_args(pic, "ok", &list, &i);
|
||||
|
||||
return pic_list_tail(pic, list, i);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_list_ref(pic_state *pic)
|
||||
{
|
||||
pic_value list;
|
||||
size_t i;
|
||||
|
||||
pic_get_args(pic, "ok", &list, &i);
|
||||
|
||||
return pic_list_ref(pic, list, i);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_list_set(pic_state *pic)
|
||||
{
|
||||
pic_value list, obj;
|
||||
size_t i;
|
||||
|
||||
pic_get_args(pic, "oko", &list, &i, &obj);
|
||||
|
||||
pic_list_set(pic, list, i, obj);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_list_copy(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
|
||||
pic_get_args(pic, "o", &obj);
|
||||
|
||||
return pic_list_copy(pic, obj);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_map(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
size_t argc, i;
|
||||
pic_value *args;
|
||||
pic_value arg, ret;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &args);
|
||||
|
||||
ret = pic_nil_value();
|
||||
do {
|
||||
arg = pic_nil_value();
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (! pic_pair_p(args[i])) {
|
||||
break;
|
||||
}
|
||||
pic_push(pic, pic_car(pic, args[i]), arg);
|
||||
args[i] = pic_cdr(pic, args[i]);
|
||||
}
|
||||
if (i != argc) {
|
||||
break;
|
||||
}
|
||||
pic_push(pic, pic_apply(pic, proc, pic_reverse(pic, arg)), ret);
|
||||
} while (1);
|
||||
|
||||
return pic_reverse(pic, ret);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_for_each(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
size_t argc, i;
|
||||
pic_value *args;
|
||||
pic_value arg;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &args);
|
||||
|
||||
do {
|
||||
arg = pic_nil_value();
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (! pic_pair_p(args[i])) {
|
||||
break;
|
||||
}
|
||||
pic_push(pic, pic_car(pic, args[i]), arg);
|
||||
args[i] = pic_cdr(pic, args[i]);
|
||||
}
|
||||
if (i != argc) {
|
||||
break;
|
||||
}
|
||||
pic_apply(pic, proc, pic_reverse(pic, arg));
|
||||
} while (1);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_memq(pic_state *pic)
|
||||
{
|
||||
pic_value key, list;
|
||||
|
||||
pic_get_args(pic, "oo", &key, &list);
|
||||
|
||||
return pic_memq(pic, key, list);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_memv(pic_state *pic)
|
||||
{
|
||||
pic_value key, list;
|
||||
|
||||
pic_get_args(pic, "oo", &key, &list);
|
||||
|
||||
return pic_memv(pic, key, list);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_member(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc = NULL;
|
||||
pic_value key, list;
|
||||
|
||||
pic_get_args(pic, "oo|l", &key, &list, &proc);
|
||||
|
||||
return pic_member(pic, key, list, proc);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_assq(pic_state *pic)
|
||||
{
|
||||
pic_value key, list;
|
||||
|
||||
pic_get_args(pic, "oo", &key, &list);
|
||||
|
||||
return pic_assq(pic, key, list);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_assv(pic_state *pic)
|
||||
{
|
||||
pic_value key, list;
|
||||
|
||||
pic_get_args(pic, "oo", &key, &list);
|
||||
|
||||
return pic_assv(pic, key, list);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_pair_assoc(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc = NULL;
|
||||
pic_value key, list;
|
||||
|
||||
pic_get_args(pic, "oo|l", &key, &list, &proc);
|
||||
|
||||
return pic_assoc(pic, key, list, proc);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_pair(pic_state *pic)
|
||||
{
|
||||
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, "set-car!", pic_pair_set_car);
|
||||
pic_defun(pic, "set-cdr!", pic_pair_set_cdr);
|
||||
pic_defun(pic, "null?", pic_pair_null_p);
|
||||
|
||||
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);
|
||||
pic_defun(pic, "map", pic_pair_map);
|
||||
pic_defun(pic, "for-each", pic_pair_for_each);
|
||||
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);
|
||||
}
|
||||
|
|
@ -0,0 +1,735 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/blob.h"
|
||||
|
||||
pic_value
|
||||
pic_eof_object()
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_init_value(v, PIC_VTYPE_EOF);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
struct pic_port *
|
||||
pic_stdin(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
|
||||
obj = pic_funcall(pic, pic->PICRIN_BASE, "current-input-port", pic_nil_value());
|
||||
|
||||
return pic_port_ptr(obj);
|
||||
}
|
||||
|
||||
struct pic_port *
|
||||
pic_stdout(pic_state *pic)
|
||||
{
|
||||
pic_value obj;
|
||||
|
||||
obj = pic_funcall(pic, pic->PICRIN_BASE, "current-output-port", pic_nil_value());
|
||||
|
||||
return pic_port_ptr(obj);
|
||||
}
|
||||
|
||||
struct pic_port *
|
||||
pic_make_standard_port(pic_state *pic, xFILE *file, short dir)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port), PIC_TT_PORT);
|
||||
port->file = file;
|
||||
port->flags = dir | PIC_PORT_TEXT;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
return port;
|
||||
}
|
||||
|
||||
struct pic_port *
|
||||
pic_open_input_string(pic_state *pic, const char *str)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||
port->file = xmopen();
|
||||
port->flags = PIC_PORT_IN | PIC_PORT_TEXT;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
|
||||
xfputs(str, port->file);
|
||||
xfflush(port->file);
|
||||
xrewind(port->file);
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
struct pic_port *
|
||||
pic_open_output_string(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||
port->file = xmopen();
|
||||
port->flags = PIC_PORT_OUT | PIC_PORT_TEXT;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
struct pic_string *
|
||||
pic_get_output_string(pic_state *pic, struct pic_port *port)
|
||||
{
|
||||
size_t size;
|
||||
char *buf;
|
||||
|
||||
/* get endpos */
|
||||
xfflush(port->file);
|
||||
size = (size_t)xftell(port->file);
|
||||
xrewind(port->file);
|
||||
|
||||
/* copy to buf */
|
||||
buf = (char *)pic_alloc(pic, size + 1);
|
||||
buf[size] = 0;
|
||||
xfread(buf, size, 1, port->file);
|
||||
|
||||
return pic_make_str(pic, buf, size);
|
||||
}
|
||||
|
||||
void
|
||||
pic_close_port(pic_state *pic, struct pic_port *port)
|
||||
{
|
||||
if (xfclose(port->file) == EOF) {
|
||||
pic_errorf(pic, "close-port: failure");
|
||||
}
|
||||
port->status = PIC_PORT_CLOSE;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_call_with_port(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
struct pic_proc *proc;
|
||||
pic_value value;
|
||||
|
||||
pic_get_args(pic, "pl", &port, &proc);
|
||||
|
||||
value = pic_apply1(pic, proc, pic_obj_value(port));
|
||||
|
||||
pic_close_port(pic, port);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_input_port_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_IN) != 0) {
|
||||
return pic_true_value();
|
||||
}
|
||||
else {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_output_port_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_OUT) != 0) {
|
||||
return pic_true_value();
|
||||
}
|
||||
else {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_textual_port_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_TEXT) != 0) {
|
||||
return pic_true_value();
|
||||
}
|
||||
else {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_binary_port_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_BINARY) != 0) {
|
||||
return pic_true_value();
|
||||
}
|
||||
else {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_port_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_port_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_eof_object_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (pic_vtype(v) == PIC_VTYPE_EOF) {
|
||||
return pic_true_value();
|
||||
}
|
||||
else {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_eof_object(pic_state *pic)
|
||||
{
|
||||
pic_get_args(pic, "");
|
||||
|
||||
return pic_eof_object();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_port_open_p(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
pic_get_args(pic, "p", &port);
|
||||
|
||||
return pic_bool_value(port->status == PIC_PORT_OPEN);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_close_port(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
pic_get_args(pic, "p", &port);
|
||||
|
||||
pic_close_port(pic, port);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
#define assert_port_profile(port, flgs, stat, caller) do { \
|
||||
if ((port->flags & (flgs)) != (flgs)) { \
|
||||
switch (flgs) { \
|
||||
case PIC_PORT_IN: \
|
||||
pic_errorf(pic, caller ": expected output port"); \
|
||||
case PIC_PORT_OUT: \
|
||||
pic_errorf(pic, caller ": expected input port"); \
|
||||
case PIC_PORT_IN | PIC_PORT_TEXT: \
|
||||
pic_errorf(pic, caller ": expected input/textual port"); \
|
||||
case PIC_PORT_IN | PIC_PORT_BINARY: \
|
||||
pic_errorf(pic, caller ": expected input/binary port"); \
|
||||
case PIC_PORT_OUT | PIC_PORT_TEXT: \
|
||||
pic_errorf(pic, caller ": expected output/textual port"); \
|
||||
case PIC_PORT_OUT | PIC_PORT_BINARY: \
|
||||
pic_errorf(pic, caller ": expected output/binary port"); \
|
||||
} \
|
||||
} \
|
||||
if (port->status != stat) { \
|
||||
switch (stat) { \
|
||||
case PIC_PORT_OPEN: \
|
||||
pic_errorf(pic, caller ": expected open port"); \
|
||||
case PIC_PORT_CLOSE: \
|
||||
pic_errorf(pic, caller ": expected close port"); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static pic_value
|
||||
pic_port_open_input_string(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
char *str;
|
||||
|
||||
pic_get_args(pic, "z", &str);
|
||||
|
||||
port = pic_open_input_string(pic, str);
|
||||
|
||||
return pic_obj_value(port);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_open_output_string(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
port = pic_open_output_string(pic);
|
||||
|
||||
return pic_obj_value(port);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_get_output_string(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "get-output-string");
|
||||
|
||||
return pic_obj_value(pic_get_output_string(pic, port));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_open_input_blob(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
struct pic_blob *blob;
|
||||
|
||||
pic_get_args(pic, "b", &blob);
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||
port->file = xmopen();
|
||||
port->flags = PIC_PORT_IN | PIC_PORT_BINARY;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
|
||||
xfwrite(blob->data, 1, blob->len, port->file);
|
||||
xfflush(port->file);
|
||||
xrewind(port->file);
|
||||
|
||||
return pic_obj_value(port);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_open_output_bytevector(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
||||
port->file = xmopen();
|
||||
port->flags = PIC_PORT_OUT | PIC_PORT_BINARY;
|
||||
port->status = PIC_PORT_OPEN;
|
||||
|
||||
return pic_obj_value(port);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_get_output_bytevector(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
pic_blob *blob;
|
||||
size_t size;
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "get-output-bytevector");
|
||||
|
||||
/* get endpos */
|
||||
xfflush(port->file);
|
||||
size = (size_t)xftell(port->file);
|
||||
xrewind(port->file);
|
||||
|
||||
/* copy to buf */
|
||||
blob = pic_make_blob(pic, size);
|
||||
xfread(blob->data, 1, size, port->file);
|
||||
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_read_char(pic_state *pic)
|
||||
{
|
||||
int c;
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "read-char");
|
||||
|
||||
if ((c = xfgetc(port->file)) == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
return pic_char_value((char)c);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_peek_char(pic_state *pic)
|
||||
{
|
||||
int c;
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "peek-char");
|
||||
|
||||
if ((c = xfgetc(port->file)) == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
xungetc(c, port->file);
|
||||
return pic_char_value((char)c);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_read_line(pic_state *pic)
|
||||
{
|
||||
int c;
|
||||
struct pic_port *port = pic_stdin(pic), *buf;
|
||||
struct pic_string *str;
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "read-line");
|
||||
|
||||
buf = pic_open_output_string(pic);
|
||||
while ((c = xfgetc(port->file)) != EOF && c != '\n') {
|
||||
xfputc(c, buf->file);
|
||||
}
|
||||
|
||||
str = pic_get_output_string(pic, buf);
|
||||
if (pic_strlen(str) == 0 && c == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_char_ready_p(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "char-ready?");
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
return pic_true_value(); /* FIXME: always returns #t */
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_read_string(pic_state *pic){
|
||||
struct pic_port *port = pic_stdin(pic), *buf;
|
||||
pic_str *str;
|
||||
int k, i;
|
||||
int c;
|
||||
|
||||
pic_get_args(pic, "i|p", &k, &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "read-stritg");
|
||||
|
||||
c = EOF;
|
||||
buf = pic_open_output_string(pic);
|
||||
for(i = 0; i < k; ++i) {
|
||||
if((c = xfgetc(port->file)) == EOF){
|
||||
break;
|
||||
}
|
||||
xfputc(c, buf->file);
|
||||
}
|
||||
|
||||
str = pic_get_output_string(pic, buf);
|
||||
if (pic_strlen(str) == 0 && c == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_read_byte(pic_state *pic){
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
int c;
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_BINARY, PIC_PORT_OPEN, "read-u8");
|
||||
if ((c = xfgetc(port->file)) == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
|
||||
return pic_int_value(c);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_peek_byte(pic_state *pic)
|
||||
{
|
||||
int c;
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_BINARY, PIC_PORT_OPEN, "peek-u8");
|
||||
|
||||
c = xfgetc(port->file);
|
||||
if (c == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
xungetc(c, port->file);
|
||||
return pic_int_value(c);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_byte_ready_p(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_BINARY, PIC_PORT_OPEN, "u8-ready?");
|
||||
|
||||
return pic_true_value(); /* FIXME: always returns #t */
|
||||
}
|
||||
|
||||
|
||||
static pic_value
|
||||
pic_port_read_blob(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
pic_blob *blob;
|
||||
size_t k, i;
|
||||
|
||||
pic_get_args(pic, "k|p", &k, &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_BINARY, PIC_PORT_OPEN, "read-bytevector");
|
||||
|
||||
blob = pic_make_blob(pic, k);
|
||||
|
||||
i = xfread(blob->data, sizeof(char), k, port->file);
|
||||
if (i == 0) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
pic_realloc(pic, blob->data, i);
|
||||
blob->len = i;
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_read_blob_ip(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port;
|
||||
struct pic_blob *bv;
|
||||
int n;
|
||||
char *buf;
|
||||
size_t start, end, i, len;
|
||||
|
||||
n = pic_get_args(pic, "b|pkk", &bv, &port, &start, &end);
|
||||
switch (n) {
|
||||
case 1:
|
||||
port = pic_stdin(pic);
|
||||
case 2:
|
||||
start = 0;
|
||||
case 3:
|
||||
end = bv->len;
|
||||
}
|
||||
|
||||
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_BINARY, PIC_PORT_OPEN, "read-bytevector!");
|
||||
|
||||
if (end < start) {
|
||||
pic_errorf(pic, "read-bytevector!: end index must be greater than or equal to start index");
|
||||
}
|
||||
|
||||
len = end - start;
|
||||
|
||||
buf = pic_calloc(pic, len, sizeof(char));
|
||||
i = xfread(buf, sizeof(char), len, port->file);
|
||||
memcpy(bv->data + start, buf, i);
|
||||
pic_free(pic, buf);
|
||||
|
||||
if (i == 0) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
else {
|
||||
return pic_size_value(i);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_newline(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "newline");
|
||||
|
||||
xfputs("\n", port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_write_char(pic_state *pic)
|
||||
{
|
||||
char c;
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "c|p", &c, &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "write-char");
|
||||
|
||||
xfputc(c, port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_write_string(pic_state *pic)
|
||||
{
|
||||
char *str;
|
||||
struct pic_port *port;
|
||||
int start, end, n, i;
|
||||
|
||||
n = pic_get_args(pic, "z|pii", &str, &port, &start, &end);
|
||||
switch (n) {
|
||||
case 1:
|
||||
port = pic_stdout(pic);
|
||||
case 2:
|
||||
start = 0;
|
||||
case 3:
|
||||
end = INT_MAX;
|
||||
}
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "write-string");
|
||||
|
||||
for (i = start; i < end && str[i] != '\0'; ++i) {
|
||||
xfputc(str[i], port->file);
|
||||
}
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_write_byte(pic_state *pic)
|
||||
{
|
||||
int i;
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "i|p", &i, &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "write-u8");
|
||||
|
||||
xfputc(i, port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_write_blob(pic_state *pic)
|
||||
{
|
||||
struct pic_blob *blob;
|
||||
struct pic_port *port;
|
||||
int n;
|
||||
size_t start, end, i;
|
||||
|
||||
n = pic_get_args(pic, "b|pkk", &blob, &port, &start, &end);
|
||||
switch (n) {
|
||||
case 1:
|
||||
port = pic_stdout(pic);
|
||||
case 2:
|
||||
start = 0;
|
||||
case 3:
|
||||
end = blob->len;
|
||||
}
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "write-bytevector");
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
xfputc(blob->data[i], port->file);
|
||||
}
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_port_flush(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
assert_port_profile(port, PIC_PORT_OUT, PIC_PORT_OPEN, "flush-output-port");
|
||||
|
||||
xfflush(port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_port(pic_state *pic)
|
||||
{
|
||||
pic_defvar(pic, "current-input-port", pic_obj_value(pic->xSTDIN), NULL);
|
||||
pic_defvar(pic, "current-output-port", pic_obj_value(pic->xSTDOUT), NULL);
|
||||
pic_defvar(pic, "current-error-port", pic_obj_value(pic->xSTDERR), NULL);
|
||||
|
||||
pic_defun(pic, "call-with-port", pic_port_call_with_port);
|
||||
|
||||
pic_defun(pic, "input-port?", pic_port_input_port_p);
|
||||
pic_defun(pic, "output-port?", pic_port_output_port_p);
|
||||
pic_defun(pic, "textual-port?", pic_port_textual_port_p);
|
||||
pic_defun(pic, "binary-port?", pic_port_binary_port_p);
|
||||
pic_defun(pic, "port?", pic_port_port_p);
|
||||
|
||||
pic_defun(pic, "port-open?", pic_port_port_open_p);
|
||||
pic_defun(pic, "close-port", pic_port_close_port);
|
||||
|
||||
/* string I/O */
|
||||
pic_defun(pic, "open-input-string", pic_port_open_input_string);
|
||||
pic_defun(pic, "open-output-string", pic_port_open_output_string);
|
||||
pic_defun(pic, "get-output-string", pic_port_get_output_string);
|
||||
pic_defun(pic, "open-input-bytevector", pic_port_open_input_blob);
|
||||
pic_defun(pic, "open-output-bytevector", pic_port_open_output_bytevector);
|
||||
pic_defun(pic, "get-output-bytevector", pic_port_get_output_bytevector);
|
||||
|
||||
/* input */
|
||||
pic_defun(pic, "read-char", pic_port_read_char);
|
||||
pic_defun(pic, "peek-char", pic_port_peek_char);
|
||||
pic_defun(pic, "read-line", pic_port_read_line);
|
||||
pic_defun(pic, "eof-object?", pic_port_eof_object_p);
|
||||
pic_defun(pic, "eof-object", pic_port_eof_object);
|
||||
pic_defun(pic, "char-ready?", pic_port_char_ready_p);
|
||||
pic_defun(pic, "read-string", pic_port_read_string);
|
||||
pic_defun(pic, "read-u8", pic_port_read_byte);
|
||||
pic_defun(pic, "peek-u8", pic_port_peek_byte);
|
||||
pic_defun(pic, "u8-ready?", pic_port_byte_ready_p);
|
||||
pic_defun(pic, "read-bytevector", pic_port_read_blob);
|
||||
pic_defun(pic, "read-bytevector!", pic_port_read_blob_ip);
|
||||
|
||||
/* output */
|
||||
pic_defun(pic, "newline", pic_port_newline);
|
||||
pic_defun(pic, "write-char", pic_port_write_char);
|
||||
pic_defun(pic, "write-string", pic_port_write_string);
|
||||
pic_defun(pic, "write-u8", pic_port_write_byte);
|
||||
pic_defun(pic, "write-bytevector", pic_port_write_blob);
|
||||
pic_defun(pic, "flush-output-port", pic_port_flush);
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/irep.h"
|
||||
|
||||
struct pic_proc *
|
||||
pic_make_proc(pic_state *pic, pic_func_t func, const char *name)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
|
||||
assert(name != NULL);
|
||||
|
||||
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC);
|
||||
proc->kind = PIC_PROC_KIND_FUNC;
|
||||
proc->u.func.f = func;
|
||||
proc->u.func.name = pic_intern_cstr(pic, name);
|
||||
proc->env = NULL;
|
||||
return proc;
|
||||
}
|
||||
|
||||
struct pic_proc *
|
||||
pic_make_proc_irep(pic_state *pic, struct pic_irep *irep, struct pic_env *env)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
|
||||
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC);
|
||||
proc->kind = PIC_PROC_KIND_IREP;
|
||||
proc->u.irep = irep;
|
||||
proc->env = env;
|
||||
return proc;
|
||||
}
|
||||
|
||||
pic_sym
|
||||
pic_proc_name(struct pic_proc *proc)
|
||||
{
|
||||
switch (proc->kind) {
|
||||
case PIC_PROC_KIND_FUNC:
|
||||
return proc->u.func.name;
|
||||
case PIC_PROC_KIND_IREP:
|
||||
return proc->u.irep->name;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_proc_proc_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_proc_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_proc_apply(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
pic_value *args;
|
||||
size_t argc;
|
||||
pic_value arg_list;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &args);
|
||||
|
||||
if (argc == 0) {
|
||||
pic_errorf(pic, "apply: wrong number of arguments");
|
||||
}
|
||||
|
||||
arg_list = args[--argc];
|
||||
while (argc--) {
|
||||
arg_list = pic_cons(pic, args[argc], arg_list);
|
||||
}
|
||||
|
||||
return pic_apply_trampoline(pic, proc, arg_list);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_proc(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "procedure?", pic_proc_proc_p);
|
||||
pic_defun(pic, "apply", pic_proc_apply);
|
||||
}
|
||||
|
|
@ -0,0 +1,934 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "picrin.h"
|
||||
#include "picrin/read.h"
|
||||
#include "picrin/error.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/vector.h"
|
||||
#include "picrin/blob.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/proc.h"
|
||||
|
||||
static pic_value read(pic_state *pic, struct pic_port *port, int c);
|
||||
static pic_value read_nullable(pic_state *pic, struct pic_port *port, int c);
|
||||
|
||||
static noreturn void
|
||||
read_error(pic_state *pic, const char *msg)
|
||||
{
|
||||
pic_throw(pic, pic->sREAD, msg, pic_nil_value());
|
||||
}
|
||||
|
||||
static int
|
||||
skip(struct pic_port *port, int c)
|
||||
{
|
||||
while (isspace(c)) {
|
||||
c = xfgetc(port->file);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
next(struct pic_port *port)
|
||||
{
|
||||
return xfgetc(port->file);
|
||||
}
|
||||
|
||||
static int
|
||||
peek(struct pic_port *port)
|
||||
{
|
||||
int c;
|
||||
|
||||
xungetc((c = xfgetc(port->file)), port->file);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static bool
|
||||
expect(struct pic_port *port, const char *str)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = (int)*str++) != 0) {
|
||||
if (c != peek(port))
|
||||
return false;
|
||||
next(port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
isdelim(int c)
|
||||
{
|
||||
return c == EOF || strchr("();,|\" \t\n\r", c) != NULL; /* ignores "#", "'" */
|
||||
}
|
||||
|
||||
static bool
|
||||
strcaseeq(const char *s1, const char *s2)
|
||||
{
|
||||
char a, b;
|
||||
|
||||
while ((a = *s1++) * (b = *s2++)) {
|
||||
if (tolower(a) != tolower(b))
|
||||
return false;
|
||||
}
|
||||
return a == b;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_comment(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
int c;
|
||||
|
||||
UNUSED(pic);
|
||||
UNUSED(str);
|
||||
|
||||
do {
|
||||
c = next(port);
|
||||
} while (! (c == EOF || c == '\n'));
|
||||
|
||||
return pic_undef_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_block_comment(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
int x, y;
|
||||
int i = 1;
|
||||
|
||||
UNUSED(pic);
|
||||
UNUSED(str);
|
||||
|
||||
y = next(port);
|
||||
|
||||
while (y != EOF && i > 0) {
|
||||
x = y;
|
||||
y = next(port);
|
||||
if (x == '|' && y == '#') {
|
||||
i--;
|
||||
}
|
||||
if (x == '#' && y == '|') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return pic_undef_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_datum_comment(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(str);
|
||||
|
||||
read(pic, port, next(port));
|
||||
|
||||
return pic_undef_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_directive(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
switch (peek(port)) {
|
||||
case 'n':
|
||||
if (expect(port, "no-fold-case")) {
|
||||
pic->reader->typecase = PIC_CASE_DEFAULT;
|
||||
return pic_undef_value();
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (expect(port, "fold-case")) {
|
||||
pic->reader->typecase = PIC_CASE_FOLD;
|
||||
return pic_undef_value();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return read_comment(pic, port, str);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_eval(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
pic_value form;
|
||||
|
||||
UNUSED(str);
|
||||
|
||||
form = read(pic, port, next(port));
|
||||
|
||||
return pic_eval(pic, form, pic->lib);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_quote(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(str);
|
||||
|
||||
return pic_list2(pic, pic_sym_value(pic->sQUOTE), read(pic, port, next(port)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_quasiquote(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(str);
|
||||
|
||||
return pic_list2(pic, pic_sym_value(pic->sQUASIQUOTE), read(pic, port, next(port)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_unquote(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(str);
|
||||
|
||||
return pic_list2(pic, pic_sym_value(pic->sUNQUOTE), read(pic, port, next(port)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_unquote_splicing(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(str);
|
||||
|
||||
return pic_list2(pic, pic_sym_value(pic->sUNQUOTE_SPLICING), read(pic, port, next(port)));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_symbol(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
size_t len, i;
|
||||
char *buf;
|
||||
pic_sym sym;
|
||||
int c;
|
||||
|
||||
len = strlen(str);
|
||||
buf = pic_calloc(pic, 1, len + 1);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (pic->reader->typecase == PIC_CASE_FOLD) {
|
||||
buf[i] = (char)tolower(str[i]);
|
||||
} else {
|
||||
buf[i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
while (! isdelim(peek(port))) {
|
||||
c = next(port);
|
||||
if (pic->reader->typecase == PIC_CASE_FOLD) {
|
||||
c = tolower(c);
|
||||
}
|
||||
len += 1;
|
||||
buf = pic_realloc(pic, buf, len + 1);
|
||||
buf[len - 1] = (char)c;
|
||||
}
|
||||
|
||||
sym = pic_intern(pic, buf, len);
|
||||
pic_free(pic, buf);
|
||||
|
||||
return pic_sym_value(sym);
|
||||
}
|
||||
|
||||
static size_t
|
||||
read_uinteger(pic_state *pic, struct pic_port *port, int c, char buf[])
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (! isdigit(c)) {
|
||||
read_error(pic, "expected one or more digits");
|
||||
}
|
||||
|
||||
buf[i++] = (char)c;
|
||||
while (isdigit(c = peek(port))) {
|
||||
buf[i++] = (char)next(port);
|
||||
}
|
||||
|
||||
buf[i] = '\0';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t
|
||||
read_suffix(pic_state *pic, struct pic_port *port, char buf[])
|
||||
{
|
||||
size_t i = 0;
|
||||
int c;
|
||||
|
||||
c = peek(port);
|
||||
|
||||
if (c != 'e' && c != 'E') {
|
||||
return i;
|
||||
}
|
||||
|
||||
buf[i++] = (char)next(port);
|
||||
|
||||
switch ((c = next(port))) {
|
||||
case '-':
|
||||
case '+':
|
||||
buf[i++] = (char)c;
|
||||
c = next(port);
|
||||
default:
|
||||
return i + read_uinteger(pic, port, c, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_unsigned(pic_state *pic, struct pic_port *port, int c)
|
||||
{
|
||||
char buf[256];
|
||||
size_t i;
|
||||
|
||||
i = read_uinteger(pic, port, c, buf);
|
||||
|
||||
switch (peek(port)) {
|
||||
case '.':
|
||||
buf[i++] = (char)next(port);
|
||||
i += read_uinteger(pic, port, next(port), buf + i);
|
||||
read_suffix(pic, port, buf + i);
|
||||
return pic_float_value(atof(buf));
|
||||
|
||||
default:
|
||||
read_suffix(pic, port, buf + i);
|
||||
return pic_int_value((int)(atof(buf)));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_number(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
return read_unsigned(pic, port, str[0]);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
negate(pic_value n)
|
||||
{
|
||||
if (pic_int_p(n)) {
|
||||
return pic_int_value(-pic_int(n));
|
||||
} else {
|
||||
return pic_float_value(-pic_float(n));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_minus(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
pic_value sym;
|
||||
|
||||
if (isdigit(peek(port))) {
|
||||
return negate(read_unsigned(pic, port, next(port)));
|
||||
}
|
||||
else {
|
||||
sym = read_symbol(pic, port, str);
|
||||
if (strcaseeq(pic_symbol_name(pic, pic_sym(sym)), "-inf.0")) {
|
||||
return pic_float_value(-INFINITY);
|
||||
}
|
||||
if (strcaseeq(pic_symbol_name(pic, pic_sym(sym)), "-nan.0")) {
|
||||
return pic_float_value(-NAN);
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_plus(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
pic_value sym;
|
||||
|
||||
if (isdigit(peek(port))) {
|
||||
return read_unsigned(pic, port, next(port));
|
||||
}
|
||||
else {
|
||||
sym = read_symbol(pic, port, str);
|
||||
if (strcaseeq(pic_symbol_name(pic, pic_sym(sym)), "+inf.0")) {
|
||||
return pic_float_value(INFINITY);
|
||||
}
|
||||
if (strcaseeq(pic_symbol_name(pic, pic_sym(sym)), "+nan.0")) {
|
||||
return pic_float_value(NAN);
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_true(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(pic);
|
||||
UNUSED(port);
|
||||
UNUSED(str);
|
||||
|
||||
return pic_true_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_false(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(pic);
|
||||
UNUSED(port);
|
||||
UNUSED(str);
|
||||
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_char(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
int c;
|
||||
|
||||
UNUSED(str);
|
||||
|
||||
c = next(port);
|
||||
|
||||
if (! isdelim(peek(port))) {
|
||||
switch (c) {
|
||||
default: read_error(pic, "unexpected character after char literal");
|
||||
case 'a': c = '\a'; if (! expect(port, "lerm")) goto fail; break;
|
||||
case 'b': c = '\b'; if (! expect(port, "ackspace")) goto fail; break;
|
||||
case 'd': c = 0x7F; if (! expect(port, "elete")) goto fail; break;
|
||||
case 'e': c = 0x1B; if (! expect(port, "scape")) goto fail; break;
|
||||
case 'n':
|
||||
if ((c = peek(port)) == 'e') {
|
||||
c = '\n';
|
||||
if (! expect(port, "ewline"))
|
||||
goto fail;
|
||||
} else {
|
||||
c = '\0';
|
||||
if (! expect(port, "ull"))
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 'r': c = '\r'; if (! expect(port, "eturn")) goto fail; break;
|
||||
case 's': c = ' '; if (! expect(port, "pace")) goto fail; break;
|
||||
case 't': c = '\t'; if (! expect(port, "ab")) goto fail; break;
|
||||
}
|
||||
}
|
||||
|
||||
return pic_char_value((char)c);
|
||||
|
||||
fail:
|
||||
read_error(pic, "unexpected character while reading character literal");
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_string(pic_state *pic, struct pic_port *port, const char *name)
|
||||
{
|
||||
int c;
|
||||
char *buf;
|
||||
size_t size, cnt;
|
||||
pic_str *str;
|
||||
|
||||
UNUSED(name);
|
||||
|
||||
size = 256;
|
||||
buf = pic_alloc(pic, size);
|
||||
cnt = 0;
|
||||
|
||||
/* TODO: intraline whitespaces */
|
||||
|
||||
while ((c = next(port)) != '"') {
|
||||
if (c == '\\') {
|
||||
switch (c = next(port)) {
|
||||
case 'a': c = '\a'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
}
|
||||
}
|
||||
buf[cnt++] = (char)c;
|
||||
if (cnt >= size) {
|
||||
buf = pic_realloc(pic, buf, size *= 2);
|
||||
}
|
||||
}
|
||||
buf[cnt] = '\0';
|
||||
|
||||
str = pic_make_str(pic, buf, cnt);
|
||||
pic_free(pic, buf);
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_pipe(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
char *buf;
|
||||
size_t size, cnt;
|
||||
pic_sym sym;
|
||||
/* Currently supports only ascii chars */
|
||||
char HEX_BUF[3];
|
||||
size_t i = 0;
|
||||
int c;
|
||||
|
||||
UNUSED(str);
|
||||
|
||||
size = 256;
|
||||
buf = pic_alloc(pic, size);
|
||||
cnt = 0;
|
||||
while ((c = next(port)) != '|') {
|
||||
if (c == '\\') {
|
||||
switch ((c = next(port))) {
|
||||
case 'a': c = '\a'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 'x':
|
||||
i = 0;
|
||||
while ((HEX_BUF[i++] = (char)next(port)) != ';') {
|
||||
if (i >= sizeof HEX_BUF)
|
||||
read_error(pic, "expected ';'");
|
||||
}
|
||||
c = (char)strtol(HEX_BUF, NULL, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[cnt++] = (char)c;
|
||||
if (cnt >= size) {
|
||||
buf = pic_realloc(pic, buf, size *= 2);
|
||||
}
|
||||
}
|
||||
buf[cnt] = '\0';
|
||||
|
||||
sym = pic_intern_cstr(pic, buf);
|
||||
pic_free(pic, buf);
|
||||
|
||||
return pic_sym_value(sym);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_blob(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
int nbits, n, c;
|
||||
size_t len, i;
|
||||
char buf[256];
|
||||
unsigned char *dat;
|
||||
pic_blob *blob;
|
||||
|
||||
UNUSED(str);
|
||||
|
||||
nbits = 0;
|
||||
|
||||
while (isdigit(c = next(port))) {
|
||||
nbits = 10 * nbits + c - '0';
|
||||
}
|
||||
|
||||
if (nbits != 8) {
|
||||
read_error(pic, "unsupported bytevector bit width");
|
||||
}
|
||||
|
||||
if (c != '(') {
|
||||
read_error(pic, "expected '(' character");
|
||||
}
|
||||
|
||||
len = 0;
|
||||
dat = NULL;
|
||||
c = next(port);
|
||||
while ((c = skip(port, c)) != ')') {
|
||||
read_uinteger(pic, port, c, buf);
|
||||
n = atoi(buf);
|
||||
if (n < 0 || (1 << nbits) <= n) {
|
||||
read_error(pic, "invalid element in bytevector literal");
|
||||
}
|
||||
len += 1;
|
||||
dat = pic_realloc(pic, dat, len);
|
||||
dat[len - 1] = (unsigned char)n;
|
||||
c = next(port);
|
||||
}
|
||||
|
||||
blob = pic_make_blob(pic, len);
|
||||
for (i = 0; i < len; ++i) {
|
||||
blob->data[i] = dat[i];
|
||||
}
|
||||
|
||||
pic_free(pic, dat);
|
||||
return pic_obj_value(blob);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_pair(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
const int tCLOSE = (str[0] == '(') ? ')' : ']';
|
||||
pic_value car, cdr;
|
||||
int c;
|
||||
|
||||
retry:
|
||||
|
||||
c = skip(port, ' ');
|
||||
|
||||
if (c == tCLOSE) {
|
||||
return pic_nil_value();
|
||||
}
|
||||
if (c == '.' && isdelim(peek(port))) {
|
||||
cdr = read(pic, port, next(port));
|
||||
|
||||
closing:
|
||||
if ((c = skip(port, ' ')) != tCLOSE) {
|
||||
if (pic_undef_p(read_nullable(pic, port, c))) {
|
||||
goto closing;
|
||||
}
|
||||
read_error(pic, "unmatched parenthesis");
|
||||
}
|
||||
return cdr;
|
||||
}
|
||||
else {
|
||||
car = read_nullable(pic, port, c);
|
||||
|
||||
if (pic_undef_p(car)) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
cdr = read_pair(pic, port, str);
|
||||
return pic_cons(pic, car, cdr);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_vector(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
pic_value list;
|
||||
|
||||
list = read(pic, port, str[1]);
|
||||
|
||||
return pic_obj_value(pic_make_vec_from_list(pic, list));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_label_set(pic_state *pic, struct pic_port *port, int i)
|
||||
{
|
||||
pic_value val;
|
||||
int c;
|
||||
|
||||
switch ((c = skip(port, ' '))) {
|
||||
case '(': case '[':
|
||||
{
|
||||
pic_value tmp;
|
||||
|
||||
val = pic_cons(pic, pic_none_value(), pic_none_value());
|
||||
|
||||
xh_put_int(&pic->reader->labels, i, &val);
|
||||
|
||||
tmp = read(pic, port, c);
|
||||
pic_pair_ptr(val)->car = pic_car(pic, tmp);
|
||||
pic_pair_ptr(val)->cdr = pic_cdr(pic, tmp);
|
||||
|
||||
return val;
|
||||
}
|
||||
case '#':
|
||||
{
|
||||
bool vect;
|
||||
|
||||
if (peek(port) == '(') {
|
||||
vect = true;
|
||||
} else {
|
||||
vect = false;
|
||||
}
|
||||
|
||||
if (vect) {
|
||||
pic_vec *tmp;
|
||||
|
||||
val = pic_obj_value(pic_make_vec(pic, 0));
|
||||
|
||||
xh_put_int(&pic->reader->labels, i, &val);
|
||||
|
||||
tmp = pic_vec_ptr(read(pic, port, c));
|
||||
SWAP(pic_value *, tmp->data, pic_vec_ptr(val)->data);
|
||||
SWAP(size_t, tmp->len, pic_vec_ptr(val)->len);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
FALLTHROUGH;
|
||||
}
|
||||
default:
|
||||
{
|
||||
val = read(pic, port, c);
|
||||
|
||||
xh_put_int(&pic->reader->labels, i, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_label_ref(pic_state *pic, struct pic_port *port, int i)
|
||||
{
|
||||
xh_entry *e;
|
||||
|
||||
UNUSED(port);
|
||||
|
||||
e = xh_get_int(&pic->reader->labels, i);
|
||||
if (! e) {
|
||||
read_error(pic, "label of given index not defined");
|
||||
}
|
||||
return xh_val(e, pic_value);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_label(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
i = 0;
|
||||
c = str[1]; /* initial index letter */
|
||||
do {
|
||||
i = i * 10 + c;
|
||||
} while (isdigit(c = next(port)));
|
||||
|
||||
if (c == '=') {
|
||||
return read_label_set(pic, port, i);
|
||||
}
|
||||
if (c == '#') {
|
||||
return read_label_ref(pic, port, i);
|
||||
}
|
||||
read_error(pic, "broken label expression");
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_unmatch(pic_state *pic, struct pic_port *port, const char *str)
|
||||
{
|
||||
UNUSED(port);
|
||||
UNUSED(str);
|
||||
|
||||
read_error(pic, "unmatched parenthesis");
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read_nullable(pic_state *pic, struct pic_port *port, int c)
|
||||
{
|
||||
struct pic_trie *trie = pic->reader->trie;
|
||||
char buf[128];
|
||||
size_t i = 0;
|
||||
pic_str *str;
|
||||
|
||||
c = skip(port, c);
|
||||
|
||||
if (c == EOF) {
|
||||
read_error(pic, "unexpected EOF");
|
||||
}
|
||||
|
||||
if (trie->table[c] == NULL) {
|
||||
read_error(pic, "invalid character at the seeker head");
|
||||
}
|
||||
|
||||
buf[i++] = (char)c;
|
||||
|
||||
while (i < sizeof buf) {
|
||||
trie = trie->table[c];
|
||||
|
||||
if ((c = peek(port)) == EOF) {
|
||||
break;
|
||||
}
|
||||
if (trie->table[c] == NULL) {
|
||||
break;
|
||||
}
|
||||
buf[i++] = (char)next(port);
|
||||
}
|
||||
if (i == sizeof buf) {
|
||||
read_error(pic, "too long dispatch string");
|
||||
}
|
||||
|
||||
if (trie->proc == NULL) {
|
||||
read_error(pic, "no reader registered for current string");
|
||||
}
|
||||
str = pic_make_str(pic, buf, i);
|
||||
return pic_apply2(pic, trie->proc, pic_obj_value(port), pic_obj_value(str));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
read(pic_state *pic, struct pic_port *port, int c)
|
||||
{
|
||||
pic_value val;
|
||||
|
||||
retry:
|
||||
val = read_nullable(pic, port, c);
|
||||
|
||||
if (pic_undef_p(val)) {
|
||||
c = next(port);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
struct pic_trie *
|
||||
pic_make_trie(pic_state *pic)
|
||||
{
|
||||
struct pic_trie *trie;
|
||||
|
||||
trie = pic_alloc(pic, sizeof(struct pic_trie));
|
||||
trie->proc = NULL;
|
||||
memset(trie->table, 0, sizeof trie->table);
|
||||
|
||||
return trie;
|
||||
}
|
||||
|
||||
void
|
||||
pic_trie_delete(pic_state *pic, struct pic_trie *trie)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof trie->table / sizeof(struct pic_trie *); ++i) {
|
||||
if (trie->table[i] != NULL) {
|
||||
pic_trie_delete(pic, trie->table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
pic_free(pic, trie);
|
||||
}
|
||||
|
||||
void
|
||||
pic_define_reader(pic_state *pic, const char *str, pic_func_t reader)
|
||||
{
|
||||
struct pic_trie *trie = pic->reader->trie;
|
||||
int c;
|
||||
|
||||
while ((c = *str++)) {
|
||||
if (trie->table[c] == NULL) {
|
||||
trie->table[c] = pic_make_trie(pic);
|
||||
}
|
||||
trie = trie->table[c];
|
||||
}
|
||||
trie->proc = pic_make_proc(pic, reader, "reader");
|
||||
}
|
||||
|
||||
#define DEFINE_READER(name) \
|
||||
static pic_value \
|
||||
pic_##name(pic_state *pic) \
|
||||
{ \
|
||||
struct pic_port *port; \
|
||||
const char *str; \
|
||||
\
|
||||
pic_get_args(pic, "pz", &port, &str); \
|
||||
\
|
||||
return name(pic, port, str); \
|
||||
}
|
||||
|
||||
DEFINE_READER(read_unmatch)
|
||||
DEFINE_READER(read_comment)
|
||||
DEFINE_READER(read_quote)
|
||||
DEFINE_READER(read_quasiquote)
|
||||
DEFINE_READER(read_unquote)
|
||||
DEFINE_READER(read_unquote_splicing)
|
||||
DEFINE_READER(read_string)
|
||||
DEFINE_READER(read_pipe)
|
||||
DEFINE_READER(read_plus)
|
||||
DEFINE_READER(read_minus)
|
||||
DEFINE_READER(read_pair)
|
||||
DEFINE_READER(read_directive)
|
||||
DEFINE_READER(read_block_comment)
|
||||
DEFINE_READER(read_datum_comment)
|
||||
DEFINE_READER(read_true)
|
||||
DEFINE_READER(read_false)
|
||||
DEFINE_READER(read_char)
|
||||
DEFINE_READER(read_vector)
|
||||
DEFINE_READER(read_blob)
|
||||
DEFINE_READER(read_eval)
|
||||
DEFINE_READER(read_symbol)
|
||||
DEFINE_READER(read_number)
|
||||
DEFINE_READER(read_label)
|
||||
|
||||
void
|
||||
pic_init_reader(pic_state *pic)
|
||||
{
|
||||
static const char INIT[] = "!$%&*./:<=>?@^_~";
|
||||
char buf[3] = { 0 };
|
||||
size_t i;
|
||||
|
||||
pic_define_reader(pic, ")", pic_read_unmatch);
|
||||
pic_define_reader(pic, ";", pic_read_comment);
|
||||
pic_define_reader(pic, "'", pic_read_quote);
|
||||
pic_define_reader(pic, "`", pic_read_quasiquote);
|
||||
pic_define_reader(pic, ",", pic_read_unquote);
|
||||
pic_define_reader(pic, ",@", pic_read_unquote_splicing);
|
||||
pic_define_reader(pic, "\"", pic_read_string);
|
||||
pic_define_reader(pic, "|", pic_read_pipe);
|
||||
pic_define_reader(pic, "+", pic_read_plus);
|
||||
pic_define_reader(pic, "-", pic_read_minus);
|
||||
pic_define_reader(pic, "(", pic_read_pair);
|
||||
pic_define_reader(pic, "[", pic_read_pair);
|
||||
|
||||
pic_define_reader(pic, "#!", pic_read_directive);
|
||||
pic_define_reader(pic, "#|", pic_read_block_comment);
|
||||
pic_define_reader(pic, "#;", pic_read_datum_comment);
|
||||
pic_define_reader(pic, "#t", pic_read_true);
|
||||
pic_define_reader(pic, "#true", pic_read_true);
|
||||
pic_define_reader(pic, "#f", pic_read_false);
|
||||
pic_define_reader(pic, "#false", pic_read_false);
|
||||
pic_define_reader(pic, "#\\", pic_read_char);
|
||||
pic_define_reader(pic, "#(", pic_read_vector);
|
||||
pic_define_reader(pic, "#u", pic_read_blob);
|
||||
pic_define_reader(pic, "#.", pic_read_eval);
|
||||
|
||||
/* read number */
|
||||
for (buf[0] = '0'; buf[0] <= '9'; ++buf[0]) {
|
||||
pic_define_reader(pic, buf, pic_read_number);
|
||||
}
|
||||
|
||||
/* read symbol */
|
||||
for (buf[0] = 'a'; buf[0] <= 'z'; ++buf[0]) {
|
||||
pic_define_reader(pic, buf, pic_read_symbol);
|
||||
}
|
||||
for (buf[0] = 'A'; buf[0] <= 'Z'; ++buf[0]) {
|
||||
pic_define_reader(pic, buf, pic_read_symbol);
|
||||
}
|
||||
for (i = 0; i < sizeof INIT; ++i) {
|
||||
buf[0] = INIT[i];
|
||||
pic_define_reader(pic, buf, pic_read_symbol);
|
||||
}
|
||||
|
||||
/* read label */
|
||||
buf[0] = '#';
|
||||
for (buf[1] = '0'; buf[1] <= '9'; ++buf[1]) {
|
||||
pic_define_reader(pic, buf, pic_read_label);
|
||||
}
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_read(pic_state *pic, struct pic_port *port)
|
||||
{
|
||||
pic_value val;
|
||||
int c = next(port);
|
||||
|
||||
retry:
|
||||
c = skip(port, c);
|
||||
|
||||
if (c == EOF) {
|
||||
return pic_eof_object();
|
||||
}
|
||||
|
||||
val = read_nullable(pic, port, c);
|
||||
|
||||
if (pic_undef_p(val)) {
|
||||
c = next(port);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_read_cstr(pic_state *pic, const char *str)
|
||||
{
|
||||
struct pic_port *port;
|
||||
|
||||
port = pic_open_input_string(pic, str);
|
||||
|
||||
return pic_read(pic, port);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_read_read(pic_state *pic)
|
||||
{
|
||||
struct pic_port *port = pic_stdin(pic);
|
||||
|
||||
pic_get_args(pic, "|p", &port);
|
||||
|
||||
return pic_read(pic, port);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_read(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "read", pic_read_read);
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/record.h"
|
||||
|
||||
struct pic_record *
|
||||
pic_make_record(pic_state *pic, pic_value rectype)
|
||||
{
|
||||
struct pic_record *rec;
|
||||
|
||||
rec = (struct pic_record *)pic_obj_alloc(pic, sizeof(struct pic_record), PIC_TT_RECORD);
|
||||
xh_init_int(&rec->hash, sizeof(pic_value));
|
||||
|
||||
pic_record_set(pic, rec, pic_intern_cstr(pic, "@@type"), rectype);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_record_type(pic_state *pic, struct pic_record *rec)
|
||||
{
|
||||
return pic_record_ref(pic, rec, pic_intern_cstr(pic, "@@type"));
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_record_ref(pic_state *pic, struct pic_record *rec, pic_sym slot)
|
||||
{
|
||||
xh_entry *e;
|
||||
|
||||
e = xh_get_int(&rec->hash, slot);
|
||||
if (! e) {
|
||||
pic_errorf(pic, "slot named ~s is not found for record: ~s", pic_sym_value(slot), rec);
|
||||
}
|
||||
return xh_val(e, pic_value);
|
||||
}
|
||||
|
||||
void
|
||||
pic_record_set(pic_state *pic, struct pic_record *rec, pic_sym slot, pic_value val)
|
||||
{
|
||||
UNUSED(pic);
|
||||
|
||||
xh_put_int(&rec->hash, slot, &val);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_record_make_record(pic_state *pic)
|
||||
{
|
||||
struct pic_record * rec;
|
||||
pic_value rectype;
|
||||
|
||||
pic_get_args(pic, "o", &rectype);
|
||||
|
||||
rec = pic_make_record(pic, rectype);
|
||||
|
||||
return pic_obj_value(rec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_record_record_p(pic_state *pic)
|
||||
{
|
||||
pic_value rec;
|
||||
|
||||
pic_get_args(pic, "o", &rec);
|
||||
|
||||
return pic_bool_value(pic_record_p(rec));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_record_record_type(pic_state *pic)
|
||||
{
|
||||
struct pic_record *rec;
|
||||
|
||||
pic_get_args(pic, "r", &rec);
|
||||
|
||||
return pic_record_type(pic, rec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_record_record_ref(pic_state *pic)
|
||||
{
|
||||
struct pic_record *rec;
|
||||
pic_sym slot;
|
||||
|
||||
pic_get_args(pic, "rm", &rec, &slot);
|
||||
|
||||
return pic_record_ref(pic, rec, slot);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_record_record_set(pic_state *pic)
|
||||
{
|
||||
struct pic_record *rec;
|
||||
pic_sym slot;
|
||||
pic_value val;
|
||||
|
||||
pic_get_args(pic, "rmo", &rec, &slot, &val);
|
||||
|
||||
pic_record_set(pic, rec, slot, val);
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_record(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "make-record", pic_record_make_record);
|
||||
pic_defun(pic, "record?", pic_record_record_p);
|
||||
pic_defun(pic, "record-type", pic_record_record_type);
|
||||
pic_defun(pic, "record-ref", pic_record_record_ref);
|
||||
pic_defun(pic, "record-set!", pic_record_record_set);
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/gc.h"
|
||||
#include "picrin/read.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/macro.h"
|
||||
#include "picrin/cont.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/error.h"
|
||||
|
||||
void pic_init_core(pic_state *);
|
||||
|
||||
pic_state *
|
||||
pic_open(int argc, char *argv[], char **envp)
|
||||
{
|
||||
struct pic_port *pic_make_standard_port(pic_state *, xFILE *, short);
|
||||
char t;
|
||||
|
||||
pic_state *pic;
|
||||
size_t ai;
|
||||
|
||||
pic = malloc(sizeof(pic_state));
|
||||
|
||||
/* root block */
|
||||
pic->wind = NULL;
|
||||
|
||||
/* command line */
|
||||
pic->argc = argc;
|
||||
pic->argv = argv;
|
||||
pic->envp = envp;
|
||||
|
||||
/* prepare VM stack */
|
||||
pic->stbase = pic->sp = calloc(PIC_STACK_SIZE, sizeof(pic_value));
|
||||
pic->stend = pic->stbase + PIC_STACK_SIZE;
|
||||
|
||||
/* callinfo */
|
||||
pic->cibase = pic->ci = calloc(PIC_STACK_SIZE, sizeof(pic_callinfo));
|
||||
pic->ciend = pic->cibase + PIC_STACK_SIZE;
|
||||
|
||||
/* exception handler */
|
||||
pic->xpbase = pic->xp = calloc(PIC_RESCUE_SIZE, sizeof(struct pic_proc *));
|
||||
pic->xpend = pic->xpbase + PIC_RESCUE_SIZE;
|
||||
|
||||
/* memory heap */
|
||||
pic->heap = pic_heap_open();
|
||||
|
||||
/* symbol table */
|
||||
xh_init_str(&pic->syms, sizeof(pic_sym));
|
||||
xh_init_int(&pic->sym_names, sizeof(const char *));
|
||||
pic->sym_cnt = 0;
|
||||
pic->uniq_sym_cnt = 0;
|
||||
|
||||
/* global variables */
|
||||
xh_init_int(&pic->globals, sizeof(pic_value));
|
||||
|
||||
/* macros */
|
||||
xh_init_int(&pic->macros, sizeof(struct pic_macro *));
|
||||
|
||||
/* attributes */
|
||||
xh_init_ptr(&pic->attrs, sizeof(struct pic_dict *));
|
||||
|
||||
/* features */
|
||||
pic->features = pic_nil_value();
|
||||
|
||||
/* libraries */
|
||||
pic->libs = pic_nil_value();
|
||||
pic->lib = NULL;
|
||||
|
||||
/* reader */
|
||||
pic->reader = malloc(sizeof(struct pic_reader));
|
||||
pic->reader->typecase = PIC_CASE_DEFAULT;
|
||||
pic->reader->trie = pic_make_trie(pic);
|
||||
xh_init_int(&pic->reader->labels, sizeof(pic_value));
|
||||
|
||||
/* raised error object */
|
||||
pic->err = pic_undef_value();
|
||||
|
||||
/* standard ports */
|
||||
pic->xSTDIN = NULL;
|
||||
pic->xSTDOUT = NULL;
|
||||
pic->xSTDERR = NULL;
|
||||
|
||||
/* GC arena */
|
||||
pic->arena = calloc(PIC_ARENA_SIZE, sizeof(struct pic_object **));
|
||||
pic->arena_size = PIC_ARENA_SIZE;
|
||||
pic->arena_idx = 0;
|
||||
|
||||
/* native stack marker */
|
||||
pic->native_stack_start = &t;
|
||||
|
||||
#define S(slot,name) pic->slot = pic_intern_cstr(pic, name);
|
||||
|
||||
ai = pic_gc_arena_preserve(pic);
|
||||
S(sDEFINE, "define");
|
||||
S(sLAMBDA, "lambda");
|
||||
S(sIF, "if");
|
||||
S(sBEGIN, "begin");
|
||||
S(sSETBANG, "set!");
|
||||
S(sQUOTE, "quote");
|
||||
S(sQUASIQUOTE, "quasiquote");
|
||||
S(sUNQUOTE, "unquote");
|
||||
S(sUNQUOTE_SPLICING, "unquote-splicing");
|
||||
S(sDEFINE_SYNTAX, "define-syntax");
|
||||
S(sIMPORT, "import");
|
||||
S(sEXPORT, "export");
|
||||
S(sDEFINE_LIBRARY, "define-library");
|
||||
S(sIN_LIBRARY, "in-library");
|
||||
S(sCOND_EXPAND, "cond-expand");
|
||||
S(sAND, "and");
|
||||
S(sOR, "or");
|
||||
S(sELSE, "else");
|
||||
S(sLIBRARY, "library");
|
||||
S(sONLY, "only");
|
||||
S(sRENAME, "rename");
|
||||
S(sPREFIX, "prefix");
|
||||
S(sEXCEPT, "except");
|
||||
S(sCONS, "cons");
|
||||
S(sCAR, "car");
|
||||
S(sCDR, "cdr");
|
||||
S(sNILP, "null?");
|
||||
S(sADD, "+");
|
||||
S(sSUB, "-");
|
||||
S(sMUL, "*");
|
||||
S(sDIV, "/");
|
||||
S(sMINUS, "minus");
|
||||
S(sEQ, "=");
|
||||
S(sLT, "<");
|
||||
S(sLE, "<=");
|
||||
S(sGT, ">");
|
||||
S(sGE, ">=");
|
||||
S(sNOT, "not");
|
||||
S(sREAD, "read");
|
||||
S(sFILE, "file");
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
#define R(slot,name) pic->slot = pic_gensym(pic, pic_intern_cstr(pic, name));
|
||||
|
||||
ai = pic_gc_arena_preserve(pic);
|
||||
R(rDEFINE, "define");
|
||||
R(rLAMBDA, "lambda");
|
||||
R(rIF, "if");
|
||||
R(rBEGIN, "begin");
|
||||
R(rSETBANG, "set!");
|
||||
R(rQUOTE, "quote");
|
||||
R(rDEFINE_SYNTAX, "define-syntax");
|
||||
R(rIMPORT, "import");
|
||||
R(rEXPORT, "export");
|
||||
R(rDEFINE_LIBRARY, "define-library");
|
||||
R(rIN_LIBRARY, "in-library");
|
||||
R(rCOND_EXPAND, "cond-expand");
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
|
||||
/* root block */
|
||||
pic->wind = pic_alloc(pic, sizeof(struct pic_winder));
|
||||
pic->wind->prev = NULL;
|
||||
pic->wind->depth = 0;
|
||||
pic->wind->in = pic->wind->out = NULL;
|
||||
|
||||
/* init readers */
|
||||
pic_init_reader(pic);
|
||||
|
||||
/* standard libraries */
|
||||
pic->PICRIN_BASE = pic_open_library(pic, pic_read_cstr(pic, "(picrin base)"));
|
||||
pic->PICRIN_USER = pic_open_library(pic, pic_read_cstr(pic, "(picrin user)"));
|
||||
pic->lib = pic->PICRIN_USER;
|
||||
|
||||
/* standard I/O */
|
||||
pic->xSTDIN = pic_make_standard_port(pic, xstdin, PIC_PORT_IN);
|
||||
pic->xSTDOUT = pic_make_standard_port(pic, xstdout, PIC_PORT_OUT);
|
||||
pic->xSTDERR = pic_make_standard_port(pic, xstderr, PIC_PORT_OUT);
|
||||
|
||||
pic_init_core(pic);
|
||||
|
||||
return pic;
|
||||
}
|
||||
|
||||
void
|
||||
pic_close(pic_state *pic)
|
||||
{
|
||||
xh_entry *it;
|
||||
|
||||
/* invoke exit handlers */
|
||||
while (pic->wind) {
|
||||
if (pic->wind->out) {
|
||||
pic_apply0(pic, pic->wind->out);
|
||||
}
|
||||
pic->wind = pic->wind->prev;
|
||||
}
|
||||
|
||||
/* clear out root objects */
|
||||
pic->sp = pic->stbase;
|
||||
pic->ci = pic->cibase;
|
||||
pic->xp = pic->xpbase;
|
||||
pic->arena_idx = 0;
|
||||
pic->err = pic_undef_value();
|
||||
xh_clear(&pic->globals);
|
||||
xh_clear(&pic->macros);
|
||||
xh_clear(&pic->attrs);
|
||||
pic->features = pic_nil_value();
|
||||
pic->libs = pic_nil_value();
|
||||
|
||||
/* free all heap objects */
|
||||
pic_gc_run(pic);
|
||||
|
||||
/* free heaps */
|
||||
pic_heap_close(pic->heap);
|
||||
|
||||
/* free runtime context */
|
||||
free(pic->stbase);
|
||||
free(pic->cibase);
|
||||
free(pic->xpbase);
|
||||
|
||||
/* free reader struct */
|
||||
xh_destroy(&pic->reader->labels);
|
||||
pic_trie_delete(pic, pic->reader->trie);
|
||||
free(pic->reader);
|
||||
|
||||
/* free global stacks */
|
||||
xh_destroy(&pic->syms);
|
||||
xh_destroy(&pic->globals);
|
||||
xh_destroy(&pic->macros);
|
||||
xh_destroy(&pic->attrs);
|
||||
|
||||
/* free GC arena */
|
||||
free(pic->arena);
|
||||
|
||||
/* free symbol names */
|
||||
for (it = xh_begin(&pic->sym_names); it != NULL; it = xh_next(it)) {
|
||||
free(xh_val(it, char *));
|
||||
}
|
||||
xh_destroy(&pic->sym_names);
|
||||
|
||||
free(pic);
|
||||
}
|
||||
|
|
@ -0,0 +1,497 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/port.h"
|
||||
|
||||
static pic_str *
|
||||
make_str_rope(pic_state *pic, xrope *rope)
|
||||
{
|
||||
pic_str *str;
|
||||
|
||||
str = (pic_str *)pic_obj_alloc(pic, sizeof(pic_str), PIC_TT_STRING);
|
||||
str->rope = rope; /* delegate ownership */
|
||||
return str;
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_make_str(pic_state *pic, const char *imbed, size_t len)
|
||||
{
|
||||
if (imbed == NULL && len > 0) {
|
||||
pic_errorf(pic, "zero length specified against NULL ptr");
|
||||
}
|
||||
return make_str_rope(pic, xr_new_copy(imbed, len));
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_make_str_cstr(pic_state *pic, const char *cstr)
|
||||
{
|
||||
return pic_make_str(pic, cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_make_str_fill(pic_state *pic, size_t len, char fill)
|
||||
{
|
||||
size_t i;
|
||||
char buf[len + 1];
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
buf[i] = fill;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
|
||||
return pic_make_str(pic, buf, len);
|
||||
}
|
||||
|
||||
size_t
|
||||
pic_strlen(pic_str *str)
|
||||
{
|
||||
return xr_len(str->rope);
|
||||
}
|
||||
|
||||
char
|
||||
pic_str_ref(pic_state *pic, pic_str *str, size_t i)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = xr_at(str->rope, i);
|
||||
if (c == -1) {
|
||||
pic_errorf(pic, "index out of range %d", i);
|
||||
}
|
||||
return (char)c;
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_strcat(pic_state *pic, pic_str *a, pic_str *b)
|
||||
{
|
||||
return make_str_rope(pic, xr_cat(a->rope, b->rope));
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_substr(pic_state *pic, pic_str *str, size_t s, size_t e)
|
||||
{
|
||||
return make_str_rope(pic, xr_sub(str->rope, s, e));
|
||||
}
|
||||
|
||||
int
|
||||
pic_strcmp(pic_str *str1, pic_str *str2)
|
||||
{
|
||||
return strcmp(xr_cstr(str1->rope), xr_cstr(str2->rope));
|
||||
}
|
||||
|
||||
const char *
|
||||
pic_str_cstr(pic_str *str)
|
||||
{
|
||||
return xr_cstr(str->rope);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_xvfformat(pic_state *pic, xFILE *file, const char *fmt, va_list ap)
|
||||
{
|
||||
char c;
|
||||
pic_value irrs = pic_nil_value();
|
||||
|
||||
while ((c = *fmt++)) {
|
||||
switch (c) {
|
||||
default:
|
||||
xfputc(c, file);
|
||||
break;
|
||||
case '%':
|
||||
c = *fmt++;
|
||||
if (! c)
|
||||
goto exit;
|
||||
switch (c) {
|
||||
default:
|
||||
xfputc(c, file);
|
||||
break;
|
||||
case '%':
|
||||
xfputc('%', file);
|
||||
break;
|
||||
case 'c':
|
||||
xfprintf(file, "%c", va_arg(ap, int));
|
||||
break;
|
||||
case 's':
|
||||
xfprintf(file, "%s", va_arg(ap, const char *));
|
||||
break;
|
||||
case 'd':
|
||||
xfprintf(file, "%d", va_arg(ap, int));
|
||||
break;
|
||||
case 'p':
|
||||
xfprintf(file, "%p", va_arg(ap, void *));
|
||||
break;
|
||||
case 'f':
|
||||
xfprintf(file, "%f", va_arg(ap, double));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '~':
|
||||
c = *fmt++;
|
||||
if (! c)
|
||||
goto exit;
|
||||
switch (c) {
|
||||
default:
|
||||
xfputc(c, file);
|
||||
break;
|
||||
case '~':
|
||||
xfputc('~', file);
|
||||
break;
|
||||
case '%':
|
||||
xfputc('\n', file);
|
||||
break;
|
||||
case 'a':
|
||||
irrs = pic_cons(pic, pic_fdisplay(pic, va_arg(ap, pic_value), file), irrs);
|
||||
break;
|
||||
case 's':
|
||||
irrs = pic_cons(pic, pic_fwrite(pic, va_arg(ap, pic_value), file), irrs);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
|
||||
return pic_reverse(pic, irrs);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_xvformat(pic_state *pic, const char *fmt, va_list ap)
|
||||
{
|
||||
struct pic_port *port;
|
||||
pic_value irrs;
|
||||
|
||||
port = pic_open_output_string(pic);
|
||||
|
||||
irrs = pic_xvfformat(pic, port->file, fmt, ap);
|
||||
irrs = pic_cons(pic, pic_obj_value(pic_get_output_string(pic, port)), irrs);
|
||||
|
||||
pic_close_port(pic, port);
|
||||
return irrs;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_xformat(pic_state *pic, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
pic_value objs;
|
||||
|
||||
va_start(ap, fmt);
|
||||
objs = pic_xvformat(pic, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
void
|
||||
pic_vfformat(pic_state *pic, xFILE *file, const char *fmt, va_list ap)
|
||||
{
|
||||
pic_xvfformat(pic, file, fmt, ap);
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_vformat(pic_state *pic, const char *fmt, va_list ap)
|
||||
{
|
||||
struct pic_port *port;
|
||||
pic_str *str;
|
||||
|
||||
port = pic_open_output_string(pic);
|
||||
|
||||
pic_vfformat(pic, port->file, fmt, ap);
|
||||
str = pic_get_output_string(pic, port);
|
||||
|
||||
pic_close_port(pic, port);
|
||||
return str;
|
||||
}
|
||||
|
||||
pic_str *
|
||||
pic_format(pic_state *pic, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
pic_str *str;
|
||||
|
||||
va_start(ap, fmt);
|
||||
str = pic_vformat(pic, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_str_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
pic_str *str;
|
||||
char *buf;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
buf = pic_alloc(pic, (size_t)argc);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], char);
|
||||
buf[i] = pic_char(argv[i]);
|
||||
}
|
||||
|
||||
str = pic_make_str(pic, buf, (size_t)argc);
|
||||
pic_free(pic, buf);
|
||||
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_make_string(pic_state *pic)
|
||||
{
|
||||
size_t len;
|
||||
char c = ' ';
|
||||
|
||||
pic_get_args(pic, "k|c", &len, &c);
|
||||
|
||||
return pic_obj_value(pic_make_str_fill(pic, len, c));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_length(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
|
||||
pic_get_args(pic, "s", &str);
|
||||
|
||||
return pic_size_value(pic_strlen(str));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_ref(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
size_t k;
|
||||
|
||||
pic_get_args(pic, "sk", &str, &k);
|
||||
|
||||
return pic_char_value(pic_str_ref(pic, str, k));
|
||||
}
|
||||
|
||||
#define DEFINE_STRING_CMP(name, op) \
|
||||
static pic_value \
|
||||
pic_str_string_##name(pic_state *pic) \
|
||||
{ \
|
||||
size_t argc, i; \
|
||||
pic_value *argv; \
|
||||
\
|
||||
pic_get_args(pic, "*", &argc, &argv); \
|
||||
\
|
||||
if (argc < 1 || ! pic_str_p(argv[0])) { \
|
||||
return pic_false_value(); \
|
||||
} \
|
||||
\
|
||||
for (i = 1; i < argc; ++i) { \
|
||||
if (! pic_str_p(argv[i])) { \
|
||||
return pic_false_value(); \
|
||||
} \
|
||||
if (! (pic_strcmp(pic_str_ptr(argv[i-1]), pic_str_ptr(argv[i])) op 0)) { \
|
||||
return pic_false_value(); \
|
||||
} \
|
||||
} \
|
||||
return pic_true_value(); \
|
||||
}
|
||||
|
||||
DEFINE_STRING_CMP(eq, ==)
|
||||
DEFINE_STRING_CMP(lt, <)
|
||||
DEFINE_STRING_CMP(gt, >)
|
||||
DEFINE_STRING_CMP(le, <=)
|
||||
DEFINE_STRING_CMP(ge, >=)
|
||||
|
||||
static pic_value
|
||||
pic_str_string_copy(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
int n;
|
||||
size_t start, end;
|
||||
|
||||
n = pic_get_args(pic, "s|kk", &str, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = pic_strlen(str);
|
||||
}
|
||||
|
||||
return pic_obj_value(pic_substr(pic, str, start, end));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_append(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
pic_str *str;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
str = pic_make_str(pic, NULL, 0);
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (! pic_str_p(argv[i])) {
|
||||
pic_errorf(pic, "type error");
|
||||
}
|
||||
str = pic_strcat(pic, str, pic_str_ptr(argv[i]));
|
||||
}
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_map(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
pic_value *argv, vals, val;
|
||||
size_t argc, i, len, j;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &argv);
|
||||
|
||||
len = SIZE_MAX;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], str);
|
||||
|
||||
len = len < pic_strlen(pic_str_ptr(argv[i]))
|
||||
? len
|
||||
: pic_strlen(pic_str_ptr(argv[i]));
|
||||
}
|
||||
if (len == SIZE_MAX) {
|
||||
pic_errorf(pic, "string-map: one or more strings expected, but got zero");
|
||||
}
|
||||
else {
|
||||
char buf[len];
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
vals = pic_nil_value();
|
||||
for (j = 0; j < argc; ++j) {
|
||||
pic_push(pic, pic_char_value(pic_str_ref(pic, pic_str_ptr(argv[j]), i)), vals);
|
||||
}
|
||||
val = pic_apply(pic, proc, vals);
|
||||
|
||||
pic_assert_type(pic, val, char);
|
||||
buf[i] = pic_char(val);
|
||||
}
|
||||
|
||||
return pic_obj_value(pic_make_str(pic, buf, len));
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_for_each(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
size_t argc, len, i, j;
|
||||
pic_value *argv, vals;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &argv);
|
||||
|
||||
len = SIZE_MAX;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], str);
|
||||
|
||||
len = len < pic_strlen(pic_str_ptr(argv[i]))
|
||||
? len
|
||||
: pic_strlen(pic_str_ptr(argv[i]));
|
||||
}
|
||||
if (len == SIZE_MAX) {
|
||||
pic_errorf(pic, "string-map: one or more strings expected, but got zero");
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
vals = pic_nil_value();
|
||||
for (j = 0; j < argc; ++j) {
|
||||
pic_push(pic, pic_char_value(pic_str_ref(pic, pic_str_ptr(argv[j]), i)), vals);
|
||||
}
|
||||
pic_apply(pic, proc, vals);
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_list_to_string(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
pic_value list, e;
|
||||
size_t i = 0;
|
||||
|
||||
pic_get_args(pic, "o", &list);
|
||||
|
||||
if (pic_length(pic, list) == 0) {
|
||||
return pic_obj_value(pic_make_str(pic, NULL, 0));
|
||||
} else {
|
||||
char buf[pic_length(pic, list)];
|
||||
|
||||
pic_for_each (e, list) {
|
||||
pic_assert_type(pic, e, char);
|
||||
|
||||
buf[i++] = pic_char(e);
|
||||
}
|
||||
|
||||
str = pic_make_str(pic, buf, i);
|
||||
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_str_string_to_list(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
pic_value list;
|
||||
int n;
|
||||
size_t start, end, i;
|
||||
|
||||
n = pic_get_args(pic, "s|kk", &str, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = pic_strlen(str);
|
||||
}
|
||||
|
||||
list = pic_nil_value();
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
pic_push(pic, pic_char_value(pic_str_ref(pic, str, i)), list);
|
||||
}
|
||||
return pic_reverse(pic, list);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_str(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "string?", pic_str_string_p);
|
||||
pic_defun(pic, "string", pic_str_string);
|
||||
pic_defun(pic, "make-string", pic_str_make_string);
|
||||
pic_defun(pic, "string-length", pic_str_string_length);
|
||||
pic_defun(pic, "string-ref", pic_str_string_ref);
|
||||
pic_defun(pic, "string-copy", pic_str_string_copy);
|
||||
pic_defun(pic, "string-append", pic_str_string_append);
|
||||
pic_defun(pic, "string-map", pic_str_string_map);
|
||||
pic_defun(pic, "string-for-each", pic_str_string_for_each);
|
||||
pic_defun(pic, "list->string", pic_str_list_to_string);
|
||||
pic_defun(pic, "string->list", pic_str_string_to_list);
|
||||
|
||||
pic_defun(pic, "string=?", pic_str_string_eq);
|
||||
pic_defun(pic, "string<?", pic_str_string_lt);
|
||||
pic_defun(pic, "string>?", pic_str_string_gt);
|
||||
pic_defun(pic, "string<=?", pic_str_string_le);
|
||||
pic_defun(pic, "string>=?", pic_str_string_ge);
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/string.h"
|
||||
|
||||
pic_sym
|
||||
pic_intern(pic_state *pic, const char *str, size_t len)
|
||||
{
|
||||
char *cstr;
|
||||
xh_entry *e;
|
||||
pic_sym id;
|
||||
|
||||
cstr = (char *)pic_malloc(pic, len + 1);
|
||||
cstr[len] = '\0';
|
||||
memcpy(cstr, str, len);
|
||||
|
||||
e = xh_get_str(&pic->syms, cstr);
|
||||
if (e) {
|
||||
return xh_val(e, pic_sym);
|
||||
}
|
||||
|
||||
id = pic->sym_cnt++;
|
||||
xh_put_str(&pic->syms, cstr, &id);
|
||||
xh_put_int(&pic->sym_names, id, &cstr);
|
||||
return id;
|
||||
}
|
||||
|
||||
pic_sym
|
||||
pic_intern_cstr(pic_state *pic, const char *str)
|
||||
{
|
||||
return pic_intern(pic, str, strlen(str));
|
||||
}
|
||||
|
||||
pic_sym
|
||||
pic_intern_str(pic_state *pic, pic_str *str)
|
||||
{
|
||||
return pic_intern_cstr(pic, pic_str_cstr(str));
|
||||
}
|
||||
|
||||
pic_sym
|
||||
pic_gensym(pic_state *pic, pic_sym base)
|
||||
{
|
||||
int uid = pic->uniq_sym_cnt++, len;
|
||||
char *str, mark;
|
||||
pic_sym uniq;
|
||||
|
||||
if (pic_interned_p(pic, base)) {
|
||||
mark = '@';
|
||||
} else {
|
||||
mark = '.';
|
||||
}
|
||||
|
||||
len = snprintf(NULL, 0, "%s%c%d", pic_symbol_name(pic, base), mark, uid);
|
||||
str = pic_alloc(pic, (size_t)len + 1);
|
||||
sprintf(str, "%s%c%d", pic_symbol_name(pic, base), mark, uid);
|
||||
|
||||
/* don't put the symbol to pic->syms to keep it uninterned */
|
||||
uniq = pic->sym_cnt++;
|
||||
xh_put_int(&pic->sym_names, uniq, &str);
|
||||
|
||||
return uniq;
|
||||
}
|
||||
|
||||
pic_sym
|
||||
pic_ungensym(pic_state *pic, pic_sym base)
|
||||
{
|
||||
const char *name, *occr;
|
||||
|
||||
if (pic_interned_p(pic, base)) {
|
||||
return base;
|
||||
}
|
||||
|
||||
name = pic_symbol_name(pic, base);
|
||||
if ((occr = strrchr(name, '@')) == NULL) {
|
||||
pic_panic(pic, "logic flaw");
|
||||
}
|
||||
return pic_intern(pic, name, (size_t)(occr - name));
|
||||
}
|
||||
|
||||
bool
|
||||
pic_interned_p(pic_state *pic, pic_sym sym)
|
||||
{
|
||||
return sym == pic_intern_cstr(pic, pic_symbol_name(pic, sym));
|
||||
}
|
||||
|
||||
const char *
|
||||
pic_symbol_name(pic_state *pic, pic_sym sym)
|
||||
{
|
||||
return xh_val(xh_get_int(&pic->sym_names, sym), const char *);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_symbol_symbol_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_sym_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_symbol_symbol_eq_p(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (! pic_sym_p(argv[i])) {
|
||||
return pic_false_value();
|
||||
}
|
||||
if (! pic_eq_p(argv[i], argv[0])) {
|
||||
return pic_false_value();
|
||||
}
|
||||
}
|
||||
return pic_true_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_symbol_symbol_to_string(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (! pic_sym_p(v)) {
|
||||
pic_errorf(pic, "symbol->string: expected symbol");
|
||||
}
|
||||
|
||||
return pic_obj_value(pic_make_str_cstr(pic, pic_symbol_name(pic, pic_sym(v))));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_symbol_string_to_symbol(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
if (! pic_str_p(v)) {
|
||||
pic_errorf(pic, "string->symbol: expected string");
|
||||
}
|
||||
|
||||
return pic_symbol_value(pic_intern_cstr(pic, pic_str_cstr(pic_str_ptr(v))));
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_symbol(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "symbol?", pic_symbol_symbol_p);
|
||||
pic_defun(pic, "symbol->string", pic_symbol_symbol_to_string);
|
||||
pic_defun(pic, "string->symbol", pic_symbol_string_to_symbol);
|
||||
|
||||
pic_defun(pic, "symbol=?", pic_symbol_symbol_eq_p);
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/cont.h"
|
||||
|
||||
static pic_value
|
||||
pic_system_cmdline(pic_state *pic)
|
||||
{
|
||||
pic_value v = pic_nil_value();
|
||||
int i;
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
for (i = 0; i < pic->argc; ++i) {
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
|
||||
v = pic_cons(pic, pic_obj_value(pic_make_str_cstr(pic, pic->argv[i])), v);
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
}
|
||||
|
||||
return pic_reverse(pic, v);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_system_exit(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
int argc, status = EXIT_SUCCESS;
|
||||
|
||||
argc = pic_get_args(pic, "|o", &v);
|
||||
if (argc == 1) {
|
||||
switch (pic_type(v)) {
|
||||
case PIC_TT_FLOAT:
|
||||
status = (int)pic_float(v);
|
||||
break;
|
||||
case PIC_TT_INT:
|
||||
status = pic_int(v);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pic_close(pic);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_system_emergency_exit(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
int argc, status = EXIT_FAILURE;
|
||||
|
||||
argc = pic_get_args(pic, "|o", &v);
|
||||
if (argc == 1) {
|
||||
switch (pic_type(v)) {
|
||||
case PIC_TT_FLOAT:
|
||||
status = (int)pic_float(v);
|
||||
break;
|
||||
case PIC_TT_INT:
|
||||
status = pic_int(v);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Exit(status);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_system_getenv(pic_state *pic)
|
||||
{
|
||||
char *str, *val;
|
||||
|
||||
pic_get_args(pic, "z", &str);
|
||||
|
||||
val = getenv(str);
|
||||
|
||||
if (val == NULL)
|
||||
return pic_nil_value();
|
||||
else
|
||||
return pic_obj_value(pic_make_str_cstr(pic, val));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_system_getenvs(pic_state *pic)
|
||||
{
|
||||
char **envp;
|
||||
pic_value data = pic_nil_value();
|
||||
size_t ai = pic_gc_arena_preserve(pic);
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
if (! pic->envp) {
|
||||
return pic_nil_value();
|
||||
}
|
||||
|
||||
for (envp = pic->envp; *envp; ++envp) {
|
||||
pic_str *key, *val;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; (*envp)[i] != '='; ++i)
|
||||
;
|
||||
|
||||
key = pic_make_str(pic, *envp, i);
|
||||
val = pic_make_str_cstr(pic, getenv(pic_str_cstr(key)));
|
||||
|
||||
/* push */
|
||||
data = pic_acons(pic, pic_obj_value(key), pic_obj_value(val), data);
|
||||
|
||||
pic_gc_arena_restore(pic, ai);
|
||||
pic_gc_protect(pic, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_system(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "command-line", pic_system_cmdline);
|
||||
pic_defun(pic, "exit", pic_system_exit);
|
||||
pic_defun(pic, "emergency-exit", pic_system_emergency_exit);
|
||||
pic_defun(pic, "get-environment-variable", pic_system_getenv);
|
||||
pic_defun(pic, "get-environment-variables", pic_system_getenvs);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "picrin.h"
|
||||
|
||||
#define UTC_TAI_DIFF 35
|
||||
|
||||
static pic_value
|
||||
pic_current_second(pic_state *pic)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
time(&t);
|
||||
return pic_float_value((double)t + UTC_TAI_DIFF);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_current_jiffy(pic_state *pic)
|
||||
{
|
||||
clock_t c;
|
||||
|
||||
pic_get_args(pic, "");
|
||||
|
||||
c = clock();
|
||||
return pic_int_value((int)c); /* The year 2038 problem :-| */
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_jiffies_per_second(pic_state *pic)
|
||||
{
|
||||
pic_get_args(pic, "");
|
||||
|
||||
return pic_int_value(CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_time(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "current-second", pic_current_second);
|
||||
pic_defun(pic, "current-jiffy", pic_current_jiffy);
|
||||
pic_defun(pic, "jiffies-per-second", pic_jiffies_per_second);
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/proc.h"
|
||||
#include "picrin/dict.h"
|
||||
|
||||
static pic_value
|
||||
var_lookup(pic_state *pic, pic_value var)
|
||||
{
|
||||
pic_value val, env;
|
||||
struct pic_dict *binding;
|
||||
|
||||
val = pic_ref(pic, pic->PICRIN_BASE, "current-dynamic-environment");
|
||||
if (pic_eq_p(val, var)) {
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
env = pic_apply0(pic, pic_proc_ptr(val));
|
||||
while (! pic_nil_p(env)) {
|
||||
pic_assert_type(pic, pic_car(pic, env), dict);
|
||||
|
||||
binding = pic_dict_ptr(pic_car(pic, env));
|
||||
if (pic_dict_has(pic, binding, var)) {
|
||||
return pic_dict_ref(pic, binding, var);
|
||||
}
|
||||
env = pic_cdr(pic, env);
|
||||
}
|
||||
|
||||
return pic_false_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
var_call(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *self = pic_get_proc(pic);
|
||||
pic_value val, tmp, box, conv;
|
||||
int n;
|
||||
|
||||
n = pic_get_args(pic, "|oo", &val, &tmp);
|
||||
|
||||
box = var_lookup(pic, pic_obj_value(self));
|
||||
if (! pic_test(box)) {
|
||||
box = pic_attr_ref(pic, pic_obj_value(self), "@@box");
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 0:
|
||||
return pic_car(pic, box);
|
||||
|
||||
case 1:
|
||||
conv = pic_attr_ref(pic, pic_obj_value(self), "@@converter");
|
||||
if (pic_test(conv)) {
|
||||
pic_assert_type(pic, conv, proc);
|
||||
|
||||
val = pic_apply1(pic, pic_proc_ptr(conv), val);
|
||||
}
|
||||
pic_set_car(pic, box, val);
|
||||
|
||||
return pic_none_value();
|
||||
|
||||
case 2:
|
||||
assert(pic_false_p(tmp));
|
||||
|
||||
conv = pic_attr_ref(pic, pic_obj_value(self), "@@converter");
|
||||
if (pic_test(conv)) {
|
||||
pic_assert_type(pic, conv, proc);
|
||||
|
||||
return pic_apply1(pic, pic_proc_ptr(conv), val);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
struct pic_proc *
|
||||
pic_make_var(pic_state *pic, pic_value init, struct pic_proc *conv)
|
||||
{
|
||||
struct pic_proc *var;
|
||||
|
||||
var = pic_make_proc(pic, var_call, "<var-call>");
|
||||
pic_attr_set(pic, pic_obj_value(var), "@@box", pic_list1(pic, init));
|
||||
pic_attr_set(pic, pic_obj_value(var), "@@converter", conv ? pic_obj_value(conv) : pic_false_value());
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_var_make_parameter(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *conv = NULL;
|
||||
pic_value init;
|
||||
|
||||
pic_get_args(pic, "o|l", &init, &conv);
|
||||
|
||||
return pic_obj_value(pic_make_var(pic, init, conv));
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_var(pic_state *pic)
|
||||
{
|
||||
pic_define_noexport(pic, "current-dynamic-environment", pic_false_value());
|
||||
|
||||
pic_defun(pic, "make-parameter", pic_var_make_parameter);
|
||||
|
||||
pic_set(pic, pic->PICRIN_BASE, "current-dynamic-environment", pic_obj_value(pic_make_var(pic, pic_nil_value(), NULL)));
|
||||
}
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/vector.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/pair.h"
|
||||
|
||||
struct pic_vector *
|
||||
pic_make_vec(pic_state *pic, size_t len)
|
||||
{
|
||||
struct pic_vector *vec;
|
||||
size_t i;
|
||||
|
||||
vec = (struct pic_vector *)pic_obj_alloc(pic, sizeof(struct pic_vector), PIC_TT_VECTOR);
|
||||
vec->len = len;
|
||||
vec->data = (pic_value *)pic_alloc(pic, sizeof(pic_value) * len);
|
||||
for (i = 0; i < len; ++i) {
|
||||
vec->data[i] = pic_none_value();
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
struct pic_vector *
|
||||
pic_make_vec_from_list(pic_state *pic, pic_value data)
|
||||
{
|
||||
struct pic_vector *vec;
|
||||
size_t len, i;
|
||||
|
||||
len = pic_length(pic, data);
|
||||
|
||||
vec = pic_make_vec(pic, len);
|
||||
for (i = 0; i < len; ++i) {
|
||||
vec->data[i] = pic_car(pic, data);
|
||||
data = pic_cdr(pic, data);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_p(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
|
||||
pic_get_args(pic, "o", &v);
|
||||
|
||||
return pic_bool_value(pic_vec_p(v));
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector(pic_state *pic)
|
||||
{
|
||||
size_t argc, i;
|
||||
pic_value *argv;
|
||||
pic_vec *vec;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
vec = pic_make_vec(pic, (size_t)argc);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
vec->data[i] = argv[i];
|
||||
}
|
||||
|
||||
return pic_obj_value(vec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_make_vector(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
int n;
|
||||
size_t k, i;
|
||||
struct pic_vector *vec;
|
||||
|
||||
n = pic_get_args(pic, "k|o", &k, &v);
|
||||
|
||||
vec = pic_make_vec(pic, k);
|
||||
if (n == 2) {
|
||||
for (i = 0; i < k; ++i) {
|
||||
vec->data[i] = v;
|
||||
}
|
||||
}
|
||||
return pic_obj_value(vec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_length(pic_state *pic)
|
||||
{
|
||||
struct pic_vector *v;
|
||||
|
||||
pic_get_args(pic, "v", &v);
|
||||
|
||||
return pic_size_value(v->len);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_ref(pic_state *pic)
|
||||
{
|
||||
struct pic_vector *v;
|
||||
size_t k;
|
||||
|
||||
pic_get_args(pic, "vk", &v, &k);
|
||||
|
||||
if (v->len <= k) {
|
||||
pic_errorf(pic, "vector-ref: index out of range");
|
||||
}
|
||||
return v->data[k];
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_set(pic_state *pic)
|
||||
{
|
||||
struct pic_vector *v;
|
||||
size_t k;
|
||||
pic_value o;
|
||||
|
||||
pic_get_args(pic, "vko", &v, &k, &o);
|
||||
|
||||
if (v->len <= k) {
|
||||
pic_errorf(pic, "vector-set!: index out of range");
|
||||
}
|
||||
v->data[k] = o;
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_copy_i(pic_state *pic)
|
||||
{
|
||||
pic_vec *to, *from;
|
||||
int n;
|
||||
size_t at, start, end;
|
||||
|
||||
n = pic_get_args(pic, "vkv|kk", &to, &at, &from, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 3:
|
||||
start = 0;
|
||||
case 4:
|
||||
end = from->len;
|
||||
}
|
||||
|
||||
if (to == from && (start <= at && at < end)) {
|
||||
/* copy in reversed order */
|
||||
at += end - start;
|
||||
while (start < end) {
|
||||
to->data[--at] = from->data[--end];
|
||||
}
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
while (start < end) {
|
||||
to->data[at++] = from->data[start++];
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_copy(pic_state *pic)
|
||||
{
|
||||
pic_vec *vec, *to;
|
||||
int n;
|
||||
size_t start, end, i = 0;
|
||||
|
||||
n = pic_get_args(pic, "v|kk", &vec, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = vec->len;
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
pic_errorf(pic, "vector-copy: end index must not be less than start index");
|
||||
}
|
||||
|
||||
to = pic_make_vec(pic, end - start);
|
||||
while (start < end) {
|
||||
to->data[i++] = vec->data[start++];
|
||||
}
|
||||
|
||||
return pic_obj_value(to);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_append(pic_state *pic)
|
||||
{
|
||||
pic_value *argv;
|
||||
size_t argc, i, j, len;
|
||||
pic_vec *vec;
|
||||
|
||||
pic_get_args(pic, "*", &argc, &argv);
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], vec);
|
||||
len += pic_vec_ptr(argv[i])->len;
|
||||
}
|
||||
|
||||
vec = pic_make_vec(pic, len);
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
for (j = 0; j < pic_vec_ptr(argv[i])->len; ++j) {
|
||||
vec->data[len + j] = pic_vec_ptr(argv[i])->data[j];
|
||||
}
|
||||
len += pic_vec_ptr(argv[i])->len;
|
||||
}
|
||||
|
||||
return pic_obj_value(vec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_fill_i(pic_state *pic)
|
||||
{
|
||||
pic_vec *vec;
|
||||
pic_value obj;
|
||||
int n;
|
||||
size_t start, end;
|
||||
|
||||
n = pic_get_args(pic, "vo|kk", &vec, &obj, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 2:
|
||||
start = 0;
|
||||
case 3:
|
||||
end = vec->len;
|
||||
}
|
||||
|
||||
while (start < end) {
|
||||
vec->data[start++] = obj;
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_map(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
size_t argc, i, len, j;
|
||||
pic_value *argv, vals;
|
||||
pic_vec *vec;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &argv);
|
||||
|
||||
len = INT_MAX;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], vec);
|
||||
|
||||
len = len < pic_vec_ptr(argv[i])->len
|
||||
? len
|
||||
: pic_vec_ptr(argv[i])->len;
|
||||
}
|
||||
|
||||
vec = pic_make_vec(pic, len);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
vals = pic_nil_value();
|
||||
for (j = 0; j < argc; ++j) {
|
||||
pic_push(pic, pic_vec_ptr(argv[j])->data[i], vals);
|
||||
}
|
||||
vec->data[i] = pic_apply(pic, proc, vals);
|
||||
}
|
||||
|
||||
return pic_obj_value(vec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_for_each(pic_state *pic)
|
||||
{
|
||||
struct pic_proc *proc;
|
||||
size_t argc, i, len, j;
|
||||
pic_value *argv, vals;
|
||||
|
||||
pic_get_args(pic, "l*", &proc, &argc, &argv);
|
||||
|
||||
len = INT_MAX;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
pic_assert_type(pic, argv[i], vec);
|
||||
|
||||
len = len < pic_vec_ptr(argv[i])->len
|
||||
? len
|
||||
: pic_vec_ptr(argv[i])->len;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
vals = pic_nil_value();
|
||||
for (j = 0; j < argc; ++j) {
|
||||
pic_push(pic, pic_vec_ptr(argv[j])->data[i], vals);
|
||||
}
|
||||
pic_apply(pic, proc, vals);
|
||||
}
|
||||
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_list_to_vector(pic_state *pic)
|
||||
{
|
||||
struct pic_vector *vec;
|
||||
pic_value list, e, *data;
|
||||
|
||||
pic_get_args(pic, "o", &list);
|
||||
|
||||
vec = pic_make_vec(pic, pic_length(pic, list));
|
||||
|
||||
data = vec->data;
|
||||
|
||||
pic_for_each (e, list) {
|
||||
*data++ = e;
|
||||
}
|
||||
return pic_obj_value(vec);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_to_list(pic_state *pic)
|
||||
{
|
||||
struct pic_vector *vec;
|
||||
pic_value list;
|
||||
int n;
|
||||
size_t start, end, i;
|
||||
|
||||
n = pic_get_args(pic, "v|kk", &vec, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = vec->len;
|
||||
}
|
||||
|
||||
list = pic_nil_value();
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
pic_push(pic, vec->data[i], list);
|
||||
}
|
||||
return pic_reverse(pic, list);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_vector_to_string(pic_state *pic)
|
||||
{
|
||||
pic_vec *vec;
|
||||
char *buf;
|
||||
int n;
|
||||
size_t start, end, i;
|
||||
pic_str *str;
|
||||
|
||||
n = pic_get_args(pic, "v|kk", &vec, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = vec->len;
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
pic_errorf(pic, "vector->string: end index must not be less than start index");
|
||||
}
|
||||
|
||||
buf = pic_alloc(pic, end - start);
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
pic_assert_type(pic, vec->data[i], char);
|
||||
|
||||
buf[i - start] = pic_char(vec->data[i]);
|
||||
}
|
||||
|
||||
str = pic_make_str(pic, buf, end - start);
|
||||
pic_free(pic, buf);
|
||||
|
||||
return pic_obj_value(str);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_vec_string_to_vector(pic_state *pic)
|
||||
{
|
||||
pic_str *str;
|
||||
int n;
|
||||
size_t start, end;
|
||||
size_t i;
|
||||
pic_vec *vec;
|
||||
|
||||
n = pic_get_args(pic, "s|kk", &str, &start, &end);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
start = 0;
|
||||
case 2:
|
||||
end = pic_strlen(str);
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
pic_errorf(pic, "string->vector: end index must not be less than start index");
|
||||
}
|
||||
|
||||
vec = pic_make_vec(pic, end - start);
|
||||
|
||||
for (i = 0; i < end - start; ++i) {
|
||||
vec->data[i] = pic_char_value(pic_str_ref(pic, str, i + start));
|
||||
}
|
||||
return pic_obj_value(vec);
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_vector(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "vector?", pic_vec_vector_p);
|
||||
pic_defun(pic, "vector", pic_vec_vector);
|
||||
pic_defun(pic, "make-vector", pic_vec_make_vector);
|
||||
pic_defun(pic, "vector-length", pic_vec_vector_length);
|
||||
pic_defun(pic, "vector-ref", pic_vec_vector_ref);
|
||||
pic_defun(pic, "vector-set!", pic_vec_vector_set);
|
||||
pic_defun(pic, "vector-copy!", pic_vec_vector_copy_i);
|
||||
pic_defun(pic, "vector-copy", pic_vec_vector_copy);
|
||||
pic_defun(pic, "vector-append", pic_vec_vector_append);
|
||||
pic_defun(pic, "vector-fill!", pic_vec_vector_fill_i);
|
||||
pic_defun(pic, "vector-map", pic_vec_vector_map);
|
||||
pic_defun(pic, "vector-for-each", pic_vec_vector_for_each);
|
||||
pic_defun(pic, "list->vector", pic_vec_list_to_vector);
|
||||
pic_defun(pic, "vector->list", pic_vec_vector_to_list);
|
||||
pic_defun(pic, "string->vector", pic_vec_string_to_vector);
|
||||
pic_defun(pic, "vector->string", pic_vec_vector_to_string);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,504 @@
|
|||
/**
|
||||
* See Copyright Notice in picrin.h
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "picrin.h"
|
||||
#include "picrin/port.h"
|
||||
#include "picrin/pair.h"
|
||||
#include "picrin/string.h"
|
||||
#include "picrin/vector.h"
|
||||
#include "picrin/blob.h"
|
||||
#include "picrin/dict.h"
|
||||
#include "picrin/record.h"
|
||||
#include "picrin/proc.h"
|
||||
|
||||
static bool
|
||||
is_tagged(pic_state *pic, pic_sym tag, pic_value pair)
|
||||
{
|
||||
return pic_pair_p(pic_cdr(pic, pair))
|
||||
&& pic_nil_p(pic_cddr(pic, pair))
|
||||
&& pic_eq_p(pic_car(pic, pair), pic_symbol_value(tag));
|
||||
}
|
||||
|
||||
static bool
|
||||
is_quote(pic_state *pic, pic_value pair)
|
||||
{
|
||||
return is_tagged(pic, pic->sQUOTE, pair);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_unquote(pic_state *pic, pic_value pair)
|
||||
{
|
||||
return is_tagged(pic, pic->sUNQUOTE, pair);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_unquote_splicing(pic_state *pic, pic_value pair)
|
||||
{
|
||||
return is_tagged(pic, pic->sUNQUOTE_SPLICING, pair);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_quasiquote(pic_state *pic, pic_value pair)
|
||||
{
|
||||
return is_tagged(pic, pic->sQUASIQUOTE, pair);
|
||||
}
|
||||
|
||||
struct writer_control {
|
||||
pic_state *pic;
|
||||
xFILE *file;
|
||||
int mode;
|
||||
xhash labels; /* object -> int */
|
||||
xhash visited; /* object -> int */
|
||||
int cnt;
|
||||
};
|
||||
|
||||
#define WRITE_MODE 1
|
||||
#define DISPLAY_MODE 2
|
||||
|
||||
static void
|
||||
writer_control_init(struct writer_control *p, pic_state *pic, xFILE *file, int mode)
|
||||
{
|
||||
p->pic = pic;
|
||||
p->file = file;
|
||||
p->mode = mode;
|
||||
p->cnt = 0;
|
||||
xh_init_ptr(&p->labels, sizeof(int));
|
||||
xh_init_ptr(&p->visited, sizeof(int));
|
||||
}
|
||||
|
||||
static void
|
||||
writer_control_destroy(struct writer_control *p)
|
||||
{
|
||||
xh_destroy(&p->labels);
|
||||
xh_destroy(&p->visited);
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_shared(struct writer_control *p, pic_value obj)
|
||||
{
|
||||
xh_entry *e;
|
||||
size_t i;
|
||||
int c;
|
||||
|
||||
switch (pic_type(obj)) {
|
||||
case PIC_TT_PAIR:
|
||||
case PIC_TT_VECTOR:
|
||||
e = xh_get_ptr(&p->labels, pic_obj_ptr(obj));
|
||||
if (e == NULL) {
|
||||
c = -1;
|
||||
xh_put_ptr(&p->labels, pic_obj_ptr(obj), &c);
|
||||
}
|
||||
else if (xh_val(e, int) == -1) {
|
||||
c = p->cnt++;
|
||||
xh_put_ptr(&p->labels, pic_obj_ptr(obj), &c);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (pic_pair_p(obj)) {
|
||||
traverse_shared(p, pic_car(p->pic, obj));
|
||||
traverse_shared(p, pic_cdr(p->pic, obj));
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < pic_vec_ptr(obj)->len; ++i) {
|
||||
traverse_shared(p, pic_vec_ptr(obj)->data[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* pass */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_core(struct writer_control *p, pic_value);
|
||||
|
||||
static void
|
||||
write_pair(struct writer_control *p, struct pic_pair *pair)
|
||||
{
|
||||
xh_entry *e;
|
||||
int c;
|
||||
|
||||
write_core(p, pair->car);
|
||||
|
||||
if (pic_nil_p(pair->cdr)) {
|
||||
return;
|
||||
}
|
||||
else if (pic_pair_p(pair->cdr)) {
|
||||
|
||||
/* shared objects */
|
||||
if ((e = xh_get_ptr(&p->labels, pic_obj_ptr(pair->cdr))) && xh_val(e, int) != -1) {
|
||||
xfprintf(p->file, " . ");
|
||||
|
||||
if ((xh_get_ptr(&p->visited, pic_obj_ptr(pair->cdr)))) {
|
||||
xfprintf(p->file, "#%d#", xh_val(e, int));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
xfprintf(p->file, "#%d=", xh_val(e, int));
|
||||
c = 1;
|
||||
xh_put_ptr(&p->visited, pic_obj_ptr(pair->cdr), &c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
xfprintf(p->file, " ");
|
||||
}
|
||||
|
||||
write_pair(p, pic_pair_ptr(pair->cdr));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
xfprintf(p->file, " . ");
|
||||
write_core(p, pair->cdr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_str(pic_state *pic, struct pic_string *str, xFILE *file)
|
||||
{
|
||||
size_t i;
|
||||
const char *cstr = pic_str_cstr(str);
|
||||
|
||||
UNUSED(pic);
|
||||
|
||||
for (i = 0; i < pic_strlen(str); ++i) {
|
||||
if (cstr[i] == '"' || cstr[i] == '\\') {
|
||||
xfputc('\\', file);
|
||||
}
|
||||
xfputc(cstr[i], file);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_record(pic_state *pic, struct pic_record *rec, xFILE *file)
|
||||
{
|
||||
const pic_sym sWRITER = pic_intern_cstr(pic, "writer");
|
||||
pic_value type, writer, str;
|
||||
|
||||
#if DEBUG
|
||||
|
||||
xfprintf(file, "#<record %p>", rec);
|
||||
|
||||
#else
|
||||
|
||||
type = pic_record_type(pic, rec);
|
||||
if (! pic_record_p(type)) {
|
||||
pic_errorf(pic, "\"@@type\" property of record object is not of record type");
|
||||
}
|
||||
writer = pic_record_ref(pic, pic_record_ptr(type), sWRITER);
|
||||
if (! pic_proc_p(writer)) {
|
||||
pic_errorf(pic, "\"writer\" property of record type object is not a procedure");
|
||||
}
|
||||
str = pic_apply1(pic, pic_proc_ptr(writer), pic_obj_value(rec));
|
||||
if (! pic_str_p(str)) {
|
||||
pic_errorf(pic, "return value from writer procedure is not of string type");
|
||||
}
|
||||
xfprintf(file, "%s", pic_str_cstr(pic_str_ptr(str)));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
write_core(struct writer_control *p, pic_value obj)
|
||||
{
|
||||
pic_state *pic = p->pic;
|
||||
xFILE *file = p->file;
|
||||
size_t i;
|
||||
xh_entry *e, *it;
|
||||
int c;
|
||||
double f;
|
||||
|
||||
/* shared objects */
|
||||
if (pic_vtype(obj) == PIC_VTYPE_HEAP
|
||||
&& (e = xh_get_ptr(&p->labels, pic_obj_ptr(obj)))
|
||||
&& xh_val(e, int) != -1) {
|
||||
if ((xh_get_ptr(&p->visited, pic_obj_ptr(obj)))) {
|
||||
xfprintf(file, "#%d#", xh_val(e, int));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
xfprintf(file, "#%d=", xh_val(e, int));
|
||||
c = 1;
|
||||
xh_put_ptr(&p->visited, pic_obj_ptr(obj), &c);
|
||||
}
|
||||
}
|
||||
|
||||
switch (pic_type(obj)) {
|
||||
case PIC_TT_UNDEF:
|
||||
xfprintf(file, "#<undef>");
|
||||
break;
|
||||
case PIC_TT_NIL:
|
||||
xfprintf(file, "()");
|
||||
break;
|
||||
case PIC_TT_BOOL:
|
||||
if (pic_true_p(obj))
|
||||
xfprintf(file, "#t");
|
||||
else
|
||||
xfprintf(file, "#f");
|
||||
break;
|
||||
case PIC_TT_PAIR:
|
||||
if (is_quote(pic, obj)) {
|
||||
xfprintf(file, "'");
|
||||
write_core(p, pic_list_ref(pic, obj, 1));
|
||||
break;
|
||||
}
|
||||
else if (is_unquote(pic, obj)) {
|
||||
xfprintf(file, ",");
|
||||
write_core(p, pic_list_ref(pic, obj, 1));
|
||||
break;
|
||||
}
|
||||
else if (is_unquote_splicing(pic, obj)) {
|
||||
xfprintf(file, ",@");
|
||||
write_core(p, pic_list_ref(pic, obj, 1));
|
||||
break;
|
||||
}
|
||||
else if (is_quasiquote(pic, obj)) {
|
||||
xfprintf(file, "`");
|
||||
write_core(p, pic_list_ref(pic, obj, 1));
|
||||
break;
|
||||
}
|
||||
xfprintf(file, "(");
|
||||
write_pair(p, pic_pair_ptr(obj));
|
||||
xfprintf(file, ")");
|
||||
break;
|
||||
case PIC_TT_SYMBOL:
|
||||
xfprintf(file, "%s", pic_symbol_name(pic, pic_sym(obj)));
|
||||
break;
|
||||
case PIC_TT_CHAR:
|
||||
if (p->mode == DISPLAY_MODE) {
|
||||
xfputc(pic_char(obj), file);
|
||||
break;
|
||||
}
|
||||
switch (pic_char(obj)) {
|
||||
default: xfprintf(file, "#\\%c", pic_char(obj)); break;
|
||||
case '\a': xfprintf(file, "#\\alarm"); break;
|
||||
case '\b': xfprintf(file, "#\\backspace"); break;
|
||||
case 0x7f: xfprintf(file, "#\\delete"); break;
|
||||
case 0x1b: xfprintf(file, "#\\escape"); break;
|
||||
case '\n': xfprintf(file, "#\\newline"); break;
|
||||
case '\r': xfprintf(file, "#\\return"); break;
|
||||
case ' ': xfprintf(file, "#\\space"); break;
|
||||
case '\t': xfprintf(file, "#\\tab"); break;
|
||||
}
|
||||
break;
|
||||
case PIC_TT_FLOAT:
|
||||
f = pic_float(obj);
|
||||
if (isnan(f)) {
|
||||
xfprintf(file, signbit(f) ? "-nan.0" : "+nan.0");
|
||||
} else if (isinf(f)) {
|
||||
xfprintf(file, signbit(f) ? "-inf.0" : "+inf.0");
|
||||
} else {
|
||||
xfprintf(file, "%f", pic_float(obj));
|
||||
}
|
||||
break;
|
||||
case PIC_TT_INT:
|
||||
xfprintf(file, "%d", pic_int(obj));
|
||||
break;
|
||||
case PIC_TT_EOF:
|
||||
xfprintf(file, "#.(eof-object)");
|
||||
break;
|
||||
case PIC_TT_STRING:
|
||||
if (p->mode == DISPLAY_MODE) {
|
||||
xfprintf(file, "%s", pic_str_cstr(pic_str_ptr(obj)));
|
||||
break;
|
||||
}
|
||||
xfprintf(file, "\"");
|
||||
write_str(pic, pic_str_ptr(obj), file);
|
||||
xfprintf(file, "\"");
|
||||
break;
|
||||
case PIC_TT_VECTOR:
|
||||
xfprintf(file, "#(");
|
||||
for (i = 0; i < pic_vec_ptr(obj)->len; ++i) {
|
||||
write_core(p, pic_vec_ptr(obj)->data[i]);
|
||||
if (i + 1 < pic_vec_ptr(obj)->len) {
|
||||
xfprintf(file, " ");
|
||||
}
|
||||
}
|
||||
xfprintf(file, ")");
|
||||
break;
|
||||
case PIC_TT_BLOB:
|
||||
xfprintf(file, "#u8(");
|
||||
for (i = 0; i < pic_blob_ptr(obj)->len; ++i) {
|
||||
xfprintf(file, "%d", pic_blob_ptr(obj)->data[i]);
|
||||
if (i + 1 < pic_blob_ptr(obj)->len) {
|
||||
xfprintf(file, " ");
|
||||
}
|
||||
}
|
||||
xfprintf(file, ")");
|
||||
break;
|
||||
case PIC_TT_DICT:
|
||||
xfprintf(file, "#.(dictionary");
|
||||
for (it = xh_begin(&pic_dict_ptr(obj)->hash); it != NULL; it = xh_next(it)) {
|
||||
xfprintf(file, " '");
|
||||
write_core(p, xh_key(it, pic_value));
|
||||
xfprintf(file, " '");
|
||||
write_core(p, xh_val(it, pic_value));
|
||||
}
|
||||
xfprintf(file, ")");
|
||||
break;
|
||||
case PIC_TT_RECORD:
|
||||
write_record(pic, pic_record_ptr(obj), file);
|
||||
break;
|
||||
default:
|
||||
xfprintf(file, "#<%s %p>", pic_type_repr(pic_type(obj)), pic_ptr(obj));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write(pic_state *pic, pic_value obj, xFILE *file)
|
||||
{
|
||||
struct writer_control p;
|
||||
|
||||
writer_control_init(&p, pic, file, WRITE_MODE);
|
||||
|
||||
traverse_shared(&p, obj); /* FIXME */
|
||||
|
||||
write_core(&p, obj);
|
||||
|
||||
writer_control_destroy(&p);
|
||||
}
|
||||
|
||||
static void
|
||||
write_simple(pic_state *pic, pic_value obj, xFILE *file)
|
||||
{
|
||||
struct writer_control p;
|
||||
|
||||
writer_control_init(&p, pic, file, WRITE_MODE);
|
||||
|
||||
/* no traverse here! */
|
||||
|
||||
write_core(&p, obj);
|
||||
|
||||
writer_control_destroy(&p);
|
||||
}
|
||||
|
||||
static void
|
||||
write_shared(pic_state *pic, pic_value obj, xFILE *file)
|
||||
{
|
||||
struct writer_control p;
|
||||
|
||||
writer_control_init(&p, pic, file, WRITE_MODE);
|
||||
|
||||
traverse_shared(&p, obj);
|
||||
|
||||
write_core(&p, obj);
|
||||
|
||||
writer_control_destroy(&p);
|
||||
}
|
||||
|
||||
static void
|
||||
display(pic_state *pic, pic_value obj, xFILE *file)
|
||||
{
|
||||
struct writer_control p;
|
||||
|
||||
writer_control_init(&p, pic, file, DISPLAY_MODE);
|
||||
|
||||
traverse_shared(&p, obj); /* FIXME */
|
||||
|
||||
write_core(&p, obj);
|
||||
|
||||
writer_control_destroy(&p);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_write(pic_state *pic, pic_value obj)
|
||||
{
|
||||
return pic_fwrite(pic, obj, xstdout);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_fwrite(pic_state *pic, pic_value obj, xFILE *file)
|
||||
{
|
||||
write(pic, obj, file);
|
||||
xfflush(file);
|
||||
return obj;
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_display(pic_state *pic, pic_value obj)
|
||||
{
|
||||
return pic_fdisplay(pic, obj, xstdout);
|
||||
}
|
||||
|
||||
pic_value
|
||||
pic_fdisplay(pic_state *pic, pic_value obj, xFILE *file)
|
||||
{
|
||||
display(pic, obj, file);
|
||||
xfflush(file);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void
|
||||
pic_printf(pic_state *pic, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
pic_str *str;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
str = pic_str_ptr(pic_car(pic, pic_xvformat(pic, fmt, ap)));
|
||||
|
||||
va_end(ap);
|
||||
|
||||
xprintf("%s", pic_str_cstr(str));
|
||||
xfflush(xstdout);
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_write_write(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "o|p", &v, &port);
|
||||
write(pic, v, port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_write_write_simple(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "o|p", &v, &port);
|
||||
write_simple(pic, v, port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_write_write_shared(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "o|p", &v, &port);
|
||||
write_shared(pic, v, port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
static pic_value
|
||||
pic_write_display(pic_state *pic)
|
||||
{
|
||||
pic_value v;
|
||||
struct pic_port *port = pic_stdout(pic);
|
||||
|
||||
pic_get_args(pic, "o|p", &v, &port);
|
||||
display(pic, v, port->file);
|
||||
return pic_none_value();
|
||||
}
|
||||
|
||||
void
|
||||
pic_init_write(pic_state *pic)
|
||||
{
|
||||
pic_defun(pic, "write", pic_write_write);
|
||||
pic_defun(pic, "write-simple", pic_write_write_simple);
|
||||
pic_defun(pic, "write-shared", pic_write_write_shared);
|
||||
pic_defun(pic, "display", pic_write_display);
|
||||
}
|
||||
Loading…
Reference in New Issue