Open jcubic opened 4 years ago
This macro don't work:
(define-syntax for
(syntax-rules (in as)
((for element in list body ...)
(map (lambda (element)
body ...)
list))
((for list as element body ...)
(for element in list body ...))))
(for '(0 1 2 3 4) as i
(print i))
Because identifiers are not used to match the pattern. The code try to match first pattern so element is a list.
for
macro is working.
Example that don't work (taken from SRFI 46)
(let-syntax
((f (syntax-rules ()
((f ?e)
(let-syntax
((g (syntax-rules ::: ()
((g (??x ?e) (??y :::))
'((??x) ?e (??y) :::)))))
(g (1 2) (3 4)))))))
(f :::))
it should return ((1) 2 (3) (4))
but it return ((#:??x) 2 (3) (4))
SRFI 46 example works.
Two examples that should work:
(define-syntax foo (syntax-rules () ((_ x ...) #(x ...))))
(define-syntax foo (syntax-rules () ((_ #(x y ...)) x)))
There is need to add vector support to syntax-rules.
Another use case nested ellipsis from practical-scheme.net.
(define-syntax ellipsis-test
(syntax-rules ()
[(_ (a (b c ...) ...) ...)
'((a ...)
(((a b) ...) ...)
((((a b c) ...) ...) ...))]))
(ellipsis-test (1 (2 3 4) (5 6)) (7 (8 9 10 11)))
;; ⇒ ((1 7)
;; (((1 2) (1 5)) ((7 8)))
;; ((((1 2 3) (1 2 4)) ((1 5 6))) (((7 8 9) (7 8 10) (7 8 11)))))
NOTE: this is not part of R7RS, can be implemented later.
While debugging SRFI-197 macro, found another example that doesn't work:
(define-syntax foo
(syntax-rules ()
((_)
(let ()
(define-syntax %foo
(syntax-rules (foo bar)
((_ (foo))
(display "foo"))
((_ x)
(display 'x))))
(%foo (10))))))
(foo)
should print (10)
. The problem here are collisions of _
==> foo
in outer syntax that maps into nested _
which is also the name of the identifier. Changing the identifier from foo
to foo_
or nested _
to __
solves the issue.
This one case can be fixed by not matching the first expression in the pattern to identifiers.
Also this:
(define-syntax foo
(syntax-rules ()
((_)
(let ()
(define-syntax %foo
(syntax-rules (foo bar)
((__ (foo))
(print '(foo)))
((__ x)
(print 'x))))
(%foo (foo)))))
prints: (#:foo)
instead of (foo)
.
The problem with SRFI-210 is not about hygiene:
This works fine:
(define-syntax foo
(syntax-rules ()
((_ () ((operand1 arg1) ...))
(let ((arg1 operand1) ...)
(list arg1 ...)))
((_ (operand1 operand2 ...) (temp ...))
(foo (operand2 ...) (temp ... (operand1 arg1))))))
(pprint (macroexpand (foo (10 20) ())))
;; (#:let ((#:arg1 10)
;; (#:arg1 20))
;; (#:list #:arg1 #:arg1))
(print (foo (10 20) ()))
;; => (10 20)
The problem was that identifiers in syntax-rules
were checking the scope if they were not shadowed, but this was wrong. So the code was removed and the unit test updated.
Another problem found from SRFI-210 is this macro:
(define-syntax foo
(syntax-rules ()
((_ (arg more ...))
(letrec-syntax ((aux (syntax-rules ::: ()
((aux () ((operand1 arg1) :::))
(let ((arg1 operand1) :::)
(list arg1 :::)))
((aux (operand1 operand2 :::) (temp :::))
(aux (operand2 :::) (temp ::: (operand1 arg1)))))))
(aux (arg more ...) ())))))
(print (foo (10 20)))
;; ==> (20 20)
Same code with single a syntax-rules
works fine.
This is the limitation of renaming syntax-rules
, I don't think I can fix this. Inside nested syntax rules everything got renamed including nested syntax-rules
so arg1
is renamed before the macro is expended and it got one value.
The whole syntax-rules need to be refactored into a proper scope based system.
Hygienic macro syntax-rules
(x ... ...)
List of issues