-
Notifications
You must be signed in to change notification settings - Fork 0
Quote
with
-include_lib("astranaut/include/quote.hrl").
you can use quote(Code) to represent ast of the code.
quote(Code) | quote(Code, Options)
Options
atom() => {atom() => true}
proplists() => map(),
Line => #{line => Line}
#{line => Line, code_line => CodeLine, debug => Debug}.
Line
Line could be any expression, the ast will be transformed.
quote(
fun(_) ->
ok
end, 10).
=>
astranaut:replace_line_zero(quote(fun(_) -> ok end), 10).
=>
{'fun', 10, {clauses, [{clause, 10, [{var, 10, '_'}], [], [{atom, 10, ok}]}]}}.
CodeLine
if CodeLine is true
10: quote(
11: fun(_) ->
12: ok
13: end, code_line).
=>
{'fun' 10, {clauses, [{clause, 11, [{var, 11, '_'}], [], [{atom, 12, ok}]}]}}.
Debug
if Debug is true, ast generated by quote will be printed to console at compile time.
unquote(Ast)
unquote = Ast.
unquote_splicing(Asts)
unquote_splicing = Asts.
why two forms
unquote(Var) is not a valid ast in function clause pattern.
Var = {var, 0, A}
quote(fun(unquote = Var) -> unquote(Var) end).
bind one ast
_@V, same as unquote(V)
V = {var, 10, 'Var'},
quote({hello, World, unquote(V)}) =>
{tuple, 1, [{atom, 1, hello}, {var, 1, 'World'}, V]} =>
{tuple, 1, [{atom, 1, hello}, {var, 1, 'World'}, {var, 10, 'Var'}]}
bind a list of ast
_L@Vs,same as unquote_splicing(Vs)
Vs = [{var, 2, 'Var'}, {atom, 2, atom}],
quote({A, unquote_splicing(Vs), B}) =>
{tuple, 1, [{var, 1, 'A'}, Vs ++ [{var, 1, 'B'}]]} =>
{tuple, 1, [{var, 1, 'A'}, {var, 2, 'Var'}, {atom, 2, atom}, {var, 1, 'B'}]}
bind a value
Atom = hello,
Integer = 10,
Float = 1.3,
String = "123",
Variable = 'Var',
_A@Atom => {atom, 0, Atom} => {atom, 0, hello}
_I@Integer => {integer, 0, Integer} => {integer, 0, 10}
_F@Float => {float, 0, Float} => {float, 0, 1.3}
_S@String => {string, 0, String} => {string, 0, "123"}
_V@Variable => {var, 0, Variable} => {var, 0, 'Var'}
why binding
_X@V could be used in any part of quoted ast.
it's legal:
Class = 'Class0',
Exception = 'Exception0',
StackTrace = 'StackTrace0',
quote(
try
throw(hello)
catch
_V@Class:_V@Exception:_V@StackTrace ->
erlang:raise(_V@Class, _V@Exception, _V@StackTrace)
end).
it's illegal
Class = {var, 0, 'Class0'},
Exception = {var, 0, 'Exception0'},
StackTrace = {var, 0, 'StackTrace0'},
quote(
try
A
catch
unquote(Class):unquote(Exception):unquote(StackTrace) ->
erlang:raise(_@Class, _@Exception, _@StackTrace)
end).
in other hand, V in unquote_xxx(V) could be any expression, it's more powerful than _X@V
quote macro could also be used in pattern match such as
for limit of erlang ast format in pattern, some special forms is used
left side of match
quote(_A@Atom) = {atom, 1, A}
=>
{atom, _, Atom} = {atom, 1, A}
function pattern
macro_clause(quote = {hello, _A@World = World2} = C) ->
quote({hello2, _A@World, _@World2,_@C});
=>
macro_clause({tuple, _, [{atom, _, hello}, {atom, _, World} = World2]} = C) ->
{tuple, 2, {atom, 2, hello2}, {atom, 2, World}, World2, C}
case clause pattern:
case Ast of
quote(_A@Atom) ->
Atom;
_ ->
other
end.
=>
case ast of
{atom, _, Atom} ->
Atom;
_ ->
other
end.