2014-03-01 06:21:44 -05:00
|
|
|
/**
|
|
|
|
* See Copyright Notice in picrin.h
|
|
|
|
*/
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <math.h>
|
2014-03-01 06:21:44 -05:00
|
|
|
#include "picrin.h"
|
2014-06-25 02:36:36 -04:00
|
|
|
#include "picrin/error.h"
|
2014-03-01 06:21:44 -05:00
|
|
|
#include "picrin/pair.h"
|
|
|
|
#include "picrin/string.h"
|
|
|
|
#include "picrin/vector.h"
|
|
|
|
#include "picrin/blob.h"
|
|
|
|
#include "picrin/port.h"
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
typedef pic_value (*read_func_t)(pic_state *, struct pic_port *, char);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value read(pic_state *pic, struct pic_port *port, char c);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static noreturn void
|
|
|
|
read_error(pic_state *pic, const char *msg)
|
|
|
|
{
|
|
|
|
pic_error(pic, msg);
|
|
|
|
}
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static char
|
|
|
|
skip(struct pic_port *port, char c)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
while (isspace(c)) {
|
|
|
|
c = xfgetc(port->file);
|
|
|
|
}
|
|
|
|
return c;
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static char
|
|
|
|
next(struct pic_port *port)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 05:06:48 -04:00
|
|
|
return xfgetc(port->file);
|
2014-06-25 02:36:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static char
|
|
|
|
peek(struct pic_port *port)
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
|
|
|
|
xungetc((c = xfgetc(port->file)), port->file);
|
|
|
|
|
|
|
|
return c;
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
2014-03-31 22:40:20 -04:00
|
|
|
static pic_value
|
2014-06-25 02:36:36 -04:00
|
|
|
read_comment(pic_state *pic, struct pic_port *port, char c)
|
2014-03-31 22:40:20 -04:00
|
|
|
{
|
2014-06-25 05:06:48 -04:00
|
|
|
UNUSED(pic);
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
do {
|
|
|
|
c = next(port);
|
|
|
|
} while (! (c == EOF || c == '\n'));
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 05:06:48 -04:00
|
|
|
return pic_undef_value();
|
2014-06-25 02:36:36 -04:00
|
|
|
}
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
read_block_comment(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
char x, y;
|
2014-06-25 08:38:11 -04:00
|
|
|
int i;
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 05:06:48 -04:00
|
|
|
UNUSED(pic);
|
2014-06-25 02:36:36 -04:00
|
|
|
UNUSED(c);
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
x = next(port);
|
|
|
|
y = next(port);
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 08:38:11 -04:00
|
|
|
i = 1;
|
|
|
|
while (x != EOF && y != EOF && i > 0) {
|
|
|
|
if (x == '|' && y == '#') {
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
if (x == '#' && y == '|') {
|
|
|
|
i++;
|
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
x = y;
|
|
|
|
y = next(port);
|
|
|
|
}
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 05:06:48 -04:00
|
|
|
return pic_undef_value();
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_datum_comment(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
UNUSED(c);
|
|
|
|
|
|
|
|
read(pic, port, next(port));
|
|
|
|
|
|
|
|
return pic_undef_value();
|
2014-06-25 02:36:36 -04:00
|
|
|
}
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
read_quote(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
UNUSED(c);
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return pic_list2(pic, pic_sym_value(pic->sQUOTE), read(pic, port, next(port)));
|
|
|
|
}
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
read_quasiquote(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
UNUSED(c);
|
|
|
|
|
|
|
|
return pic_list2(pic, pic_sym_value(pic->sQUASIQUOTE), read(pic, port, next(port)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_comma(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
c = next(port);
|
|
|
|
|
|
|
|
if (c == '@') {
|
|
|
|
return pic_list2(pic, pic_sym_value(pic->sUNQUOTE_SPLICING), read(pic, port, next(port)));
|
|
|
|
} else {
|
|
|
|
return pic_list2(pic, pic_sym_value(pic->sUNQUOTE), read(pic, port, c));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_symbol(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
static const char TRAIL_SYMBOL[] = "+/*!$%&:@^~?<=>_.-";
|
|
|
|
size_t len;
|
|
|
|
char *buf;
|
|
|
|
pic_sym sym;
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
buf = NULL;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (len != 0) {
|
|
|
|
c = next(port);
|
2014-03-31 22:40:20 -04:00
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
len += 1;
|
|
|
|
buf = pic_realloc(pic, buf, len);
|
|
|
|
buf[len - 1] = c;
|
|
|
|
} while (isalnum(peek(port)) || strchr(TRAIL_SYMBOL, peek(port)));
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
buf[len] = '\0';
|
|
|
|
sym = pic_intern_cstr(pic, buf);
|
|
|
|
pic_free(pic, buf);
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return pic_sym_value(sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_uinteger(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
c = skip(port, c);
|
|
|
|
|
|
|
|
if (! isdigit(c)) {
|
|
|
|
read_error(pic, "expected one or more digits");
|
|
|
|
}
|
|
|
|
|
|
|
|
n = c - '0';
|
|
|
|
while (isdigit(c = peek(port))) {
|
|
|
|
next(port);
|
|
|
|
n = n * 10 + c - '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_number(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
i = read_uinteger(pic, port, c);
|
|
|
|
|
|
|
|
if (peek(port) == '.') {
|
|
|
|
next(port);
|
|
|
|
j = read_uinteger(pic, port, next(port));
|
|
|
|
return pic_float_value(i + (double)j * pow(10, -snprintf(NULL, 0, "%d", j)));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return pic_int_value(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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, char c)
|
|
|
|
{
|
|
|
|
static const char DIGITS[] = "0123456789";
|
|
|
|
|
|
|
|
/* TODO: -inf.0, -nan.0 */
|
|
|
|
|
|
|
|
if (strchr(DIGITS, peek(port))) {
|
|
|
|
return negate(read_number(pic, port, c));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return read_symbol(pic, port, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_plus(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
static const char DIGITS[] = "0123456789";
|
|
|
|
|
|
|
|
/* TODO: +inf.0, +nan.0 */
|
|
|
|
|
|
|
|
if (strchr(DIGITS, peek(port))) {
|
|
|
|
return read_number(pic, port, c);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return read_symbol(pic, port, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_boolean(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
UNUSED(pic);
|
|
|
|
UNUSED(port);
|
|
|
|
|
|
|
|
/* TODO: support #true and #false */
|
|
|
|
|
|
|
|
if (c == 't') {
|
|
|
|
return pic_true_value();
|
|
|
|
} else {
|
|
|
|
return pic_false_value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_char(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
UNUSED(pic);
|
|
|
|
UNUSED(c);
|
|
|
|
|
|
|
|
/* TODO: #\alart, #\space, so on and so on */
|
|
|
|
|
|
|
|
return pic_char_value(next(port));
|
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
|
|
|
read_string(pic_state *pic, struct pic_port *port, char c)
|
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
size_t size, cnt;
|
|
|
|
pic_str *str;
|
|
|
|
|
|
|
|
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++] = c;
|
|
|
|
if (cnt >= size) {
|
|
|
|
buf = pic_realloc(pic, buf, size *= 2);
|
2014-03-31 22:40:20 -04:00
|
|
|
}
|
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
buf[cnt] = '\0';
|
|
|
|
|
|
|
|
str = pic_str_new(pic, buf, size);
|
|
|
|
pic_free(pic, buf);
|
|
|
|
return pic_obj_value(str);
|
2014-03-31 22:40:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
2014-06-25 02:36:36 -04:00
|
|
|
read_unsigned_blob(pic_state *pic, struct pic_port *port, char c)
|
2014-03-31 22:40:20 -04:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
int nbits, n;
|
|
|
|
size_t len;
|
|
|
|
char *buf;
|
|
|
|
pic_blob *blob;
|
2014-03-31 22:40:20 -04:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
nbits = 0;
|
|
|
|
|
|
|
|
while (isdigit(c = next(port))) {
|
|
|
|
nbits = 10 * nbits + c - '0';
|
2014-03-31 22:40:20 -04:00
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
|
|
|
|
if (nbits != 8) {
|
|
|
|
read_error(pic, "unsupported bytevector bit width");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c != '(') {
|
|
|
|
read_error(pic, "expected '(' character");
|
|
|
|
}
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
buf = NULL;
|
|
|
|
c = next(port);
|
|
|
|
while ((c = skip(port, c)) != ')') {
|
|
|
|
n = read_uinteger(pic, port, c);
|
|
|
|
if (n < 0 || (1 << nbits) <= n) {
|
|
|
|
read_error(pic, "invalid element in bytevector literal");
|
|
|
|
}
|
|
|
|
len += 1;
|
|
|
|
buf = pic_realloc(pic, buf, len);
|
|
|
|
buf[len - 1] = n;
|
|
|
|
c = next(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
blob = pic_blob_new(pic, buf, len);
|
|
|
|
pic_free(pic, buf);
|
|
|
|
return pic_obj_value(blob);
|
2014-03-31 22:40:20 -04:00
|
|
|
}
|
|
|
|
|
2014-03-01 06:21:44 -05:00
|
|
|
static pic_value
|
2014-06-25 02:36:36 -04:00
|
|
|
read_pair(pic_state *pic, struct pic_port *port, char c)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
char tOPEN = c, tCLOSE = (tOPEN == '(') ? ')' : ']';
|
2014-03-01 06:21:44 -05:00
|
|
|
pic_value car, cdr;
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
c = skip(port, ' ');
|
|
|
|
|
|
|
|
if (c == tCLOSE) {
|
2014-03-01 06:21:44 -05:00
|
|
|
return pic_nil_value();
|
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
if (c == '.') {
|
|
|
|
cdr = read(pic, port, next(port));
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
if ((c = skip(port, ' ')) != tCLOSE) {
|
|
|
|
read_error(pic, "unmatched parenthesis");
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
return cdr;
|
|
|
|
}
|
|
|
|
else {
|
2014-06-25 02:36:36 -04:00
|
|
|
car = read(pic, port, c);
|
|
|
|
cdr = read_pair(pic, port, tOPEN); /* FIXME: don't use recursion */
|
2014-03-01 06:21:44 -05:00
|
|
|
return pic_cons(pic, car, cdr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
read_vector(pic_state *pic, struct pic_port *port, char c)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
|
|
|
pic_value val;
|
|
|
|
|
|
|
|
val = pic_nil_value();
|
2014-06-25 02:36:36 -04:00
|
|
|
while ((c = skip(port, c)) != ')') {
|
|
|
|
val = pic_cons(pic, read(pic, port, c), val);
|
|
|
|
c = next(port);
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
return pic_obj_value(pic_vec_new_from_list(pic, pic_reverse(pic, val)));
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
2014-06-25 02:36:36 -04:00
|
|
|
read_label_set(pic_state *pic, struct pic_port *port, int i)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
|
|
|
pic_value val;
|
2014-06-25 02:36:36 -04:00
|
|
|
char c;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
switch (c = skip(port, ' ')) {
|
|
|
|
case '(': case '[':
|
|
|
|
{
|
|
|
|
pic_value tmp;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
val = pic_cons(pic, pic_none_value(), pic_none_value());
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
xh_put_int(&pic->rlabels, i, &val);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
tmp = read(pic, port, c);
|
|
|
|
pic_pair_ptr(val)->car = pic_car(pic, tmp);
|
|
|
|
pic_pair_ptr(val)->cdr = pic_cdr(pic, tmp);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
case '#':
|
|
|
|
{
|
|
|
|
bool vect;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
if (peek(port) == '(') {
|
|
|
|
vect = true;
|
|
|
|
} else {
|
|
|
|
vect = false;
|
|
|
|
}
|
2014-03-04 09:44:27 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
if (vect) {
|
|
|
|
pic_vec *tmp;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
val = pic_obj_value(pic_vec_new(pic, 0));
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
xh_put_int(&pic->rlabels, i, &val);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
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);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return val;
|
|
|
|
}
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
FALLTHROUGH;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
val = read(pic, port, c);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
xh_put_int(&pic->rlabels, i, &val);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
read_label_ref(pic_state *pic, struct pic_port *port, int i)
|
|
|
|
{
|
|
|
|
xh_entry *e;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
UNUSED(port);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
e = xh_get_int(&pic->rlabels, i);
|
|
|
|
if (! e) {
|
|
|
|
read_error(pic, "label of given index not defined");
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
2014-06-25 02:36:36 -04:00
|
|
|
return xh_val(e, pic_value);
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static pic_value
|
2014-06-25 02:36:36 -04:00
|
|
|
read_label(pic_state *pic, struct pic_port *port, char c)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
int i;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
i = 0;
|
|
|
|
do {
|
|
|
|
i = i * 10 + c;
|
|
|
|
} while (isdigit(c = next(port)));
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
if (c == '=') {
|
|
|
|
return read_label_set(pic, port, i);
|
|
|
|
}
|
|
|
|
if (c == '#') {
|
|
|
|
return read_label_ref(pic, port, i);
|
|
|
|
}
|
|
|
|
read_error(pic, "broken label expression");
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
read_dispatch(pic_state *pic, struct pic_port *port, char c)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
c = next(port);
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case '!':
|
|
|
|
return read_comment(pic, port, c);
|
|
|
|
case '|':
|
|
|
|
return read_block_comment(pic, port, c);
|
|
|
|
case ';':
|
|
|
|
return read_datum_comment(pic, port, c);
|
|
|
|
case 't': case 'f':
|
|
|
|
return read_boolean(pic, port, c);
|
|
|
|
case '\\':
|
|
|
|
return read_char(pic, port, c);
|
|
|
|
case '(':
|
|
|
|
return read_vector(pic, port, c);
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
return read_label(pic, port, c);
|
|
|
|
case 'u':
|
|
|
|
return read_unsigned_blob(pic, port, c);
|
|
|
|
default:
|
|
|
|
read_error(pic, "unexpected dispatch character");
|
|
|
|
}
|
|
|
|
}
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
2014-06-25 05:06:48 -04:00
|
|
|
read_nullable(pic_state *pic, struct pic_port *port, char c)
|
2014-06-25 02:36:36 -04:00
|
|
|
{
|
|
|
|
c = skip(port, c);
|
|
|
|
|
|
|
|
if (c == EOF) {
|
|
|
|
read_error(pic, "unexpected EOF");
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
switch (c) {
|
|
|
|
case ';':
|
|
|
|
return read_comment(pic, port, c);
|
|
|
|
case '#':
|
|
|
|
return read_dispatch(pic, port, c);
|
|
|
|
case '\'':
|
|
|
|
return read_quote(pic, port, c);
|
|
|
|
case '`':
|
|
|
|
return read_quasiquote(pic, port, c);
|
|
|
|
case ',':
|
|
|
|
return read_comma(pic, port, c);
|
|
|
|
case '"':
|
|
|
|
return read_string(pic, port, c);
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
return read_number(pic, port, c);
|
|
|
|
case '+':
|
|
|
|
return read_plus(pic, port, c);
|
|
|
|
case '-':
|
|
|
|
return read_minus(pic, port, c);
|
|
|
|
case '(': case '[':
|
|
|
|
return read_pair(pic, port, c);
|
|
|
|
default:
|
|
|
|
return read_symbol(pic, port, c);
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 05:06:48 -04:00
|
|
|
static pic_value
|
|
|
|
read(pic_state *pic, struct pic_port *port, char c)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 05:06:48 -04:00
|
|
|
pic_value val;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 05:06:48 -04:00
|
|
|
retry:
|
|
|
|
val = read_nullable(pic, port, c);
|
|
|
|
|
|
|
|
if (pic_undef_p(val)) {
|
|
|
|
c = next(port);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
pic_value
|
|
|
|
pic_read(pic_state *pic, struct pic_port *port)
|
|
|
|
{
|
2014-06-25 08:40:18 -04:00
|
|
|
pic_value val;
|
|
|
|
char c = next(port);
|
2014-06-25 05:06:48 -04:00
|
|
|
|
2014-06-25 08:40:18 -04:00
|
|
|
retry:
|
|
|
|
c = skip(port, c);
|
2014-06-25 05:06:48 -04:00
|
|
|
|
2014-06-25 08:40:18 -04:00
|
|
|
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;
|
2014-06-25 02:36:36 -04:00
|
|
|
}
|
2014-03-01 06:21:44 -05:00
|
|
|
|
|
|
|
pic_value
|
2014-06-25 02:36:36 -04:00
|
|
|
pic_read_cstr(pic_state *pic, const char *str)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
struct pic_port *port;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
port = pic_open_input_string(pic, str);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return pic_read(pic, port);
|
|
|
|
}
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
static pic_value
|
|
|
|
pic_parse(pic_state *pic, struct pic_port *port)
|
|
|
|
{
|
|
|
|
pic_value val, acc;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
pic_try {
|
|
|
|
acc = pic_nil_value();
|
|
|
|
while (! pic_eof_p(val = pic_read(pic, port))) {
|
|
|
|
pic_push(pic, val, acc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pic_catch {
|
|
|
|
return pic_undef_value();
|
|
|
|
}
|
|
|
|
|
|
|
|
return pic_reverse(pic, acc);
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
2014-03-01 06:54:02 -05:00
|
|
|
pic_list
|
2014-03-03 10:26:33 -05:00
|
|
|
pic_parse_file(pic_state *pic, FILE *file)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
struct pic_port *port;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
|
|
|
|
port->file = xfpopen(file);
|
|
|
|
port->flags = PIC_PORT_OUT | PIC_PORT_TEXT;
|
|
|
|
port->status = PIC_PORT_OPEN;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return pic_parse(pic, port);
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|
|
|
|
|
2014-03-01 06:54:02 -05:00
|
|
|
pic_list
|
2014-06-25 02:36:36 -04:00
|
|
|
pic_parse_cstr(pic_state *pic, const char *str)
|
2014-03-01 06:21:44 -05:00
|
|
|
{
|
2014-06-25 02:36:36 -04:00
|
|
|
struct pic_port *port;
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
port = pic_open_input_string(pic, str);
|
2014-03-01 06:21:44 -05:00
|
|
|
|
2014-06-25 02:36:36 -04:00
|
|
|
return pic_parse(pic, port);
|
2014-03-01 06:21:44 -05:00
|
|
|
}
|