Ilya Zakharevich on Wed, 12 Mar 2003 10:10:21 -0800 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: trap()ing user errors |
On Wed, Mar 12, 2003 at 04:35:28PM +0100, Bill Allombert wrote: > Hello PARI-Dev, > > It seems that currently trap() cannot catch user error raised with > error(). It could be useful to add that. Also it would not > cost much to support all the errors reported by PARI or at least > a 'none of the above' error code. > > Beside I do not like the syntax/semantic of trap: > Trap currently has two very different use: > 1) Install an error handler. > 2) Execute an instruction in error recovery mode. > > I would prefer that the second usage be covered by a > iferr(SEQ,REC{,error}) > so that trap() will not need a third parameter anymore. I think I sent a patch for this during the last round (at least in C mode). But all this is cosmetic problems. Here comes the *real* problem with the current modus operandi: one can't rethrow(). Given a possibility of rethrow(), one could forget about the current (IMO, extremely lousy) scheme, and always trap all errors, then rethrow() if needed. Below are the problems with implementing rethrow(): One could easily modify the pari_err() logic to save its parameters in a safe place (or better a stack of safe places), and then support err(rethrow) [which would pop this stack of safe places]. However, there are several places where the error string is assembled on the stack. [Examples below.] Thus actually err() will need to *copy* all the char* parameters. This would significantly decrease the performance, thus may make the whole err/trap scheme infeasible. > As a general note, I think it better if functions return errors > as part of their output whenever is convenient, instead of raising > an error. Having a possibility of non-local return is very important. > This ask for more work of the caller, but this avoid > relying on trap when error catching is needed. Given the current scheme (when reliance on trap() is very shaky), one *should* rely on non-local returns if the algorithm asks for it. > For example, sqrtn(Mod(a,p),3) raise an error id a is not a cube mod p. > Unfortunately testing if it is take almost the same time that doing > the computation so it is a waste to have to write > if(Mod(a,p)^((p-1)/3)!=1,next); sqrtn(Mod(a,p),3) > if we want to avoid using trap. Design a better trap(). Then do not hesitate to use it. Hope this helps, Ilya P.S. Here is my list of suspicious err()s which have arguments on stack. buch2.c: char str[64]; sprintf(str,"buchall (%s)",precpb); err(warnprec,str,PRECREG); gp.c anal.c: a lot [These found by pfind -alllines src /\.c$/ "=~ /\berr\s*\(\s*\w+\s*,\s*[^\"\s]/" + manual filtering.] Now #!/bin/sh pfind.pl -alllines src '/\.c$/' '=~ /\berr\s*\(\s*\w+\s*,\s*\"[^\"]*\"\s*,\s*[^\"\s]/' > o grep "%s" o >oo-s grep -v "%s" o | grep -v "\<oper[if]\|warnprec\>" | grep -v '%.*" *, *[a-zA-Z][a-zA-Z.]* *)' | grep -v '%.*%.*" *, *[a-zA-Z][a-zA-Z.]* *, *[a-zA-Z][a-zA-Z.]* *)' | grep -v '(member *, *".*" *, *mark\.member *, *mark\.start *)' | grep -v '(talker2 *, *".*" *, *mark\.[a-z]* *, *mark\.[a-z]* *)' >oo-no-s + manual filtering Finds: src/gp/gp.c : if (*p) err(talker2,"I was expecting an integer here", s, s); src/gp/gp.c : if (n < 0) err(talker2,"integer too large in get_int",s,s); src/gp/gp.c : if (*p == '-') err(talker2,"arguments must be positive integers",s,s); src/gp/gp.c : err(talker2,"default: inexistent format",v,v); src/gp/gp.c : if (*s != ']') err(talker2,"expected character: ']'",s, *st); src/gp/gp.c : err(talker2,"no such section in help: ?",s,s); src/language/anal.c : if (*s != ',') err(talker2, "missing comma", old, code); src/language/anal.c : case 'v': err(talker2, "this code has to come first", s-1, code); src/language/anal.c : default: err(talker2, "unknown parser code", s-1, code); src/language/anal.c : if (*s) err(talker2,"not a valid identifier", s, name); src/language/anal.c : if (!GP_DATA) err(talker2,"history not available", old, mark.start); src/language/anal.c : err(talker2,"not a suitable VECSMALL component",old,mark.start); src/language/anal.c : err(talker2,"global variable: ",old , mark.start); src/language/anal.c : default: err(talker2,"symbol already in use",ch1,mark.start); src/language/anal.c : if (nb > 8) err(talker2,"exponent too large",old,mark.start); src/language/anal.c : if (strict) err(talker2,"unused characters", analyseur, c); src/language/anal.c : err(talker2,"; or ] expected",old,mark.start); src/language/anal.c : err(talker2,"global variable not allowed", old,mark.start); src/language/es.c : if (fclose(f->file)) err(warnfile, "close", f->name); src/language/es.c : if (fclose(f->file)) err(warnfile, "close", f->name); src/language/es.c : if (unlink(f->name)) err(warnfile, "delete", f->name); src/language/es.c : if (pclose(f->file) < 0) err(warnfile, "close pipe", f->name); src/language/es.c : if (!p) err(talker2,"unknown user ",s,s-1); src/language/es.c : err(openfiler,"input",name0); src/language/es.c : if (!f) err(openfiler,"output",name); src/language/es.c : if (!f) err(openfiler,"binary output",name); src/language/es.c : err(talker2, "I can't see into the future", old, entry); src/language/es.c : err(talker2, "I can't remember before the big bang", old, entry); src/basemath/base1.c : err(talker,"missing units in %s", f); src/basemath/base1.c : if (typ(x[k])!=t_INT) err(talker,"polynomial not in Z[X] in %s",s); src/basemath/base2.c : err(talker,"not a pseudo-matrix in %s", s); src/basemath/buch2.c : err(warner,"%s, not given",s); src/basemath/buch3.c : if (!hnfdivide(H, D)) err(talker,"incorrect subgroup in %s", s); src/gp/gp.c : { err(talker,"[secure mode]: can't modify '%s' default (to %s)",d,v); } src/gp/gp.c : err(warner,"broken prettyprinter: '%s'",v); src/gp/gp.c : err(talker,"unknown default: %s",s); src/gp/gp.c : if ((flag & h_RL) == 0) err(talker, "%s: %s", s1, s2); src/gp/gp.c : err(talker,"Texmacs_stdin command %s not implemented", c.cmd); src/gp/gp.c : err(talker, "[secure mode]: system commands not allowed\nTried to run '%s'",s); src/gp/highlvl.c : if (lib) err(talker,"couldn't open dynamic library '%s'",lib); src/gp/highlvl.c : if (lib) err(talker,"can't find symbol '%s' in library '%s'",name,lib); src/gp/highlvl.c : err(talker,"can't find symbol '%s' in dynamic symbol table of process",name); src/gp/highlvl.c : if (lib) err(talker,"couldn't open dynamic library '%s'",lib); src/gp/highlvl.c : if (lib) err(talker,"can't find symbol '%s' in library '%s'",name,lib); src/gp/highlvl.c : err(talker,"can't find symbol '%s' in dynamic symbol table of process",name); src/gp/highlvl.c : if (*s) err(talker,"Unknown type: %s",s); src/gp/highlvl.c : err(talker,"Unknown type: t_%s",st); src/language/anal.c : err(talker,"[install] identifier '%s' already in use", name); src/language/anal.c : err(warner, "[install] updating '%s' prototype; module not reloaded", name); src/language/anal.c : if (doerr) err(talker,"identifier already in use: %s", s); src/language/anal.c : err(talker, "%s already exists with incompatible valence", s); src/language/anal.c : err(warner, "unused characters: %s", s); src/language/anal.c : err(warner,"using obsolete function %s",ep->name); src/language/es.c : err(warner,"broken prettyprinter: '%s'",pp->cmd); src/language/es.c : if (!f) err(talker, "could not open requested file %s", s); src/language/es.c : if (fd == -1) err(talker,"tempfile %s already exists",s); src/language/es.c : if (unlink(s)) err(warner, "I/O: can\'t remove file %s", s); src/language/es.c : if (!file) err(talker,"[pipe:] '%s' failed",cmd); src/language/es.c : err(warner,"undefined environment variable: %s",env); src/language/es.c : err(warner,"skipping directory %s",name); src/language/es.c : err(talker,"%s is a GP binary file. Please use writebin", name); src/language/es.c : err(talker, "%s is not a GP binary file",name); src/language/es.c : err(talker, "unexpected endianness in %s",name); src/language/es.c : err(talker, "%s written by an incompatible version of GP",name); src/language/es.c : err(warner,"%s is set (%s), but is not writeable", s,t); src/language/es.c : err(warner,"%s is set (%s), but is not a directory", s,t); src/language/es.c : err(talker,"couldn't find a suitable name for a tempfile (%s)",s); src/modules/mpqs.c : #define bummer(fn) err(talker, "error whilst writing to file %s", fn) src/modules/mpqs.c : err(talker, "error whilst appending to file %s", f->name); src/modules/mpqs.c : err(warner, "error whilst flushing file %s", f->name); src/modules/mpqs.c : err(talker, "can\'t rename file %s to %s", TMP_str, REL_str);