/* Copyright(C) 2006-2007 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Senna Query Language is based on Mini-Scheme, original credits follow */ /* * ---------- Mini-Scheme Interpreter Version 0.85 ---------- * * coded by Atsushi Moriwaki (11/5/1989) * * E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp * * THIS SOFTWARE IS IN THE PUBLIC DOMAIN * ------------------------------------ * This software is completely free to copy, modify and/or re-distribute. * But I would appreciate it if you left my name on the code as the author. * */ /*-- * * This version has been modified by R.C. Secrist. * * Mini-Scheme is now maintained by Akira KIDA. * * This is a revised and modified version by Akira KIDA. * current version is 0.85k4 (15 May 1994) * * Please send suggestions, bug reports and/or requests to: * *-- */ #include "senna_in.h" #include #include #include #include #include "ql.h" #define InitFile "init.scm" /* global variables */ sen_cell *sen_ql_nil; /* special cell representing empty cell */ sen_cell *sen_ql_t; /* special cell representing #t */ sen_cell *sen_ql_f; /* special cell representing #f */ /* sen query language */ /* todo : update set-car! set-cdr! inline static void obj_ref(sen_cell *o) { if (o->nrefs < 0xffff) { o->nrefs++; } if (PAIRP(o)) { // todo : check cycle if (CAR(o) != NIL) { obj_ref(CAR(o)); } if (CDR(o) != NIL) { obj_ref(CDR(o)); } } } inline static void obj_unref(sen_cell *o) { if (!o->nrefs) { SEN_LOG(sen_log_error, "o->nrefs corrupt"); return; } if (o->nrefs < 0xffff) { o->nrefs--; } if (PAIRP(o)) { // todo : check cycle if (CAR(o) != NIL) { obj_unref(CAR(o)); } if (CDR(o) != NIL) { obj_unref(CDR(o)); } } } inline static void rplaca(sen_ctx *ctx, sen_cell *a, sen_cell *b) { if (a->nrefs) { ctx->impl->nbinds++; if (a->u.l.car) { ctx->impl->nunbinds++; obj_unref(a->u.l.car); } if (b) { obj_ref(b); } } a->u.l.car = b; } inline static void rplacd(sen_ctx *ctx, sen_cell *a, sen_cell *b) { if (a->nrefs) { ctx->impl->nbinds++; if (a->u.l.cdr) { ctx->impl->nunbinds++; obj_unref(a->u.l.cdr); } if (b) { obj_ref(b); } } a->u.l.cdr = b; } */ sen_rc sen_obj2int(sen_ctx *ctx, sen_cell *o) { sen_rc rc = sen_invalid_argument; if (o) { switch (o->header.type) { case SEN_CELL_STR : if (o->u.b.size) { const char *end = o->u.b.value + o->u.b.size, *rest; int64_t i = sen_atoll(o->u.b.value, end, &rest); if (rest == end) { sen_cell_clear(ctx, o); SETINT(o, i); rc = sen_success; } } break; case SEN_CELL_INT : rc = sen_success; break; default : break; } } return rc; } static void symbol2str(void *x, char *buf) { uint16_t symname_size; const char *symname = _sen_hash_strkey_by_val(x, &symname_size); memcpy(buf, symname, symname_size); buf[symname_size] = '\0'; } static int keywordp(void *x) { uint16_t symname_size; const char *symname = _sen_hash_strkey_by_val(x, &symname_size); return symname_size && *symname == ':'; } /* get new symbol */ sen_cell * sen_ql_mk_symbol(sen_ctx *ctx, const char *name, int name_size) { sen_cell *x; sen_search_flags f = SEN_TABLE_ADD; if (!sen_hash_get(ctx, ctx->impl->symbols, name, name_size, (void **) &x, &f)) { return F; } if (!x->header.impl_flags) { x->header.impl_flags |= SEN_CELL_SYMBOL; x->header.type = SEN_VOID; } if (x->header.type == SEN_VOID && ctx->impl->db) { uint16_t symname_size; const char *symname = _sen_hash_strkey_by_val(x, &symname_size); sen_obj *obj = sen_ctx_lookup(ctx, symname, symname_size); if (obj) { sen_ql_obj_bind(obj, x); } } return x; } sen_cell * sen_ql_at(sen_ctx *ctx, const char *key) { sen_cell *o; if (!sen_hash_at(ctx, ctx->impl->symbols, key, strlen(key), (void **) &o)) { return NULL; } return o; } void sen_ql_def_native_func(sen_ctx *ctx, const char *name, sen_ql_native_func *func) { sen_cell *o = INTERN(name); if (o != F) { o->header.type = SEN_VOID; o->header.impl_flags |= SEN_CELL_NATIVE; o->u.o.func = func; } } /* inline static void sen_ctx_igc(sen_ctx *ctx) { uint32_t i; sen_cell *o; sen_set_eh *ep; for (i = ctx->impl->lseqno; i != ctx->impl->seqno; i++) { if ((ep = sen_set_at(ctx->impl->objects, &i, (void **) &o))) { if (ctx->impl->nbinds && (o->nrefs || (BULKP(o) && (o->header.impl_flags & SEN_OBJ_ALLOCATED)))) { continue; } sen_cell_clear(ctx, o); sen_set_del(ctx->impl->objects, ep); } } ctx->impl->lseqno = ctx->impl->seqno; ctx->impl->nbinds = 0; } */ #define MARKP(p) ((p)->header.impl_flags & SEN_CELL_MARKED) #define REFERERP(p) ((p)->header.type & SEN_CELL_LIST) #define SETREFERER(p) ((p)->header.type |= SEN_CELL_LIST) #define UNSETREFERER(p) ((p)->header.type &= ~SEN_CELL_LIST) /*-- * We use algorithm E (Knuth, The Art of Computer Programming Vol.1, * sec.3.5) for marking. */ inline static void obj_mark(sen_ctx *ctx, sen_cell *o) { sen_cell *t, *q, *p; t = NULL; p = o; // if (MARKP(o)) { return; } E2: p->header.impl_flags |= SEN_CELL_MARKED; // if (!o->nrefs) { SEN_LOG(sen_log_error, "obj->nrefs corrupt"); } if (BULKP(o) && !(o->header.impl_flags & SEN_OBJ_ALLOCATED)) { char *b = SEN_MALLOC(o->u.b.size + 1); if (b) { memcpy(b, o->u.b.value, o->u.b.size); b[o->u.b.size] = '\0'; o->u.b.value = b; o->header.impl_flags |= SEN_OBJ_ALLOCATED; } } if (!REFERERP(p)) { goto E6; } q = CAR(p); if (q && !MARKP(q)) { UNSETREFERER(p); CAR(p) = t; t = p; p = q; goto E2; } E5: q = CDR(p); if (q && !MARKP(q)) { CDR(p) = t; t = p; p = q; goto E2; } E6: if (!t) { return; } q = t; if (!REFERERP(q)) { SETREFERER(q); t = CAR(q); CAR(q) = p; p = q; goto E5; } else { t = CDR(q); CDR(q) = p; p = q; goto E6; } } #define MARK2P(p) ((p)->header.impl_flags & SEN_CELL_MARK2) sen_rc sen_ql_obj_mark(sen_ctx *ctx, sen_cell *o) { sen_cell *t, *q, *p; t = NULL; p = o; if (MARK2P(o)) { return sen_invalid_argument; } E2: p->header.impl_flags |= SEN_CELL_MARK2; if (!REFERERP(p)) { goto E6; } q = CAR(p); if (q && !MARK2P(q)) { UNSETREFERER(p); CAR(p) = t; t = p; p = q; goto E2; } E5: q = CDR(p); if (q && !MARK2P(q)) { CDR(p) = t; t = p; p = q; goto E2; } E6: if (!t) { return sen_success; } q = t; if (!REFERERP(q)) { SETREFERER(q); t = CAR(q); CAR(q) = p; p = q; goto E5; } else { t = CDR(q); CDR(q) = p; p = q; goto E6; } return sen_success; } sen_rc sen_ql_obj_unmark(sen_ctx *ctx, sen_cell *o) { sen_cell *t, *q, *p; t = NULL; p = o; if (!MARK2P(o)) { return sen_invalid_argument; } E2: p->header.impl_flags &= ~SEN_CELL_MARK2; if (!REFERERP(p)) { goto E6; } q = CAR(p); if (q && MARK2P(q)) { UNSETREFERER(p); CAR(p) = t; t = p; p = q; goto E2; } E5: q = CDR(p); if (q && MARK2P(q)) { CDR(p) = t; t = p; p = q; goto E2; } E6: if (!t) { return sen_success; } q = t; if (!REFERERP(q)) { SETREFERER(q); t = CAR(q); CAR(q) = p; p = q; goto E5; } else { t = CDR(q); CDR(q) = p; p = q; goto E6; } return sen_success; } inline static sen_rc sen_ctx_mgc(sen_ctx *ctx) { /* if (!(sc = sen_set_cursor_open(ctx->impl->symbols))) { return sen_memory_exhausted; } { sen_cell *o; while (sen_set_cursor_next(sc, NULL, (void **) &o)) { obj_mark(o); } sen_set_cursor_close(sc); } */ obj_mark(ctx, ctx->impl->global_env); /* mark current registers */ obj_mark(ctx, ctx->impl->args); obj_mark(ctx, ctx->impl->envir); obj_mark(ctx, ctx->impl->code); obj_mark(ctx, ctx->impl->dump); obj_mark(ctx, ctx->impl->value); obj_mark(ctx, ctx->impl->phs); ctx->impl->n_entries = 0; { sen_cell *o; SEN_ARRAY_EACH(ctx->impl->objects, 0, 0, id, &o, { if (o->header.impl_flags & (SEN_CELL_MARKED|SEN_CELL_MARK2)) { o->header.impl_flags &= ~SEN_CELL_MARKED; ctx->impl->n_entries++; } else { sen_cell_clear(ctx, o); sen_array_delete_by_id(ctx, ctx->impl->objects, id, NULL); } }); } { sen_tmp_obj_db *o; SEN_ARRAY_EACH(ctx->impl->values, 0, 0, id, &o, { if (o->cell.header.impl_flags & (SEN_CELL_MARKED|SEN_CELL_MARK2)) { o->cell.header.impl_flags &= ~SEN_CELL_MARKED; ctx->impl->n_entries++; } else { sen_obj_close(ctx, (sen_obj *)o->obj); } }); } ctx->impl->lseqno = ctx->impl->seqno; ctx->impl->nbinds = 0; ctx->impl->nunbinds = 0; return sen_success; } inline static void Eval_Cycle(sen_ctx *ctx); /* ========== Evaluation Cycle ========== */ /* operator code */ enum { OP_T0LVL = SEN_OP_T0LVL, OP_ERR0 = SEN_OP_ERR0, OP_LOAD, OP_T1LVL, OP_READ, OP_VALUEPRINT, OP_EVAL, OP_E0ARGS, OP_E1ARGS, OP_APPLY, OP_DOMACRO, OP_LAMBDA, OP_QUOTE, OP_DEF0, OP_DEF1, OP_BEGIN, OP_IF0, OP_IF1, OP_SET0, OP_SET1, OP_LET0, OP_LET1, OP_LET2, OP_LET0AST, OP_LET1AST, OP_LET2AST, OP_LET0REC, OP_LET1REC, OP_LET2REC, OP_COND0, OP_COND1, OP_DELAY, OP_AND0, OP_AND1, OP_OR0, OP_OR1, OP_C0STREAM, OP_C1STREAM, OP_0MACRO, OP_1MACRO, OP_CASE0, OP_CASE1, OP_CASE2, OP_PEVAL, OP_PAPPLY, OP_CONTINUATION, OP_SETCAR, OP_SETCDR, OP_FORCE, OP_ERR1, OP_PUT, OP_GET, OP_QUIT, OP_SDOWN, OP_RDSEXPR, OP_RDLIST, OP_RDDOT, OP_RDQUOTE, OP_RDQQUOTE, OP_RDUNQUOTE, OP_RDUQTSP, OP_NATIVE, OP_QQUOTE0, OP_QQUOTE1, OP_QQUOTE2 }; sen_cell * sen_ql_feed(sen_ctx *ctx, char *str, uint32_t str_size, int mode) { if (SEN_QL_WAITINGP(ctx)) { SEN_BULK_REWIND(&ctx->impl->outbuf); SEN_BULK_REWIND(&ctx->impl->subbuf); ctx->impl->bufcur = 0; } for (;;) { switch (ctx->stat) { case SEN_QL_TOPLEVEL : ctx->impl->co.mode &= ~SEN_CTX_HEAD; Eval_Cycle(ctx); break; case SEN_QL_WAIT_EXPR : ctx->impl->co.mode = mode; ctx->impl->cur = str; ctx->impl->str_end = str + str_size; Eval_Cycle(ctx); break; case SEN_QL_WAIT_ARG : ctx->impl->co.mode = mode; if ((mode & SEN_CTX_HEAD)) { ctx->impl->cur = str; ctx->impl->str_end = str + str_size; } else { char *buf; sen_cell *ph = CAR(ctx->impl->phs); if (!(buf = SEN_MALLOC(str_size + 1))) { return NIL; } memcpy(buf, str, str_size); buf[str_size] = '\0'; ph->header.impl_flags |= SEN_OBJ_ALLOCATED; ph->u.b.value = buf; ph->u.b.size = str_size; ctx->impl->phs = CDR(ctx->impl->phs); } if ((ctx->impl->phs == NIL) || (mode & (SEN_CTX_HEAD|SEN_CTX_TAIL))) { ctx->stat = SEN_QL_EVAL; } break; case SEN_QL_EVAL : Eval_Cycle(ctx); break; case SEN_QL_WAIT_DATA : ctx->impl->co.mode = mode; if ((mode & SEN_CTX_HEAD)) { ctx->impl->args = NIL; ctx->impl->cur = str; ctx->impl->str_end = str + str_size; } else { ctx->impl->arg.u.b.value = str; ctx->impl->arg.u.b.size = str_size; ctx->impl->arg.header.type = SEN_CELL_STR; ctx->impl->args = &ctx->impl->arg; } /* fall through */ case SEN_QL_NATIVE : SEN_ASSERT(ctx->impl->co.func); ctx->impl->value = ctx->impl->co.func(ctx, ctx->impl->args, &ctx->impl->co); if (ERRP(ctx, SEN_ERROR)) { ctx->stat = SEN_QL_QUITTING; return F; } ERRCLR(ctx); if (ctx->impl->co.last && !(ctx->impl->co.mode & (SEN_CTX_HEAD|SEN_CTX_TAIL))) { ctx->stat = SEN_QL_WAIT_DATA; } else { ctx->impl->co.mode = 0; Eval_Cycle(ctx); } break; case SEN_QL_QUITTING : case SEN_CTX_QUIT : return NIL; } if (ERRP(ctx, SEN_ERROR)) { ctx->stat = SEN_QL_QUITTING; return F; } if (SEN_QL_WAITINGP(ctx)) { /* waiting input data */ if (ctx->impl->inbuf) { SEN_FREE(ctx->impl->inbuf); ctx->impl->inbuf = NULL; } break; } if ((ctx->stat & 0x40) && SEN_QL_GET_MODE(ctx) == sen_ql_step) { break; } } return NIL; } /**** sexp parser ****/ inline static void skipline(sen_ctx *ctx) { while (ctx->impl->cur < ctx->impl->str_end) { if (*ctx->impl->cur++ == '\n') { break; } } } /*************** scheme interpreter ***************/ # define BACKQUOTE '`' #include #include /* macros for cell operations */ #define HASPROP(p) ((p)->header.impl_flags & SEN_CELL_SYMBOL) #define SYMPROP(p) CDR(p) #define SYNTAXP(p) ((p)->header.type == SEN_CELL_SYNTAX) #define SYNTAXNUM(p) ((p)->header.domain) #define PROCNUM(p) IVALUE(p) #define MACROP(p) ((p)->header.type == SEN_CELL_MACRO) #define CLOSURE_CODE(p) CAR(p) #define CLOSURE_ENV(p) CDR(p) #define CONT_DUMP(p) CDR(p) #define PROMISEP(p) ((p)->header.impl_flags & SEN_CELL_PROMISE) #define SETPROMISE(p) (p)->header.impl_flags |= SEN_CELL_PROMISE #define LAMBDA (INTERN("lambda")) #define QUOTE (INTERN("quote")) #define QQUOTE (INTERN("quasiquote")) #define UNQUOTE (INTERN("unquote")) #define UNQUOTESP (INTERN("unquote-splicing")) /* get new cell. parameter a, b is marked by gc. */ #define GET_CELL(ctx,a,b,o) SEN_CELL_NEW(ctx, o) /* get number atom */ inline static sen_cell * mk_number(sen_ctx *ctx, int64_t num) { sen_cell *x; SEN_CELL_NEW(ctx, x); SETINT(x, num); return x; } /* get new string */ sen_cell * sen_ql_mk_string(sen_ctx *ctx, const char *str, unsigned int len) { sen_cell *x = sen_cell_alloc(ctx, len); if (!x) { return F; } memcpy(x->u.b.value, str, len); x->u.b.value[len] = '\0'; return x; } inline static sen_cell * mk_const_string(sen_ctx *ctx, const char *str) { sen_cell *x; SEN_CELL_NEW(ctx, x); x->header.impl_flags = 0; x->header.type = SEN_CELL_STR; x->u.b.value = (char *)str; x->u.b.size = strlen(str); return x; } sen_cell * sen_ql_mk_symbol2(sen_ctx *ctx, const char *q, unsigned int len, int kwdp) { char buf[SEN_SYM_MAX_KEY_SIZE], *p = buf; if (len + 1 >= SEN_SYM_MAX_KEY_SIZE) { QLERR("too long symbol"); } if (kwdp) { *p++ = ':'; memcpy(p, q, len); len++; } else { memcpy(p, q, len); } return sen_ql_mk_symbol(ctx, buf, len); } static sen_cell * str2num(sen_ctx *ctx, char *str, unsigned int len) { const char *cur, *str_end = str + len; int64_t i = sen_atoll(str, str_end, &cur); if (cur == str_end) { return mk_number(ctx, i); } if (cur != str) { /* todo : support #i notation */ char *end, buf0[128], *buf = len < 128 ? buf0 : SEN_MALLOC(len + 1); if (buf) { double d; memcpy(buf, str, len); buf[len] = '\0'; errno = 0; d = strtod(buf, &end); if (!(len < 128)) { SEN_FREE(buf); } if (!errno && buf + len == end) { sen_cell *x; SEN_CELL_NEW(ctx, x); SETFLOAT(x, d); return x; } } } return NIL; } /* make symbol or number atom from string */ static sen_cell * mk_atom(sen_ctx *ctx, char *str, unsigned int len, sen_cell *v) { sen_cell **vp = &v, *p; const char *cur, *last, *str_end = str + len; if ((p = str2num(ctx, str, len)) != NIL) { return p; } for (last = cur = str; cur < str_end; cur += len) { if (!(len = sen_str_charlen_nonnull(cur, str_end, ctx->encoding))) { break; } if (*cur == '.') { if (last < cur) { *vp = sen_ql_mk_symbol2(ctx, last, cur - last, str != last); } v = CONS(v, CONS(NIL, NIL)); vp = &CADR(v); last = cur + 1; } } if (last < cur) { *vp = sen_ql_mk_symbol2(ctx, last, cur - last, str != last); } return v; } /* make constant */ inline static sen_cell * mk_const(sen_ctx *ctx, char *name, unsigned int len) { char tmp[256]; char tmp2[256]; /* todo : rewirte with sen_str_* functions */ if (len == 1) { if (*name == 't') { return T; } else if (*name == 'f') { return F; } } else if (len > 1) { if (*name == 'p' && name[1] == '<' && name[12] == '>') {/* #p (SEN_CELL_OBJECT) */ sen_id cls = sen_btoi(name + 2); if (cls) { sen_id self = sen_btoi(name + 7); if (self) { sen_cell * v = sen_ql_obj_new(ctx, cls, self); if (len > 13 && name[13] == '.') { return mk_atom(ctx, name + 13, len - 13, v); } else { return v; } } } } else if (*name == ':' && name[1] == '<') {/* #: (SEN_CELL_TIME) */ sen_cell *x; sen_timeval tv; const char *cur; tv.tv_sec = sen_atoi(name + 2, name + len, &cur); if (cur >= name + len || *cur != '.') { QLERR("illegal time format '%s'", name); } tv.tv_usec = sen_atoi(cur + 1, name + len, &cur); if (cur >= name + len || *cur != '>') { QLERR("illegal time format '%s'", name); } SEN_CELL_NEW(ctx, x); SETTIME(x, &tv); return x; } else if (*name == 'o') {/* #o (octal) */ long long unsigned int x; len = (len > 255) ? 255 : len - 1; memcpy(tmp2, name + 1, len); tmp2[len] = '\0'; sprintf(tmp, "0%s", tmp2); sscanf(tmp, "%Lo", &x); return mk_number(ctx, x); } else if (*name == 'd') { /* #d (decimal) */ long long int x; sscanf(&name[1], "%Ld", &x); return mk_number(ctx, x); } else if (*name == 'x') { /* #x (hex) */ long long unsigned int x; len = (len > 255) ? 255 : len - 1; memcpy(tmp2, name + 1, len); tmp2[len] = '\0'; sprintf(tmp, "0x%s", tmp2); sscanf(tmp, "%Lx", &x); return mk_number(ctx, x); } } return NIL; } sen_rc sen_ctx_load(sen_ctx *ctx, const char *filename) { if (!ctx || !ctx->impl) { return sen_invalid_argument; } if (!filename) { filename = InitFile; } ctx->impl->args = CONS(mk_const_string(ctx, filename), NIL); ctx->stat = SEN_QL_TOPLEVEL; ctx->impl->op = OP_LOAD; return sen_ql_feed(ctx, "init", 4, 0) == F ? sen_internal_error : sen_success; } /* ========== Routines for Reading ========== */ #define TOK_LPAREN 0 #define TOK_RPAREN 1 #define TOK_DOT 2 #define TOK_ATOM 3 #define TOK_QUOTE 4 #define TOK_COMMENT 5 #define TOK_DQUOTE 6 #define TOK_BQUOTE 7 #define TOK_COMMA 8 #define TOK_ATMARK 9 #define TOK_SHARP 10 #define TOK_EOS 11 #define TOK_QUESTION 12 #define lparenp(c) ((c) == '(' || (c) == '[') #define rparenp(c) ((c) == ')' || (c) == ']') /* read chacters to delimiter */ inline static char readstr(sen_ctx *ctx, char **str, unsigned int *size) { char *start, *end; for (start = end = ctx->impl->cur;;) { unsigned int len; /* null check and length check */ if (!(len = sen_str_charlen_nonnull(end, ctx->impl->str_end, ctx->encoding))) { ctx->impl->cur = ctx->impl->str_end; break; } if (sen_isspace(end, ctx->encoding) || *end == ';' || lparenp(*end) || rparenp(*end)) { ctx->impl->cur = end; break; } end += len; } if (start < end || ctx->impl->cur < ctx->impl->str_end) { *str = start; *size = (unsigned int)(end - start); return TOK_ATOM; } else { return TOK_EOS; } } /* read string expression "xxx...xxx" */ inline static char readstrexp(sen_ctx *ctx, char **str, unsigned int *size) { char *start, *src, *dest; for (start = src = dest = ctx->impl->cur;;) { unsigned int len; /* null check and length check */ if (!(len = sen_str_charlen_nonnull(src, ctx->impl->str_end, ctx->encoding))) { ctx->impl->cur = ctx->impl->str_end; if (start < dest) { *str = start; *size = (unsigned int)(dest - start); return TOK_ATOM; } return TOK_EOS; } if (src[0] == '"' && len == 1) { ctx->impl->cur = src + 1; *str = start; *size = (unsigned int)(dest - start); return TOK_ATOM; } else if (src[0] == '\\' && src + 1 < ctx->impl->str_end && len == 1) { src++; switch (*src) { case 'n' : *dest++ = '\n'; break; case 'r' : *dest++ = '\r'; break; case 't' : *dest++ = '\t'; break; default : *dest++ = *src; break; } src++; } else { while (len--) { *dest++ = *src++; } } } } /* get token */ inline static char token(sen_ctx *ctx) { SKIPSPACE(ctx->impl); if (ctx->impl->cur >= ctx->impl->str_end) { return TOK_EOS; } switch (*ctx->impl->cur) { case '(': case '[': ctx->impl->cur++; return TOK_LPAREN; case ')': case ']': ctx->impl->cur++; return TOK_RPAREN; case '.': ctx->impl->cur++; if (ctx->impl->cur == ctx->impl->str_end || sen_isspace(ctx->impl->cur, ctx->encoding) || *ctx->impl->cur == ';' || lparenp(*ctx->impl->cur) || rparenp(*ctx->impl->cur)) { return TOK_DOT; } else { ctx->impl->cur--; return TOK_ATOM; } case '\'': ctx->impl->cur++; return TOK_QUOTE; case ';': ctx->impl->cur++; return TOK_COMMENT; case '"': ctx->impl->cur++; return TOK_DQUOTE; case BACKQUOTE: ctx->impl->cur++; return TOK_BQUOTE; case ',': ctx->impl->cur++; if (ctx->impl->cur < ctx->impl->str_end && *ctx->impl->cur == '@') { ctx->impl->cur++; return TOK_ATMARK; } else { return TOK_COMMA; } case '#': ctx->impl->cur++; return TOK_SHARP; case '?': ctx->impl->cur++; return TOK_QUESTION; default: return TOK_ATOM; } } /* ========== Routines for Printing ========== */ #define ok_abbrev(x) (PAIRP(x) && CDR(x) == NIL) void sen_obj_inspect(sen_ctx *ctx, sen_cell *obj, sen_obj *buf, int flags) { if (!obj) { SEN_BULK_PUTS(ctx, buf, "NULL"); } else if (obj == NIL) { SEN_BULK_PUTS(ctx, buf, "()"); } else if (obj == T) { SEN_BULK_PUTS(ctx, buf, "#t"); } else if (obj == F) { SEN_BULK_PUTS(ctx, buf, "#f"); } else { if (SYMBOLP(obj)) { char b[SEN_TABLE_MAX_KEY_SIZE + 1]; symbol2str(obj, b); if (flags & SEN_OBJ_INSPECT_SYMBOL_AS_STR) { sen_bulk_esc(ctx, buf, (*b == ':') ? b + 1 : b, strlen(b) - (*b == ':') ? 1 : 0, ctx->encoding); } else { SEN_BULK_PUTS(ctx, buf, b); } return; } switch (obj->header.type) { case SEN_VOID : if (SYMBOLP(obj)) { char b[SEN_TABLE_MAX_KEY_SIZE + 1]; symbol2str(obj, b); SEN_BULK_PUTS(ctx, buf, b); } else { SEN_BULK_PUTS(ctx, buf, "#"); } break; case SEN_CELL_OBJECT : if (flags & SEN_OBJ_INSPECT_ESC) { SEN_BULK_PUTS(ctx, buf, "#p<"); sen_bulk_itob(ctx, buf, obj->header.domain); sen_bulk_itob(ctx, buf, obj->u.o.id); SEN_BULK_PUTC(ctx, buf, '>'); } else { sen_ql_obj_key(ctx, obj, buf); } break; case SEN_SNIP : case SEN_PATSNIP : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_STR : if (flags & SEN_OBJ_INSPECT_ESC) { sen_bulk_esc(ctx, buf, STRVALUE(obj), STRSIZE(obj), ctx->encoding); } else { sen_bulk_write(ctx, buf, STRVALUE(obj), STRSIZE(obj)); } break; case SEN_CELL_INT : sen_bulk_lltoa(ctx, buf, IVALUE(obj)); break; case SEN_CELL_FLOAT : sen_bulk_ftoa(ctx, buf, FVALUE(obj)); break; case SEN_CELL_TIME : SEN_BULK_PUTS(ctx, buf, "#:<"); sen_bulk_itoa(ctx, buf, obj->u.tv.tv_sec); SEN_BULK_PUTS(ctx, buf, "."); sen_bulk_itoa(ctx, buf, obj->u.tv.tv_usec); SEN_BULK_PUTC(ctx, buf, '>'); break; case SEN_QUERY : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_VERSES : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_OP : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_SYNTAX : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_PROC : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_MACRO : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_CLOSURE : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_CONTINUATION : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_TYPE : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_TABLE_HASH_KEY : case SEN_TABLE_NO_KEY : case SEN_TABLE_PAT_KEY : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_COLUMN_FIX_SIZE : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_COLUMN_VAR_SIZE : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_COLUMN_INDEX : SEN_BULK_PUTS(ctx, buf, "#"); break; case SEN_CELL_LIST : /* todo : detect loop */ if (CAR(obj) == QUOTE && ok_abbrev(CDR(obj))) { SEN_BULK_PUTC(ctx, buf, '\''); sen_obj_inspect(ctx, CADR(obj), buf, flags); } else if (CAR(obj) == QQUOTE && ok_abbrev(CDR(obj))) { SEN_BULK_PUTC(ctx, buf, '`'); sen_obj_inspect(ctx, CADR(obj), buf, flags); } else if (CAR(obj) == UNQUOTE && ok_abbrev(CDR(obj))) { SEN_BULK_PUTC(ctx, buf, ','); sen_obj_inspect(ctx, CADR(obj), buf, flags); } else if (CAR(obj) == UNQUOTESP && ok_abbrev(CDR(obj))) { SEN_BULK_PUTS(ctx, buf, ",@"); sen_obj_inspect(ctx, CADR(obj), buf, flags); } else { SEN_BULK_PUTC(ctx, buf, '('); for (;;) { sen_obj_inspect(ctx, CAR(obj), buf, flags); if ((obj = CDR(obj)) && (obj != NIL)) { if (PAIRP(obj)) { SEN_BULK_PUTC(ctx, buf, ' '); } else { SEN_BULK_PUTS(ctx, buf, " . "); sen_obj_inspect(ctx, obj, buf, flags); SEN_BULK_PUTC(ctx, buf, ')'); break; } } else { SEN_BULK_PUTC(ctx, buf, ')'); break; } } } break; default : if (SYMBOLP(obj)) { char b[SEN_TABLE_MAX_KEY_SIZE + 1]; symbol2str(obj, b); SEN_BULK_PUTS(ctx, buf, b); } else { SEN_BULK_PUTS(ctx, buf, "#header.type); SEN_BULK_PUTS(ctx, buf, ")?>"); } break; } } } /* ========== Routines for Evaluation Cycle ========== */ /* make closure. c is code. e is environment */ inline static sen_cell * mk_closure(sen_ctx *ctx, sen_cell *c, sen_cell *e) { sen_cell *x; GET_CELL(ctx, c, e, x); x->header.type = SEN_CELL_CLOSURE; x->header.impl_flags = 0; CAR(x) = c; CDR(x) = e; return x; } /* make continuation. */ inline static sen_cell * mk_continuation(sen_ctx *ctx, sen_cell *d) { sen_cell *x; GET_CELL(ctx, NIL, d, x); x->header.type = SEN_CELL_CONTINUATION; x->header.impl_flags = 0; CONT_DUMP(x) = d; return x; } /* reverse list -- make new cells */ inline static sen_cell * reverse(sen_ctx *ctx, sen_cell *a) /* a must be checked by gc */ { sen_cell *p = NIL; for ( ; PAIRP(a); a = CDR(a)) { p = CONS(CAR(a), p); if (ERRP(ctx, SEN_ERROR)) { return F; } } return p; } /* reverse list --- no make new cells */ inline static sen_cell * non_alloc_rev(sen_cell *term, sen_cell *list) { sen_cell *p = list, *result = term, *q; while (p != NIL) { q = CDR(p); CDR(p) = result; result = p; p = q; } return result; } /* append list -- make new cells */ inline static sen_cell * append(sen_ctx *ctx, sen_cell *a, sen_cell *b) { sen_cell *p = b, *q; if (a != NIL) { a = reverse(ctx, a); if (ERRP(ctx, SEN_ERROR)) { return F; } while (a != NIL) { q = CDR(a); CDR(a) = p; p = a; a = q; } } return p; } /* equivalence of atoms */ inline static int eqv(sen_cell *a, sen_cell *b) { if (a == b) { return 1; } if (a->header.type != b->header.type) { return 0; } switch (a->header.type) { case SEN_CELL_OBJECT : return (a->u.o.id == b->u.o.id && a->header.domain == b->header.domain); break; case SEN_CELL_STR : return (a->u.b.size == b->u.b.size && !memcmp(a->u.b.value, b->u.b.value, a->u.b.size)); break; case SEN_CELL_INT : return (IVALUE(a) == IVALUE(b)); break; case SEN_CELL_FLOAT : return !islessgreater(FVALUE(a), FVALUE(b)); break; case SEN_CELL_TIME : return (!memcmp(&a->u.tv, &b->u.tv, sizeof(sen_timeval))); break; default : /* todo : support other types */ return 0; break; } } /* expr (&) by int atoms */ inline static int logtest(sen_cell *a, sen_cell *b) { if (a == b) { return 1; } if (a->header.type != b->header.type) { return 0; } switch (a->header.type) { case SEN_CELL_INT : return (IVALUE(a) & IVALUE(b) ? 1 : 0); break; default : return 0; break; } } /* true or false value macro */ #define istrue(p) ((p) != NIL && (p) != F) #define isfalse(p) ((p) == F) /* control macros for Eval_Cycle */ #define s_goto(ctx,a) do {\ ctx->impl->op = (a);\ return T;\ } while (0) #define s_save(ctx,a,b,args) (\ ctx->impl->dump = CONS(ctx->impl->envir, CONS((args), ctx->impl->dump)),\ ctx->impl->dump = CONS((b), ctx->impl->dump),\ ctx->impl->dump = CONS(mk_number(ctx, (int64_t)(a)), ctx->impl->dump)) #define s_return(ctx,a) do {\ ctx->impl->value = (a);\ ctx->impl->op = IVALUE(CAR(ctx->impl->dump));\ ctx->impl->args = CADR(ctx->impl->dump);\ ctx->impl->envir = CADDR(ctx->impl->dump);\ ctx->impl->code = CADDDR(ctx->impl->dump);\ ctx->impl->dump = CDDDDR(ctx->impl->dump);\ return T;\ } while (0) #define RTN_NIL_IF_HEAD(ctx) do {\ if (((ctx)->impl->co.mode & SEN_CTX_HEAD)) { s_goto(ctx, OP_T0LVL); }\ } while (0) #define RTN_NIL_IF_TAIL(ctx) do {\ if (((ctx)->impl->co.mode & SEN_CTX_TAIL)) { s_return((ctx), NIL); } else { return NIL; }\ } while (0) static sen_cell * list_deep_copy(sen_ctx *ctx, sen_cell *c) { /* NOTE: only list is copied */ if (PAIRP(c)) { /* TODO: convert recursion to loop */ return CONS(list_deep_copy(ctx, CAR(c)), list_deep_copy(ctx, CDR(c))); } else { return c; } } static void qquote_uquotelist(sen_ctx *ctx, sen_cell *cl, sen_cell *pcl, int level) { /* reverse list */ sen_cell *x, *y; while (PAIRP(cl)) { x = CAR(cl); if (PAIRP(x)) { y = CAR(x); if (y == UNQUOTE) { if (level) { qquote_uquotelist(ctx, CDR(x), x, level - 1); } else { CDR(ctx->impl->args) = CONS(cl, CDR(ctx->impl->args)); /* save (unquote ...) cell */ } } else if (y == UNQUOTESP) { if (level) { qquote_uquotelist(ctx, CDR(x), x, level - 1); } else { CDR(ctx->impl->args) = CONS(pcl, CDR(ctx->impl->args)); /* save pre (unquote-splicing) cell */ } } else { qquote_uquotelist(ctx, x, cl, level); } } else if (x == QQUOTE) { qquote_uquotelist(ctx, CDR(cl), cl, level + 1); return; } if (!level && CADR(cl) == UNQUOTE) { CDR(ctx->impl->args) = CONS(cl, CDR(ctx->impl->args)); /* save (a . ,b) cell */ return; } pcl = cl; cl = CDR(cl); } } #define GC_THRESHOLD 1000000 static sen_cell * opexe(sen_ctx *ctx) { register sen_cell *x, *y; if (ctx->impl->op == OP_T0LVL || ctx->impl->n_entries > ctx->impl->ncells + GC_THRESHOLD) { if (ctx->impl->gc_verbose) { sen_obj buf; sen_bulk_init(ctx, &buf, 0); sen_obj_inspect(ctx, ctx->impl->envir, &buf, SEN_OBJ_INSPECT_ESC); *buf.u.b.curr = '\0'; SEN_LOG(sen_log_notice, "mgc > ncells=%d envir=<%s>", ctx->impl->n_entries, buf.u.b.head); sen_bulk_fin(ctx, &buf); } sen_ctx_mgc(ctx); if (ctx->impl->gc_verbose) { SEN_LOG(sen_log_notice, "mgc < ncells=%d", ctx->impl->n_entries); } ctx->impl->ncells = ctx->impl->n_entries; } switch (ctx->impl->op) { case OP_LOAD: /* load */ if (BULKP(CAR(ctx->impl->args))) { struct stat st; char *fname = STRVALUE(CAR(ctx->impl->args)); if (fname && !stat(fname, &st)) { if (ctx->impl->inbuf) { SEN_FREE(ctx->impl->inbuf); } if ((ctx->impl->inbuf = SEN_MALLOC(st.st_size))) { int fd; if ((fd = open(fname, O_RDONLY)) != -1) { if (read(fd, ctx->impl->inbuf, st.st_size) == st.st_size) { SEN_BULK_PUTS(ctx, &ctx->impl->outbuf, "loading "); SEN_BULK_PUTS(ctx, &ctx->impl->outbuf, STRVALUE(CAR(ctx->impl->args))); ctx->impl->cur = ctx->impl->inbuf; ctx->impl->str_end = ctx->impl->inbuf + st.st_size; } close(fd); } if (ctx->impl->cur != ctx->impl->inbuf) { SEN_FREE(ctx->impl->inbuf); ctx->impl->inbuf = NULL; } } } } s_goto(ctx, OP_T0LVL); case OP_T0LVL: /* top level */ ctx->impl->dump = NIL; ctx->impl->envir = ctx->impl->global_env; if (ctx->impl->batchmode) { s_save(ctx, OP_T0LVL, NIL, NIL); } else { s_save(ctx, OP_VALUEPRINT, NIL, NIL); } s_save(ctx, OP_T1LVL, NIL, NIL); ctx->impl->pht = &ctx->impl->phs; *ctx->impl->pht = NIL; s_goto(ctx, OP_READ); case OP_T1LVL: /* top level */ // verbose check? if (ctx->impl->phs != NIL && !(ctx->impl->co.mode & (SEN_CTX_HEAD|SEN_CTX_TAIL))) { RTN_NIL_IF_TAIL(ctx); } // SEN_BULK_PUTC(ctx, &ctx->impl->outbuf, '\n'); ctx->impl->code = ctx->impl->value; s_goto(ctx, OP_EVAL); case OP_READ: /* read */ RTN_NIL_IF_HEAD(ctx); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case OP_VALUEPRINT: /* print evalution result */ ctx->impl->args = ctx->impl->value; s_save(ctx, OP_T0LVL, NIL, NIL); sen_obj_inspect(ctx, ctx->impl->args, &ctx->impl->outbuf, SEN_OBJ_INSPECT_ESC); s_return(ctx, T); case OP_EVAL: /* main part of evalution */ // fixme : quick hack. if (SYMBOLP(ctx->impl->code)) { /* symbol */ if (keywordp(ctx->impl->code)) { s_return(ctx, ctx->impl->code); } for (x = ctx->impl->envir; x != NIL; x = CDR(x)) { for (y = CAR(x); y != NIL; y = CDR(y)) if (CAAR(y) == ctx->impl->code) break; if (y != NIL) break; } if (x != NIL) { s_return(ctx, CDAR(y)); } else { if (PROCP(ctx->impl->code)) { s_return(ctx, ctx->impl->code); } if (NATIVE_FUNCP(ctx->impl->code)) { s_return(ctx, ctx->impl->code); } { char buf[SEN_TABLE_MAX_KEY_SIZE + 1]; symbol2str(ctx->impl->code, buf); QLERR("Unbounded variable %s", buf); } } } else if (PAIRP(ctx->impl->code)) { if (SYNTAXP(x = CAR(ctx->impl->code))) { /* SYNTAX */ ctx->impl->code = CDR(ctx->impl->code); s_goto(ctx, SYNTAXNUM(x)); } else {/* first, eval top element and eval arguments */ s_save(ctx, OP_E0ARGS, NIL, ctx->impl->code); ctx->impl->code = CAR(ctx->impl->code); // if (NATIVE_FUNCP(ctx->impl->code)) { s_return(ctx, ctx->impl->code); } /* call native funcs. fast */ s_goto(ctx, OP_EVAL); } } else { s_return(ctx, ctx->impl->code); } case OP_E0ARGS: /* eval arguments */ if (MACROP(ctx->impl->value)) { /* macro expansion */ s_save(ctx, OP_DOMACRO, NIL, NIL); ctx->impl->args = CONS(ctx->impl->code, NIL); ctx->impl->code = ctx->impl->value; s_goto(ctx, OP_APPLY); } else { ctx->impl->code = CDR(ctx->impl->code); s_goto(ctx, OP_E1ARGS); } case OP_E1ARGS: /* eval arguments */ ctx->impl->args = CONS(ctx->impl->value, ctx->impl->args); if (PAIRP(ctx->impl->code)) { /* continue */ s_save(ctx, OP_E1ARGS, ctx->impl->args, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); ctx->impl->args = NIL; s_goto(ctx, OP_EVAL); } else { /* end */ ctx->impl->args = reverse(ctx, ctx->impl->args); ctx->impl->code = CAR(ctx->impl->args); ctx->impl->args = CDR(ctx->impl->args); s_goto(ctx, OP_APPLY); } case OP_APPLY: /* apply 'code' to 'args' */ if (NATIVE_FUNCP(ctx->impl->code)) { ctx->impl->dump = CONS(ctx->impl->code, ctx->impl->dump); ctx->impl->co.func = ctx->impl->code->u.o.func; s_goto(ctx, OP_NATIVE); } else if (PROCP(ctx->impl->code)) { s_goto(ctx, PROCNUM(ctx->impl->code)); /* PROCEDURE */ } else if (CLOSUREP(ctx->impl->code)) { /* CLOSURE */ /* make environment */ ctx->impl->envir = CONS(NIL, CLOSURE_ENV(ctx->impl->code)); for (x = CAR(CLOSURE_CODE(ctx->impl->code)), y = ctx->impl->args; PAIRP(x); x = CDR(x), y = CDR(y)) { if (y == NIL) { QLERR("Few arguments"); } else { CAR(ctx->impl->envir) = CONS(CONS(CAR(x), CAR(y)), CAR(ctx->impl->envir)); } } if (x == NIL) { /*-- * if (y != NIL) { * QLERR("Many arguments"); * } */ } else if (SYMBOLP(x)) CAR(ctx->impl->envir) = CONS(CONS(x, y), CAR(ctx->impl->envir)); else { QLERR("Syntax error in closure"); } ctx->impl->code = CDR(CLOSURE_CODE(ctx->impl->code)); ctx->impl->args = NIL; s_goto(ctx, OP_BEGIN); } else if (CONTINUATIONP(ctx->impl->code)) { /* CONTINUATION */ ctx->impl->dump = CONT_DUMP(ctx->impl->code); s_return(ctx, ctx->impl->args != NIL ? CAR(ctx->impl->args) : NIL); } else { QLERR("Illegal function"); } case OP_DOMACRO: /* do macro */ ctx->impl->code = ctx->impl->value; s_goto(ctx, OP_EVAL); case OP_LAMBDA: /* lambda */ s_return(ctx, mk_closure(ctx, ctx->impl->code, ctx->impl->envir)); case OP_QUOTE: /* quote */ s_return(ctx, CAR(ctx->impl->code)); case OP_DEF0: /* define */ if (PAIRP(CAR(ctx->impl->code))) { x = CAAR(ctx->impl->code); ctx->impl->code = CONS(LAMBDA, CONS(CDAR(ctx->impl->code), CDR(ctx->impl->code))); } else { x = CAR(ctx->impl->code); ctx->impl->code = CADR(ctx->impl->code); } if (!SYMBOLP(x)) { QLERR("Variable is not symbol"); } s_save(ctx, OP_DEF1, NIL, x); s_goto(ctx, OP_EVAL); case OP_DEF1: /* define */ for (x = CAR(ctx->impl->envir); x != NIL; x = CDR(x)) if (CAAR(x) == ctx->impl->code) break; if (x != NIL) CDAR(x) = ctx->impl->value; else CAR(ctx->impl->envir) = CONS(CONS(ctx->impl->code, ctx->impl->value), CAR(ctx->impl->envir)); s_return(ctx, ctx->impl->code); case OP_SET0: /* set! */ s_save(ctx, OP_SET1, NIL, CAR(ctx->impl->code)); ctx->impl->code = CADR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_SET1: /* set! */ for (x = ctx->impl->envir; x != NIL; x = CDR(x)) { for (y = CAR(x); y != NIL; y = CDR(y)) if (CAAR(y) == ctx->impl->code) break; if (y != NIL) break; } if (x != NIL) { CDAR(y) = ctx->impl->value; s_return(ctx, ctx->impl->value); } else { if (SYMBOLP(ctx->impl->code)) { char buf[SEN_TABLE_MAX_KEY_SIZE + 1]; symbol2str(ctx->impl->code, buf); QLERR("Unbounded variable %s", buf); } else { QLERR("Unbounded variable"); } } case OP_BEGIN: /* begin */ if (!PAIRP(ctx->impl->code)) { s_return(ctx, ctx->impl->code); } if (CDR(ctx->impl->code) != NIL) { s_save(ctx, OP_BEGIN, NIL, CDR(ctx->impl->code)); } ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_IF0: /* if */ s_save(ctx, OP_IF1, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_IF1: /* if */ if (istrue(ctx->impl->value)) ctx->impl->code = CAR(ctx->impl->code); else ctx->impl->code = CADR(ctx->impl->code); /* (if #f 1) ==> () because * CAR(NIL) = NIL */ s_goto(ctx, OP_EVAL); case OP_LET0: /* let */ ctx->impl->args = NIL; ctx->impl->value = ctx->impl->code; ctx->impl->code = SYMBOLP(CAR(ctx->impl->code)) ? CADR(ctx->impl->code) : CAR(ctx->impl->code); s_goto(ctx, OP_LET1); case OP_LET1: /* let (caluculate parameters) */ ctx->impl->args = CONS(ctx->impl->value, ctx->impl->args); if (PAIRP(ctx->impl->code)) { /* continue */ QLASSERT(LISTP(CAR(ctx->impl->code)) && LISTP(CDAR(ctx->impl->code))); s_save(ctx, OP_LET1, ctx->impl->args, CDR(ctx->impl->code)); ctx->impl->code = CADAR(ctx->impl->code); ctx->impl->args = NIL; s_goto(ctx, OP_EVAL); } else { /* end */ ctx->impl->args = reverse(ctx, ctx->impl->args); ctx->impl->code = CAR(ctx->impl->args); ctx->impl->args = CDR(ctx->impl->args); s_goto(ctx, OP_LET2); } case OP_LET2: /* let */ ctx->impl->envir = CONS(NIL, ctx->impl->envir); for (x = SYMBOLP(CAR(ctx->impl->code)) ? CADR(ctx->impl->code) : CAR(ctx->impl->code), y = ctx->impl->args; y != NIL; x = CDR(x), y = CDR(y)) CAR(ctx->impl->envir) = CONS(CONS(CAAR(x), CAR(y)), CAR(ctx->impl->envir)); if (SYMBOLP(CAR(ctx->impl->code))) { /* named let */ for (x = CADR(ctx->impl->code), ctx->impl->args = NIL; PAIRP(x); x = CDR(x)) ctx->impl->args = CONS(CAAR(x), ctx->impl->args); x = mk_closure(ctx, CONS(reverse(ctx, ctx->impl->args), CDDR(ctx->impl->code)), ctx->impl->envir); CAR(ctx->impl->envir) = CONS(CONS(CAR(ctx->impl->code), x), CAR(ctx->impl->envir)); ctx->impl->code = CDDR(ctx->impl->code); ctx->impl->args = NIL; } else { ctx->impl->code = CDR(ctx->impl->code); ctx->impl->args = NIL; } s_goto(ctx, OP_BEGIN); case OP_LET0AST: /* let* */ if (CAR(ctx->impl->code) == NIL) { ctx->impl->envir = CONS(NIL, ctx->impl->envir); ctx->impl->code = CDR(ctx->impl->code); s_goto(ctx, OP_BEGIN); } s_save(ctx, OP_LET1AST, CDR(ctx->impl->code), CAR(ctx->impl->code)); QLASSERT(LISTP(CAR(ctx->impl->code)) && LISTP(CAAR(ctx->impl->code)) && LISTP((CDR(CAAR(ctx->impl->code))))); ctx->impl->code = CADAAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_LET1AST: /* let* (make new frame) */ ctx->impl->envir = CONS(NIL, ctx->impl->envir); s_goto(ctx, OP_LET2AST); case OP_LET2AST: /* let* (caluculate parameters) */ CAR(ctx->impl->envir) = CONS(CONS(CAAR(ctx->impl->code), ctx->impl->value), CAR(ctx->impl->envir)); ctx->impl->code = CDR(ctx->impl->code); if (PAIRP(ctx->impl->code)) { /* continue */ QLASSERT(LISTP(CAR(ctx->impl->code)) && LISTP(CDAR(ctx->impl->code))); s_save(ctx, OP_LET2AST, ctx->impl->args, ctx->impl->code); ctx->impl->code = CADAR(ctx->impl->code); ctx->impl->args = NIL; s_goto(ctx, OP_EVAL); } else { /* end */ ctx->impl->code = ctx->impl->args; ctx->impl->args = NIL; s_goto(ctx, OP_BEGIN); } case OP_LET0REC: /* letrec */ ctx->impl->envir = CONS(NIL, ctx->impl->envir); ctx->impl->args = NIL; ctx->impl->value = ctx->impl->code; ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_LET1REC); case OP_LET1REC: /* letrec (caluculate parameters) */ ctx->impl->args = CONS(ctx->impl->value, ctx->impl->args); if (PAIRP(ctx->impl->code)) { /* continue */ QLASSERT(LISTP(CAR(ctx->impl->code)) && LISTP(CDAR(ctx->impl->code))); s_save(ctx, OP_LET1REC, ctx->impl->args, CDR(ctx->impl->code)); ctx->impl->code = CADAR(ctx->impl->code); ctx->impl->args = NIL; s_goto(ctx, OP_EVAL); } else { /* end */ ctx->impl->args = reverse(ctx, ctx->impl->args); ctx->impl->code = CAR(ctx->impl->args); ctx->impl->args = CDR(ctx->impl->args); s_goto(ctx, OP_LET2REC); } case OP_LET2REC: /* letrec */ for (x = CAR(ctx->impl->code), y = ctx->impl->args; y != NIL; x = CDR(x), y = CDR(y)) CAR(ctx->impl->envir) = CONS(CONS(CAAR(x), CAR(y)), CAR(ctx->impl->envir)); ctx->impl->code = CDR(ctx->impl->code); ctx->impl->args = NIL; s_goto(ctx, OP_BEGIN); case OP_COND0: /* cond */ if (!PAIRP(ctx->impl->code)) { QLERR("Syntax error in cond"); } s_save(ctx, OP_COND1, NIL, ctx->impl->code); ctx->impl->code = CAAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_COND1: /* cond */ if (istrue(ctx->impl->value)) { if ((ctx->impl->code = CDAR(ctx->impl->code)) == NIL) { s_return(ctx, ctx->impl->value); } s_goto(ctx, OP_BEGIN); } else { if ((ctx->impl->code = CDR(ctx->impl->code)) == NIL) { s_return(ctx, NIL); } else { s_save(ctx, OP_COND1, NIL, ctx->impl->code); ctx->impl->code = CAAR(ctx->impl->code); s_goto(ctx, OP_EVAL); } } case OP_DELAY: /* delay */ x = mk_closure(ctx, CONS(NIL, ctx->impl->code), ctx->impl->envir); if (ERRP(ctx, SEN_ERROR)) { return F; } SETPROMISE(x); s_return(ctx, x); case OP_AND0: /* and */ if (ctx->impl->code == NIL) { s_return(ctx, T); } s_save(ctx, OP_AND1, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_AND1: /* and */ if (isfalse(ctx->impl->value)) { s_return(ctx, ctx->impl->value); } else if (ctx->impl->code == NIL) { s_return(ctx, ctx->impl->value); } else { s_save(ctx, OP_AND1, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); } case OP_OR0: /* or */ if (ctx->impl->code == NIL) { s_return(ctx, F); } s_save(ctx, OP_OR1, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_OR1: /* or */ if (istrue(ctx->impl->value)) { s_return(ctx, ctx->impl->value); } else if (ctx->impl->code == NIL) { s_return(ctx, ctx->impl->value); } else { s_save(ctx, OP_OR1, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); } case OP_C0STREAM: /* cons-stream */ s_save(ctx, OP_C1STREAM, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_C1STREAM: /* cons-stream */ ctx->impl->args = ctx->impl->value; /* save ctx->impl->value to register ctx->impl->args for gc */ x = mk_closure(ctx, CONS(NIL, ctx->impl->code), ctx->impl->envir); if (ERRP(ctx, SEN_ERROR)) { return F; } SETPROMISE(x); s_return(ctx, CONS(ctx->impl->args, x)); case OP_0MACRO: /* macro */ x = CAR(ctx->impl->code); ctx->impl->code = CADR(ctx->impl->code); if (!SYMBOLP(x)) { QLERR("Variable is not symbol"); } s_save(ctx, OP_1MACRO, NIL, x); s_goto(ctx, OP_EVAL); case OP_1MACRO: /* macro */ ctx->impl->value->header.type = SEN_CELL_MACRO; for (x = CAR(ctx->impl->envir); x != NIL; x = CDR(x)) if (CAAR(x) == ctx->impl->code) break; if (x != NIL) CDAR(x) = ctx->impl->value; else CAR(ctx->impl->envir) = CONS(CONS(ctx->impl->code, ctx->impl->value), CAR(ctx->impl->envir)); s_return(ctx, ctx->impl->code); case OP_CASE0: /* case */ s_save(ctx, OP_CASE1, NIL, CDR(ctx->impl->code)); ctx->impl->code = CAR(ctx->impl->code); s_goto(ctx, OP_EVAL); case OP_CASE1: /* case */ for (x = ctx->impl->code; x != NIL; x = CDR(x)) { if (!PAIRP(y = CAAR(x))) break; for ( ; y != NIL; y = CDR(y)) if (eqv(CAR(y), ctx->impl->value)) break; if (y != NIL) break; } if (x != NIL) { if (PAIRP(CAAR(x))) { ctx->impl->code = CDAR(x); s_goto(ctx, OP_BEGIN); } else {/* else */ s_save(ctx, OP_CASE2, NIL, CDAR(x)); ctx->impl->code = CAAR(x); s_goto(ctx, OP_EVAL); } } else { s_return(ctx, NIL); } case OP_CASE2: /* case */ if (istrue(ctx->impl->value)) { s_goto(ctx, OP_BEGIN); } else { s_return(ctx, NIL); } case OP_PAPPLY: /* apply */ ctx->impl->code = CAR(ctx->impl->args); ctx->impl->args = CADR(ctx->impl->args); s_goto(ctx, OP_APPLY); case OP_PEVAL: /* eval */ ctx->impl->code = CAR(ctx->impl->args); ctx->impl->args = NIL; s_goto(ctx, OP_EVAL); case OP_CONTINUATION: /* call-with-current-continuation */ ctx->impl->code = CAR(ctx->impl->args); ctx->impl->args = CONS(mk_continuation(ctx, ctx->impl->dump), NIL); s_goto(ctx, OP_APPLY); case OP_SETCAR: /* set-car! */ if (PAIRP(CAR(ctx->impl->args))) { CAAR(ctx->impl->args) = CADR(ctx->impl->args); s_return(ctx, CAR(ctx->impl->args)); } else { QLERR("Unable to set-car! for non-cons cell"); } case OP_SETCDR: /* set-cdr! */ if (PAIRP(CAR(ctx->impl->args))) { CDAR(ctx->impl->args) = CADR(ctx->impl->args); s_return(ctx, CAR(ctx->impl->args)); } else { QLERR("Unable to set-cdr! for non-cons cell"); } case OP_FORCE: /* force */ ctx->impl->code = CAR(ctx->impl->args); if (PROMISEP(ctx->impl->code)) { ctx->impl->args = NIL; s_goto(ctx, OP_APPLY); } else { s_return(ctx, ctx->impl->code); } case OP_ERR0: /* error */ SEN_BULK_PUTS(ctx, &ctx->impl->outbuf, "*** ERROR: "); SEN_BULK_PUTS(ctx, &ctx->impl->outbuf, ctx->errbuf); SEN_BULK_PUTC(ctx, &ctx->impl->outbuf, '\n'); ctx->impl->args = NIL; s_goto(ctx, OP_T0LVL); case OP_ERR1: /* error */ SEN_BULK_PUTS(ctx, &ctx->impl->outbuf, "*** ERROR:"); while (ctx->impl->args != NIL) { SEN_BULK_PUTC(ctx, &ctx->impl->outbuf, ' '); sen_obj_inspect(ctx, CAR(ctx->impl->args), &ctx->impl->outbuf, SEN_OBJ_INSPECT_ESC); ctx->impl->args = CDR(ctx->impl->args); } SEN_BULK_PUTC(ctx, &ctx->impl->outbuf, '\n'); s_goto(ctx, OP_T0LVL); case OP_PUT: /* put */ if (!HASPROP(CAR(ctx->impl->args)) || !HASPROP(CADR(ctx->impl->args))) { QLERR("Illegal use of put"); } for (x = SYMPROP(CAR(ctx->impl->args)), y = CADR(ctx->impl->args); x != NIL; x = CDR(x)) if (CAAR(x) == y) break; if (x != NIL) CDAR(x) = CADDR(ctx->impl->args); else SYMPROP(CAR(ctx->impl->args)) = CONS(CONS(y, CADDR(ctx->impl->args)), SYMPROP(CAR(ctx->impl->args))); s_return(ctx, T); case OP_GET: /* get */ if (!HASPROP(CAR(ctx->impl->args)) || !HASPROP(CADR(ctx->impl->args))) { QLERR("Illegal use of get"); } for (x = SYMPROP(CAR(ctx->impl->args)), y = CADR(ctx->impl->args); x != NIL; x = CDR(x)) if (CAAR(x) == y) break; if (x != NIL) { s_return(ctx, CDAR(x)); } else { s_return(ctx, NIL); } case OP_SDOWN: /* shutdown */ SEN_LOG(sen_log_notice, "shutting down.."); sen_gctx.stat = SEN_CTX_QUIT; s_goto(ctx, OP_QUIT); case OP_RDSEXPR: { char tok, *str; unsigned len; RTN_NIL_IF_HEAD(ctx); switch (ctx->impl->tok) { case TOK_COMMENT: skipline(ctx); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case TOK_LPAREN: if ((tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } ctx->impl->tok = tok; if (ctx->impl->tok == TOK_RPAREN) { s_return(ctx, NIL); } else if (ctx->impl->tok == TOK_DOT) { QLERR("syntax error: illegal dot expression"); } else { s_save(ctx, OP_RDLIST, NIL, NIL); s_goto(ctx, OP_RDSEXPR); } case TOK_QUOTE: s_save(ctx, OP_RDQUOTE, NIL, NIL); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case TOK_BQUOTE: s_save(ctx, OP_RDQQUOTE, NIL, NIL); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case TOK_COMMA: s_save(ctx, OP_RDUNQUOTE, NIL, NIL); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case TOK_ATMARK: s_save(ctx, OP_RDUQTSP, NIL, NIL); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case TOK_ATOM: if (readstr(ctx, &str, &len) == TOK_EOS) { ctx->impl->tok = TOK_EOS; RTN_NIL_IF_TAIL(ctx); } s_return(ctx, mk_atom(ctx, str, len, NIL)); case TOK_DQUOTE: if (readstrexp(ctx, &str, &len) == TOK_EOS) { QLERR("unterminated string"); } s_return(ctx, sen_ql_mk_string(ctx, str, len)); case TOK_SHARP: if ((readstr(ctx, &str, &len) == TOK_EOS) || (x = mk_const(ctx, str, len)) == NIL) { QLERR("Undefined sharp expression"); } else { s_return(ctx, x); } case TOK_EOS : if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); case TOK_QUESTION: { sen_cell *o, *p; SEN_CELL_NEW(ctx, o); p = CONS(o, NIL); o->header.type = SEN_CELL_STR; o->header.impl_flags = 0; o->u.b.size = 1; o->u.b.value = "?"; *ctx->impl->pht = p; ctx->impl->pht = &CDR(p); s_return(ctx, o); } default: QLERR("syntax error: illegal token"); } } break; case OP_RDLIST: RTN_NIL_IF_HEAD(ctx); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } if (ctx->impl->tok == TOK_COMMENT) { skipline(ctx); s_goto(ctx, OP_RDLIST); } ctx->impl->args = CONS(ctx->impl->value, ctx->impl->args); if (ctx->impl->tok == TOK_RPAREN) { sen_cell *v = non_alloc_rev(NIL, ctx->impl->args); if (ctx->impl->cur < ctx->impl->str_end && *ctx->impl->cur == '.') { char *str = NULL; unsigned len = 0; if (readstr(ctx, &str, &len) != TOK_ATOM) { /* error */ } s_return(ctx, mk_atom(ctx, str, len, v)); } else { s_return(ctx, v); } } else if (ctx->impl->tok == TOK_DOT) { s_save(ctx, OP_RDDOT, ctx->impl->args, NIL); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { ctx->impl->op = OP_RDSEXPR; RTN_NIL_IF_TAIL(ctx); } s_goto(ctx, OP_RDSEXPR); } else { s_save(ctx, OP_RDLIST, ctx->impl->args, NIL);; s_goto(ctx, OP_RDSEXPR); } case OP_RDDOT: RTN_NIL_IF_HEAD(ctx); if ((ctx->impl->tok = token(ctx)) == TOK_EOS) { RTN_NIL_IF_TAIL(ctx); } if (ctx->impl->tok != TOK_RPAREN) { QLERR("syntax error: illegal dot expression"); } else { sen_cell *v = non_alloc_rev(ctx->impl->value, ctx->impl->args); if (ctx->impl->cur < ctx->impl->str_end && *ctx->impl->cur == '.') { char *str = NULL; unsigned len = 0; if (readstr(ctx, &str, &len) != TOK_ATOM) { /* error */ } s_return(ctx, mk_atom(ctx, str, len, v)); } else { s_return(ctx, v); } } case OP_RDQUOTE: s_return(ctx, CONS(QUOTE, CONS(ctx->impl->value, NIL))); case OP_RDQQUOTE: s_return(ctx, CONS(QQUOTE, CONS(ctx->impl->value, NIL))); case OP_RDUNQUOTE: s_return(ctx, CONS(UNQUOTE, CONS(ctx->impl->value, NIL))); case OP_RDUQTSP: s_return(ctx, CONS(UNQUOTESP, CONS(ctx->impl->value, NIL))); case OP_NATIVE: ctx->impl->dump = CDR(ctx->impl->dump); s_return(ctx, ctx->impl->value); case OP_QQUOTE0: ctx->impl->code = list_deep_copy(ctx, ctx->impl->code); ctx->impl->args = CONS(ctx->impl->code, NIL); qquote_uquotelist(ctx, ctx->impl->code, ctx->impl->code, 0); ctx->impl->code = CDR(ctx->impl->args); s_goto(ctx, OP_QQUOTE1); case OP_QQUOTE1: while (PAIRP(ctx->impl->code)) { x = CAR(ctx->impl->code); if (PAIRP(x) && LISTP(CDR(x))) { s_save(ctx, OP_QQUOTE2, ctx->impl->args, ctx->impl->code); y = CADR(x); if (y == UNQUOTE) { QLASSERT(LISTP(CDDR(x))); ctx->impl->code = CADDR(x); } else if (CAR(y) == UNQUOTESP) { QLASSERT(LISTP(CDR(y))); ctx->impl->code = CADR(y); } else { y = CAR(x); if (CAR(y) == UNQUOTE) { ctx->impl->code = CADR(y); } else if (CAAR(y) == UNQUOTESP) { ctx->impl->code = CADAR(y); } else { /* error */ } } s_goto(ctx, OP_EVAL); } ctx->impl->code = CDR(ctx->impl->code); } s_return(ctx, CAAR(ctx->impl->args)); case OP_QQUOTE2: x = CAR(ctx->impl->code); y = CADR(x); if (y == UNQUOTE) { CDR(x) = ctx->impl->value; } else if (CAR(y) == UNQUOTESP) { if (ctx->impl->value == NIL) { CDR(x) = CDDR(x); } else if (!PAIRP(ctx->impl->value) ) { /* error */ } else { ctx->impl->value = list_deep_copy(ctx, ctx->impl->value); for (y = ctx->impl->value; CDR(y) != NIL; y = CDR(y)) {} CDR(y) = CDDR(x); CDR(x) = ctx->impl->value; } } else { y = CAAR(x); if (y == UNQUOTE) { CAR(x) = ctx->impl->value; } else if (CAR(y) == UNQUOTESP) { if (ctx->impl->value == NIL) { CAR(x) = CDAR(x); } else if (!PAIRP(ctx->impl->value) ) { /* error */ } else { ctx->impl->value = list_deep_copy(ctx, ctx->impl->value); for (y = ctx->impl->value; CDR(y) != NIL; y = CDR(y)) {} CDR(y) = CDAR(x); CAR(x) = ctx->impl->value; } } else { /* error */ } } ctx->impl->code = CDR(ctx->impl->code); s_goto(ctx, OP_QQUOTE1); } SEN_LOG(sen_log_error, "illegal op (%d)", ctx->impl->op); return NIL; } /* kernel of this intepreter */ inline static void Eval_Cycle(sen_ctx *ctx) { ctx->impl->co.func = NULL; ctx->impl->co.last = 0; while (opexe(ctx) != NIL) { switch (ctx->impl->op) { case OP_NATIVE : ctx->stat = SEN_QL_NATIVE; return; case OP_T0LVL : ctx->stat = SEN_QL_TOPLEVEL; return; case OP_T1LVL : ctx->stat = (ctx->impl->phs != NIL) ? SEN_QL_WAIT_ARG : SEN_QL_EVAL; return; case OP_QUIT : ctx->stat = SEN_QL_QUITTING; return; default : break; } if (ERRP(ctx, SEN_ERROR)) { return; } } ctx->stat = SEN_QL_WAIT_EXPR; } sen_cell * sen_ql_eval(sen_ctx *ctx, sen_cell *code, sen_cell *objs) { sen_ql_co co; uint8_t op = ctx->impl->op; uint8_t stat = ctx->stat; uint8_t feed_mode = ctx->impl->feed_mode; sen_cell *o, *code_ = ctx->impl->code; o = CONS(objs, ctx->impl->envir); memcpy(&co, &ctx->impl->co, sizeof(sen_ql_co)); s_save(ctx, OP_QUIT, ctx->impl->args, o); ctx->impl->op = OP_EVAL; ctx->stat = SEN_QL_EVAL; ctx->impl->code = code; ctx->impl->feed_mode = sen_ql_atonce; sen_ql_feed(ctx, NULL, 0, 0); ctx->impl->feed_mode = feed_mode; ctx->stat = stat; ctx->impl->op = op; ctx->impl->envir = CDR(o); ctx->impl->code = code_; memcpy(&ctx->impl->co, &co, sizeof(sen_ql_co)); return ctx->impl->value; } /* ========== native functions ========== */ #define s_retbool(tf) do { return (tf) ? T : F; } while (0) #define do_op(x,y,op) do {\ switch ((x)->header.type) {\ case SEN_CELL_INT :\ switch ((y)->header.type) {\ case SEN_CELL_INT :\ IVALUE(x) = IVALUE(x) op IVALUE(y);\ break;\ case SEN_CELL_FLOAT :\ SETFLOAT(x, ((double) IVALUE(x)) op FVALUE(y));\ break;\ default :\ if (sen_obj2int(ctx, y)) { QLERR("can't convert into numeric value"); }\ IVALUE(x) = IVALUE(x) op IVALUE(y);\ }\ break;\ case SEN_CELL_FLOAT :\ switch ((y)->header.type) {\ case SEN_CELL_INT :\ FVALUE(x) = FVALUE(x) op IVALUE(y);\ break;\ case SEN_CELL_FLOAT :\ FVALUE(x) = FVALUE(x) op FVALUE(y);\ break;\ default :\ if (sen_obj2int(ctx, y)) { QLERR("can't convert into numeric value"); }\ FVALUE(x) = FVALUE(x) op IVALUE(y);\ }\ break;\ default :\ QLERR("can't convert into numeric");\ }\ } while (0) #define do_compare(x,y,r,op) do {\ switch (x->header.type) {\ case SEN_CELL_INT :\ switch (y->header.type) {\ case SEN_CELL_INT :\ r = (IVALUE(x) op IVALUE(y));\ break;\ case SEN_CELL_FLOAT :\ r = (IVALUE(x) op FVALUE(y));\ break;\ default :\ if (sen_obj2int(ctx, y)) { QLERR("can't convert into numeric value"); }\ r = (IVALUE(x) op IVALUE(y));\ }\ break;\ case SEN_CELL_FLOAT :\ switch (y->header.type) {\ case SEN_CELL_INT :\ r = (FVALUE(x) op IVALUE(y));\ break;\ case SEN_CELL_FLOAT :\ r = (FVALUE(x) op FVALUE(y));\ break;\ default :\ if (sen_obj2int(ctx, y)) { QLERR("can't convert into numeric value"); }\ r = (FVALUE(x) op IVALUE(y));\ }\ break;\ case SEN_CELL_STR :\ if (y->header.type == SEN_CELL_STR) {\ int r_;\ uint32_t la = x->u.b.size, lb = y->u.b.size;\ if (la > lb) {\ if (!(r_ = memcmp(x->u.b.value, y->u.b.value, lb))) {\ r_ = 1;\ }\ } else {\ if (!(r_ = memcmp(x->u.b.value, y->u.b.value, la))) {\ r_ = la == lb ? 0 : -1;\ }\ }\ r = (r_ op 0);\ } else {\ QLERR("can't compare");\ }\ break;\ case SEN_CELL_TIME :\ if (y->header.type == SEN_CELL_TIME) {\ if (x->u.tv.tv_sec != y->u.tv.tv_sec) {\ r = (x->u.tv.tv_sec op y->u.tv.tv_sec);\ } else {\ r = (x->u.tv.tv_usec op y->u.tv.tv_usec);\ }\ } else {\ QLERR("can't compare");\ }\ break;\ default :\ r = (memcmp(&x->u.tv, &y->u.tv, sizeof(sen_timeval)) op 0);\ }\ } while (0) #define time_op(x,y,v,op) {\ switch (y->header.type) {\ case SEN_CELL_TIME :\ {\ double dv= x->u.tv.tv_sec op y->u.tv.tv_sec;\ dv += (x->u.tv.tv_usec op y->u.tv.tv_usec) / 1000000.0;\ SETFLOAT(v, dv);\ }\ break;\ case SEN_CELL_INT :\ {\ sen_timeval tv;\ int64_t sec = x->u.tv.tv_sec op IVALUE(y);\ if (sec < INT32_MIN || INT32_MAX < sec) { QLERR("time val overflow"); }\ tv.tv_sec = (int)sec;\ tv.tv_usec = x->u.tv.tv_usec;\ SETTIME(v, &tv);\ }\ break;\ case SEN_CELL_FLOAT :\ {\ sen_timeval tv;\ double sec = x->u.tv.tv_sec op (int)FVALUE(y);\ int32_t usec = x->u.tv.tv_usec op (int)((FVALUE(y) - (int)FVALUE(y)) * 1000000);\ if (sec < INT32_MIN || INT32_MAX < sec) { QLERR("time val overflow"); }\ tv.tv_sec = (int)sec;\ if (usec < 0) {\ tv.tv_sec--;\ usec += 1000000;\ } else if (usec >= 1000000) {\ tv.tv_sec++;\ usec -= 1000000;\ }\ tv.tv_usec = usec;\ SETTIME(v, &tv);\ }\ break;\ default :\ QLERR("can't convert into numeric value");\ break;\ }\ } while (0) static sen_cell * nf_add(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *x, *v; if (!PAIRP(args)) { QLERR("list required"); } switch (CAR(args)->header.type) { case SEN_CELL_STR : { sen_obj buf; sen_bulk_init(ctx, &buf, 0); while (PAIRP(args)) { POP(x, args); sen_obj_inspect(ctx, x, &buf, 0); } SEN_STR2OBJ(ctx, &buf, v); } break; case SEN_CELL_TIME : if (PAIRP(CDR(args)) && NUMBERP(CADR(args))) { SEN_CELL_NEW(ctx, v); time_op(CAR(args), CADR(args), v, +); } else { QLERR("can't convert into numeric value"); } break; default : v = mk_number(ctx, 0); while (PAIRP(args)) { POP(x, args); do_op(v, x, +); } break; } return v; } static sen_cell * nf_sub(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *v = mk_number(ctx, 0); register sen_cell *x; if (PAIRP(args) && CDR(args) != NIL) { if (CAR(args)->header.type == SEN_CELL_TIME) { time_op(CAR(args), CADR(args), v, -); return v; } POP(x, args); do_op(v, x, +); } while (PAIRP(args)) { POP(x, args); do_op(v, x, -); } return v; } static sen_cell * nf_mul(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *v, *x; if (CAR(args)->header.type == SEN_CELL_STR && CADR(args)->header.type == SEN_CELL_INT) { int i, n = (int)IVALUE(CADR(args)); sen_obj buf; sen_bulk_init(ctx, &buf, 0); POP(x, args); for (i = 0; i < n; i++) { sen_obj_inspect(ctx, x, &buf, 0); } SEN_STR2OBJ(ctx, &buf, v); } else { v = mk_number(ctx, 1); while (PAIRP(args)) { POP(x, args); do_op(v, x, *); } } return v; } static sen_cell * nf_div(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *v; register sen_cell *x; if (PAIRP(args) && CDR(args) != NIL) { v = mk_number(ctx, 0); POP(x, args); do_op(v, x, +); } else { v = mk_number(ctx, 1); } while (PAIRP(args)) { POP(x, args); if (x->header.type == SEN_CELL_INT && IVALUE(x) == 0 && v->header.type == SEN_CELL_INT) { SETFLOAT(v, (double)IVALUE(v)); } do_op(v, x, /); } return v; } static sen_cell * nf_rem(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register int64_t v; register sen_cell *x; x = args; if (sen_obj2int(ctx, CAR(x))) { QLERR("can't convert into integer"); } v = IVALUE(CAR(x)); while (CDR(x) != NIL) { x = CDR(x); if (sen_obj2int(ctx, CAR(x))) { QLERR("can't convert into integer"); } if (IVALUE(CAR(x)) != 0) v %= IVALUE(CAR(x)); else { QLERR("Divided by zero"); } } return mk_number(ctx, v); } static sen_cell * nf_car(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { if (PAIRP(CAR(args))) { return CAAR(args); } else { QLERR("Unable to car for non-cons cell"); } } static sen_cell * nf_cdr(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { if (PAIRP(CAR(args))) { return CDAR(args); } else { QLERR("Unable to cdr for non-cons cell"); } } static sen_cell * nf_cons(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { CDR(args) = CADR(args); return args; } static sen_cell * nf_not(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(isfalse(CAR(args))); } static sen_cell * nf_bool(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(CAR(args) == F || CAR(args) == T); } static sen_cell * nf_null(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(CAR(args) == NIL); } static sen_cell * nf_zerop(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *x = CAR(args); switch (x->header.type) { case SEN_CELL_INT : s_retbool(IVALUE(x) == 0); break; case SEN_CELL_FLOAT : s_retbool(!(islessgreater(FVALUE(x), 0.0))); break; default : QLERR("can't convert into numeric value"); } } static sen_cell * nf_posp(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *x = CAR(args); switch (x->header.type) { case SEN_CELL_INT : s_retbool(IVALUE(x) > 0); break; case SEN_CELL_FLOAT : s_retbool(!(isgreater(FVALUE(x), 0.0))); break; default : QLERR("can't convert into numeric value"); } } static sen_cell * nf_negp(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *x = CAR(args); switch (x->header.type) { case SEN_CELL_INT : s_retbool(IVALUE(x) < 0); break; case SEN_CELL_FLOAT : s_retbool(!(isless(FVALUE(x), 0.0))); break; default : QLERR("can't convert into numeric value"); } } static sen_cell * nf_neq(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { int r = 1; register sen_cell *x, *y; POP(x, args); if (!PAIRP(args)) { QLERR("Few arguments"); } do { POP(y, args); switch (x->header.type) { case SEN_CELL_INT : switch (y->header.type) { case SEN_CELL_INT : r = (IVALUE(x) == IVALUE(y)); break; case SEN_CELL_FLOAT : r = (IVALUE(x) <= FVALUE(y) && IVALUE(x) >= FVALUE(y)); break; default : if (sen_obj2int(ctx, y)) { QLERR("can't convert into numeric value"); } r = (IVALUE(x) == IVALUE(y)); } break; case SEN_CELL_FLOAT : switch (y->header.type) { case SEN_CELL_INT : r = (FVALUE(x) <= IVALUE(y) && FVALUE(x) >= IVALUE(y)); break; case SEN_CELL_FLOAT : r = (FVALUE(x) <= FVALUE(y) && FVALUE(x) >= FVALUE(y)); break; default : if (sen_obj2int(ctx, y)) { QLERR("can't convert into numeric value"); } r = (FVALUE(x) <= IVALUE(y) && FVALUE(x) >= IVALUE(y)); } break; case SEN_CELL_STR : if (y->header.type == SEN_CELL_STR) { int r_; uint32_t la = x->u.b.size, lb = y->u.b.size; if (la > lb) { if (!(r_ = memcmp(x->u.b.value, y->u.b.value, lb))) { r_ = 1; } } else { if (!(r_ = memcmp(x->u.b.value, y->u.b.value, la))) { r_ = la == lb ? 0 : -1; } } r = (r_ == 0); } else { QLERR("can't compare"); } break; case SEN_CELL_TIME : if (y->header.type == SEN_CELL_TIME) { if (x->u.tv.tv_sec != y->u.tv.tv_sec) { r = (x->u.tv.tv_sec == y->u.tv.tv_sec); } else { r = (x->u.tv.tv_usec == y->u.tv.tv_usec); } } else { QLERR("can't compare"); } break; case SEN_CELL_OBJECT : r = (y->header.type == SEN_CELL_OBJECT && x->u.o.id == y->u.o.id && x->header.domain == y->header.domain); break; default : r = (memcmp(&x->u.tv, &y->u.tv, sizeof(sen_timeval)) == 0); break; } x = y; } while (PAIRP(args) && r); return r ? T : F; } static sen_cell * nf_less(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { int r = 1; register sen_cell *x, *y; POP(x, args); if (!PAIRP(args)) { QLERR("Few arguments"); } do { POP(y, args); do_compare(x, y, r, <); x = y; } while (PAIRP(args) && r); return r ? T : F; } static sen_cell * nf_gre(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { int r = 1; register sen_cell *x, *y; POP(x, args); if (!PAIRP(args)) { QLERR("Few arguments"); } do { POP(y, args); do_compare(x, y, r, >); x = y; } while (PAIRP(args) && r); return r ? T : F; } static sen_cell * nf_leq(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { int r = 1; register sen_cell *x, *y; POP(x, args); if (!PAIRP(args)) { QLERR("Few arguments"); } do { POP(y, args); do_compare(x, y, r, <=); x = y; } while (PAIRP(args) && r); return r ? T : F; } static sen_cell * nf_geq(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { int r = 1; register sen_cell *x, *y; POP(x, args); if (!PAIRP(args)) { QLERR("Few arguments"); } do { POP(y, args); do_compare(x, y, r, >=); x = y; } while (PAIRP(args) && r); return r ? T : F; } static sen_cell * nf_symbol(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(SYMBOLP(CAR(args))); } static sen_cell * nf_number(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(NUMBERP(CAR(args))); } static sen_cell * nf_string(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(BULKP(CAR(args))); } static sen_cell * nf_proc(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { /*-- * continuation should be procedure by the example * (call-with-current-continuation procedure?) ==> #t * in R^3 report sec. 6.9 */ s_retbool(PROCEDUREP(CAR(args))); } static sen_cell * nf_pair(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(PAIRP(CAR(args))); } static sen_cell * nf_eq(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(CAR(args) == CADR(args)); } static sen_cell * nf_eqv(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(eqv(CAR(args), CADR(args))); } static sen_cell * nf_logtest(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(logtest(CAR(args), CADR(args))); } static sen_cell * nf_write(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { args = CAR(args); sen_obj_inspect(ctx, args, &ctx->impl->outbuf, SEN_OBJ_INSPECT_ESC); return T; } static sen_cell * nf_display(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { args = CAR(args); sen_obj_inspect(ctx, args, &ctx->impl->outbuf, 0); return T; } static sen_cell * nf_newline(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { SEN_BULK_PUTC(ctx, &ctx->impl->outbuf, '\n'); return T; } static sen_cell * nf_reverse(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { return reverse(ctx, CAR(args)); } static sen_cell * nf_append(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { return append(ctx, CAR(args), CADR(args)); } static sen_cell * nf_gc(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_ctx_mgc(ctx); // sen_index_expire(); return T; } static sen_cell * nf_gcverb(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { int was = ctx->impl->gc_verbose; ctx->impl->gc_verbose = (CAR(args) != F); s_retbool(was); } static sen_cell * nf_nativep(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(NATIVE_FUNCP(CAR(args))); } static sen_cell * nf_length(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register long v; register sen_cell *x; for (x = CAR(args), v = 0; PAIRP(x); x = CDR(x)) { ++v; } return mk_number(ctx, v); } static sen_cell * nf_assq(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { register sen_cell *x, *y; x = CAR(args); for (y = CADR(args); PAIRP(y); y = CDR(y)) { if (!PAIRP(CAR(y))) { QLERR("Unable to handle non pair element"); } if (x == CAAR(y)) break; } if (PAIRP(y)) { return CAR(y); } else { return F; } } static sen_cell * nf_get_closure(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { args = CAR(args); if (args == NIL) { return F; } else if (CLOSUREP(args)) { return CONS(LAMBDA, CLOSURE_CODE(ctx->impl->value)); } else { return F; } } static sen_cell * nf_closurep(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { /* * Note, macro object is also a closure. * Therefore, (closure? <#MACRO>) ==> #t */ if (CAR(args) == NIL) { return F; } s_retbool(CLOSUREP(CAR(args))); } static sen_cell * nf_macrop(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { if (CAR(args) == NIL) { return F; } s_retbool(MACROP(CAR(args))); } static sen_cell * nf_voidp(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { s_retbool(CAR(args)->header.type == SEN_VOID); } static sen_cell * nf_list(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { if (PAIRP(args)) { return args; } else { QLERR("Unable to handle non-cons argument"); } } static sen_cell * nf_batchmode(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { if (CAR(args) == F) { ctx->impl->batchmode = 0; return F; } else { ctx->impl->batchmode = 1; return T; } } static sen_cell * nf_loglevel(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { static sen_logger_info info; sen_cell *x = CAR(args); if (sen_obj2int(ctx, x)) { QLERR("can't convert into integer"); } info.max_level = IVALUE(x); info.flags = SEN_LOG_TIME|SEN_LOG_MESSAGE; info.func = NULL; info.func_arg = NULL; return (sen_logger_info_set(&info)) ? F : T; } static sen_cell * nf_now(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_cell *x; sen_timeval tv; if (sen_timeval_now(&tv)) { QLERR("sysdate failed"); } SEN_CELL_NEW(ctx, x); SETTIME(x, &tv); return x; } static sen_cell * nf_timestr(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_timeval tv; char buf[SEN_TIMEVAL_STR_SIZE]; sen_cell *x = CAR(args); switch (x->header.type) { case SEN_CELL_STR : if (sen_obj2int(ctx, x)) { QLERR("can't convert into integer"); } /* fallthru */ case SEN_CELL_INT : tv.tv_sec = IVALUE(x); tv.tv_usec = 0; break; case SEN_CELL_FLOAT : tv.tv_sec = (int32_t) FVALUE(x); tv.tv_usec = (int32_t) ((FVALUE(x) - tv.tv_sec) * 1000000); break; case SEN_CELL_TIME : memcpy(&tv, &x->u.tv, sizeof(sen_timeval)); break; default : QLERR("can't convert into time"); } if (sen_timeval2str(&tv, buf)) { QLERR("timeval2str failed"); } return sen_ql_mk_string(ctx, buf, strlen(buf)); } static sen_cell * nf_tonumber(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_cell *x, *v; if (!PAIRP(args)) { QLERR("list required"); } x = CAR(args); switch (x->header.type) { case SEN_CELL_STR : if ((v = str2num(ctx, STRVALUE(x), x->u.b.size)) == NIL) { v = mk_number(ctx, 0); } break; case SEN_CELL_INT : case SEN_CELL_FLOAT : v = x; break; case SEN_CELL_TIME : { double dv= x->u.tv.tv_sec; dv += x->u.tv.tv_usec / 1000000.0; SEN_CELL_NEW(ctx, v); SETFLOAT(v, dv); } break; default : v = mk_number(ctx, 0); break; } return v; } static sen_cell * nf_totime(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_timeval tv; sen_cell *x, *v; if (!PAIRP(args)) { QLERR("list required"); } x = CAR(args); switch (x->header.type) { case SEN_CELL_STR : { /* if (PAIRP(CDR(args)) && BULKP(CADR(args))) { fmt = STRVALUE(CADR(args)); } */ if (sen_str2timeval(STRVALUE(x), x->u.b.size, &tv)) { QLERR("cast error"); } SEN_CELL_NEW(ctx, v); SETTIME(v, &tv); } break; case SEN_CELL_INT : tv.tv_sec = (int32_t) IVALUE(x); tv.tv_usec = 0; SEN_CELL_NEW(ctx, v); SETTIME(v, &tv); break; case SEN_CELL_FLOAT : tv.tv_sec = (int32_t) FVALUE(x); tv.tv_usec = (int32_t) ((FVALUE(x) - tv.tv_sec) * 1000000); SEN_CELL_NEW(ctx, v); SETTIME(v, &tv); break; case SEN_CELL_TIME : v = x; break; default : QLERR("can't convert into number"); } return v; } static sen_cell * nf_substrb(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_cell *str, *s, *e; int64_t is, ie; if (!PAIRP(args)) { QLERR("list required"); } POP(str, args); if (!BULKP(str)) { QLERR("string required"); } POP(s, args); if (!INTP(s)) { QLERR("integer required"); } POP(e, args); if (!INTP(e)) { QLERR("integer required"); } is = IVALUE(s); ie = IVALUE(e) + 1; if (ie <= 0) { ie = str->u.b.size + ie; if (ie < 0) { ie = 0; } } else if (ie > str->u.b.size) { ie = str->u.b.size; } if (is < 0) { is = str->u.b.size + is + 1; if (is < 0) { is = 0; } } else if (is > str->u.b.size) { is = str->u.b.size; } if (is < ie) { return sen_ql_mk_string(ctx, STRVALUE(str) + is, ie - is); } else { sen_cell *o; SEN_CELL_NEW(ctx, o); o->header.impl_flags = 0; o->header.type = SEN_CELL_STR; o->u.b.size = 0; o->u.b.value = NULL; return o; } } static sen_cell * nf_tob32h(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_cell *x, *v; if (!PAIRP(args)) { QLERR("list required"); } x = CAR(args); switch (x->header.type) { case SEN_CELL_INT : { sen_obj buf; sen_bulk_init(ctx, &buf, 13); if (sen_bulk_lltob32h(ctx, &buf, IVALUE(x))) { sen_bulk_fin(ctx, &buf); QLERR("lltob32h failed"); } SEN_STR2OBJ(ctx, &buf, v); } break; case SEN_CELL_FLOAT : { sen_obj buf; sen_bulk_init(ctx, &buf, 13); if (sen_bulk_lltob32h(ctx, &buf, (int64_t)FVALUE(x))) { sen_bulk_fin(ctx, &buf); QLERR("lltob32h failed"); } SEN_STR2OBJ(ctx, &buf, v); } break; default : QLERR("can't convert into int"); } return v; } static sen_cell * nf_intern(sen_ctx *ctx, sen_cell *args, sen_ql_co *co) { sen_cell *x, *v; if (!PAIRP(args)) { QLERR("list required"); } x = CAR(args); if SYMBOLP(x) { return x; } switch (x->header.type) { case SEN_CELL_STR : v = sen_ql_mk_symbol2(ctx, STRVALUE(x), STRSIZE(x), 0); break; default : QLERR("can't convert into string"); } return v; } /* ========== Initialization of internal keywords ========== */ inline static void mk_syntax(sen_ctx *ctx, uint8_t op, char *name) { sen_cell *x; if ((x = INTERN(name)) != F) { x->header.type = SEN_CELL_SYNTAX; SYNTAXNUM(x) = op; } } inline static void mk_proc(sen_ctx *ctx, uint8_t op, char *name) { sen_cell *x; if ((x = INTERN(name)) != F) { x->header.type = SEN_CELL_PROC; IVALUE(x) = (int64_t) op; } } void sen_ql_init_const(void) { static sen_cell _NIL, _T, _F; /* init NIL */ NIL = &_NIL; NIL->header.type = SEN_VOID; CAR(NIL) = CDR(NIL) = NIL; /* init T */ T = &_T; T->header.type = SEN_VOID; CAR(T) = CDR(T) = T; /* init F */ F = &_F; F->header.type = SEN_VOID; CAR(F) = CDR(F) = F; } inline static void init_vars_global(sen_ctx *ctx) { sen_cell *x; /* init global_env */ ctx->impl->global_env = CONS(NIL, NIL); /* init else */ if ((x = INTERN("else")) != F) { CAR(ctx->impl->global_env) = CONS(CONS(x, T), CAR(ctx->impl->global_env)); } } inline static void init_syntax(sen_ctx *ctx) { /* init syntax */ mk_syntax(ctx, OP_LAMBDA, "lambda"); mk_syntax(ctx, OP_QUOTE, "quote"); mk_syntax(ctx, OP_DEF0, "define"); mk_syntax(ctx, OP_IF0, "if"); mk_syntax(ctx, OP_BEGIN, "begin"); mk_syntax(ctx, OP_SET0, "set!"); mk_syntax(ctx, OP_LET0, "let"); mk_syntax(ctx, OP_LET0AST, "let*"); mk_syntax(ctx, OP_LET0REC, "letrec"); mk_syntax(ctx, OP_COND0, "cond"); mk_syntax(ctx, OP_DELAY, "delay"); mk_syntax(ctx, OP_AND0, "and"); mk_syntax(ctx, OP_OR0, "or"); mk_syntax(ctx, OP_C0STREAM, "cons-stream"); mk_syntax(ctx, OP_0MACRO, "define-macro"); mk_syntax(ctx, OP_CASE0, "case"); mk_syntax(ctx, OP_QQUOTE0, "quasiquote"); } inline static void init_procs(sen_ctx *ctx) { /* init procedure */ mk_proc(ctx, OP_PEVAL, "eval"); mk_proc(ctx, OP_PAPPLY, "apply"); mk_proc(ctx, OP_CONTINUATION, "call-with-current-continuation"); mk_proc(ctx, OP_FORCE, "force"); mk_proc(ctx, OP_SETCAR, "set-car!"); mk_proc(ctx, OP_SETCDR, "set-cdr!"); mk_proc(ctx, OP_READ, "read"); mk_proc(ctx, OP_LOAD, "load"); mk_proc(ctx, OP_ERR1, "error"); mk_proc(ctx, OP_PUT, "put"); mk_proc(ctx, OP_GET, "get"); mk_proc(ctx, OP_QUIT, "quit"); mk_proc(ctx, OP_SDOWN, "shutdown"); sen_ql_def_native_func(ctx, "+", nf_add); sen_ql_def_native_func(ctx, "-", nf_sub); sen_ql_def_native_func(ctx, "*", nf_mul); sen_ql_def_native_func(ctx, "/", nf_div); sen_ql_def_native_func(ctx, "remainder", nf_rem); sen_ql_def_native_func(ctx, "car", nf_car); sen_ql_def_native_func(ctx, "cdr", nf_cdr); sen_ql_def_native_func(ctx, "cons", nf_cons); sen_ql_def_native_func(ctx, "not", nf_not); sen_ql_def_native_func(ctx, "boolean?", nf_bool); sen_ql_def_native_func(ctx, "symbol?", nf_symbol); sen_ql_def_native_func(ctx, "number?", nf_number); sen_ql_def_native_func(ctx, "string?", nf_string); sen_ql_def_native_func(ctx, "procedure?", nf_proc); sen_ql_def_native_func(ctx, "pair?", nf_pair); sen_ql_def_native_func(ctx, "eqv?", nf_eqv); sen_ql_def_native_func(ctx, "logtest", nf_logtest); sen_ql_def_native_func(ctx, "eq?", nf_eq); sen_ql_def_native_func(ctx, "null?", nf_null); sen_ql_def_native_func(ctx, "zero?", nf_zerop); sen_ql_def_native_func(ctx, "positive?", nf_posp); sen_ql_def_native_func(ctx, "negative?", nf_negp); sen_ql_def_native_func(ctx, "=", nf_neq); sen_ql_def_native_func(ctx, "<", nf_less); sen_ql_def_native_func(ctx, ">", nf_gre); sen_ql_def_native_func(ctx, "<=", nf_leq); sen_ql_def_native_func(ctx, ">=", nf_geq); sen_ql_def_native_func(ctx, "write", nf_write); sen_ql_def_native_func(ctx, "display", nf_display); sen_ql_def_native_func(ctx, "newline", nf_newline); sen_ql_def_native_func(ctx, "reverse", nf_reverse); sen_ql_def_native_func(ctx, "append", nf_append); sen_ql_def_native_func(ctx, "gc", nf_gc); sen_ql_def_native_func(ctx, "gc-verbose", nf_gcverb); sen_ql_def_native_func(ctx, "native?", nf_nativep); sen_ql_def_native_func(ctx, "length", nf_length); /* a.k */ sen_ql_def_native_func(ctx, "assq", nf_assq); /* a.k */ sen_ql_def_native_func(ctx, "get-closure-code", nf_get_closure); /* a.k */ sen_ql_def_native_func(ctx, "closure?", nf_closurep); /* a.k */ sen_ql_def_native_func(ctx, "macro?", nf_macrop); /* a.k */ sen_ql_def_native_func(ctx, "void?", nf_voidp); sen_ql_def_native_func(ctx, "list", nf_list); sen_ql_def_native_func(ctx, "batchmode", nf_batchmode); sen_ql_def_native_func(ctx, "loglevel", nf_loglevel); sen_ql_def_native_func(ctx, "now", nf_now); sen_ql_def_native_func(ctx, "timestr", nf_timestr); sen_ql_def_native_func(ctx, "x->time", nf_totime); sen_ql_def_native_func(ctx, "x->number", nf_tonumber); sen_ql_def_native_func(ctx, "substrb", nf_substrb); sen_ql_def_native_func(ctx, "x->b32h", nf_tob32h); sen_ql_def_native_func(ctx, "intern", nf_intern); } /* initialize several globals */ void sen_ql_init_globals(sen_ctx *ctx) { init_vars_global(ctx); init_syntax(ctx); init_procs(ctx); ctx->impl->output = sen_ctx_concat_func; /* initialization of global pointers to special symbols */ }