qse/ase/lsp/eval.c

288 lines
6.9 KiB
C
Raw Normal View History

2005-02-04 15:39:11 +00:00
/*
2006-10-22 13:10:46 +00:00
* $Id: eval.c,v 1.14 2006-10-22 13:10:45 bacon Exp $
2005-02-04 15:39:11 +00:00
*/
2006-10-22 13:10:46 +00:00
#include <sse/lsp/lsp.h>
#include <sse/lsp/env.h>
#include <sse/lsp/prim.h>
#include <sse/bas/assert.h>
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* make_func (
sse_lsp_t* lsp, sse_lsp_obj_t* cdr, int is_macro);
static sse_lsp_obj_t* eval_cons (
sse_lsp_t* lsp, sse_lsp_obj_t* cons);
static sse_lsp_obj_t* apply (
sse_lsp_t* lsp, sse_lsp_obj_t* func, sse_lsp_obj_t* actual);
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* sse_lsp_eval (sse_lsp_t* lsp, sse_lsp_obj_t* obj)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_NONE;
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
if (SSE_LSP_TYPE(obj) == SSE_LSP_OBJ_CONS)
2005-02-04 15:39:11 +00:00
return eval_cons (lsp, obj);
2006-10-22 13:10:46 +00:00
else if (SSE_LSP_TYPE(obj) == SSE_LSP_OBJ_SYMBOL) {
sse_lsp_assoc_t* assoc;
2005-02-04 15:39:11 +00:00
/*
if (obj == lsp->mem->lambda || obj == lsp->mem->macro) {
printf ("lambda or macro can't be used as a normal symbol\n");
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_BAD_SYMBOL;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
*/
2006-10-22 13:10:46 +00:00
assoc = sse_lsp_lookup(lsp->mem, obj);
if (assoc == SSE_NULL || assoc->value == SSE_NULL) {
2005-02-04 15:39:11 +00:00
if (lsp->opt_undef_symbol) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_UNDEF_SYMBOL;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
return lsp->mem->nil;
}
obj = assoc->value;
}
return obj;
}
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* make_func (sse_lsp_t* lsp, sse_lsp_obj_t* cdr, int is_macro)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* func, * formal, * body, * p;
2005-02-04 15:39:11 +00:00
if (cdr == lsp->mem->nil) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_TOO_FEW_ARGS;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
if (SSE_LSP_TYPE(cdr) != SSE_LSP_OBJ_CONS) {
lsp->errnum = SSE_LSP_ERR_BAD_ARG;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
formal = SSE_LSP_CAR(cdr);
body = SSE_LSP_CDR(cdr);
2005-02-04 15:39:11 +00:00
if (body == lsp->mem->nil) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_EMPTY_BODY;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2005-09-20 08:05:32 +00:00
// TODO: more lambda expression syntax checks required???.
/* check if the lambda express has non-nil value
* at the terminating cdr */
2006-10-22 13:10:46 +00:00
for (p = body; SSE_LSP_TYPE(p) == SSE_LSP_OBJ_CONS; p = SSE_LSP_CDR(p));
2005-09-19 16:13:18 +00:00
if (p != lsp->mem->nil) {
2005-09-20 08:05:32 +00:00
/* like in (lambda (x) (+ x 10) . 4) */
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_BAD_ARG;
return SSE_NULL;
2005-09-19 16:13:18 +00:00
}
2005-02-04 15:39:11 +00:00
func = (is_macro)?
2006-10-22 13:10:46 +00:00
sse_lsp_make_macro (lsp->mem, formal, body):
sse_lsp_make_func (lsp->mem, formal, body);
if (func == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_MEMORY;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
return func;
}
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* eval_cons (sse_lsp_t* lsp, sse_lsp_obj_t* cons)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* car, * cdr;
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
sse_assert (SSE_LSP_TYPE(cons) == SSE_LSP_OBJ_CONS);
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
car = SSE_LSP_CAR(cons);
cdr = SSE_LSP_CDR(cons);
2005-02-04 15:39:11 +00:00
if (car == lsp->mem->lambda) {
return make_func (lsp, cdr, 0);
}
else if (car == lsp->mem->macro) {
return make_func (lsp, cdr, 1);
}
2006-10-22 13:10:46 +00:00
else if (SSE_LSP_TYPE(car) == SSE_LSP_OBJ_SYMBOL) {
sse_lsp_assoc_t* assoc;
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
if ((assoc = sse_lsp_lookup(lsp->mem, car)) != SSE_NULL) {
//sse_lsp_obj_t* func = assoc->value;
sse_lsp_obj_t* func = assoc->func;
if (func == SSE_NULL) {
2005-09-20 09:17:06 +00:00
/* the symbol's function definition is void */
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_UNDEF_FUNC;
return SSE_NULL;
2005-09-20 09:17:06 +00:00
}
2006-10-22 13:10:46 +00:00
if (SSE_LSP_TYPE(func) == SSE_LSP_OBJ_FUNC ||
SSE_LSP_TYPE(func) == SSE_LSP_OBJ_MACRO) {
2005-02-04 15:39:11 +00:00
return apply (lsp, func, cdr);
}
2006-10-22 13:10:46 +00:00
else if (SSE_LSP_TYPE(func) == SSE_LSP_OBJ_PRIM) {
2005-09-20 12:06:51 +00:00
/* primitive function */
2006-10-22 13:10:46 +00:00
return SSE_LSP_PRIM(func) (lsp, cdr);
2005-02-04 15:39:11 +00:00
}
else {
2005-09-20 08:05:32 +00:00
//TODO: emit the name for debugging
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_UNDEF_FUNC;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
}
else {
//TODO: better error handling.
2005-09-20 08:05:32 +00:00
//TODO: emit the name for debugging
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_UNDEF_FUNC;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
}
2006-10-22 13:10:46 +00:00
else if (SSE_LSP_TYPE(car) == SSE_LSP_OBJ_FUNC ||
SSE_LSP_TYPE(car) == SSE_LSP_OBJ_MACRO) {
2005-02-04 15:39:11 +00:00
return apply (lsp, car, cdr);
}
2006-10-22 13:10:46 +00:00
else if (SSE_LSP_TYPE(car) == SSE_LSP_OBJ_CONS) {
if (SSE_LSP_CAR(car) == lsp->mem->lambda) {
sse_lsp_obj_t* func = make_func (lsp, SSE_LSP_CDR(car), 0);
if (func == SSE_NULL) return SSE_NULL;
2005-02-04 15:39:11 +00:00
return apply (lsp, func, cdr);
}
2006-10-22 13:10:46 +00:00
else if (SSE_LSP_CAR(car) == lsp->mem->macro) {
sse_lsp_obj_t* func = make_func (lsp, SSE_LSP_CDR(car), 1);
if (func == SSE_NULL) return SSE_NULL;
2005-02-04 15:39:11 +00:00
return apply (lsp, func, cdr);
}
}
2005-09-20 08:05:32 +00:00
//TODO: emit the name for debugging
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_BAD_FUNC;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* apply (
sse_lsp_t* lsp, sse_lsp_obj_t* func, sse_lsp_obj_t* actual)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_frame_t* frame;
sse_lsp_obj_t* formal;
sse_lsp_obj_t* body;
sse_lsp_obj_t* value;
sse_lsp_mem_t* mem;
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
sse_assert (
SSE_LSP_TYPE(func) == SSE_LSP_OBJ_FUNC ||
SSE_LSP_TYPE(func) == SSE_LSP_OBJ_MACRO);
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
sse_assert (SSE_LSP_TYPE(SSE_LSP_CDR(func)) == SSE_LSP_OBJ_CONS);
2005-02-04 15:39:11 +00:00
mem = lsp->mem;
2006-10-22 13:10:46 +00:00
if (SSE_LSP_TYPE(func) == SSE_LSP_OBJ_MACRO) {
formal = SSE_LSP_MFORMAL (func);
body = SSE_LSP_MBODY (func);
2005-02-04 15:39:11 +00:00
}
else {
2006-10-22 13:10:46 +00:00
formal = SSE_LSP_FFORMAL (func);
body = SSE_LSP_FBODY (func);
2005-02-04 15:39:11 +00:00
}
// make a new frame.
2006-10-22 13:10:46 +00:00
frame = sse_lsp_frame_new ();
if (frame == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_MEMORY;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
// attach it to the brooding frame list to
// make them not to be garbage collected.
frame->link = mem->brooding_frame;
mem->brooding_frame = frame;
// evaluate arguments and push them into the frame.
while (formal != mem->nil) {
if (actual == mem->nil) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_TOO_FEW_ARGS;
2005-02-04 15:39:11 +00:00
mem->brooding_frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
value = SSE_LSP_CAR(actual);
if (SSE_LSP_TYPE(func) != SSE_LSP_OBJ_MACRO) {
2005-02-04 15:39:11 +00:00
// macro doesn't evaluate actual arguments.
2006-10-22 13:10:46 +00:00
value = sse_lsp_eval (lsp, value);
if (value == SSE_NULL) {
2005-02-04 15:39:11 +00:00
mem->brooding_frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
}
2006-10-22 13:10:46 +00:00
if (sse_lsp_frame_lookup (
frame, SSE_LSP_CAR(formal)) != SSE_NULL) {
2005-09-20 09:17:06 +00:00
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_DUP_FORMAL;
2005-02-04 15:39:11 +00:00
mem->brooding_frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2005-09-20 08:05:32 +00:00
2006-10-22 13:10:46 +00:00
if (sse_lsp_frame_insert_value (
frame, SSE_LSP_CAR(formal), value) == SSE_NULL) {
2005-09-20 09:17:06 +00:00
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_MEMORY;
2005-02-04 15:39:11 +00:00
mem->brooding_frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
actual = SSE_LSP_CDR(actual);
formal = SSE_LSP_CDR(formal);
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
if (SSE_LSP_TYPE(actual) == SSE_LSP_OBJ_CONS) {
lsp->errnum = SSE_LSP_ERR_TOO_MANY_ARGS;
2005-02-04 15:39:11 +00:00
mem->brooding_frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
else if (actual != mem->nil) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_BAD_ARG;
2005-02-04 15:39:11 +00:00
mem->brooding_frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
// push the frame
mem->brooding_frame = frame->link;
frame->link = mem->frame;
mem->frame = frame;
// do the evaluation of the body
value = mem->nil;
while (body != mem->nil) {
2006-10-22 13:10:46 +00:00
value = sse_lsp_eval(lsp, SSE_LSP_CAR(body));
if (value == SSE_NULL) {
2005-02-04 15:39:11 +00:00
mem->frame = frame->link;
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
body = SSE_LSP_CDR(body);
2005-02-04 15:39:11 +00:00
}
// pop the frame.
mem->frame = frame->link;
// destroy the frame.
2006-10-22 13:10:46 +00:00
sse_lsp_frame_free (frame);
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
//if (SSE_LSP_CAR(func) == mem->macro) {
if (SSE_LSP_TYPE(func) == SSE_LSP_OBJ_MACRO) {
value = sse_lsp_eval(lsp, value);
if (value == SSE_NULL) return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
return value;
}