aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-05-29 20:11:52 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-05-29 20:11:52 -0700
commit8a3b6c735d7640117e5c80f5bb7e84e6c2997c51 (patch)
tree048f0dc97b8353d4434f3a2d7d574dd877d9adac
parent10e1cc59ba222b463661fe01b0b783a2b8d49112 (diff)
downloadtl-who-8a3b6c735d7640117e5c80f5bb7e84e6c2997c51.tar.gz
tl-who-8a3b6c735d7640117e5c80f5bb7e84e6c2997c51.tar.bz2
tl-who-8a3b6c735d7640117e5c80f5bb7e84e6c2997c51.zip
Add warning when local macros used in attr expression.
The with-html-output ("WHO") macro defines some local macrolets. Those are in scope of the entire thing, but they can only be meaningfully used in the imperative Lisp forms that are placed into the HTML tag body. If they are used in an attribute expression, it's probably a programming error; an output side effect doesn't belong there. We implement a diagnostic strategy which produces a warning in this situation. * who.tl (attr-warning-macrolet): New function, which wraps macrolet code around the expression passed in. These macrolets intercept the local macros and generate a warning. Then they decline to expand, deferring to the real macros. (convert-attributes): Wrap the warning macrolets around the run-time evaluation of the val expression. We don't do anything for the compile-time evaluation of a constant attribute expression, because the macro calls we want to intercept do not appear in a constant expression. * test/simple.tl: New test 41 validating that warnings are generated for all the local macros when they are called from an attr expression.
-rw-r--r--test/simple.tl13
-rw-r--r--who.tl14
2 files changed, 26 insertions, 1 deletions
diff --git a/test/simple.tl b/test/simple.tl
index 3601814..b9d1a65 100644
--- a/test/simple.tl
+++ b/test/simple.tl
@@ -449,3 +449,16 @@
(with-html-output-to-string (out)
(:foo (fmt "<a href=\"foo.html\">click</a>"))))
"<foo><a href=\"foo.html\">click</a></foo>")
+
+;;; 41
+;;; Test that warning is produced when any of the WHO local macros are used in
+;;; an Lisp expression that calculates an attribute
+(each ((sym '(htm noesc-fmt fmt esc str)))
+ (test (catch
+ (eval '(progn
+ (with-html-output-to-string (out)
+ (:foo :attr (,sym "abc")))
+ nil))
+ (warning (x)
+ t))
+ t))
diff --git a/who.tl b/who.tl
index 4d0c63d..90932f5 100644
--- a/who.tl
+++ b/who.tl
@@ -85,6 +85,18 @@
(set body (rest sexp)))))
(convert-tag-to-string-list tag attr-list body body-fn)))
+(defun attr-warning-macrolet (form)
+ (with-gensyms (warn)
+ ^(macrolet ((,warn (f . rest)
+ ^(compile-warning ,f
+ "not recommended in attribute expr")))
+ (macrolet ((htm (:form f . rest) (,warn f) f)
+ (noesc-fmt (:form f . rest) (,warn f) f)
+ (fmt (:form f . rest) (,warn f) f)
+ (esc (:form f . rest) (,warn f) f)
+ (str (:form f . rest) (,warn f) f))
+ ,form))))
+
;; Helper function for convert-tag-to-string-list which converts the
;; alist attr-list of attributes into a list of strings and/or Lisp
;; forms.
@@ -110,7 +122,7 @@
` @attr=@aqc@(tostringp eval)@aqc`)
(t ` @attr=@aqc@(html-encode (tostringp eval))@aqc`)))
;; For non-constant, do the same things as above but at runtime
- ^(let ((,=var= ,val))
+ ^(let ((,=var= ,(attr-warning-macrolet val)))
(cond
((null ,=var=))
((eq ,=var= t)