add fnblock return-from

This commit is contained in:
yoyo 2024-09-12 19:53:56 +09:00
parent 07300eff7c
commit 5b71814caf
9 changed files with 148 additions and 41 deletions

View File

@ -21,6 +21,8 @@ Object Not = (Object){.type=OBLTIN, .beg= "not"};
Object Bquote= (Object){.type=OBLTIN, .beg="`"}; Object Bquote= (Object){.type=OBLTIN, .beg="`"};
Object Lambda= (Object){.type=OBLTIN, .beg="lambda"}; Object Lambda= (Object){.type=OBLTIN, .beg="lambda"};
Object Block= (Object){.type=OBLTIN, .beg="block"};
Object RetFrom = (Object){.type=OBLTIN, .beg="return-from"};
Object Let= (Object){.type=OBLTIN, .beg="let"}; Object Let= (Object){.type=OBLTIN, .beg="let"};
Object Progn=(Object){.type=OBLTIN, .beg="progn"}; Object Progn=(Object){.type=OBLTIN, .beg="progn"};
Object Car = (Object){.type=OBLTIN, .beg="car"}; Object Car = (Object){.type=OBLTIN, .beg="car"};
@ -39,6 +41,8 @@ extern Object* fnmod(Object *, Object *);
extern Object* fnlambda(Object *, Object *); extern Object* fnlambda(Object *, Object *);
extern Object* fnlet(Object *, Object *); extern Object* fnlet(Object *, Object *);
extern Object* fnprogn(Object *, Object *); extern Object* fnprogn(Object *, Object *);
extern Object* fnblock(Object *, Object *);
extern Object* fnretfrom(Object *, Object *);
extern Object* fndefine(Object *, Object *); extern Object* fndefine(Object *, Object *);
extern Object* fndefmacro(Object *, Object *); extern Object* fndefmacro(Object *, Object *);
extern Object* fnsetq(Object *, Object *); extern Object* fnsetq(Object *, Object *);
@ -68,6 +72,8 @@ bltinlookup(Object *obj)
}bltins[] = { }bltins[] = {
{&Lambda , fnlambda}, {&Lambda , fnlambda},
{&Progn , fnprogn}, {&Progn , fnprogn},
{&Block , fnblock},
{&RetFrom ,fnretfrom},
{&Plus , fnplus}, {&Plus , fnplus},
{&Mul , fnmul}, {&Mul , fnmul},
{&Mod , fnmod}, {&Mod , fnmod},

20
dat.h
View File

@ -13,6 +13,7 @@ enum OType
OINT, OINT,
OFUNC, OFUNC,
OMACRO, OMACRO,
OBLOCK,
OFRAME, OFRAME,
OENV, OENV,
}; };
@ -36,23 +37,32 @@ struct Object
char *ptr; char *ptr;
char *end; char *end;
}; };
/* Block */
struct{
Object *_tag;
Object *_up;
Object *_body;
void *jmp;
};
/* function */ /* function */
struct{ struct{
Object *params; Object *params;
Object *body;
Object *frame; /* running frame */ Object *frame; /* running frame */
Object *body;
Object *block;
}; };
/* Frame */ /* Frame */
struct{ struct{
Object *tag; /* block name */ Object *tag; /* Frame enter name */
Object *local; /* local vars */
Object *up; Object *up;
Object *local; /* local vars */
}; };
/* Env */ /* Env */
struct{ struct{
Object *frames; Object *frames;
Object *bp; Object *bp;
Object *sp; /* current */ Object *sp; /* current */
Object *retval; /* for return-from */
}; };
}; };
}; };
@ -60,6 +70,8 @@ struct Object
extern GC *gc; extern GC *gc;
extern Object Nil; extern Object Nil;
extern Object Top; extern Object Top;
extern Object Block;
extern Object RetFrom;
extern Object Comma; extern Object Comma;
extern Object Splice; extern Object Splice;
extern Object Bquote; extern Object Bquote;

111
eval.c
View File

@ -1,6 +1,8 @@
#include "dat.h" #include "dat.h"
#include "fn.h" #include "fn.h"
#include <assert.h> #include <assert.h>
#include <setjmp.h>
#include <string.h>
#define cdr(x) ((x)!= &Nil && (x)->type == OCELL ? (x)->cdr : &Nil) #define cdr(x) ((x)!= &Nil && (x)->type == OCELL ? (x)->cdr : &Nil)
#define car(x) ((x)!= &Nil && (x)->type == OCELL ? (x)->car : &Nil) #define car(x) ((x)!= &Nil && (x)->type == OCELL ? (x)->car : &Nil)
@ -20,6 +22,35 @@ static char *typtab[] = {
static Object* evallist(Object *env, Object *list); static Object* evallist(Object *env, Object *list);
static Object* curblock(Object *env) { return env->sp->car->block; }
static Object* curframe(Object *env) { return env->sp->car; }
static int
_streq(Object *a, Object *b)
{
int la = strlen(a->beg);
return la == strlen(b->beg) && memcmp(a->beg, b->beg, la) == 0;
}
static void
enterframe(Object *env, Object *tag, Object *local, Object *up)
{
assert(env->bp != &Nil);
Object *frame = newframe(gc, tag, local, up, curblock(env));
env->sp = env->sp->cdr = newcons(gc, frame, &Nil);
}
static void
leaveframe(Object *env)
{
assert(env->sp != env->bp);
Object *p = env->bp;
while(cdr(p) != env->sp)
p = p->cdr;
p->cdr = &Nil;
env->sp = p;
}
static int static int
exprlen(Object *expr) exprlen(Object *expr)
{ {
@ -65,7 +96,7 @@ clone(Object *p)
static Object* static Object*
find(Object *env, Object *obj) find(Object *env, Object *obj)
{ {
for(Object *cur=env->sp->car; cur!=&Nil; cur=cur->up) for(Object *cur=curframe(env); cur!=&Nil; cur=cur->up)
for(Object *p=cur->local; p!=&Nil; p=cdr(p)) for(Object *p=cur->local; p!=&Nil; p=cdr(p))
if(strequal(obj, car(car(p)))) if(strequal(obj, car(car(p))))
return clone(cdr(car(p))); return clone(cdr(car(p)));
@ -83,7 +114,7 @@ _newfn(Object *env, Object *l, enum OType type)
error("parameter is not IDNET"); error("parameter is not IDNET");
Object *params = l->car; Object *params = l->car;
Object *body = l->cdr; Object *body = l->cdr;
return newfn(gc, env->sp->car, params, body, type); return newfn(gc, curframe(env), params, body, type);
} }
static void static void
@ -130,12 +161,55 @@ fnprogn(Object *env, Object *list)
return progn(env, list); return progn(env, list);
} }
Object*
fnblock(Object *env, Object *list)
{
if(list->type != OCELL)
error("Malformed block");
Object *tag = car(list);
Object *body = cdr(list);
Object *frame = curframe(env);
jmp_buf jmp;
Object *b = frame->block = newblock(gc, tag, curblock(env), body, &jmp);
Object *res = 0;
if(setjmp(jmp) == 1){
res = env->retval;
env->retval = 0;
Object *p = curblock(env);
for(;p!=b; p=p->up)
assert(p->tag != &Top);
curframe(env)->block = p->up;
return res;
}
res = progn(env, body);
frame->block = frame->block->up;
return res;
}
Object*
fnretfrom(Object *env, Object *list)
{
if(list->type != OCELL)
error("Malformed return-from");
Object *tag = car(list);
Object *p = curblock(env);
for(; p!= &Top; p=p->up)
if(_streq(p->tag, tag)){
env->retval = eval(env, car(cdr(list)));
longjmp(*(jmp_buf*)p->jmp, 1);
}
error("can't excute return-from");
return 0;
}
Object* Object*
fnsetq(Object *env, Object *list) fnsetq(Object *env, Object *list)
{ {
if(list->type != OCELL || exprlen(list)!=2 || list->car->type!=OIDENT) if(list->type != OCELL || exprlen(list)!=2 || list->car->type!=OIDENT)
error("Malformed setq"); error("Malformed setq");
for(Object *frame=env->sp->car; frame!=&Nil; frame=frame->up) for(Object *frame=curframe(env); frame!=&Nil; frame=frame->up)
for(Object *p=frame->local; p!=&Nil; p=cdr(p)) for(Object *p=frame->local; p!=&Nil; p=cdr(p))
if(strequal(list->car, car(car(p)))) if(strequal(list->car, car(car(p))))
return p->car->cdr = eval(env, car(cdr(list))); return p->car->cdr = eval(env, car(cdr(list)));
@ -144,25 +218,6 @@ fnsetq(Object *env, Object *list)
return 0; return 0;
} }
static void
enter(Object *env, Object *tag, Object *local, Object *up)
{
assert(env->bp != &Nil);
Object *frame = newframe(gc, tag, local, up);
env->sp = env->sp->cdr = newcons(gc, frame, &Nil);
}
static void
leave(Object *env)
{
assert(env->sp != env->bp);
Object *p = env->bp;
while(cdr(p) != env->sp)
p = p->cdr;
p->cdr = &Nil;
env->sp = p;
}
Object* Object*
fnlet(Object *env, Object *list) fnlet(Object *env, Object *list)
{ {
@ -174,9 +229,9 @@ fnlet(Object *env, Object *list)
Object *val = eval(env, car(cdr(car(p)))); Object *val = eval(env, car(cdr(car(p))));
local = newacons(gc, id, val, local); local = newacons(gc, id, val, local);
} }
enter(env, &Let, local, env->sp->car); enterframe(env, &Let, local, curframe(env));
Object *res = progn(env, cdr(list)); Object *res = progn(env, cdr(list));
leave(env); leaveframe(env);
return res; return res;
} }
@ -429,9 +484,9 @@ static Object*
applyfn(Object *env, Object *tag, Object *fn, Object *args) applyfn(Object *env, Object *tag, Object *fn, Object *args)
{ {
Object *local = applyargs(fn, args); Object *local = applyargs(fn, args);
enter(env, tag, local,fn->frame); enterframe(env, tag, local,fn->frame);
Object *res = progn(env, fn->body); Object *res = progn(env, fn->body);
leave(env); leaveframe(env);
return res; return res;
} }
@ -439,9 +494,9 @@ static Object*
applymacro(Object *env, Object *tag, Object* fn, Object *args) applymacro(Object *env, Object *tag, Object* fn, Object *args)
{ {
Object *local = applyargs(fn, args); Object *local = applyargs(fn, args);
enter(env, tag, local, fn->frame); enterframe(env, tag, local, fn->frame);
Object *r = progn(env, fn->body); Object *r = progn(env, fn->body);
leave(env); leaveframe(env);
return eval(env, r); return eval(env, r);
} }

3
fn.h
View File

@ -13,7 +13,8 @@ Object* eval(Object *env, Object *expr);
Object* newint(GC *,long); Object* newint(GC *,long);
Object* newcons(GC *,Object*,Object*); Object* newcons(GC *,Object*,Object*);
Object* newenv(GC *gc, Object *frames, Object *bp, Object *sp); Object* newenv(GC *gc, Object *frames, Object *bp, Object *sp);
Object* newframe(GC *gc, Object* tag, Object *local, Object *up); Object* newblock(GC *gc, Object* tag, Object *up, Object *body, void *jmp);
Object* newframe(GC *gc, Object* tag, Object *local, Object *up, Object *block);
Object* newacons(GC *,Object*, Object*, Object*); Object* newacons(GC *,Object*, Object*, Object*);
Object* newsymbol(GC *,char*, int); Object* newsymbol(GC *,char*, int);
Object* newstr(GC *,int); Object* newstr(GC *,int);

21
gc.c
View File

@ -42,6 +42,7 @@ findobj(GC *gc, uintptr_t *stk)
static Object* static Object*
cloneobj(GC *dst, GC *src, Object *obj) cloneobj(GC *dst, GC *src, Object *obj)
{ {
if(obj==0)return 0;
if(obj->type==OBLTIN||obj->type==OSYMBOL) return obj; if(obj->type==OBLTIN||obj->type==OSYMBOL) return obj;
if(obj->flag&FORWARD) return obj->forward; if(obj->flag&FORWARD) return obj->forward;
@ -69,12 +70,21 @@ cloneobj(GC *dst, GC *src, Object *obj)
p->frames = cloneobj(dst, src, obj->frames); p->frames = cloneobj(dst, src, obj->frames);
p->bp = cloneobj(dst, src, obj->bp); p->bp = cloneobj(dst, src, obj->bp);
p->sp = cloneobj(dst, src, obj->sp); p->sp = cloneobj(dst, src, obj->sp);
p->retval = cloneobj(dst, src, obj->retval);
break;
case OBLOCK:
obj->forward = p = newblock(dst, &Nil, &Nil, &Nil, obj->jmp);
p->tag = cloneobj(dst, src, obj->tag);
p->up = cloneobj(dst, src, obj->up);
p->body = cloneobj(dst, src, obj->body);
p->jmp = obj->jmp;
break; break;
case OFRAME: case OFRAME:
obj->forward = p = newframe(dst, &Nil, &Nil, &Nil); obj->forward = p = newframe(dst, &Nil, &Nil, &Nil, &Nil);
p->tag = cloneobj(dst, src, obj->tag); p->tag = cloneobj(dst, src, obj->tag);
p->local = cloneobj(dst, src, obj->local); p->local = cloneobj(dst, src, obj->local);
p->up = cloneobj(dst, src, obj->up); p->up = cloneobj(dst, src, obj->up);
p->block = cloneobj(dst, src, obj->block);
break; break;
case OMACRO: case OMACRO:
case OFUNC: case OFUNC:
@ -123,7 +133,7 @@ gcraise(GC *src)
static void static void
mark(GC *gc, Object *obj) mark(GC *gc, Object *obj)
{ {
if(obj->flag&USING||obj->type==ONONE||obj->type==OSYMBOL||obj->type==OBLTIN) if(obj==0||obj->flag&USING||obj->type==ONONE||obj->type==OSYMBOL||obj->type==OBLTIN)
return; return;
obj->flag = USING; obj->flag = USING;
@ -137,11 +147,18 @@ mark(GC *gc, Object *obj)
mark(gc, obj->frames); mark(gc, obj->frames);
mark(gc, obj->bp); mark(gc, obj->bp);
mark(gc, obj->sp); mark(gc, obj->sp);
mark(gc, obj->retval);
break;
case OBLOCK:
mark(gc, obj->tag);
mark(gc, obj->up);
mark(gc, obj->body);
break; break;
case OFRAME: case OFRAME:
mark(gc, obj->tag); mark(gc, obj->tag);
mark(gc, obj->local); mark(gc, obj->local);
mark(gc, obj->up); mark(gc, obj->up);
mark(gc, obj->block);
break; break;
case OMACRO: case OMACRO:
case OFUNC: case OFUNC:

View File

@ -1,5 +1,5 @@
(defmacro defun (name args body) (defmacro defun (name args body)
`(define ,name (lambda ,args ,body))) `(define ,name (block ,name (lambda ,args ,body))))
(defmacro cond (expr . rest) (defmacro cond (expr . rest)
(if (not expr) (if (not expr)

8
main.c
View File

@ -31,9 +31,13 @@ SExprint(Object *obj)
case OSYMBOL: case OSYMBOL:
printf("%s", obj->beg); printf("%s", obj->beg);
break; break;
case OBLOCK:
printf("\n<block-%s>\n", obj->tag->beg);
break;
case OFRAME: case OFRAME:
printf("<frame> %s\n", obj->tag->beg); printf("\n<frame-%s>\n", obj->tag->beg);
printexpr(obj->local); printexpr(obj->local);
printexpr(obj->block);
break; break;
case OENV: case OENV:
printf("<env>"); printf("<env>");
@ -64,7 +68,7 @@ int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
*argv = "lib/lib.lisp"; *argv = "lib/lib.lisp";
gc = newgc(&argc, 400); gc = newgc(&argc, 24000);
lispmain(argv); lispmain(argv);
panic("unreachable"); panic("unreachable");
} }

16
obj.c
View File

@ -29,12 +29,24 @@ newcons(GC *gc, Object *car, Object *cdr)
} }
Object* Object*
newframe(GC *gc, Object* tag, Object *local, Object *up) newblock(GC *gc, Object* tag, Object *up, Object *body, void *jmp)
{
Object *obj = newobj(gc, OBLOCK, 0);
obj->tag = tag;
obj->up = up;
obj->body = body;
obj->jmp = jmp;
return obj;
}
Object*
newframe(GC *gc, Object* tag, Object *local, Object *up, Object *block)
{ {
Object *obj = newobj(gc, OFRAME, 0); Object *obj = newobj(gc, OFRAME, 0);
obj->tag = tag; obj->tag = tag;
obj->local = local; obj->local = local;
obj->up = up; obj->up = up;
obj->block = block;
return obj; return obj;
} }
@ -73,7 +85,7 @@ newsymbol(GC *gc, char *str, int len)
&Nil, &Minus, &Plus, &Mul, &Mod, &Div, &Ge, &Le, &Nil, &Minus, &Plus, &Mul, &Mod, &Div, &Ge, &Le,
&Lt, &Gt, &Ne, &Lambda, &Car, &Cdr, &Quote, &Cons, &Lt, &Gt, &Ne, &Lambda, &Car, &Cdr, &Quote, &Cons,
&Define, &Setq, &Eq, &If, &Macro, &Progn, &Bquote, &Define, &Setq, &Eq, &If, &Macro, &Progn, &Bquote,
&Comma, &Not, &Splice, &Let, &Comma, &Not, &Splice, &Let, &Block, &RetFrom,
}; };
for(int i = 0; i < sizeof(syms)/sizeof(syms[0]); ++i){ for(int i = 0; i < sizeof(syms)/sizeof(syms[0]); ++i){
Object *c = syms[i]; Object *c = syms[i];

2
repl.c
View File

@ -66,7 +66,7 @@ readlib(FILE *f, Object *env)
void void
lispmain(char *argv[]) lispmain(char *argv[])
{ {
Object *frame = newframe(gc, &Top, &Nil, &Nil); Object *frame = newframe(gc, &Top, &Nil, &Nil, &Top);
Object *cons = newcons(gc, frame, &Nil); Object *cons = newcons(gc, frame, &Nil);
Object *env = newenv(gc, cons, cons, cons); Object *env = newenv(gc, cons, cons, cons);
for(; *argv; ++argv){ for(; *argv; ++argv){