Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hygienic macro syntax-rules #43

Open
26 of 39 tasks
jcubic opened this issue Apr 16, 2020 · 11 comments
Open
26 of 39 tasks

Hygienic macro syntax-rules #43

jcubic opened this issue Apr 16, 2020 · 11 comments
Labels
enhancement New feature or request
Milestone

Comments

@jcubic
Copy link
Owner

jcubic commented Apr 16, 2020

Hygienic macro syntax-rules

  • Handling of ellipsis.
  • Handling identifiers.
  • Proper macro expand.
  • Ellipsis alias (nested syntax-rules).
  • Proper working identifiers
  • Matching literal atoms
  • Matching symbol as last cdr in pattern
  • Spread ellipsis (x ... ...)
  • SRFI 46 (named ellipsis)
  • vectors
    • pattern
    • template
  • objects
    • pattern
    • template
  • Example Usage:
    • SRFI 26
    • SRFI 156
    • define-values from R7RS spec
    • SRFI 197
    • SRFI 210
    • SRFI 239
    • R6RS do macro
    • Gauche ellipsis test from (SRFI-149)
  • Ellipsis (pattern language) extensions from R7RS
    • Escape ellipsis

List of issues

@jcubic jcubic added the enhancement New feature or request label Apr 16, 2020
@jcubic jcubic added this to the 1.0 milestone Apr 16, 2020
jcubic added a commit that referenced this issue Apr 26, 2020
jcubic added a commit that referenced this issue Aug 19, 2020
syntax-rules to transform (a b ...) on single item
fix repr of (cons 1 undefined)
@jcubic
Copy link
Owner Author

jcubic commented Aug 19, 2020

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.

@jcubic
Copy link
Owner Author

jcubic commented Aug 20, 2020

for macro is working.

@jcubic
Copy link
Owner Author

jcubic commented Aug 22, 2020

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))

jcubic added a commit that referenced this issue Aug 22, 2020
jcubic added a commit that referenced this issue Aug 22, 2020
jcubic added a commit that referenced this issue Aug 22, 2020
jcubic added a commit that referenced this issue Sep 17, 2020
throw exception when invoking syntax that shadow literal identifier
jcubic added a commit that referenced this issue Sep 17, 2020
jcubic added a commit that referenced this issue Sep 17, 2020
@jcubic
Copy link
Owner Author

jcubic commented Nov 6, 2020

SRFI 46 example works.

jcubic added a commit that referenced this issue Nov 8, 2020
The problem was identifiers definition get expanded into values from parent syntax-rules
jcubic added a commit that referenced this issue Nov 27, 2020
Fix case when there is list and first item in user code is nil
When the user code is in ellipsis processing and there is next item
There is need to be list where first item need to be nil.
@jcubic
Copy link
Owner Author

jcubic commented Dec 1, 2020

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.

@jcubic
Copy link
Owner Author

jcubic commented Dec 5, 2020

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.

@jcubic
Copy link
Owner Author

jcubic commented Dec 7, 2020

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).

@jcubic
Copy link
Owner Author

jcubic commented Jan 24, 2024

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)

@jcubic
Copy link
Owner Author

jcubic commented Jan 24, 2024

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.

@jcubic
Copy link
Owner Author

jcubic commented Jan 24, 2024

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.

@jcubic
Copy link
Owner Author

jcubic commented Jan 24, 2024

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.

jcubic added a commit that referenced this issue Jan 24, 2024
jcubic added a commit that referenced this issue Jan 25, 2024
jcubic added a commit that referenced this issue Jan 25, 2024
Fix case with spread and tail (x ... . x) matched against (x y . z)
jcubic added a commit that referenced this issue Jan 25, 2024
jcubic added a commit that referenced this issue Jan 30, 2024
jcubic added a commit that referenced this issue Feb 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant