shithub: femtolisp

Download patch

ref: 212e0968cc531399fb96edef89f34c4cac29078b
parent: 944262d59abe6be8acd552d53e50bcc77ca89896
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Nov 10 22:46:14 EST 2024

add io-filename, produce parsing errors with file, line and column information

--- a/ios.c
+++ b/ios.c
@@ -3,6 +3,8 @@
 
 #define MOST_OF(x) ((x) - ((x)>>4))
 
+static char emptystr[] = "";
+
 ios_t *ios_stdin = nil;
 ios_t *ios_stdout = nil;
 ios_t *ios_stderr = nil;
@@ -534,6 +536,10 @@
 		LLT_FREE(s->buf);
 	s->buf = nil;
 	s->size = s->maxsize = s->bpos = 0;
+	if(s->filename != emptystr){
+		LLT_FREE(s->filename);
+		s->filename = emptystr;
+	}
 }
 
 static void
@@ -733,6 +739,7 @@
 		goto open_file_err;
 	if(!wr)
 		s->readonly = 1;
+	s->filename = LLT_STRDUP(fname);
 	return s;
 open_file_err:
 	s->fd = -1;
@@ -744,6 +751,7 @@
 {
 	_ios_init(s);
 	s->bm = bm_mem;
+	s->filename = emptystr;
 	_buf_realloc(s, initsize);
 	return s;
 }
@@ -788,14 +796,17 @@
 {
 	ios_stdin = LLT_ALLOC(sizeof(ios_t));
 	ios_fd(ios_stdin, STDIN_FILENO, 0, 0);
+	ios_stdin->filename = LLT_STRDUP("<stdin>");
 
 	ios_stdout = LLT_ALLOC(sizeof(ios_t));
 	ios_fd(ios_stdout, STDOUT_FILENO, 0, 0);
 	ios_stdout->bm = bm_line;
+	ios_stdout->filename = LLT_STRDUP("<stdout>");
 
 	ios_stderr = LLT_ALLOC(sizeof(ios_t));
 	ios_fd(ios_stderr, STDERR_FILENO, 0, 0);
 	ios_stderr->bm = bm_none;
+	ios_stderr->filename = LLT_STRDUP("<stderr>");
 }
 
 /* higher level interface */
--- a/ios.h
+++ b/ios.h
@@ -53,6 +53,8 @@
 	// request durable writes (fsync)
 	// uint8_t durable:1;
 
+	char *filename;
+
 	// todo: mutex
 	uint8_t local[IOS_INLSIZE];
 }ios_t;
--- a/iostream.c
+++ b/iostream.c
@@ -370,6 +370,12 @@
 	return size_wrap(ios_copyall(dest, src));
 }
 
+BUILTIN("io-filename", io_filename)
+{
+	argcount(nargs, 1);
+	return cvalue_static_cstring(toiostream(args[0])->filename);
+}
+
 BUILTIN("io-line", io_line)
 {
 	argcount(nargs, 1);
--- a/plan9/platform.h
+++ b/plan9/platform.h
@@ -8,6 +8,7 @@
 #define LLT_ALLOC(n) malloc(n)
 #define LLT_REALLOC(p, n) realloc((p), (n))
 #define LLT_FREE(x) free(x)
+#define LLT_STRDUP(s) strdup(s)
 
 #if defined(__amd64__) || \
     defined(__arm64__) || \
--- a/posix/platform.h
+++ b/posix/platform.h
@@ -30,6 +30,7 @@
 #define LLT_ALLOC(n) malloc(n)
 #define LLT_REALLOC(p, n) realloc((p), (n))
 #define LLT_FREE(x) free(x)
+#define LLT_STRDUP(s) strdup(s)
 
 #ifndef __SIZEOF_POINTER__
 #error pointer size unknown
--- a/read.c
+++ b/read.c
@@ -199,12 +199,31 @@
 	ctx->toktype = TOK_NONE;
 }
 
+static _Noreturn void
+parse_error(const char *format, ...)
+{
+	char msgbuf[512];
+	va_list args;
+	int n;
+
+	n = snprintf(msgbuf, sizeof(msgbuf), "%s:%"PRIu64":%"PRIu64": ",
+		RS->filename, (uint64_t)RS->lineno, (uint64_t)RS->colno);
+	if(n >= (int)sizeof(msgbuf))
+		n = 0;
+	va_start(args, format);
+	vsnprintf(msgbuf+n, sizeof(msgbuf)-n, format, args);
+	value_t msg = string_from_cstr(msgbuf);
+	va_end(args);
+
+	fl_raise(fl_list2(FL(ParseError), msg));
+}
+
 static void
 accumchar(Rctx *ctx, char c, int *pi)
 {
 	ctx->buf[(*pi)++] = c;
 	if(*pi >= (int)(sizeof(ctx->buf)-1))
-		lerrorf(FL(ParseError), "token too long");
+		parse_error("token too long");
 }
 
 // return: 1 if escaped (forced to be symbol)
@@ -287,7 +306,7 @@
 	else if(c == '#'){
 		ch = ios_getc(RS); c = (char)ch;
 		if(ch == IOS_EOF)
-			lerrorf(FL(ParseError), "invalid read macro");
+			parse_error("invalid read macro");
 		if(c == '.')
 			ctx->toktype = TOK_SHARPDOT;
 		else if(c == '\'')
@@ -295,12 +314,12 @@
 		else if(c == '\\'){
 			Rune cval;
 			if(ios_getutf8(RS, &cval) == IOS_EOF)
-				lerrorf(FL(ParseError), "end of input in character constant");
+				parse_error("end of input in character constant");
 			if(cval == 'u' || cval == 'U' || cval == 'x'){
 				read_token(ctx, 'u', 0);
 				if(ctx->buf[1] != '\0'){ // not a solitary 'u','U','x'
 					if(!read_numtok(&ctx->buf[1], &ctx->tokval, 16))
-						lerrorf(FL(ParseError), "invalid hex character constant");
+						parse_error("invalid hex character constant");
 					cval = numval(ctx->tokval);
 				}
 			}else if(cval >= 'a' && cval <= 'z'){
@@ -320,7 +339,7 @@
 				else if(ctx->tokval == FL(spacesym))     cval = 0x20;
 				else if(ctx->tokval == FL(deletesym))    cval = 0x7F;
 				else
-					lerrorf(FL(ParseError), "unknown character #\\%s", ctx->buf);
+					parse_error("unknown character #\\%s", ctx->buf);
 			}
 			ctx->toktype = TOK_NUM;
 			ctx->tokval = mk_rune(cval);
@@ -327,7 +346,7 @@
 		}else if(c == '('){
 			ctx->toktype = TOK_SHARPOPEN;
 		}else if(c == '<'){
-			lerrorf(FL(ParseError), "unreadable object");
+			parse_error("unreadable object");
 		}else if(isdigit(c)){
 			read_token(ctx, c, 1);
 			c = (char)ios_getc(RS);
@@ -336,10 +355,10 @@
 			else if(c == '=')
 				ctx->toktype = TOK_LABEL;
 			else
-				lerrorf(FL(ParseError), "invalid label");
+				parse_error("invalid label");
 			x = strtoll(ctx->buf, &end, 10);
 			if(*end != '\0')
-				lerrorf(FL(ParseError), "invalid label");
+				parse_error("invalid label");
 			ctx->tokval = fixnum(x);
 		}else if(c == '!'){
 			// #! single line comment for shbang script support
@@ -354,7 +373,7 @@
 				ch = ios_getc(RS);
 			hashpipe_gotc:
 				if(ch == IOS_EOF)
-					lerrorf(FL(ParseError), "eof within comment");
+					parse_error("eof within comment");
 				if((char)ch == '|'){
 					ch = ios_getc(RS);
 					if((char)ch == '#'){
@@ -387,7 +406,7 @@
 			read_token(ctx, (char)ch, 0);
 			x = strtol(ctx->buf, &end, 10);
 			if(*end != '\0' || ctx->buf[0] == '\0')
-				lerrorf(FL(ParseError), "invalid gensym label");
+				parse_error("invalid gensym label");
 			ctx->toktype = TOK_GENSYM;
 			ctx->tokval = fixnum(x);
 		}else if(symchar(c)){
@@ -398,7 +417,7 @@
 			    (c == 'd' && (base = 10)) ||
 			    (c == 'x' && (base = 16))) && (isdigit_base(ctx->buf[1], base) || ctx->buf[1] == '-')){
 				if(!read_numtok(&ctx->buf[1], &ctx->tokval, base))
-					lerrorf(FL(ParseError), "invalid base %d constant", base);
+					parse_error("invalid base %d constant", base);
 				return (ctx->toktype = TOK_NUM);
 			}
 
@@ -405,7 +424,7 @@
 			ctx->toktype = TOK_SHARPSYM;
 			ctx->tokval = symbol(ctx->buf);
 		}else{
-			lerrorf(FL(ParseError), "unknown read macro");
+			parse_error("unknown read macro");
 		}
 	}else if(c == ','){
 		ctx->toktype = TOK_COMMA;
@@ -465,7 +484,7 @@
 		ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
 	while(peek(ctx) != closer){
 		if(ios_eof(RS))
-			lerrorf(FL(ParseError), "unexpected end of input");
+			parse_error("unexpected end of input");
 		if(i >= vector_size(v)){
 			v = FL(stack)[FL(sp)-1] = vector_grow(v);
 			if(label != UNBOUND)
@@ -500,7 +519,7 @@
 			temp = LLT_REALLOC(buf, sz);
 			if(temp == nil){
 				LLT_FREE(buf);
-				lerrorf(FL(ParseError), "out of memory reading string");
+				parse_error("out of memory reading string");
 			}
 			buf = temp;
 		}
@@ -507,7 +526,7 @@
 		c = ios_getc(RS);
 		if(c == IOS_EOF){
 			LLT_FREE(buf);
-			lerrorf(FL(ParseError), "unexpected end of input in string");
+			parse_error("unexpected end of input in string");
 		}
 		if(c == '"')
 			break;
@@ -515,7 +534,7 @@
 			c = ios_getc(RS);
 			if(c == IOS_EOF){
 				LLT_FREE(buf);
-				lerrorf(FL(ParseError), "end of input in escape sequence");
+				parse_error("end of input in escape sequence");
 			}
 			j = 0;
 			if(octal_digit(c)){
@@ -543,7 +562,7 @@
 					r = strtol(eseq, nil, 16);
 				if(!j || r > Runemax){
 					LLT_FREE(buf);
-					lerrorf(FL(ParseError), "invalid escape sequence");
+					parse_error("invalid escape sequence");
 				}
 				if(ndig == 2)
 					buf[i++] = (char)r;
@@ -555,7 +574,7 @@
 				char esc = read_escape_control_char((char)c);
 				if(esc == (char)c && !strchr("\\'\"`", esc)){
 					LLT_FREE(buf);
-					lerrorf(FL(ParseError), "invalid escape sequence: \\%c", (char)c);
+					parse_error("invalid escape sequence: \\%c", (char)c);
 				}
 				buf[i++] = esc;
 			}
@@ -583,7 +602,7 @@
 	t = peek(ctx);
 	while(t != closer){
 		if(ios_eof(RS))
-			lerrorf(FL(ParseError), "unexpected end of input");
+			parse_error("unexpected end of input");
 		c = mk_cons(); car_(c) = cdr_(c) = FL(Nil);
 		if(iscons(*pc))
 			cdr_(*pc) = c;
@@ -603,11 +622,10 @@
 			cdr_(*pc) = c;
 			t = peek(ctx);
 			if(ios_eof(RS))
-				lerrorf(FL(ParseError), "unexpected end of input");
+				parse_error("unexpected end of input");
 			if(t != closer){
 				take(ctx);
-				lerrorf(
-					FL(ParseError),
+				parse_error(
 					"expected '%c'",
 					closer == TOK_CLOSEB ? ']' : (closer == TOK_CLOSEC ? '}' : ')')
 				);
@@ -632,13 +650,13 @@
 	take(ctx);
 	switch(t){
 	case TOK_CLOSE:
-		lerrorf(FL(ParseError), "unexpected ')'");
+		parse_error("unexpected ')'");
 	case TOK_CLOSEB:
-		lerrorf(FL(ParseError), "unexpected ']'");
+		parse_error("unexpected ']'");
 	case TOK_CLOSEC:
-		lerrorf(FL(ParseError), "unexpected '}'");
+		parse_error("unexpected '}'");
 	case TOK_DOT:
-		lerrorf(FL(ParseError), "unexpected '.'");
+		parse_error("unexpected '.'");
 	case TOK_SYM:
 	case TOK_NUM:
 		return ctx->tokval;
@@ -688,7 +706,7 @@
 		c = nextchar();
 		if(c != '('){
 			take(ctx);
-			lerrorf(FL(ParseError), "expected argument list for %s", symbol_name(ctx->tokval));
+			parse_error("expected argument list for %s", symbol_name(ctx->tokval));
 		}
 		PUSH(FL(Nil));
 		read_list(ctx, &FL(stack)[FL(sp)-1], UNBOUND, TOK_CLOSE);
@@ -721,7 +739,7 @@
 	case TOK_LABEL:
 		// create backreference label
 		if(ptrhash_has(&FL(readstate)->backrefs, (void*)ctx->tokval))
-			lerrorf(FL(ParseError), "label %"PRIdPTR" redefined", numval(ctx->tokval));
+			parse_error("label %"PRIdPTR" redefined", numval(ctx->tokval));
 		oldtokval = ctx->tokval;
 		v = do_read_sexpr(ctx, ctx->tokval);
 		ptrhash_put(&FL(readstate)->backrefs, (void*)oldtokval, (void*)v);
@@ -730,7 +748,7 @@
 		// look up backreference
 		v = (value_t)ptrhash_get(&FL(readstate)->backrefs, (void*)ctx->tokval);
 		if(v == (value_t)HT_NOTFOUND)
-			lerrorf(FL(ParseError), "undefined label %"PRIdPTR, numval(ctx->tokval));
+			parse_error("undefined label %"PRIdPTR, numval(ctx->tokval));
 		return v;
 	case TOK_GENSYM:
 		pv = (value_t*)ptrhash_bp(&FL(readstate)->gensyms, (void*)ctx->tokval);