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