%{
open FslexFsyacc
open FslexFsyacc.Lex
let clazz s = s |> List.rev |> List.reduce(fun a b -> Either(a,b))
%}

file :
    | HEADER definition+ "%%" rule+ {s0,List.rev s1,List.rev s3}
    | HEADER rule+ {s0,[],List.rev s1}
definition+ :
    | definition+ definition {s1::s0}
    | definition {[s0]}
definition :
    | CAP "=" expr {s0,s2}
expr :
    | atomic {s0}
    | HOLE {Hole s0}
    | expr "*" {Natural s0}
    | expr "+" {Plural s0}
    | expr "?" {Optional s0}
    | expr "|" expr {Either(s0,s2)}
    | expr "&" expr {Both(s0,s2)}
    | "(" expr ")" {s1}
    | "[" atomic+ "]" {clazz s1}
atomic :
    | ID {Atomic s0}
    | LITERAL {Atomic s0}
atomic+ :
    | atomic+ "&" atomic {s2::s0}
    | atomic {[s0]}
rule+ :
    | rule+ rule {s1::s0}
    | rule {[s0]}
rule :
    | expr "/" expr REDUCER {[s0;s2],s3}
    | expr REDUCER {[s0],s1}

%%

%left "|"
%left "&"
%nonassoc "*" "+" "?"

%%

%type<string> HEADER ID CAP LITERAL REDUCER HOLE
%type<RegularExpression<string>> atomic expr
%type<RegularExpression<string> list> atomic+
%type<string*RegularExpression<string>> definition
%type<(string*RegularExpression<string>)list> definition+
%type<RegularExpression<string>list*string> rule
%type<(RegularExpression<string>list*string)list> rule+
%type<string*(string*RegularExpression<string>)list*(RegularExpression<string>list*string)list> file
