1-module(elixir_quote).
2-export([escape/3, linify/3, linify_with_context_counter/3, build/6, quote/6, has_unquotes/1, fun_to_quoted/1]).
3-export([dot/5, tail_list/3, list/2, validate_runtime/2]). %% Quote callbacks
4
5-include("elixir.hrl").
6-define(defs(Kind), Kind == def; Kind == defp; Kind == defmacro; Kind == defmacrop; Kind == '@').
7-define(lexical(Kind), Kind == import; Kind == alias; Kind == require).
8-compile({inline, [keyfind/2, keystore/3, keydelete/2, keynew/3, do_tuple_linify/5]}).
9
10-record(elixir_quote, {
11  line=false,
12  file=nil,
13  context=nil,
14  vars_hygiene=true,
15  aliases_hygiene=true,
16  imports_hygiene=true,
17  unquote=true,
18  generated=false
19}).
20
21build(Meta, Line, File, Context, Unquote, Generated) ->
22  Acc0 = [],
23  {ELine, Acc1} = validate_compile(Meta, line, Line, Acc0),
24  {EFile, Acc2} = validate_compile(Meta, file, File, Acc1),
25  {EContext, Acc3} = validate_compile(Meta, context, Context, Acc2),
26  validate_runtime(unquote, Unquote),
27  validate_runtime(generated, Generated),
28
29  Q = #elixir_quote{
30    line=ELine,
31    file=EFile,
32    unquote=Unquote,
33    context=EContext,
34    generated=Generated
35  },
36
37  {Q, Acc3}.
38
39validate_compile(_Meta, line, Value, Acc) when is_boolean(Value) ->
40  {Value, Acc};
41validate_compile(_Meta, file, nil, Acc) ->
42  {nil, Acc};
43validate_compile(Meta, Key, Value, Acc) ->
44  case is_valid(Key, Value) of
45    true ->
46      {Value, Acc};
47    false ->
48      Var = {Key, Meta, ?MODULE},
49      Call = {{'.', Meta, [?MODULE, validate_runtime]}, Meta, [Key, Value]},
50      {Var, [{'=', Meta, [Var, Call]} | Acc]}
51  end.
52
53validate_runtime(Key, Value) ->
54  case is_valid(Key, Value) of
55    true ->
56      Value;
57
58    false ->
59      erlang:error(
60        'Elixir.ArgumentError':exception(
61          <<"invalid runtime value for option :", (erlang:atom_to_binary(Key, utf8))/binary,
62            " in quote, got: ", ('Elixir.Kernel':inspect(Value))/binary>>
63        )
64      )
65  end.
66
67is_valid(line, Line) -> is_integer(Line);
68is_valid(file, File) -> is_binary(File);
69is_valid(context, Context) -> is_atom(Context) andalso (Context /= nil);
70is_valid(generated, Generated) -> is_boolean(Generated);
71is_valid(unquote, Unquote) -> is_boolean(Unquote).
72
73%% Apply the line from site call on quoted contents.
74%% Receives a Key to look for the default line as argument.
75linify(0, _Key, Exprs) ->
76  Exprs;
77linify(Line, Key, Exprs) when is_integer(Line) ->
78  LinifyMeta = linify_meta(Line, Key),
79  do_linify(LinifyMeta, Exprs, nil).
80
81%% Same as linify but also considers the context counter.
82linify_with_context_counter(Line, Var, Exprs) when is_integer(Line) ->
83  LinifyMeta = linify_meta(Line, line),
84  do_linify(LinifyMeta, Exprs, Var).
85
86do_linify(LinifyMeta, {quote, Meta, [_ | _] = Args}, {Receiver, Counter} = Var)
87    when is_list(Meta) ->
88  NewMeta =
89    case keyfind(context, Meta) == {context, Receiver} of
90      true -> keynew(counter, Meta, Counter);
91      false -> Meta
92    end,
93  do_tuple_linify(LinifyMeta, NewMeta, quote, Args, Var);
94
95do_linify(LinifyMeta, {Left, Meta, Receiver}, {Receiver, Counter} = Var)
96    when is_atom(Left), is_list(Meta), Left /= '_' ->
97  do_tuple_linify(LinifyMeta, keynew(counter, Meta, Counter), Left, Receiver, Var);
98
99do_linify(LinifyMeta, {Lexical, Meta, [_ | _] = Args}, {_, Counter} = Var)
100    when ?lexical(Lexical); Lexical == '__aliases__' ->
101  do_tuple_linify(LinifyMeta, keynew(counter, Meta, Counter), Lexical, Args, Var);
102
103do_linify(LinifyMeta, {Left, Meta, Right}, Var) when is_list(Meta) ->
104  do_tuple_linify(LinifyMeta, Meta, Left, Right, Var);
105
106do_linify(LinifyMeta, {Left, Right}, Var) ->
107  {do_linify(LinifyMeta, Left, Var), do_linify(LinifyMeta, Right, Var)};
108
109do_linify(LinifyMeta, List, Var) when is_list(List) ->
110  [do_linify(LinifyMeta, X, Var) || X <- List];
111
112do_linify(_, Else, _) -> Else.
113
114do_tuple_linify(LinifyMeta, Meta, Left, Right, Var) ->
115  {do_linify(LinifyMeta, Left, Var), LinifyMeta(Meta), do_linify(LinifyMeta, Right, Var)}.
116
117linify_meta(0, line) -> fun(Meta) -> Meta end;
118linify_meta(Line, line) -> fun(Meta) -> keynew(line, Meta, Line) end;
119linify_meta(Line, keep) ->
120  fun(Meta) ->
121    case lists:keytake(keep, 1, Meta) of
122      {value, {keep, {_, Int}}, MetaNoFile} ->
123        [{line, Int} | keydelete(line, MetaNoFile)];
124      _ ->
125        keynew(line, Meta, Line)
126    end
127  end.
128
129%% Some expressions cannot be unquoted at compilation time.
130%% This function is responsible for doing runtime unquoting.
131dot(Meta, Left, Right, Args, Context) ->
132  annotate(dot(Meta, Left, Right, Args), Context).
133
134dot(Meta, Left, {'__aliases__', _, Args}, nil) ->
135  {'__aliases__', Meta, [Left | Args]};
136
137dot(Meta, Left, Right, nil) when is_atom(Right) ->
138  case atom_to_list(Right) of
139    "Elixir." ++ _ ->
140      {'__aliases__', Meta, [Left, Right]};
141    _ ->
142      {{'.', Meta, [Left, Right]}, [{no_parens, true} | Meta], []}
143  end;
144
145dot(Meta, Left, {Right, _, Context}, nil) when is_atom(Right), is_atom(Context) ->
146  {{'.', Meta, [Left, Right]}, [{no_parens, true} | Meta], []};
147
148dot(Meta, Left, {Right, _, Args}, nil) when is_atom(Right) ->
149  {{'.', Meta, [Left, Right]}, Meta, Args};
150
151dot(_Meta, _Left, Right, nil) ->
152  argument_error(<<"expected unquote after dot to return an atom, an alias or a quoted call, got: ",
153                   ('Elixir.Macro':to_string(Right))/binary>>);
154
155dot(Meta, Left, Right, Args) when is_atom(Right) ->
156  {{'.', Meta, [Left, Right]}, Meta, Args};
157
158dot(Meta, Left, {Right, _, Context}, Args) when is_atom(Right), is_atom(Context) ->
159  {{'.', Meta, [Left, Right]}, Meta, Args};
160
161dot(_Meta, _Left, Right, _Args) ->
162  argument_error(<<"expected unquote after dot with args to return an atom or a quoted call, got: ",
163                   ('Elixir.Macro':to_string(Right))/binary>>).
164
165list(Left, Right) when is_list(Right) ->
166  validate_list(Left),
167  Left ++ Right.
168
169tail_list(Left, Right, Tail) when is_list(Right), is_list(Tail) ->
170  validate_list(Left),
171  Tail ++ Left ++ Right;
172
173tail_list(Left, Right, Tail) when is_list(Left) ->
174  validate_list(Left),
175  [H | T] = lists:reverse(Tail ++ Left),
176  lists:reverse([{'|', [], [H, Right]} | T]).
177
178validate_list(List) when is_list(List) ->
179  ok;
180validate_list(List) when not is_list(List) ->
181  argument_error(<<"expected a list with quoted expressions in unquote_splicing/1, got: ",
182                   ('Elixir.Kernel':inspect(List))/binary>>).
183
184argument_error(Message) ->
185  error('Elixir.ArgumentError':exception([{message, Message}])).
186
187%% Annotates the AST with context and other info.
188%%
189%% Note we need to delete the counter because linify
190%% adds the counter recursively, even inside quoted
191%% expressions, so we need to clean up the forms to
192%% allow them to get a new counter on the next expansion.
193
194annotate({Def, Meta, [{H, M, A} | T]}, Context) when ?defs(Def) ->
195  {Def, Meta, [{H, keystore(context, M, Context), A} | T]};
196annotate({{'.', _, [_, Def]} = Target, Meta, [{H, M, A} | T]}, Context) when ?defs(Def) ->
197  {Target, Meta, [{H, keystore(context, M, Context), A} | T]};
198
199annotate({Lexical, Meta, [_ | _] = Args}, Context) when ?lexical(Lexical) ->
200  NewMeta = keystore(context, keydelete(counter, Meta), Context),
201  {Lexical, NewMeta, Args};
202annotate(Tree, _Context) -> Tree.
203
204has_unquotes({unquote, _, [_]}) -> true;
205has_unquotes({unquote_splicing, _, [_]}) -> true;
206has_unquotes({{'.', _, [_, unquote]}, _, [_]}) -> true;
207has_unquotes({Var, _, Ctx}) when is_atom(Var), is_atom(Ctx) -> false;
208has_unquotes({Name, _, Args}) when is_list(Args) ->
209  has_unquotes(Name) orelse lists:any(fun has_unquotes/1, Args);
210has_unquotes({Left, Right}) ->
211  has_unquotes(Left) orelse has_unquotes(Right);
212has_unquotes(List) when is_list(List) ->
213  lists:any(fun has_unquotes/1, List);
214has_unquotes(_Other) -> false.
215
216%% Escapes the given expression. It is similar to quote, but
217%% lines are kept and hygiene mechanisms are disabled.
218escape(Expr, Kind, Unquote) ->
219  do_quote(Expr, #elixir_quote{
220    line=true,
221    file=nil,
222    vars_hygiene=false,
223    aliases_hygiene=false,
224    imports_hygiene=false,
225    unquote=Unquote
226  }, Kind).
227
228%% fun_to_quoted
229
230fun_to_quoted(Function) ->
231  Meta = [],
232  {module, Module} = erlang:fun_info(Function, module),
233  {name, Name}     = erlang:fun_info(Function, name),
234  {arity, Arity}   = erlang:fun_info(Function, arity),
235  {'&', Meta, [{'/', Meta, [{{'.', Meta, [Module, Name]}, [{no_parens, true} | Meta], []}, Arity]}]}.
236
237%% Quotes an expression and return its quoted Elixir AST.
238
239quote(_Meta, {unquote_splicing, _, [_]}, _Binding, #elixir_quote{unquote=true}, _, _) ->
240  argument_error(<<"unquote_splicing only works inside arguments and block contexts, "
241    "wrap it in parens if you want it to work with one-liners">>);
242
243quote(Meta, Expr, Binding, Q, Prelude, E) ->
244  Context = Q#elixir_quote.context,
245
246  Vars = [{'{}', [],
247    ['=', [], [
248      {'{}', [], [K, Meta, Context]},
249      V
250    ]]
251  } || {K, V} <- Binding],
252
253  Quoted = do_quote(Expr, Q, E),
254
255  WithVars = case Vars of
256    [] -> Quoted;
257    _ -> {'{}', [], ['__block__', [], Vars ++ [Quoted]]}
258  end,
259
260  case Prelude of
261    [] -> WithVars;
262    _ -> {'__block__', [], Prelude ++ [WithVars]}
263  end.
264
265%% Actual quoting and helpers
266
267do_quote({quote, Meta, [Arg]}, Q, E) ->
268  TArg = do_quote(Arg, Q#elixir_quote{unquote=false}, E),
269
270  NewMeta = case Q of
271    #elixir_quote{vars_hygiene=true, context=Context} -> keystore(context, Meta, Context);
272    _ -> Meta
273  end,
274
275  {'{}', [], [quote, meta(NewMeta, Q), [TArg]]};
276
277do_quote({quote, Meta, [Opts, Arg]}, Q, E) ->
278  TOpts = do_quote(Opts, Q, E),
279  TArg = do_quote(Arg, Q#elixir_quote{unquote=false}, E),
280
281  NewMeta = case Q of
282    #elixir_quote{vars_hygiene=true, context=Context} -> keystore(context, Meta, Context);
283    _ -> Meta
284  end,
285
286  {'{}', [], [quote, meta(NewMeta, Q), [TOpts, TArg]]};
287
288do_quote({unquote, _Meta, [Expr]}, #elixir_quote{unquote=true}, _) ->
289  Expr;
290
291%% Aliases
292
293do_quote({'__aliases__', Meta, [H | T]} = Alias, #elixir_quote{aliases_hygiene=true} = Q, E) when is_atom(H) and (H /= 'Elixir') ->
294  Annotation =
295    case elixir_aliases:expand(Alias, E) of
296      Atom when is_atom(Atom) -> Atom;
297      Aliases when is_list(Aliases) -> false
298    end,
299  AliasMeta = keystore(alias, keydelete(counter, Meta), Annotation),
300  do_quote_tuple('__aliases__', AliasMeta, [H | T], Q, E);
301
302%% Vars
303
304do_quote({Name, Meta, nil}, #elixir_quote{vars_hygiene=true, imports_hygiene=true} = Q, E) when is_atom(Name) ->
305  ImportMeta = import_meta(Meta, Name, 0, Q, E),
306  {'{}', [], [Name, meta(ImportMeta, Q), Q#elixir_quote.context]};
307
308do_quote({Name, Meta, nil}, #elixir_quote{vars_hygiene=true} = Q, _E) when is_atom(Name) ->
309  {'{}', [], [Name, meta(Meta, Q), Q#elixir_quote.context]};
310
311%% Unquote
312
313do_quote({{{'.', Meta, [Left, unquote]}, _, [Expr]}, _, Args}, #elixir_quote{unquote=true} = Q, E) ->
314  do_quote_call(Left, Meta, Expr, Args, Q, E);
315
316do_quote({{'.', Meta, [Left, unquote]}, _, [Expr]}, #elixir_quote{unquote=true} = Q, E) ->
317  do_quote_call(Left, Meta, Expr, nil, Q, E);
318
319%% Imports
320
321do_quote({'&', Meta, [{'/', _, [{F, _, C}, A]}] = Args},
322         #elixir_quote{imports_hygiene=true} = Q, E) when is_atom(F), is_integer(A), is_atom(C) ->
323  do_quote_fa('&', Meta, Args, F, A, Q, E);
324
325do_quote({Name, Meta, Args}, #elixir_quote{imports_hygiene=true} = Q, E) when is_atom(Name), is_list(Args) ->
326  do_quote_import(Meta, Name, length(Args), Args, Q, E);
327
328do_quote({Name, Meta, Context}, #elixir_quote{imports_hygiene=true} = Q, E) when is_atom(Name), is_atom(Context) ->
329  do_quote_import(Meta, Name, 0, Context, Q, E);
330
331%% Two-element tuples
332
333do_quote({Left, Right}, #elixir_quote{unquote=true} = Q, E) when
334    is_tuple(Left)  andalso (element(1, Left) == unquote_splicing);
335    is_tuple(Right) andalso (element(1, Right) == unquote_splicing) ->
336  do_quote({'{}', [], [Left, Right]}, Q, E);
337
338do_quote({Left, Right}, Q, E) ->
339  TLeft  = do_quote(Left, Q, E),
340  TRight = do_quote(Right, Q, E),
341  {TLeft, TRight};
342
343%% Everything else
344
345do_quote(Other, Q, E) when is_atom(E) ->
346  do_escape(Other, Q, E);
347
348do_quote({_, _, _} = Tuple, Q, E) ->
349  Annotated = annotate(Tuple, Q#elixir_quote.context),
350  do_quote_tuple(Annotated, Q, E);
351
352do_quote([], _, _) ->
353  [];
354
355do_quote([H | T], #elixir_quote{unquote=false} = Q, E) ->
356  do_quote_simple_list(T, do_quote(H, Q, E), Q, E);
357
358do_quote([H | T], Q, E) ->
359  do_quote_tail(lists:reverse(T, [H]), Q, E);
360
361do_quote(Other, _, _) ->
362  Other.
363
364%% do_escape
365
366do_escape({Left, Meta, Right}, Q, E = prune_metadata) ->
367  TM = [{K, V} || {K, V} <- Meta, (K == no_parens) orelse (K == line)],
368  TL = do_quote(Left, Q, E),
369  TR = do_quote(Right, Q, E),
370  {'{}', [], [TL, TM, TR]};
371
372do_escape(Tuple, Q, E) when is_tuple(Tuple) ->
373  TT = do_quote(tuple_to_list(Tuple), Q, E),
374  {'{}', [], TT};
375
376do_escape(BitString, _, _) when is_bitstring(BitString) ->
377  case bit_size(BitString) rem 8 of
378    0 ->
379      BitString;
380    Size ->
381      <<Bits:Size, Bytes/binary>> = BitString,
382      {'<<>>', [], [{'::', [], [Bits, {size, [], [Size]}]}, {'::', [], [Bytes, {binary, [], []}]}]}
383  end;
384
385do_escape(Map, Q, E) when is_map(Map) ->
386  TT = do_quote(maps:to_list(Map), Q, E),
387  {'%{}', [], TT};
388
389do_escape([], _, _) -> [];
390
391do_escape([H | T], #elixir_quote{unquote=false} = Q, E) ->
392  do_quote_simple_list(T, do_quote(H, Q, E), Q, E);
393
394do_escape([H | T], Q, E) ->
395  %% The improper case is inefficient, but improper lists are rare.
396  try lists:reverse(T, [H]) of
397    L -> do_quote_tail(L, Q, E)
398  catch
399    _:_ ->
400      {L, R} = reverse_improper(T, [H]),
401      TL = do_quote_splice(L, Q, E, [], []),
402      TR = do_quote(R, Q, E),
403      update_last(TL, fun(X) -> {'|', [], [X, TR]} end)
404  end;
405
406do_escape(Other, _, _)
407    when is_number(Other); is_pid(Other); is_atom(Other) ->
408  Other;
409
410do_escape(Fun, _, _) when is_function(Fun) ->
411  case (erlang:fun_info(Fun, env) == {env, []}) andalso
412       (erlang:fun_info(Fun, type) == {type, external}) of
413    true  -> fun_to_quoted(Fun);
414    false -> bad_escape(Fun)
415  end;
416
417do_escape(Other, _, _) ->
418  bad_escape(Other).
419
420bad_escape(Arg) ->
421  argument_error(<<"cannot escape ", ('Elixir.Kernel':inspect(Arg, []))/binary, ". ",
422                   "The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, ",
423                   "PIDs and remote functions in the format &Mod.fun/arity">>).
424
425import_meta(Meta, Name, Arity, Q, E) ->
426  case (keyfind(import, Meta) == false) andalso
427      elixir_dispatch:find_import(Meta, Name, Arity, E) of
428    false ->
429      case (Arity == 1) andalso keyfind(ambiguous_op, Meta) of
430        {ambiguous_op, nil} -> keystore(ambiguous_op, Meta, Q#elixir_quote.context);
431        _ -> Meta
432      end;
433    Receiver ->
434      keystore(import, keystore(context, Meta, Q#elixir_quote.context), Receiver)
435  end.
436
437%% do_quote_*
438
439do_quote_import(Meta, Name, Arity, ArgsOrAtom, Q, E) ->
440  ImportMeta = import_meta(Meta, Name, Arity, Q, E),
441  Annotated = annotate({Name, ImportMeta, ArgsOrAtom}, Q#elixir_quote.context),
442  do_quote_tuple(Annotated, Q, E).
443
444do_quote_call(Left, Meta, Expr, Args, Q, E) ->
445  All  = [Left, {unquote, Meta, [Expr]}, Args, Q#elixir_quote.context],
446  TAll = [do_quote(X, Q, E) || X <- All],
447  {{'.', Meta, [elixir_quote, dot]}, Meta, [meta(Meta, Q) | TAll]}.
448
449do_quote_fa(Target, Meta, Args, F, A, Q, E) ->
450  NewMeta =
451    case elixir_dispatch:find_import(Meta, F, A, E) of
452      false -> Meta;
453      Receiver ->
454        lists:keystore(context, 1,
455          lists:keystore(import, 1, Meta, {import, Receiver}),
456          {context, Q#elixir_quote.context}
457        )
458    end,
459  do_quote_tuple(Target, NewMeta, Args, Q, E).
460
461do_quote_tuple({Left, Meta, Right}, Q, E) ->
462  do_quote_tuple(Left, Meta, Right, Q, E).
463
464do_quote_tuple(Left, Meta, Right, Q, E) ->
465  TLeft = do_quote(Left, Q, E),
466  TRight = do_quote(Right, Q, E),
467  {'{}', [], [TLeft, meta(Meta, Q), TRight]}.
468
469do_quote_simple_list([], Prev, _, _) -> [Prev];
470do_quote_simple_list([H | T], Prev, Q, E) ->
471  [Prev | do_quote_simple_list(T, do_quote(H, Q, E), Q, E)];
472do_quote_simple_list(Other, Prev, Q, E) ->
473  [{'|', [], [Prev, do_quote(Other, Q, E)]}].
474
475do_quote_tail([{'|', Meta, [{unquote_splicing, _, [Left]}, Right]} | T], #elixir_quote{unquote=true} = Q, E) ->
476  %% Process the remaining entries on the list.
477  %% For [1, 2, 3, unquote_splicing(arg) | tail], this will quote
478  %% 1, 2 and 3, which could even be unquotes.
479  TT = do_quote_splice(T, Q, E, [], []),
480  TR = do_quote(Right, Q, E),
481  do_runtime_list(Meta, tail_list, [Left, TR, TT]);
482
483do_quote_tail(List, Q, E) ->
484  do_quote_splice(List, Q, E, [], []).
485
486do_quote_splice([{unquote_splicing, Meta, [Expr]} | T], #elixir_quote{unquote=true} = Q, E, Buffer, Acc) ->
487  Runtime = do_runtime_list(Meta, list, [Expr, do_list_concat(Buffer, Acc)]),
488  do_quote_splice(T, Q, E, [], Runtime);
489
490do_quote_splice([H | T], Q, E, Buffer, Acc) ->
491  TH = do_quote(H, Q, E),
492  do_quote_splice(T, Q, E, [TH | Buffer], Acc);
493
494do_quote_splice([], _Q, _E, Buffer, Acc) ->
495  do_list_concat(Buffer, Acc).
496
497do_list_concat(Left, []) -> Left;
498do_list_concat([], Right) -> Right;
499do_list_concat(Left, Right) -> {{'.', [], [erlang, '++']}, [], [Left, Right]}.
500
501do_runtime_list(Meta, Fun, Args) ->
502  {{'.', Meta, [elixir_quote, Fun]}, Meta, Args}.
503
504%% Helpers
505
506meta(Meta, Q) ->
507  generated(keep(Meta, Q), Q).
508
509generated(Meta, #elixir_quote{generated=true}) -> [{generated, true} | Meta];
510generated(Meta, #elixir_quote{generated=false}) -> Meta.
511
512keep(Meta, #elixir_quote{file=nil, line=Line}) ->
513  line(Meta, Line);
514keep(Meta, #elixir_quote{file=File}) ->
515  case lists:keytake(line, 1, Meta) of
516    {value, {line, Line}, MetaNoLine} ->
517      [{keep, {File, Line}} | MetaNoLine];
518    false ->
519      [{keep, {File, 0}} | Meta]
520  end.
521
522line(Meta, true) ->
523  Meta;
524line(Meta, false) ->
525  keydelete(line, Meta);
526line(Meta, Line) ->
527  keystore(line, Meta, Line).
528
529reverse_improper([H | T], Acc) -> reverse_improper(T, [H | Acc]);
530reverse_improper([], Acc) -> Acc;
531reverse_improper(T, Acc) -> {Acc, T}.
532
533update_last([], _) -> [];
534update_last([H], F) -> [F(H)];
535update_last([H | T], F) -> [H | update_last(T, F)].
536
537keyfind(Key, Meta) ->
538  lists:keyfind(Key, 1, Meta).
539keydelete(Key, Meta) ->
540  lists:keydelete(Key, 1, Meta).
541keystore(_Key, Meta, nil) ->
542  Meta;
543keystore(Key, Meta, Value) ->
544  lists:keystore(Key, 1, Meta, {Key, Value}).
545keynew(Key, Meta, Value) ->
546  case lists:keymember(Key, 1, Meta) of
547    true -> Meta;
548    false -> [{Key, Value} | Meta]
549  end.
550