Skip to content

Commit

Permalink
Allow GlobalRef and module qualified names in macro definitions (Juli…
Browse files Browse the repository at this point in the history
…aLang#53535)

The following is currently an error:
```
julia> module MyMacroModule
           macro mymacro end
       end
Main.MyMacroModule

julia> macro MyMacroModule.mymacro()
           1
       end
ERROR: syntax: invalid macro definition around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1
```

Discussing with Jeff, we didn't think there was any good reason not to
allow this, just a missing case in lowering. It's probably not
particularly useful (unlike the corresponding case for functions that is
used all the time), but it came up in writing a test case for JuliaLang#53515.
  • Loading branch information
Keno authored and mkitti committed Apr 13, 2024
1 parent 8606ca1 commit 4f96056
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
12 changes: 10 additions & 2 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -2610,15 +2610,23 @@

(define (valid-modref? e)
(and (length= e 3) (eq? (car e) '|.|) (pair? (caddr e))
(eq? (car (caddr e)) 'quote) (symbol? (cadr (caddr e)))
(or (eq? (car (caddr e)) 'quote)
(eq? (car (caddr e)) 'inert))
(symbol? (cadr (caddr e)))
(or (symbol? (cadr e))
(valid-modref? (cadr e)))))

(define (macroify-name e . suffixes)
(cond ((symbol? e) (symbol (apply string #\@ e suffixes)))
((and (pair? e) (eq? (car e) 'quote))
`(quote ,(apply macroify-name (cadr e) suffixes)))
((and (pair? e) (eq? (car e) 'inert))
`(inert ,(apply macroify-name (cadr e) suffixes)))
((globalref? e)
`(globalref ,(cadr e) ,(apply macroify-name (caddr e) suffixes)))
((valid-modref? e)
`(|.| ,(cadr e)
(quote ,(apply macroify-name (cadr (caddr e)) suffixes))))
,(apply macroify-name (caddr e) suffixes)))
(else (error (string "invalid macro usage \"@(" (deparse e) ")\"" )))))

(define (macroify-call s call startloc)
Expand Down
11 changes: 7 additions & 4 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1347,15 +1347,18 @@
(else (error "invalid let syntax"))))
(else (error "invalid let syntax")))))))))

(define (valid-macro-def-name? e)
(or (symbol? e) (valid-modref? e) (globalref? e)))

(define (expand-macro-def e)
(cond ((and (pair? (cadr e))
(eq? (car (cadr e)) 'call)
(symbol? (cadr (cadr e))))
(valid-macro-def-name? (cadr (cadr e))))
(let ((anames (remove-empty-parameters (cddr (cadr e)))))
(if (has-parameters? anames)
(error "macros cannot accept keyword arguments"))
(expand-forms
`(function (call ,(symbol (string #\@ (cadr (cadr e))))
`(function (call ,(macroify-name (cadr (cadr e)))
(|::| __source__ (core LineNumberNode))
(|::| __module__ (core Module))
,@(map (lambda (v)
Expand All @@ -1364,8 +1367,8 @@
v))
anames))
,@(cddr e)))))
((and (length= e 2) (symbol? (cadr e)))
(expand-forms `(function ,(symbol (string #\@ (cadr e))))))
((and (length= e 2) (valid-macro-def-name? (cadr e)))
(expand-forms `(function ,(macroify-name (cadr e)))))
(else
(error "invalid macro definition"))))

Expand Down
13 changes: 13 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3637,3 +3637,16 @@ end
@test array == [7]
@test execs == 4
end

# Allow GlobalRefs in macro definition
module MyMacroModule
macro mymacro end
end
macro MyMacroModule.mymacro()
1
end
@eval macro $(GlobalRef(MyMacroModule, :mymacro))(x)
2
end
@test (@MyMacroModule.mymacro) == 1
@test (@MyMacroModule.mymacro(a)) == 2

0 comments on commit 4f96056

Please sign in to comment.