From d0923800e0b2b2476ff39d8144549172b5c668cb Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Thu, 29 Jul 2021 08:05:46 -0700
Subject: parser: allow trailing commas in json, via opt-in flag.

* parser.c (read_bad_json_s): New symbol variable.
(parser_common_init): Propagate value of *read-bad-json* into
read_bad_json flag in parser structure.
(parser_init): Initialize read_bad_json_s and register the
*read-bad-json* dynamic variable.

* parser.h (struct parser): New member, read_bad_json.
(read_bad_json_s): Declared.

* parser.y (json_val): Support an opt_comma symbol just before
the closing bracket or brace.
(opt_comma): New nonterminal symbol. Recognizes ',' or nothing.
Error is flagged if ',' is recognized, and *read-bad-json*
is nil.

* y.tab.c.shipped: Updated.

* tests/010/json.tl: New tests.

* txr.1: Documented.
---
 parser.y | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

(limited to 'parser.y')

diff --git a/parser.y b/parser.y
index 9e15ca44..7e068714 100644
--- a/parser.y
+++ b/parser.y
@@ -970,13 +970,15 @@ json_val : NUMBER               { $$ = $1; }
          | '"' litchars '"'     { $$ = $2;
                                   rl($$, num(parser->lineno)); }
          | '[' ']'              { $$ = vector(zero, nil); }
-         | '[' json_vals ']'    { $$ = if3(vectorp($2),
+         | '[' json_vals
+               opt_comma ']'    { $$ = if3(vectorp($2),
                                            $2,
                                            rl(cons(vector_lit_s,
                                                    cons(nreverse($2), nil)),
                                               $2)); }
          | '{' '}'              { $$ = make_hash(hash_weak_none, t); }
-         | '{' json_pairs '}'   { $$ = if3(hashp($2),
+         | '{' json_pairs
+               opt_comma '}'    { $$ = if3(hashp($2),
                                            $2,
                                            rl(cons(hash_lit_s,
                                                    cons(nil, nreverse($2))),
@@ -1003,6 +1005,11 @@ json_val : NUMBER               { $$ = $1; }
                                   yybadtok(yychar, lit("JSON hash")); }
          ;
 
+opt_comma : ','                 { if (!parser->read_bad_json)
+                                    yyerr("trailing comma in JSON array"); }
+          |
+          ;
+
 json_vals : json_val                    { $$ = if3(parser->quasi_level > 0 &&
                                                    unquotes_occur($1, 0),
                                                    cons($1, nil),
-- 
cgit v1.2.3