summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apl9.h26
-rw-r--r--error.c49
-rw-r--r--eval.c15
-rw-r--r--main.c16
-rw-r--r--memory.c19
-rw-r--r--symbol.c63
6 files changed, 156 insertions, 32 deletions
diff --git a/apl9.h b/apl9.h
index d115ea3..88135c6 100644
--- a/apl9.h
+++ b/apl9.h
@@ -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
diff --git a/error.c b/error.c
index 47837a9..2a59553 100644
--- a/error.c
+++ b/error.c
@@ -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);
}
diff --git a/eval.c b/eval.c
index 4131871..b629f90 100644
--- a/eval.c
+++ b/eval.c
@@ -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)
diff --git a/main.c b/main.c
index 9acd568..60beed2 100644
--- a/main.c
+++ b/main.c
@@ -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;
}
diff --git a/memory.c b/memory.c
index 533e159..806d5df 100644
--- a/memory.c
+++ b/memory.c
@@ -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
diff --git a/symbol.c b/symbol.c
index 6e9aa4a..8e51ba9 100644
--- a/symbol.c
+++ b/symbol.c
@@ -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;
}
}