~pmikkelsen/lpa

fe152caa60e1086c3f5b973e83135d04bde81fe1 — Peter Mikkelsen 2 months ago 7434af4
Work on error trapping/handling
11 files changed, 177 insertions(+), 75 deletions(-)

M dat.h
A error.c
M eval.c
M fns.h
M fs.c
M memory.c
M mkfile
M parse.c
M scan.c
M session.c
M value.c
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;
}