9front - general discussion about 9front
 help / color / mirror / Atom feed
From: ori@eigenstate.org
To: 9front@9front.org
Subject: rc: null list in concatenation line numbers
Date: Thu, 15 Oct 2020 18:40:53 -0700	[thread overview]
Message-ID: <71CE86A5EC086742886B6A2E7F09C255@eigenstate.org> (raw)

This change causes rc to print the line number of an error
within Xerror(), meaning that the feared 'null list in
concatenation' will now tell you from where it came, like
so:

	stdin:10: null 
	test.rc:6: null list in concatenation

This change works by adding a bytecode instruction to
our code which updates a location. In the interests of
not bloating the bytecode too much, the new Xloc
instruction packs both the line number and file
into one integer, which limits us to 2048 filenames
and 1 million lines per file. Hitting these limits
won't break scripts, but they will turn the location
information into garbage. I think this is acceptable:
if you source thousands of files, you deserve it.

I also failed to resist temptation to clean up some
style annoyances -- lack of 'extern' on variables,
inconsistent repetition of typedef'ed tags, and
some useless casts from malloc, so this patch is a
bit noisier than it could be.

Testing and review welcome.

diff -r e05e4b6c6546 sys/src/cmd/rc/code.c
--- a/sys/src/cmd/rc/code.c	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/code.c	Thu Oct 15 18:39:30 2020 -0700
@@ -6,10 +6,12 @@
 #define	c0	t->child[0]
 #define	c1	t->child[1]
 #define	c2	t->child[2]
+code *codebuf;
 int codep, ncode;
 #define	emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
 #define	emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
 #define	emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
+
 void stuffdot(int);
 char *fnstr(tree*);
 void outcode(tree*, int);
@@ -37,9 +39,9 @@
 int
 compile(tree *t)
 {
+	codep = 0;
 	ncode = 100;
-	codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
-	codep = 0;
+	codebuf = emalloc(ncode*sizeof codebuf[0]);
 	emiti(0);			/* reference count */
 	outcode(t, flag['e']?1:0);
 	if(nerror){
@@ -79,12 +81,28 @@
 void
 outcode(tree *t, int eflag)
 {
-	int p, q;
+	static int file, line;
+	int p, q, f, l;
 	tree *tt;
 	if(t==0)
 		return;
 	if(t->type!=NOT && t->type!=';')
 		runq->iflast = 0;
+	if(t->file != file || t->line != line){
+		file = t->file;
+		line = t->line;
+
+		/*
+		 * These are small enough that with a ton of sourcing,
+		 * overflow is a realistic risk. If we run out of files,
+		 * set to file 0, which is always '???'
+		 */
+		f = (t->file > LFMAX) ? 0 : t->file << LSHIFT;
+		l = (t->line > LMASK) ? -1 : t->line;
+
+		emitf(Xloc);
+		emiti(f|l);
+	}
 	switch(t->type){
 	default:
 		pfmt(err, "bad type %d in outcode\n", t->type);
diff -r e05e4b6c6546 sys/src/cmd/rc/exec.c
--- a/sys/src/cmd/rc/exec.c	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/exec.c	Thu Oct 15 18:39:30 2020 -0700
@@ -14,6 +14,7 @@
 	struct thread *p = new(struct thread);
 
 	p->code = codecopy(c);
+	p->loc = 0;
 	p->pc = pc;
 	p->argv = 0;
 	p->redir = p->startredir = runq?runq->redir:0;
@@ -205,6 +206,11 @@
 	pushlist();
 	argv0 = estrdup(argv[0]);
 	for(i = argc-1;i!=0;--i) pushword(argv[i]);
+
+	lexpath = erealloc(lexpath, sizeof(char*));
+	nlexpath = 1;
+	lexpath[0] = strdup("???");
+
 	for(;;){
 		if(flag['r'])
 			pfnc(err, runq);
@@ -953,10 +959,15 @@
 void
 Xerror(char *s)
 {
+	int f, l;
+
+	f = runq->loc >> LSHIFT;
+	l = runq->loc & LMASK;
+	assert(f >= 0 && f < nlexpath);
 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
-		pfmt(err, "rc: %s: %r\n", s);
+		pfmt(err, "rc:%d: %s: %r\n", l, s);
 	else
-		pfmt(err, "rc (%s): %s: %r\n", argv0, s);
+		pfmt(err, "%s:%d: %s: %r\n", lexpath[f], l, s);
 	flush(err);
 	setstatus("error");
 	while(!runq->iflag) Xreturn();
@@ -965,10 +976,15 @@
 void
 Xerror1(char *s)
 {
+	int f, l;
+
+	f = runq->loc >> LSHIFT;
+	l = runq->loc & LMASK;
+	assert(f >= 0 && f < nlexpath);
 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
-		pfmt(err, "rc: %s\n", s);
+		pfmt(err, "rc:%d: %s\n", l, s);
 	else
-		pfmt(err, "rc (%s): %s\n", argv0, s);
+		pfmt(err, "%s:%d: %s\n", lexpath[f], l, s);
 	flush(err);
 	setstatus("error");
 	while(!runq->iflag) Xreturn();
@@ -1025,3 +1041,10 @@
 {
 	globlist(runq->argv->words);
 }
+
+void
+Xloc(void)
+{
+	runq->loc = runq->code[runq->pc].i;
+	runq->pc++;
+}
diff -r e05e4b6c6546 sys/src/cmd/rc/exec.h
--- a/sys/src/cmd/rc/exec.h	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/exec.h	Thu Oct 15 18:39:30 2020 -0700
@@ -5,7 +5,7 @@
 extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void);
 extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
 extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
-extern void Xrdwr(void);
+extern void Xrdwr(void), Xloc(void);
 extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
 extern void Xtrue(void), Xword(void), Xglobs(void), Xwrite(void), Xpipefd(void), Xcase(void);
 extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
@@ -30,7 +30,7 @@
 struct redir{
 	char type;			/* what to do */
 	short from, to;			/* what to do it to */
-	struct redir *next;		/* what else to do (reverse order) */
+	redir *next;		/* what else to do (reverse order) */
 };
 #define	NSTATUS	ERRMAX			/* length of status (from plan 9) */
 /*
@@ -40,14 +40,15 @@
 #define	RDUP	2			/* dup2(from, to); */
 #define	RCLOSE	3			/* close(from); */
 struct thread{
-	union code *code;		/* code for this thread */
+	code *code;			/* code for this thread */
 	int pc;				/* code[pc] is the next instruction */
-	struct list *argv;		/* argument stack */
-	struct redir *redir;		/* redirection stack */
-	struct redir *startredir;	/* redir inheritance point */
-	struct var *local;		/* list of local variables */
+	int loc;			/* source code location */
+	list *argv;			/* argument stack */
+	redir *redir;			/* redirection stack */
+	redir *startredir;		/* redir inheritance point */
+	var *local;			/* list of local variables */
 	char *cmdfile;			/* file name in Xrdcmd */
-	struct io *cmdfd;		/* file descriptor for Xrdcmd */
+	io *cmdfd;			/* file descriptor for Xrdcmd */
 	int iflast;			/* static `if not' checking */
 	int eof;			/* is cmdfd at eof? */
 	int iflag;			/* interactive? */
@@ -55,7 +56,7 @@
 	int pid;			/* process for Xpipewait to wait for */
 	char status[NSTATUS];		/* status for Xpipewait */
 	tree *treenodes;		/* tree nodes created by this process */
-	thread *ret;		/* who continues when this finishes */
+	thread *ret;			/* who continues when this finishes */
 };
 thread *runq;
 code *codecopy(code*);
diff -r e05e4b6c6546 sys/src/cmd/rc/lex.c
--- a/sys/src/cmd/rc/lex.c	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/lex.c	Thu Oct 15 18:39:30 2020 -0700
@@ -25,6 +25,13 @@
 int doprompt = 1;
 int inquote;
 int incomm;
+int lastc;
+int ndot;
+int nerror;
+int lexline;
+int lexfile;
+char **lexpath;
+int nlexpath;
 /*
  * Look ahead in the input stream
  */
@@ -39,13 +46,14 @@
 /*
  * Consume the lookahead character.
  */
-
 int
 advance(void)
 {
 	int c = nextc();
 	lastc = future;
 	future = EOF;
+	if(c == '\n')
+		lexline++;
 	return c;
 }
 /*
diff -r e05e4b6c6546 sys/src/cmd/rc/pfnc.c
--- a/sys/src/cmd/rc/pfnc.c	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/pfnc.c	Thu Oct 15 18:39:30 2020 -0700
@@ -51,6 +51,7 @@
 	Xrdfn, "Xrdfn",
 	Xsimple, "Xsimple",
 	Xqw, "Xqw",
+	Xloc, "Xloc",
 0};
 
 void
diff -r e05e4b6c6546 sys/src/cmd/rc/rc.h
--- a/sys/src/cmd/rc/rc.h	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/rc.h	Thu Oct 15 18:39:30 2020 -0700
@@ -43,6 +43,8 @@
 	char	*str;
 	int	quoted;
 	int	iskw;
+	int	file;
+	int	line;
 	tree	*child[3];
 	tree	*next;
 };
@@ -54,6 +56,19 @@
 tree *simplemung(tree*), *heredoc(tree*);
 void freetree(tree*);
 tree *cmdtree;
+
+/*
+ * Locations are stored as instructions in the rc bytecode.
+ * To avoid wasting too much space, both the file and line
+ * is packed into a single integer, as
+ *     (file << LSHIFT) | line
+ * With 32 bit integers, this gives us 2048 filenames, with
+ * just over 1 million lines of code in each.
+ */
+#define LSHIFT	20
+#define LMASK	((1<<LSHIFT)-1)
+#define LFMAX	(1<<(8*sizeof(int)-LSHIFT-1))
+
 /*
  * The first word of any code vector is a reference count.
  * Always create a new reference to a code vector by calling codecopy(.).
@@ -126,10 +141,15 @@
  */
 #define	onebyte(c)	((c&0x80)==0x00)
 
-char **argp;
-char **args;
-int nerror;		/* number of errors encountered during compilation */
-int doprompt;		/* is it time for a prompt? */
+extern char **argp;
+extern char **args;
+extern int nerror;		/* number of errors encountered during compilation */
+extern int doprompt;		/* is it time for a prompt? */
+extern int lexfile;
+extern int lexline;
+extern char **lexpath;
+extern int nlexpath;
+
 /*
  * Which fds are the reading/writing end of a pipe?
  * Unfortunately, this can vary from system to system.
@@ -143,7 +163,7 @@
  * How many dot commands have we executed?
  * Used to ensure that -v flag doesn't print rcmain.
  */
-int ndot;
+extern int ndot;
+extern int lastc;
+extern int lastword;
 char *getstatus(void);
-int lastc;
-int lastword;
diff -r e05e4b6c6546 sys/src/cmd/rc/simple.c
--- a/sys/src/cmd/rc/simple.c	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/simple.c	Thu Oct 15 18:39:30 2020 -0700
@@ -11,7 +11,7 @@
  */
 int
 exitnext(void){
-	union code *c=&runq->code[runq->pc];
+	code *c=&runq->code[runq->pc];
 	while(c->f==Xpopredir || c->f==Xunlocal) c++;
 	return c->f==Xexit;
 }
@@ -294,7 +294,7 @@
 execdot(void)
 {
 	int iflag = 0;
-	int fd;
+	int fd, i;
 	list *av;
 	thread *p = runq;
 	char *zero, *file;
@@ -354,6 +354,20 @@
 		Xerror(".: can't open");
 		return;
 	}
+
+	lexline = 1;
+	for(i = 0; i < nlexpath; i++){
+		if(strcmp(lexpath[i], zero) == 0){
+			lexfile = i;
+			break;
+		}
+	}
+	if(i == nlexpath){
+		lexpath = erealloc(lexpath, (nlexpath + 1)*sizeof(char*));
+		lexpath[nlexpath] = estrdup(zero);
+		lexfile = nlexpath;
+		nlexpath++;
+	}
 	/* set up for a new command loop */
 	start(dotcmds, 1, (struct var *)0);
 	pushredir(RCLOSE, fd, 0);
diff -r e05e4b6c6546 sys/src/cmd/rc/tree.c
--- a/sys/src/cmd/rc/tree.c	Mon Oct 12 02:03:52 2020 +0200
+++ b/sys/src/cmd/rc/tree.c	Thu Oct 15 18:39:30 2020 -0700
@@ -16,6 +16,8 @@
 	t->str = 0;
 	t->child[0] = t->child[1] = t->child[2] = 0;
 	t->next = treenodes;
+	t->file = lexfile;
+	t->line = lexline;
 	treenodes = t;
 	return t;
 }



             reply	other threads:[~2020-10-16  1:40 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-16  1:40 ori [this message]
2020-10-16  3:43 ` [9front] " Xiao-Yong Jin
2020-10-17  1:47   ` ori
2020-10-16  5:40 ` Iruatã Souza
2020-10-22  1:18 ` ori
2020-10-22 12:11   ` tlaronde
2020-10-25 20:29   ` ori
2020-10-25 23:18     ` cinap_lenrek
2020-10-26  1:00       ` ori
2020-10-25 23:41     ` cinap_lenrek
2020-10-26  1:33       ` ori
2020-10-26  7:36         ` cinap_lenrek
2020-10-28  3:16           ` ori
2020-10-28  9:50             ` cinap_lenrek
2020-10-28 17:59               ` ori
2020-10-31  1:55               ` ori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=71CE86A5EC086742886B6A2E7F09C255@eigenstate.org \
    --to=ori@eigenstate.org \
    --cc=9front@9front.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).