A tool to gather statistics on common grammatical constructs, to hopefully produce helpful error messages & to rank syntactic completion
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2777 lines
66 KiB

(**************************************************************************)
(* *)
(* 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 *)
%{
%}
(* 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 LETOP
%token ANDOP
%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 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 (* function_type (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
%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
(* Entry points *)
%start<unit> implementation (* for implementation files *)
%start<unit> interface (* for interface files *)
%%
(* macros *)
%inline extra_str(symb): symb { };
%inline extra_sig(symb): symb { };
%inline extra_cstr(symb): symb { };
%inline extra_csig(symb): symb { };
%inline extra_def(symb): symb { };
%inline extra_text(symb): symb { };
%inline extra_rhs(symb): symb { };
%inline mkrhs(symb): symb { }
;
%inline text_str(symb): symb { }
%inline text_str_SEMISEMI: SEMISEMI { [] }
%inline text_sig(symb): symb { }
%inline text_sig_SEMISEMI: SEMISEMI { [] }
%inline text_def(symb): symb { }
%inline top_def(symb): symb { }
%inline text_cstr(symb): symb { [] }
%inline text_csig(symb): symb { [] }
(* Using this %inline definition means that we do not control precisely
when [mark_rhs_docs] is called, but I don't think this matters. *)
%inline mark_rhs_docs(symb): symb { }
%inline op(symb): symb { }
%inline mkloc(symb): symb { }
%inline mkexp(symb): symb { }
%inline mkpat(symb): symb { }
%inline mktyp(symb): symb { }
%inline mkstr(symb): symb { }
%inline mksig(symb): symb { }
%inline mkmod(symb): symb { }
%inline mkmty(symb): symb { }
%inline mkcty(symb): symb { }
%inline mkctf(symb): symb { }
%inline mkcf(symb): symb { }
%inline mkclass(symb): symb { }
%inline wrap_mkstr_ext(symb): symb { }
%inline wrap_mksig_ext(symb): symb { }
%inline mk_directive_arg(symb): symb { }
(* Generic definitions *)
(* [iloption(X)] recognizes either nothing or [X]. Assuming [X] produces
an OCaml list, it produces an OCaml list, too. *)
%inline iloption(X):
(* nothing *)
{ [] }
| x = X
{ [] }
(* [llist(X)] recognizes a possibly empty list of [X]s. It is left-recursive. *)
reversed_llist(X):
(* empty *)
{ [] }
| xs = reversed_llist(X) x = X
{ [] }
%inline llist(X):
xs = reversed_llist(X)
{ [] }
(* [reversed_nonempty_llist(X)] recognizes a nonempty list of [X]s, and produces
an OCaml list in reverse order -- that is, the last element in the input text
appears first in this list. Its definition is left-recursive. *)
reversed_nonempty_llist(X):
x = X
{ [] }
| xs = reversed_nonempty_llist(X) x = X
{ [] }
(* [nonempty_llist(X)] recognizes a nonempty list of [X]s, and produces an OCaml
list in direct order -- that is, the first element in the input text appears
first in this list. *)
%inline nonempty_llist(X):
xs = reversed_nonempty_llist(X)
{ [] }
(* [reversed_separated_nonempty_llist(separator, X)] recognizes a nonempty list
of [X]s, separated with [separator]s, and produces an OCaml list in reverse
order -- that is, the last element in the input text appears first in this
list. Its definition is left-recursive. *)
(* [inline_reversed_separated_nonempty_llist(separator, X)] is semantically
equivalent to [reversed_separated_nonempty_llist(separator, X)], but is
marked %inline, which means that the case of a list of length one and
the case of a list of length more than one will be distinguished at the
use site, and will give rise there to two productions. This can be used
to avoid certain conflicts. *)
%inline inline_reversed_separated_nonempty_llist(separator, X):
x = X
{ []}
| xs = reversed_separated_nonempty_llist(separator, X)
separator
x = X
{ []}
reversed_separated_nonempty_llist(separator, X):
xs = inline_reversed_separated_nonempty_llist(separator, X)
{ []}
(* [separated_nonempty_llist(separator, X)] recognizes a nonempty list of [X]s,
separated with [separator]s, and produces an OCaml list in direct order --
that is, the first element in the input text appears first in this list. *)
%inline separated_nonempty_llist(separator, X):
xs = reversed_separated_nonempty_llist(separator, X)
{ []}
%inline inline_separated_nonempty_llist(separator, X):
xs = inline_reversed_separated_nonempty_llist(separator, X)
{ []}
(* [reversed_separated_nontrivial_llist(separator, X)] recognizes a list of at
least two [X]s, separated with [separator]s, and produces an OCaml list in
reverse order -- that is, the last element in the input text appears first
in this list. Its definition is left-recursive. *)
reversed_separated_nontrivial_llist(separator, X):
xs = reversed_separated_nontrivial_llist(separator, X)
separator
x = X
{ []}
| x1 = X
separator
x2 = X
{ []}
(* [separated_nontrivial_llist(separator, X)] recognizes a list of at least
two [X]s, separated with [separator]s, and produces an OCaml list in direct
order -- that is, the first element in the input text appears first in this
list. *)
%inline separated_nontrivial_llist(separator, X):
xs = reversed_separated_nontrivial_llist(separator, X)
{ []}
(* [separated_or_terminated_nonempty_list(delimiter, X)] recognizes a nonempty
list of [X]s, separated with [delimiter]s, and optionally terminated with a
final [delimiter]. Its definition is right-recursive. *)
separated_or_terminated_nonempty_list(delimiter, X):
x = X ioption(delimiter)
{ []}
| x = X
delimiter
xs = separated_or_terminated_nonempty_list(delimiter, X)
{ []}
(* [reversed_preceded_or_separated_nonempty_llist(delimiter, X)] recognizes a
nonempty list of [X]s, separated with [delimiter]s, and optionally preceded
with a leading [delimiter]. It produces an OCaml list in reverse order. Its
definition is left-recursive. *)
reversed_preceded_or_separated_nonempty_llist(delimiter, X):
ioption(delimiter) x = X
{ []}
| xs = reversed_preceded_or_separated_nonempty_llist(delimiter, X)
delimiter
x = X
{ []}
(* [preceded_or_separated_nonempty_llist(delimiter, X)] recognizes a nonempty
list of [X]s, separated with [delimiter]s, and optionally preceded with a
leading [delimiter]. It produces an OCaml list in direct order. *)
%inline preceded_or_separated_nonempty_llist(delimiter, X):
xs = reversed_preceded_or_separated_nonempty_llist(delimiter, X)
{ []}
(* [bar_llist(X)] recognizes a nonempty list of [X]'s, separated with BARs,
with an optional leading BAR. We assume that [X] is itself parameterized
with an opening symbol, which can be [epsilon] or [BAR]. *)
(* This construction may seem needlessly complicated: one might think that
using [preceded_or_separated_nonempty_llist(BAR, X)], where [X] is *not*
itself parameterized, would be sufficient. Indeed, this simpler approach
would recognize the same language. However, the two approaches differ in
the footprint of [X]. We want the start location of [X] to include [BAR]
when present. In the future, we might consider switching to the simpler
definition, at the cost of producing slightly different locations. TODO *)
reversed_bar_llist(X):
(* An [X] without a leading BAR. *)
x = X(epsilon)
{ [] }
| (* An [X] with a leading BAR. *)
x = X(BAR)
{ [] }
| (* An initial list, followed with a BAR and an [X]. *)
xs = reversed_bar_llist(X)
x = X(BAR)
{ [] }
%inline bar_llist(X):
xs = reversed_bar_llist(X)
{ [] }
(* [xlist(A, B)] recognizes [AB*]. We assume that the semantic value for [A]
is a pair [x, b], while the semantic value for [B*] is a list [bs].
We return the pair [x, b :: bs]. *)
%inline xlist(A, B):
a = A bs = B*
{ [] }
(* [listx(delimiter, X, Y)] recognizes a nonempty list of [X]s, optionally
followed with a [Y], separated-or-terminated with [delimiter]s. The
semantic value is a pair of a list of [X]s and an optional [Y]. *)
listx(delimiter, X, Y):
| x = X ioption(delimiter)
{ [] }
| x = X delimiter y = Y delimiter?
{ [] }
| x = X
delimiter
tail = listx(delimiter, X, Y)
{ [] }
(* -------------------------------------------------------------------------- *)
(* Entry points. *)
(* An .ml file. *)
implementation:
structure EOF
{ }
;
(* An .mli file. *)
interface:
signature EOF
{ }
;
(* A toplevel phrase. *)
toplevel_phrase:
(* An expression with attributes, ended by a double semicolon. *)
extra_str(text_str(str_exp))
SEMISEMI
{ }
| (* A list of structure items, ended by a double semicolon. *)
extra_str(flatten(text_str(structure_item)*))
SEMISEMI
{ }
| (* A directive, ended by a double semicolon. *)
toplevel_directive
SEMISEMI
{ }
| (* End of input. *)
EOF
{ }
;
(* An .ml file that is read by #use. *)
use_file:
(* An optional standalone expression,
followed with a series of elements,
followed with EOF. *)
extra_def(append(
optional_use_file_standalone_expression,
flatten(use_file_element*)
))
EOF
{ }
;
(* An optional standalone expression is just an expression with attributes
(str_exp), with extra wrapping. *)
%inline optional_use_file_standalone_expression:
iloption(text_def(top_def(str_exp)))
{ [] }
;
(* An element in a #used file is one of the following:
- a double semicolon followed with an optional standalone expression;
- a structure item;
- a toplevel directive.
*)
%inline use_file_element:
preceded(SEMISEMI, optional_use_file_standalone_expression)
| text_def(top_def(structure_item))
| text_def(mark_rhs_docs(toplevel_directive))
{ }
;
parse_core_type:
core_type EOF
{ }
;
parse_expression:
seq_expr EOF
{ }
;
parse_pattern:
pattern EOF
{ }
;
(* -------------------------------------------------------------------------- *)
(* Functor arguments appear in module expressions and module types. *)
%inline functor_args:
reversed_nonempty_llist(functor_arg)
{ }
(* Produce a reversed list on purpose;
later processed using [fold_left]. *)
;
functor_arg:
(* An anonymous and untyped argument. *)
LPAREN RPAREN
{ }
| (* An argument accompanied with an explicit type. *)
LPAREN x = mkrhs(module_name) COLON mty = module_type RPAREN
{ }
;
module_name:
(* A named argument. *)
x = UIDENT
{ }
| (* An anonymous argument. *)
UNDERSCORE
{ }
;
(* -------------------------------------------------------------------------- *)
(* Module expressions. *)
(* The syntax of module expressions is not properly stratified. The cases of
functors, functor applications, and attributes interact and cause conflicts,
which are resolved by precedence declarations. This is concise but fragile.
Perhaps in the future an explicit stratification could be used. *)
module_expr:
| STRUCT attrs = attributes s = structure END
{ }
(*| STRUCT attributes structure error
{ }*)
| FUNCTOR attrs = attributes args = functor_args MINUSGREATER me = module_expr
{ }
| me = paren_module_expr
{ }
| me = module_expr attr = attribute
{ }
| mkmod(
(* A module identifier. *)
x = mkrhs(mod_longident)
{ }
| (* In a functor application, the actual argument must be parenthesized. *)
me1 = module_expr me2 = paren_module_expr
{ }
| (* Application to unit is sugar for application to an empty structure. *)
me1 = module_expr LPAREN RPAREN
{ }
| (* An extension. *)
ex = extension
{ }
)
{ }
;
(* A parenthesized module expression is a module expression that begins
and ends with parentheses. *)
paren_module_expr:
(* A module expression annotated with a module type. *)
LPAREN me = module_expr COLON mty = module_type RPAREN
{ }
(*| LPAREN module_expr COLON module_type error
{ }*)
| (* A module expression within parentheses. *)
LPAREN me = module_expr RPAREN
{ }
(*| LPAREN module_expr error
{ }*)
| (* A core language expression that produces a first-class module.
This expression can be annotated in various ways. *)
LPAREN VAL attrs = attributes e = expr_colon_package_type RPAREN
{ }
(*| LPAREN VAL attributes expr COLON error
{ }*)
(*| LPAREN VAL attributes expr COLONGREATER error
{ }*)
(*| LPAREN VAL attributes expr error
{ }*)
;
(* The various ways of annotating a core language expression that
produces a first-class module that we wish to unpack. *)
%inline expr_colon_package_type:
e = expr
{ }
| e = expr COLON ty = package_type
{ }
| e = expr COLON ty1 = package_type COLONGREATER ty2 = package_type
{ }
| e = expr COLONGREATER ty2 = package_type
{ }
;
(* A structure, which appears between STRUCT and END (among other places),
begins with an optional standalone expression, and continues with a list
of structure elements. *)
structure:
extra_str(append(
optional_structure_standalone_expression,
flatten(structure_element*)
))
{ }
;
(* An optional standalone expression is just an expression with attributes
(str_exp), with extra wrapping. *)
%inline optional_structure_standalone_expression:
items = iloption(mark_rhs_docs(text_str(str_exp)))
{ [] }
;
(* An expression with attributes, wrapped as a structure item. *)
%inline str_exp:
e = seq_expr
attrs = post_item_attributes
{ }
;
(* A structure element is one of the following:
- a double semicolon followed with an optional standalone expression;
- a structure item. *)
%inline structure_element:
append(text_str_SEMISEMI, optional_structure_standalone_expression)
| text_str(structure_item)
{ [] }
;
(* A structure item. *)
structure_item:
let_bindings(ext)
{ }
| mkstr(
item_extension post_item_attributes
{ }
| floating_attribute
{ }
)
| wrap_mkstr_ext(
primitive_declaration
{ }
| value_description
{ }
| type_declarations
{ }
| str_type_extension
{ }
| str_exception_declaration
{ }
| module_binding
{ }
| rec_module_bindings
{ }
| module_type_declaration
{ }
| open_declaration
{ }
| class_declarations
{ }
| class_type_declarations
{ }
| include_statement(module_expr)
{ }
)
{ }
;
(* A single module binding. *)
%inline module_binding:
MODULE
ext = ext attrs1 = attributes
name = mkrhs(module_name)
body = module_binding_body
attrs2 = post_item_attributes
{ }
;
(* The body (right-hand side) of a module binding. *)
module_binding_body:
EQUAL me = module_expr
{ }
| mkmod(
COLON mty = module_type EQUAL me = module_expr
{ }
| arg = functor_arg body = module_binding_body
{ }
) { }
;
(* A group of recursive module bindings. *)
%inline rec_module_bindings:
xlist(rec_module_binding, and_module_binding)
{ }
;
(* The first binding in a group of recursive module bindings. *)
%inline rec_module_binding:
MODULE
ext = ext
attrs1 = attributes
REC
name = mkrhs(module_name)
body = module_binding_body
attrs2 = post_item_attributes
{ }
;
(* The following bindings in a group of recursive module bindings. *)
%inline and_module_binding:
AND
attrs1 = attributes
name = mkrhs(module_name)
body = module_binding_body
attrs2 = post_item_attributes
{ }
;
(* -------------------------------------------------------------------------- *)
(* Shared material between structures and signatures. *)
(* An [include] statement can appear in a structure or in a signature,
which is why this definition is parameterized. *)
%inline include_statement(thing):
INCLUDE
ext = ext
attrs1 = attributes
thing = thing
attrs2 = post_item_attributes
{ }
;
(* A module type declaration. *)
module_type_declaration:
MODULE TYPE
ext = ext
attrs1 = attributes
id = mkrhs(ident)
typ = preceded(EQUAL, module_type)?
attrs2 = post_item_attributes
{ }
;
(* -------------------------------------------------------------------------- *)
(* Opens. *)
open_declaration:
OPEN
override = override_flag
ext = ext
attrs1 = attributes
me = module_expr
attrs2 = post_item_attributes
{ }
;
open_description:
OPEN
override = override_flag
ext = ext
attrs1 = attributes
id = mkrhs(mod_ext_longident)
attrs2 = post_item_attributes
{ }
;
%inline open_dot_declaration: mkrhs(mod_longident)
{ }
;
(* -------------------------------------------------------------------------- *)
(* Module types *)
module_type:
| SIG attrs = attributes s = signature END
{ }
(*| SIG attributes signature error
{ }*)
| FUNCTOR attrs = attributes args = functor_args
MINUSGREATER mty = module_type
%prec below_WITH
{ }
| MODULE TYPE OF attributes module_expr %prec below_LBRACKETAT
{ }
| LPAREN module_type RPAREN
{ }
(*| LPAREN module_type error
{ }*)
| module_type attribute
{ }
| mkmty(
mkrhs(mty_longident)
{ }
| module_type MINUSGREATER module_type
%prec below_WITH
{ }
| module_type WITH separated_nonempty_llist(AND, with_constraint)
{ }
(* | LPAREN MODULE mkrhs(mod_longident) RPAREN
{ } *)
| extension
{ }
)
{ }
;
(* A signature, which appears between SIG and END (among other places),
is a list of signature elements. *)
signature:
extra_sig(flatten(signature_element*))
{ }
;
(* A signature element is one of the following:
- a double semicolon;
- a signature item. *)
%inline signature_element:
text_sig_SEMISEMI
| text_sig(signature_item)
{ [] }
;
(* A signature item. *)
signature_item:
| item_extension post_item_attributes
{ }
| mksig(
floating_attribute
{ }
)
{ }
| wrap_mksig_ext(
value_description
{ }
| primitive_declaration
{ }
| type_declarations
{ }
| type_subst_declarations
{ }
| sig_type_extension
{ }
| sig_exception_declaration
{ }
| module_declaration
{ }
| module_alias
{ }
| module_subst
{ }
| rec_module_declarations
{ }
| module_type_declaration
{ }
| open_description
{ }
| include_statement(module_type)
{ }
| class_descriptions
{ }
| class_type_declarations
{ }
)
{ }
(* A module declaration. *)
%inline module_declaration:
MODULE
ext = ext attrs1 = attributes
name = mkrhs(module_name)
body = module_declaration_body
attrs2 = post_item_attributes
{ }
;
(* The body (right-hand side) of a module declaration. *)
module_declaration_body:
COLON mty = module_type
{ }
| mkmty(
arg = functor_arg body = module_declaration_body
{ }
)
{ }
;
(* A module alias declaration (in a signature). *)
%inline module_alias:
MODULE
ext = ext attrs1 = attributes
name = mkrhs(module_name)
EQUAL
body = module_expr_alias
attrs2 = post_item_attributes
{ }
;
%inline module_expr_alias:
id = mkrhs(mod_longident)
{ }
;
(* A module substitution (in a signature). *)
module_subst:
MODULE
ext = ext attrs1 = attributes
uid = mkrhs(UIDENT)
COLONEQUAL
body = mkrhs(mod_ext_longident)
attrs2 = post_item_attributes
{ }
(*| MODULE ext attributes mkrhs(UIDENT) COLONEQUAL error
{ }*)
;
(* A group of recursive module declarations. *)
%inline rec_module_declarations:
xlist(rec_module_declaration, and_module_declaration)
{ }
;
%inline rec_module_declaration:
MODULE
ext = ext
attrs1 = attributes
REC
name = mkrhs(module_name)
COLON
mty = module_type
attrs2 = post_item_attributes
{ }
;
%inline and_module_declaration:
AND
attrs1 = attributes
name = mkrhs(module_name)
COLON
mty = module_type
attrs2 = post_item_attributes
{ }
;
(* -------------------------------------------------------------------------- *)
(* Class declarations. *)
%inline class_declarations:
xlist(class_declaration, and_class_declaration)
{ }
;
%inline class_declaration:
CLASS
ext = ext
attrs1 = attributes
virt = virtual_flag
params = formal_class_parameters
id = mkrhs(LIDENT)
body = class_fun_binding
attrs2 = post_item_attributes
{ }
;
%inline and_class_declaration:
AND
attrs1 = attributes
virt = virtual_flag
params = formal_class_parameters
id = mkrhs(LIDENT)
body = class_fun_binding
attrs2 = post_item_attributes
{ }
;
class_fun_binding:
EQUAL class_expr
{ }
| mkclass(
COLON class_type EQUAL class_expr
{ }
| labeled_simple_pattern class_fun_binding
{ }
) { }
;
formal_class_parameters:
params = class_parameters(type_parameter)
{ }
;
(* -------------------------------------------------------------------------- *)
(* Class expressions. *)
class_expr:
class_simple_expr
{ }
| FUN attributes class_fun_def
{ }
| let_bindings(no_ext) IN class_expr
{ }
| LET OPEN override_flag attributes mkrhs(mod_longident) IN class_expr
{ }
| class_expr attribute
{ }
| mkclass(
class_simple_expr nonempty_llist(labeled_simple_expr)
{ }
| extension
{ }
) { }
;
class_simple_expr:
| LPAREN class_expr RPAREN
{ }
(*| LPAREN class_expr error
{ }*)
| mkclass(
tys = actual_class_parameters cid = mkrhs(class_longident)
{ }
(*| OBJECT attributes class_structure error
{ }*)
| LPAREN class_expr COLON class_type RPAREN
{ }
(*| LPAREN class_expr COLON class_type error
{ }*)
) { }
| OBJECT attributes class_structure END
{ }
;
class_fun_def:
mkclass(
labeled_simple_pattern MINUSGREATER e = class_expr
| labeled_simple_pattern e = class_fun_def
{ }
) { }
;
%inline class_structure:
| class_self_pattern extra_cstr(class_fields)
{ }
;
class_self_pattern:
LPAREN pattern RPAREN
{ }
| mkpat(LPAREN pattern COLON core_type RPAREN
{ })
{ }
| (* empty *)
{ }
;
%inline class_fields:
flatten(text_cstr(class_field)*)
{ }
;
class_field:
| INHERIT override_flag attributes class_expr
self = preceded(AS, mkrhs(LIDENT))?
post_item_attributes
{ }
| VAL value post_item_attributes
{ }
| METHOD method_ post_item_attributes
{ }
| CONSTRAINT attributes constrain_field post_item_attributes
{ }
| INITIALIZER attributes seq_expr post_item_attributes
{ }
| item_extension post_item_attributes
{ }
| mkcf(floating_attribute
{ })
{ }
;
value:
no_override_flag
attrs = attributes
mutable_ = virtual_with_mutable_flag
label = mkrhs(label) COLON ty = core_type
{ }
| override_flag attributes mutable_flag mkrhs(label) EQUAL seq_expr
{ }
| override_flag attributes mutable_flag mkrhs(label) type_constraint
EQUAL seq_expr
{ }
;
method_:
no_override_flag
attrs = attributes
private_ = virtual_with_private_flag
label = mkrhs(label) COLON ty = poly_type
{ }
| override_flag attributes private_flag mkrhs(label) strict_binding
{ }
| override_flag attributes private_flag mkrhs(label)
COLON poly_type EQUAL seq_expr
{ }
| override_flag attributes private_flag mkrhs(label) COLON TYPE lident_list
DOT core_type EQUAL seq_expr
{ }
;
(* Class types *)
class_type:
class_signature
{ }
| mkcty(
label = arg_label
domain = tuple_type
MINUSGREATER
codomain = class_type
{ }
) { }
;
class_signature:
mkcty(
tys = actual_class_parameters cid = mkrhs(clty_longident)
{ }
| extension
{ }
) { }
| OBJECT attributes class_sig_body END
{ }
(*| OBJECT attributes class_sig_body error
{ }*)
| class_signature attribute
{ }
| LET OPEN override_flag attributes mkrhs(mod_longident) IN class_signature
{ }
;
%inline class_parameters(parameter):
| (* empty *)
{ }
| LBRACKET params = separated_nonempty_llist(COMMA, parameter) RBRACKET
{ }
;
%inline actual_class_parameters:
tys = class_parameters(core_type)
{ }
;
%inline class_sig_body:
class_self_type extra_csig(class_sig_fields)
{ }
;
class_self_type:
LPAREN core_type RPAREN
{ }
| mktyp((* empty *) { })
{ }
;
%inline class_sig_fields:
flatten(text_csig(class_sig_field)*)
{ }
;
class_sig_field:
INHERIT attributes class_signature post_item_attributes
{ }
| VAL attributes value_type post_item_attributes
{ }
| METHOD attributes private_virtual_flags mkrhs(label) COLON poly_type
post_item_attributes
{ }
| CONSTRAINT attributes constrain_field post_item_attributes
{ }
| item_extension post_item_attributes
{ }
| mkctf(floating_attribute
{ })
{ }
;
%inline value_type:
flags = mutable_virtual_flags
label = mkrhs(label)
COLON
ty = core_type
{ }
;
%inline constrain:
core_type EQUAL core_type
{ }
;
constrain_field:
core_type EQUAL core_type
{ }
;
(* A group of class descriptions. *)
%inline class_descriptions:
xlist(class_description, and_class_description)
{ }
;
%inline class_description:
CLASS
ext = ext
attrs1 = attributes
virt = virtual_flag
params = formal_class_parameters
id = mkrhs(LIDENT)
COLON
cty = class_type
attrs2 = post_item_attributes
{ }
;
%inline and_class_description:
AND
attrs1 = attributes
virt = virtual_flag
params = formal_class_parameters
id = mkrhs(LIDENT)
COLON
cty = class_type
attrs2 = post_item_attributes
{ }
;
class_type_declarations:
xlist(class_type_declaration, and_class_type_declaration)
{ }
;
%inline class_type_declaration:
CLASS TYPE
ext = ext
attrs1 = attributes
virt = virtual_flag
params = formal_class_parameters
id = mkrhs(LIDENT)
EQUAL
csig = class_signature
attrs2 = post_item_attributes
{ }
;
%inline and_class_type_declaration:
AND
attrs1 = attributes
virt = virtual_flag
params = formal_class_parameters
id = mkrhs(LIDENT)
EQUAL
csig = class_signature
attrs2 = post_item_attributes
{ }
;
(* Core expressions *)
seq_expr:
| expr %prec below_SEMI { }
| expr SEMI { }
| mkexp(expr SEMI seq_expr
{ })
{ }
| expr SEMI PERCENT attr_id seq_expr
{ }
;
labeled_simple_pattern:
QUESTION LPAREN label_let_pattern opt_default RPAREN
{ }
| QUESTION label_var
{ }
| OPTLABEL LPAREN let_pattern opt_default RPAREN
{ }
| OPTLABEL pattern_var
{ }
| TILDE LPAREN label_let_pattern RPAREN
{ }
| TILDE label_var
{ }
| LABEL simple_pattern
{ }
| simple_pattern
{ }
;
pattern_var:
mkpat(
mkrhs(LIDENT) { }
| UNDERSCORE { }
) { }
;
%inline opt_default:
preceded(EQUAL, seq_expr)?
{ }
;
label_let_pattern:
x = label_var
{ }
| x = label_var COLON cty = core_type
{ }
;
%inline label_var:
mkrhs(LIDENT)
{ }
;
let_pattern:
pattern
{ }
| mkpat(pattern COLON core_type
{ })
{ }
;
expr:
simple_expr %prec below_HASH
{ }
| expr_attrs
{ }
| mkexp(expr_)
{ }
| let_bindings(ext) IN seq_expr
{ }
| pbop_op = mkrhs(LETOP) bindings = letop_bindings IN body = seq_expr
{ }
| expr COLONCOLON expr
{ }
| mkrhs(label) LESSMINUS expr
{ }
| simple_expr DOT mkrhs(label_longident) LESSMINUS expr
{ }
| simple_expr DOT LPAREN seq_expr RPAREN LESSMINUS expr
{ }
| simple_expr DOT LBRACKET seq_expr RBRACKET LESSMINUS expr
{ }
| simple_expr DOT LBRACE expr RBRACE LESSMINUS expr
{ }
| simple_expr DOTOP LBRACKET expr_semi_list RBRACKET LESSMINUS expr
{ }
| simple_expr DOTOP LPAREN expr_semi_list RPAREN LESSMINUS expr
{ }
| simple_expr DOTOP LBRACE expr_semi_list RBRACE LESSMINUS expr
{ }
| simple_expr DOT mod_longident DOTOP LBRACKET expr_semi_list RBRACKET
LESSMINUS expr
{ }
| simple_expr DOT mod_longident DOTOP LPAREN expr_semi_list RPAREN
LESSMINUS expr
{ }
| simple_expr DOT mod_longident DOTOP LBRACE expr_semi_list RBRACE
LESSMINUS expr
{ }
| expr attribute
{ }
| UNDERSCORE
{ }
;
%inline expr_attrs:
| LET MODULE ext_attributes mkrhs(module_name) module_binding_body IN seq_expr
{ }
| LET EXCEPTION ext_attributes let_exception_declaration IN seq_expr
{ }
| LET OPEN override_flag ext_attributes module_expr IN seq_expr
{ }
| FUNCTION ext_attributes match_cases
{ }
| FUN ext_attributes labeled_simple_pattern fun_def
{ }
| FUN ext_attributes LPAREN TYPE lident_list RPAREN fun_def
{ }
| MATCH ext_attributes seq_expr WITH match_cases
{ }
| TRY ext_attributes seq_expr WITH match_cases
{ }
(*| TRY ext_attributes seq_expr WITH error
{ }*)
| IF ext_attributes seq_expr THEN expr ELSE expr
{ }
| IF ext_attributes seq_expr THEN expr
{ }
| WHILE ext_attributes seq_expr DO seq_expr DONE
{ }
| FOR ext_attributes pattern EQUAL seq_expr direction_flag seq_expr DO
seq_expr DONE
{ }
| ASSERT ext_attributes simple_expr %prec below_HASH
{ }
| LAZY ext_attributes simple_expr %prec below_HASH
{ }
| OBJECT ext_attributes class_structure END
{ }
(*| OBJECT ext_attributes class_structure error
{ }*)
;
%inline expr_:
| simple_expr nonempty_llist(labeled_simple_expr)
{ }
| expr_comma_list %prec below_COMMA
{ }
| mkrhs(constr_longident) simple_expr %prec below_HASH
{ }
| name_tag simple_expr %prec below_HASH
{ }
| e1 = expr op = op(infix_operator) e2 = expr
{ }
| subtractive expr %prec prec_unary_minus
{ }
| additive expr %prec prec_unary_plus
{ }
;
simple_expr:
| LPAREN seq_expr RPAREN
{ }
(*| LPAREN seq_expr error
{ }*)
| LPAREN seq_expr type_constraint RPAREN
{ }
| simple_expr DOT LPAREN seq_expr RPAREN
{ }
(*| simple_expr DOT LPAREN seq_expr error
{ }*)
| simple_expr DOT LBRACKET seq_expr RBRACKET
{ }
(*| simple_expr DOT LBRACKET seq_expr error
{ }*)
| simple_expr DOTOP LBRACKET expr_semi_list RBRACKET
{ }
(*| simple_expr DOTOP LBRACKET expr_semi_list error
{ }*)
| simple_expr DOTOP LPAREN expr_semi_list RPAREN
{ }
(*| simple_expr DOTOP LPAREN expr_semi_list error
{ }*)
| simple_expr DOTOP LBRACE expr_semi_list RBRACE
{ }
(*| simple_expr DOTOP LBRACE expr error
{ }*)
| simple_expr DOT mod_longident DOTOP LBRACKET expr_semi_list RBRACKET
{ }
(*| simple_expr DOT
mod_longident DOTOP LBRACKET expr_semi_list error
{ }*)
| simple_expr DOT mod_longident DOTOP LPAREN expr_semi_list RPAREN
{ }
(*| simple_expr DOT
mod_longident DOTOP LPAREN expr_semi_list error
{ }*)
| simple_expr DOT mod_longident DOTOP LBRACE expr_semi_list RBRACE
{ }
(*| simple_expr DOT
mod_longident DOTOP LBRACE expr_semi_list error
{ }*)
| simple_expr DOT LBRACE expr RBRACE
{ }
(*| simple_expr DOT LBRACE expr error
{ }*)
| simple_expr_attrs
{ }
| mkexp(simple_expr_)
{ }
;
%inline simple_expr_attrs:
| BEGIN ext = ext attrs = attributes e = seq_expr END
{ }
| BEGIN ext_attributes END
{ }
(*| BEGIN ext_attributes seq_expr error
{ }*)
| NEW ext_attributes mkrhs(class_longident)
{ }
| LPAREN MODULE ext_attributes module_expr RPAREN
{ }
| LPAREN MODULE ext_attributes module_expr COLON package_type RPAREN
{ }
(*| LPAREN MODULE ext_attributes module_expr COLON error
{ }*)
;
%inline simple_expr_:
| mkrhs(val_longident)
{ }
| constant
{ }
| mkrhs(constr_longident) %prec prec_constant_constructor
{ }
| name_tag %prec prec_constant_constructor
{ }
| op(PREFIXOP) simple_expr
{ }
| op(BANG {"!"}) simple_expr
{ }
| LBRACELESS object_expr_content GREATERRBRACE
{ }
(*| LBRACELESS object_expr_content error
{ }*)
| LBRACELESS GREATERRBRACE
{ }
| simple_expr DOT mkrhs(label_longident)
{ }
| od=open_dot_declaration DOT LPAREN seq_expr RPAREN
{ }
| od=open_dot_declaration DOT LBRACELESS object_expr_content GREATERRBRACE
{ }
(*| mod_longident DOT LBRACELESS object_expr_content error
{ }*)
| simple_expr HASH mkrhs(label)
{ }
| simple_expr op(HASHOP) simple_expr
{ }
| extension
{ }
| od=open_dot_declaration DOT mkrhs(LPAREN RPAREN { })
{ }
(*| mod_longident DOT LPAREN seq_expr error
{ }*)
| LBRACE record_expr_content RBRACE
{ }
(*| LBRACE record_expr_content error
{ }*)
| od=open_dot_declaration DOT LBRACE record_expr_content RBRACE
{ }
(*| mod_longident DOT LBRACE record_expr_content error
{ }*)
| LBRACKETBAR expr_semi_list BARRBRACKET
{ }
(*| LBRACKETBAR expr_semi_list error
{ }*)
| LBRACKETBAR BARRBRACKET
{ }
| od=open_dot_declaration DOT LBRACKETBAR expr_semi_list BARRBRACKET
{ }
| od=open_dot_declaration DOT LBRACKETBAR BARRBRACKET
{ }
(*| mod_longident DOT
LBRACKETBAR expr_semi_list error
{ }*)
| LBRACKET expr_semi_list RBRACKET
{ }
(*| LBRACKET expr_semi_list error
{ }*)
| od=open_dot_declaration DOT LBRACKET expr_semi_list RBRACKET
{ }
| od=open_dot_declaration DOT mkrhs(LBRACKET RBRACKET { })
{ }
(*| mod_longident DOT
LBRACKET expr_semi_list error
{ }*)
| od=open_dot_declaration DOT LPAREN MODULE ext_attributes module_expr COLON
package_type RPAREN
{ }
(*| mod_longident DOT
LPAREN MODULE ext_attributes module_expr COLON error
{ }*)
;
labeled_simple_expr:
simple_expr %prec below_HASH
{ }
| LABEL simple_expr %prec below_HASH
{ }
| TILDE label = LIDENT
{ }
| QUESTION label = LIDENT
{ }
| OPTLABEL simple_expr %prec below_HASH
{ }
;
%inline lident_list:
xs = mkrhs(LIDENT)+
{ }
;
%inline let_ident:
val_ident { }
;
let_binding_body:
let_ident strict_binding
{ }
| let_ident type_constraint EQUAL seq_expr
{ }
| let_ident COLON typevar_list DOT core_type EQUAL seq_expr
(* TODO: could replace [typevar_list DOT core_type]
with [mktyp(poly(core_type))]
and simplify the semantic action? *)
{ }
| let_ident COLON TYPE lident_list DOT core_type EQUAL seq_expr
{ }
| pattern_no_exn EQUAL seq_expr
{ }
| simple_pattern_not_ident COLON core_type EQUAL seq_expr
{ }
;
(* The formal parameter EXT can be instantiated with ext or no_ext
so as to indicate whether an extension is allowed or disallowed. *)
let_bindings(EXT):
let_binding(EXT) { }
| let_bindings(EXT) and_let_binding { }
;
%inline let_binding(EXT):
LET
ext = EXT
attrs1 = attributes
rec_flag = rec_flag
body = let_binding_body
attrs2 = post_item_attributes
{ }
;
and_let_binding:
AND
attrs1 = attributes
body = let_binding_body
attrs2 = post_item_attributes
{ }
;
letop_binding_body:
pat = let_ident exp = strict_binding
{ }
| pat = simple_pattern COLON typ = core_type EQUAL exp = seq_expr
{ }
| pat = pattern_no_exn EQUAL exp = seq_expr
{ }
;
letop_bindings:
body = letop_binding_body
{ }
| bindings = letop_bindings pbop_op = mkrhs(ANDOP) body = let_binding_body
{ }
;
fun_binding:
strict_binding
{ }
| type_constraint EQUAL seq_expr
{ }
;
strict_binding:
EQUAL seq_expr
{ }
| labeled_simple_pattern fun_binding
{ }
| LPAREN TYPE lident_list RPAREN fun_binding
{ }
;
%inline match_cases:
xs = preceded_or_separated_nonempty_llist(BAR, match_case)
{ }
;
match_case:
pattern MINUSGREATER seq_expr
{ }
| pattern WHEN seq_expr MINUSGREATER seq_expr
{ }
| pattern MINUSGREATER DOT
{ }
;
fun_def:
MINUSGREATER seq_expr
{ }
| mkexp(COLON atomic_type MINUSGREATER seq_expr
{ })
{ }
(* Cf #5939: we used to accept (fun p when e0 -> e) *)
| labeled_simple_pattern fun_def
{ }
| LPAREN TYPE lident_list RPAREN fun_def
{ }
;
%inline expr_comma_list:
es = separated_nontrivial_llist(COMMA, expr)
{ }
;
record_expr_content:
eo = ioption(terminated(simple_expr, WITH))
fields = separated_or_terminated_nonempty_list(SEMI, record_expr_field)
{ }
;
%inline record_expr_field:
| label = mkrhs(label_longident)
c = type_constraint?
eo = preceded(EQUAL, expr)?
{ }
;
%inline object_expr_content:
xs = separated_or_terminated_nonempty_list(SEMI, object_expr_field)
{ }
;
%inline object_expr_field:
label = mkrhs(label)
oe = preceded(EQUAL, expr)?
{ }
;
%inline expr_semi_list:
es = separated_or_terminated_nonempty_list(SEMI, expr)
{ }
;
type_constraint:
COLON core_type { }
| COLON core_type COLONGREATER core_type { }
| COLONGREATER core_type { }
(*| COLON error { }*)
(*| COLONGREATER error { }*)
;
(* Patterns *)
(* Whereas [pattern] is an arbitrary pattern, [pattern_no_exn] is a pattern
that does not begin with the [EXCEPTION] keyword. Thus, [pattern_no_exn]
is the intersection of the context-free language [pattern] with the
regular language [^EXCEPTION .*].
Ideally, we would like to use [pattern] everywhere and check in a later
phase that EXCEPTION patterns are used only where they are allowed (there
is code in typing/typecore.ml to this end). Unfortunately, in the
definition of [let_binding_body], we cannot allow [pattern]. That would
create a shift/reduce conflict: upon seeing LET EXCEPTION ..., the parser
wouldn't know whether this is the beginning of a LET EXCEPTION construct or
the beginning of a LET construct whose pattern happens to begin with
EXCEPTION. The conflict is avoided there by using [pattern_no_exn] in the
definition of [let_binding_body].
In order to avoid duplication between the definitions of [pattern] and
[pattern_no_exn], we create a parameterized definition [pattern_(self)]
and instantiate it twice. *)
pattern:
pattern_(pattern)
{ }
| EXCEPTION ext_attributes pattern %prec prec_constr_appl
{ }
;
pattern_no_exn:
pattern_(pattern_no_exn)
{ }
;
%inline pattern_(self):
| self COLONCOLON pattern
{ }
| self attribute
{ }
| pattern_gen
{ }
| mkpat(
self AS mkrhs(val_ident)
{ }
(*| self AS error
{ }*)
| pattern_comma_list(self) %prec below_COMMA
{ }
(*| self COLONCOLON error
{ }*)
| self BAR pattern
{ }
(*| self BAR error
{ }*)
) { }
;
pattern_gen:
simple_pattern
{ }
| mkpat(
mkrhs(constr_longident) pattern %prec prec_constr_appl
{ }
| name_tag pattern %prec prec_constr_appl
{ }
) { }
| LAZY ext_attributes simple_pattern
{ }
;
simple_pattern:
mkpat(mkrhs(val_ident) %prec below_EQUAL
{ })
{ }
| simple_pattern_not_ident { }
;
simple_pattern_not_ident:
| LPAREN pattern RPAREN
{ }
| simple_delimited_pattern
{ }
| LPAREN MODULE ext_attributes mkrhs(module_name) RPAREN
{ }
| LPAREN MODULE ext_attributes mkrhs(module_name) COLON package_type RPAREN
{ }
| mkpat(simple_pattern_not_ident_)
{ }
;
%inline simple_pattern_not_ident_:
| UNDERSCORE
{ }
| signed_constant
{ }
| signed_constant DOTDOT signed_constant
{ }
| mkrhs(constr_longident)
{ }
| name_tag
{ }
| HASH mkrhs(type_longident)
{ }
| mkrhs(mod_longident) DOT simple_delimited_pattern
{ }
| mkrhs(mod_longident) DOT mkrhs(LBRACKET RBRACKET { })
{ }
| mkrhs(mod_longident) DOT mkrhs(LPAREN RPAREN { })
{ }
| mkrhs(mod_longident) DOT LPAREN pattern RPAREN
{ }
(*| mod_longident DOT LPAREN pattern error
{ }*)
(*| mod_longident DOT LPAREN error
{ }*)
(*| LPAREN pattern error
{ }*)
| LPAREN pattern COLON core_type RPAREN
{ }
(*| LPAREN pattern COLON core_type error
{ }*)
(*| LPAREN pattern COLON error
{ }*)
(*| LPAREN MODULE ext_attributes module_name COLON package_type
error
{ }*)
| extension
{ }
;
simple_delimited_pattern:
mkpat(
LBRACE record_pat_content RBRACE
{ }
(*| LBRACE record_pat_content error
{ }*)
| LBRACKET pattern_semi_list RBRACKET
{ }
(*| LBRACKET pattern_semi_list error
{ }*)
| LBRACKETBAR pattern_semi_list BARRBRACKET
{ }
| LBRACKETBAR BARRBRACKET
{ }
(*| LBRACKETBAR pattern_semi_list error
{ }*)
) { }
pattern_comma_list(self):
pattern_comma_list(self) COMMA pattern { }
| self COMMA pattern { }
(*| self COMMA error { }*)
;
%inline pattern_semi_list:
ps = separated_or_terminated_nonempty_list(SEMI, pattern)
{ }
;
(* A label-pattern list is a nonempty list of label-pattern pairs, optionally
followed with an UNDERSCORE, separated-or-terminated with semicolons. *)
%inline record_pat_content:
listx(SEMI, record_pat_field, UNDERSCORE)
{ }
;
%inline record_pat_field:
label = mkrhs(label_longident)
octy = preceded(COLON, core_type)?
opat = preceded(EQUAL, pattern)?
{ }
;
(* Value descriptions *)
value_description:
VAL
ext = ext
attrs1 = attributes
id = mkrhs(val_ident)
COLON
ty = core_type
attrs2 = post_item_attributes
{ }
;
(* Primitive declarations *)
primitive_declaration:
EXTERNAL
ext = ext
attrs1 = attributes
id = mkrhs(val_ident)
COLON
ty = core_type
EQUAL
prim = raw_string+
attrs2 = post_item_attributes
{ }
;
(* Type declarations and type substitutions. *)
(* Type declarations [type t = u] and type substitutions [type t := u] are very
similar, so we view them as instances of [generic_type_declarations]. In the
case of a type declaration, the use of [nonrec_flag] means that [NONREC] may
be absent or present, whereas in the case of a type substitution, the use of
[no_nonrec_flag] means that [NONREC] must be absent. The use of [type_kind]
versus [type_subst_kind] means that in the first case, we expect an [EQUAL]
sign, whereas in the second case, we expect [COLONEQUAL]. *)
%inline type_declarations:
generic_type_declarations(nonrec_flag, type_kind)
{ }
;
%inline type_subst_declarations:
generic_type_declarations(no_nonrec_flag, type_subst_kind)
{ }
;
(* A set of type declarations or substitutions begins with a
[generic_type_declaration] and continues with a possibly empty list of
[generic_and_type_declaration]s. *)
%inline generic_type_declarations(flag, kind):
xlist(
generic_type_declaration(flag, kind),
generic_and_type_declaration(kind)
)
{ }
;
(* [generic_type_declaration] and [generic_and_type_declaration] look similar,
but are in reality different enough that it is difficult to share anything
between them. *)
generic_type_declaration(flag, kind):
TYPE
ext = ext
attrs1 = attributes
flag = flag
params = type_parameters
id = mkrhs(LIDENT)
kind_priv_manifest = kind
cstrs = constraints
attrs2 = post_item_attributes
{ }
;
%inline generic_and_type_declaration(kind):
AND
attrs1 = attributes
params = type_parameters
id = mkrhs(LIDENT)
kind_priv_manifest = kind
cstrs = constraints
attrs2 = post_item_attributes
{ }
;
%inline constraints:
llist(preceded(CONSTRAINT, constrain))
{ }
;
(* Lots of %inline expansion are required for [nonempty_type_kind] to be
LR(1). At the cost of some manual expansion, it would be possible to give a
definition that leads to a smaller grammar (after expansion) and therefore
a smaller automaton. *)
nonempty_type_kind:
| priv = inline_private_flag
ty = core_type
{ }
| oty = type_synonym
priv = inline_private_flag
cs = constructor_declarations
{ }
| oty = type_synonym
priv = inline_private_flag
DOTDOT
{ }
| oty = type_synonym
priv = inline_private_flag
LBRACE ls = label_declarations RBRACE
{ }
;
%inline type_synonym:
ioption(terminated(core_type, EQUAL))
{ }
;
type_kind:
(*empty*)
{ }
| EQUAL nonempty_type_kind
{ }
;
%inline type_subst_kind:
COLONEQUAL nonempty_type_kind
{ }
;
type_parameters:
(* empty *)
{ }
| p = type_parameter
{ }
| LPAREN ps = separated_nonempty_llist(COMMA, type_parameter) RPAREN
{ }
;
type_parameter:
type_variance type_variable { }
;
type_variable:
mktyp(
QUOTE tyvar = ident
{ }
| UNDERSCORE
{ }
) { }
;
type_variance:
(* empty *) { }
| PLUS { }
| MINUS { }
;
(* A sequence of constructor declarations is either a single BAR, which
means that the list is empty, or a nonempty BAR-separated list of
declarations, with an optional leading BAR. *)
constructor_declarations:
| BAR
{ }
| cs = bar_llist(constructor_declaration)
{ }
;
(* A constructor declaration begins with an opening symbol, which can
be either epsilon or BAR. Note that this opening symbol is included
in the footprint $sloc. *)
(* Because [constructor_declaration] and [extension_constructor_declaration]
are identical except for their semantic actions, we introduce the symbol
[generic_constructor_declaration], whose semantic action is neutral -- it
merely returns a tuple. *)
generic_constructor_declaration(opening):
opening
cid = mkrhs(constr_ident)
args_res = generalized_constructor_arguments
attrs = attributes
{ }
;
%inline constructor_declaration(opening):
d = generic_constructor_declaration(opening)
{ }
;
str_exception_declaration:
sig_exception_declaration
{ }
| EXCEPTION
ext = ext
attrs1 = attributes
id = mkrhs(constr_ident)
EQUAL
lid = mkrhs(constr_longident)
attrs2 = attributes
attrs = post_item_attributes
{ }
;
sig_exception_declaration:
EXCEPTION
ext = ext
attrs1 = attributes
id = mkrhs(constr_ident)
args_res = generalized_constructor_arguments
attrs2 = attributes
attrs = post_item_attributes
{ }
;
%inline let_exception_declaration:
mkrhs(constr_ident) generalized_constructor_arguments attributes
{ }
;
generalized_constructor_arguments:
(*empty*) { }
| OF constructor_arguments { }
| COLON constructor_arguments MINUSGREATER atomic_type %prec below_HASH
{ }
| COLON atomic_type %prec below_HASH
{ }
;
constructor_arguments:
| tys = inline_separated_nonempty_llist(STAR, atomic_type)
%prec below_HASH
{ }
| LBRACE label_declarations RBRACE
{ }
;
label_declarations:
label_declaration { }
| label_declaration_semi { }
| label_declaration_semi label_declarations { }
;
label_declaration:
mutable_flag mkrhs(label) COLON poly_type_no_attr attributes
{ }
;
label_declaration_semi:
mutable_flag mkrhs(label) COLON poly_type_no_attr attributes SEMI attributes
{ }
;
(* Type Extensions *)
%inline str_type_extension:
type_extension(extension_constructor)
{ }
;
%inline sig_type_extension:
type_extension(extension_constructor_declaration)
{ }
;
%inline type_extension(declaration):
TYPE
ext = ext
attrs1 = attributes
no_nonrec_flag
params = type_parameters
tid = mkrhs(type_longident)
PLUSEQ
priv = private_flag
cs = bar_llist(declaration)
attrs2 = post_item_attributes
{ }
;
%inline extension_constructor(opening):
extension_constructor_declaration(opening)
{ }
| extension_constructor_rebind(opening)
{ }
;
%inline extension_constructor_declaration(opening):
d = generic_constructor_declaration(opening)
{ }
;
extension_constructor_rebind(opening):
opening
cid = mkrhs(constr_ident)
EQUAL
lid = mkrhs(constr_longident)
attrs = attributes
{ }
;
(* "with" constraints (additional type equations over signature components) *)
with_constraint:
TYPE type_parameters mkrhs(label_longident) with_type_binder
core_type_no_attr constraints
{ }
(* used label_longident instead of type_longident to disallow
functor applications in type path *)
| TYPE type_parameters mkrhs(label_longident)
COLONEQUAL core_type_no_attr
{ }
| MODULE mkrhs(mod_longident) EQUAL mkrhs(mod_ext_longident)
{ }
| MODULE mkrhs(mod_longident) COLONEQUAL mkrhs(mod_ext_longident)
{ }
;
with_type_binder:
EQUAL { }
| EQUAL PRIVATE { }
;
(* Polymorphic types *)
%inline typevar:
QUOTE mkrhs(ident)
{ }
;
%inline typevar_list:
nonempty_llist(typevar)
{ [] }
;
%inline poly(X):
typevar_list DOT X
{ }
;
possibly_poly(X):
X
{ }
| mktyp(poly(X))
{ }
;
%inline poly_type:
possibly_poly(core_type)
{ }
;
%inline poly_type_no_attr:
possibly_poly(core_type_no_attr)
{ }
;
(* -------------------------------------------------------------------------- *)
(* Core language types. *)
(* A core type (core_type) is a core type without attributes (core_type_no_attr)
followed with a list of attributes. *)
core_type:
core_type_no_attr
{ }
| core_type attribute
{ }
;
(* A core type without attributes is currently defined as an alias type, but
this could change in the future if new forms of types are introduced. From
the outside, one should use core_type_no_attr. *)
%inline core_type_no_attr:
alias_type
{ }
;
(* Alias types include:
- function types (see below);
- proper alias types: 'a -> int as 'a
*)
alias_type:
function_type
{ }
| mktyp(
ty = alias_type AS QUOTE tyvar = ident
{ }
)
{ }
;
(* Function types include:
- tuple types (see below);
- proper function types: int -> int
foo: int -> int
?foo: int -> int
*)
function_type:
| ty = tuple_type
%prec MINUSGREATER
{ }
| mktyp(
label = arg_label
domain = extra_rhs(tuple_type)
MINUSGREATER
codomain = function_type
{ }
)
{ }
;
%inline arg_label:
| label = optlabel
{ }
| label = LIDENT COLON
{ }
| (* empty *)
{ }
;
(* Tuple types include:
- atomic types (see below);
- proper tuple types: int * int * int list
A proper tuple type is a star-separated list of at least two atomic types.
*)
tuple_type:
| ty = atomic_type
%prec below_HASH
{ }
| mktyp(
tys = separated_nontrivial_llist(STAR, atomic_type)
{ }
)
{ }
;
(* Atomic types are the most basic level in the syntax of types.
Atomic types include:
- types between parentheses: (int -> int)
- first-class module types: (module S)
- type variables: 'a
- applications of type constructors: int, int list, int option list
- variant types: [`A]
*)
atomic_type:
| LPAREN core_type RPAREN
{ }
| LPAREN MODULE ext_attributes package_type RPAREN
{ }
| mktyp( (* begin mktyp group *)
QUOTE ident
{ }
| UNDERSCORE
{ }
| tys = actual_type_parameters
tid = mkrhs(type_longident)
{ }
| LESS meth_list GREATER
{ }
| LESS GREATER
{ }
| tys = actual_type_parameters
HASH
cid = mkrhs(class_longident)
{ }
| LBRACKET tag_field RBRACKET
(* not row_field; see CONFLICTS *)
{ }
| LBRACKET BAR row_field_list RBRACKET
{ }
| LBRACKET row_field BAR row_field_list RBRACKET
{ }
| LBRACKETGREATER BAR? row_field_list RBRACKET
{ }
| LBRACKETGREATER RBRACKET
{ }
| LBRACKETLESS BAR? row_field_list RBRACKET
{ }
| LBRACKETLESS BAR? row_field_list GREATER name_tag_list RBRACKET
{ }
| extension
{ }
)
{ } (* end mktyp group *)
;
(* This is the syntax of the actual type parameters in an application of
a type constructor, such as int, int list, or (int, bool) Hashtbl.t.
We allow one of the following:
- zero parameters;
- one parameter:
an atomic type;
among other things, this can be an arbitrary type between parentheses;
- two or more parameters:
arbitrary types, between parentheses, separated with commas.
*)
%inline actual_type_parameters:
| (* empty *)
{ }
| ty = atomic_type
{ }
| LPAREN tys = separated_nontrivial_llist(COMMA, core_type) RPAREN
{ }
;
%inline package_type:
mktyp(module_type
{ })
{ }
;
%inline row_field_list:
separated_nonempty_llist(BAR, row_field)
{ }
;
row_field:
tag_field
{ }
| core_type
{ }
;
tag_field:
mkrhs(name_tag) OF opt_ampersand amper_type_list attributes
{ }
| mkrhs(name_tag) attributes
{ }
;
opt_ampersand:
AMPERSAND { }
| (* empty *) { }
;
%inline amper_type_list:
separated_nonempty_llist(AMPERSAND, core_type_no_attr)
{ }
;
%inline name_tag_list:
nonempty_llist(name_tag)
{ }
;
(* A method list (in an object type). *)
meth_list:
head = field_semi tail = meth_list
| head = inherit_field SEMI tail = meth_list
{ }
| head = field_semi
| head = inherit_field SEMI
{ }
| head = field
| head = inherit_field
{ }
| DOTDOT
{ }
;
%inline field:
mkrhs(label) COLON poly_type_no_attr attributes
{ }
;
%inline field_semi:
mkrhs(label) COLON poly_type_no_attr attributes SEMI attributes
{ }
;
%inline inherit_field:
ty = atomic_type
{ }
;
%inline label:
LIDENT { }
;
(* Constants *)
constant:
| INT { }
| CHAR { }
| STRING { }
| FLOAT { }
;
signed_constant:
constant { }
| MINUS INT { }
| MINUS FLOAT { }
| PLUS INT { }
| PLUS FLOAT { }
;
(* Identifiers and long identifiers *)
ident:
UIDENT { }
| LIDENT { }
;
val_ident:
LIDENT { }
| LPAREN operator RPAREN { }
(*| LPAREN operator error { }*)
(*| LPAREN error { }*)
(*| LPAREN MODULE error { }*)
;
operator:
PREFIXOP { }
| LETOP { }
| ANDOP { }
| DOTOP LPAREN index_mod RPAREN { }
| DOTOP LPAREN index_mod RPAREN LESSMINUS { }
| DOTOP LBRACKET index_mod RBRACKET { }
| DOTOP LBRACKET index_mod RBRACKET LESSMINUS { }
| DOTOP LBRACE index_mod RBRACE { }
| DOTOP LBRACE index_mod RBRACE LESSMINUS { }
| HASHOP { }
| BANG { }
| infix_operator { }
;
%inline infix_operator:
| op = INFIXOP0 { }
| op = INFIXOP1 { }
| op = INFIXOP2 { }
| op = INFIXOP3 { }
| op = INFIXOP4 { }
| PLUS { }
| PLUSDOT { }
| PLUSEQ { }
| MINUS { }
| MINUSDOT { }
| STAR { }
| PERCENT { }
| EQUAL { }
| LESS { }
| GREATER { }
| OR { }
| BARBAR { }
| AMPERSAND { }
| AMPERAMPER { }
| COLONEQUAL { }
;
index_mod:
| { }
| SEMI DOTDOT { }
;
constr_ident:
UIDENT { }
| LBRACKET RBRACKET { }
| LPAREN RPAREN { }
| LPAREN COLONCOLON RPAREN { }
| FALSE { }
| TRUE { }
;
val_longident:
val_ident { }
| mod_longident DOT val_ident { }
;
constr_longident:
mod_longident %prec below_DOT { }
| mod_longident DOT LPAREN COLONCOLON RPAREN { }
| LBRACKET RBRACKET { }
| LPAREN RPAREN { }
| LPAREN COLONCOLON RPAREN { }
| FALSE { }
| TRUE { }
;
label_longident:
LIDENT { }
| mod_longident DOT LIDENT { }
;
type_longident:
LIDENT { }
| mod_ext_longident DOT LIDENT { }
;
mod_longident:
UIDENT { }
| mod_longident DOT UIDENT { }
;
mod_ext_longident:
UIDENT { }
| mod_ext_longident DOT UIDENT { }
| mod_ext_longident LPAREN mod_ext_longident RPAREN
{ }
(*| mod_ext_longident LPAREN error
{ }*)
;
mty_longident:
ident { }
| mod_ext_longident DOT ident { }
;
clty_longident:
LIDENT { }
| mod_ext_longident DOT LIDENT { }
;
class_longident:
LIDENT { }
| mod_longident DOT LIDENT { }
;
(* Toplevel directives *)
toplevel_directive:
HASH dir = mkrhs(ident)
arg = ioption(mk_directive_arg(toplevel_directive_argument))
{ }
;
%inline toplevel_directive_argument:
| STRING { }
| INT { }
| val_longident { }
| mod_longident { }
| FALSE { }
| TRUE { }
;
(* Miscellaneous *)
(* The symbol epsilon can be used instead of an (* empty *) comment. *)
%inline epsilon:
(* empty *)
{ }
;
%inline raw_string:
s = STRING
{ }
;
name_tag:
BACKQUOTE ident { }
;
rec_flag:
(* empty *) { }
| REC { }
;
%inline nonrec_flag:
(* empty *) { }
| NONREC { }
;
%inline no_nonrec_flag:
(* empty *) { }
| NONREC { }
;
direction_flag:
TO { }
| DOWNTO { }
;
private_flag:
inline_private_flag
{ }
;
%inline inline_private_flag:
(* empty *) { }
| PRIVATE { }
;
mutable_flag:
(* empty *) { }
| MUTABLE { }
;
virtual_flag:
(* empty *) { }
| VIRTUAL { }
;
mutable_virtual_flags:
(* empty *)
{ }
| MUTABLE
{ }
| VIRTUAL
{ }
| MUTABLE VIRTUAL
| VIRTUAL MUTABLE
{ }
;
private_virtual_flags:
(* empty *) { }
| PRIVATE { }
| VIRTUAL { }
| PRIVATE VIRTUAL { }
| VIRTUAL PRIVATE { }
;
(* This nonterminal symbol indicates the definite presence of a VIRTUAL
keyword and the possible presence of a MUTABLE keyword. *)
virtual_with_mutable_flag:
| VIRTUAL { }
| MUTABLE VIRTUAL { }
| VIRTUAL MUTABLE { }
;
(* This nonterminal symbol indicates the definite presence of a VIRTUAL
keyword and the possible presence of a PRIVATE keyword. *)
virtual_with_private_flag:
| VIRTUAL { }
| PRIVATE VIRTUAL { }
| VIRTUAL PRIVATE { }
;
%inline no_override_flag:
(* empty *) { }
;
%inline override_flag:
(* empty *) { }
| BANG { }
;
subtractive:
| MINUS { }
| MINUSDOT { }
;
additive:
| PLUS { }
| PLUSDOT { }
;
optlabel:
| OPTLABEL { }
| QUESTION LIDENT COLON { }
;
(* Attributes and extensions *)
single_attr_id:
LIDENT { }
| UIDENT { }
| AND { }
| AS { }
| ASSERT { }
| BEGIN { }
| CLASS { }
| CONSTRAINT { }
| DO { }
| DONE { }
| DOWNTO { }
| ELSE { }
| END { }
| EXCEPTION { }
| EXTERNAL { }
| FALSE { }
| FOR { }
| FUN { }
| FUNCTION { }
| FUNCTOR { }
| IF { }
| IN { }
| INCLUDE { }
| INHERIT { }
| INITIALIZER { }
| LAZY { }
| LET { }
| MATCH { }
| METHOD { }
| MODULE { }
| MUTABLE { }
| NEW { }
| NONREC { }
| OBJECT { }
| OF { }
| OPEN { }
| OR { }
| PRIVATE { }
| REC { }
| SIG { }
| STRUCT { }
| THEN { }
| TO { }
| TRUE { }
| TRY { }
| TYPE { }
| VAL { }
| VIRTUAL { }
| WHEN { }
| WHILE { }
| WITH { }
(* mod/land/lor/lxor/lsl/lsr/asr are not supported for now *)
;
attr_id:
mkloc(
single_attr_id { }
| single_attr_id DOT attr_id { }
) { }
;
attribute:
LBRACKETAT attr_id payload RBRACKET
{ }
;
post_item_attribute:
LBRACKETATAT attr_id payload RBRACKET
{ }
;
floating_attribute:
LBRACKETATATAT attr_id payload RBRACKET
{ }
;
%inline post_item_attributes:
post_item_attribute*
{ }
;
%inline attributes:
attribute*
{ }
;
ext:
| (* empty *) { }
| PERCENT attr_id { }
;
%inline no_ext:
| (* empty *) { }
| PERCENT attr_id { }
;
%inline ext_attributes:
ext attributes { }
;
extension:
LBRACKETPERCENT attr_id payload RBRACKET { }
;
item_extension:
LBRACKETPERCENTPERCENT attr_id payload RBRACKET { }
;
payload:
structure { }
| COLON signature { }
| COLON core_type { }
| QUESTION pattern { }
| QUESTION pattern WHEN seq_expr { }
;
%%