(* camlp4 pa_r.cmo pa_rp.cmo pa_extend.cmo q_MLast.cmo pr_dump.cmo *)
(* File generated by pretty print; do not edit! *)

open Pcaml;
open Stdpp;

type choice 'a 'b =
  [ Left of 'a
  | Right of 'b ]
;

(* Buffer *)

module Buff =
  struct
    value buff = ref (String.create 80);
    value store len x =
      do {
        if len >= String.length buff.val then
          buff.val := buff.val ^ String.create (String.length buff.val)
        else ();
        buff.val.[len] := x;
        succ len
      }
    ;
    value get len = String.sub buff.val 0 len;
  end
;

(* Lexer *)

value rec skip_to_eol =
  parser
  [ [: `'\n' | '\r' :] -> ()
  | [: `_; s :] -> skip_to_eol s ]
;

value no_ident = ['('; ')'; ' '; '\t'; '\n'; '\r'; ';'];

value rec ident len =
  parser
  [ [: `x when not (List.mem x no_ident); s :] -> ident (Buff.store len x) s
  | [: :] -> Buff.get len ]
;

value rec string len =
  parser
  [ [: `'"' :] -> Buff.get len
  | [: `'\\'; `c; s :] -> string (Buff.store (Buff.store len '\\') c) s
  | [: `x; s :] -> string (Buff.store len x) s ]
;

value rec number len =
  parser
  [ [: `('0'..'9' as c); s :] -> number (Buff.store len c) s
  | [: :] -> ("INT", Buff.get len) ]
;

value char_or_quote_id x =
  parser
  [ [: `''' :] -> ("CHAR", String.make 1 x)
  | [: s :] ->
      let len = Buff.store (Buff.store 0 ''') x in
      ("LIDENT", ident len s) ]
;

value rec char len =
  parser
  [ [: `''' :] -> len
  | [: `x; s :] -> char (Buff.store len x) s ]
;

value quote =
  parser
  [ [: `'\\'; len = char (Buff.store 0 '\\') :] -> ("CHAR", Buff.get len)
  | [: `x; s :] -> char_or_quote_id x s ]
;

value rec lexer kwt =
  parser bp
  [ [: `' ' | '\t' | '\n' | '\r'; s :] -> lexer kwt s
  | [: `';'; a = semi kwt bp :] -> a
  | [: `'(' :] -> (("", "("), (bp, bp + 1))
  | [: `')' :] -> (("", ")"), (bp, bp + 1))
  | [: `'"'; s = string 0 :] ep -> (("STRING", s), (bp, ep))
  | [: `'''; tok = quote :] ep -> (tok, (bp, ep))
  | [: `'<'; tok = less :] ep -> (tok, (bp, ep))
  | [: `('0'..'9' as c); n = number (Buff.store 0 c) :] ep -> (n, (bp, ep))
  | [: `x; s = ident (Buff.store 0 x) :] ep ->
      let con =
        try do { (Hashtbl.find kwt s : unit); "" } with
        [ Not_found ->
            match x with
            [ 'A'..'Z' -> "UIDENT"
            | _ -> "LIDENT" ] ]
      in
      ((con, s), (bp, ep))
  | [: :] -> (("EOI", ""), (bp, bp + 1)) ]
and semi kwt bp =
  parser
  [ [: `';'; _ = skip_to_eol; s :] -> lexer kwt s
  | [: :] ep -> (("", ";"), (bp, ep)) ]
and less =
  parser
  [ [: `':'; lab = label 0; `'<' ? "'<' expected"; q = quotation 0 :] ->
      ("QUOT", lab ^ ":" ^ q)
  | [: :] -> ("LIDENT", "<") ]
and label len =
  parser
  [ [: `('a'..'z' | 'A'..'Z' | '_' as c); s :] -> label (Buff.store len c) s
  | [: :] -> Buff.get len ]
and quotation len =
  parser
  [ [: `'>'; s :] -> quotation_greater len s
  | [: `x; s :] -> quotation (Buff.store len x) s
  | [: :] -> failwith "quotation not terminated" ]
and quotation_greater len =
  parser
  [ [: `'>' :] -> Buff.get len
  | [: a = quotation (Buff.store len '>') :] -> a ]
;

value lexer_using kwt (con, prm) =
  match con with
  [ "CHAR" | "EOI" | "INT" | "LIDENT" | "QUOT" | "STRING" | "UIDENT" -> ()
  | "ANTIQUOT" -> ()
  | "" ->
      try Hashtbl.find kwt prm with [ Not_found -> Hashtbl.add kwt prm () ]
  | _ ->
      raise
        (Token.Error
           ("the constructor \"" ^ con ^ "\" is not recognized by Plexer")) ]
;

value lexer_text (con, prm) =
  if con = "" then "'" ^ prm ^ "'"
  else if prm = "" then con
  else con ^ " \"" ^ prm ^ "\""
;

value lexer_gmake () =
  let kwt = Hashtbl.create 89 in
  {Token.tok_func = Token.lexer_func_of_parser (lexer kwt);
   Token.tok_using = lexer_using kwt; Token.tok_removing = fun [];
   Token.tok_match = Token.default_match; Token.tok_text = lexer_text}
;

(* Building AST *)

type sexpr =
  [ Sexpr of MLast.loc and list sexpr
  | Satom of MLast.loc and atom and string
  | Squot of MLast.loc and string and string ]
and atom =
  [ Alid
  | Auid
  | Aint
  | Achar
  | Astring ]
;

value error_loc loc err =
  raise_with_loc loc (Stream.Error (err ^ " expected"))
;
value error se err =
  let loc =
    match se with [ Satom loc _ _ | Sexpr loc _ | Squot loc _ _ -> loc ]
  in
  error_loc loc err
;

value expr_id loc s =
  match s.[0] with
  [ 'A'..'Z' -> <:expr< $uid:s$ >>
  | _ -> <:expr< $lid:s$ >> ]
;

value patt_id loc s =
  match s.[0] with
  [ 'A'..'Z' -> <:patt< $uid:s$ >>
  | _ -> <:patt< $lid:s$ >> ]
;

value ctyp_id loc s =
  match s.[0] with
  [ ''' ->
      let s = String.sub s 1 (String.length s - 1) in
      <:ctyp< '$s$ >>
  | 'A'..'Z' -> <:ctyp< $uid:s$ >>
  | _ -> <:ctyp< $lid:s$ >> ]
;

value strm_n = "strm__";
value peek_fun loc = <:expr< Stream.peek >>;
value junk_fun loc = <:expr< Stream.junk >>;

value rec module_expr_se =
  fun
  [ Sexpr loc [Satom _ Alid "struct" :: sl] ->
      let mel = List.map str_item_se sl in
      <:module_expr< struct $list:mel$ end >>
  | Satom loc Auid s -> <:module_expr< $uid:s$ >>
  | se -> error se "module expr" ]
and str_item_se se =
  match se with
  [ Satom loc _ _ | Squot loc _ _ ->
      let e = expr_se se in
      <:str_item< $exp:e$ >>
  | Sexpr loc [Satom _ Alid "module"; Satom _ Auid i; se] ->
      let mb = module_binding_se se in
      <:str_item< module $i$ = $mb$ >>
  | Sexpr loc [Satom _ Alid "open"; Satom _ Auid s] ->
      let s = [s] in
      <:str_item< open $s$ >>
  | Sexpr loc [Satom _ Alid "type" :: sel] ->
      let tdl = type_declaration_list_se sel in
      <:str_item< type $list:tdl$ >>
  | Sexpr loc [Satom _ Alid "value" :: sel] ->
      let (r, sel) =
        match sel with
        [ [Satom _ Alid "rec" :: sel] -> (True, sel)
        | _ -> (False, sel) ]
      in
      let lbs = value_binding_se sel in
      <:str_item< value $rec:r$ $list:lbs$ >>
  | Sexpr loc _ ->
      let e = expr_se se in
      <:str_item< $exp:e$ >> ]
and value_binding_se =
  fun
  [ [se1; se2 :: sel] -> [(ipatt_se se1, expr_se se2) :: value_binding_se sel]
  | [] -> []
  | [se :: _] -> error se "value_binding" ]
and module_binding_se se = module_expr_se se
and expr_se =
  fun
  [ Satom loc (Alid | Auid) s -> expr_ident_se loc s
  | Satom loc Aint s -> <:expr< $int:s$ >>
  | Satom loc Achar s -> <:expr< $chr:s$ >>
  | Satom loc Astring s -> <:expr< $str:s$ >>
  | Sexpr loc [] -> <:expr< () >>
  | Sexpr loc [Satom _ Alid "if"; se; se1] ->
      let e = expr_se se in
      let e1 = expr_se se1 in
      <:expr< if $e$ then $e1$ else () >>
  | Sexpr loc [Satom _ Alid "if"; se; se1; se2] ->
      let e = expr_se se in
      let e1 = expr_se se1 in
      let e2 = expr_se se2 in
      <:expr< if $e$ then $e1$ else $e2$ >>
  | Sexpr loc [Satom loc1 Alid "lambda"] -> <:expr< fun [] >>
  | Sexpr loc [Satom loc1 Alid "lambda"; sep :: sel] ->
      let e = progn_se loc1 sel in
      match ipatt_opt_se sep with
      [ Left p -> <:expr< fun $p$ -> $e$ >>
      | Right (se, sel) ->
          List.fold_right
            (fun se e ->
               let p = ipatt_se se in
               <:expr< fun $p$ -> $e$ >>)
            [se :: sel] e ]
  | Sexpr loc [Satom _ Alid "lambda_match" :: sel] ->
      let pel = List.map (match_case loc) sel in
      <:expr< fun [ $list:pel$ ] >>
  | Sexpr loc [Satom _ Alid "let" :: sel] ->
      let (r, sel) =
        match sel with
        [ [Satom _ Alid "rec" :: sel] -> (True, sel)
        | _ -> (False, sel) ]
      in
      match sel with
      [ [Sexpr _ sel1 :: sel2] ->
          let lbs = List.map let_binding_se sel1 in
          let e = progn_se loc sel2 in
          <:expr< let $rec:r$ $list:lbs$ in $e$ >>
      | [se :: _] -> error se "let_binding"
      | _ -> error_loc loc "let_binding" ]
  | Sexpr loc [Satom _ Alid "let*" :: sel] ->
      match sel with
      [ [Sexpr _ sel1 :: sel2] ->
          List.fold_right
            (fun se ek ->
               let (p, e) = let_binding_se se in
               <:expr< let $p$ = $e$ in $ek$ >>)
            sel1 (progn_se loc sel2)
      | [se :: _] -> error se "let_binding"
      | _ -> error_loc loc "let_binding" ]
  | Sexpr loc [Satom _ Alid "match"; se :: sel] ->
      let e = expr_se se in
      let pel = List.map (match_case loc) sel in
      <:expr< match $e$ with [ $list:pel$ ] >>
  | Sexpr loc [Satom _ Alid "parser" :: sel] ->
      let e =
        match sel with
        [ [(Satom _ _ _ as se) :: sel] ->
            let p = patt_se se in
            let pc = parser_cases_se loc sel in
            <:expr< let $p$ = Stream.count $lid:strm_n$ in $pc$ >>
        | _ -> parser_cases_se loc sel ]
      in
      <:expr< fun ($lid:strm_n$ : Stream.t _) -> $e$ >>
  | Sexpr loc [Satom _ Alid "try"; se :: sel] ->
      let e = expr_se se in
      let pel = List.map (match_case loc) sel in
      <:expr< try $e$ with [ $list:pel$ ] >>
  | Sexpr loc [Satom _ Alid "progn" :: sel] ->
      let el = List.map expr_se sel in
      <:expr< do { $list:el$ } >>
  | Sexpr loc [Satom _ Alid "while"; se :: sel] ->
      let e = expr_se se in
      let el = List.map expr_se sel in
      <:expr< while $e$ do { $list:el$ } >>
  | Sexpr loc [Satom _ Alid ":="; se1; se2] ->
      let e2 = expr_se se2 in
      match expr_se se1 with
      [ <:expr< $uid:"()"$ $e1$ $i$ >> -> <:expr< $e1$.($i$) := $e2$ >>
      | e1 -> <:expr< $e1$ := $e2$ >> ]
  | Sexpr loc [Satom _ Alid "[]"; se1; se2] ->
      let e1 = expr_se se1 in
      let e2 = expr_se se2 in
      <:expr< $e1$.[$e2$] >>
  | Sexpr loc [Satom _ Alid "," :: sel] ->
      let el = List.map expr_se sel in
      <:expr< ( $list:el$ ) >>
  | Sexpr loc [Satom _ Alid "{}" :: sel] ->
      let lel = List.map (label_expr_se loc) sel in
      <:expr< { $list:lel$ } >>
  | Sexpr loc [Satom _ Alid ":"; se1; se2] ->
      let e = expr_se se1 in
      let t = ctyp_se se2 in
      <:expr< ( $e$ : $t$ ) >>
  | Sexpr loc [Satom _ Alid "list" :: sel] ->
      let rec loop =
        fun
        [ [] -> <:expr< [] >>
        | [se1; Satom _ Alid "::"; se2] ->
            let e = expr_se se1 in
            let el = expr_se se2 in
            <:expr< [$e$ :: $el$] >>
        | [se :: sel] ->
            let e = expr_se se in
            let el = loop sel in
            <:expr< [$e$ :: $el$] >> ]
      in
      loop sel
  | Sexpr loc [se :: sel] ->
      List.fold_left
        (fun e se ->
           let e1 = expr_se se in
           <:expr< $e$ $e1$ >>)
        (expr_se se) sel
  | Squot loc typ txt -> Pcaml.handle_expr_quotation loc (typ, txt) ]
and progn_se loc =
  fun
  [ [] -> <:expr< () >>
  | [se] -> expr_se se
  | sel ->
      let el = List.map expr_se sel in
      <:expr< do { $list:el$ } >> ]
and let_binding_se =
  fun
  [ Sexpr loc [se1; se2] -> (ipatt_se se1, expr_se se2)
  | se -> error se "let_binding" ]
and match_case loc =
  fun
  [ Sexpr _ [se1; se2] -> (patt_se se1, None, expr_se se2)
  | Sexpr _ [se1; sew; se2] -> (patt_se se1, Some (expr_se sew), expr_se se2)
  | se -> error se "match_case" ]
and label_expr_se loc =
  fun
  [ Sexpr _ [se1; se2] -> (patt_se se1, expr_se se2)
  | se -> error se "label_expr" ]
and expr_ident_se loc s =
  if s.[0] = '<' then <:expr< $lid:s$ >>
  else
    let rec loop ibeg i =
      if i = String.length s then
        if i > ibeg then expr_id loc (String.sub s ibeg (i - ibeg))
        else
          raise_with_loc (fst loc + i - 1, fst loc + i)
            (Stream.Error "expr expected")
      else if s.[i] = '.' then
        if i > ibeg then
          let e1 = expr_id loc (String.sub s ibeg (i - ibeg)) in
          let e2 = loop (i + 1) (i + 1) in
          <:expr< $e1$ . $e2$ >>
        else
          raise_with_loc (fst loc + i - 1, fst loc + i + 1)
            (Stream.Error "expr expected")
      else loop ibeg (i + 1)
    in
    loop 0 0
and parser_cases_se loc =
  fun
  [ [] -> <:expr< raise Stream.Failure >>
  | [Sexpr loc [Sexpr _ spsel :: act] :: sel] ->
      let ekont _ = parser_cases_se loc sel in
      let act =
        match act with
        [ [se] -> expr_se se
        | [sep; se] ->
            let p = patt_se sep in
            let e = expr_se se in
            <:expr< let $p$ = Stream.count $lid:strm_n$ in $e$ >>
        | _ -> error_loc loc "parser_case" ]
      in
      stream_pattern_se loc act ekont spsel
  | [se :: _] -> error se "parser_case" ]
and stream_pattern_se loc act ekont =
  fun
  [ [] -> act
  | [se :: sel] ->
      let ckont err = <:expr< raise (Stream.Error $err$) >> in
      let skont = stream_pattern_se loc act ckont sel in
      stream_pattern_component skont ekont <:expr< "" >> se ]
and stream_pattern_component skont ekont err =
  fun
  [ Sexpr loc [Satom _ Alid "`"; se :: wol] ->
      let wo =
        match wol with
        [ [se] -> Some (expr_se se)
        | [] -> None
        | _ -> error_loc loc "stream_pattern_component" ]
      in
      let e = peek_fun loc in
      let p = patt_se se in
      let j = junk_fun loc in
      let k = ekont err in
      <:expr< match $e$ $lid:strm_n$ with
       [ Some $p$ $when:wo$ -> do { $j$ $lid:strm_n$ ; $skont$ }
       | _ -> $k$ ] >>
  | Sexpr loc [se1; se2] ->
      let p = patt_se se1 in
      let e =
        let e = expr_se se2 in
        <:expr< try Some ($e$ $lid:strm_n$) with [ Stream.Failure -> None ] >>
      in
      let k = ekont err in
      <:expr< match $e$ with [ Some $p$ -> $skont$ | _ -> $k$ ] >>
  | Sexpr loc [Satom _ Alid "?"; se1; se2] ->
      stream_pattern_component skont ekont (expr_se se2) se1
  | Satom loc Alid s -> <:expr< let $lid:s$ = $lid:strm_n$ in $skont$ >>
  | se -> error se "stream_pattern_component" ]
and patt_se =
  fun
  [ Satom loc Alid "_" -> <:patt< _ >>
  | Satom loc (Alid | Auid) s -> patt_ident_se loc s
  | Satom loc Aint s -> <:patt< $int:s$ >>
  | Satom loc Achar s -> <:patt< $chr:s$ >>
  | Satom loc Astring s -> <:patt< $str:s$ >>
  | Sexpr loc [Satom _ Alid "or"; se :: sel] ->
      List.fold_left
        (fun p se ->
           let p1 = patt_se se in
           <:patt< $p$ | $p1$ >>)
        (patt_se se) sel
  | Sexpr loc [Satom _ Alid "range"; se1; se2] ->
      let p1 = patt_se se1 in
      let p2 = patt_se se2 in
      <:patt< $p1$ .. $p2$ >>
  | Sexpr loc [Satom _ Alid "," :: sel] ->
      let pl = List.map patt_se sel in
      <:patt< ( $list:pl$ ) >>
  | Sexpr loc [Satom _ Alid "as"; se1; se2] ->
      let p1 = patt_se se1 in
      let p2 = patt_se se2 in
      <:patt< ($p1$ as $p2$) >>
  | Sexpr loc [Satom _ Alid "list" :: sel] ->
      let rec loop =
        fun
        [ [] -> <:patt< [] >>
        | [se1; Satom _ Alid "::"; se2] ->
            let p = patt_se se1 in
            let pl = patt_se se2 in
            <:patt< [$p$ :: $pl$] >>
        | [se :: sel] ->
            let p = patt_se se in
            let pl = loop sel in
            <:patt< [$p$ :: $pl$] >> ]
      in
      loop sel
  | Sexpr loc [se :: sel] ->
      List.fold_left
        (fun p se ->
           let p1 = patt_se se in
           <:patt< $p$ $p1$ >>)
        (patt_se se) sel
  | Sexpr loc [] -> <:patt< () >>
  | Squot loc typ txt -> Pcaml.handle_patt_quotation loc (typ, txt) ]
and patt_ident_se loc s =
  loop 0 0 where rec loop ibeg i =
    if i = String.length s then
      if i > ibeg then patt_id loc (String.sub s ibeg (i - ibeg))
      else
        raise_with_loc (fst loc + i - 1, fst loc + i)
          (Stream.Error "patt expected")
    else if s.[i] = '.' then
      if i > ibeg then
        let p1 = patt_id loc (String.sub s ibeg (i - ibeg)) in
        let p2 = loop (i + 1) (i + 1) in
        <:patt< $p1$ . $p2$ >>
      else
        raise_with_loc (fst loc + i - 1, fst loc + i + 1)
          (Stream.Error "patt expected")
    else loop ibeg (i + 1)
and ipatt_se se =
  match ipatt_opt_se se with
  [ Left p -> p
  | Right (se, _) -> error se "ipatt" ]
and ipatt_opt_se =
  fun
  [ Satom loc Alid "_" -> Left <:patt< _ >>
  | Satom loc Alid s -> Left <:patt< $lid:s$ >>
  | Sexpr loc [Satom _ Alid "," :: sel] ->
      let pl = List.map ipatt_se sel in
      Left <:patt< ( $list:pl$ ) >>
  | Sexpr loc [] -> Left <:patt< () >>
  | Sexpr loc [se :: sel] -> Right (se, sel)
  | se -> error se "ipatt" ]
and type_declaration_list_se =
  fun
  [ [se1; se2 :: sel] ->
      let (n1, loc1, tpl) =
        match se1 with
        [ Sexpr _ [Satom loc Alid n :: sel] ->
            (n, loc, List.map type_parameter_se sel)
        | Satom loc Alid n -> (n, loc, [])
        | se -> error se "type declaration" ]
      in
      [((loc1, n1), tpl, ctyp_se se2, []) :: type_declaration_list_se sel]
  | [] -> []
  | [se :: _] -> error se "type_declaration" ]
and type_parameter_se =
  fun
  [ Satom _ Alid s when String.length s >= 2 && s.[0] = ''' ->
      (String.sub s 1 (String.length s - 1), (False, False))
  | se -> error se "type_parameter" ]
and ctyp_se =
  fun
  [ Sexpr loc [Satom _ Alid "sum" :: sel] ->
      let cdl = List.map constructor_declaration_se sel in
      <:ctyp< [ $list:cdl$ ] >>
  | Sexpr loc [se :: sel] ->
      List.fold_left
        (fun t se ->
           let t2 = ctyp_se se in
           <:ctyp< $t$ $t2$ >>)
        (ctyp_se se) sel
  | Satom loc (Alid | Auid) s -> ctyp_ident_se loc s
  | se -> error se "ctyp" ]
and ctyp_ident_se loc s =
  loop 0 0 where rec loop ibeg i =
    if i = String.length s then
      if i > ibeg then ctyp_id loc (String.sub s ibeg (i - ibeg))
      else
        raise_with_loc (fst loc + i - 1, fst loc + i)
          (Stream.Error "ctyp expected")
    else if s.[i] = '.' then
      if i > ibeg then
        let t1 = ctyp_id loc (String.sub s ibeg (i - ibeg)) in
        let t2 = loop (i + 1) (i + 1) in
        <:ctyp< $t1$ . $t2$ >>
      else
        raise_with_loc (fst loc + i - 1, fst loc + i + 1)
          (Stream.Error "ctyp expected")
    else loop ibeg (i + 1)
and constructor_declaration_se =
  fun
  [ Sexpr loc [Satom _ Auid ci :: sel] -> (loc, ci, List.map ctyp_se sel)
  | se -> error se "constructor_declaration" ]
;

value top_phrase_se se =
  match se with
  [ Satom loc _ _ | Squot loc _ _ -> str_item_se se
  | Sexpr loc [Satom _ Alid s :: sl] ->
      if s.[0] = '#' then
        let n = String.sub s 1 (String.length s - 1) in
        match sl with
        [ [Satom _ Astring s] -> MLast.StDir loc n (Some <:expr< $str:s$ >>)
        | _ -> match () with [] ]
      else str_item_se se
  | Sexpr loc _ -> str_item_se se ]
;

(* Parser *)

value phony_quot = ref False;
Pcaml.add_option "-phony_quot" (Arg.Set phony_quot) "phony quotations";

Pcaml.no_constructors_arity.val := False;

do {
  Grammar.Unsafe.gram_reinit gram (lexer_gmake ());
  Grammar.Unsafe.clear_entry interf;
  Grammar.Unsafe.clear_entry implem;
  Grammar.Unsafe.clear_entry top_phrase;
  Grammar.Unsafe.clear_entry use_file;
  Grammar.Unsafe.clear_entry module_type;
  Grammar.Unsafe.clear_entry module_expr;
  Grammar.Unsafe.clear_entry sig_item;
  Grammar.Unsafe.clear_entry str_item;
  Grammar.Unsafe.clear_entry expr;
  Grammar.Unsafe.clear_entry patt;
  Grammar.Unsafe.clear_entry ctyp;
  Grammar.Unsafe.clear_entry let_binding;
  Grammar.Unsafe.clear_entry class_type;
  Grammar.Unsafe.clear_entry class_expr;
  Grammar.Unsafe.clear_entry class_sig_item;
  Grammar.Unsafe.clear_entry class_str_item
};

Pcaml.parse_interf.val := Grammar.Entry.parse interf;
Pcaml.parse_implem.val := Grammar.Entry.parse implem;

value sexpr = Grammar.Entry.create gram "sexpr";
value atom = Grammar.Entry.create gram "atom";

EXTEND
  implem:
    [ [ st = LIST0 [ s = str_item -> (s, loc) ]; EOI -> (st, False) ] ]
  ;
  top_phrase:
    [ [ se = sexpr -> Some (top_phrase_se se)
      | EOI -> None ] ]
  ;
  use_file:
    [ [ l = LIST0 sexpr; EOI -> (List.map top_phrase_se l, False) ] ]
  ;
  str_item:
    [ [ se = sexpr -> str_item_se se
      | e = expr -> <:str_item< $exp:e$ >> ] ]
  ;
  expr:
    [ "top"
      [ se = sexpr -> expr_se se ] ]
  ;
  patt:
    [ [ se = sexpr -> patt_se se ] ]
  ;
  sexpr:
    [ [ "("; sl = LIST0 sexpr; ")" -> Sexpr loc sl
      | a = atom -> Satom loc Alid a
      | s = LIDENT -> Satom loc Alid s
      | s = UIDENT -> Satom loc Auid s
      | s = INT -> Satom loc Aint s
      | s = CHAR -> Satom loc Achar s
      | s = STRING -> Satom loc Astring s
      | s = QUOT ->
          let i = String.index s ':' in
          let typ = String.sub s 0 i in
          let txt = String.sub s (i + 1) (String.length s - i - 1) in
          if phony_quot.val then
            Satom loc Alid ("<:" ^ typ ^ "<" ^ txt ^ ">>")
          else Squot loc typ txt ] ]
  ;
  atom:
    [ [ "_" -> "_"
      | "," -> ","
      | "=" -> "="
      | ":" -> ":"
      | "." -> "." ] ]
  ;
END;
