clisp/eval.c
2024-09-11 13:44:05 +09:00

451 lines
8.5 KiB
C

#include "dat.h"
#include "fn.h"
#define cdr(x) ((x)!= &Nil && (x)->type == OCELL ? (x)->cdr : &Nil)
#define car(x) ((x)!= &Nil && (x)->type == OCELL ? (x)->car : &Nil)
static char *typtab[] = {
[ONONE] = "error",
[OBLTIN] = "bltin",
[OSYMBOL] = "symbol",
[OCELL] = "cell",
[OIDENT] = "ident",
[OSTRING] = "string",
[OINT] = "int",
[OFUNC] = "func",
[OMACRO] = "macro",
[OENV] = "env",
};
static Object* evallist(Object *env, Object *list);
static int
exprlen(Object *expr)
{
int l = 0;
while(expr != &Nil){
expr = cdr(expr);
l += 1;
}
return l;
}
static int
islist(Object *obj)
{
return obj == &Nil || obj->type == OCELL;
}
static Object*
clone(Object *p)
{
switch(p->type){
default: panic("unreachable");
case OENV:
case OSYMBOL:
case OINT:
case OIDENT:
case OBLTIN:
return p;
case OMACRO:
case OFUNC:
return newfn(gc, p->env, clone(p->params), clone(p->body), p->type);
case OCELL:
return newcons(gc, clone(p->car), clone(p->cdr));
case OSTRING:{
Object *s = newstr(gc, p->end - p->beg);
strinit(s, p);
return s;
}
}
}
static Object*
find(Object *env, Object *obj)
{
for(Object *cur=env; cur!=&Nil; cur=cur->up)
for(Object *p=cur->vars; p!=&Nil; p=cdr(p)){
Object *v = car(p);
if(strequal(obj, car(v)))
return clone(cdr(v));
}
error("not exist variable");
return 0;
}
static Object*
_newfn(Object *env, Object *l, enum OType type)
{
if(l->type!=OCELL || islist(l->car)==0 || l->cdr->type!=OCELL)
error("malformed function");
for(Object *p=l->car; p->type==OCELL; p=cdr(p))
if(p->car->type!=OIDENT)
error("parameter is not IDNET");
Object *params = l->car;
Object *body = l->cdr;
return newfn(gc, env, params, body, type);
}
static Object*
defvar(Object *env, Object *id, Object *val)
{
for(Object *p=env->vars; p!=&Nil; p=cdr(p))
if(strequal(id, car(car(p))))
error("already exist variable. use setq plz...");
return newacons(gc, id, val, env->vars);
}
Object*
fnlambda(Object *env, Object *l)
{
return _newfn(env, l, OFUNC);
}
Object*
fnmacro(Object *env, Object *l)
{
if(l->type != OCELL)
error("Malformed macro");
Object *macro = _newfn(env, l->cdr, OMACRO);
env->vars = defvar(env, l->car, macro);
return macro;
}
static Object*
progn(Object *env, Object *list)
{
Object *r = &Nil;
for(Object *p=list; p!=&Nil; p=cdr(p)){
r = eval(env, car(p));
}
return r;
}
Object*
fnprogn(Object *env, Object *list)
{
return progn(env, list);
}
Object*
fnsetq(Object *env, Object *list)
{
if(exprlen(list)!=2 || list->car->type!=OIDENT)
error("Malformed setq");
Object *cur = env;
Object *p = 0;
for(; cur!=&Nil; cur=cur->up)
for(p=cur->vars; p!=&Nil; p=p->cdr)
if(strequal(list->car, p->car->car))
goto found;
error("setq not exist variable");
found:;
return p->car->cdr = eval(env, list->cdr->car);
}
Object*
fndefine(Object *env, Object *list)
{
if(exprlen(list)!=2 || list->car->type!=OIDENT)
error("Malformed define");
Object *val = eval(env, list->cdr->car);
env->vars = defvar(env, list->car, val);
return val;
}
Object*
fnquote(Object *env, Object *list)
{
if(exprlen(list)!=1)
error("Malformed quote");
return list->car;
}
static Object*
evalcomma(Object *env, Object *p)
{
if(p->type != OCELL)
return p;
if(p->car == &Comma){
if(car(cdr(p)) == &Splice){
return newcons(gc, &Splice, eval(env, p->cdr->cdr));
}else
return eval(env, p->cdr);
}
p->car = evalcomma(env, p->car);
p->cdr = evalcomma(env, p->cdr);
if(car(car(p)) == &Splice){
Object *i = p->car;
while(cdr(i) != &Nil)
i = i->cdr;
if(i->type == OCELL){
i->cdr = p->cdr;
return p->car->cdr;
}
p->car = i;
}
return p;
}
Object*
fnbquote(Object *env, Object *list)
{
if(exprlen(list) != 1)
error("Malformed fnbquote");
return evalcomma(env, list->car);
}
Object*
fncar(Object *env, Object *list)
{
list = evallist(env, list);
if(exprlen(list) < 1)
error("car: expected list");
return car(car(list));
}
Object*
fncdr(Object *env, Object *list)
{
list = evallist(env, list);
if(exprlen(list) < 1)
error("cdr: expected list");
return cdr(car(list));
}
Object*
fncons(Object *env, Object *list)
{
if(exprlen(list) != 2)
error("Malformoed cons");
list = evallist(env, list);
if(list->type != OCELL)
error("cons:bad list");
list->cdr = car(list->cdr);
return list;
}
Object*
fnplus(Object *env, Object *list)
{
long sum = 0;
Object *p=evallist(env, list);
for(;p!=&Nil; p=cdr(p)){
if(p->car->type != OINT)
error("+ take only number");
sum += p->car->num;
}
return newint(gc, sum);
}
Object*
fnmul(Object *env, Object *list)
{
Object *p = evallist(env, list);
if(car(p)->type != OINT)
error("* take only [INT]");
long sum = p->car->num;
for(p=p->cdr;p!=&Nil; p=cdr(p)){
if(car(p)->type != OINT)
error("* take only [INT]");
sum *= p->car->num;
}
return newint(gc, sum);
}
Object*
fndiv(Object *env, Object *list)
{
Object *p=evallist(env, list);
if(p->car->type != OINT)
error("/ take only [INT]");
long sum = p->car->num;
for(p=p->cdr;p!=&Nil; p=cdr(p)){
if(car(p)->type != OINT)
error("/ take only [INT]");
if(p->car->num == 0)
error("Can't div zero");
sum /= p->car->num;
}
return newint(gc, sum);
}
Object*
fnmod(Object *env, Object *list)
{
Object *p=evallist(env, list);
if(p->car->type != OINT)
error("%% take only [INT]");
long sum = p->car->num;
for(p=p->cdr;p!=&Nil; p=cdr(p)){
if(car(p)->type != OINT)
error("%% take only [INT]");
if(p->car->num == 0)
error("Can't mod zero");
sum %= p->car->num;
}
return newint(gc, sum);
}
static long
cmp(Object *env, Object *list)
{
Object *a = eval(env, car(list));
Object *b = eval(env, car(cdr(list)));
if(a->type != OINT || b->type != OINT)
error("cmp only take [INT]");
return a->num - b->num;
}
static Object*
_newint(int n)
{
if(n == 0)
return &Nil;
return newint(gc, 1);
}
Object*
fnnot(Object *env, Object *list)
{
if(exprlen(list) != 1)
error("Malformed not");
return _newint(eval(env, car(list)) == &Nil);
}
Object*
fneq(Object *env, Object *list)
{
return _newint(cmp(env, list) == 0);
}
Object*
fnge(Object *env, Object *list)
{
return _newint(cmp(env, list) >= 0);
}
Object*
fngt(Object *env, Object *list)
{
return _newint(cmp(env, list) > 0);
}
Object*
fnle(Object *env, Object *list)
{
return _newint(cmp(env, list) <= 0);
}
Object*
fnlt(Object *env, Object *list)
{
return _newint(cmp(env, list) < 0);
}
Object*
fnne(Object *env, Object *list)
{
return _newint(cmp(env, list) != 0);
}
Object*
fnif(Object *env, Object *list)
{
if(cdr(list)->type != OCELL)
error("Malformed if stmt");
Object *test = list->car;
Object *then = car(cdr(list));
Object *else_ = car(cdr(cdr(list)));
if(eval(env, test)!=&Nil)
return eval(env, then);
return eval(env, else_);
}
static Object*
evallist(Object *env, Object *list)
{
if(list == &Nil)
return &Nil;
Object *car = eval(env, car(list));
Object *cdr = evallist(env, cdr(list));
return newcons(gc, car, cdr);
}
static Object*
enter(Object *env, Object *vars, Object *args)
{
Object *map = &Nil;
for(;vars->type==OCELL; vars=cdr(vars), args=cdr(args)){
if(args->type!=OCELL)
error("Cna't apply function argment dose not match");
Object *id = car(vars);
Object *val = car(args);
map = newacons(gc, id, val, map);
}
if(vars != &Nil)
map = newacons(gc, vars, args, map);
return newenv(gc, &Nil, map, env);
}
static Object*
applyfn(Object *fn, Object *args)
{
Object *env = enter(fn->env, fn->params, args);
return progn(env, fn->body);
}
static Object*
applymacro(Object *env, Object* fn, Object *args)
{
Object *nenv = enter(fn->env, fn->params, args);
Object *r = 0;
for(Object *p=fn->body; p!=&Nil; p=cdr(p)){
r = eval(nenv, car(p));
}
return eval(env, r);
}
static Object*
apply(Object *env, Object *fn, Object *args)
{
if(islist(args) == 0)
error("apply:args is not list type");
switch(fn->type){
default:
error("apply:can't eval type");
case OMACRO:
return applymacro(env, fn, args);
case OBLTIN:{
Bltinfn blt = bltinlookup(fn);
return blt(env, args);
}
case OFUNC:{
Object *elist = evallist(env, args);
Object*res = applyfn(fn, elist);
return res;
}
}
}
Object*
eval(Object *env, Object *obj)
{
switch(obj->type){
default:
error("eval: can't eval type");
case OSTRING:
case OINT:
case OBLTIN:
case OSYMBOL:
return obj;
case OIDENT:
return find(env, obj);
case OCELL:{
Object *fn = eval(env, obj->car);
Object *res = apply(env, fn, obj->cdr);
return res;
}
}
}