summaryrefslogtreecommitdiffstats
path: root/parser.y
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-11-05 23:50:22 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-11-05 23:50:22 -0800
commitd3ec853013356d9c8267980a5146728c16e002ba (patch)
treea4cc5ae81784c16d6177b7a4a032b5ea014ab784 /parser.y
parenta8d9b5d83b10ff215e40fffd1d88fd081a5f1728 (diff)
downloadtxr-d3ec853013356d9c8267980a5146728c16e002ba.tar.gz
txr-d3ec853013356d9c8267980a5146728c16e002ba.tar.bz2
txr-d3ec853013356d9c8267980a5146728c16e002ba.zip
syntax: new .? operator for null-safe object access.
* lib.c (obj_print_impl): Render the new syntactic conventions introduced in qref/uref back into the .? syntax. The printers for qref and uref are united into a single implementation to reduce code proliferation. * parser.l (grammar): Produce new tokens OREFDOT and UOREFDOT. * parser.y (OREFDOT, UREFDOT): New terminal symbols. (n_expr): Handle .? syntax via the new OREFDOT and UOREFDOT token via qref_helper and uoref_helper. Logic for the existing referencing dot is moved into the new qref_helper function. (n_dot_expr): Handle .? syntax via uoref_helper. (uoref_helper, qref_helper): New static functions. * share/txr/stdlib/struct.tl (qref): Handle the new case when the expression which gives the object is (t expr). Handle the new case when the first argument after the object has this form, and is followed by more arguments. Both these cases emit the right conditional code. (uref): Handle the leading .? syntax indicated by a leading t by generating a lambda which checks its argument for nil. Transformations to qref handle the other cases. * txr.1: Documentation updated in several places.
Diffstat (limited to 'parser.y')
-rw-r--r--parser.y44
1 files changed, 32 insertions, 12 deletions
diff --git a/parser.y b/parser.y
index 41fb965f..360ed36c 100644
--- a/parser.y
+++ b/parser.y
@@ -69,6 +69,8 @@ static val make_expr(parser_t *, val sym, val rest, val lineno);
static val check_parse_time_action(val spec_rev);
static void misplaced_consing_dot_check(scanner_t *scanner, val term_atom_cons);
static val uref_helper(parser_t *, val expr);
+static val uoref_helper(parser_t *, val expr);
+static val qref_helper(parser_t *, val lexpr, val rexpr);
static val fname_helper(parser_t *, val name);
#if YYBISON
@@ -128,7 +130,8 @@ INLINE val expand_form_ver(val form, int ver)
%token <val> NUMBER METANUM
%token <val> HASH_N_EQUALS HASH_N_HASH
-%token <chr> REGCHAR REGTOKEN LITCHAR SPLICE CONSDOT LAMBDOT UREFDOT
+%token <chr> REGCHAR REGTOKEN LITCHAR SPLICE
+%token <chr> CONSDOT LAMBDOT UREFDOT OREFDOT UOREFDOT
%type <val> spec hash_semi_or_n_expr hash_semi_or_i_expr
%type <val> clauses_rev clauses_opt clause
@@ -166,7 +169,7 @@ INLINE val expand_form_ver(val form, int ver)
%left '&'
%right '~' '*' '?' '+' '%'
%right DOTDOT
-%right '.' CONSDOT LAMBDOT UREFDOT REGCHAR REGTOKEN LITCHAR
+%right '.' CONSDOT LAMBDOT UREFDOT OREFDOT UOREFDOT REGCHAR REGTOKEN LITCHAR
%right OLD_DOTDOT
%%
@@ -1072,17 +1075,12 @@ n_expr : SYMTOK { $$ = ifnign(symhlpr($1, t)); }
uref_helper(parser, $4),
nao),
or2($1, $4)); }
- | n_expr '.' n_expr { uses_or2;
- if (consp($3) && car($3) == qref_s) {
- rplacd($3, rlc(cons($1, cdr($3)), $1));
- rl($$, num(parser->lineno));
- $$ = $3;
- } else {
- $$ = rl(rlc(list(qref_s, $1, $3, nao),
- or2($1, $3)),
- num(parser->lineno));
- } }
+ | n_expr '.' n_expr { $$ = qref_helper(parser, $1, $3); }
+ | n_expr OREFDOT n_expr { $$ = qref_helper(parser,
+ cons(t, cons($1, nil)),
+ $3); }
| UREFDOT n_expr { $$ = uref_helper(parser, $2); }
+ | UOREFDOT n_expr { $$ = uoref_helper(parser, $2); }
| HASH_N_EQUALS { parser_circ_def(parser, $1, unique_s); }
n_dot_expr { parser_circ_def(parser, $1, $3);
$$ = $3; }
@@ -1094,6 +1092,7 @@ n_exprs_opt : n_exprs { $$ = $1; }
;
n_dot_expr : '.' n_expr { $$ = uref_helper(parser, $2); }
+ | OREFDOT n_expr { $$ = uoref_helper(parser, $2); }
| n_expr %prec LOW { $$ = $1; }
;
@@ -1789,6 +1788,27 @@ static val uref_helper(parser_t *parser, val expr)
}
}
+static val uoref_helper(parser_t *parser, val expr)
+{
+ val uref = uref_helper(parser, expr);
+ rplacd(uref, cons(t, cdr(uref)));
+ return uref;
+}
+
+static val qref_helper(parser_t *parser, val lexpr, val rexpr)
+{
+ uses_or2;
+
+ if (consp(rexpr) && car(rexpr) == qref_s) {
+ rplacd(rexpr, rlc(cons(lexpr, cdr(rexpr)), lexpr));
+ return rl(rexpr, num(parser->lineno));
+ } else {
+ return rl(rlc(list(qref_s, lexpr, rexpr, nao),
+ or2(lexpr, rexpr)),
+ num(parser->lineno));
+ }
+}
+
static val fname_helper(parser_t *parser, val name)
{
if (!name) {