anchor.diff:  -module(ephp_parser).
   -compile([export_all]).
   
  --record(text, {content, row, col}).
  --record(print, {text, row, col}).
  --record(st_if, {conditions, then, else, row, col}).
  --record(operation, {content, row, col}).
  --record(variable, {name, row, col}).
  --record(number, {number, type, row, col}).
  --record(constant, {name, row, col}).
  --record(string, {content, row, col}).
  +-include("ephp.hrl").
   
   -define(IS_SPACE(X),
  -    X =:= <<" ">> orelse
  -    X =:= <<"\t">> orelse
  -    X =:= <<"\r">>
  +    erlang:'or'(X =:= <<" ">>,
  +                erlang:'or'(X =:= <<"\t">>,
  +                            X =:= <<"\r">>)
  +               )
   ).
   -define(IS_NEWLINE(X),
       X =:= <<"\n">>
   ).
   -define(IS_NUMBER(X),
  -    X >= $0 andalso X =< $9
  +    erlang:'and'(X >= $0, X =< $9)
   ).
   -define(IS_ALPHA(X),
  -    ((X >= $A andalso X =< $Z) orelse (X >= $a andalso X =< $z))
  -).
  +    erlang:'or'(
  +        erlang:'and'(X >= $A, X =< $Z),
  +        erlang:'and'(X >= $a, X =< $z)
  +    )
  +).
  +-define(OR(I,X,Y), erlang:'or'(I =:= X,I =:= Y)).
   -define(IS_OP1(X),
  +    X =:= <<126>> orelse
  +    X =:= <<"@">> orelse
  +    X =:= <<"!">> orelse
  +    X =:= <<"*">> orelse
  +    X =:= <<"/">> orelse
  +    X =:= <<"%">> orelse
       X =:= <<"+">> orelse
       X =:= <<"-">> orelse
  -    X =:= <<"*">> orelse
  -    X =:= <<"/">> orelse
  +    X =:= <<".">> orelse
  +    X =:= <<"<">> orelse
       X =:= <<">">> orelse
  -    X =:= <<"<">> orelse
  -    X =:= <<"%">>
  +    X =:= <<"&">> orelse
  +    X =:= <<"^">> orelse
  +    X =:= <<"|">>
   ).
   -define(IS_OP2(X),
  -    X =:= <<"==">> orelse
  +    X =:= <<"**">> orelse
  +    X =:= <<"++">> orelse
  +    X =:= <<"--">> orelse
  +    X =:= <<"<<">> orelse
  +    X =:= <<">>">> orelse
       X =:= <<"<=">> orelse
       X =:= <<">=">> orelse
  -    X =:= <<"!=">>
  +    X =:= <<"==">> orelse
  +    X =:= <<"!=">> orelse
  +    X =:= <<"<>">> orelse
  +    X =:= <<"&&">> orelse
  +    X =:= <<"||">> orelse
  +    X =:= <<"??">> orelse
  +    X =:= <<"+=">> orelse
  +    X =:= <<"-=">> orelse
  +    X =:= <<"*=">> orelse
  +    X =:= <<"/=">> orelse
  +    X =:= <<".=">> orelse
  +    X =:= <<"%=">> orelse
  +    X =:= <<"&=">> orelse
  +    X =:= <<"|=">> orelse
  +    X =:= <<"^=">> orelse
  +    X =:= <<"or">> orelse X =:= <<"OR">> orelse
  +    X =:= <<"Or">> orelse X =:= <<"oR">>
   ).
   -define(IS_OP3(X),
       X =:= <<"===">> orelse
  -    X =:= <<"!==">>
  +    X =:= <<"!==">> orelse
  +    X =:= <<"<=>">> orelse
  +    X =:= <<"**=">> orelse
  +    X =:= <<"<<=">> orelse
  +    X =:= <<">>=">> orelse
  +    X =:= <<"and">> orelse X =:= <<"And">> orelse X =:= <<"aNd">> orelse
  +    X =:= <<"ANd">> orelse X =:= <<"anD">> orelse X =:= <<"AnD">> orelse
  +    X =:= <<"aND">> orelse X =:= <<"AND">> orelse
  +    X =:= <<"xor">> orelse X =:= <<"Xor">> orelse X =:= <<"xOr">> orelse
  +    X =:= <<"XOr">> orelse X =:= <<"xoR">> orelse X =:= <<"XoR">> orelse
  +    X =:= <<"xOR">> orelse X =:= <<"XOR">>
   ).
   
   parse(Document) ->
  
positive.code:     {Rest, Pos, Parsed}.
  
  string(<<"\"",Rest/binary>>, {_,Row,Col}=Pos, []) ->
      string_parsed(Rest, Pos, [#string{content = <<>>, row=Row, col=Col}]);
  string(<<"'",Rest/binary>>, {_,Row,Col}=Pos, []) ->
      string_fixed(Rest, Pos, [#string{content = <<>>, row=Row, col=Col}]).
  
  string_fixed(<<"\\\\",Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_fixed(Rest, add_pos(Pos,1), [S#string{content = <<C/binary, "\\\\">>}]);
  string_fixed(<<"\\'",Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_fixed(Rest, add_pos(Pos,1), [S#string{content = <<C/binary, "\\'">>}]);
  string_fixed(<<"'",Rest/binary>>, Pos, Parsed) ->
      {Rest, add_pos(Pos,1), Parsed};
  string_fixed(<<"\n",Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_fixed(Rest, new_line(Pos), [S#string{content = <<C/binary, "\n">>}]);
  string_fixed(<<A/utf8,Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_fixed(Rest, add_pos(Pos,1), [S#string{content = <<C/binary, A/utf8>>}]).
  
  string_parsed(<<"\\\\",Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_parsed(Rest, add_pos(Pos,1), [S#string{content = <<C/binary, "\\\\">>}]);
  string_parsed(<<"\\\"",Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_parsed(Rest, add_pos(Pos,1), [S#string{content = <<C/binary, "\\\"">>}]);
  string_parsed(<<"\"",Rest/binary>>, Pos, Parsed) ->
      {Rest, add_pos(Pos,1), Parsed};
  string_parsed(<<"\n",Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_parsed(Rest, new_line(Pos), [S#string{content = <<C/binary, "\n">>}]);
  %% TODO add the variable parsing
  string_parsed(<<A/utf8,Rest/binary>>, Pos, [#string{content=C}=S]) ->
      string_parsed(Rest, add_pos(Pos,1), [S#string{content = <<C/binary, A/utf8>>}]).
  
  
  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}, Parsed) ->
      {Rest1, Pos1, Conditions} = conditions(Rest0, {0,Row,Col}, []),
      {Rest2, Pos2, CodeBlock} = code_block(Rest1, Pos1, []),
      If = #st_if{
          conditions=Conditions,
          then=CodeBlock,
          row=Row,
          col=Col
      },
      code(Rest2, Pos2, [If|Parsed]);
  st_if(<<>>, Pos, _Parsed) ->
      throw({error, {parse, Pos, incomplete_if_statement}}).
  
  
negative.code: code_block_level({_,Row,Col}) -> {code_block,Row,Col}.
  code_value_level({_,Row,Col}) -> {code_value,Row,Col}.
  code_statement_level({_,Row,Col}) -> {code_statement,Row,Col}.
  
  % TODO: change this implementation for calculate operations
  add_op('end', [{op,Content}|Parsed]) ->
      [{op,lists:reverse(Content)}|Parsed];
  add_op(Add, [{op,Content}|Parsed]) ->
      [{op,[Add|Content]}|Parsed];
  add_op(Add, Parsed) ->
      [{op,[Add]}|Parsed].
  
  %% took from http://php.net/manual/en/language.operators.precedence.php
  
  -type associativity() :: no_assoc | left | right.
  -spec precedence(binary()) -> {associativity(), pos_integer()} | false.
  
  precedence(<<"clone">>) -> {no_assoc, 1};
  precedence(<<"new">>) -> {no_assoc, 1};
  precedence(<<"[">>) -> {left, 2}; %% array
  precedence(<<"**">>) -> {right, 3}; %% arith
  precedence(<<"++">>) -> {right, 4};
  precedence(<<"--">>) -> {right, 4};
  precedence(<<126>>) -> {right, 4}; %% ~ (types and increment/decrement)
  precedence(<<"(int)">>) -> {right, 4};
  precedence(<<"(float)">>) -> {right, 4};
  precedence(<<"(string)">>) -> {right, 4};
  precedence(<<"(array)">>) -> {right, 4};
  precedence(<<"(object)">>) -> {right, 4};
  precedence(<<"(bool)">>) -> {right, 4};
  precedence(<<"@">>) -> {right, 4};
  precedence(<<"instaceof">>) -> {no_assoc, 5};
  precedence(<<"!">>) -> {right, 6}; %% logic
  precedence(<<"*">>) -> {left, 7};
  precedence(<<"/">>) -> {left, 7};
  precedence(<<"%">>) -> {left, 7};
  precedence(<<"+">>) -> {left, 8};
  precedence(<<"-">>) -> {left, 8};
  precedence(<<".">>) -> {left, 8}; %% concat
  precedence(<<"<<">>) -> {left, 9}; %% bit by bit
  precedence(<<">>">>) -> {left, 9}; %% bit by bit
  precedence(<<"<">>) -> {no_assoc, 10};
  precedence(<<"<=">>) -> {no_assoc, 10};
  precedence(<<">">>) -> {no_assoc, 10};
  precedence(<<">=">>) -> {no_assoc, 10};
  precedence(<<"==">>) -> {no_assoc, 11};
  precedence(<<"!=">>) -> {no_assoc, 11};
  precedence(<<"===">>) -> {no_assoc, 11};
  precedence(<<"!==">>) -> {no_assoc, 11};
  precedence(<<"<>">>) -> {no_assoc, 11};
  precedence(<<"<=>">>) -> {no_assoc, 11};
  precedence(<<"&">>) -> {left, 12}; %% bit by bit & references
  precedence(<<"^">>) -> {left, 13}; %% bit by bit
  precedence(<<"|">>) -> {left, 14}; %% bit by bit
  precedence(<<"&&">>) -> {left, 15}; %% logic
  precedence(<<"||">>) -> {left, 16}; %% logic
  precedence(<<"??">>) -> {right, 17}; %% comparison
  precedence(<<"?:">>) -> {left, 18}; %% ternary
  precedence(<<"=">>) -> {right, 19}; %% assign
  precedence(<<"+=">>) -> {right, 19};
  precedence(<<"-=">>) -> {right, 19};
  precedence(<<"*=">>) -> {right, 19};
  precedence(<<"**=">>) -> {right, 19};
  precedence(<<"/=">>) -> {right, 19};
  precedence(<<".=">>) -> {right, 19};
  precedence(<<"%=">>) -> {right, 19};
  precedence(<<"&=">>) -> {right, 19};
  precedence(<<"|=">>) -> {right, 19};
  precedence(<<"^=">>) -> {right, 19};
  precedence(<<"<<=">>) -> {right, 19};
  precedence(<<">>=">>) -> {right, 19};
  precedence(<<"and">>) -> {left, 20};
  precedence(<<"xor">>) -> {left, 21};
  precedence(<<"or">>) -> {left, 22};
  precedence(_) -> false.
  