From 63211dfd66f3cbd4159885018257022b20a4c975 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 2 Dec 2011 15:39:43 -0800 Subject: * parser.y (list): unquote and splice actions look inside the argument form. If an unquote or splice are applied to a quoted form, its quote becomes a regular quote. This behavior is necessary to make ,',form work in nested quotes, otherwise the ' is a quasiquote which captures the comma in ,form, reducing ,',form to ,form. * txr.1: Documented this special behavior. --- ChangeLog | 11 +++++++++++ parser.y | 10 ++++++++-- txr.1 | 26 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c4b12c7b..6c7dc43b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2011-12-02 Kaz Kylheku + + * parser.y (list): unquote and splice actions look inside the + argument form. If an unquote or splice are applied to a quoted + form, its quote becomes a regular quote. + This behavior is necessary to make ,',form work in nested + quotes, otherwise the ' is a quasiquote which captures + the comma in ,form, reducing ,',form to ,form. + + * txr.1: Documented this special behavior. + 2011-12-02 Kaz Kylheku * eval.c (expand_qquote): Bugfix: removed bogus recognition diff --git a/parser.y b/parser.y index affcd636..82fd9101 100644 --- a/parser.y +++ b/parser.y @@ -607,10 +607,16 @@ var_op : '*' { $$ = list(t, nao); } list : '(' exprs ')' { $$ = rl($2, num($1)); } | '(' ')' { $$ = nil; } - | ',' expr { $$ = rlcp(list(unquote_s, $2, nao), $2); } + | ',' expr { val expr = $2; + if (consp(expr) && first(expr) == qquote_s) + expr = cons(quote_s, rest(expr)); + $$ = rlcp(list(unquote_s, expr, nao), $2); } | '\'' expr { $$ = rlcp(list(choose_quote($2), $2, nao), $2); } - | SPLICE expr { $$ = rlcp(list(splice_s, $2, nao), $2); } + | SPLICE expr { val expr = $2; + if (consp(expr) && first(expr) == qquote_s) + expr = cons(quote_s, rest(expr)); + $$ = rlcp(list(splice_s, expr, nao), $2); } | '(' error { $$ = nil; yybadtoken(yychar, lit("list expression")); } ; diff --git a/txr.1 b/txr.1 index 86877df4..808c7c9d 100644 --- a/txr.1 +++ b/txr.1 @@ -4225,6 +4225,10 @@ of the variable a. Note that TXR Lisp does not have a distinct quote and backquote syntax. There is only one quote, which supports unquoting. +A quoted form which contains no unquotes codifies an ordinary quote. + +A quoted form which contains unquotes expresses a quasiquote. + .IP ,form Thes comma character is used within a quoted list to denote an unquote. Wheras @@ -4241,6 +4245,28 @@ the form which follows ,* must evaluate to a list. That list is spliced into the quoted list. For example: '(a b c ,*(list (+ 3 3) (+ 4 4) d) evaluates to (a b c 6 8 d). The expression (list (+ 3 3) (+ 4 4)) is evaluated to produce the list (6 8), and this list is spliced into the quoted template. + +.IP ,'form + +The comma-quote combination has a special meaning: the quote always +behaves as a regular quote and not a quasiquote, even if form contains +unquotes. Therefore, it does not "capture" these unquotes: they cannot +"belong" to this quote. The comma and quote "cancel out", so the only effect +of comma-quote is to add one level of unquoting. So for instance, whereas in +'(a b c '(,d)), the subsitution of d belongs to the inner quote (it is unquoted +by the leftmost comma which belongs to the innermost quote) by contrast, +in '(a b c '(,',d)) the d is now one comma removed from the leftmost comma and +thus the substitution of d belongs to the outer quote. +In other dialects of Lisp, this would be written `(a b c `(,',d)), making it +explicit which kind of quote is being specified. TXR Lisp works out which +kind of quote to use internally. + +.IP ,*'form + +The comma-splice form is analogous to comma-quote (see above). Like in the +,' combination, in the ,*' combination, the quote behaves as a regular quote +and not a quasiquote. + .PP .SS Nested Quotes -- cgit v1.2.3