An exception trapping facility. Examples: acid: +try { 1 + {} ; } bad rhs type + acid: +try { 1 + 1 ; } ok acid: +try { error("foobar") ; } foobar acid: e = try { 1 + {} ; } acid: print(e) bad rhs type + Justification: The Acid testing framework I developed required error trapping. philip.dye@cs.cmu.edu Notes: Fri Apr 6 10:16:00 EDT 2007 rsc This is interesting but I'm not ready to make such a significant change to acid. Saving patch for future reference. Reference: /n/sources/patch/saved/acid.trap-exceptions Date: Wed Mar 14 21:43:51 CET 2007 Signed-off-by: philip.dye@cs.cmu.edu Reviewed-by: geoff --- /sys/src/cmd/acid/acid.h Tue Mar 13 00:00:26 2007 +++ /sys/src/cmd/acid/acid.h Tue Mar 13 00:00:25 2007 @@ -1,4 +1,5 @@ /* acid.h */ + enum { Eof = -1, @@ -53,6 +54,9 @@ Extern List* tracelist; Extern int initialising; Extern int quiet; +Extern void* tryio; +Extern char* tryres; +Extern int tryiop; extern void (*expop[])(Node*, Node*); #define expr(n, r) (r)->comt=0; (*expop[(n)->op])(n, r); @@ -217,6 +221,7 @@ void odot(Node*, Node*); void pcode(Node*, int); void pexpr(Node*); +void* getio(void); int popio(void); void pstr(String*); void pushfile(char*); @@ -234,6 +239,7 @@ char* system(void); void trlist(Map*, uvlong, uvlong, Symbol*); void unwind(void); +void unwindtry(Lsym** _hash); void userinit(void); void varreg(void); void varsym(void); @@ -295,4 +301,5 @@ OFMT, OEVAL, OWHAT, + OTRY, }; --- /sys/src/cmd/acid/dbg.y Tue Mar 13 00:00:29 2007 +++ /sys/src/cmd/acid/dbg.y Tue Mar 13 00:00:29 2007 @@ -40,7 +40,7 @@ %token Tfconst %token Tstring %token Tif Tdo Tthen Telse Twhile Tloop Thead Ttail Tappend Tfn Tret Tlocal -%token Tcomplex Twhat Tdelete Teval Tbuiltin +%token Tcomplex Twhat Tdelete Teval Tbuiltin Ttry %% @@ -259,6 +259,10 @@ | expr Tfmt { $$ = an(OFMT, $1, con($2)); + } + | Ttry '{' slist '}' + { + $$ = an(OTRY, $3, ZN); } ; --- /sys/src/cmd/acid/exec.c Tue Mar 13 00:00:33 2007 +++ /sys/src/cmd/acid/exec.c Tue Mar 13 00:00:32 2007 @@ -15,24 +15,30 @@ /* Unstack io channels */ if(iop != 0) { - for(i = 1; i < iop; i++) + for(i = tryiop+1; i < iop; i++) Bterm(io[i]); - bout = io[0]; - iop = 0; + bout = io[tryiop]; + iop = tryiop; } ret = 0; gotint = 0; Bflush(bout); - if(silent) + if (silent && tryio == nil) silent = 0; else { va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); - fprint(2, "%L: (error) %s\n", buf); + if (tryio) { + tryres = strdup(buf) ; + if(tryres == 0) + fatal("no memory"); + } + else + fprint(2, "%L: (error) %s\n", buf); } - while(popio()) + while ((getio() != tryio) && popio()) ; interactive = 1; longjmp(err, 1); @@ -57,6 +63,24 @@ } void +unwindtry(Lsym** _hash) +{ + int i; + Lsym *s; + Value *v; + + for(i = 0; i < Hashsize; i++) { + for(s = hash[i]; s && s != _hash[i] ; s = s->hash) { + while(s->v->pop) { + v = s->v->pop; + free(s->v); + s->v = v; + } + } + } +} + +void execute(Node *n) { Value *v; @@ -84,7 +108,7 @@ switch(n->op) { default: expr(n, &res); - if(ret || (res.type == TLIST && res.l == 0)) + if(ret || (res.type == TLIST && res.l == 0) || tryio) break; prnt->right = &res; expr(prnt, &xx); --- /sys/src/cmd/acid/expr.c Tue Mar 13 00:00:37 2007 +++ /sys/src/cmd/acid/expr.c Tue Mar 13 00:00:36 2007 @@ -201,21 +201,20 @@ void oappend(Node *n, Node *res) { - Value *v; Node r, l; - int empty; + int empty ; expr(n->left, &l); expr(n->right, &r); if(l.type != TLIST) error("must append to list"); - empty = (l.l == nil && (n->left->op == ONAME)); + empty = ( l.l == nil && ( n->left->op == ONAME ) ) ; append(res, &l, &r); - if(empty) { - v = n->left->sym->v; - v->type = res->type; - v->Store = res->Store; - v->comt = res->comt; + if ( empty ) { + Value * v = n->left->sym->v ; + v->type = res->type ; + v->Store = res->Store ; + v->comt = res->comt ; } } @@ -334,7 +333,18 @@ Node l, r; expr(n->left, &l); - expr(n->right, &r); + if ( n->right != ZN ) { + expr(n->right, &r) ; + } else { + switch ( l.type ) { + default: + expr(con(0),&r) ; + break; + case TSTRING: + case TLIST: + break; + } + } res->fmt = l.fmt; res->op = OCONST; res->type = TFLOAT; @@ -367,6 +377,10 @@ } break; case TSTRING: + if ( n->right == ZN ) { + *res = l ; + break ; + } if(r.type == TSTRING) { res->type = TSTRING; res->fmt = 's'; @@ -381,6 +395,10 @@ } error("bad rhs for +"); case TLIST: + if ( n->right == ZN ) { + *res = l ; + break ; + } res->type = TLIST; switch(r.type) { case TLIST: @@ -981,6 +999,53 @@ whatis(n->sym); } +void* tryio = nil; +char* tryres = nil; +int tryiop = 0; + +void +otry(Node *n, Node *res) +{ + int _interactive, _silent; + jmp_buf _err; + void* _tryio; + int _tryiop; + Lsym* _hash[Hashsize] ; + + memcpy(_err,err,sizeof(jmp_buf)); + _interactive = interactive; + interactive = 0; + _silent = silent; + silent = 1; + _tryio = tryio; + tryio = getio(); + _tryiop = tryiop; + tryiop = iop; + + /* save symbol table state */ + memcpy(_hash,hash,sizeof(_hash)) ; + + if ( setjmp(err) ) { + unwindtry(_hash) ; + res->string = strnode(tryres) ; + tryres = nil; + } else { + execute(n->left); + res->string = strnode("ok") ; + } + + iop = tryiop; + tryiop = _tryiop; + tryio = _tryio; + silent = _silent; + interactive = _interactive; + memcpy(err,_err,sizeof(jmp_buf)); + + res->fmt = 's'; + res->op = OCONST; + res->type = TSTRING; +} + void (*expop[])(Node*, Node*) = { [ONAME] oname, @@ -1032,4 +1097,5 @@ [OFMT] ofmt, [OEVAL] oeval, [OWHAT] owhat, + [OTRY] otry, }; --- /sys/src/cmd/acid/lex.c Tue Mar 13 00:00:42 2007 +++ /sys/src/cmd/acid/lex.c Tue Mar 13 00:00:41 2007 @@ -33,6 +33,7 @@ "delete", Tdelete, "whatis", Twhat, "eval", Teval, + "try", Ttry, "builtin", Tbuiltin, 0, 0 }; @@ -131,6 +132,13 @@ { Bflush(lexio->fin); Binit(lexio->fin, 0, OREAD); +} + + +void* +getio(void) +{ + return (void*) lexio ; } int --- /sys/doc/acid.ms Tue Mar 13 00:00:48 2007 +++ /sys/doc/acid.ms Tue Mar 13 00:00:46 2007 @@ -992,6 +992,58 @@ of the same name until the function returns. The body of a function is a list of statements enclosed by braces. .SH +Trapping Exceptions +.PP +.DS + result\f(CW = try \fPbody\f(CW ;\fP + + body: + \f(CW{\fP statement \f(CW}\fP +.DE +Use the +.CW try +statement to trap exceptions in Acid. The body of a +.CW try +statement is a list of statements enclosed by braces. +.PP +Within the +.I body +of a +.CW try +statement, if the code being executed encounters an interpreter error or +generates one by calling +.CW error(\fIstring\f(CW), +execution of the +.CW try +.I body +is aborted. The values of all local variables within the scope of the +.CW try +.I body +are lost. The values of local variables outside of the +.CW try +body are kept. Processes being debugged are not effected. +The +.CW try +statement returns +.I string +from the call to +.CW error(\fIstring\f(CW). +.PP +If no exception occurs, the +.CW try +statement returns +.CW ok. +.PP +.RE +For example: +.P1 +acid: result = try { 1 + 1 ; } +acid: print(result) +ok +acid: try { 1 + {} ; } +bad rhs type + +.P2 +.SH Code variables .PP Acid permits the delayed evaluation of a parameter to a function. The parameter