diff options
-rw-r--r-- | apl9.h | 26 | ||||
-rw-r--r-- | error.c | 49 | ||||
-rw-r--r-- | eval.c | 15 | ||||
-rw-r--r-- | main.c | 16 | ||||
-rw-r--r-- | memory.c | 19 | ||||
-rw-r--r-- | symbol.c | 63 |
6 files changed, 156 insertions, 32 deletions
@@ -68,7 +68,7 @@ typedef struct Datum Datum; typedef struct Symbol Symbol; typedef struct Symtab Symtab; typedef struct QuadnameDef QuadnameDef; -typedef struct ErrorHandler ErrorHandler; +typedef struct ErrorGuard ErrorGuard; typedef struct DfnFrame DfnFrame; typedef struct ThreadData ThreadData; typedef struct Mail Mail; @@ -208,10 +208,14 @@ struct QuadnameDef opdyad dyadop; }; -struct ErrorHandler +struct ErrorGuard { - Rune *msg; + u64int code; /* a bitmask of errors */ + int active; /* can the guard be used? */ jmp_buf jmp; + Statement *guard; + DfnFrame *frame; /* the frame to replace with upon activation of error guard */ + ErrorGuard *next; }; struct DfnFrame @@ -222,6 +226,7 @@ struct DfnFrame Array *right; Datum *lefto; Datum *righto; + ErrorGuard *errorguards; /* a linked list of error handlers */ DfnFrame *prev; /* prev in the call stack */ DfnFrame *chain; /* prev in the lexical scope */ }; @@ -232,6 +237,8 @@ struct ThreadData DfnFrame *currentdfn; Mail *mail; Mail *lastmail; + int lasterror; + Rune *lasterrormsg; QLock lock; Rendez empty; }; @@ -284,6 +291,8 @@ Symbol *getsym(Rune *, int); void initsymtab(void); DfnFrame *getcurrentdfn(void); DfnFrame *pushdfnframe(Rune *, DfnFrame *, Datum *, Datum *, Array *, Array *); +DfnFrame *dupdfnframe(DfnFrame *); +void freedfnframe(DfnFrame *, int); void popdfnframe(void); vlong globalIO(void); void globalIOset(vlong); @@ -306,6 +315,8 @@ void freeoperator(Operator); void freestatement(Statement); Function dupfunction(Function); Operator dupoperator(Operator); +void freeerrorguards(ErrorGuard *); +void freeerrorguard(ErrorGuard *); /* functions.c */ Array *runfunc(Function, Array *,Array *); @@ -317,14 +328,8 @@ void initquadnames(void); Datum *quadnamedatum(QuadnameDef); /* error.c */ +ErrorGuard *newerrorguard(Array *, Statement *); void throwerror(Rune *, int); -#define SETUPERROR(e) {\ - jmp_buf old;\ - memcpy(old, globalerror.jmp, sizeof(jmp_buf));\ - e = setjmp(globalerror.jmp);\ - if(e != 0)\ - memcpy(globalerror.jmp, old, sizeof(jmp_buf));\ -} /* inverse.c */ Function inverse(Function); @@ -474,7 +479,6 @@ extern int arrayalloccounts; /* memory.c */ extern int datumalloccounts; /* memory.c */ extern QuadnameDef quadnames[]; /* quadnames.c */ extern int printprecision; /* print.c */ -extern ErrorHandler globalerror; /* error.c */ extern Rune *errorstrs[]; /* error.c */ extern int needsnewline; /* quadnames.c */ extern int mainstacksize; /* concurrency.c */
\ No newline at end of file @@ -5,7 +5,7 @@ #include "apl9.h" -ErrorHandler globalerror; +ErrorGuard *globalerrorguard; Rune *errorstrs[] = { [ESyntax] = L"SYNTAX ERROR", @@ -20,11 +20,52 @@ Rune *errorstrs[] = { [ENotImplemented] = L"NOT IMPLEMENTED", }; +ErrorGuard * +newerrorguard(Array *codes, Statement *guard) +{ + DfnFrame *fr = getcurrentdfn(); + ErrorGuard *eg = emallocz(sizeof(ErrorGuard), 1); + eg->active = 1; + eg->guard = guard; + + if(fr == nil) + globalerrorguard = eg; + else{ + eg->next = fr->errorguards; + fr->errorguards = eg; + eg->frame = dupdfnframe(fr); + } + + for(int i = 0; i < GetSize(codes); i++) + eg->code |= (1<<codes->intdata[i]); + + return eg; +} + void throwerror(Rune *msg, int err) { - free(globalerror.msg); - globalerror.msg = msg ? runestrdup(msg) : nil; - longjmp(globalerror.jmp, err); + ErrorGuard *matching = globalerrorguard; + DfnFrame *frame = getcurrentdfn(); + ThreadData *td = getthreaddata(); + td->lasterror = err; + if(td->lasterrormsg) + free(td->lasterrormsg); + td->lasterrormsg = msg; + + while(frame != nil){ + for(ErrorGuard *eg = frame->errorguards; eg != nil; eg = eg->next){ + if(!eg->active) + continue; + if(((1<<err) & eg->code) || (eg->code == 1)){ + matching = eg; + goto match; + } + } + frame = frame->prev; + popdfnframe(); + } +match: + longjmp(matching->jmp, 1); } @@ -131,8 +131,19 @@ retry: if(!stmt->errorguard){ if(stmt->toks[0]->array->intdata[0] == 1) return eval(stmt->guard, toplevel); - }else - print("Not registering error guard for error codes: %S\n", ppdatum(stmt->toks[0])); + }else{ + ErrorGuard *eg = newerrorguard(stmt->toks[0]->array, stmt->guard); + if(setjmp(eg->jmp)){ + eg->active = 0; + + /* Replace the old dfnframe with the one in eg->frame */ + ThreadData *td = getthreaddata(); + DfnFrame *old = td->currentdfn; + td->currentdfn = eg->frame; + freedfnframe(old, 1); + return eval(eg->guard, toplevel); + } + } } } if(stmt->next && !stop) @@ -29,18 +29,16 @@ threadmain(int argc, char *argv[]) break; }ARGEND - int errorcode; + ErrorGuard *eg = newerrorguard(mkscalarint(0), nil); restart: - SETUPERROR(errorcode); - if(errorcode){ - /* remove aborted dfn frames */ + if(setjmp(eg->jmp)){ + ThreadData *td = getthreaddata(); + if(td->lasterrormsg) + print("%S: %S\n", errorstrs[td->lasterror], td->lasterrormsg); + else + print("%S\n", errorstrs[td->lasterror]); while(getcurrentdfn()) popdfnframe(); - - if(globalerror.msg) - print("%S: %S\n", errorstrs[errorcode], globalerror.msg); - else - print("%S\n", errorstrs[errorcode]); goto restart; } @@ -271,4 +271,23 @@ dupoperator(Operator o) threadexitsall("dupoperator"); } return p; +} + +void +freeerrorguards(ErrorGuard *e) +{ + ErrorGuard *next; + while(e != nil){ + next = e->next; + freeerrorguard(e); + e = next; + } +} + +void +freeerrorguard(ErrorGuard *e) +{ + if(e->active) + freedfnframe(e->frame, 1); /* otherwise the frame is on the dfn stack and will be free'd that way */ + free(e); }
\ No newline at end of file @@ -8,6 +8,8 @@ Symtab *globalsymtab; Symtab *newsymtab(void); +Symbol *dupsymbol(Symbol *); +Symtab *dupsymtab(Symtab *); void freesymtab(Symtab *); Datum *getalpha(void); @@ -65,6 +67,28 @@ newsymtab(void) return tab; } +Symbol * +dupsymbol(Symbol *s) +{ + Symbol *new = emalloc(sizeof(Symbol)); + memcpy(new, s, sizeof(Symbol)); + new->name = runestrdup(s->name); + if(new->value) + incdatumref(new->value); + return new; +} + +Symtab * +dupsymtab(Symtab *tab) +{ + Symtab *new = newsymtab(); + memcpy(new, tab, sizeof(Symtab)); + new->syms = emalloc(sizeof(Symbol*) * new->nsyms); + for(int i = 0; i < tab->nsyms; i++) + new->syms[i] = dupsymbol(tab->syms[i]); + return new; +} + void freesymtab(Symtab *tab) { @@ -130,22 +154,49 @@ pushdfnframe(Rune *code, DfnFrame *scope, Datum *lefto, Datum *righto, Array *le incarrayref(right); new->prev = td->currentdfn; new->chain = scope; + new->errorguards = nil; td->currentdfn = new; return new; } +DfnFrame * +dupdfnframe(DfnFrame *f) +{ + DfnFrame *new = emalloc(sizeof(DfnFrame)); + memcpy(new, f, sizeof(DfnFrame)); + new->code = runestrdup(f->code); + new->symtab = dupsymtab(f->symtab); + if(f->lefto) + incdatumref(f->lefto); + if(f->righto) + incdatumref(f->righto); + if(f->left) + incdatumref(f->left); + if(f->right) + incarrayref(f->right); + return new; +} + +void +freedfnframe(DfnFrame *f, int keeperrorguards) +{ + freesymtab(f->symtab); + freedatum(f->lefto); + freedatum(f->righto); + freedatum(f->left); + freearray(f->right); + if(!keeperrorguards) + freeerrorguards(f->errorguards); + free(f); +} + void popdfnframe(void) { ThreadData *td = getthreaddata(); if(td->currentdfn != nil){ DfnFrame *prev = td->currentdfn->prev; - freesymtab(td->currentdfn->symtab); - freedatum(td->currentdfn->lefto); - freedatum(td->currentdfn->righto); - freedatum(td->currentdfn->left); - freearray(td->currentdfn->right); - free(td->currentdfn); + freedfnframe(td->currentdfn, 0); td->currentdfn = prev; } } |