ref: fe152caa60e1086c3f5b973e83135d04bde81fe1
parent: 7434af4553ec451105b72cb221d214266bc034bb
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Fri Jul 26 15:10:16 EDT 2024
Work on error trapping/handling
--- a/dat.h
+++ b/dat.h
@@ -16,6 +16,8 @@
DataCallStack,
DataFunction,
DataLocalList,
+ DataErrorCtx,
+ DataErrorTrap,
DataMax,
};
@@ -140,8 +142,6 @@
Token *tokens;
uvlong offset;
- jmp_buf errbuf;
- char *err;
};
enum ArrayType
@@ -282,4 +282,30 @@
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
--- /dev/null
+++ b/error.c
@@ -1,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);
+ }
+}
+
--- a/eval.c
+++ b/eval.c
@@ -316,20 +316,12 @@
/* 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:
--- a/fns.h
+++ b/fns.h
@@ -8,6 +8,16 @@
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 @@
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 *primdyad(int, Array *, Array *);
/* scan.c */
-TokenList *scan(char *, char **);
+TokenList *scan(char *);
/* session.c */
void initsessions(void);
@@ -67,5 +77,5 @@
/* value.c */
char *printval(void *);
-void *parseval(Session *s, char *, char **);
+void *parseval(Session *s, char *);
--- a/fs.c
+++ b/fs.c
@@ -266,7 +266,6 @@
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 @@
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
--- a/memory.c
+++ b/memory.c
@@ -39,6 +39,8 @@
[DataCallStack] = {.size = sizeof(CallStack) },
[DataFunction] = {.size = sizeof(Function) },
[DataLocalList] = {.size = sizeof(LocalList) },
+ [DataErrorCtx] = {.size = sizeof(ErrorCtx) },
+ [DataErrorTrap] = {.size = sizeof(ErrorTrap) },
};
void *
--- a/mkfile
+++ b/mkfile
@@ -4,6 +4,7 @@
SCRIPTS=lpa
OFILES=\
array.$O\
+ error.$O\
eval.$O\
fs.$O\
main.$O\
--- a/parse.c
+++ b/parse.c
@@ -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 *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 @@
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 @@
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);
--- a/scan.c
+++ b/scan.c
@@ -19,7 +19,7 @@
}
TokenList *
-scan(char *buf, char **errp)
+scan(char *buf)
{
Rune r;
int n, id;
@@ -77,8 +77,7 @@
tok->name[size] = 0;
continue;
}
- *errp = "scan error";
- return nil;
+ error(ESyntax, "unexpected: '%C'", r);
next:
cp += n;
}
--- a/session.c
+++ b/session.c
@@ -42,24 +42,23 @@
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();
}
}
}
--- a/value.c
+++ b/value.c
@@ -28,29 +28,22 @@
}
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;
}