-
Notifications
You must be signed in to change notification settings - Fork 0
Macro
-include_lib("astranaut/include/macro.hrl").
macro.hrl add three attribute: use_macro, exec_macro debug_macro
use_macro
-use_macro({Macro/A, opts()}).
-use_macro({Module, Macro/A, opts()}).
exec_macro
execute macro and add result to current ast.
-exec_macro({Macro, Arguments}).
-exec_macro({Module, Macro, Arguments}).
export_macro
used in where macro defined, options in export_macro will be merged to options in use_macro.
-export_macro({[MacroA/A, MacroB/B], opts()}).
debug_macro
-debug_macro(true).
module will be printed to console after astranaut_macro transform.
opts()
#{debug => Debug, debug_ast => DebugAst, alias => Alias,
formatter => Formatter, attrs => Attrs, order => Order,
as_attr => AsAttr, merge_function => MergeFunction, auto_export => AutoExport,
group_args => GroupArgs}
}
opts() could also be proplists, same usage of map().
Debug
print code generated when macro called compile time.
DebugAst
print ast generated when macro called compile time.
Alias
use Alias(Arguments) instead of Module:Macro(Arguments).
Formatter
module include format_error/1 to format macro errors,
if formatter is true, formatter is the module where macro defined,
default is astranaut_traverse.
Attrs
module attributes as extra args while calling macro.
-module(a).
-behaviour(gen_server).
-use_macro({macro/2, [{attrs, [module, line, behaviour]}]}).
hello() ->
macro_a:macro(world).
macro(Ast, #{module => Module, line => Line, behaviour => Behaviours} = Attributes) ->
{warning, Ast, {attributes, Module, Line, Behaviours}}.
Order
macro expand order for nested macro , value is pre | post. default is post.
pre is expand macro from outside to inside, post is expand macro from inside to outside.
AsAttr
user defined attribute name replace of -exec_macro.
MergeFunction
-exec_macro ast function merge to function with same name and arity if exists.
AutoExport
-exec_macro ast function auto export, merge to current export if exists.
GroupArgs
treat macro arguments as list
-use_macro({a, [group_args]}).
test() ->
a(hello, world).
a(Asts) ->
quote({unquote_splicing(Asts)}).
define macro as normal erlang functions.
macro expand order is the order of -use_macro in file.
macro will be expand at compile time by parse_transformer astranaut_macro.
macro does not know runtime value of arguments.
arguments passed in macro is erlang ast.
arguments passed in -exec_macro is term.
-export will be moved to appropriate location in ast forms.
macro return value is same meaning of traverse_fun_return().
-use_macro({macro_1/1, []}).
-use_macro({macro_2/1, []}).
-export([test/0]).
test() ->
macro_1(hello()).
macro_1(Ast) ->
quote(
fun() -> unquote(Ast) end
).
-exec_macro({macro_2, [hello]}).
macro_2(Name) ->
astranaut:function(
Name,
quote(
fun() ->
unquote_atom(Name)
end)).
=>
-use_macro({macro_1/1, []}).
-export([test/0]).
-export([hello/0]).
test_macro_1() ->
fun() -> hello() end.
macro_1(Ast) ->
quote(
fun() -> unquote(Ast) end
).
hello() ->
hello.
macro_2(Name) ->
astranaut:function(
Name,
quote(
fun() ->
unquote_atom(Name)
end)).
each macro expansion has it's unique namespace.
@{macro_module_name}@_{counter} is added to it's original name.
-module(macro_example).
macro_with_vars_1(Ast) ->
quote(
begin
A = 10,
B = unquote(Ast),
A + B
end
).
macro_with_vars_2(Ast) ->
quote(
begin
A = 10,
B = unquote(Ast),
A + B
end
).
test_macro_with_vars(N) ->
A1 = macro_with_vars_1(N),
A2 = macro_with_vars_2(A1),
A3 = macro_with_vars_2(N),
A4 = macro_with_vars_1(A1),
A1 + A2.
=>
test_macro_with_vars(N) ->
A1 =
begin
A@macro_example@_1 = 10,
B@macro_example@_1 = N,
A@macro_example@_1 + B@macro_example@_1
end,
A2 =
begin
A@macro_example@_3 = 10,
B@macro_example@_3 = A1,
A@macro_example@_3 + B@macro_example@_3
end,
A3 =
begin
A@macro_example@_4 = 10,
B@macro_example@_4 = N,
A@macro_example@_4 + B@macro_example@_4
end,
A4 =
begin
A@macro_example@_2 = 10,
B@macro_example@_2 = A1,
A@macro_example@_2 + B@macro_example@_2
end,
A1 + A2 + A3 + A4.
for old parse_transform module which is used widely, two function is provided.
*astranaut_macro:transform_macro(Module, Function, Arity, Opts, Forms).
*astranaut_macro:transform_macros([Macro...], Forms).
Macro = {Module, Function, Arity, Opts}.
example:
-module(do).
-include_lib("astranaut/include/quote.hrl").
-export([parse_transform/2]).
parse_transform(Forms, _Options) ->
astranaut_macro:transform_macro(do_macro, do, 1, [{alias, do}, formatter], Forms).