Current section

Files

Jump to
xmlrat src xmlrat_xpath_parse.erl
Raw

src/xmlrat_xpath_parse.erl

-module(xmlrat_xpath_parse).
-export([parse/1,file/1]).
-define(p_charclass,true).
-define(p_choose,true).
-define(p_label,true).
-define(p_optional,true).
-define(p_regexp,true).
-define(p_scan,true).
-define(p_seq,true).
-define(p_string,true).
-define(p_zero_or_more,true).
-spec file(file:name()) -> any().
file(Filename) -> case file:read_file(Filename) of {ok,Bin} -> parse(Bin); Err -> Err end.
-spec parse(binary() | list()) -> any().
parse(List) when is_list(List) -> parse(unicode:characters_to_binary(List));
parse(Input) when is_binary(Input) ->
_ = setup_memo(),
Result = case 'expr'(Input,{{line,1},{column,1}}) of
{AST, <<>>, _Index} -> AST;
Any -> Any
end,
release_memo(), Result.
-spec 'expr'(input(), index()) -> parse_result().
'expr'(Input, Index) ->
p(Input, Index, 'expr', fun(I,D) -> (p_seq([p_optional(fun 's'/2), fun 'orexpr'/2]))(I,D) end, fun(Node, _Idx) ->[_,E] = Node, E end).
-spec 'orexpr'(input(), index()) -> parse_result().
'orexpr'(Input, Index) ->
p(Input, Index, 'orexpr', fun(I,D) -> (p_choose([fun 'orunit'/2, fun 'andexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('orexpr', Node, Idx) end).
-spec 'orunit'(input(), index()) -> parse_result().
'orunit'(Input, Index) ->
p(Input, Index, 'orunit', fun(I,D) -> (p_seq([p_label('a', fun 'andexpr'/2), p_optional(fun 's'/2), p_string(<<"or">>), p_optional(fun 's'/2), p_label('b', fun 'orexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{'or', A, B}
end).
-spec 'andexpr'(input(), index()) -> parse_result().
'andexpr'(Input, Index) ->
p(Input, Index, 'andexpr', fun(I,D) -> (p_choose([fun 'andunit'/2, fun 'eqexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('andexpr', Node, Idx) end).
-spec 'andunit'(input(), index()) -> parse_result().
'andunit'(Input, Index) ->
p(Input, Index, 'andunit', fun(I,D) -> (p_seq([p_label('a', fun 'eqexpr'/2), p_optional(fun 's'/2), p_string(<<"and">>), p_optional(fun 's'/2), p_label('b', fun 'andexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{'and', A, B}
end).
-spec 'eqexpr'(input(), index()) -> parse_result().
'eqexpr'(Input, Index) ->
p(Input, Index, 'eqexpr', fun(I,D) -> (p_choose([fun 'equnit'/2, fun 'nequnit'/2, fun 'relexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('eqexpr', Node, Idx) end).
-spec 'equnit'(input(), index()) -> parse_result().
'equnit'(Input, Index) ->
p(Input, Index, 'equnit', fun(I,D) -> (p_seq([p_label('a', fun 'relexpr'/2), p_optional(fun 's'/2), p_string(<<"=">>), p_optional(fun 's'/2), p_label('b', fun 'eqexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{eq, A, B}
end).
-spec 'nequnit'(input(), index()) -> parse_result().
'nequnit'(Input, Index) ->
p(Input, Index, 'nequnit', fun(I,D) -> (p_seq([p_label('a', fun 'relexpr'/2), p_optional(fun 's'/2), p_string(<<"!=">>), p_optional(fun 's'/2), p_label('b', fun 'eqexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{neq, A, B}
end).
-spec 'relexpr'(input(), index()) -> parse_result().
'relexpr'(Input, Index) ->
p(Input, Index, 'relexpr', fun(I,D) -> (p_choose([fun 'ltunit'/2, fun 'gtunit'/2, fun 'lteunit'/2, fun 'gteunit'/2, fun 'addexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('relexpr', Node, Idx) end).
-spec 'ltunit'(input(), index()) -> parse_result().
'ltunit'(Input, Index) ->
p(Input, Index, 'ltunit', fun(I,D) -> (p_seq([p_label('a', fun 'addexpr'/2), p_optional(fun 's'/2), p_string(<<"<">>), p_optional(fun 's'/2), p_label('b', fun 'relexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{lt, A, B}
end).
-spec 'gtunit'(input(), index()) -> parse_result().
'gtunit'(Input, Index) ->
p(Input, Index, 'gtunit', fun(I,D) -> (p_seq([p_label('a', fun 'addexpr'/2), p_optional(fun 's'/2), p_string(<<">">>), p_optional(fun 's'/2), p_label('b', fun 'relexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{gt, A, B}
end).
-spec 'lteunit'(input(), index()) -> parse_result().
'lteunit'(Input, Index) ->
p(Input, Index, 'lteunit', fun(I,D) -> (p_seq([p_label('a', fun 'addexpr'/2), p_optional(fun 's'/2), p_string(<<"<=">>), p_optional(fun 's'/2), p_label('b', fun 'relexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{lte, A, B}
end).
-spec 'gteunit'(input(), index()) -> parse_result().
'gteunit'(Input, Index) ->
p(Input, Index, 'gteunit', fun(I,D) -> (p_seq([p_label('a', fun 'addexpr'/2), p_optional(fun 's'/2), p_string(<<">=">>), p_optional(fun 's'/2), p_label('b', fun 'relexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{gte, A, B}
end).
-spec 'addexpr'(input(), index()) -> parse_result().
'addexpr'(Input, Index) ->
p(Input, Index, 'addexpr', fun(I,D) -> (p_choose([fun 'addunit'/2, fun 'subunit'/2, fun 'multexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('addexpr', Node, Idx) end).
-spec 'addunit'(input(), index()) -> parse_result().
'addunit'(Input, Index) ->
p(Input, Index, 'addunit', fun(I,D) -> (p_seq([p_label('a', fun 'multexpr'/2), p_optional(fun 's'/2), p_string(<<"+">>), p_optional(fun 's'/2), p_label('b', fun 'addexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{add, A, B}
end).
-spec 'subunit'(input(), index()) -> parse_result().
'subunit'(Input, Index) ->
p(Input, Index, 'subunit', fun(I,D) -> (p_seq([p_label('a', fun 'multexpr'/2), p_optional(fun 's'/2), p_string(<<"-">>), p_optional(fun 's'/2), p_label('b', fun 'addexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{subtract, A, B}
end).
-spec 'multexpr'(input(), index()) -> parse_result().
'multexpr'(Input, Index) ->
p(Input, Index, 'multexpr', fun(I,D) -> (p_choose([fun 'multunit'/2, fun 'divunit'/2, fun 'modunit'/2, fun 'unaryexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('multexpr', Node, Idx) end).
-spec 'multunit'(input(), index()) -> parse_result().
'multunit'(Input, Index) ->
p(Input, Index, 'multunit', fun(I,D) -> (p_seq([p_label('a', fun 'unaryexpr'/2), p_optional(fun 's'/2), p_string(<<"*">>), p_optional(fun 's'/2), p_label('b', fun 'multexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{multiply, A, B}
end).
-spec 'divunit'(input(), index()) -> parse_result().
'divunit'(Input, Index) ->
p(Input, Index, 'divunit', fun(I,D) -> (p_seq([p_label('a', fun 'unaryexpr'/2), p_optional(fun 's'/2), p_string(<<"div">>), p_optional(fun 's'/2), p_label('b', fun 'multexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{'div', A, B}
end).
-spec 'modunit'(input(), index()) -> parse_result().
'modunit'(Input, Index) ->
p(Input, Index, 'modunit', fun(I,D) -> (p_seq([p_label('a', fun 'unaryexpr'/2), p_optional(fun 's'/2), p_string(<<"mod">>), p_optional(fun 's'/2), p_label('b', fun 'multexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{'mod', A, B}
end).
-spec 'unaryexpr'(input(), index()) -> parse_result().
'unaryexpr'(Input, Index) ->
p(Input, Index, 'unaryexpr', fun(I,D) -> (p_choose([fun 'negateunit'/2, fun 'unionexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('unaryexpr', Node, Idx) end).
-spec 'negateunit'(input(), index()) -> parse_result().
'negateunit'(Input, Index) ->
p(Input, Index, 'negateunit', fun(I,D) -> (p_seq([p_string(<<"-">>), p_optional(fun 's'/2), fun 'unaryexpr'/2]))(I,D) end, fun(Node, _Idx) ->[_,_,A] = Node, {negate, A} end).
-spec 'unionexpr'(input(), index()) -> parse_result().
'unionexpr'(Input, Index) ->
p(Input, Index, 'unionexpr', fun(I,D) -> (p_choose([fun 'unionunit'/2, fun 'pathexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('unionexpr', Node, Idx) end).
-spec 'unionunit'(input(), index()) -> parse_result().
'unionunit'(Input, Index) ->
p(Input, Index, 'unionunit', fun(I,D) -> (p_seq([p_label('a', fun 'pathexpr'/2), p_optional(fun 's'/2), p_string(<<"|">>), p_optional(fun 's'/2), p_label('b', fun 'unionexpr'/2)]))(I,D) end, fun(Node, _Idx) ->
A = proplists:get_value(a, Node),
B = proplists:get_value(b, Node),
{union, A, B}
end).
-spec 'pathexpr'(input(), index()) -> parse_result().
'pathexpr'(Input, Index) ->
p(Input, Index, 'pathexpr', fun(I,D) -> (p_choose([fun 'relanyunit'/2, fun 'relunit'/2, fun 'filterexpr'/2, fun 'locpath'/2]))(I,D) end, fun(Node, Idx) ->transform('pathexpr', Node, Idx) end).
-spec 'relunit'(input(), index()) -> parse_result().
'relunit'(Input, Index) ->
p(Input, Index, 'relunit', fun(I,D) -> (p_seq([p_label('e', fun 'filterexpr'/2), p_optional(fun 's'/2), p_string(<<"\/">>), p_optional(fun 's'/2), p_label('p', fun 'rellocpath'/2)]))(I,D) end, fun(Node, _Idx) ->
Expr = proplists:get_value(e, Node),
Path = proplists:get_value(p, Node),
lists:flatten([Expr]) ++ Path
end).
-spec 'relanyunit'(input(), index()) -> parse_result().
'relanyunit'(Input, Index) ->
p(Input, Index, 'relanyunit', fun(I,D) -> (p_seq([p_label('e', fun 'filterexpr'/2), p_optional(fun 's'/2), p_string(<<"\/\/">>), p_optional(fun 's'/2), p_label('p', fun 'rellocpath'/2)]))(I,D) end, fun(Node, _Idx) ->
Expr = proplists:get_value(e, Node),
Path = proplists:get_value(p, Node),
lists:flatten([Expr, '_']) ++ Path
end).
-spec 'filterexpr'(input(), index()) -> parse_result().
'filterexpr'(Input, Index) ->
p(Input, Index, 'filterexpr', fun(I,D) -> (p_choose([fun 'filterunit'/2, fun 'primaryexpr'/2]))(I,D) end, fun(Node, Idx) ->transform('filterexpr', Node, Idx) end).
-spec 'filterunit'(input(), index()) -> parse_result().
'filterunit'(Input, Index) ->
p(Input, Index, 'filterunit', fun(I,D) -> (p_seq([p_label('e', fun 'primaryexpr'/2), p_optional(fun 's'/2), p_label('p', fun 'predicate'/2)]))(I,D) end, fun(Node, _Idx) ->
Expr = proplists:get_value(e, Node),
Pred = proplists:get_value(p, Node),
[Expr, {self, {name_match, '*'}, Pred}]
end).
-spec 'predicate'(input(), index()) -> parse_result().
'predicate'(Input, Index) ->
p(Input, Index, 'predicate', fun(I,D) -> (p_seq([p_string(<<"[">>), p_optional(fun 's'/2), p_label('e', fun 'expr'/2), p_optional(fun 's'/2), p_string(<<"]">>)]))(I,D) end, fun(Node, _Idx) ->
Expr = proplists:get_value(e, Node),
Expr
end).
-spec 'primaryexpr'(input(), index()) -> parse_result().
'primaryexpr'(Input, Index) ->
p(Input, Index, 'primaryexpr', fun(I,D) -> (p_choose([fun 'varref'/2, fun 'bracketexpr'/2, fun 'literal'/2, fun 'number'/2, fun 'funcall'/2]))(I,D) end, fun(Node, Idx) ->transform('primaryexpr', Node, Idx) end).
-spec 'bracketexpr'(input(), index()) -> parse_result().
'bracketexpr'(Input, Index) ->
p(Input, Index, 'bracketexpr', fun(I,D) -> (p_seq([p_string(<<"(">>), p_optional(fun 's'/2), p_label('i', fun 'orexpr'/2), p_optional(fun 's'/2), p_string(<<")">>)]))(I,D) end, fun(Node, _Idx) ->proplists:get_value(i, Node) end).
-spec 'locpath'(input(), index()) -> parse_result().
'locpath'(Input, Index) ->
p(Input, Index, 'locpath', fun(I,D) -> (p_choose([fun 'rellocpath'/2, fun 'abslocpath'/2]))(I,D) end, fun(Node, _Idx) ->lists:flatten(Node) end).
-spec 'abslocpath'(input(), index()) -> parse_result().
'abslocpath'(Input, Index) ->
p(Input, Index, 'abslocpath', fun(I,D) -> (p_choose([fun 'abbrabslocunit'/2, fun 'abslocunit'/2]))(I,D) end, fun(Node, Idx) ->transform('abslocpath', Node, Idx) end).
-spec 'abslocunit'(input(), index()) -> parse_result().
'abslocunit'(Input, Index) ->
p(Input, Index, 'abslocunit', fun(I,D) -> (p_seq([p_string(<<"\/">>), p_optional(fun 's'/2), p_optional(fun 'rellocpath'/2)]))(I,D) end, fun(Node, _Idx) ->[_, _, P] = Node, [absolute, P] end).
-spec 'abbrabslocunit'(input(), index()) -> parse_result().
'abbrabslocunit'(Input, Index) ->
p(Input, Index, 'abbrabslocunit', fun(I,D) -> (p_seq([p_string(<<"\/\/">>), p_optional(fun 's'/2), fun 'rellocpath'/2]))(I,D) end, fun(Node, _Idx) ->[_,_,P] = Node, [absolute, '_', P] end).
-spec 'rellocpath'(input(), index()) -> parse_result().
'rellocpath'(Input, Index) ->
p(Input, Index, 'rellocpath', fun(I,D) -> (p_seq([fun 'step'/2, p_zero_or_more(p_choose([fun 'pathunit'/2, fun 'abbrrellocpath'/2]))]))(I,D) end, fun(Node, _Idx) ->lists:flatten(Node) end).
-spec 'abbrrellocpath'(input(), index()) -> parse_result().
'abbrrellocpath'(Input, Index) ->
p(Input, Index, 'abbrrellocpath', fun(I,D) -> (p_seq([p_string(<<"\/\/">>), p_optional(fun 's'/2), fun 'step'/2]))(I,D) end, fun(Node, _Idx) ->[_,_,S] = Node, ['_', S] end).
-spec 'pathunit'(input(), index()) -> parse_result().
'pathunit'(Input, Index) ->
p(Input, Index, 'pathunit', fun(I,D) -> (p_seq([p_string(<<"\/">>), p_optional(fun 's'/2), fun 'step'/2]))(I,D) end, fun(Node, _Idx) ->[_,_,S] = Node, S end).
-spec 'step'(input(), index()) -> parse_result().
'step'(Input, Index) ->
p(Input, Index, 'step', fun(I,D) -> (p_choose([fun 'fullstep'/2, fun 'abbrstep'/2]))(I,D) end, fun(Node, Idx) ->transform('step', Node, Idx) end).
-spec 'fullstep'(input(), index()) -> parse_result().
'fullstep'(Input, Index) ->
p(Input, Index, 'fullstep', fun(I,D) -> (p_seq([p_optional(fun 'axisspec'/2), p_optional(fun 's'/2), fun 'nodetest'/2, p_zero_or_more(p_seq([p_optional(fun 's'/2), fun 'predicate'/2]))]))(I,D) end, fun(Node, _Idx) ->
[Axis0, _, NodeTest, Preds0] = Node,
Axis1 = case Axis0 of
A when is_atom(A) -> A;
_ -> child
end,
Preds1 = [X || [_S, X] <- Preds0],
{Axis1, NodeTest, lists:flatten(Preds1)}
end).
-spec 'abbrstep'(input(), index()) -> parse_result().
'abbrstep'(Input, Index) ->
p(Input, Index, 'abbrstep', fun(I,D) -> (p_choose([p_label('self', p_string(<<".">>)), p_label('parent', p_string(<<"..">>))]))(I,D) end, fun(Node, _Idx) ->
case Node of
{self, _} -> self;
{parent, _} -> parent
end
end).
-spec 'axisspec'(input(), index()) -> parse_result().
'axisspec'(Input, Index) ->
p(Input, Index, 'axisspec', fun(I,D) -> (p_choose([fun 'fullaxisspec'/2, fun 'abbraxisspec'/2]))(I,D) end, fun(Node, Idx) ->transform('axisspec', Node, Idx) end).
-spec 'fullaxisspec'(input(), index()) -> parse_result().
'fullaxisspec'(Input, Index) ->
p(Input, Index, 'fullaxisspec', fun(I,D) -> (p_seq([fun 'axisname'/2, p_optional(fun 's'/2), p_string(<<"::">>)]))(I,D) end, fun(Node, _Idx) ->[Axis|_] = Node, Axis end).
-spec 'abbraxisspec'(input(), index()) -> parse_result().
'abbraxisspec'(Input, Index) ->
p(Input, Index, 'abbraxisspec', fun(I,D) -> (p_seq([p_optional(fun 's'/2), p_string(<<"@">>)]))(I,D) end, fun(_Node, _Idx) ->attribute end).
-spec 'funcall'(input(), index()) -> parse_result().
'funcall'(Input, Index) ->
p(Input, Index, 'funcall', fun(I,D) -> (p_seq([p_label('name', fun 'qname'/2), p_optional(fun 's'/2), p_string(<<"(">>), p_optional(fun 's'/2), p_label('args', p_optional(fun 'funargs'/2)), p_optional(fun 's'/2), p_string(<<")">>)]))(I,D) end, fun(Node, _Idx) ->
Fun = proplists:get_value(name, Node),
Args = proplists:get_value(args, Node),
{function_call, Fun, Args}
end).
-spec 'funargs'(input(), index()) -> parse_result().
'funargs'(Input, Index) ->
p(Input, Index, 'funargs', fun(I,D) -> (p_seq([p_label('head', fun 'expr'/2), p_label('tail', p_zero_or_more(p_seq([p_optional(fun 's'/2), p_string(<<",">>), p_optional(fun 's'/2), fun 'expr'/2])))]))(I,D) end, fun(Node, _Idx) ->
Head = proplists:get_value(head, Node),
Tails = proplists:get_value(tail, Node),
Tail = [X || [_, _, _, X] <- Tails],
[Head | Tail]
end).
-spec 'nodetest'(input(), index()) -> parse_result().
'nodetest'(Input, Index) ->
p(Input, Index, 'nodetest', fun(I,D) -> (p_choose([fun 'nodebracket'/2, fun 'pi'/2, fun 'nametest'/2]))(I,D) end, fun(Node, Idx) ->transform('nodetest', Node, Idx) end).
-spec 'nodebracket'(input(), index()) -> parse_result().
'nodebracket'(Input, Index) ->
p(Input, Index, 'nodebracket', fun(I,D) -> (p_seq([p_label('t', fun 'nodetype'/2), p_optional(fun 's'/2), p_string(<<"(">>), p_optional(fun 's'/2), p_string(<<")">>)]))(I,D) end, fun(Node, _Idx) ->
[{t,Type}|_] = Node,
{type_match, Type}
end).
-spec 'pi'(input(), index()) -> parse_result().
'pi'(Input, Index) ->
p(Input, Index, 'pi', fun(I,D) -> (p_seq([p_string(<<"processing-instruction">>), p_optional(fun 's'/2), p_string(<<"(">>), p_optional(fun 's'/2), p_label('arg', fun 'literal'/2), p_optional(fun 's'/2), p_string(<<")">>)]))(I,D) end, fun(Node, _Idx) ->
Arg = proplists:get_value(arg, Node),
{pi, Arg}
end).
-spec 'nodetype'(input(), index()) -> parse_result().
'nodetype'(Input, Index) ->
p(Input, Index, 'nodetype', fun(I,D) -> (p_choose([p_string(<<"comment">>), p_string(<<"text">>), p_string(<<"processing-instruction">>), p_string(<<"node">>)]))(I,D) end, fun(Node, _Idx) ->binary_to_atom(iolist_to_binary(Node)) end).
-spec 'nametest'(input(), index()) -> parse_result().
'nametest'(Input, Index) ->
p(Input, Index, 'nametest', fun(I,D) -> (p_choose([fun 'nametestany'/2, fun 'nametestns'/2, fun 'qname'/2]))(I,D) end, fun(Node, _Idx) ->{name_match, Node} end).
-spec 'nametestns'(input(), index()) -> parse_result().
'nametestns'(Input, Index) ->
p(Input, Index, 'nametestns', fun(I,D) -> (p_seq([fun 'ncname'/2, p_optional(fun 's'/2), p_string(<<":">>), p_optional(fun 's'/2), p_string(<<"*">>)]))(I,D) end, fun(Node, _Idx) ->[NS|_] = Node, {NS, '_'} end).
-spec 'nametestany'(input(), index()) -> parse_result().
'nametestany'(Input, Index) ->
p(Input, Index, 'nametestany', fun(I,D) -> (p_string(<<"*">>))(I,D) end, fun(_Node, _Idx) ->'_' end).
-spec 'varref'(input(), index()) -> parse_result().
'varref'(Input, Index) ->
p(Input, Index, 'varref', fun(I,D) -> (p_seq([p_string(<<"$">>), fun 'qname'/2]))(I,D) end, fun(Node, _Idx) ->[_,Name] = Node, {var, Name} end).
-spec 'axisname'(input(), index()) -> parse_result().
'axisname'(Input, Index) ->
p(Input, Index, 'axisname', fun(I,D) -> (p_choose([p_string(<<"ancestor">>), p_string(<<"ancestor-or-self">>), p_string(<<"attribute">>), p_string(<<"child">>), p_string(<<"descendant">>), p_string(<<"descendant-or-self">>), p_string(<<"following">>), p_string(<<"following-sibling">>), p_string(<<"namespace">>), p_string(<<"parent">>), p_string(<<"preceding">>), p_string(<<"preceding-sibling">>), p_string(<<"self">>)]))(I,D) end, fun(Node, _Idx) ->binary_to_atom(iolist_to_binary(Node)) end).
-spec 'ncname'(input(), index()) -> parse_result().
'ncname'(Input, Index) ->
p(Input, Index, 'ncname', fun(I,D) -> (p_regexp(<<"[A-Z_a-z][A-Z_a-z\\-.0-9]*">>))(I,D) end, fun(Node, _Idx) ->iolist_to_binary(Node) end).
-spec 'qname'(input(), index()) -> parse_result().
'qname'(Input, Index) ->
p(Input, Index, 'qname', fun(I,D) -> (p_seq([fun 'ncname'/2, p_optional(p_seq([p_string(<<":">>), fun 'ncname'/2]))]))(I,D) end, fun(Node, _Idx) ->
case Node of
[NS, [_, N]] when is_binary(N) -> {NS, N};
[N, _] -> N
end
end).
-spec 's'(input(), index()) -> parse_result().
's'(Input, Index) ->
p(Input, Index, 's', fun(I,D) -> (p_regexp(<<"[\\x20\\x09\\x0d\\x0A]+">>))(I,D) end, fun(Node, _Idx) ->Node end).
-spec 'literal'(input(), index()) -> parse_result().
'literal'(Input, Index) ->
p(Input, Index, 'literal', fun(I,D) -> (p_choose([fun 'dqlit'/2, fun 'sqlit'/2]))(I,D) end, fun(Node, Idx) ->transform('literal', Node, Idx) end).
-spec 'dqlit'(input(), index()) -> parse_result().
'dqlit'(Input, Index) ->
p(Input, Index, 'dqlit', fun(I,D) -> (p_seq([p_charclass(<<"[\"]">>), p_regexp(<<"[^\"]*">>), p_charclass(<<"[\"]">>)]))(I,D) end, fun(Node, _Idx) ->[_,D,_] = Node, iolist_to_binary(D) end).
-spec 'sqlit'(input(), index()) -> parse_result().
'sqlit'(Input, Index) ->
p(Input, Index, 'sqlit', fun(I,D) -> (p_seq([p_charclass(<<"[\']">>), p_regexp(<<"[^']*">>), p_charclass(<<"[\']">>)]))(I,D) end, fun(Node, _Idx) ->[_,D,_] = Node, iolist_to_binary(D) end).
-spec 'number'(input(), index()) -> parse_result().
'number'(Input, Index) ->
p(Input, Index, 'number', fun(I,D) -> (p_choose([fun 'int'/2, fun 'float'/2, fun 'zerofloat'/2]))(I,D) end, fun(Node, Idx) ->transform('number', Node, Idx) end).
-spec 'int'(input(), index()) -> parse_result().
'int'(Input, Index) ->
p(Input, Index, 'int', fun(I,D) -> (p_regexp(<<"[0-9]+">>))(I,D) end, fun(Node, _Idx) ->binary_to_integer(iolist_to_binary(Node)) end).
-spec 'float'(input(), index()) -> parse_result().
'float'(Input, Index) ->
p(Input, Index, 'float', fun(I,D) -> (p_seq([p_regexp(<<"[0-9]+">>), p_string(<<".">>), p_regexp(<<"[0-9]*">>)]))(I,D) end, fun(Node, _Idx) ->binary_to_float(iolist_to_binary(Node)) end).
-spec 'zerofloat'(input(), index()) -> parse_result().
'zerofloat'(Input, Index) ->
p(Input, Index, 'zerofloat', fun(I,D) -> (p_regexp(<<"[.][0-9]+">>))(I,D) end, fun(Node, _Idx) ->binary_to_float(iolist_to_binary([$0, Node])) end).
transform(_,Node,_Index) -> Node.
-file("peg_includes.hrl", 1).
-type index() :: {{line, pos_integer()}, {column, pos_integer()}}.
-type input() :: binary().
-type parse_failure() :: {fail, term()}.
-type parse_success() :: {term(), input(), index()}.
-type parse_result() :: parse_failure() | parse_success().
-type parse_fun() :: fun((input(), index()) -> parse_result()).
-type xform_fun() :: fun((input(), index()) -> term()).
-spec p(input(), index(), atom(), parse_fun(), xform_fun()) -> parse_result().
p(Inp, StartIndex, Name, ParseFun, TransformFun) ->
case get_memo(StartIndex, Name) of % See if the current reduction is memoized
{ok, Memo} -> %Memo; % If it is, return the stored result
Memo;
_ -> % If not, attempt to parse
Result = case ParseFun(Inp, StartIndex) of
{fail,_} = Failure -> % If it fails, memoize the failure
Failure;
{Match, InpRem, NewIndex} -> % If it passes, transform and memoize the result.
Transformed = TransformFun(Match, StartIndex),
{Transformed, InpRem, NewIndex}
end,
memoize(StartIndex, Name, Result),
Result
end.
-spec setup_memo() -> ets:tid().
setup_memo() ->
put({parse_memo_table, ?MODULE}, ets:new(?MODULE, [set])).
-spec release_memo() -> true.
release_memo() ->
ets:delete(memo_table_name()).
-spec memoize(index(), atom(), parse_result()) -> true.
memoize(Index, Name, Result) ->
Memo = case ets:lookup(memo_table_name(), Index) of
[] -> [];
[{Index, Plist}] -> Plist
end,
ets:insert(memo_table_name(), {Index, [{Name, Result}|Memo]}).
-spec get_memo(index(), atom()) -> {ok, term()} | {error, not_found}.
get_memo(Index, Name) ->
case ets:lookup(memo_table_name(), Index) of
[] -> {error, not_found};
[{Index, Plist}] ->
case proplists:lookup(Name, Plist) of
{Name, Result} -> {ok, Result};
_ -> {error, not_found}
end
end.
-spec memo_table_name() -> ets:tid().
memo_table_name() ->
get({parse_memo_table, ?MODULE}).
-ifdef(p_eof).
-spec p_eof() -> parse_fun().
p_eof() ->
fun(<<>>, Index) -> {eof, [], Index};
(_, Index) -> {fail, {expected, eof, Index}} end.
-endif.
-ifdef(p_optional).
-spec p_optional(parse_fun()) -> parse_fun().
p_optional(P) ->
fun(Input, Index) ->
case P(Input, Index) of
{fail,_} -> {[], Input, Index};
{_, _, _} = Success -> Success
end
end.
-endif.
-ifdef(p_not).
-spec p_not(parse_fun()) -> parse_fun().
p_not(P) ->
fun(Input, Index)->
case P(Input,Index) of
{fail,_} ->
{[], Input, Index};
{Result, _, _} -> {fail, {expected, {no_match, Result},Index}}
end
end.
-endif.
-ifdef(p_assert).
-spec p_assert(parse_fun()) -> parse_fun().
p_assert(P) ->
fun(Input,Index) ->
case P(Input,Index) of
{fail,_} = Failure-> Failure;
_ -> {[], Input, Index}
end
end.
-endif.
-ifdef(p_seq).
-spec p_seq([parse_fun()]) -> parse_fun().
p_seq(P) ->
fun(Input, Index) ->
p_all(P, Input, Index, [])
end.
-spec p_all([parse_fun()], input(), index(), [term()]) -> parse_result().
p_all([], Inp, Index, Accum ) -> {lists:reverse( Accum ), Inp, Index};
p_all([P|Parsers], Inp, Index, Accum) ->
case P(Inp, Index) of
{fail, _} = Failure -> Failure;
{Result, InpRem, NewIndex} -> p_all(Parsers, InpRem, NewIndex, [Result|Accum])
end.
-endif.
-ifdef(p_choose).
-spec p_choose([parse_fun()]) -> parse_fun().
p_choose(Parsers) ->
fun(Input, Index) ->
p_attempt(Parsers, Input, Index, none)
end.
-spec p_attempt([parse_fun()], input(), index(), none | parse_failure()) -> parse_result().
p_attempt([], _Input, _Index, Failure) -> Failure;
p_attempt([P|Parsers], Input, Index, FirstFailure)->
case P(Input, Index) of
{fail, _} = Failure ->
case FirstFailure of
none -> p_attempt(Parsers, Input, Index, Failure);
_ -> p_attempt(Parsers, Input, Index, FirstFailure)
end;
Result -> Result
end.
-endif.
-ifdef(p_zero_or_more).
-spec p_zero_or_more(parse_fun()) -> parse_fun().
p_zero_or_more(P) ->
fun(Input, Index) ->
p_scan(P, Input, Index, [])
end.
-endif.
-ifdef(p_one_or_more).
-spec p_one_or_more(parse_fun()) -> parse_fun().
p_one_or_more(P) ->
fun(Input, Index)->
Result = p_scan(P, Input, Index, []),
case Result of
{[_|_], _, _} ->
Result;
_ ->
{fail, {expected, Failure, _}} = P(Input,Index),
{fail, {expected, {at_least_one, Failure}, Index}}
end
end.
-endif.
-ifdef(p_label).
-spec p_label(atom(), parse_fun()) -> parse_fun().
p_label(Tag, P) ->
fun(Input, Index) ->
case P(Input, Index) of
{fail,_} = Failure ->
Failure;
{Result, InpRem, NewIndex} ->
{{Tag, Result}, InpRem, NewIndex}
end
end.
-endif.
-ifdef(p_scan).
-spec p_scan(parse_fun(), input(), index(), [term()]) -> {[term()], input(), index()}.
p_scan(_, <<>>, Index, Accum) -> {lists:reverse(Accum), <<>>, Index};
p_scan(P, Inp, Index, Accum) ->
case P(Inp, Index) of
{fail,_} -> {lists:reverse(Accum), Inp, Index};
{Result, InpRem, NewIndex} -> p_scan(P, InpRem, NewIndex, [Result | Accum])
end.
-endif.
-ifdef(p_string).
-spec p_string(binary()) -> parse_fun().
p_string(S) ->
Length = erlang:byte_size(S),
fun(Input, Index) ->
try
<<S:Length/binary, Rest/binary>> = Input,
{S, Rest, p_advance_index(S, Index)}
catch
error:{badmatch,_} -> {fail, {expected, {string, S}, Index}}
end
end.
-endif.
-ifdef(p_anything).
-spec p_anything() -> parse_fun().
p_anything() ->
fun(<<>>, Index) -> {fail, {expected, any_character, Index}};
(Input, Index) when is_binary(Input) ->
<<C/utf8, Rest/binary>> = Input,
{<<C/utf8>>, Rest, p_advance_index(<<C/utf8>>, Index)}
end.
-endif.
-ifdef(p_charclass).
-spec p_charclass(string() | binary()) -> parse_fun().
p_charclass(Class) ->
{ok, RE} = re:compile(Class, [unicode, dotall]),
fun(Inp, Index) ->
case re:run(Inp, RE, [anchored]) of
{match, [{0, Length}|_]} ->
{Head, Tail} = erlang:split_binary(Inp, Length),
{Head, Tail, p_advance_index(Head, Index)};
_ -> {fail, {expected, {character_class, binary_to_list(Class)}, Index}}
end
end.
-endif.
-ifdef(p_regexp).
-spec p_regexp(binary()) -> parse_fun().
p_regexp(Regexp) ->
{ok, RE} = re:compile(Regexp, [unicode, dotall, anchored]),
fun(Inp, Index) ->
case re:run(Inp, RE) of
{match, [{0, Length}|_]} ->
{Head, Tail} = erlang:split_binary(Inp, Length),
{Head, Tail, p_advance_index(Head, Index)};
_ -> {fail, {expected, {regexp, binary_to_list(Regexp)}, Index}}
end
end.
-endif.
-ifdef(line).
-spec line(index() | term()) -> pos_integer() | undefined.
line({{line,L},_}) -> L;
line(_) -> undefined.
-endif.
-ifdef(column).
-spec column(index() | term()) -> pos_integer() | undefined.
column({_,{column,C}}) -> C;
column(_) -> undefined.
-endif.
-spec p_advance_index(input() | unicode:charlist() | pos_integer(), index()) -> index().
p_advance_index(MatchedInput, Index) when is_list(MatchedInput) orelse is_binary(MatchedInput)-> % strings
lists:foldl(fun p_advance_index/2, Index, unicode:characters_to_list(MatchedInput));
p_advance_index(MatchedInput, Index) when is_integer(MatchedInput) -> % single characters
{{line, Line}, {column, Col}} = Index,
case MatchedInput of
$\n -> {{line, Line+1}, {column, 1}};
_ -> {{line, Line}, {column, Col+1}}
end.