anchor.diff:  -module(elixir_quote).
   -export([escape/2, linify/2, linify/3, quote/4]). %% Exposed API
  --export([unquote/4, tail_join/3, join/2]).        %% Quote callbacks
  +-export([dot/5, tail_list/3, list/2]).            %% Quote callbacks
   -include("elixir.hrl").
   -define(defs(Kind), Kind == def; Kind == defp; Kind == defmacro; Kind == defmacrop).
   
  
positive.code: do_quote({ unquote, _Meta, [Expr] }, #elixir_quote{unquote=true} = Q, _) ->
    { Expr, Q#elixir_quote{unquoted=true} };
  
  %% Context mark
  
  do_quote({ defmodule, Meta, [{ '__aliases__', AliasMeta, Atoms } = H|T] }, #elixir_quote{escape=false} = Q, S) ->
    %% Only store the context if we actually have a full alias as
    %% argument, otherwise the expression is being automatically
    %% generated and we don't want the alias to count.
    NewH =
      case lists:all(fun is_atom/1, Atoms) of
        true  ->
          { '__aliases__', keystore(context, AliasMeta, Q#elixir_quote.context), Atoms };
        false ->
          H
      end,
    do_quote_tuple({ defmodule, Meta, [NewH|T] }, Q, S);
  
  %% Store the context information in the first element of the
  %% definition tuple so we can access it later on.
  do_quote({ Def, Meta, [{ H, M, A }|T] }, #elixir_quote{escape=false} = Q, S) when ?defs(Def) ->
    MM = keystore(context, M, Q#elixir_quote.context),
    do_quote_tuple({ Def, Meta, [{ H, MM, A }|T] }, Q, S);
  do_quote({ { '.', _, [_, Def] } = Target, Meta, [{ H, M, A }|T] }, #elixir_quote{escape=false} = Q, S) when ?defs(Def) ->
    MM = keystore(context, M, Q#elixir_quote.context),
    do_quote_tuple({ Target, Meta, [{ H, MM, A }|T] }, Q, S);
  
  do_quote({ Def, Meta, [_|_] = Args }, #elixir_quote{escape=false} = Q, S) when Def == alias; Def == import ->
    NewMeta = keystore(context, Meta, Q#elixir_quote.context),
    do_quote_tuple({ Def, NewMeta, Args }, Q, S);
  do_quote({ { '.', _, [_, Def] } = Target, Meta, Args }, #elixir_quote{escape=false} = Q, S) when Def == alias; Def == import ->
    NewMeta = keystore(context, Meta, Q#elixir_quote.context),
    do_quote_tuple({ Target, NewMeta, Args }, Q, S);
  
  %% Aliases
  
  do_quote({ 'alias!', _Meta, [Expr] }, #elixir_quote{aliases_hygiene=true} = Q, S) ->
  
negative.code:       { { '.', Meta, [Left, Right] }, Meta, [] }
    end;
  
  dot(Meta, Left, { Right, _, Context }, nil) when is_atom(Right), is_atom(Context) ->
    { { '.', Meta, [Left, Right] }, Meta, [] };
  
  dot(Meta, Left, { Right, _, Args }, nil) when is_atom(Right) ->
    { { '.', Meta, [Left, Right] }, Meta, Args };
  
  dot(_Meta, _Left, Right, nil) ->
    argument_error(<<"expected unquote after dot to return an atom, an alias or a quoted call, got: ",
                     ('Elixir.Macro':to_string(Right))/binary>>);
  
  dot(Meta, Left, Right, Args) when is_atom(Right) ->
    { { '.', Meta, [Left, Right] }, Meta, Args };
  
  dot(Meta, Left, { Right, _, Context }, Args) when is_atom(Right), is_atom(Context) ->
    { { '.', Meta, [Left, Right] }, Meta, Args };
  
  dot(_Meta, _Left, Right, _Args) ->
    argument_error(<<"expected unquote after dot with args to return an atom or a quoted call, got: ",
                     ('Elixir.Macro':to_string(Right))/binary>>).
  
  list(Left, Right) when is_list(Right) ->
    validate_list(Left),
    Left ++ Right.
  
  tail_list(Left, Right, Tail) when is_list(Right), is_list(Tail) ->
    validate_list(Left),
    Tail ++ Left ++ Right;
  
  tail_list(Left, Right, Tail) when is_list(Left) ->
    validate_list(Left),
    [H|T] = lists:reverse(Tail ++ Left),
    lists:reverse([{ '|', [], [H, Right] }|T]).
  
  validate_list(List) when is_list(List) ->
    ok;
  validate_list(List) when not is_list(List) ->
    argument_error(<<"expected a list with quoted expressions in unquote_splicing/1, got: ",
                     ('Elixir.Kernel':inspect(List))/binary>>).
  
  argument_error(Message) ->
    error('Elixir.ArgumentError':exception([{message,Message}])).
  
  %% Annotates the AST with context and other info
  
  annotate({ defmodule, Meta, [{ '__aliases__', AliasMeta, Atoms } = H|T] }, Context) ->
    %% Only store the context if we actually have a full alias as
    %% argument, otherwise the expression is being automatically
    %% generated and we don't want the alias to count.
    NewH =
      case lists:all(fun is_atom/1, Atoms) of
        true  ->
          { '__aliases__', keystore(context, AliasMeta, Context), Atoms };
        false ->
          H
      end,
    { defmodule, Meta, [NewH|T] };
  
  annotate({ Def, Meta, [{ H, M, A }|T] }, Context) when ?defs(Def) ->
    %% Store the context information in the first element of the
    %% definition tuple so we can access it later on.
    MM = keystore(context, M, Context),
    { Def, Meta, [{ H, MM, A }|T] };
  annotate({ { '.', _, [_, Def] } = Target, Meta, [{ H, M, A }|T] }, Context) when ?defs(Def) ->
    MM = keystore(context, M, Context),
    { Target, Meta, [{ H, MM, A }|T] };
  
  annotate({ Def, Meta, [_|_] = Args }, Context) when Def == alias; Def == import ->
    NewMeta = keystore(context, Meta, Context),
    { Def, NewMeta, Args };
  annotate({ { '.', _, [_, Def] } = Target, Meta, Args }, Context) when Def == alias; Def == import ->
    NewMeta = keystore(context, Meta, Context),
    { Target, NewMeta, Args };
  
  annotate(Tree, _Context) -> Tree.
  
  %% Escapes the given expression. It is similar to quote, but
  %% lines are kept and hygiene mechanisms are disabled.
  