anchor.diff:  %% helper functions
   %%------------------------------------------------------------------------------
   
  -add_to_text(L, _Pos, [#text{text=Text}=T|Parsed]) ->
  +add_to_text(L, _Pos, [#print_text{text=Text}=P|Parsed]) ->
       NewText = <<Text/binary, L/binary>>,
  -    [T#text{text=NewText}|Parsed];
  +    [P#print_text{text=NewText}|Parsed];
   add_to_text(L, Pos, Parsed) ->
  -    [add_line(#text{text=L}, Pos)|Parsed].
  +    [add_line(#print_text{text=L}, Pos)|Parsed].
   
   add_pos({Level,Row,Col}, Offset) ->
       {Level,Row,Col+Offset}.
  
positive.code: constant(<<A:8,Rest/binary>>, Pos, [#constant{name=N}=C])
          when ?IS_ALPHA(A) orelse ?IS_NUMBER(A) orelse A =:= $_ ->
      constant(Rest, add_pos(Pos,1), [C#constant{name = <<N/binary, A:8>>}]);
  constant(Rest, Pos, Parsed) ->
      {Rest, Pos, Parsed}.
  
  string(<<"\"",Rest/binary>>, Pos, []) ->
      string_parsed(Rest, Pos, [add_line(#text_to_process{text=[]}, Pos)]);
  string(<<"'",Rest/binary>>, Pos, []) ->
      string_fixed(Rest, Pos, [add_line(#text{text = <<>>}, Pos)]);
  string(<<"<<<'",Rest/binary>>, {Level,Row,_}=Pos, []) ->
      [W,Rest0] = binary:split(Rest, <<"'">>),
      [Text,Rest1] = binary:split(Rest0, <<"\n", W/binary, ";">>),
      NPos = {Level,Row+length(binary:matches(Text,<<"\n">>)),1},
      {Rest1, add_pos(NPos,byte_size(W)+1), [add_line(#text{text=Text}, Pos)]};
  string(<<"<<<",Rest/binary>>, {Level,Row,_}=Pos, []) ->
      [W,Rest0] = binary:split(Rest, <<"\n">>),
      [Text,Rest1] = binary:split(Rest0, <<"\n", W/binary, ";">>),
      NPos = {Level,Row+length(binary:matches(Text,<<"\n">>)),1},
      %% TODO parse Text for variables
      {Rest1, add_pos(NPos,byte_size(W)+1), [add_line(#text{text=Text}, Pos)]}.
  
  string_fixed(<<"\\\\",Rest/binary>>, Pos, [#text{text=C}=S]) ->
      string_fixed(Rest, add_pos(Pos,1), [S#text{text = <<C/binary, "\\\\">>}]);
  string_fixed(<<"\\'",Rest/binary>>, Pos, [#text{text=C}=S]) ->
      string_fixed(Rest, add_pos(Pos,1), [S#text{text = <<C/binary, "\\'">>}]);
  string_fixed(<<"'",Rest/binary>>, Pos, Parsed) ->
      {Rest, add_pos(Pos,1), Parsed};
  string_fixed(<<"\n",Rest/binary>>, Pos, [#text{text=C}=S]) ->
      string_fixed(Rest, new_line(Pos), [S#text{text = <<C/binary, "\n">>}]);
  string_fixed(<<A/utf8,Rest/binary>>, Pos, [#text{text=C}=S]) ->
      string_fixed(Rest, add_pos(Pos,1), [S#text{text = <<C/binary, A/utf8>>}]).
  
  string_parsed(<<"\\\\",Rest/binary>>, Pos, [#text_to_process{text=[C|R]}=S])
          when is_binary(C) ->
      string_parsed(Rest, add_pos(Pos,1), [S#text_to_process{text = [<<C/binary, "\\\\">>|R]}]);
  string_parsed(<<"\\\"",Rest/binary>>, Pos, [#text_to_process{text=[C|R]}=S])
          when is_binary(C)  ->
      string_parsed(Rest, add_pos(Pos,1), [S#text_to_process{text = [<<C/binary, "\\\"">>|R]}]);
  string_parsed(<<"\"",Rest/binary>>, Pos, [#text_to_process{text=C}=S|Parsed]) ->
      {Rest, add_pos(Pos,1), [S#text_to_process{text=lists:reverse(C)}|Parsed]};
  string_parsed(<<"\n",Rest/binary>>, Pos, [#text_to_process{text=[C|R]}=S|Parsed])
          when is_binary(C) ->
      string_parsed(Rest, new_line(Pos), [S#text_to_process{text = [<<C/binary, "\n">>|R]}|Parsed]);
  string_parsed(<<"${",Rest/binary>>, {Level,Row,Col}, [#text_to_process{text=C}=S|Parsed]) ->
      {Rest0, {_,Row0,Col0}, [Var]} = variable(Rest, {enclosed,Row,Col+2}, []),
      string_parsed(Rest0, {Level,Row0,Col0}, [S#text_to_process{text=[Var|C]}|Parsed]);
  string_parsed(<<"{$",Rest/binary>>, {Level,Row,Col}, [#text_to_process{text=C}=S|Parsed]) ->
      {Rest0, {_,Row0,Col0}, [Var]} = variable(Rest, {enclosed,Row,Col+2}, []),
      string_parsed(Rest0, {Level,Row0,Col0}, [S#text_to_process{text=[Var|C]}|Parsed]);
  string_parsed(<<"$",Rest/binary>>, {Level,Row,Col}, [#text_to_process{text=C}=S|Parsed]) ->
      {Rest0, {_,Row0,Col0}, [Var]} = variable(Rest, {Level,Row,Col+1}, []),
      string_parsed(Rest0, {Level,Row0,Col0}, [S#text_to_process{text=[Var|C]}|Parsed]);
  string_parsed(<<A/utf8,Rest/binary>>, Pos, [#text_to_process{text=[C|R]}=S|Parsed])
          when is_binary(C) ->
      string_parsed(Rest, add_pos(Pos,1), [S#text_to_process{text = [<<C/binary, A/utf8>>|R]}|Parsed]);
  string_parsed(Rest, Pos, [#text_to_process{text=C}=S|Parsed]) ->
      string_parsed(Rest, Pos, [S#text_to_process{text=[<<>>|C]}|Parsed]).
  
  
  st_if(<<SP:1/binary,Rest/binary>>, Pos, Parsed) when ?IS_SPACE(SP) ->
      st_if(Rest, add_pos(Pos,1), Parsed);
  st_if(<<SP:1/binary,Rest/binary>>, Pos, Parsed) when ?IS_NEWLINE(SP) ->
      st_if(Rest, new_line(Pos), Parsed);
  st_if(<<"(",_/binary>> = Rest0, {Level,Row,Col}=Pos, Parsed) ->
      {Rest1, Pos1, Conditions} = conditions(Rest0, add_pos({0,Row,Col},2), []),
      {Rest2, {_,Row2,Col2}, CodeBlock} = code_block(Rest1, Pos1, []),
      If = add_line(#if_block{
          conditions=Conditions,
  
negative.code: operator(<<"or">>,Left,Right) -> operator('or',Left,Right);
  operator(<<"&&">>,Left,Right) -> operator('and',Left,Right);
  operator(<<"||">>,Left,Right) -> operator('or',Left,Right);
  operator(Op,R1,R2) when (is_record(R1, int) orelse is_record(R1, float))
                  andalso (is_record(R2, int) orelse is_record(R2, float)) ->
      N1 = element(2, R1),
      N2 = element(2, R2),
      Res = case Op of
          <<"+">> -> N1+N2;
          <<"-">> -> N1-N2;
          <<"*">> -> N1*N2;
          <<"/">> -> N1/N2;
          <<"%">> -> N1 rem N2;
          <<">">> -> N1 > N2;
          <<"<">> -> N1 < N2;
          <<"==">> -> N1 == N2
          %% TODO add more optimizations for the rest of the operators
      end,
      if
          is_integer(Res) -> #int{int=Res};
          is_float(Res) -> #float{float=Res};
          is_boolean(Res) -> Res;
          true -> throw({error, R1, R2, Res})
      end;
  operator(<<".">>,#text{text=T1},#text{text=T2}) ->
      #text{text = <<T1/binary,T2/binary>>};
  operator(<<".">>,Left,Right) ->
      #concat{texts=[Left,Right]};
  operator(Op,Left,Right) ->
      #operation{type=Op, expression_left=Left, expression_right=Right}.
  
  