Skip to content

Commit

Permalink
RFC: Allow macrocall as function sig
Browse files Browse the repository at this point in the history
@KristofferC requested that `function @main(args) end` should work.
This is currently a parse error. This PR makes it work as expected
by allowing macrocall as a valid signature in function (needs
to exapand to a call expr). Note that this is only the flisp changes.
If this PR is accepted, an equivalent change would need to be made
in JuliaSyntax.
  • Loading branch information
Keno committed Jul 25, 2024
1 parent bbb4403 commit 0029ab6
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
15 changes: 8 additions & 7 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ The `@main` macro may be used standalone or as part of the function definition,
case, parentheses are required. In particular, the following are equivalent:
```
function (@main)(args)
function @main(args)
println("Hello World")
end
```
Expand All @@ -618,7 +618,7 @@ imported into `Main`, it will be treated as an entrypoint in `Main`:
```
module MyApp
export main
(@main)(args) = println("Hello World")
@main(args) = println("Hello World")
end
using .MyApp
# `julia` Will execute MyApp.main at the conclusion of script execution
Expand All @@ -628,7 +628,7 @@ Note that in particular, the semantics do not attach to the method
or the name:
```
module MyApp
(@main)(args) = println("Hello World")
@main(args) = println("Hello World")
end
const main = MyApp.main
# `julia` Will *NOT* execute MyApp.main unless there is a separate `@main` annotation in `Main`
Expand All @@ -638,9 +638,6 @@ const main = MyApp.main
This macro is new in Julia 1.11. At present, the precise semantics of `@main` are still subject to change.
"""
macro main(args...)
if !isempty(args)
error("`@main` is expected to be used as `(@main)` without macro arguments.")
end
if isdefined(__module__, :main)
if Base.binding_module(__module__, :main) !== __module__
error("Symbol `main` is already a resolved import in module $(__module__). `@main` must be used in the defining module.")
Expand All @@ -651,5 +648,9 @@ macro main(args...)
global main
global var"#__main_is_entrypoint__#"::Bool = true
end)
esc(:main)
if !isempty(args)
Expr(:call, esc(:main), map(esc, args)...)
else
esc(:main)
end
end
5 changes: 2 additions & 3 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1329,13 +1329,12 @@

(define (valid-func-sig? paren sig)
(and (pair? sig)
(or (eq? (car sig) 'call)
(eq? (car sig) 'tuple)
(or (memq (car sig) '(macrocall call tuple))
(and paren (eq? (car sig) 'block))
(and paren (eq? (car sig) '...))
(and (eq? (car sig) '|::|)
(pair? (cadr sig))
(eq? (car (cadr sig)) 'call))
(memq (car (cadr sig)) '(call macrocall)))
(and (eq? (car sig) 'where)
(valid-func-sig? paren (cadr sig))))))

Expand Down
28 changes: 28 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3904,3 +3904,31 @@ module ExtendedIsDefined
@test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x4), false))
end
end

# PR# 55040 - Macrocall as function sig
@test :(function @f()() end) == :(function (@f)() end)

function callme end
macro callmemacro(args...)
Expr(:call, esc(:callme), map(esc, args)...)
end
function @callmemacro(a::Int)
return 1
end
@callmemacro(b::Float64) = 2
function @callmemacro(a::T, b::T) where T <: Int64
return 3
end
function @callmemacro(a::Int, b::Int, c::Int)::Float64
return 4
end
function @callmemacro(d::String)
(a, b, c)
# ^ Should not be accidentally parsed as an argument list
return 4
end

@test callme(1) === 1
@test callme(2.0) === 2
@test callme(3, 3) === 3
@test callme(4, 4, 4) === 4.0

0 comments on commit 0029ab6

Please sign in to comment.