Julia:宏如何知道它们的参数何时停止?

Ado*_*uka 5 macros julia

这是一个初学者问题,但我在文档(或 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),)
Run Code Online (Sandbox Code Playgroud)

例如,是否可以将两个连续的 if 块作为单独的参数?

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

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

Bog*_*ski 4

规则为:

@name expr1 expr2 ...
Run Code Online (Sandbox Code Playgroud)

宏调用是一个宏,它会输入所有空格分隔的表达式,直到到达语句末尾。通常,当到达换行符、一个;或其他一些字符(例如])表示语句结束)时,语句就会结束。

以下是一些使用@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)
Run Code Online (Sandbox Code Playgroud)

我认为在上面的例子中,至关重要的是要看到 @a x = 1 y = 2Julia 解析器将其视为x = 1一个整体,尽管之间存在空格,=因为它将其视为单个表达式。

另请注意,您只能将有效表达式提供给宏,例如:

julia> @a =
ERROR: syntax: unexpected "="
Run Code Online (Sandbox Code Playgroud)

失败为:

julia> =
ERROR: syntax: unexpected "="
Run Code Online (Sandbox Code Playgroud)

(这实际上是使用 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)
Run Code Online (Sandbox Code Playgroud)

最后注意:

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
Run Code Online (Sandbox Code Playgroud)

[因为在这种情况下,Julia 会以一种特殊的方式直接@a将一个参数传递给宏来解析宏调用。