Skip to content

Commit 7123a74

Browse files
committed
Allow macrocall as function sig
`@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. The same changes were previously applied in JuliaSyntax.
1 parent 6ac507c commit 7123a74

File tree

4 files changed

+45
-10
lines changed

4 files changed

+45
-10
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ Language changes
5151
* Errors during `getfield` now raise a new `FieldError` exception type instead of the generic
5252
`ErrorException` ([#54504]).
5353

54+
- Macros in function-signature-position no longer require parentheses. E.g. `function @main(args) ... end` is now permitted,
55+
whereas `function (@main)(args) ... end` was required in prior Julia versions.
56+
5457
Compiler/Runtime improvements
5558
-----------------------------
5659

base/client.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ The `@main` macro may be used standalone or as part of the function definition,
606606
case, parentheses are required. In particular, the following are equivalent:
607607
608608
```
609-
function (@main)(args)
609+
function @main(args)
610610
println("Hello World")
611611
end
612612
```
@@ -625,7 +625,7 @@ imported into `Main`, it will be treated as an entrypoint in `Main`:
625625
```
626626
module MyApp
627627
export main
628-
(@main)(args) = println("Hello World")
628+
@main(args) = println("Hello World")
629629
end
630630
using .MyApp
631631
# `julia` Will execute MyApp.main at the conclusion of script execution
@@ -635,7 +635,7 @@ Note that in particular, the semantics do not attach to the method
635635
or the name:
636636
```
637637
module MyApp
638-
(@main)(args) = println("Hello World")
638+
@main(args) = println("Hello World")
639639
end
640640
const main = MyApp.main
641641
# `julia` Will *NOT* execute MyApp.main unless there is a separate `@main` annotation in `Main`
@@ -645,9 +645,6 @@ const main = MyApp.main
645645
This macro is new in Julia 1.11. At present, the precise semantics of `@main` are still subject to change.
646646
"""
647647
macro main(args...)
648-
if !isempty(args)
649-
error("`@main` is expected to be used as `(@main)` without macro arguments.")
650-
end
651648
if isdefined(__module__, :main)
652649
if Base.binding_module(__module__, :main) !== __module__
653650
error("Symbol `main` is already a resolved import in module $(__module__). `@main` must be used in the defining module.")
@@ -658,5 +655,9 @@ macro main(args...)
658655
global main
659656
global var"#__main_is_entrypoint__#"::Bool = true
660657
end)
661-
esc(:main)
658+
if !isempty(args)
659+
Expr(:call, esc(:main), map(esc, args)...)
660+
else
661+
esc(:main)
662+
end
662663
end

src/julia-parser.scm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,13 +1329,13 @@
13291329

13301330
(define (valid-func-sig? paren sig)
13311331
(and (pair? sig)
1332-
(or (eq? (car sig) 'call)
1333-
(eq? (car sig) 'tuple)
1332+
(or (memq (car sig) '(call tuple))
1333+
(and (not paren) (eq? (car sig) 'macrocall))
13341334
(and paren (eq? (car sig) 'block))
13351335
(and paren (eq? (car sig) '...))
13361336
(and (eq? (car sig) '|::|)
13371337
(pair? (cadr sig))
1338-
(eq? (car (cadr sig)) 'call))
1338+
(memq (car (cadr sig)) '(call macrocall)))
13391339
(and (eq? (car sig) 'where)
13401340
(valid-func-sig? paren (cadr sig))))))
13411341

test/syntax.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4046,3 +4046,34 @@ function fs56711()
40464046
return f
40474047
end
40484048
@test !@isdefined(x_should_not_be_defined)
4049+
4050+
# PR# 55040 - Macrocall as function sig
4051+
@test :(function @f()() end) == :(function (@f)() end)
4052+
4053+
function callme end
4054+
macro callmemacro(args...)
4055+
Expr(:call, esc(:callme), map(esc, args)...)
4056+
end
4057+
function @callmemacro(a::Int)
4058+
return 1
4059+
end
4060+
@callmemacro(b::Float64) = 2
4061+
function @callmemacro(a::T, b::T) where T <: Int64
4062+
return 3
4063+
end
4064+
function @callmemacro(a::Int, b::Int, c::Int)::Float64
4065+
return 4
4066+
end
4067+
function @callmemacro(d::String)
4068+
(a, b, c)
4069+
# ^ Should not be accidentally parsed as an argument list
4070+
return 4
4071+
end
4072+
4073+
@test callme(1) === 1
4074+
@test callme(2.0) === 2
4075+
@test callme(3, 3) === 3
4076+
@test callme(4, 4, 4) === 4.0
4077+
4078+
# Ambiguous 1-arg anymous vs macrosig
4079+
@test_parseerror "function (@foo(a)) end"

0 commit comments

Comments
 (0)