Macros 朱莉娅:宏怎么知道它们的参数何时停止?

Macros 朱莉娅:宏怎么知道它们的参数何时停止?,macros,julia,Macros,Julia,这是一个初学者问题,但我在文档(或StackOverflow)中找到答案时遇到了一些困难,我认为这对其他人也有帮助。问题很简单: Julia宏调用如何知道宏的参数何时完成? 当使用括号来标记参数时,应该很简单(我认为…)。然而,在另一种情况下,它似乎更微妙。我怀疑它与“表达式的数量”(这本身可能是一个稍微棘手的概念)有关,但我不确定,我希望有一个正式的规则 我认为这一点不明显的原因如下: julia> macro a(arg...) print(arg) end; julia> @a

这是一个初学者问题,但我在文档(或StackOverflow)中找到答案时遇到了一些困难,我认为这对其他人也有帮助。问题很简单:

Julia宏调用如何知道宏的参数何时完成?

当使用括号来标记参数时,应该很简单(我认为…)。然而,在另一种情况下,它似乎更微妙。我怀疑它与“表达式的数量”(这本身可能是一个稍微棘手的概念)有关,但我不确定,我希望有一个正式的规则

我认为这一点不明显的原因如下:

julia> macro a(arg...)
print(arg)
end;
julia> @a gg=3 if true # the :(gg = 3) is the first argument of the macro
              print("val")
              a = 1;;; # the macro does not see the semicolons (which makes sense to me)
              end  # the if statement is the second argument of the macro
# note: replacing "true" by "@a true" makes the number of arguments of 
# the second macro depend on the following newline being there or not

# next: the first two assignments are two arguments. The last assignment is not an argument at all
julia> @a a = 4 f=3; aaa = "asdf" 

julia> @a af = 4 (f=3; aaa = "asdf") # two arguments; the second one is a quote block
julia> @a af = 4; (f=3; aaa = "asdf") # one argument.

# edit:
julia> @a @a aa # One argument, counterexample to last claim
(:(#= REPL[37]:1 =# @a aa),)
例如,是否可以将两个连续的if块作为单独的参数

我似乎注意到的一条规则是(当不使用括号括参数时),如果宏部分(
@a
)被删除,任何带有多个参数的宏调用都会变成无效语法。一般来说这是真的吗

编辑: 否,请参阅代码段中的反例。

以下规则:

@name expr1 expr2 ...
宏调用是将所有空格分隔的表达式送入宏,直到到达语句末尾。通常情况下,当您到达一个换行符a
时,语句结束
或其他字符,如
]
表示语句结束

下面是一些使用
@a
宏的示例

julia> @a @a aa # here @a aa produces one expression which is passed to outer @a call
(:(#= REPL[37]:1 =# @a aa),)

julia> @a x = 1 y = 2 # two expressions are passed to a macro
(:(x = 1), :(y = 2))

julia> @a x = 1 y = 2; # the same, but we terminated the statement using ;
(:(x = 1), :(y = 2))

julia> @a x = 1 y = 2; 1; # 1 does not go into the macro as ; terminated the statement
(:(x = 1), :(y = 2))

julia> @a (@a x) y # outer @a gets two expressions as we delimited the @a x with parentheses
(:(#= REPL[40]:1 =# @a x), :y)

julia> @a begin
       @a x
       end y # similar but with begin-end block
(quote
    #= REPL[44]:2 =#
    #= REPL[44]:2 =# @a x
end, :y)

julia> @a [@a x] y # this time we used square brackets
(:([#= REPL[39]:1 =# @a(x)]), :y)
我认为在上面的例子中,例如,看到这一点对于我们来说是至关重要的
@a x=1 y=2
Julia解析器将
x=1
视为一个整体,尽管
=
之间有空格,因为它将其视为一个表达式

还请注意,只能将有效表达式的内容馈送到宏,例如:

julia> @a =
ERROR: syntax: unexpected "="
失败原因如下:

julia> =
ERROR: syntax: unexpected "="
(在使用Julia宏设计DSL时,这实际上是一个重要的考虑因素,因为您必须确保所设计的语法包含有效的表达式)

还请注意,宏被馈送到所有空格分隔的表达式,因此这是一个错误:

julia> macro b(x)
       print(x)
       end
@b (macro with 1 method)

julia> @b 1 2
ERROR: LoadError: MethodError: no method matching @b(::LineNumberNode, ::Module, ::Int64, ::Int64)
最后注意:

julia> @a [@a x] y
(:([#= REPL[64]:1 =# @a(x)]), :y)
julia> @a[@a x] y
ERROR: syntax: extra token "y" after end of expression
Julia解析宏调用时,在
[
后面紧跟着
@a
,在这种情况下,它以一种特殊的方式只向宏传递一个参数