anchor.diff:  escape_attr([C | Rest], Acc) ->
       escape_attr(Rest, [C | Acc]).
   
  +to_tag(A) when is_atom(A) ->
  +    atom_to_list(A);
  +to_tag(L) ->
  +    L.
  +
   to_tokens([], Acc) ->
       lists:reverse(Acc);
   to_tokens([{Tag, []} | Rest], Acc) ->
  -    to_tokens(Rest, [{end_tag, Tag} | Acc]);
  -to_tokens([{Tag, [{T1, A1, C1} | R1]} | Rest], Acc) ->
  +    to_tokens(Rest, [{end_tag, to_tag(Tag)} | Acc]);
  +to_tokens([{Tag0, [{T0} | R1]} | Rest], Acc) ->
  +    %% Allow {br}
  +    to_tokens([{Tag0, [{T0, [], []} | R1]} | Rest], Acc);
  +to_tokens([{Tag0, [{T0, C0} | R1]} | Rest], Acc) ->
  +    %% Allow {p, ["content"]}
  +    to_tokens([{Tag0, [{T0, [], C0} | R1]} | Rest], Acc);
  +to_tokens([{Tag0, [{T0, A1, C0} | R1]} | Rest], Acc) when is_binary(C0) ->
  +    %% Allow {"p", [{"class", "foo"}], <<"content">>}
  +    to_tokens([{Tag0, [{T0, A1, binary_to_list(C0)} | R1]} | Rest], Acc);
  +to_tokens([{Tag0, [{T0, A1, C0=[C | _]} | R1]} | Rest], Acc)
  +  when is_integer(C) ->
  +    %% Allow {"p", [{"class", "foo"}], "content"}
  +    to_tokens([{Tag0, [{T0, A1, [C0]} | R1]} | Rest], Acc);
  +to_tokens([{Tag0, [{T0, A1, C1} | R1]} | Rest], Acc) ->
  +    %% Native {"p", [{"class", "foo"}], ["content"]}
  +    Tag = to_tag(Tag0),
  +    T1 = to_tag(T0),
       case is_singleton(T1) of
           true ->
               to_tokens([{Tag, R1} | Rest], [{start_tag, T1, A1, true} | Acc]);
  
positive.code:     test_parse_tokens(),
      test_escape(),
      test_escape_attr(),
      ok.
  
  
  %% Internal API
  
  to_html([], Acc) ->
      lists:reverse(Acc);
  to_html([{data, Data, _Whitespace} | Rest], Acc) ->
      to_html(Rest, [escape(Data) | Acc]);
  to_html([{start_tag, Tag, Attrs, Singleton} | Rest], Acc) ->
      Open = "<" ++ Tag ++ attrs_to_html(Attrs, []) ++ case Singleton of
                                                           true -> " />";
                                                           false -> ">"
                                                       end,
      to_html(Rest, [Open | Acc]);
  to_html([{end_tag, Tag} | Rest], Acc) ->
      to_html(Rest, ["</" ++ Tag ++ ">" | Acc]).
  
  attrs_to_html([], Acc) ->
      lists:reverse(Acc);
  attrs_to_html([{K, V} | Rest], Acc) ->
      attrs_to_html(Rest, [" " ++ K ++ "=\"" ++ escape_attr(V) ++ "\"" | Acc]).
      
  test_escape() ->
      "&amp;quot;\"word &lt;&lt;up!&amp;quot;" =
  
negative.code:             to_tokens([{T1, C1}, {Tag, R1} | Rest],
                        [{start_tag, T1, A1, false} | Acc])
      end;
  to_tokens([{Tag0, [L | R1]} | Rest], Acc) when is_list(L) ->
      Tag = to_tag(Tag0),
      to_tokens([{Tag, R1} | Rest], [{data, L, false} | Acc]);
  to_tokens([{Tag0, [B | R1]} | Rest], Acc) when is_binary(B) ->
      Tag = to_tag(Tag0),
      to_tokens([{Tag, R1} | Rest], [{data, binary_to_list(B), false} | Acc]).
  
  test_tokens() ->
      [{start_tag, "foo", [{"bar", "baz"},
  