/**************************************************************************/ /* */ /* OCaml */ /* */ /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ /* */ /* Copyright 1996 Institut National de Recherche en Informatique et */ /* en Automatique. */ /* */ /* All rights reserved. This file is distributed under the terms of */ /* the GNU Lesser General Public License version 2.1, with the */ /* special exception on linking described in the file LICENSE. */ /* */ /**************************************************************************/ /* The parser definition */ %{ open Location open Asttypes open Longident open Parsetree open Ast_helper open Docstrings let mktyp d = Typ.mk ~loc:(symbol_rloc()) d let mkpat d = Pat.mk ~loc:(symbol_rloc()) d let mkexp d = Exp.mk ~loc:(symbol_rloc()) d let mkmty ?attrs d = Mty.mk ~loc:(symbol_rloc()) ?attrs d let mksig d = Sig.mk ~loc:(symbol_rloc()) d let mkmod ?attrs d = Mod.mk ~loc:(symbol_rloc()) ?attrs d let mkstr d = Str.mk ~loc:(symbol_rloc()) d let mkclass ?attrs d = Cl.mk ~loc:(symbol_rloc()) ?attrs d let mkcty ?attrs d = Cty.mk ~loc:(symbol_rloc()) ?attrs d let mkctf ?attrs ?docs d = Ctf.mk ~loc:(symbol_rloc()) ?attrs ?docs d let mkcf ?attrs ?docs d = Cf.mk ~loc:(symbol_rloc()) ?attrs ?docs d let mkrhs rhs pos = mkloc rhs (rhs_loc pos) let reloc_pat x = { x with ppat_loc = symbol_rloc () };; let reloc_exp x = { x with pexp_loc = symbol_rloc () };; let mkoperator name pos = let loc = rhs_loc pos in Exp.mk ~loc (Pexp_ident(mkloc (Lident name) loc)) let mkpatvar name pos = Pat.mk ~loc:(rhs_loc pos) (Ppat_var (mkrhs name pos)) (* Ghost expressions and patterns: expressions and patterns that do not appear explicitly in the source file they have the loc_ghost flag set to true. Then the profiler will not try to instrument them and the -annot option will not try to display their type. Every grammar rule that generates an element with a location must make at most one non-ghost element, the topmost one. How to tell whether your location must be ghost: A location corresponds to a range of characters in the source file. If the location contains a piece of code that is syntactically valid (according to the documentation), and corresponds to the AST node, then the location must be real; in all other cases, it must be ghost. *) let ghexp d = Exp.mk ~loc:(symbol_gloc ()) d let ghpat d = Pat.mk ~loc:(symbol_gloc ()) d let ghtyp d = Typ.mk ~loc:(symbol_gloc ()) d let ghloc d = { txt = d; loc = symbol_gloc () } let ghstr d = Str.mk ~loc:(symbol_gloc()) d let ghsig d = Sig.mk ~loc:(symbol_gloc()) d let mkinfix arg1 name arg2 = mkexp(Pexp_apply(mkoperator name 2, [Nolabel, arg1; Nolabel, arg2])) let neg_string f = if String.length f > 0 && f.[0] = '-' then String.sub f 1 (String.length f - 1) else "-" ^ f let mkuminus name arg = match name, arg.pexp_desc with | "-", Pexp_constant(Pconst_integer (n,m)) -> mkexp(Pexp_constant(Pconst_integer(neg_string n,m))) | ("-" | "-."), Pexp_constant(Pconst_float (f, m)) -> mkexp(Pexp_constant(Pconst_float(neg_string f, m))) | _ -> mkexp(Pexp_apply(mkoperator ("~" ^ name) 1, [Nolabel, arg])) let mkuplus name arg = let desc = arg.pexp_desc in match name, desc with | "+", Pexp_constant(Pconst_integer _) | ("+" | "+."), Pexp_constant(Pconst_float _) -> mkexp desc | _ -> mkexp(Pexp_apply(mkoperator ("~" ^ name) 1, [Nolabel, arg])) let mkexp_cons consloc args loc = Exp.mk ~loc (Pexp_construct(mkloc (Lident "::") consloc, Some args)) let mkpat_cons consloc args loc = Pat.mk ~loc (Ppat_construct(mkloc (Lident "::") consloc, Some args)) let rec mktailexp nilloc = function [] -> let loc = { nilloc with loc_ghost = true } in let nil = { txt = Lident "[]"; loc = loc } in Exp.mk ~loc (Pexp_construct (nil, None)) | e1 :: el -> let exp_el = mktailexp nilloc el in let loc = {loc_start = e1.pexp_loc.loc_start; loc_end = exp_el.pexp_loc.loc_end; loc_ghost = true} in let arg = Exp.mk ~loc (Pexp_tuple [e1; exp_el]) in mkexp_cons {loc with loc_ghost = true} arg loc let rec mktailpat nilloc = function [] -> let loc = { nilloc with loc_ghost = true } in let nil = { txt = Lident "[]"; loc = loc } in Pat.mk ~loc (Ppat_construct (nil, None)) | p1 :: pl -> let pat_pl = mktailpat nilloc pl in let loc = {loc_start = p1.ppat_loc.loc_start; loc_end = pat_pl.ppat_loc.loc_end; loc_ghost = true} in let arg = Pat.mk ~loc (Ppat_tuple [p1; pat_pl]) in mkpat_cons {loc with loc_ghost = true} arg loc let mkstrexp e attrs = { pstr_desc = Pstr_eval (e, attrs); pstr_loc = e.pexp_loc } let mkexp_constraint e (t1, t2) = match t1, t2 with | Some t, None -> ghexp(Pexp_constraint(e, t)) | _, Some t -> ghexp(Pexp_coerce(e, t1, t)) | None, None -> assert false let mkexp_opt_constraint e = function | None -> e | Some constraint_ -> mkexp_constraint e constraint_ let mkpat_opt_constraint p = function | None -> p | Some typ -> mkpat (Ppat_constraint(p, typ)) let array_function str name = ghloc (Ldot(Lident str, (if !Clflags.fast then "unsafe_" ^ name else name))) let syntax_error () = raise Syntaxerr.Escape_error let unclosed opening_name opening_num closing_name closing_num = raise(Syntaxerr.Error(Syntaxerr.Unclosed(rhs_loc opening_num, opening_name, rhs_loc closing_num, closing_name))) let expecting pos nonterm = raise Syntaxerr.(Error(Expecting(rhs_loc pos, nonterm))) let not_expecting pos nonterm = raise Syntaxerr.(Error(Not_expecting(rhs_loc pos, nonterm))) let bigarray_function str name = ghloc (Ldot(Ldot(Lident "Bigarray", str), name)) let bigarray_untuplify = function { pexp_desc = Pexp_tuple explist; pexp_loc = _ } -> explist | exp -> [exp] let bigarray_get arr arg = let get = if !Clflags.fast then "unsafe_get" else "get" in match bigarray_untuplify arg with [c1] -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Array1" get)), [Nolabel, arr; Nolabel, c1])) | [c1;c2] -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Array2" get)), [Nolabel, arr; Nolabel, c1; Nolabel, c2])) | [c1;c2;c3] -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Array3" get)), [Nolabel, arr; Nolabel, c1; Nolabel, c2; Nolabel, c3])) | coords -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Genarray" "get")), [Nolabel, arr; Nolabel, ghexp(Pexp_array coords)])) let bigarray_set arr arg newval = let set = if !Clflags.fast then "unsafe_set" else "set" in match bigarray_untuplify arg with [c1] -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Array1" set)), [Nolabel, arr; Nolabel, c1; Nolabel, newval])) | [c1;c2] -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Array2" set)), [Nolabel, arr; Nolabel, c1; Nolabel, c2; Nolabel, newval])) | [c1;c2;c3] -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Array3" set)), [Nolabel, arr; Nolabel, c1; Nolabel, c2; Nolabel, c3; Nolabel, newval])) | coords -> mkexp(Pexp_apply(ghexp(Pexp_ident(bigarray_function "Genarray" "set")), [Nolabel, arr; Nolabel, ghexp(Pexp_array coords); Nolabel, newval])) let lapply p1 p2 = if !Clflags.applicative_functors then Lapply(p1, p2) else raise (Syntaxerr.Error(Syntaxerr.Applicative_path (symbol_rloc()))) let exp_of_label lbl pos = mkexp (Pexp_ident(mkrhs (Lident(Longident.last lbl)) pos)) let pat_of_label lbl pos = mkpat (Ppat_var (mkrhs (Longident.last lbl) pos)) let mk_newtypes newtypes exp = List.fold_right (fun newtype exp -> mkexp (Pexp_newtype (newtype, exp))) newtypes exp let wrap_type_annotation newtypes core_type body = let exp = mkexp(Pexp_constraint(body,core_type)) in let exp = mk_newtypes newtypes exp in (exp, ghtyp(Ptyp_poly(newtypes, Typ.varify_constructors newtypes core_type))) let wrap_exp_attrs body (ext, attrs) = (* todo: keep exact location for the entire attribute *) let body = {body with pexp_attributes = attrs @ body.pexp_attributes} in match ext with | None -> body | Some id -> ghexp(Pexp_extension (id, PStr [mkstrexp body []])) let mkexp_attrs d attrs = wrap_exp_attrs (mkexp d) attrs let wrap_typ_attrs typ (ext, attrs) = (* todo: keep exact location for the entire attribute *) let typ = {typ with ptyp_attributes = attrs @ typ.ptyp_attributes} in match ext with | None -> typ | Some id -> ghtyp(Ptyp_extension (id, PTyp typ)) let mktyp_attrs d attrs = wrap_typ_attrs (mktyp d) attrs let wrap_pat_attrs pat (ext, attrs) = (* todo: keep exact location for the entire attribute *) let pat = {pat with ppat_attributes = attrs @ pat.ppat_attributes} in match ext with | None -> pat | Some id -> ghpat(Ppat_extension (id, PPat (pat, None))) let mkpat_attrs d attrs = wrap_pat_attrs (mkpat d) attrs let wrap_class_attrs body attrs = {body with pcl_attributes = attrs @ body.pcl_attributes} let wrap_class_type_attrs body attrs = {body with pcty_attributes = attrs @ body.pcty_attributes} let wrap_mod_attrs body attrs = {body with pmod_attributes = attrs @ body.pmod_attributes} let wrap_mty_attrs body attrs = {body with pmty_attributes = attrs @ body.pmty_attributes} let wrap_str_ext body ext = match ext with | None -> body | Some id -> ghstr(Pstr_extension ((id, PStr [body]), [])) let mkstr_ext d ext = wrap_str_ext (mkstr d) ext let wrap_sig_ext body ext = match ext with | None -> body | Some id -> ghsig(Psig_extension ((id, PSig [body]), [])) let mksig_ext d ext = wrap_sig_ext (mksig d) ext let text_str pos = Str.text (rhs_text pos) let text_sig pos = Sig.text (rhs_text pos) let text_cstr pos = Cf.text (rhs_text pos) let text_csig pos = Ctf.text (rhs_text pos) let text_def pos = [Ptop_def (Str.text (rhs_text pos))] let extra_text text pos items = let pre_extras = rhs_pre_extra_text pos in let post_extras = rhs_post_extra_text pos in text pre_extras @ items @ text post_extras let extra_str pos items = extra_text Str.text pos items let extra_sig pos items = extra_text Sig.text pos items let extra_cstr pos items = extra_text Cf.text pos items let extra_csig pos items = extra_text Ctf.text pos items let extra_def pos items = extra_text (fun txt -> [Ptop_def (Str.text txt)]) pos items let extra_rhs_core_type ct ~pos = let docs = rhs_info pos in { ct with ptyp_attributes = add_info_attrs docs ct.ptyp_attributes } type let_binding = { lb_pattern: pattern; lb_expression: expression; lb_attributes: attributes; lb_docs: docs Lazy.t; lb_text: text Lazy.t; lb_loc: Location.t; } type let_bindings = { lbs_bindings: let_binding list; lbs_rec: rec_flag; lbs_extension: string Asttypes.loc option; lbs_loc: Location.t } let mklb first (p, e) attrs = { lb_pattern = p; lb_expression = e; lb_attributes = attrs; lb_docs = symbol_docs_lazy (); lb_text = if first then empty_text_lazy else symbol_text_lazy (); lb_loc = symbol_rloc (); } let mklbs ext rf lb = { lbs_bindings = [lb]; lbs_rec = rf; lbs_extension = ext ; lbs_loc = symbol_rloc (); } let addlb lbs lb = { lbs with lbs_bindings = lb :: lbs.lbs_bindings } let val_of_let_bindings lbs = let bindings = List.map (fun lb -> Vb.mk ~loc:lb.lb_loc ~attrs:lb.lb_attributes ~docs:(Lazy.force lb.lb_docs) ~text:(Lazy.force lb.lb_text) lb.lb_pattern lb.lb_expression) lbs.lbs_bindings in let str = mkstr(Pstr_value(lbs.lbs_rec, List.rev bindings)) in match lbs.lbs_extension with | None -> str | Some id -> ghstr (Pstr_extension((id, PStr [str]), [])) let expr_of_let_bindings lbs body = let bindings = List.map (fun lb -> Vb.mk ~loc:lb.lb_loc ~attrs:lb.lb_attributes lb.lb_pattern lb.lb_expression) lbs.lbs_bindings in mkexp_attrs (Pexp_let(lbs.lbs_rec, List.rev bindings, body)) (lbs.lbs_extension, []) let class_of_let_bindings lbs body = let bindings = List.map (fun lb -> Vb.mk ~loc:lb.lb_loc ~attrs:lb.lb_attributes lb.lb_pattern lb.lb_expression) lbs.lbs_bindings in if lbs.lbs_extension <> None then raise Syntaxerr.(Error(Not_expecting(lbs.lbs_loc, "extension"))); mkclass(Pcl_let (lbs.lbs_rec, List.rev bindings, body)) (* Alternatively, we could keep the generic module type in the Parsetree and extract the package type during type-checking. In that case, the assertions below should be turned into explicit checks. *) let package_type_of_module_type pmty = let err loc s = raise (Syntaxerr.Error (Syntaxerr.Invalid_package_type (loc, s))) in let map_cstr = function | Pwith_type (lid, ptyp) -> let loc = ptyp.ptype_loc in if ptyp.ptype_params <> [] then err loc "parametrized types are not supported"; if ptyp.ptype_cstrs <> [] then err loc "constrained types are not supported"; if ptyp.ptype_private <> Public then err loc "private types are not supported"; (* restrictions below are checked by the 'with_constraint' rule *) assert (ptyp.ptype_kind = Ptype_abstract); assert (ptyp.ptype_attributes = []); let ty = match ptyp.ptype_manifest with | Some ty -> ty | None -> assert false in (lid, ty) | _ -> err pmty.pmty_loc "only 'with type t =' constraints are supported" in match pmty with | {pmty_desc = Pmty_ident lid} -> (lid, []) | {pmty_desc = Pmty_with({pmty_desc = Pmty_ident lid}, cstrs)} -> (lid, List.map map_cstr cstrs) | _ -> err pmty.pmty_loc "only module type identifier and 'with type' constraints are supported" %} /* Tokens */ %token AMPERAMPER %token AMPERSAND %token AND %token AS %token ASSERT %token BACKQUOTE %token BANG %token BAR %token BARBAR %token BARRBRACKET %token BEGIN %token CHAR %token CLASS %token COLON %token COLONCOLON %token COLONEQUAL %token COLONGREATER %token COMMA %token CONSTRAINT %token DO %token DONE %token DOT %token DOTDOT %token DOWNTO %token ELSE %token END %token EOF %token EQUAL %token EXCEPTION %token EXTERNAL %token FALSE %token FLOAT %token FOR %token FUN %token FUNCTION %token FUNCTOR %token GREATER %token GREATERRBRACE %token GREATERRBRACKET %token IF %token IN %token INCLUDE %token INFIXOP0 %token INFIXOP1 %token INFIXOP2 %token INFIXOP3 %token INFIXOP4 %token DOTOP %token INHERIT %token INITIALIZER %token INT %token LABEL %token LAZY %token LBRACE %token LBRACELESS %token LBRACKET %token LBRACKETBAR %token LBRACKETLESS %token LBRACKETGREATER %token LBRACKETPERCENT %token LBRACKETPERCENTPERCENT %token LESS %token LESSMINUS %token LET %token LIDENT %token LPAREN %token LBRACKETAT %token LBRACKETATAT %token LBRACKETATATAT %token MATCH %token METHOD %token MINUS %token MINUSDOT %token MINUSGREATER %token MODULE %token MUTABLE %token NEW %token NONREC %token OBJECT %token OF %token OPEN %token OPTLABEL %token OR /* %token PARSER */ %token PERCENT %token PLUS %token PLUSDOT %token PLUSEQ %token PREFIXOP %token PRIVATE %token QUESTION %token QUOTE %token RBRACE %token RBRACKET %token REC %token RPAREN %token SEMI %token SEMISEMI %token HASH %token HASHOP %token SIG %token STAR %token STRING %token STRUCT %token THEN %token TILDE %token TO %token TRUE %token TRY %token TYPE %token UIDENT %token UNDERSCORE %token VAL %token VIRTUAL %token WHEN %token WHILE %token WITH %token COMMENT %token DOCSTRING %token EOL /* Precedences and associativities. Tokens and rules have precedences. A reduce/reduce conflict is resolved in favor of the first rule (in source file order). A shift/reduce conflict is resolved by comparing the precedence and associativity of the token to be shifted with those of the rule to be reduced. By default, a rule has the precedence of its rightmost terminal (if any). When there is a shift/reduce conflict between a rule and a token that have the same precedence, it is resolved using the associativity: if the token is left-associative, the parser will reduce; if right-associative, the parser will shift; if non-associative, the parser will declare a syntax error. We will only use associativities with operators of the kind x * x -> x for example, in the rules of the form expr: expr BINOP expr in all other cases, we define two precedences if needed to resolve conflicts. The precedences must be listed from low to high. */ %nonassoc IN %nonassoc below_SEMI %nonassoc SEMI /* below EQUAL ({lbl=...; lbl=...}) */ %nonassoc LET /* above SEMI ( ...; let ... in ...) */ %nonassoc below_WITH %nonassoc FUNCTION WITH /* below BAR (match ... with ...) */ %nonassoc AND /* above WITH (module rec A: SIG with ... and ...) */ %nonassoc THEN /* below ELSE (if ... then ...) */ %nonassoc ELSE /* (if ... then ... else ...) */ %nonassoc LESSMINUS /* below COLONEQUAL (lbl <- x := e) */ %right COLONEQUAL /* expr (e := e := e) */ %nonassoc AS %left BAR /* pattern (p|p|p) */ %nonassoc below_COMMA %left COMMA /* expr/expr_comma_list (e,e,e) */ %right MINUSGREATER /* core_type2 (t -> t -> t) */ %right OR BARBAR /* expr (e || e || e) */ %right AMPERSAND AMPERAMPER /* expr (e && e && e) */ %nonassoc below_EQUAL %left INFIXOP0 EQUAL LESS GREATER /* expr (e OP e OP e) */ %right INFIXOP1 /* expr (e OP e OP e) */ %nonassoc below_LBRACKETAT %nonassoc LBRACKETAT %nonassoc LBRACKETATAT %right COLONCOLON /* expr (e :: e :: e) */ %left INFIXOP2 PLUS PLUSDOT MINUS MINUSDOT PLUSEQ /* expr (e OP e OP e) */ %left PERCENT INFIXOP3 STAR /* expr (e OP e OP e) */ %right INFIXOP4 /* expr (e OP e OP e) */ %nonassoc prec_unary_minus prec_unary_plus /* unary - */ %nonassoc prec_constant_constructor /* cf. simple_expr (C versus C x) */ %nonassoc prec_constr_appl /* above AS BAR COLONCOLON COMMA */ %nonassoc below_HASH %nonassoc HASH /* simple_expr/toplevel_directive */ %left HASHOP %nonassoc below_DOT %nonassoc DOT DOTOP /* Finally, the first tokens of simple_expr are above everything else. */ %nonassoc BACKQUOTE BANG BEGIN CHAR FALSE FLOAT INT LBRACE LBRACELESS LBRACKET LBRACKETBAR LIDENT LPAREN NEW PREFIXOP STRING TRUE UIDENT LBRACKETPERCENT LBRACKETPERCENTPERCENT /* Entry points */ %start implementation /* for implementation files */ %type implementation %start interface /* for interface files */ %type interface %start toplevel_phrase /* for interactive use */ %type toplevel_phrase %start use_file /* for the #use directive */ %type use_file %start parse_core_type %type parse_core_type %start parse_expression %type parse_expression %start parse_pattern %type parse_pattern %% /* Entry points */ implementation: structure EOF { extra_str 1 $1 } ; interface: signature EOF { extra_sig 1 $1 } ; toplevel_phrase: top_structure SEMISEMI { Ptop_def (extra_str 1 $1) } | toplevel_directive SEMISEMI { $1 } | EOF { raise End_of_file } ; top_structure: seq_expr post_item_attributes { (text_str 1) @ [mkstrexp $1 $2] } | top_structure_tail { $1 } ; top_structure_tail: /* empty */ { [] } | structure_item top_structure_tail { (text_str 1) @ $1 :: $2 } ; use_file: use_file_body { extra_def 1 $1 } ; use_file_body: use_file_tail { $1 } | seq_expr post_item_attributes use_file_tail { (text_def 1) @ Ptop_def[mkstrexp $1 $2] :: $3 } ; use_file_tail: EOF { [] } | SEMISEMI EOF { text_def 1 } | SEMISEMI seq_expr post_item_attributes use_file_tail { mark_rhs_docs 2 3; (text_def 1) @ (text_def 2) @ Ptop_def[mkstrexp $2 $3] :: $4 } | SEMISEMI structure_item use_file_tail { (text_def 1) @ (text_def 2) @ Ptop_def[$2] :: $3 } | SEMISEMI toplevel_directive use_file_tail { mark_rhs_docs 2 3; (text_def 1) @ (text_def 2) @ $2 :: $3 } | structure_item use_file_tail { (text_def 1) @ Ptop_def[$1] :: $2 } | toplevel_directive use_file_tail { mark_rhs_docs 1 1; (text_def 1) @ $1 :: $2 } ; parse_core_type: core_type EOF { $1 } ; parse_expression: seq_expr EOF { $1 } ; parse_pattern: pattern EOF { $1 } ; /* Module expressions */ functor_arg: LPAREN RPAREN { mkrhs "*" 2, None } | LPAREN functor_arg_name COLON module_type RPAREN { mkrhs $2 2, Some $4 } ; functor_arg_name: UIDENT { $1 } | UNDERSCORE { "_" } ; functor_args: functor_args functor_arg { $2 :: $1 } | functor_arg { [ $1 ] } ; module_expr: mod_longident { mkmod(Pmod_ident (mkrhs $1 1)) } | STRUCT attributes structure END { mkmod ~attrs:$2 (Pmod_structure(extra_str 3 $3)) } | STRUCT attributes structure error { unclosed "struct" 1 "end" 4 } | FUNCTOR attributes functor_args MINUSGREATER module_expr { let modexp = List.fold_left (fun acc (n, t) -> mkmod(Pmod_functor(n, t, acc))) $5 $3 in wrap_mod_attrs modexp $2 } | module_expr paren_module_expr { mkmod(Pmod_apply($1, $2)) } | module_expr LPAREN RPAREN { mkmod(Pmod_apply($1, mkmod (Pmod_structure []))) } | paren_module_expr { $1 } | module_expr attribute { Mod.attr $1 $2 } | extension { mkmod(Pmod_extension $1) } ; paren_module_expr: LPAREN module_expr COLON module_type RPAREN { mkmod(Pmod_constraint($2, $4)) } | LPAREN module_expr COLON module_type error { unclosed "(" 1 ")" 5 } | LPAREN module_expr RPAREN { $2 } | LPAREN module_expr error { unclosed "(" 1 ")" 3 } | LPAREN VAL attributes expr RPAREN { mkmod ~attrs:$3 (Pmod_unpack $4)} | LPAREN VAL attributes expr COLON package_type RPAREN { mkmod ~attrs:$3 (Pmod_unpack( ghexp(Pexp_constraint($4, ghtyp(Ptyp_package $6))))) } | LPAREN VAL attributes expr COLON package_type COLONGREATER package_type RPAREN { mkmod ~attrs:$3 (Pmod_unpack( ghexp(Pexp_coerce($4, Some(ghtyp(Ptyp_package $6)), ghtyp(Ptyp_package $8))))) } | LPAREN VAL attributes expr COLONGREATER package_type RPAREN { mkmod ~attrs:$3 (Pmod_unpack( ghexp(Pexp_coerce($4, None, ghtyp(Ptyp_package $6))))) } | LPAREN VAL attributes expr COLON error { unclosed "(" 1 ")" 6 } | LPAREN VAL attributes expr COLONGREATER error { unclosed "(" 1 ")" 6 } | LPAREN VAL attributes expr error { unclosed "(" 1 ")" 5 } ; structure: seq_expr post_item_attributes structure_tail { mark_rhs_docs 1 2; (text_str 1) @ mkstrexp $1 $2 :: $3 } | structure_tail { $1 } ; structure_tail: /* empty */ { [] } | SEMISEMI structure { (text_str 1) @ $2 } | structure_item structure_tail { (text_str 1) @ $1 :: $2 } ; structure_item: let_bindings { val_of_let_bindings $1 } | primitive_declaration { let (body, ext) = $1 in mkstr_ext (Pstr_primitive body) ext } | value_description { let (body, ext) = $1 in mkstr_ext (Pstr_primitive body) ext } | type_declarations { let (nr, l, ext ) = $1 in mkstr_ext (Pstr_type (nr, List.rev l)) ext } | str_type_extension { let (l, ext) = $1 in mkstr_ext (Pstr_typext l) ext } | str_exception_declaration { let (l, ext) = $1 in mkstr_ext (Pstr_exception l) ext } | module_binding { let (body, ext) = $1 in mkstr_ext (Pstr_module body) ext } | rec_module_bindings { let (l, ext) = $1 in mkstr_ext (Pstr_recmodule(List.rev l)) ext } | module_type_declaration { let (body, ext) = $1 in mkstr_ext (Pstr_modtype body) ext } | open_statement { let (body, ext) = $1 in mkstr_ext (Pstr_open body) ext } | class_declarations { let (l, ext) = $1 in mkstr_ext (Pstr_class (List.rev l)) ext } | class_type_declarations { let (l, ext) = $1 in mkstr_ext (Pstr_class_type (List.rev l)) ext } | str_include_statement { let (body, ext) = $1 in mkstr_ext (Pstr_include body) ext } | item_extension post_item_attributes { mkstr(Pstr_extension ($1, (add_docs_attrs (symbol_docs ()) $2))) } | floating_attribute { mark_symbol_docs (); mkstr(Pstr_attribute $1) } ; str_include_statement: INCLUDE ext_attributes module_expr post_item_attributes { let (ext, attrs) = $2 in Incl.mk $3 ~attrs:(attrs@$4) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; module_binding_body: EQUAL module_expr { $2 } | COLON module_type EQUAL module_expr { mkmod(Pmod_constraint($4, $2)) } | functor_arg module_binding_body { mkmod(Pmod_functor(fst $1, snd $1, $2)) } ; module_binding: MODULE ext_attributes UIDENT module_binding_body post_item_attributes { let (ext, attrs) = $2 in Mb.mk (mkrhs $3 3) $4 ~attrs:(attrs@$5) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) , ext } ; rec_module_bindings: rec_module_binding { let (b, ext) = $1 in ([b], ext) } | rec_module_bindings and_module_binding { let (l, ext) = $1 in ($2 :: l, ext) } ; rec_module_binding: MODULE ext_attributes REC UIDENT module_binding_body post_item_attributes { let (ext, attrs) = $2 in Mb.mk (mkrhs $4 4) $5 ~attrs:(attrs@$6) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) , ext } ; and_module_binding: AND attributes UIDENT module_binding_body post_item_attributes { Mb.mk (mkrhs $3 3) $4 ~attrs:($2@$5) ~loc:(symbol_rloc ()) ~text:(symbol_text ()) ~docs:(symbol_docs ()) } ; /* Module types */ module_type: mty_longident { mkmty(Pmty_ident (mkrhs $1 1)) } | SIG attributes signature END { mkmty ~attrs:$2 (Pmty_signature (extra_sig 3 $3)) } | SIG attributes signature error { unclosed "sig" 1 "end" 4 } | FUNCTOR attributes functor_args MINUSGREATER module_type %prec below_WITH { let mty = List.fold_left (fun acc (n, t) -> mkmty(Pmty_functor(n, t, acc))) $5 $3 in wrap_mty_attrs mty $2 } | module_type MINUSGREATER module_type %prec below_WITH { mkmty(Pmty_functor(mknoloc "_", Some $1, $3)) } | module_type WITH with_constraints { mkmty(Pmty_with($1, List.rev $3)) } | MODULE TYPE OF attributes module_expr %prec below_LBRACKETAT { mkmty ~attrs:$4 (Pmty_typeof $5) } /* | LPAREN MODULE mod_longident RPAREN { mkmty (Pmty_alias (mkrhs $3 3)) } */ | LPAREN module_type RPAREN { $2 } | LPAREN module_type error { unclosed "(" 1 ")" 3 } | extension { mkmty(Pmty_extension $1) } | module_type attribute { Mty.attr $1 $2 } ; signature: /* empty */ { [] } | SEMISEMI signature { (text_sig 1) @ $2 } | signature_item signature { (text_sig 1) @ $1 :: $2 } ; signature_item: value_description { let (body, ext) = $1 in mksig_ext (Psig_value body) ext } | primitive_declaration { let (body, ext) = $1 in mksig_ext (Psig_value body) ext} | type_declarations { let (nr, l, ext) = $1 in mksig_ext (Psig_type (nr, List.rev l)) ext } | sig_type_extension { let (l, ext) = $1 in mksig_ext (Psig_typext l) ext } | sig_exception_declaration { let (l, ext) = $1 in mksig_ext (Psig_exception l) ext } | module_declaration { let (body, ext) = $1 in mksig_ext (Psig_module body) ext } | module_alias { let (body, ext) = $1 in mksig_ext (Psig_module body) ext } | rec_module_declarations { let (l, ext) = $1 in mksig_ext (Psig_recmodule (List.rev l)) ext } | module_type_declaration { let (body, ext) = $1 in mksig_ext (Psig_modtype body) ext } | open_statement { let (body, ext) = $1 in mksig_ext (Psig_open body) ext } | sig_include_statement { let (body, ext) = $1 in mksig_ext (Psig_include body) ext } | class_descriptions { let (l, ext) = $1 in mksig_ext (Psig_class (List.rev l)) ext } | class_type_declarations { let (l, ext) = $1 in mksig_ext (Psig_class_type (List.rev l)) ext } | item_extension post_item_attributes { mksig(Psig_extension ($1, (add_docs_attrs (symbol_docs ()) $2))) } | floating_attribute { mark_symbol_docs (); mksig(Psig_attribute $1) } ; open_statement: | OPEN override_flag ext_attributes mod_longident post_item_attributes { let (ext, attrs) = $3 in Opn.mk (mkrhs $4 4) ~override:$2 ~attrs:(attrs@$5) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext} ; sig_include_statement: INCLUDE ext_attributes module_type post_item_attributes %prec below_WITH { let (ext, attrs) = $2 in Incl.mk $3 ~attrs:(attrs@$4) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext} ; module_declaration_body: COLON module_type { $2 } | LPAREN UIDENT COLON module_type RPAREN module_declaration_body { mkmty(Pmty_functor(mkrhs $2 2, Some $4, $6)) } | LPAREN RPAREN module_declaration_body { mkmty(Pmty_functor(mkrhs "*" 1, None, $3)) } ; module_declaration: MODULE ext_attributes UIDENT module_declaration_body post_item_attributes { let (ext, attrs) = $2 in Md.mk (mkrhs $3 3) $4 ~attrs:(attrs@$5) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; module_alias: MODULE ext_attributes UIDENT EQUAL mod_longident post_item_attributes { let (ext, attrs) = $2 in Md.mk (mkrhs $3 3) (Mty.alias ~loc:(rhs_loc 5) (mkrhs $5 5)) ~attrs:(attrs@$6) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; rec_module_declarations: rec_module_declaration { let (body, ext) = $1 in ([body], ext) } | rec_module_declarations and_module_declaration { let (l, ext) = $1 in ($2 :: l, ext) } ; rec_module_declaration: MODULE ext_attributes REC UIDENT COLON module_type post_item_attributes { let (ext, attrs) = $2 in Md.mk (mkrhs $4 4) $6 ~attrs:(attrs@$7) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext} ; and_module_declaration: AND attributes UIDENT COLON module_type post_item_attributes { Md.mk (mkrhs $3 3) $5 ~attrs:($2@$6) ~loc:(symbol_rloc()) ~text:(symbol_text()) ~docs:(symbol_docs()) } ; module_type_declaration_body: /* empty */ { None } | EQUAL module_type { Some $2 } ; module_type_declaration: MODULE TYPE ext_attributes ident module_type_declaration_body post_item_attributes { let (ext, attrs) = $3 in Mtd.mk (mkrhs $4 4) ?typ:$5 ~attrs:(attrs@$6) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; /* Class expressions */ class_declarations: class_declaration { let (body, ext) = $1 in ([body], ext) } | class_declarations and_class_declaration { let (l, ext) = $1 in ($2 :: l, ext) } ; class_declaration: CLASS ext_attributes virtual_flag class_type_parameters LIDENT class_fun_binding post_item_attributes { let (ext, attrs) = $2 in Ci.mk (mkrhs $5 5) $6 ~virt:$3 ~params:$4 ~attrs:(attrs@$7) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) , ext } ; and_class_declaration: AND attributes virtual_flag class_type_parameters LIDENT class_fun_binding post_item_attributes { Ci.mk (mkrhs $5 5) $6 ~virt:$3 ~params:$4 ~attrs:($2@$7) ~loc:(symbol_rloc ()) ~text:(symbol_text ()) ~docs:(symbol_docs ()) } ; class_fun_binding: EQUAL class_expr { $2 } | COLON class_type EQUAL class_expr { mkclass(Pcl_constraint($4, $2)) } | labeled_simple_pattern class_fun_binding { let (l,o,p) = $1 in mkclass(Pcl_fun(l, o, p, $2)) } ; class_type_parameters: /*empty*/ { [] } | LBRACKET type_parameter_list RBRACKET { List.rev $2 } ; class_fun_def: labeled_simple_pattern MINUSGREATER class_expr { let (l,o,p) = $1 in mkclass(Pcl_fun(l, o, p, $3)) } | labeled_simple_pattern class_fun_def { let (l,o,p) = $1 in mkclass(Pcl_fun(l, o, p, $2)) } ; class_expr: class_simple_expr { $1 } | FUN attributes class_fun_def { wrap_class_attrs $3 $2 } | class_simple_expr simple_labeled_expr_list { mkclass(Pcl_apply($1, List.rev $2)) } | let_bindings IN class_expr { class_of_let_bindings $1 $3 } | LET OPEN override_flag attributes mod_longident IN class_expr { wrap_class_attrs (mkclass(Pcl_open($3, mkrhs $5 5, $7))) $4 } | class_expr attribute { Cl.attr $1 $2 } | extension { mkclass(Pcl_extension $1) } ; class_simple_expr: LBRACKET core_type_comma_list RBRACKET class_longident { mkclass(Pcl_constr(mkloc $4 (rhs_loc 4), List.rev $2)) } | class_longident { mkclass(Pcl_constr(mkrhs $1 1, [])) } | OBJECT attributes class_structure END { mkclass ~attrs:$2 (Pcl_structure $3) } | OBJECT attributes class_structure error { unclosed "object" 1 "end" 4 } | LPAREN class_expr COLON class_type RPAREN { mkclass(Pcl_constraint($2, $4)) } | LPAREN class_expr COLON class_type error { unclosed "(" 1 ")" 5 } | LPAREN class_expr RPAREN { $2 } | LPAREN class_expr error { unclosed "(" 1 ")" 3 } ; class_structure: | class_self_pattern class_fields { Cstr.mk $1 (extra_cstr 2 (List.rev $2)) } ; class_self_pattern: LPAREN pattern RPAREN { reloc_pat $2 } | LPAREN pattern COLON core_type RPAREN { mkpat(Ppat_constraint($2, $4)) } | /* empty */ { ghpat(Ppat_any) } ; class_fields: /* empty */ { [] } | class_fields class_field { $2 :: (text_cstr 2) @ $1 } ; class_field: | INHERIT override_flag attributes class_expr parent_binder post_item_attributes { mkcf (Pcf_inherit ($2, $4, $5)) ~attrs:($3@$6) ~docs:(symbol_docs ()) } | VAL value post_item_attributes { let v, attrs = $2 in mkcf (Pcf_val v) ~attrs:(attrs@$3) ~docs:(symbol_docs ()) } | METHOD method_ post_item_attributes { let meth, attrs = $2 in mkcf (Pcf_method meth) ~attrs:(attrs@$3) ~docs:(symbol_docs ()) } | CONSTRAINT attributes constrain_field post_item_attributes { mkcf (Pcf_constraint $3) ~attrs:($2@$4) ~docs:(symbol_docs ()) } | INITIALIZER attributes seq_expr post_item_attributes { mkcf (Pcf_initializer $3) ~attrs:($2@$4) ~docs:(symbol_docs ()) } | item_extension post_item_attributes { mkcf (Pcf_extension $1) ~attrs:$2 ~docs:(symbol_docs ()) } | floating_attribute { mark_symbol_docs (); mkcf (Pcf_attribute $1) } ; parent_binder: AS LIDENT { Some (mkrhs $2 2) } | /* empty */ { None } ; value: /* TODO: factorize these rules (also with method): */ override_flag attributes MUTABLE VIRTUAL label COLON core_type { if $1 = Override then syntax_error (); (mkloc $5 (rhs_loc 5), Mutable, Cfk_virtual $7), $2 } | override_flag attributes VIRTUAL mutable_flag label COLON core_type { if $1 = Override then syntax_error (); (mkrhs $5 5, $4, Cfk_virtual $7), $2 } | override_flag attributes mutable_flag label EQUAL seq_expr { (mkrhs $4 4, $3, Cfk_concrete ($1, $6)), $2 } | override_flag attributes mutable_flag label type_constraint EQUAL seq_expr { let e = mkexp_constraint $7 $5 in (mkrhs $4 4, $3, Cfk_concrete ($1, e)), $2 } ; method_: /* TODO: factorize those rules... */ override_flag attributes PRIVATE VIRTUAL label COLON poly_type { if $1 = Override then syntax_error (); (mkloc $5 (rhs_loc 5), Private, Cfk_virtual $7), $2 } | override_flag attributes VIRTUAL private_flag label COLON poly_type { if $1 = Override then syntax_error (); (mkloc $5 (rhs_loc 5), $4, Cfk_virtual $7), $2 } | override_flag attributes private_flag label strict_binding { (mkloc $4 (rhs_loc 4), $3, Cfk_concrete ($1, ghexp(Pexp_poly ($5, None)))), $2 } | override_flag attributes private_flag label COLON poly_type EQUAL seq_expr { (mkloc $4 (rhs_loc 4), $3, Cfk_concrete ($1, ghexp(Pexp_poly($8, Some $6)))), $2 } | override_flag attributes private_flag label COLON TYPE lident_list DOT core_type EQUAL seq_expr { let exp, poly = wrap_type_annotation $7 $9 $11 in (mkloc $4 (rhs_loc 4), $3, Cfk_concrete ($1, ghexp(Pexp_poly(exp, Some poly)))), $2 } ; /* Class types */ class_type: class_signature { $1 } | QUESTION LIDENT COLON simple_core_type_or_tuple MINUSGREATER class_type { mkcty(Pcty_arrow(Optional $2 , $4, $6)) } | OPTLABEL simple_core_type_or_tuple MINUSGREATER class_type { mkcty(Pcty_arrow(Optional $1, $2, $4)) } | LIDENT COLON simple_core_type_or_tuple MINUSGREATER class_type { mkcty(Pcty_arrow(Labelled $1, $3, $5)) } | simple_core_type_or_tuple MINUSGREATER class_type { mkcty(Pcty_arrow(Nolabel, $1, $3)) } ; class_signature: LBRACKET core_type_comma_list RBRACKET clty_longident { mkcty(Pcty_constr (mkloc $4 (rhs_loc 4), List.rev $2)) } | clty_longident { mkcty(Pcty_constr (mkrhs $1 1, [])) } | OBJECT attributes class_sig_body END { mkcty ~attrs:$2 (Pcty_signature $3) } | OBJECT attributes class_sig_body error { unclosed "object" 1 "end" 4 } | class_signature attribute { Cty.attr $1 $2 } | extension { mkcty(Pcty_extension $1) } | LET OPEN override_flag attributes mod_longident IN class_signature { wrap_class_type_attrs (mkcty(Pcty_open($3, mkrhs $5 5, $7))) $4 } ; class_sig_body: class_self_type class_sig_fields { Csig.mk $1 (extra_csig 2 (List.rev $2)) } ; class_self_type: LPAREN core_type RPAREN { $2 } | /* empty */ { mktyp(Ptyp_any) } ; class_sig_fields: /* empty */ { [] } | class_sig_fields class_sig_field { $2 :: (text_csig 2) @ $1 } ; class_sig_field: INHERIT attributes class_signature post_item_attributes { mkctf (Pctf_inherit $3) ~attrs:($2@$4) ~docs:(symbol_docs ()) } | VAL attributes value_type post_item_attributes { mkctf (Pctf_val $3) ~attrs:($2@$4) ~docs:(symbol_docs ()) } | METHOD attributes private_virtual_flags label COLON poly_type post_item_attributes { let (p, v) = $3 in mkctf (Pctf_method (mkrhs $4 4, p, v, $6)) ~attrs:($2@$7) ~docs:(symbol_docs ()) } | CONSTRAINT attributes constrain_field post_item_attributes { mkctf (Pctf_constraint $3) ~attrs:($2@$4) ~docs:(symbol_docs ()) } | item_extension post_item_attributes { mkctf (Pctf_extension $1) ~attrs:$2 ~docs:(symbol_docs ()) } | floating_attribute { mark_symbol_docs (); mkctf(Pctf_attribute $1) } ; value_type: VIRTUAL mutable_flag label COLON core_type { mkrhs $3 3, $2, Virtual, $5 } | MUTABLE virtual_flag label COLON core_type { mkrhs $3 3, Mutable, $2, $5 } | label COLON core_type { mkrhs $1 1, Immutable, Concrete, $3 } ; constrain: core_type EQUAL core_type { $1, $3, symbol_rloc() } ; constrain_field: core_type EQUAL core_type { $1, $3 } ; class_descriptions: class_description { let (body, ext) = $1 in ([body],ext) } | class_descriptions and_class_description { let (l, ext) = $1 in ($2 :: l, ext) } ; class_description: CLASS ext_attributes virtual_flag class_type_parameters LIDENT COLON class_type post_item_attributes { let (ext, attrs) = $2 in Ci.mk (mkrhs $5 5) $7 ~virt:$3 ~params:$4 ~attrs:(attrs @ $8) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) , ext } ; and_class_description: AND attributes virtual_flag class_type_parameters LIDENT COLON class_type post_item_attributes { Ci.mk (mkrhs $5 5) $7 ~virt:$3 ~params:$4 ~attrs:($2@$8) ~loc:(symbol_rloc ()) ~text:(symbol_text ()) ~docs:(symbol_docs ()) } ; class_type_declarations: class_type_declaration { let (body, ext) = $1 in ([body],ext) } | class_type_declarations and_class_type_declaration { let (l, ext) = $1 in ($2 :: l, ext) } ; class_type_declaration: CLASS TYPE ext_attributes virtual_flag class_type_parameters LIDENT EQUAL class_signature post_item_attributes { let (ext, attrs) = $3 in Ci.mk (mkrhs $6 6) $8 ~virt:$4 ~params:$5 ~attrs:(attrs@$9) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) , ext} ; and_class_type_declaration: AND attributes virtual_flag class_type_parameters LIDENT EQUAL class_signature post_item_attributes { Ci.mk (mkrhs $5 5) $7 ~virt:$3 ~params:$4 ~attrs:($2@$8) ~loc:(symbol_rloc ()) ~text:(symbol_text ()) ~docs:(symbol_docs ()) } ; /* Core expressions */ seq_expr: | expr %prec below_SEMI { $1 } | expr SEMI { $1 } | expr SEMI seq_expr { mkexp(Pexp_sequence($1, $3)) } | expr SEMI PERCENT attr_id seq_expr { let seq = mkexp(Pexp_sequence ($1, $5)) in let payload = PStr [mkstrexp seq []] in mkexp (Pexp_extension ($4, payload)) } ; labeled_simple_pattern: QUESTION LPAREN label_let_pattern opt_default RPAREN { (Optional (fst $3), $4, snd $3) } | QUESTION label_var { (Optional (fst $2), None, snd $2) } | OPTLABEL LPAREN let_pattern opt_default RPAREN { (Optional $1, $4, $3) } | OPTLABEL pattern_var { (Optional $1, None, $2) } | TILDE LPAREN label_let_pattern RPAREN { (Labelled (fst $3), None, snd $3) } | TILDE label_var { (Labelled (fst $2), None, snd $2) } | LABEL simple_pattern { (Labelled $1, None, $2) } | simple_pattern { (Nolabel, None, $1) } ; pattern_var: LIDENT { mkpat(Ppat_var (mkrhs $1 1)) } | UNDERSCORE { mkpat Ppat_any } ; opt_default: /* empty */ { None } | EQUAL seq_expr { Some $2 } ; label_let_pattern: label_var { $1 } | label_var COLON core_type { let (lab, pat) = $1 in (lab, mkpat(Ppat_constraint(pat, $3))) } ; label_var: LIDENT { ($1, mkpat(Ppat_var (mkrhs $1 1))) } ; let_pattern: pattern { $1 } | pattern COLON core_type { mkpat(Ppat_constraint($1, $3)) } ; expr: simple_expr %prec below_HASH { $1 } | simple_expr simple_labeled_expr_list { mkexp(Pexp_apply($1, List.rev $2)) } | let_bindings IN seq_expr { expr_of_let_bindings $1 $3 } | LET MODULE ext_attributes UIDENT module_binding_body IN seq_expr { mkexp_attrs (Pexp_letmodule(mkrhs $4 4, $5, $7)) $3 } | LET EXCEPTION ext_attributes let_exception_declaration IN seq_expr { mkexp_attrs (Pexp_letexception($4, $6)) $3 } | LET OPEN override_flag ext_attributes mod_longident IN seq_expr { mkexp_attrs (Pexp_open($3, mkrhs $5 5, $7)) $4 } | FUNCTION ext_attributes opt_bar match_cases { mkexp_attrs (Pexp_function(List.rev $4)) $2 } | FUN ext_attributes labeled_simple_pattern fun_def { let (l,o,p) = $3 in mkexp_attrs (Pexp_fun(l, o, p, $4)) $2 } | FUN ext_attributes LPAREN TYPE lident_list RPAREN fun_def { mkexp_attrs (mk_newtypes $5 $7).pexp_desc $2 } | MATCH ext_attributes seq_expr WITH opt_bar match_cases { mkexp_attrs (Pexp_match($3, List.rev $6)) $2 } | TRY ext_attributes seq_expr WITH opt_bar match_cases { mkexp_attrs (Pexp_try($3, List.rev $6)) $2 } | TRY ext_attributes seq_expr WITH error { syntax_error() } | expr_comma_list %prec below_COMMA { mkexp(Pexp_tuple(List.rev $1)) } | constr_longident simple_expr %prec below_HASH { mkexp(Pexp_construct(mkrhs $1 1, Some $2)) } | name_tag simple_expr %prec below_HASH { mkexp(Pexp_variant($1, Some $2)) } | IF ext_attributes seq_expr THEN expr ELSE expr { mkexp_attrs(Pexp_ifthenelse($3, $5, Some $7)) $2 } | IF ext_attributes seq_expr THEN expr { mkexp_attrs (Pexp_ifthenelse($3, $5, None)) $2 } | WHILE ext_attributes seq_expr DO seq_expr DONE { mkexp_attrs (Pexp_while($3, $5)) $2 } | FOR ext_attributes pattern EQUAL seq_expr direction_flag seq_expr DO seq_expr DONE { mkexp_attrs(Pexp_for($3, $5, $7, $6, $9)) $2 } | expr COLONCOLON expr { mkexp_cons (rhs_loc 2) (ghexp(Pexp_tuple[$1;$3])) (symbol_rloc()) } | expr INFIXOP0 expr { mkinfix $1 $2 $3 } | expr INFIXOP1 expr { mkinfix $1 $2 $3 } | expr INFIXOP2 expr { mkinfix $1 $2 $3 } | expr INFIXOP3 expr { mkinfix $1 $2 $3 } | expr INFIXOP4 expr { mkinfix $1 $2 $3 } | expr PLUS expr { mkinfix $1 "+" $3 } | expr PLUSDOT expr { mkinfix $1 "+." $3 } | expr PLUSEQ expr { mkinfix $1 "+=" $3 } | expr MINUS expr { mkinfix $1 "-" $3 } | expr MINUSDOT expr { mkinfix $1 "-." $3 } | expr STAR expr { mkinfix $1 "*" $3 } | expr PERCENT expr { mkinfix $1 "%" $3 } | expr EQUAL expr { mkinfix $1 "=" $3 } | expr LESS expr { mkinfix $1 "<" $3 } | expr GREATER expr { mkinfix $1 ">" $3 } | expr OR expr { mkinfix $1 "or" $3 } | expr BARBAR expr { mkinfix $1 "||" $3 } | expr AMPERSAND expr { mkinfix $1 "&" $3 } | expr AMPERAMPER expr { mkinfix $1 "&&" $3 } | expr COLONEQUAL expr { mkinfix $1 ":=" $3 } | subtractive expr %prec prec_unary_minus { mkuminus $1 $2 } | additive expr %prec prec_unary_plus { mkuplus $1 $2 } | simple_expr DOT label_longident LESSMINUS expr { mkexp(Pexp_setfield($1, mkrhs $3 3, $5)) } | simple_expr DOT LPAREN seq_expr RPAREN LESSMINUS expr { mkexp(Pexp_apply(ghexp(Pexp_ident(array_function "Array" "set")), [Nolabel,$1; Nolabel,$4; Nolabel,$7])) } | simple_expr DOT LBRACKET seq_expr RBRACKET LESSMINUS expr { mkexp(Pexp_apply(ghexp(Pexp_ident(array_function "String" "set")), [Nolabel,$1; Nolabel,$4; Nolabel,$7])) } | simple_expr DOT LBRACE seq_expr RBRACE LESSMINUS expr { bigarray_set $1 $4 $7 } | simple_expr DOTOP LBRACKET seq_expr RBRACKET LESSMINUS expr { let id = mkexp @@ Pexp_ident( ghloc @@ Lident ("." ^ $2 ^ "[]<-")) in mkexp @@ Pexp_apply(id , [Nolabel, $1; Nolabel, $4; Nolabel, $7]) } | simple_expr DOTOP LPAREN seq_expr RPAREN LESSMINUS expr { let id = mkexp @@ Pexp_ident( ghloc @@ Lident ("." ^ $2 ^ "()<-")) in mkexp @@ Pexp_apply(id , [Nolabel, $1; Nolabel, $4; Nolabel, $7]) } | simple_expr DOTOP LBRACE seq_expr RBRACE LESSMINUS expr { let id = mkexp @@ Pexp_ident( ghloc @@ Lident ("." ^ $2 ^ "{}<-")) in mkexp @@ Pexp_apply(id , [Nolabel, $1; Nolabel, $4; Nolabel, $7]) } | simple_expr DOT mod_longident DOTOP LBRACKET seq_expr RBRACKET LESSMINUS expr { let id = mkexp @@ Pexp_ident( ghloc @@ Ldot($3,"." ^ $4 ^ "[]<-")) in mkexp @@ Pexp_apply(id , [Nolabel, $1; Nolabel, $6; Nolabel, $9]) } | simple_expr DOT mod_longident DOTOP LPAREN seq_expr RPAREN LESSMINUS expr { let id = mkexp @@ Pexp_ident( ghloc @@ Ldot($3, "." ^ $4 ^ "()<-")) in mkexp @@ Pexp_apply(id , [Nolabel, $1; Nolabel, $6; Nolabel, $9]) } | simple_expr DOT mod_longident DOTOP LBRACE seq_expr RBRACE LESSMINUS expr { let id = mkexp @@ Pexp_ident( ghloc @@ Ldot($3, "." ^ $4 ^ "{}<-")) in mkexp @@ Pexp_apply(id , [Nolabel, $1; Nolabel, $6; Nolabel, $9]) } | label LESSMINUS expr { mkexp(Pexp_setinstvar(mkrhs $1 1, $3)) } | ASSERT ext_attributes simple_expr %prec below_HASH { mkexp_attrs (Pexp_assert $3) $2 } | LAZY ext_attributes simple_expr %prec below_HASH { mkexp_attrs (Pexp_lazy $3) $2 } | OBJECT ext_attributes class_structure END { mkexp_attrs (Pexp_object $3) $2 } | OBJECT ext_attributes class_structure error { unclosed "object" 1 "end" 4 } | expr attribute { Exp.attr $1 $2 } | UNDERSCORE { not_expecting 1 "wildcard \"_\"" } ; simple_expr: val_longident { mkexp(Pexp_ident (mkrhs $1 1)) } | constant { mkexp(Pexp_constant $1) } | constr_longident %prec prec_constant_constructor { mkexp(Pexp_construct(mkrhs $1 1, None)) } | name_tag %prec prec_constant_constructor { mkexp(Pexp_variant($1, None)) } | LPAREN seq_expr RPAREN { reloc_exp $2 } | LPAREN seq_expr error { unclosed "(" 1 ")" 3 } | BEGIN ext_attributes seq_expr END { wrap_exp_attrs (reloc_exp $3) $2 (* check location *) } | BEGIN ext_attributes END { mkexp_attrs (Pexp_construct (mkloc (Lident "()") (symbol_rloc ()), None)) $2 } | BEGIN ext_attributes seq_expr error { unclosed "begin" 1 "end" 4 } | LPAREN seq_expr type_constraint RPAREN { mkexp_constraint $2 $3 } | simple_expr DOT label_longident { mkexp(Pexp_field($1, mkrhs $3 3)) } | mod_longident DOT LPAREN seq_expr RPAREN { mkexp(Pexp_open(Fresh, mkrhs $1 1, $4)) } | mod_longident DOT LPAREN RPAREN { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp(Pexp_construct(mkrhs (Lident "()") 1, None)))) } | mod_longident DOT LPAREN seq_expr error { unclosed "(" 3 ")" 5 } | simple_expr DOT LPAREN seq_expr RPAREN { mkexp(Pexp_apply(ghexp(Pexp_ident(array_function "Array" "get")), [Nolabel,$1; Nolabel,$4])) } | simple_expr DOT LPAREN seq_expr error { unclosed "(" 3 ")" 5 } | simple_expr DOT LBRACKET seq_expr RBRACKET { mkexp(Pexp_apply(ghexp(Pexp_ident(array_function "String" "get")), [Nolabel,$1; Nolabel,$4])) } | simple_expr DOT LBRACKET seq_expr error { unclosed "[" 3 "]" 5 } | simple_expr DOTOP LBRACKET seq_expr RBRACKET { let id = mkexp @@ Pexp_ident( ghloc @@ Lident ("." ^ $2 ^ "[]")) in mkexp @@ Pexp_apply(id, [Nolabel, $1; Nolabel, $4]) } | simple_expr DOTOP LBRACKET seq_expr error { unclosed "[" 3 "]" 5 } | simple_expr DOTOP LPAREN seq_expr RPAREN { let id = mkexp @@ Pexp_ident( ghloc @@ Lident ("." ^ $2 ^ "()")) in mkexp @@ Pexp_apply(id, [Nolabel, $1; Nolabel, $4]) } | simple_expr DOTOP LPAREN seq_expr error { unclosed "(" 3 ")" 5 } | simple_expr DOTOP LBRACE seq_expr RBRACE { let id = mkexp @@ Pexp_ident( ghloc @@ Lident ("." ^ $2 ^ "{}")) in mkexp @@ Pexp_apply(id, [Nolabel, $1; Nolabel, $4]) } | simple_expr DOTOP LBRACE seq_expr error { unclosed "{" 3 "}" 5 } | simple_expr DOT mod_longident DOTOP LBRACKET seq_expr RBRACKET { let id = mkexp @@ Pexp_ident( ghloc @@ Ldot($3, "." ^ $4 ^ "[]")) in mkexp @@ Pexp_apply(id, [Nolabel, $1; Nolabel, $6]) } | simple_expr DOT mod_longident DOTOP LBRACKET seq_expr error { unclosed "[" 5 "]" 7 } | simple_expr DOT mod_longident DOTOP LPAREN seq_expr RPAREN { let id = mkexp @@ Pexp_ident( ghloc @@ Ldot($3, "." ^ $4 ^ "()")) in mkexp @@ Pexp_apply(id, [Nolabel, $1; Nolabel, $6]) } | simple_expr DOT mod_longident DOTOP LPAREN seq_expr error { unclosed "(" 5 ")" 7 } | simple_expr DOT mod_longident DOTOP LBRACE seq_expr RBRACE { let id = mkexp @@ Pexp_ident( ghloc @@ Ldot($3, "." ^ $4 ^ "{}")) in mkexp @@ Pexp_apply(id, [Nolabel, $1; Nolabel, $6]) } | simple_expr DOT mod_longident DOTOP LBRACE seq_expr error { unclosed "{" 5 "}" 7 } | simple_expr DOT LBRACE seq_expr RBRACE { bigarray_get $1 $4 } | simple_expr DOT LBRACE expr_comma_list error { unclosed "{" 3 "}" 5 } | LBRACE record_expr RBRACE { let (exten, fields) = $2 in mkexp (Pexp_record(fields, exten)) } | LBRACE record_expr error { unclosed "{" 1 "}" 3 } | mod_longident DOT LBRACE record_expr RBRACE { let (exten, fields) = $4 in let rec_exp = mkexp(Pexp_record(fields, exten)) in mkexp(Pexp_open(Fresh, mkrhs $1 1, rec_exp)) } | mod_longident DOT LBRACE record_expr error { unclosed "{" 3 "}" 5 } | LBRACKETBAR expr_semi_list opt_semi BARRBRACKET { mkexp (Pexp_array(List.rev $2)) } | LBRACKETBAR expr_semi_list opt_semi error { unclosed "[|" 1 "|]" 4 } | LBRACKETBAR BARRBRACKET { mkexp (Pexp_array []) } | mod_longident DOT LBRACKETBAR expr_semi_list opt_semi BARRBRACKET { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp(Pexp_array(List.rev $4)))) } | mod_longident DOT LBRACKETBAR BARRBRACKET { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp(Pexp_array []))) } | mod_longident DOT LBRACKETBAR expr_semi_list opt_semi error { unclosed "[|" 3 "|]" 6 } | LBRACKET expr_semi_list opt_semi RBRACKET { reloc_exp (mktailexp (rhs_loc 4) (List.rev $2)) } | LBRACKET expr_semi_list opt_semi error { unclosed "[" 1 "]" 4 } | mod_longident DOT LBRACKET expr_semi_list opt_semi RBRACKET { let list_exp = reloc_exp (mktailexp (rhs_loc 6) (List.rev $4)) in mkexp(Pexp_open(Fresh, mkrhs $1 1, list_exp)) } | mod_longident DOT LBRACKET RBRACKET { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp(Pexp_construct(mkrhs (Lident "[]") 1, None)))) } | mod_longident DOT LBRACKET expr_semi_list opt_semi error { unclosed "[" 3 "]" 6 } | PREFIXOP simple_expr { mkexp(Pexp_apply(mkoperator $1 1, [Nolabel,$2])) } | BANG simple_expr { mkexp(Pexp_apply(mkoperator "!" 1, [Nolabel,$2])) } | NEW ext_attributes class_longident { mkexp_attrs (Pexp_new(mkrhs $3 3)) $2 } | LBRACELESS field_expr_list GREATERRBRACE { mkexp (Pexp_override $2) } | LBRACELESS field_expr_list error { unclosed "{<" 1 ">}" 3 } | LBRACELESS GREATERRBRACE { mkexp (Pexp_override [])} | mod_longident DOT LBRACELESS field_expr_list GREATERRBRACE { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp (Pexp_override $4)))} | mod_longident DOT LBRACELESS GREATERRBRACE { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp (Pexp_override [])))} | mod_longident DOT LBRACELESS field_expr_list error { unclosed "{<" 3 ">}" 5 } | simple_expr HASH label { mkexp(Pexp_send($1, mkrhs $3 3)) } | simple_expr HASHOP simple_expr { mkinfix $1 $2 $3 } | LPAREN MODULE ext_attributes module_expr RPAREN { mkexp_attrs (Pexp_pack $4) $3 } | LPAREN MODULE ext_attributes module_expr COLON package_type RPAREN { mkexp_attrs (Pexp_constraint (ghexp (Pexp_pack $4), ghtyp (Ptyp_package $6))) $3 } | LPAREN MODULE ext_attributes module_expr COLON error { unclosed "(" 1 ")" 6 } | mod_longident DOT LPAREN MODULE ext_attributes module_expr COLON package_type RPAREN { mkexp(Pexp_open(Fresh, mkrhs $1 1, mkexp_attrs (Pexp_constraint (ghexp (Pexp_pack $6), ghtyp (Ptyp_package $8))) $5 )) } | mod_longident DOT LPAREN MODULE ext_attributes module_expr COLON error { unclosed "(" 3 ")" 8 } | extension { mkexp (Pexp_extension $1) } ; simple_labeled_expr_list: labeled_simple_expr { [$1] } | simple_labeled_expr_list labeled_simple_expr { $2 :: $1 } ; labeled_simple_expr: simple_expr %prec below_HASH { (Nolabel, $1) } | label_expr { $1 } ; label_expr: LABEL simple_expr %prec below_HASH { (Labelled $1, $2) } | TILDE label_ident { (Labelled (fst $2), snd $2) } | QUESTION label_ident { (Optional (fst $2), snd $2) } | OPTLABEL simple_expr %prec below_HASH { (Optional $1, $2) } ; label_ident: LIDENT { ($1, mkexp(Pexp_ident(mkrhs (Lident $1) 1))) } ; lident_list: LIDENT { [mkrhs $1 1] } | LIDENT lident_list { mkrhs $1 1 :: $2 } ; let_binding_body: val_ident strict_binding { (mkpatvar $1 1, $2) } | val_ident type_constraint EQUAL seq_expr { let v = mkpatvar $1 1 in (* PR#7344 *) let t = match $2 with Some t, None -> t | _, Some t -> t | _ -> assert false in (ghpat(Ppat_constraint(v, ghtyp(Ptyp_poly([],t)))), mkexp_constraint $4 $2) } | val_ident COLON typevar_list DOT core_type EQUAL seq_expr { (ghpat(Ppat_constraint(mkpatvar $1 1, ghtyp(Ptyp_poly(List.rev $3,$5)))), $7) } | val_ident COLON TYPE lident_list DOT core_type EQUAL seq_expr { let exp, poly = wrap_type_annotation $4 $6 $8 in (ghpat(Ppat_constraint(mkpatvar $1 1, poly)), exp) } | pattern_no_exn EQUAL seq_expr { ($1, $3) } | simple_pattern_not_ident COLON core_type EQUAL seq_expr { (ghpat(Ppat_constraint($1, $3)), $5) } ; let_bindings: let_binding { $1 } | let_bindings and_let_binding { addlb $1 $2 } ; let_binding: LET ext_attributes rec_flag let_binding_body post_item_attributes { let (ext, attr) = $2 in mklbs ext $3 (mklb true $4 (attr@$5)) } ; and_let_binding: AND attributes let_binding_body post_item_attributes { mklb false $3 ($2@$4) } ; fun_binding: strict_binding { $1 } | type_constraint EQUAL seq_expr { mkexp_constraint $3 $1 } ; strict_binding: EQUAL seq_expr { $2 } | labeled_simple_pattern fun_binding { let (l, o, p) = $1 in ghexp(Pexp_fun(l, o, p, $2)) } | LPAREN TYPE lident_list RPAREN fun_binding { mk_newtypes $3 $5 } ; match_cases: match_case { [$1] } | match_cases BAR match_case { $3 :: $1 } ; match_case: pattern MINUSGREATER seq_expr { Exp.case $1 $3 } | pattern WHEN seq_expr MINUSGREATER seq_expr { Exp.case $1 ~guard:$3 $5 } | pattern MINUSGREATER DOT { Exp.case $1 (Exp.unreachable ~loc:(rhs_loc 3) ())} ; fun_def: MINUSGREATER seq_expr { $2 } | COLON simple_core_type MINUSGREATER seq_expr { mkexp (Pexp_constraint ($4, $2)) } /* Cf #5939: we used to accept (fun p when e0 -> e) */ | labeled_simple_pattern fun_def { let (l,o,p) = $1 in ghexp(Pexp_fun(l, o, p, $2)) } | LPAREN TYPE lident_list RPAREN fun_def { mk_newtypes $3 $5 } ; expr_comma_list: expr_comma_list COMMA expr { $3 :: $1 } | expr COMMA expr { [$3; $1] } ; record_expr: simple_expr WITH lbl_expr_list { (Some $1, $3) } | lbl_expr_list { (None, $1) } ; lbl_expr_list: lbl_expr { [$1] } | lbl_expr SEMI lbl_expr_list { $1 :: $3 } | lbl_expr SEMI { [$1] } ; lbl_expr: label_longident opt_type_constraint EQUAL expr { (mkrhs $1 1, mkexp_opt_constraint $4 $2) } | label_longident opt_type_constraint { (mkrhs $1 1, mkexp_opt_constraint (exp_of_label $1 1) $2) } ; field_expr_list: field_expr opt_semi { [$1] } | field_expr SEMI field_expr_list { $1 :: $3 } ; field_expr: label EQUAL expr { (mkrhs $1 1, $3) } | label { (mkrhs $1 1, exp_of_label (Lident $1) 1) } ; expr_semi_list: expr { [$1] } | expr_semi_list SEMI expr { $3 :: $1 } ; type_constraint: COLON core_type { (Some $2, None) } | COLON core_type COLONGREATER core_type { (Some $2, Some $4) } | COLONGREATER core_type { (None, Some $2) } | COLON error { syntax_error() } | COLONGREATER error { syntax_error() } ; opt_type_constraint: type_constraint { Some $1 } | /* empty */ { None } ; /* Patterns */ pattern: | pattern AS val_ident { mkpat(Ppat_alias($1, mkrhs $3 3)) } | pattern AS error { expecting 3 "identifier" } | pattern_comma_list %prec below_COMMA { mkpat(Ppat_tuple(List.rev $1)) } | pattern COLONCOLON pattern { mkpat_cons (rhs_loc 2) (ghpat(Ppat_tuple[$1;$3])) (symbol_rloc()) } | pattern COLONCOLON error { expecting 3 "pattern" } | pattern BAR pattern { mkpat(Ppat_or($1, $3)) } | pattern BAR error { expecting 3 "pattern" } | EXCEPTION ext_attributes pattern %prec prec_constr_appl { mkpat_attrs (Ppat_exception $3) $2} | pattern attribute { Pat.attr $1 $2 } | pattern_gen { $1 } ; pattern_no_exn: | pattern_no_exn AS val_ident { mkpat(Ppat_alias($1, mkrhs $3 3)) } | pattern_no_exn AS error { expecting 3 "identifier" } | pattern_no_exn_comma_list %prec below_COMMA { mkpat(Ppat_tuple(List.rev $1)) } | pattern_no_exn COLONCOLON pattern { mkpat_cons (rhs_loc 2) (ghpat(Ppat_tuple[$1;$3])) (symbol_rloc()) } | pattern_no_exn COLONCOLON error { expecting 3 "pattern" } | pattern_no_exn BAR pattern { mkpat(Ppat_or($1, $3)) } | pattern_no_exn BAR error { expecting 3 "pattern" } | pattern_no_exn attribute { Pat.attr $1 $2 } | pattern_gen { $1 } ; pattern_gen: simple_pattern { $1 } | constr_longident pattern %prec prec_constr_appl { mkpat(Ppat_construct(mkrhs $1 1, Some $2)) } | name_tag pattern %prec prec_constr_appl { mkpat(Ppat_variant($1, Some $2)) } | LAZY ext_attributes simple_pattern { mkpat_attrs (Ppat_lazy $3) $2} ; simple_pattern: val_ident %prec below_EQUAL { mkpat(Ppat_var (mkrhs $1 1)) } | simple_pattern_not_ident { $1 } ; simple_pattern_not_ident: | UNDERSCORE { mkpat(Ppat_any) } | signed_constant { mkpat(Ppat_constant $1) } | signed_constant DOTDOT signed_constant { mkpat(Ppat_interval ($1, $3)) } | constr_longident { mkpat(Ppat_construct(mkrhs $1 1, None)) } | name_tag { mkpat(Ppat_variant($1, None)) } | HASH type_longident { mkpat(Ppat_type (mkrhs $2 2)) } | simple_delimited_pattern { $1 } | mod_longident DOT simple_delimited_pattern { mkpat @@ Ppat_open(mkrhs $1 1, $3) } | mod_longident DOT LBRACKET RBRACKET { mkpat @@ Ppat_open(mkrhs $1 1, mkpat @@ Ppat_construct ( mkrhs (Lident "[]") 4, None)) } | mod_longident DOT LPAREN RPAREN { mkpat @@ Ppat_open( mkrhs $1 1, mkpat @@ Ppat_construct ( mkrhs (Lident "()") 4, None) ) } | mod_longident DOT LPAREN pattern RPAREN { mkpat @@ Ppat_open (mkrhs $1 1, $4)} | mod_longident DOT LPAREN pattern error {unclosed "(" 3 ")" 5 } | mod_longident DOT LPAREN error { expecting 4 "pattern" } | LPAREN pattern RPAREN { reloc_pat $2 } | LPAREN pattern error { unclosed "(" 1 ")" 3 } | LPAREN pattern COLON core_type RPAREN { mkpat(Ppat_constraint($2, $4)) } | LPAREN pattern COLON core_type error { unclosed "(" 1 ")" 5 } | LPAREN pattern COLON error { expecting 4 "type" } | LPAREN MODULE ext_attributes UIDENT RPAREN { mkpat_attrs (Ppat_unpack (mkrhs $4 4)) $3 } | LPAREN MODULE ext_attributes UIDENT COLON package_type RPAREN { mkpat_attrs (Ppat_constraint(mkpat(Ppat_unpack (mkrhs $4 4)), ghtyp(Ptyp_package $6))) $3 } | LPAREN MODULE ext_attributes UIDENT COLON package_type error { unclosed "(" 1 ")" 7 } | extension { mkpat(Ppat_extension $1) } ; simple_delimited_pattern: | LBRACE lbl_pattern_list RBRACE { let (fields, closed) = $2 in mkpat(Ppat_record(fields, closed)) } | LBRACE lbl_pattern_list error { unclosed "{" 1 "}" 3 } | LBRACKET pattern_semi_list opt_semi RBRACKET { reloc_pat (mktailpat (rhs_loc 4) (List.rev $2)) } | LBRACKET pattern_semi_list opt_semi error { unclosed "[" 1 "]" 4 } | LBRACKETBAR pattern_semi_list opt_semi BARRBRACKET { mkpat(Ppat_array(List.rev $2)) } | LBRACKETBAR BARRBRACKET { mkpat(Ppat_array []) } | LBRACKETBAR pattern_semi_list opt_semi error { unclosed "[|" 1 "|]" 4 } pattern_comma_list: pattern_comma_list COMMA pattern { $3 :: $1 } | pattern COMMA pattern { [$3; $1] } | pattern COMMA error { expecting 3 "pattern" } ; pattern_no_exn_comma_list: pattern_no_exn_comma_list COMMA pattern { $3 :: $1 } | pattern_no_exn COMMA pattern { [$3; $1] } | pattern_no_exn COMMA error { expecting 3 "pattern" } ; pattern_semi_list: pattern { [$1] } | pattern_semi_list SEMI pattern { $3 :: $1 } ; lbl_pattern_list: lbl_pattern { [$1], Closed } | lbl_pattern SEMI { [$1], Closed } | lbl_pattern SEMI UNDERSCORE opt_semi { [$1], Open } | lbl_pattern SEMI lbl_pattern_list { let (fields, closed) = $3 in $1 :: fields, closed } ; lbl_pattern: label_longident opt_pattern_type_constraint EQUAL pattern { (mkrhs $1 1, mkpat_opt_constraint $4 $2) } | label_longident opt_pattern_type_constraint { (mkrhs $1 1, mkpat_opt_constraint (pat_of_label $1 1) $2) } ; opt_pattern_type_constraint: COLON core_type { Some $2 } | /* empty */ { None } ; /* Value descriptions */ value_description: VAL ext_attributes val_ident COLON core_type post_item_attributes { let (ext, attrs) = $2 in Val.mk (mkrhs $3 3) $5 ~attrs:(attrs@$6) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; /* Primitive declarations */ primitive_declaration_body: STRING { [fst $1] } | STRING primitive_declaration_body { fst $1 :: $2 } ; primitive_declaration: EXTERNAL ext_attributes val_ident COLON core_type EQUAL primitive_declaration_body post_item_attributes { let (ext, attrs) = $2 in Val.mk (mkrhs $3 3) $5 ~prim:$7 ~attrs:(attrs@$8) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) , ext } ; /* Type declarations */ type_declarations: type_declaration { let (nonrec_flag, ty, ext) = $1 in (nonrec_flag, [ty], ext) } | type_declarations and_type_declaration { let (nonrec_flag, tys, ext) = $1 in (nonrec_flag, $2 :: tys, ext) } ; type_declaration: TYPE ext_attributes nonrec_flag optional_type_parameters LIDENT type_kind constraints post_item_attributes { let (kind, priv, manifest) = $6 in let (ext, attrs) = $2 in let ty = Type.mk (mkrhs $5 5) ~params:$4 ~cstrs:(List.rev $7) ~kind ~priv ?manifest ~attrs:(attrs@$8) ~loc:(symbol_rloc ()) ~docs:(symbol_docs ()) in ($3, ty, ext) } ; and_type_declaration: AND attributes optional_type_parameters LIDENT type_kind constraints post_item_attributes { let (kind, priv, manifest) = $5 in Type.mk (mkrhs $4 4) ~params:$3 ~cstrs:(List.rev $6) ~kind ~priv ?manifest ~attrs:($2@$7) ~loc:(symbol_rloc ()) ~text:(symbol_text ()) ~docs:(symbol_docs ()) } ; constraints: constraints CONSTRAINT constrain { $3 :: $1 } | /* empty */ { [] } ; type_kind: /*empty*/ { (Ptype_abstract, Public, None) } | EQUAL core_type { (Ptype_abstract, Public, Some $2) } | EQUAL PRIVATE core_type { (Ptype_abstract, Private, Some $3) } | EQUAL constructor_declarations { (Ptype_variant(List.rev $2), Public, None) } | EQUAL PRIVATE constructor_declarations { (Ptype_variant(List.rev $3), Private, None) } | EQUAL DOTDOT { (Ptype_open, Public, None) } | EQUAL PRIVATE DOTDOT { (Ptype_open, Private, None) } | EQUAL private_flag LBRACE label_declarations RBRACE { (Ptype_record $4, $2, None) } | EQUAL core_type EQUAL private_flag constructor_declarations { (Ptype_variant(List.rev $5), $4, Some $2) } | EQUAL core_type EQUAL private_flag DOTDOT { (Ptype_open, $4, Some $2) } | EQUAL core_type EQUAL private_flag LBRACE label_declarations RBRACE { (Ptype_record $6, $4, Some $2) } ; optional_type_parameters: /*empty*/ { [] } | optional_type_parameter { [$1] } | LPAREN optional_type_parameter_list RPAREN { List.rev $2 } ; optional_type_parameter: type_variance optional_type_variable { $2, $1 } ; optional_type_parameter_list: optional_type_parameter { [$1] } | optional_type_parameter_list COMMA optional_type_parameter { $3 :: $1 } ; optional_type_variable: QUOTE ident { mktyp(Ptyp_var $2) } | UNDERSCORE { mktyp(Ptyp_any) } ; type_parameter: type_variance type_variable { $2, $1 } ; type_variance: /* empty */ { Invariant } | PLUS { Covariant } | MINUS { Contravariant } ; type_variable: QUOTE ident { mktyp(Ptyp_var $2) } ; type_parameter_list: type_parameter { [$1] } | type_parameter_list COMMA type_parameter { $3 :: $1 } ; constructor_declarations: constructor_declaration { [$1] } | bar_constructor_declaration { [$1] } | constructor_declarations bar_constructor_declaration { $2 :: $1 } ; constructor_declaration: | constr_ident generalized_constructor_arguments attributes { let args,res = $2 in Type.constructor (mkrhs $1 1) ~args ?res ~attrs:$3 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; bar_constructor_declaration: | BAR constr_ident generalized_constructor_arguments attributes { let args,res = $3 in Type.constructor (mkrhs $2 2) ~args ?res ~attrs:$4 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; str_exception_declaration: | sig_exception_declaration { $1 } | EXCEPTION ext_attributes constr_ident EQUAL constr_longident attributes post_item_attributes { let (ext,attrs) = $2 in Te.rebind (mkrhs $3 3) (mkrhs $5 5) ~attrs:(attrs @ $6 @ $7) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; sig_exception_declaration: | EXCEPTION ext_attributes constr_ident generalized_constructor_arguments attributes post_item_attributes { let args, res = $4 in let (ext,attrs) = $2 in Te.decl (mkrhs $3 3) ~args ?res ~attrs:(attrs @ $5 @ $6) ~loc:(symbol_rloc()) ~docs:(symbol_docs ()) , ext } ; let_exception_declaration: constr_ident generalized_constructor_arguments attributes { let args, res = $2 in Te.decl (mkrhs $1 1) ~args ?res ~attrs:$3 ~loc:(symbol_rloc()) } ; generalized_constructor_arguments: /*empty*/ { (Pcstr_tuple [],None) } | OF constructor_arguments { ($2,None) } | COLON constructor_arguments MINUSGREATER simple_core_type { ($2,Some $4) } | COLON simple_core_type { (Pcstr_tuple [],Some $2) } ; constructor_arguments: | core_type_list { Pcstr_tuple (List.rev $1) } | LBRACE label_declarations RBRACE { Pcstr_record $2 } ; label_declarations: label_declaration { [$1] } | label_declaration_semi { [$1] } | label_declaration_semi label_declarations { $1 :: $2 } ; label_declaration: mutable_flag label COLON poly_type_no_attr attributes { Type.field (mkrhs $2 2) $4 ~mut:$1 ~attrs:$5 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; label_declaration_semi: mutable_flag label COLON poly_type_no_attr attributes SEMI attributes { let info = match rhs_info 5 with | Some _ as info_before_semi -> info_before_semi | None -> symbol_info () in Type.field (mkrhs $2 2) $4 ~mut:$1 ~attrs:($5 @ $7) ~loc:(symbol_rloc()) ~info } ; /* Type Extensions */ str_type_extension: TYPE ext_attributes nonrec_flag optional_type_parameters type_longident PLUSEQ private_flag str_extension_constructors post_item_attributes { let (ext, attrs) = $2 in if $3 <> Recursive then not_expecting 3 "nonrec flag"; Te.mk (mkrhs $5 5) (List.rev $8) ~params:$4 ~priv:$7 ~attrs:(attrs@$9) ~docs:(symbol_docs ()) , ext } ; sig_type_extension: TYPE ext_attributes nonrec_flag optional_type_parameters type_longident PLUSEQ private_flag sig_extension_constructors post_item_attributes { let (ext, attrs) = $2 in if $3 <> Recursive then not_expecting 3 "nonrec flag"; Te.mk (mkrhs $5 5) (List.rev $8) ~params:$4 ~priv:$7 ~attrs:(attrs @ $9) ~docs:(symbol_docs ()) , ext } ; str_extension_constructors: extension_constructor_declaration { [$1] } | bar_extension_constructor_declaration { [$1] } | extension_constructor_rebind { [$1] } | bar_extension_constructor_rebind { [$1] } | str_extension_constructors bar_extension_constructor_declaration { $2 :: $1 } | str_extension_constructors bar_extension_constructor_rebind { $2 :: $1 } ; sig_extension_constructors: extension_constructor_declaration { [$1] } | bar_extension_constructor_declaration { [$1] } | sig_extension_constructors bar_extension_constructor_declaration { $2 :: $1 } ; extension_constructor_declaration: | constr_ident generalized_constructor_arguments attributes { let args, res = $2 in Te.decl (mkrhs $1 1) ~args ?res ~attrs:$3 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; bar_extension_constructor_declaration: | BAR constr_ident generalized_constructor_arguments attributes { let args, res = $3 in Te.decl (mkrhs $2 2) ~args ?res ~attrs:$4 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; extension_constructor_rebind: | constr_ident EQUAL constr_longident attributes { Te.rebind (mkrhs $1 1) (mkrhs $3 3) ~attrs:$4 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; bar_extension_constructor_rebind: | BAR constr_ident EQUAL constr_longident attributes { Te.rebind (mkrhs $2 2) (mkrhs $4 4) ~attrs:$5 ~loc:(symbol_rloc()) ~info:(symbol_info ()) } ; /* "with" constraints (additional type equations over signature components) */ with_constraints: with_constraint { [$1] } | with_constraints AND with_constraint { $3 :: $1 } ; with_constraint: TYPE optional_type_parameters label_longident with_type_binder core_type_no_attr constraints { Pwith_type (mkrhs $3 3, (Type.mk (mkrhs (Longident.last $3) 3) ~params:$2 ~cstrs:(List.rev $6) ~manifest:$5 ~priv:$4 ~loc:(symbol_rloc()))) } /* used label_longident instead of type_longident to disallow functor applications in type path */ | TYPE optional_type_parameters label_longident COLONEQUAL core_type_no_attr { Pwith_typesubst (mkrhs $3 3, (Type.mk (mkrhs (Longident.last $3) 3) ~params:$2 ~manifest:$5 ~loc:(symbol_rloc()))) } | MODULE mod_longident EQUAL mod_ext_longident { Pwith_module (mkrhs $2 2, mkrhs $4 4) } | MODULE mod_longident COLONEQUAL mod_ext_longident { Pwith_modsubst (mkrhs $2 2, mkrhs $4 4) } ; with_type_binder: EQUAL { Public } | EQUAL PRIVATE { Private } ; /* Polymorphic types */ typevar_list: QUOTE ident { [mkrhs $2 2] } | typevar_list QUOTE ident { mkrhs $3 3 :: $1 } ; poly_type: core_type { $1 } | typevar_list DOT core_type { mktyp(Ptyp_poly(List.rev $1, $3)) } ; poly_type_no_attr: core_type_no_attr { $1 } | typevar_list DOT core_type_no_attr { mktyp(Ptyp_poly(List.rev $1, $3)) } ; /* Core types */ core_type: core_type_no_attr { $1 } | core_type attribute { Typ.attr $1 $2 } ; core_type_no_attr: core_type2 %prec MINUSGREATER { $1 } | core_type2 AS QUOTE ident { mktyp(Ptyp_alias($1, $4)) } ; core_type2: simple_core_type_or_tuple { $1 } | QUESTION LIDENT COLON core_type2 MINUSGREATER core_type2 { let param = extra_rhs_core_type $4 ~pos:4 in mktyp (Ptyp_arrow(Optional $2 , param, $6)) } | OPTLABEL core_type2 MINUSGREATER core_type2 { let param = extra_rhs_core_type $2 ~pos:2 in mktyp(Ptyp_arrow(Optional $1 , param, $4)) } | LIDENT COLON core_type2 MINUSGREATER core_type2 { let param = extra_rhs_core_type $3 ~pos:3 in mktyp(Ptyp_arrow(Labelled $1, param, $5)) } | core_type2 MINUSGREATER core_type2 { let param = extra_rhs_core_type $1 ~pos:1 in mktyp(Ptyp_arrow(Nolabel, param, $3)) } ; simple_core_type: simple_core_type2 %prec below_HASH { $1 } | LPAREN core_type_comma_list RPAREN %prec below_HASH { match $2 with [sty] -> sty | _ -> raise Parse_error } ; simple_core_type2: QUOTE ident { mktyp(Ptyp_var $2) } | UNDERSCORE { mktyp(Ptyp_any) } | type_longident { mktyp(Ptyp_constr(mkrhs $1 1, [])) } | simple_core_type2 type_longident { mktyp(Ptyp_constr(mkrhs $2 2, [$1])) } | LPAREN core_type_comma_list RPAREN type_longident { mktyp(Ptyp_constr(mkrhs $4 4, List.rev $2)) } | LESS meth_list GREATER { let (f, c) = $2 in mktyp(Ptyp_object (f, c)) } | LESS GREATER { mktyp(Ptyp_object ([], Closed)) } | HASH class_longident { mktyp(Ptyp_class(mkrhs $2 2, [])) } | simple_core_type2 HASH class_longident { mktyp(Ptyp_class(mkrhs $3 3, [$1])) } | LPAREN core_type_comma_list RPAREN HASH class_longident { mktyp(Ptyp_class(mkrhs $5 5, List.rev $2)) } | LBRACKET tag_field RBRACKET { mktyp(Ptyp_variant([$2], Closed, None)) } /* PR#3835: this is not LR(1), would need lookahead=2 | LBRACKET simple_core_type RBRACKET { mktyp(Ptyp_variant([$2], Closed, None)) } */ | LBRACKET BAR row_field_list RBRACKET { mktyp(Ptyp_variant(List.rev $3, Closed, None)) } | LBRACKET row_field BAR row_field_list RBRACKET { mktyp(Ptyp_variant($2 :: List.rev $4, Closed, None)) } | LBRACKETGREATER opt_bar row_field_list RBRACKET { mktyp(Ptyp_variant(List.rev $3, Open, None)) } | LBRACKETGREATER RBRACKET { mktyp(Ptyp_variant([], Open, None)) } | LBRACKETLESS opt_bar row_field_list RBRACKET { mktyp(Ptyp_variant(List.rev $3, Closed, Some [])) } | LBRACKETLESS opt_bar row_field_list GREATER name_tag_list RBRACKET { mktyp(Ptyp_variant(List.rev $3, Closed, Some (List.rev $5))) } | LPAREN MODULE ext_attributes package_type RPAREN { mktyp_attrs (Ptyp_package $4) $3 } | extension { mktyp (Ptyp_extension $1) } ; package_type: module_type { package_type_of_module_type $1 } ; row_field_list: row_field { [$1] } | row_field_list BAR row_field { $3 :: $1 } ; row_field: tag_field { $1 } | simple_core_type { Rinherit $1 } ; tag_field: name_tag OF opt_ampersand amper_type_list attributes { Rtag (mkrhs $1 1, add_info_attrs (symbol_info ()) $5, $3, List.rev $4) } | name_tag attributes { Rtag (mkrhs $1 1, add_info_attrs (symbol_info ()) $2, true, []) } ; opt_ampersand: AMPERSAND { true } | /* empty */ { false } ; amper_type_list: core_type_no_attr { [$1] } | amper_type_list AMPERSAND core_type_no_attr { $3 :: $1 } ; name_tag_list: name_tag { [$1] } | name_tag_list name_tag { $2 :: $1 } ; simple_core_type_or_tuple: simple_core_type { $1 } | simple_core_type STAR core_type_list { mktyp(Ptyp_tuple($1 :: List.rev $3)) } ; core_type_comma_list: core_type { [$1] } | core_type_comma_list COMMA core_type { $3 :: $1 } ; core_type_list: simple_core_type { [$1] } | core_type_list STAR simple_core_type { $3 :: $1 } ; meth_list: field_semi meth_list { let (f, c) = $2 in ($1 :: f, c) } | inherit_field_semi meth_list { let (f, c) = $2 in ($1 :: f, c) } | field_semi { [$1], Closed } | field { [$1], Closed } | inherit_field_semi { [$1], Closed } | simple_core_type { [Oinherit $1], Closed } | DOTDOT { [], Open } ; field: label COLON poly_type_no_attr attributes { Otag (mkrhs $1 1, add_info_attrs (symbol_info ()) $4, $3) } ; field_semi: label COLON poly_type_no_attr attributes SEMI attributes { let info = match rhs_info 4 with | Some _ as info_before_semi -> info_before_semi | None -> symbol_info () in ( Otag (mkrhs $1 1, add_info_attrs info ($4 @ $6), $3)) } ; inherit_field_semi: simple_core_type SEMI { Oinherit $1 } label: LIDENT { $1 } ; /* Constants */ constant: | INT { let (n, m) = $1 in Pconst_integer (n, m) } | CHAR { Pconst_char $1 } | STRING { let (s, d) = $1 in Pconst_string (s, d) } | FLOAT { let (f, m) = $1 in Pconst_float (f, m) } ; signed_constant: constant { $1 } | MINUS INT { let (n, m) = $2 in Pconst_integer("-" ^ n, m) } | MINUS FLOAT { let (f, m) = $2 in Pconst_float("-" ^ f, m) } | PLUS INT { let (n, m) = $2 in Pconst_integer (n, m) } | PLUS FLOAT { let (f, m) = $2 in Pconst_float(f, m) } ; /* Identifiers and long identifiers */ ident: UIDENT { $1 } | LIDENT { $1 } ; val_ident: LIDENT { $1 } | LPAREN operator RPAREN { $2 } | LPAREN operator error { unclosed "(" 1 ")" 3 } | LPAREN error { expecting 2 "operator" } | LPAREN MODULE error { expecting 3 "module-expr" } ; operator: PREFIXOP { $1 } | INFIXOP0 { $1 } | INFIXOP1 { $1 } | INFIXOP2 { $1 } | INFIXOP3 { $1 } | INFIXOP4 { $1 } | DOTOP LPAREN RPAREN { "."^ $1 ^"()" } | DOTOP LPAREN RPAREN LESSMINUS { "."^ $1 ^ "()<-" } | DOTOP LBRACKET RBRACKET { "."^ $1 ^"[]" } | DOTOP LBRACKET RBRACKET LESSMINUS { "."^ $1 ^ "[]<-" } | DOTOP LBRACE RBRACE { "."^ $1 ^"{}" } | DOTOP LBRACE RBRACE LESSMINUS { "."^ $1 ^ "{}<-" } | HASHOP { $1 } | BANG { "!" } | PLUS { "+" } | PLUSDOT { "+." } | MINUS { "-" } | MINUSDOT { "-." } | STAR { "*" } | EQUAL { "=" } | LESS { "<" } | GREATER { ">" } | OR { "or" } | BARBAR { "||" } | AMPERSAND { "&" } | AMPERAMPER { "&&" } | COLONEQUAL { ":=" } | PLUSEQ { "+=" } | PERCENT { "%" } ; constr_ident: UIDENT { $1 } | LBRACKET RBRACKET { "[]" } | LPAREN RPAREN { "()" } | LPAREN COLONCOLON RPAREN { "::" } | FALSE { "false" } | TRUE { "true" } ; val_longident: val_ident { Lident $1 } | mod_longident DOT val_ident { Ldot($1, $3) } ; constr_longident: mod_longident %prec below_DOT { $1 } | mod_longident DOT LPAREN COLONCOLON RPAREN { Ldot($1,"::") } | LBRACKET RBRACKET { Lident "[]" } | LPAREN RPAREN { Lident "()" } | LPAREN COLONCOLON RPAREN { Lident "::" } | FALSE { Lident "false" } | TRUE { Lident "true" } ; label_longident: LIDENT { Lident $1 } | mod_longident DOT LIDENT { Ldot($1, $3) } ; type_longident: LIDENT { Lident $1 } | mod_ext_longident DOT LIDENT { Ldot($1, $3) } ; mod_longident: UIDENT { Lident $1 } | mod_longident DOT UIDENT { Ldot($1, $3) } ; mod_ext_longident: UIDENT { Lident $1 } | mod_ext_longident DOT UIDENT { Ldot($1, $3) } | mod_ext_longident LPAREN mod_ext_longident RPAREN { lapply $1 $3 } ; mty_longident: ident { Lident $1 } | mod_ext_longident DOT ident { Ldot($1, $3) } ; clty_longident: LIDENT { Lident $1 } | mod_ext_longident DOT LIDENT { Ldot($1, $3) } ; class_longident: LIDENT { Lident $1 } | mod_longident DOT LIDENT { Ldot($1, $3) } ; /* Toplevel directives */ toplevel_directive: HASH ident { Ptop_dir($2, Pdir_none) } | HASH ident STRING { Ptop_dir($2, Pdir_string (fst $3)) } | HASH ident INT { let (n, m) = $3 in Ptop_dir($2, Pdir_int (n ,m)) } | HASH ident val_longident { Ptop_dir($2, Pdir_ident $3) } | HASH ident mod_longident { Ptop_dir($2, Pdir_ident $3) } | HASH ident FALSE { Ptop_dir($2, Pdir_bool false) } | HASH ident TRUE { Ptop_dir($2, Pdir_bool true) } ; /* Miscellaneous */ name_tag: BACKQUOTE ident { $2 } ; rec_flag: /* empty */ { Nonrecursive } | REC { Recursive } ; nonrec_flag: /* empty */ { Recursive } | NONREC { Nonrecursive } ; direction_flag: TO { Upto } | DOWNTO { Downto } ; private_flag: /* empty */ { Public } | PRIVATE { Private } ; mutable_flag: /* empty */ { Immutable } | MUTABLE { Mutable } ; virtual_flag: /* empty */ { Concrete } | VIRTUAL { Virtual } ; private_virtual_flags: /* empty */ { Public, Concrete } | PRIVATE { Private, Concrete } | VIRTUAL { Public, Virtual } | PRIVATE VIRTUAL { Private, Virtual } | VIRTUAL PRIVATE { Private, Virtual } ; override_flag: /* empty */ { Fresh } | BANG { Override } ; opt_bar: /* empty */ { () } | BAR { () } ; opt_semi: | /* empty */ { () } | SEMI { () } ; subtractive: | MINUS { "-" } | MINUSDOT { "-." } ; additive: | PLUS { "+" } | PLUSDOT { "+." } ; /* Attributes and extensions */ single_attr_id: LIDENT { $1 } | UIDENT { $1 } | AND { "and" } | AS { "as" } | ASSERT { "assert" } | BEGIN { "begin" } | CLASS { "class" } | CONSTRAINT { "constraint" } | DO { "do" } | DONE { "done" } | DOWNTO { "downto" } | ELSE { "else" } | END { "end" } | EXCEPTION { "exception" } | EXTERNAL { "external" } | FALSE { "false" } | FOR { "for" } | FUN { "fun" } | FUNCTION { "function" } | FUNCTOR { "functor" } | IF { "if" } | IN { "in" } | INCLUDE { "include" } | INHERIT { "inherit" } | INITIALIZER { "initializer" } | LAZY { "lazy" } | LET { "let" } | MATCH { "match" } | METHOD { "method" } | MODULE { "module" } | MUTABLE { "mutable" } | NEW { "new" } | NONREC { "nonrec" } | OBJECT { "object" } | OF { "of" } | OPEN { "open" } | OR { "or" } | PRIVATE { "private" } | REC { "rec" } | SIG { "sig" } | STRUCT { "struct" } | THEN { "then" } | TO { "to" } | TRUE { "true" } | TRY { "try" } | TYPE { "type" } | VAL { "val" } | VIRTUAL { "virtual" } | WHEN { "when" } | WHILE { "while" } | WITH { "with" } /* mod/land/lor/lxor/lsl/lsr/asr are not supported for now */ ; attr_id: single_attr_id { mkloc $1 (symbol_rloc()) } | single_attr_id DOT attr_id { mkloc ($1 ^ "." ^ $3.txt) (symbol_rloc())} ; attribute: LBRACKETAT attr_id payload RBRACKET { ($2, $3) } ; post_item_attribute: LBRACKETATAT attr_id payload RBRACKET { ($2, $3) } ; floating_attribute: LBRACKETATATAT attr_id payload RBRACKET { ($2, $3) } ; post_item_attributes: /* empty */ { [] } | post_item_attribute post_item_attributes { $1 :: $2 } ; attributes: /* empty */{ [] } | attribute attributes { $1 :: $2 } ; ext_attributes: /* empty */ { None, [] } | attribute attributes { None, $1 :: $2 } | PERCENT attr_id attributes { Some $2, $3 } ; extension: LBRACKETPERCENT attr_id payload RBRACKET { ($2, $3) } ; item_extension: LBRACKETPERCENTPERCENT attr_id payload RBRACKET { ($2, $3) } ; payload: structure { PStr $1 } | COLON signature { PSig $2 } | COLON core_type { PTyp $2 } | QUESTION pattern { PPat ($2, None) } | QUESTION pattern WHEN seq_expr { PPat ($2, Some $4) } ; %%