From ca118fac3a97a6cd6b9342d301b3b06c515ad5f1 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 15 Jun 2021 07:58:43 -0700 Subject: expander: bug: atoms in quasiliteral. Via macros, atoms can sneak into a quasiliteral which then blow up because they get treated as strings without being converted. Example: (defmacro two () 2) `@(two)xyz` -> ;; error The expansion produces the invalid form, in which the 2 is subsequently treated as a string. (sys:quasi 2 "xyz") On the other hand, symbol macros don't have this problem: (defsymacro two 2) `@{two}xyz` -> "2xyz" The reason is that the (sys:var two) syntax will expand to (sys:var 2), and not 2. The straightforward, consistent fix is to ensure that the first case will also go to (sys:var 2). * eval.c (expand_quasi): If the expanded form is an atom which is not a bindable symbol, wrap it in a sys:var. * tests/012/quasi.tl: Test cases added. Also adding a compilation test for this file, cribbed from patmatch.tl. --- eval.c | 3 +++ tests/012/quasi.tl | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/eval.c b/eval.c index 50d20fad..bdbec0be 100644 --- a/eval.c +++ b/eval.c @@ -3823,6 +3823,9 @@ val expand_quasi(val quasi_forms, val menv) if (comp_184) form_ex = expand(form, menv); } + + if (atom(form_ex) && !bindable(form_ex)) + form_ex = list(var_s, form_ex, nao); } { diff --git a/tests/012/quasi.tl b/tests/012/quasi.tl index 276d5395..1cb24578 100644 --- a/tests/012/quasi.tl +++ b/tests/012/quasi.tl @@ -36,3 +36,18 @@ (let ((s)) (mapcar (ret `<@{(push (inc @1) s) d}>`) (range 0 2)))) ("<1>" "<2-1>" "<3-2-1>")) + +(test + (symacrolet ((two 2)) + `@{two}abc`) + "2abc") + +(test + (macrolet ((two () 2)) + `@(two)abc`) + "2abc") + +(compile-only + (eval-only + (compile-file (base-name *load-path*) "temp.tlo") + (remove-path "temp.tlo"))) -- cgit v1.2.3