M dat.h => dat.h +28 -2
@@ 16,6 16,8 @@ enum DataTag
DataCallStack,
DataFunction,
DataLocalList,
+ DataErrorCtx,
+ DataErrorTrap,
DataMax,
};
@@ 140,8 142,6 @@ struct TokenList
Token *tokens;
uvlong offset;
- jmp_buf errbuf;
- char *err;
};
enum ArrayType
@@ 282,4 282,30 @@ struct Function
uvlong symbol;
ByteCode *code;
int prim;
+};
+
+enum ErrorNum
+{
+ EAny, /* 0 = catch any error */
+ ESyntax,
+ EValue,
+
+ ErrorMax,
+};
+
+typedef struct ErrorTrap ErrorTrap;
+struct ErrorTrap
+{
+ jmp_buf env;
+ int nums[ErrorMax];
+};
+
+typedef struct ErrorCtx ErrorCtx;
+struct ErrorCtx
+{
+ char msg[4096];
+ int num;
+
+ uvlong count;
+ ErrorTrap **traps;
};=
\ No newline at end of file
A error.c => error.c +92 -0
@@ 0,0 1,92 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+
+#include "dat.h"
+#include "fns.h"
+
+static ErrorCtx *
+errorctx(void)
+{
+ /* Return a pointer to the current error context.
+ * TODO: think about what needs its own context
+ */
+ static ErrorCtx *c = nil;
+
+ if(c == nil)
+ c = alloc(DataErrorCtx);
+ return c;
+}
+
+ErrorTrap *
+setuptrap(int n, ...)
+{
+ ErrorCtx *c = errorctx();
+ c->count++;
+ c->traps = allocextra(c, sizeof(*c->traps) * c->count);
+
+ ErrorTrap *t = alloc(DataErrorTrap);
+ va_list nums;
+ va_start(nums, n);
+ for(; n > 0; n--){
+ int x = va_arg(nums, int);
+ assert(x >= EAny && x <= ErrorMax);
+ if(x == EAny){
+ for(int i = 0; i < ErrorMax; i++)
+ t->nums[i] = 1;
+ }else
+ t->nums[x] = 1;
+ }
+ va_end(nums);
+
+ c->traps[c->count-1] = t;
+ return t;
+}
+
+void
+endtrap(void)
+{
+ ErrorCtx *c = errorctx();
+ c->count--;
+}
+
+char *
+errmsg(void)
+{
+ ErrorCtx *c = errorctx();
+ return c->msg;
+}
+
+char *
+errdesc(void)
+{
+ ErrorCtx *c = errorctx();
+ switch(c->num){
+ case ESyntax: return "SYNTAX ERROR";
+ case EValue: return "VALUE ERROR";
+ default: return "ERROR ???";
+ }
+}
+
+_Noreturn void
+error(int num, char *fmt, ...)
+{
+ ErrorCtx *c;
+ ErrorTrap *t;
+ va_list args;
+
+ va_start(args, fmt);
+
+ c = errorctx();
+ c->num = num;
+ vsnprint(c->msg, sizeof(c->msg), fmt, args);
+
+ while(1){
+ assert(c->count > 0);
+ c->count--;
+ t = c->traps[c->count];
+ if(t->nums[num])
+ longjmp(t->env, 1);
+ }
+}
+
M eval.c => eval.c +5 -13
@@ 316,20 316,12 @@ evalbc(Session *s, Module *m, ByteCode *c)
/* parse at runtime and emit code */
o += getuvlong(c->instrs+o, &v);
{
- char *err;
TokenList *t = (TokenList *)v;
- Ast *a = parse(t, m->symtab, &err);
- if(!a){
- appendlog(s, "RUNTIME PARSE: ");
- appendlog(s, err);
- appendlog(s, "\n");
- return nil;
- }else{
- newcode = alloc(DataByteCode);
- codegensub(s, m, newcode, a);
- emitbyte(newcode, IReturn);
- pushcall(calls, newcode, &c, &o);
- }
+ Ast *a = parse(t, m->symtab);
+ newcode = alloc(DataByteCode);
+ codegensub(s, m, newcode, a);
+ emitbyte(newcode, IReturn);
+ pushcall(calls, newcode, &c, &o);
}
break;
case IDone:
M fns.h => fns.h +13 -3
@@ 8,6 8,16 @@ Array *simplifyarray(Array *);
char *printarray(Array *);
char *printfunc(Function *);
+/* error.c */
+#define trap(num) (setjmp(setuptrap(1, num)->env))
+#define trapmulti(n, nums) (setjmp(setuptrap(n, nums)->env))
+
+ErrorTrap *setuptrap(int n, ...);
+void endtrap(void);
+char *errmsg(void);
+char *errdesc(void);
+_Noreturn void error(int, char *, ...);
+
/* eval.c */
void *eval(Session *s, Ast *);
@@ 26,7 36,7 @@ Module *addmodule(Session *, char *);
Enumeration *enummodules(Session *s);
/* parse.c */
-Ast *parse(TokenList *, Symtab *, char **);
+Ast *parse(TokenList *, Symtab *);
/* prim.c */
char *primsymb(int);
@@ 37,7 47,7 @@ Array *primmonad(int, Array *);
Array *primdyad(int, Array *, Array *);
/* scan.c */
-TokenList *scan(char *, char **);
+TokenList *scan(char *);
/* session.c */
void initsessions(void);
@@ 67,5 77,5 @@ int getuvlong(u8int *, uvlong *);
/* value.c */
char *printval(void *);
-void *parseval(Session *s, char *, char **);
+void *parseval(Session *s, char *);
M fs.c => fs.c +9 -7
@@ 266,7 266,6 @@ symbolrw(Req *r)
Aux *aux = r->fid->aux;
Session *session = aux->session;
Symbol *symb = aux->symbol;
- char *err = nil;
if(r->ifcall.type == Tread){
/* Pretty print the value and readstr() it. */
@@ 278,18 277,21 @@ symbolrw(Req *r)
aux->cachestr = nil;
}
}else{ /* Twrite */
+ if(trap(EAny))
+ return errmsg();
+
char *buf = requeststr(r);
- void *v = parseval(session, buf, &err);
+ void *v = parseval(session, buf);
free(buf);
- if(v && getalloctag(v) == DataFunction){
+ if(getalloctag(v) == DataFunction){
Function *f = v;
if(strcmp(symb->name, f->ast->funcname->name) != 0)
- err = "Function name must match symbol name";
+ error(ESyntax, "Function name must match symbol name");
}
- if(!err)
- symset(symb->table, symb->id, v);
+ symset(symb->table, symb->id, v);
+ endtrap();
}
- return err;
+ return nil;
}
static void
M memory.c => memory.c +2 -0
@@ 39,6 39,8 @@ DataSpec dataspecs[DataMax] = {
[DataCallStack] = {.size = sizeof(CallStack) },
[DataFunction] = {.size = sizeof(Function) },
[DataLocalList] = {.size = sizeof(LocalList) },
+ [DataErrorCtx] = {.size = sizeof(ErrorCtx) },
+ [DataErrorTrap] = {.size = sizeof(ErrorTrap) },
};
void *
M mkfile => mkfile +1 -0
@@ 4,6 4,7 @@ TARG=lpafs
SCRIPTS=lpa
OFILES=\
array.$O\
+ error.$O\
eval.$O\
fs.$O\
main.$O\
M parse.c => parse.c +9 -23
@@ 5,7 5,6 @@
#include "dat.h"
#include "fns.h"
-static void _Noreturn error(TokenList *, char *);
static int peek(TokenList *);
static int peekclass(TokenList *);
static void match(TokenList *, int);
@@ 28,37 27,24 @@ static Ast *parsefunc(TokenList *);
static Ast *parseconst(TokenList *);
Ast *
-parse(TokenList *tokens, Symtab *symtab, char **errp)
+parse(TokenList *tokens, Symtab *symtab)
{
Ast *ast;
tokens->offset = 0;
- tokens->err = nil;
- if(setjmp(tokens->errbuf)){
- *errp = tokens->err;
- return nil;
- }else{
- if(symtab)
- ast = parseexpr(tokens, symtab, nil);
- else
- ast = parseprog(tokens);
- match(tokens, TokEnd);
- }
+ if(symtab)
+ ast = parseexpr(tokens, symtab, nil);
+ else
+ ast = parseprog(tokens);
+ match(tokens, TokEnd);
return ast;
}
-static void _Noreturn
-error(TokenList *tokens, char *msg)
-{
- tokens->err = msg;
- longjmp(tokens->errbuf, 1);
-}
-
static int
peek(TokenList *tokens)
{
if(tokens->offset >= tokens->count)
- error(tokens, "unexpected end of token stream");
+ error(ESyntax, "unexpected end of token stream");
return tokens->tokens[tokens->offset].tag;
}
@@ 74,7 60,7 @@ static void
match(TokenList *tokens, int tag)
{
if(peek(tokens) != tag)
- error(tokens, "Unexpected token (match failed)");
+ error(ESyntax, "Unexpected token (match failed)");
tokens->offset++;
}
@@ 274,7 260,7 @@ parseexpr(TokenList *t, Symtab *symtab, Ast *func)
if(class == 0){ /* We don't know how to parse it until runtime */
print("nameclass 0 name: %s funcname: %s\n", name, func ? func->funcname->name : "<no func>");
if(symtab)
- error(t, "could not resolve nameclasses");
+ error(EValue, "%s is undefined", name);
uvlong count = end-start;
Ast *later = alloc(DataAst);
M scan.c => scan.c +2 -3
@@ 19,7 19,7 @@ newtok(TokenList *tokens, int tag)
}
TokenList *
-scan(char *buf, char **errp)
+scan(char *buf)
{
Rune r;
int n, id;
@@ 77,8 77,7 @@ scan(char *buf, char **errp)
tok->name[size] = 0;
continue;
}
- *errp = "scan error";
- return nil;
+ error(ESyntax, "unexpected: '%C'", r);
next:
cp += n;
}
M session.c => session.c +9 -10
@@ 42,24 42,23 @@ sessionproc(void *arg)
if(strlen(buf) > 0 && buf[0] == ')')
systemcmd(s, buf+1, 0);
- else{
- char *err = nil;
- TokenList *tokens = scan(buf, &err);
- if(err){
-error:
- appendlog(s, err);
+ else{
+ if(trap(EAny)){
+ appendlog(s, errdesc());
+ appendlog(s, ": ");
+ appendlog(s, errmsg());
appendlog(s, "\n");
continue;
}
-
- Ast *ast = parse(tokens, 0, &err);
- if(err)
- goto error;
+ TokenList *tokens = scan(buf);
+ Ast *ast = parse(tokens, 0);
debugast(ast, 0);
void *val = eval(s, ast);
if(val)
appendlog(s, printval(val));
+
+ endtrap();
}
}
}
M value.c => value.c +7 -14
@@ 28,29 28,22 @@ printval(void *v)
}
void *
-parseval(Session *s, char *buf, char **errp)
+parseval(Session *s, char *buf)
{
Ast *ast;
- void *val = nil;
+ void *val;
- TokenList *tokens = scan(buf, errp);
- if(tokens == nil)
- goto end;
- ast = parse(tokens, nil, errp);
- if(ast == nil)
- goto end;
+ TokenList *tokens = scan(buf);
+ ast = parse(tokens, nil);
- if(!(ast->tag == AstProg && ast->childcount == 1)){
- *errp = "Expected single value or function definition";
- goto end;
- }
+ if(!(ast->tag == AstProg && ast->childcount == 1))
+ error(ESyntax, "Expected single value or function definition");
ast = ast->children[0];
if(checkexpr(ast))
val = eval(s, ast);
else
- *errp = "Expected value or function definition";
-end:
+ error(ESyntax, "Expected value or function definition");
return val;
}