#398 closed defect (fixed)
Nested let-syntax failure to strip renamed identifiers
Reported by: | sjamaan | Owned by: | felix winkelmann |
---|---|---|---|
Priority: | major | Milestone: | 4.9.0 |
Component: | expander | Version: | 4.6.x |
Keywords: | expander, renamed identifiers | Cc: | |
Estimated difficulty: |
Description
I dug up the old
(let ((a 1)) (letrec-syntax ((foo (syntax-rules () ((_ b) (bar a b)))) (bar (syntax-rules () ((_ c d) (cons c (let ((c 3)) (list d c 'c))))))) (let ((a 2)) (foo a))))
This returns "(1 2 3 a0)" in Chicken. I think there's a missing call to ##sys#strip-syntax somewhere. I haven't looked into the expander code yet, but I wanted to post this so I don't forget.
Attachments (1)
Change History (16)
comment:1 Changed 14 years ago by
comment:2 Changed 14 years ago by
Component: | unknown → expander |
---|
comment:3 Changed 14 years ago by
Here's what I believe to be the equivalent ER macro:
(let ((a 1)) (letrec-syntax ((foo (er-macro-transformer (lambda (x r c) `(,(r 'bar) ,(r 'a) ,(cadr x))))) (bar (er-macro-transformer (lambda (x r c) (let ((c (cadr x)) (d (caddr x))) `(,(r 'cons) ,c (,(r 'let) ((,c 3)) (,(r 'list) ,d ,c ',c)))))))) (let ((a 2)) (t '(1 2 3 a) (foo a)))))
comment:4 Changed 14 years ago by
Just for kicks, the corresponding ir-macro:
(let ((a 1)) (letrec-syntax ((foo (ir-macro-transformer (lambda (x i c) `(bar a ,(cadr x))))) (bar (ir-macro-transformer (lambda (x i c) (let ((c (cadr x)) (d (caddr x))) `(cons ,c (let ((,c 3)) (list ,d ,c ',c)))))))) (let ((a 2)) (foo a))))
All three macros fail, so it's not likely that the bug is in the syntax-rules expander. It's more likely that quote doesn't strip enough syntax. Will investigate further.
comment:5 Changed 14 years ago by
Interestingly, that ER macro returns (1 3 3 a) in MIT-scheme. So I must have made a mistake in the transcription to ER macros or something else is up.
comment:7 Changed 14 years ago by
The correct er-macro:
(let ((a 1)) (letrec-syntax ((foo (er-macro-transformer (lambda (x r c) `(,(r 'bar) ,(r 'a) ,(cadr x))))) (bar (er-macro-transformer (lambda (x r c) (let ((c (cadr x)) (d (caddr x))) `(,(r 'cons) ,(cadr x) (,(r 'let) ((,c 3)) (,(r 'list) ,d ,c ',c)))))))) (let ((a 2)) (foo a))))
This returns (1 2 3 a186)
(still wrong, of course)
I have a feeling that the ir-macro returning the wrong result (1 1 3 a85)
is due to the same error. Not 100% sure yet.
comment:8 Changed 14 years ago by
I prepared a simplified example of what's really happening here:
(let ((a 1)) (let-syntax ((foo (syntax-rules () ((_) (quote a))))) (foo)))
ER version:
(let ((a 1)) (let-syntax ((foo (lambda (x r c) `(quote ,(r 'a))))) (foo)))
Both these examples result in a renamed symbol showing up in the output.
comment:9 Changed 14 years ago by
Priority: | minor → major |
---|
This patch seems to help (at least runs the test-suite). It is incomplete (must be done for all binding forms) and should be refactored (say, a system-function in expand.scm that extends an SE with a given set of aliased variables), but may indicate a solution: the SE of foo
contains (a . a0)
mapping a
to a gensym. At the point where quote
(really: ##core#quote
) strips syntax off the argument form, the mapping of a
to a0
is not available anymore (it exists only inside the static SE of foo
). Here I register the original name on the plist of the generated gensym which will be seen by strip-syntax
. Looks somewhat hackish, but seems to work.
diff --git a/compiler.scm b/compiler.scm index 5ae4664..e198367 100644 --- a/compiler.scm +++ b/compiler.scm @@ -612,6 +612,9 @@ (aliases (map gensym vars)) (se2 (append (map cons vars aliases) se)) ) (set-real-names! aliases vars) + (for-each + (cut ##sys#put! <> '##core#real-name <>) + aliases vars) `(let ,(map (lambda (alias b) (list alias (walk (cadr b) e se (car b) #t)) ) diff --git a/eval.scm b/eval.scm index b531547..12f927b 100644 --- a/eval.scm +++ b/eval.scm @@ -393,6 +393,9 @@ (aliases (map gensym vars)) [e2 (cons aliases e)] (se2 (append (map cons vars aliases) se)) + (_ (for-each + (cut ##sys#put! <> '##core#real-name <>) + aliases vars)) [body (##sys#compile-to-closure (##sys#canonicalize-body (cddr x) se2 #f) e2
Please have a look. If this works, I can try to integrate this in a more cleaner way.
comment:10 Changed 14 years ago by
Fantastic! It works now, and I'm very relieved to see that my gut feeling was correct: the IR macro problem also went away ;)
Now all three examples return (1 2 3 a)!
Here's a patch that adds these bastards to the testsuite.
Changed 14 years ago by
Attachment: | syntax-tests.patch added |
---|
syntax-rules, er-macro and ir-macro versions of Al*'s evil testcase
comment:11 follow-up: 12 Changed 14 years ago by
Why not add this property setting code to gensym? It seems like a useful thing to keep around on all generated symbols, even outside the context of Chicken core.
Here's a silly idea: I don't know how and where gensym is usually used, but I can imagine it might even make sense to have a procedure (original-symbol-name <sym>) which retrieves this property, if available, to "undo" gensym calls. If not available, it would just return its argument unmodified.
comment:12 Changed 14 years ago by
Owner: | set to felix winkelmann |
---|---|
Status: | new → assigned |
Replying to sjamaan:
Why not add this property setting code to gensym? It seems like a useful thing to keep around on all generated symbols, even outside the context of Chicken core.
I don't know. Gensym is used very often, and I'm not sure such a feature would be required very often (the idea has a certain logic to it, yet I can't think of much use that would justify the extra code and memory requirements).
Here's a silly idea: I don't know how and where gensym is usually used, but I can imagine it might even make sense to have a procedure (original-symbol-name <sym>) which retrieves this property, if available, to "undo" gensym calls. If not available, it would just return its argument unmodified.
Hm.
comment:13 Changed 14 years ago by
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
That first line should say:
I dug up the old An Advanced Syntax-Rules Primer for the Mildly Insane by Al* Petrofsky, and found an example on which Chicken fails to expand correctly.
I should get some sleep