shithub: lpa

Download patch

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;
 }