anchor.diff:      Else -> Else
     end;
   
  -% Dot operators
  +% Heredocs
  +
  +tokenize(Line, "\"\"\"" ++ T, Tokens) -> handle_heredocs(Line, $", T, Tokens);
  +tokenize(Line, "'''" ++ T, Tokens)    -> handle_heredocs(Line, $', T, Tokens);
  +
  +% Strings
  +
  +tokenize(Line, [$"|T], Tokens) -> handle_strings(Line, $", T, Tokens);
  +tokenize(Line, [$'|T], Tokens) -> handle_strings(Line, $', T, Tokens);
  +
  +% Atoms
  +
  +tokenize(Line, [$:,T|String], Tokens) when ?is_upcase(T); ?is_downcase(T); T == $_ ->
  +  { Rest, Atom } = tokenize_atom([T|String], []),
  +  tokenize(Line, Rest, [{atom,Line,[Atom]}|Tokens]);
  +
  +tokenize(Line, [$:,H|T], Tokens) when ?is_quote(H) ->
  +  case elixir_interpolation:extract(Line, true, T, H) of
  +    { NewLine, Parts, Rest } -> tokenize(NewLine, Rest, [{atom,Line,unescape_tokens(Parts)}|Tokens]);
  +    Else -> Else
  +  end;
  +
  +% Atom operators
   
   % ## Containers
  -tokenize(Line, ".<<>>" ++ Rest, Tokens) ->
  -  tokenize(Line, Rest, [tokenize_call_identifier(identifier, Line, '<<>>', Rest),{'.',Line}|Tokens]);
  -
  -tokenize(Line, [$.,T1,T2|Rest], Tokens) when ?container2(T1, T2) ->
  -  tokenize(Line, Rest, [tokenize_call_identifier(identifier, Line, list_to_atom([T1,T2]), Rest),{'.',Line}|Tokens]);
  +tokenize(Line, ":<<>>" ++ Rest, Tokens) ->
  +  tokenize(Line, Rest, [{atom,Line,['<<>>']}|Tokens]);
  +
  +tokenize(Line, [$:,T1,T2|Rest], Tokens) when ?container2(T1, T2) ->
  +  tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2])]}|Tokens]);
   
   % ## Three Token Operators
  -tokenize(Line, [$.,T1,T2,T3|Rest], Tokens) when ?comp3(T1, T2, T3) ->
  -  tokenize(Line, Rest, [tokenize_call_identifier(identifier, Line, list_to_atom([T1,T2,T3]), Rest),{'.',Line}|Tokens]);
  +tokenize(Line, [$:,T1,T2,T3|Rest], Tokens) when ?comp3(T1, T2, T3) ->
  +  tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2,T3])]}|Tokens]);
   
   % ## Two Token Operators
  -tokenize(Line, [$.,T1,T2|Rest], Tokens) when ?comp2(T1, T2); ?op2(T1, T2) ->
  -  tokenize(Line, Rest, [tokenize_call_identifier(identifier, Line, list_to_atom([T1,T2]), Rest),{'.',Line}|Tokens]);
  +tokenize(Line, [$:,T1,T2|Rest], Tokens) when ?comp2(T1, T2); ?op2(T1, T2) ->
  +  tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2])]}|Tokens]);
   
   % ## Single Token Operators
  -tokenize(Line, [$.,T|Rest], Tokens) when ?comp1(T); ?op1(T); T == $& ->
  -  tokenize(Line, Rest, [tokenize_call_identifier(identifier, Line, list_to_atom([T]), Rest),{'.',Line}|Tokens]);
  -
  -% Heredocs
  -
  -tokenize(Line, [H,H,H|T], Tokens) when ?is_quote(H) ->
  +tokenize(Line, [$:,T|Rest], Tokens) when ?comp1(T); ?op1(T); T == $&; T == $. ->
  +  tokenize(Line, Rest, [{atom,Line,[list_to_atom([T])]}|Tokens]);
  +
  +% End of line
  +
  +tokenize(Line, ";" ++ Rest, []) ->
  +  tokenize(Line, Rest, eol(Line, []));
  +
  +tokenize(Line, ";" ++ Rest, [Top|Tokens]) when element(1, Top) /= eol ->
  +  tokenize(Line, Rest, eol(Line, [Top|Tokens]));
  +
  +tokenize(Line, "\\\n" ++ Rest, Tokens) ->
  +  tokenize(Line + 1, Rest, Tokens);
  +
  +tokenize(Line, "\\\r\n" ++ Rest, Tokens) ->
  +  tokenize(Line + 1, Rest, Tokens);
  +
  +tokenize(Line, "\n" ++ Rest, Tokens) ->
  +  tokenize(Line + 1, Rest, eol(Line, Tokens));
  +
  +tokenize(Line, "\r\n" ++ Rest, Tokens) ->
  +  tokenize(Line + 1, Rest, eol(Line, Tokens));
  +
  +% Stand-alone tokens
  +
  +% ## &
  +tokenize(Line, [$&,H|Rest], Tokens) when ?is_digit(H) ->
  +  tokenize(Line, Rest, [{'&', Line, [list_to_integer([H])]}|Tokens]);
  +
  +% ## Containers + punctuation tokens
  +
  +tokenize(Line, [T,T|Rest], Tokens) when T == $<; T == $>; T == $. ->
  +  tokenize(Line, Rest, [{list_to_atom([T,T]), Line}|Tokens]);
  +
  +tokenize(Line, [T|Rest], Tokens) when T == $(;
  +  T == ${; T == $}; T == $[; T == $]; T == $);
  +  T == $,; T == $. ->
  +  tokenize(Line, Rest, [{list_to_atom([T]), Line}|Tokens]);
  +
  +% ## Comparison three token operators
  +tokenize(Line, [T1,T2,T3|Rest], Tokens) when ?comp3(T1, T2, T3) ->
  +  handle_comp_op(Line, list_to_atom([T1,T2,T3]), Rest, Tokens);
  +
  +% ## Three token operators - none yet
  +
  +% ## Comparison two token operators
  +tokenize(Line, [T1,T2|Rest], Tokens) when ?comp2(T1, T2) ->
  +  handle_comp_op(Line, list_to_atom([T1,T2]), Rest, Tokens);
  +
  +% ## Two Token Operators
  +tokenize(Line, [T1,T2|Rest], Tokens) when ?op2(T1, T2) ->
  +  handle_op(Line, list_to_atom([T1,T2]), Rest, Tokens);
  +
  +% ## Comparison single token operators
  +tokenize(Line, [T|Rest], Tokens) when ?comp1(T) ->
  +  handle_comp_op(Line, list_to_atom([T]), Rest, Tokens);
  +
  +% ## Single Token Operators
  +tokenize(Line, [T|Rest], Tokens) when ?op1(T) ->
  +  handle_op(Line, list_to_atom([T]), Rest, Tokens);
  +
  +% Integers and floats
  +
  +tokenize(Line, [H|_] = String, Tokens) when ?is_digit(H) ->
  +  { Rest, Number } = tokenize_number(String, [], false),
  +  tokenize(Line, Rest, [{number,Line,Number}|Tokens]);
  +
  +% Aliases
  +
  +tokenize(Line, [H|_] = String, Tokens) when ?is_upcase(H) ->
  +  { Rest, Alias } = tokenize_identifier(String, [], false),
  +  tokenize(Line, Rest, [{'__aliases__',Line,[list_to_atom(Alias)]}|Tokens]);
  +
  +% Identifier
  +
  +tokenize(Line, [H|_] = String, Tokens) when ?is_downcase(H); H == $_ ->
  +  { Rest, { Kind, _, Identifier } } = tokenize_any_identifier(Line, String, []),
  +  case keyword(Line, Kind, Identifier) of
  +    false ->
  +      tokenize(Line, Rest, [{Kind,Line,Identifier}|Tokens]);
  +    Else  ->
  +      tokenize(Line, Rest, [Else|Tokens])
  +  end;
  +
  +% Ambiguous unary/binary operators tokens
  +
  +tokenize(Line, [Space,Sign,NotMarker|T], [{Identifier,_,_} = H|Tokens]) when Sign == $+ orelse Sign == $-,
  +  Space == $\s orelse Space == $\t, NotMarker /= $\s, NotMarker /= $\t,
  +  NotMarker /= $\n, NotMarker /= $:, NotMarker /= $(,
  +  NotMarker /= $+, NotMarker /= $-, NotMarker /= $>,
  +  Identifier == identifier orelse Identifier == punctuated_identifier ->
  +  Rest = [NotMarker|T],
  +  tokenize(Line, Rest, [{list_to_atom([Sign]),Line},setelement(1, H, op_identifier)|Tokens]);
  +
  +% Spaces
  +
  +tokenize(Line, [T|Rest], Tokens) when T == $ ; T == $\r; T == $\t ->
  +  tokenize(Line, Rest, Tokens);
  +
  +tokenize(_, [{line,Line}|Rest], Tokens) ->
  +  tokenize(Line, Rest, Tokens);
  +
  +tokenize(Line, T, _) ->
  +  { error, { Line, "invalid token: ", T } }.
  +
  +%% Handlers
  +
  +handle_heredocs(Line, H, T, Tokens) ->
     case extract_heredoc_with_interpolation(Line, true, T, H) of
       { error, _ } = Error ->
         Error;
  
positive.code:       end,
        tokenize(NewLine, Rest, [{Kind,Line,unescape_tokens(Parts)}|Tokens]);
      Else -> Else
    end;
  
  % Atoms
  
  tokenize(Line, [$:,T|String], Tokens) when ?is_upcase(T); ?is_downcase(T); T == $_ ->
    { Rest, Atom } = tokenize_atom([T|String], []),
    tokenize(Line, Rest, [{atom,Line,[Atom]}|Tokens]);
  
  tokenize(Line, [$:,H|T], Tokens) when ?is_quote(H) ->
    case elixir_interpolation:extract(Line, true, T, H) of
      { NewLine, Parts, Rest } -> tokenize(NewLine, Rest, [{atom,Line,unescape_tokens(Parts)}|Tokens]);
      Else -> Else
    end;
  
  % Atom operators
  
  % ## Containers
  tokenize(Line, ":<<>>" ++ Rest, Tokens) ->
    tokenize(Line, Rest, [{atom,Line,['<<>>']}|Tokens]);
  
  tokenize(Line, [$:,T1,T2|Rest], Tokens) when ?container2(T1, T2) ->
    tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2])]}|Tokens]);
  
  % ## Three Token Operators
  tokenize(Line, [$:,T1,T2,T3|Rest], Tokens) when ?comp3(T1, T2, T3) ->
    tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2,T3])]}|Tokens]);
  
  % ## Two Token Operators
  tokenize(Line, [$:,T1,T2|Rest], Tokens) when ?comp2(T1, T2); ?op2(T1, T2) ->
    tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2])]}|Tokens]);
  
  % ## Single Token Operators
  tokenize(Line, [$:,T|Rest], Tokens) when ?comp1(T); ?op1(T); T == $&; T == $. ->
    tokenize(Line, Rest, [{atom,Line,[list_to_atom([T])]}|Tokens]);
  
  % Ambiguous unary/binary operators tokens
  
  tokenize(Line, [Space,Sign,NotMarker|T], [{Identifier,_,_} = H|Tokens]) when Sign == $+ orelse Sign == $-,
    Space == $\s orelse Space == $\t, NotMarker /= $\s, NotMarker /= $\t,
    NotMarker /= $\n, NotMarker /= $:, NotMarker /= $(,
    NotMarker /= $+, NotMarker /= $-, NotMarker /= $>,
    Identifier == identifier orelse Identifier == punctuated_identifier ->
    Rest = [NotMarker|T],
    tokenize(Line, Rest, [{list_to_atom([Sign]),Line},setelement(1, H, op_identifier)|Tokens]);
  
  % Stand-alone tokens
  
  % ## Containers + punctuation tokens
  
  tokenize(Line, [T,T|Rest], Tokens) when T == $<; T == $>; T == $. ->
    tokenize(Line, Rest, [{list_to_atom([T,T]), Line}|Tokens]);
  
  tokenize(Line, [T|Rest], Tokens) when T == $(;
    T == ${; T == $}; T == $[; T == $]; T == $);
    T == $,; T == $. ->
    tokenize(Line, Rest, [{list_to_atom([T]), Line}|Tokens]);
  
  % ## Comparison three token operators
  tokenize(Line, [T1,T2,T3|Rest], Tokens) when ?comp3(T1, T2, T3) ->
    tokenize(Line, Rest, [{comp_op, Line, list_to_atom([T1,T2,T3])}|Tokens]);
  
  % ## Three token operators - none yet
  
  % ## Comparison two token operators
  tokenize(Line, [T1,T2|Rest], Tokens) when ?comp2(T1, T2) ->
    tokenize(Line, Rest, [{comp_op, Line, list_to_atom([T1,T2])}|Tokens]);
  
  % ## Two Token Operators
  tokenize(Line, [T1,T2|Rest], Tokens) when ?op2(T1, T2) ->
    tokenize(Line, Rest, [{list_to_atom([T1,T2]), Line}|Tokens]);
  
  % ## &
  tokenize(Line, [$&,H|Rest], Tokens) when ?is_digit(H) ->
    tokenize(Line, Rest, [{'&', Line, [list_to_integer([H])]}|Tokens]);
  
  % ## Comparison single token operators
  tokenize(Line, [T|Rest], Tokens) when ?comp1(T) ->
    tokenize(Line, Rest, [{comp_op, Line, list_to_atom([T])}|Tokens]);
  
  % ## Single Token Operators
  tokenize(Line, [T|Rest], Tokens) when ?op1(T) ->
    tokenize(Line, Rest, [{list_to_atom([T]), Line}|Tokens]);
  
  % Aliases
  
  tokenize(Line, [H|_] = String, Tokens) when ?is_upcase(H) ->
    { Rest, Alias } = tokenize_identifier(String, [], false),
    tokenize(Line, Rest, [{'__aliases__',Line,[list_to_atom(Alias)]}|Tokens]);
  
  % Identifier
  
  tokenize(Line, [H|_] = String, Tokens) when ?is_downcase(H); H == $_ ->
    { Rest, { Kind, _, Identifier } } = tokenize_any_identifier(Line, String, []),
    case keyword(Line, Kind, Identifier) of
      false ->
        tokenize(Line, Rest, [{Kind,Line,Identifier}|Tokens]);
      Else  ->
        tokenize(Line, Rest, [Else|Tokens])
    end;
  
  % End of line
  
  tokenize(Line, ";" ++ Rest, []) ->
    tokenize(Line, Rest, eol(Line, []));
  
  tokenize(Line, ";" ++ Rest, [Top|Tokens]) when element(1, Top) /= eol ->
    tokenize(Line, Rest, eol(Line, [Top|Tokens]));
  
  tokenize(Line, "\\\n" ++ Rest, Tokens) ->
    tokenize(Line + 1, Rest, Tokens);
  
  tokenize(Line, "\\\r\n" ++ Rest, Tokens) ->
    tokenize(Line + 1, Rest, Tokens);
  
  tokenize(Line, "\n" ++ Rest, Tokens) ->
    tokenize(Line + 1, Rest, eol(Line, Tokens));
  
  tokenize(Line, "\r\n" ++ Rest, Tokens) ->
    tokenize(Line + 1, Rest, eol(Line, Tokens));
  
  % Spaces
  
  tokenize(Line, [T|Rest], Tokens) when T == $ ; T == $\r; T == $\t ->
    tokenize(Line, Rest, Tokens);
  
  tokenize(_, [{line,Line}|Rest], Tokens) ->
    tokenize(Line, Rest, Tokens);
  
  tokenize(Line, T, _) ->
    { error, { Line, "invalid token: ", T } }.
  
  %% Helpers
  
  
negative.code: tokenize(_, [], Tokens) ->
    { ok, lists:reverse(Tokens) };
  
  % Base integers
  
  tokenize(Line, [$0,X,H|T], Tokens) when (X == $x orelse X == $X), ?is_hex(H) ->
    { Rest, Number } = tokenize_hex([H|T], []),
  