[Nickle] nickle: Branch 'master' - 14 commits

Keith Packard keithp at keithp.com
Tue Jul 9 18:13:14 PDT 2019


 autogen.sh            |    2 
 builtin.c             |   21 +++++++--
 builtin.h             |    2 
 compile.c             |   37 +++++++++--------
 configure.ac          |    6 --
 debian/changelog      |   18 +++++++-
 debian/tests/upstream |    8 +--
 execute.c             |   19 ++++++--
 file.c                |    5 +-
 io.c                  |   20 ++++++---
 lex.l                 |  107 ++++++++++++++++++++++++++++++++------------------
 main.c                |   36 +++++++++-------
 nickle.h              |    1 
 symbol.c              |   16 +++++++
 test/Makefile.am      |   14 +++++-
 test/arraytest.5c     |   30 ++++++++++++++
 test/string-file.5c   |   20 +++++++++
 value.h               |    6 ++
 18 files changed, 263 insertions(+), 105 deletions(-)

New commits:
commit 8ec2c4bd0ded52d095dbd0486880f7693d727b7b
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Jul 9 18:11:18 2019 -0700

    Remove AM_MAINTAINER_MODE
    
    This doesn't have any effect anymore.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/autogen.sh b/autogen.sh
index b217841..85694fc 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -7,4 +7,4 @@
 # configure depends on version.m4, but autoreconf does not realize this
 rm configure
 autoreconf -Wall -v --install || exit 1
-./configure --enable-maintainer-mode "$@"
+./configure "$@"
diff --git a/configure.ac b/configure.ac
index b7fbeb5..e2f4b17 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,8 +14,6 @@ AC_CONFIG_AUX_DIR(.)
 
 AM_INIT_AUTOMAKE([foreign])
 
-AM_MAINTAINER_MODE
-
 AC_SUBST([RELEASE_DATE])
 dnl Checks for programs.
 AC_PROG_CC
commit f8de289ee31ca203bd33f264358aa65822801580
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Jul 9 18:09:11 2019 -0700

    test: Add test for empty string_file
    
    This used to crash:
    
    $ nickle -e 'File::string_string(File::string_write())'
    
    Add a test for that, plus a simple test for a non-empty one too.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/test/Makefile.am b/test/Makefile.am
index 8a91f92..d7fe7fc 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -15,7 +15,8 @@ check_SCRIPTS=\
 	factorial.5c \
 	is_type.5c \
 	jsontest.5c \
-	datetest.5c
+	datetest.5c \
+	string-file.5c
 
 TABLES=math-tables.5c
 
diff --git a/test/string-file.5c b/test/string-file.5c
new file mode 100644
index 0000000..90b47b9
--- /dev/null
+++ b/test/string-file.5c
@@ -0,0 +1,20 @@
+/*
+ * Nickle test suite
+ *
+ * string I/O tests
+ */
+
+exception bad_result (poly want, poly got);
+
+void check(poly want, poly got)
+{
+    if (want != got)
+	raise bad_result(want, got);
+}
+
+check("", File::string_string(File::string_write()));
+
+file f = File::string_write();
+File::fprintf(f, "hello, world");
+check("hello, world", File::string_string(f));
+
commit 9ffc51e440208cb0ba63c643342d25ef0f5aacb7
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Jul 9 17:19:07 2019 -0700

    File::string_string can be passed an empty buffer
    
    If no writes have been done, then file->file.output will be NULL, so
    write_chain needs to check for NULL out rather than NULL out->next.
    
    Reported-by: David B. Lamkins <dlamkins at galois.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/file.c b/file.c
index a22e30b..453afc0 100644
--- a/file.c
+++ b/file.c
@@ -919,8 +919,9 @@ FileStringWrite (void)
 static char *
 write_chain(char *s, FileChainPtr out)
 {
-    if (out->next)
-	s = write_chain(s, out->next);
+    if (!out)
+	return s;
+    s = write_chain(s, out->next);
     memcpy(s, FileBuffer(out), out->used);
     return s + out->used;
 }
commit 6072bc5b8829f254bb5dea59dec615fc325921ab
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 14:00:46 2018 -0700

    Bump to version 2.84
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index 223b2cd..b7fbeb5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,8 +6,8 @@ dnl for licensing information.
 
 AC_PREREQ([2.69])
 
-AC_INIT([nickle],[2.83],[http://nickle.org],[nickle])
-RELEASE_DATE="2018-10-22"
+AC_INIT([nickle],[2.84],[http://nickle.org],[nickle])
+RELEASE_DATE="2018-10-26"
 AC_CONFIG_SRCDIR([nickle.h])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_AUX_DIR(.)
diff --git a/debian/changelog b/debian/changelog
index f5571b9..80d1733 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+nickle (2.84-1) unstable; urgency=medium
+
+  * Correct crash compiling implicit sized arrays with mismatching
+    init dimensionality. Closes: #911926.
+  * Fix SIGTSTP handling to work in more cases, including under dash
+    and when run as other than the process group leader.
+  * Ignore '_' in numeric values, permitting its use as a separator.
+
+ -- Keith Packard <keithp at keithp.com>  Fri, 26 Oct 2018 13:36:57 -0700
+
 nickle (2.83-1) unstable; urgency=medium
 
   * Include debian/source/format in tarball
commit 5d5c84a62ad34fffb73c16ed18dc2e630bf64e21
Author: Keith Packard <keithp at keithp.com>
Date:   Sat Oct 27 19:04:49 2018 -0700

    Construct a separate case for lexing '0' from other octal numbers
    
    This avoids needing code to identify this case within the octal number
    token generation code.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/lex.l b/lex.l
index 256a8d2..a498b24 100644
--- a/lex.l
+++ b/lex.l
@@ -562,12 +562,13 @@ has_member	{ yylval.ints = HASMEMBER; return HASMEMBER; }
 			REFERENCE (yylval.value);
 			return STRING_CONST;
 		}
-0[0-7_]*		{
+0		{
+		yylval.value = Zero;
+		return TEN_NUM;
+		}
+0[0-7_]+	{
 		yylval.value = atov(yytext+1, 8);
-		if (yytext[1] == '\0')
-		    return TEN_NUM;
-	        else
-		    return OCTAL0_NUM;
+		return OCTAL0_NUM;
 		}
 0o[0-7_]+	{
 		yylval.value = atov(yytext+2, 8);
@@ -913,4 +914,3 @@ aetov (char *s, int base)
 	v = Negate (v);
     RETURN (v);
 }
-
commit 3d05b8d6df9bd32fe90affe080c327e290bf85f4
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 23:30:02 2018 -0700

    Ignore '_' within numbers so it can be used as a separator
    
    Adopted from languages like Rust where this can be used to group
    digits in thousands for base-10 or power of two for base 2,8,16 to
    make them easier to read.
    
            123_456_789 = 123456789
            0xafff_1212 = 0xafff1212
    
    The patch makes both the lexer and string conversions support this.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/lex.l b/lex.l
index d31ca6f..256a8d2 100644
--- a/lex.l
+++ b/lex.l
@@ -562,74 +562,74 @@ has_member	{ yylval.ints = HASMEMBER; return HASMEMBER; }
 			REFERENCE (yylval.value);
 			return STRING_CONST;
 		}
-0[0-7]*		{
+0[0-7_]*		{
 		yylval.value = atov(yytext+1, 8);
 		if (yytext[1] == '\0')
 		    return TEN_NUM;
 	        else
 		    return OCTAL0_NUM;
 		}
-0o[0-7]+	{
+0o[0-7_]+	{
 		yylval.value = atov(yytext+2, 8);
 		return OCTAL_NUM;
 		}
-0o[0-7]+\./\.\.\.   {
+0o[0-7_]+\./\.\.\.   {
 		yylval.value = aetov(yytext+2, 8);
 		return OCTAL_FLOAT;
 		}
-0o[0-7]+/\.\.	{
+0o[0-7_]+/\.\.	{
 		yylval.value = atov(yytext+2, 8);
 		return OCTAL_NUM;
 		}
-0o(([0-7]+((\.[0-7]*(\{[0-7]+\})?)?))|(\.[0-7]+)|(\.[0-7]*\{[0-7]+\}))(([Ee][-+]?[0-7]+)?) {
+0o(([0-7_]+((\.[0-7_]*(\{[0-7_]+\})?)?))|(\.[0-7_]+)|(\.[0-7_]*\{[0-7_]+\}))(([Ee][-+]?[0-7_]+)?) {
 		yylval.value = aetov (yytext+2, 8);
 		return OCTAL_FLOAT;
 		}
-0b[01]+		{
+0b[01_]+		{
 		yylval.value = atov(yytext+2, 2);
 		return BINARY_NUM;
 		}
-0b[0-1]+\./\.\.\.   {
+0b[01_]+\./\.\.\.   {
 		yylval.value = aetov(yytext+2, 2);
 		return BINARY_FLOAT;
 		}
-0b[0-1]+/\.\.	{
+0b[01_]+/\.\.	{
 		yylval.value = atov(yytext+2, 2);
 		return BINARY_NUM;
 		}
-0b(([0-1]+((\.[0-1]*(\{[0-1]+\})?)?))|(\.[0-1]+)|(\.[0-1]*\{[0-1]+\}))(([Ee][-+]?[0-1]+)?) {
+0b(([01_]+((\.[01_]*(\{[01_]+\})?)?))|(\.[01_]+)|(\.[01_]*\{[01_]+\}))(([Ee][-+]?[01_]+)?) {
 		yylval.value = aetov (yytext+2, 2);
 		return BINARY_FLOAT;
 		}
-0x[0-9a-fA-F]+	{
+0x[0-9a-fA-F_]+	{
 		yylval.value = atov(yytext+2, 16);
 		return HEX_NUM;
 		}
-0x[0-9a-fA-F]+\./\.\.\.   {
+0x[0-9a-fA-F_]+\./\.\.\.   {
 		yylval.value = aetov(yytext+2, 16);
 		return HEX_FLOAT;
 		}
-0x[0-9a-fA-F]+/\.\.	{
+0x[0-9a-fA-F_]+/\.\.	{
 		yylval.value = atov(yytext+2, 16);
 		return HEX_NUM;
 		}
-0x(([0-9a-fA-F]+((\.[0-9a-fA-F]*(\{[0-9a-fA-F]+\})?)?))|(\.[0-9a-fA-F]+)|(\.[0-9a-fA-F]*\{[0-9a-fA-F]+\}))(([Ee][-+]?[0-9a-fA-F]+)?) {
+0x(([0-9a-fA-F_]+((\.[0-9a-fA-F_]*(\{[0-9a-fA-F_]+\})?)?))|(\.[0-9a-fA-F_]+)|(\.[0-9a-fA-F_]*\{[0-9a-fA-F_]+\}))(([Ee][-+]?[0-9a-fA-F_]+)?) {
 		yylval.value = aetov (yytext+2, 16);
 		return HEX_FLOAT;
 		}
-[0-9]+		{
+[0-9][0-9_]*		{
 		yylval.value = atov(yytext, 10);
 		return TEN_NUM;
 		}
-[0-9]+\./\.\.\.	{
+[0-9][0-9_]*\./\.\.\.	{
 		yylval.value = aetov(yytext, 10);
 		return TEN_FLOAT;
 		}
-[0-9]+/\.\.	{
+[0-9][0-9_]*/\.\.	{
 		yylval.value = atov(yytext, 10);
 		return TEN_NUM;
 		}
-(([0-9]+((\.[0-9]*(\{[0-9]+\})?)?))|(\.[0-9]+)|(\.[0-9]*\{[0-9]+\}))(([Ee][-+]?[0-9]+)?) {
+(([0-9][0-9_]*((\.[0-9_]*(\{[0-9_]+\})?)?))|(\.[0-9][0-9_]*)|(\.([0-9][0-9_]*)?\{[0-9_]+\}))(([Ee][-+]?[0-9_]+)?) {
 		yylval.value = aetov (yytext, 10);
 		return TEN_FLOAT;
 		}
@@ -788,6 +788,8 @@ atov (char *s, int base)
 	    i = c - 'a' + 10;
 	else if ('A' <= c && c <= 'Z')
 	    i = c - 'A' + 10;
+	else if (c == '_')
+	    continue;
 	else
 	    break;
 	if (i >= base)
@@ -797,12 +799,47 @@ atov (char *s, int base)
     RETURN (result);
 }
 
+static char *
+scan_number(char *s, char needle, int *lenp)
+{
+    int len = 0;
+    for (;;) {
+	char c = *s;
+	if (tolower(c) == needle)
+	    break;
+	switch (c) {
+	case '\0':
+	    return NULL;
+	case '_':
+	    break;
+	default:
+	    len++;
+	    break;
+	}
+	s++;
+    }
+    if (lenp)
+	*lenp = len;
+    return s;
+}
+
+static int
+number_len(char *s)
+{
+    int len = 0;
+    char c;
+    while ((c = *s++))
+	if (c != '_')
+	    len++;
+    return len;
+}
+
 Value
 aetov (char *s, int base)
 {
     ENTER ();
     char    *int_part, *frac_part, *rep_part, *exp_part, *next;
-    int	    sign, frac_len, rep_len, esign;
+    int	    sign, int_len = -1, frac_len = -1, rep_len = -1, exp_frac_len = -1, esign;
     Value   v, sv;
 
     int_part = s;
@@ -814,7 +851,7 @@ aetov (char *s, int base)
 	sign = -1;
     }
     next = int_part;
-    frac_part = strchr (next, '.');
+    frac_part = scan_number(next, '.', &int_len);
     frac_len = -1;
     rep_part = 0;
     rep_len = 0;
@@ -822,24 +859,20 @@ aetov (char *s, int base)
     if (frac_part) {
 	frac_part++;
 	next = frac_part;
-	rep_part = strchr (next, '{');
+	rep_part = scan_number(next, '{', &frac_len);
 	if (rep_part)
 	{
-	    frac_len = rep_part - frac_part;
 	    rep_part++;
-	    next = strchr (rep_part, '}');
+	    next = rep_part;
+	    next = scan_number(next, '}', &rep_len);
 	    if (!next)
-		RETURN (Void);	    /* "can't" happen */
-	    rep_len = next - rep_part;
-	    next = next + 1;
+		RETURN(Void);	/* can't happen */
 	}
     }
-    exp_part = strchr (next, 'e');
-    if (!exp_part)
-	exp_part = strchr (next, 'E');
+    exp_part = scan_number(next, 'e', &exp_frac_len);
     if (exp_part) {
 	if (frac_len < 0)
-	    frac_len = exp_part - frac_part;
+	    frac_len = exp_frac_len;
 	exp_part++;
 	if (*exp_part == '+')
 	    exp_part++;
@@ -848,7 +881,7 @@ aetov (char *s, int base)
 	    exp_part++;
 	}
     } else if (frac_len < 0 && frac_part)
-	frac_len = strlen(frac_part);
+	frac_len = number_len(frac_part);
     v = atov (int_part, base);
     if (frac_part)
     {
@@ -859,7 +892,7 @@ aetov (char *s, int base)
     if (rep_part)
     {
 	Value	rep;
-	
+
 	rep = Divide (atov (rep_part, base), Minus (Pow (NewInt (base),
 						       NewInt (rep_len)),
 						  One));
@@ -868,7 +901,7 @@ aetov (char *s, int base)
 				    NewInt (frac_len)));
 	v = Plus (v, rep);
     }
-    if (exp_part) 
+    if (exp_part)
     {
 	sv = Pow (NewInt (base), atov (exp_part, base));
 	if (esign > 0)
commit 336177cc7ab9e255c7384260d5d303618dc90cf9
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 16:04:06 2018 -0700

    Add array initalizer tests
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/test/Makefile.am b/test/Makefile.am
index 34ab8d0..8a91f92 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -6,6 +6,7 @@ check_SCRIPTS=\
 	orderofoptest.5c \
 	rattest.5c \
 	reftest.5c \
+	arraytest.5c \
 	modtest.5c \
 	hashtest.5c \
 	signal.5c \
diff --git a/test/arraytest.5c b/test/arraytest.5c
new file mode 100644
index 0000000..c283feb
--- /dev/null
+++ b/test/arraytest.5c
@@ -0,0 +1,30 @@
+/* Make sure array initalizers work as expected */
+
+void check (poly value, poly correct)
+{
+    if (is_number (value) && !is_rational (value))
+    {
+	real	error = abs (value - correct);
+	if (error < abs(value) / 1e7)
+	    return;
+    }
+    if (value != correct)
+	abort ("check failed (was %v, should be %v)", value, correct);
+}
+
+check (([10]) { 1, 2, ... }[9], 2);
+check (([*,*]) { { 1, 2, ...}, { 3, 4, 5, 6}} [0,3], 2);
+check (([*,*,*]) { { { 1, 2, 3 } ... }, { { 4, 5, 6}, {7, 8, 9}, {10, 11, 12}}}[0,1,2], 3);
+check (([10]) { [i] = i ** 2 + 1 }[9], 82);
+
+/* These should all generate compile errors, but shouldn't crash */
+file save_stderr = stderr;
+stderr = File::open("/dev/null", "w");
+([*,*]) { { [i] = i ** 2 + 1 }, { 4, 5, 6, 7, 8 }};
+([*]) { 1 ... };
+([*,*]) {1};
+int[*,*] x = {1};
+int[] x = {{1},2};
+stderr = save_stderr;
+
+exit(0);
commit f2ed37df1fff4660e2014bb8214c0c31b1c7127f
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 16:01:22 2018 -0700

    Ignore SIGTTOU/SIGTTIN. Adjust TSTP processing
    
    When run as other than the master of a process group, nickle may not
    get all of its work done before the controlling shell takes over the
    tty and resets that control group. This means that any processing of
    terminal parameters may generate SIGTTOU/SIGTTIN signals, which end up
    re-entering the stop function and causing general chaos. Only SIG_IGN
    appears to appease the kernel into dealing with this case correctly.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/main.c b/main.c
index e20f1dd..e4465c0 100644
--- a/main.c
+++ b/main.c
@@ -101,8 +101,8 @@ main (int argc, char **argv)
     (void) ignoreSignal (SIGPIPE);
     (void) catchSignal (SIGTERM, die);
     (void) catchSignal (SIGTSTP, stop);
-    (void) catchSignal (SIGTTIN, stop);
-    (void) catchSignal (SIGTTOU, stop);
+    (void) ignoreSignal (SIGTTIN);
+    (void) ignoreSignal (SIGTTOU);
     stdin_interactive = isatty(0);
     init ();
     setArgv (argc - 1, argv + 1);
@@ -180,22 +180,26 @@ stop (int sig)
     sigset_t	set, oset;
 
 #if HAVE_RL_CLEANUP_AFTER_SIGNAL
-    printf ("stop %d\n", stdin_in_readline);
-    if (stdin_in_readline)
+    if (stdin_in_readline) {
+	rl_echo_signal_char(sig);
 	rl_cleanup_after_signal();
+    }
 #endif
-    sigfillset (&set);
-    sigprocmask (SIG_SETMASK, &set, &oset);
+
     IoStop ();
     releaseSignal (sig);
-    sigfillset (&set);
-    sigdelset (&set, sig);
-    sigprocmask (SIG_SETMASK, &set, &set);
-    kill (getpid(), sig);
-    sigprocmask (SIG_SETMASK, &oset, &set);
-    IoStart ();
+    killpg (0, sig);
+    sigemptyset(&set);
+    sigaddset(&set, sig);
+    sigprocmask (SIG_UNBLOCK, &set, &oset);
+
+    /* stopped ... */
+
+    sigprocmask (SIG_SETMASK, &oset, NULL);
     catchSignal (sig, stop);
-#if HAVE_RL_RESET_AFTER_SIGNAL
+    IoStart ();
+
+#if HAVE_RL_CLEANUP_AFTER_SIGNAL
     if (stdin_in_readline)
 	rl_reset_after_signal();
 #endif
@@ -204,11 +208,13 @@ stop (int sig)
 void
 die (int sig)
 {
-    IoStop ();
 #if HAVE_RL_CLEANUP_AFTER_SIGNAL
-    if (stdin_in_readline)
+    if (stdin_in_readline) {
+	rl_free_line_state();
 	rl_cleanup_after_signal();
+    }
 #endif
+    IoStop ();
     _exit (sig);
 }
 
commit 549bbed54dc0c5d1361906cf1ca03f6e9cb57615
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 15:51:53 2018 -0700

    Make assignments to stdin/stdout/stderr affect C code
    
    Use values of these variables in the C code.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/builtin.c b/builtin.c
index cd65b18..bba961e 100644
--- a/builtin.c
+++ b/builtin.c
@@ -45,9 +45,9 @@ static const struct envbuiltin envvars[] = {
 };
 
 static const struct filebuiltin fvars[] = {
-    { "stdin",	&FileStdin },
-    { "stdout",	&FileStdout },
-    { "stderr",	&FileStderr },
+    { "stdin",	&FileStdinBox },
+    { "stdout",	&FileStdoutBox },
+    { "stderr",	&FileStderrBox },
     { 0,	0 },
 };
 
@@ -124,6 +124,18 @@ BuiltinSymbol (NamespacePtr *namespacep,
 					     type)));
 }
 
+static SymbolPtr
+BuiltinSymbolValue(NamespacePtr *namespacep,
+		   char	    *string,
+		   Type	    *type,
+		   BoxPtr   value)
+{
+    ENTER ();
+    RETURN (BuiltinAddName (namespacep, 
+			    NewSymbolGlobalValue (AtomId (string),
+						  value)));
+}
+
 static Type *typeUserdef[100];
 
 void
@@ -376,8 +388,7 @@ BuiltinInit (void)
 
     /* Import File objects with predefined values */
     for (f = fvars; f->name; f++) {
-	sym = BuiltinSymbol (f->namespace, f->name, typePrim[rep_file]);
-	BoxValueSet (sym->global.value, 0, *f->value);
+	sym = BuiltinSymbolValue (f->namespace, f->name, typePrim[rep_file], *f->box);
     }
 
     /* Import int objects with predefined values */
diff --git a/builtin.h b/builtin.h
index f90a893..4304b0a 100644
--- a/builtin.h
+++ b/builtin.h
@@ -91,7 +91,7 @@ struct ibuiltin {
 
 struct filebuiltin {
     char	    *name;
-    Value   	    *value;
+    BoxPtr	    *box;
     NamespacePtr    *namespace;
 };
 
diff --git a/io.c b/io.c
index f3d08d1..70a6f2b 100644
--- a/io.c
+++ b/io.c
@@ -93,7 +93,7 @@ IoFini (void)
     FileClose (FileStderr);
 }
 
-Value   FileStdin, FileStdout, FileStderr;
+BoxPtr   FileStdinBox, FileStdoutBox, FileStderrBox;
 
 Bool
 IoTimeout (void *closure)
@@ -145,17 +145,23 @@ IoNoticeReadBlocked (void)
 }
 #endif
 
+static BoxPtr
+IoMakeFile(int fd, int flags)
+{
+    BoxPtr	box = NewBox(False, False, 1, typePrim[rep_file]);
+    MemAddRoot(box);
+    BoxValueSet(box, 0, FileCreate(fd, flags));
+    return box;
+}
+
 void
 IoInit (void)
 {
     ENTER ();
     catchSignal (SIGIO, sigio);
-    FileStdin = FileCreate (0, FileReadable);
-    FileStdout = FileCreate (1, FileWritable);
-    FileStderr = FileCreate (2, FileWritable);
-    MemAddRoot (FileStdin);
-    MemAddRoot (FileStdout);
-    MemAddRoot (FileStderr);
+    FileStdinBox = IoMakeFile(0, FileReadable);
+    FileStdoutBox = IoMakeFile(1, FileWritable);
+    FileStderrBox = IoMakeFile(2, FileWritable);
     IoStart ();
     EXIT ();
 }
diff --git a/nickle.h b/nickle.h
index c57921e..38031aa 100644
--- a/nickle.h
+++ b/nickle.h
@@ -71,6 +71,7 @@ extern SymbolPtr    NewSymbolType (Atom name, Type *type);
 extern SymbolPtr    NewSymbolException (Atom name, Type *type, Value doc);
 extern SymbolPtr    NewSymbolConst (Atom name, Type *type);
 extern SymbolPtr    NewSymbolGlobal (Atom name, Type *type);
+extern SymbolPtr    NewSymbolGlobalValue (Atom name, BoxPtr value);
 extern SymbolPtr    NewSymbolArg (Atom name, Type *type);
 extern SymbolPtr    NewSymbolStatic (Atom name, Type *Rep);
 extern SymbolPtr    NewSymbolAuto (Atom name, Type *type);
diff --git a/symbol.c b/symbol.c
index 93a5411..bb710bb 100644
--- a/symbol.c
+++ b/symbol.c
@@ -127,6 +127,22 @@ NewSymbolGlobal (Atom name, Type *type)
 }
 
 SymbolPtr
+NewSymbolGlobalValue (Atom name, BoxPtr value)
+{
+    ENTER ();
+    SymbolPtr	s;
+
+    s = ALLOCATE (&SymbolGlobalType, sizeof (SymbolGlobal));
+    s->symbol.next = 0;
+    s->symbol.name = name;
+    s->symbol.class = class_global;
+    s->symbol.type = value->u.type;
+    s->symbol.forward = False;
+    s->global.value = value;
+    RETURN (s);
+}
+
+SymbolPtr
 NewSymbolArg (Atom name, Type *type)
 {
     ENTER ();
diff --git a/value.h b/value.h
index 389aff7..e6ee9fe 100644
--- a/value.h
+++ b/value.h
@@ -1237,7 +1237,11 @@ void	FileSetBuffer (Value file, int buf);
 extern Bool	anyFileWriteBlocked;
 extern Bool	anyPipeReadBlocked;
 
-extern Value    FileStdin, FileStdout, FileStderr;
+extern BoxPtr	FileStdinBox, FileStdoutBox, FileStderrBox;
+
+#define FileStdin	BoxValueGet(FileStdinBox, 0)
+#define FileStdout	BoxValueGet(FileStdoutBox, 0)
+#define FileStderr	BoxValueGet(FileStderrBox, 0)
 
 typedef Value	(*BinaryFunc) (Value, Value);
 typedef Value	(*UnaryFunc) (Value);
commit f0a7d677fb94d063ccefb4f8b21b15a26cb4ec49
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 13:57:14 2018 -0700

    Allow repeat initializers in implicit sized arrays for small dimensions
    
    When initializing an implicitly sized multi-dimensional array, permit
    repeat initializers ("...") to be used to fill out smaller dimensions.
    This is done by requiring that the maximum number of elements in each
    dimension be taken from an initalizer without a repeat element.
    
    This also requires allowing repeat initializers to be useful for
    resizable arrays, which required a change to the execution machinery
    as well.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/compile.c b/compile.c
index 463c902..0157df8 100644
--- a/compile.c
+++ b/compile.c
@@ -1411,11 +1411,11 @@ CompileBuildArray (ObjPtr obj, ExprPtr expr, TypePtr type,
     RETURN (obj);
 }
 
-static Bool
+static void
 CompileSizeDimensions (ExprPtr expr, int *dims, int ndims)
 {
     int	    dim;
-    
+
     if (!expr)
 	dim = 0;
     else switch (expr->base.tag) {
@@ -1424,8 +1424,10 @@ CompileSizeDimensions (ExprPtr expr, int *dims, int ndims)
 	expr = expr->tree.left;
 	while (expr)
 	{
-	    if (expr->tree.left->base.tag == DOTDOTDOT)
-		return False;
+	    if (expr->tree.left->base.tag == DOTDOTDOT) {
+		dim = -dim;
+		break;
+	    }
 	    if (ndims != 1)
 	    {
 		CompileSizeDimensions (expr->tree.left, dims + 1, ndims - 1);
@@ -1438,7 +1440,8 @@ CompileSizeDimensions (ExprPtr expr, int *dims, int ndims)
 	}
 	break;
     case COMP:
-	return False;
+	dim = -1;
+	break;
     case ANONINIT:
 	dim = 0;
 	break;
@@ -1446,9 +1449,8 @@ CompileSizeDimensions (ExprPtr expr, int *dims, int ndims)
 	dim = 1;
 	break;
     }
-    if (dim > *dims)
+    if (abs(dim) > *dims || dim > *dims)
 	*dims = dim;
-    return True;
 }
 
 static ExprPtr
@@ -1458,13 +1460,15 @@ CompileImplicitArray (ObjPtr obj, ExprPtr stat, ExprPtr inits, int ndim)
     ExprPtr sub;
     int	    *dims;
     int	    n;
-    
+
     dims = AllocateTemp (ndim * sizeof (int));
     memset (dims, '\0', ndim * sizeof (int));
-    if (!CompileSizeDimensions (inits, dims, ndim))
-    {
-	CompileError (obj, stat, "Implicit dimensioned array with variable initializers");
-	RETURN (0);
+    CompileSizeDimensions (inits, dims, ndim);
+    for (n = 0; n < ndim; n++) {
+	if (dims[n] < 0) {
+	    CompileError (obj, stat, "Implicit dimensioned array with variable initializers");
+	    RETURN (0);
+	}
     }
     sub = 0;
     for (n = ndim - 1; n >= 0; n--)
@@ -1590,6 +1594,9 @@ CompileArrayInits (ObjPtr obj, ExprPtr expr, TypePtr type,
 	    break;
 	case ANONINIT:
 	    break;
+	case COMP:
+	    CompileError (obj, stat, "Comprehension not valid for nested array initializer");
+	    break;
 	default:
 	    CompileError (obj, stat, "Not enough initializer dimensions");
 	    break;
@@ -1831,7 +1838,7 @@ CompileArrayInit (ObjPtr obj, ExprPtr expr, Type *type, ExprPtr stat, CodePtr co
 	    if (ndim > ninitdim ||
 		(ndim < ninitdim && TypeCanon(sub)->base.tag != type_array))
 	    {
-		CompileError (obj, stat, "Array dimension mismatch %d != %d\n",
+		CompileError (obj, stat, "Array dimension mismatch %d != %d",
 			      ndim, ninitdim);
 		RETURN (obj);
 	    }
diff --git a/execute.c b/execute.c
index 4329798..238b8fb 100644
--- a/execute.c
+++ b/execute.c
@@ -416,7 +416,7 @@ ThreadArrayIndex (Value array, Value thread, int ndim,
  * array, so the task is just to copy that first element to the end
  * of the dimension.
  */
- 
+
 static void
 ThreadArrayReplicate (Value thread, Value array, int dim, int start)
 {
@@ -425,15 +425,22 @@ ThreadArrayReplicate (Value thread, Value array, int dim, int start)
     int		total;
     Value	*elements;
 
-    assert (!array->array.resizable);
     for (i = 0; i < dim; i++)
 	dimsize *= ArrayDims(&array->array)[i];
     start = start - dimsize;
     total = ArrayDims(&array->array)[dim] * dimsize;
-    elements = BoxElements (array->array.u.fix);
-    for (i = start + dimsize; i % total; i += dimsize)
-	memmove (elements + i, elements + start,
-		 dimsize * sizeof (elements[0]));
+    if (array->array.resizable) {
+	for (i = start + dimsize; i % total; i += dimsize) {
+	    int j;
+	    for (j = 0; j < dimsize; j++)
+		ArrayValueSet(&array->array, i + j, ArrayValueGet(&array->array, start + j));
+	}
+    } else {
+	elements = BoxElements (array->array.u.fix);
+	for (i = start + dimsize; i % total; i += dimsize)
+	    memmove (elements + i, elements + start,
+		     dimsize * sizeof (elements[0]));
+    }
 }
 
 void
commit b74c10a1ce0b0799e738490cb734a906950e2008
Author: Keith Packard <keithp at keithp.com>
Date:   Fri Oct 26 13:32:31 2018 -0700

    Remove incorrect tree walking in CompileSizeDimensions
    
    CompileSizeDimensions was incorrectly interpreting the tree structure
    for bare value nodes -- it is either passed an ARRAY, or a single
    expression value, which can either be a comprehension, an empty
    initializer or a simple expression. The simple expression case was
    incorrectly looking for a '...' element to the left, which cannot
    happen. It further recursed if it hadn't reached the end of the
    dimensions, which is pointless as that case will generate an
    error when the initializers are compiled later.
    
    Debian-bug: #911926
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/compile.c b/compile.c
index 2c0640d..463c902 100644
--- a/compile.c
+++ b/compile.c
@@ -1444,10 +1444,6 @@ CompileSizeDimensions (ExprPtr expr, int *dims, int ndims)
 	break;
     default:
 	dim = 1;
-	if (expr->tree.left->base.tag == DOTDOTDOT)
-	    return False;
-	if (ndims != 1)
-	    CompileSizeDimensions (expr, dims + 1, ndims - 1);
 	break;
     }
     if (dim > *dims)
commit c69768bd29226641c8107c56cd32d6e46af13dbb
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 22 20:19:49 2018 -0700

    Bump to version 2.83
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/configure.ac b/configure.ac
index b562d84..223b2cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,8 +6,8 @@ dnl for licensing information.
 
 AC_PREREQ([2.69])
 
-AC_INIT([nickle],[2.82],[http://nickle.org],[nickle])
-RELEASE_DATE="2018-10-02"
+AC_INIT([nickle],[2.83],[http://nickle.org],[nickle])
+RELEASE_DATE="2018-10-22"
 AC_CONFIG_SRCDIR([nickle.h])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_AUX_DIR(.)
diff --git a/debian/changelog b/debian/changelog
index aa3d0ab..f5571b9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,12 @@
-nickle (2.83-1) UNRELEASED; urgency=medium
+nickle (2.83-1) unstable; urgency=medium
 
   * Include debian/source/format in tarball
+  * Fix spelling errors in man page
+  * Fix a pile of lintian warnings
+  * Sign tarfiles when released
+  * Run CI tests from installed location
 
- -- Keith Packard <keithp at keithp.com>  Wed, 03 Oct 2018 14:59:47 -0700
+ -- Keith Packard <keithp at keithp.com>  Mon, 22 Oct 2018 19:08:54 -0700
 
 nickle (2.82-1) unstable; urgency=medium
 
commit 594d768aa2cf2c9c532e4884e0da034e778c3f2f
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 22 20:18:47 2018 -0700

    debian: Run CI tests from installed location (/usr/share/nickle/test)
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/debian/tests/upstream b/debian/tests/upstream
index 5228886..e3971e8 100755
--- a/debian/tests/upstream
+++ b/debian/tests/upstream
@@ -1,5 +1,5 @@
 #!/bin/sh
-cd test
-for i in *.5c; do
-	nickle "$i" || exit 1
-fi
+cd /usr/share/nickle/test > /dev/null
+for test in *.5c; do
+    nickle $test || exit 1
+done
commit 9c6dd70b77b161e8d28ef759d61fbb22255d268a
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Oct 22 20:18:19 2018 -0700

    Install tests so they can be run later
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/test/Makefile.am b/test/Makefile.am
index e1fc3f0..34ab8d0 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -16,10 +16,16 @@ check_SCRIPTS=\
 	jsontest.5c \
 	datetest.5c
 
-noinst_PROGRAMS=math-tables
-
 TABLES=math-tables.5c
 
+# Install test files so they can be run later
+
+testdir=$(pkgdatadir)/test
+
+test_DATA=$(check_SCRIPTS) $(TABLES)
+
+noinst_PROGRAMS=math-tables
+
 CLEANFILES=$(TABLES)
 
 TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir)


More information about the Nickle mailing list