1078 lines
30 KiB
OCaml
1078 lines
30 KiB
OCaml
![]() |
%{
|
||
|
(* START HEADER *)
|
||
|
|
||
|
[@@@warning "-42"]
|
||
|
|
||
|
open Region
|
||
|
module AST = Parser_ligodity.AST
|
||
|
open AST
|
||
|
|
||
|
|
||
|
type 'a sequence_elements = {
|
||
|
s_elts : ('a, semi) Utils.nsepseq;
|
||
|
s_terminator : semi option
|
||
|
}
|
||
|
|
||
|
type 'a record_elements = {
|
||
|
r_elts : (field_assign reg, semi) Utils.nsepseq;
|
||
|
r_terminator : semi option
|
||
|
}
|
||
|
|
||
|
type 'a sequence_or_record =
|
||
|
PaSequence of 'a sequence_elements
|
||
|
| PaRecord of 'a record_elements
|
||
|
| PaSingleExpr of expr
|
||
|
|
||
|
(* END HEADER *)
|
||
|
%}
|
||
|
|
||
|
(* See [ParToken.mly] for the definition of tokens. *)
|
||
|
|
||
|
(* Entry points *)
|
||
|
|
||
|
%start contract interactive_expr
|
||
|
%type <AST.t> contract
|
||
|
%type <AST.expr> interactive_expr
|
||
|
|
||
|
|
||
|
%nonassoc Ident
|
||
|
%nonassoc COLON (* Solves a shift/reduce problem that happens with record
|
||
|
and sequences. To elaborate:
|
||
|
- sequence_or_record_in can be reduced to
|
||
|
expr -> Ident, but also to
|
||
|
field_assignment -> Ident.
|
||
|
*)
|
||
|
%%
|
||
|
|
||
|
(* RULES *)
|
||
|
|
||
|
(* The rule [sep_or_term(item,sep)] ("separated or terminated list")
|
||
|
parses a non-empty list of items separated by [sep], and optionally
|
||
|
terminated by [sep]. *)
|
||
|
|
||
|
sep_or_term_list(item,sep):
|
||
|
nsepseq(item,sep) {
|
||
|
$1, None
|
||
|
}
|
||
|
| nseq(item sep {$1,$2}) {
|
||
|
let (first,sep), tail = $1 in
|
||
|
let rec trans (seq, prev_sep as acc) = function
|
||
|
[] -> acc
|
||
|
| (item,next_sep)::others ->
|
||
|
trans ((prev_sep,item)::seq, next_sep) others in
|
||
|
let list, term = trans ([],sep) tail
|
||
|
in (first, List.rev list), Some term }
|
||
|
|
||
|
(* Compound constructs *)
|
||
|
|
||
|
par(X):
|
||
|
LPAR X RPAR {
|
||
|
let region = cover $1 $3
|
||
|
and value = {
|
||
|
lpar = $1;
|
||
|
inside = $2;
|
||
|
rpar = $3}
|
||
|
in {region; value}
|
||
|
}
|
||
|
|
||
|
braces(X):
|
||
|
LBRACE X RBRACE {
|
||
|
let region = cover $1 $3
|
||
|
and value = {
|
||
|
lpar = $1;
|
||
|
inside = $2;
|
||
|
rpar = $3}
|
||
|
in {region; value}
|
||
|
}
|
||
|
|
||
|
|
||
|
(* Sequences
|
||
|
|
||
|
Series of instances of the same syntactical category have often to
|
||
|
be parsed, like lists of expressions, patterns etc. The simplest of
|
||
|
all is the possibly empty sequence (series), parsed below by
|
||
|
[seq]. The non-empty sequence is parsed by [nseq]. Note that the
|
||
|
latter returns a pair made of the first parsed item (the parameter
|
||
|
[X]) and the rest of the sequence (possibly empty). This way, the
|
||
|
OCaml typechecker can keep track of this information along the
|
||
|
static control-flow graph. The rule [sepseq] parses possibly empty
|
||
|
sequences of items separated by some token (e.g., a comma), and
|
||
|
rule [nsepseq] is for non-empty such sequences. See module [Utils]
|
||
|
for the types corresponding to the semantic actions of those
|
||
|
rules.
|
||
|
*)
|
||
|
|
||
|
(* Possibly empty sequence of items *)
|
||
|
|
||
|
seq(item):
|
||
|
(**) { [] }
|
||
|
| item seq(item) { $1::$2 }
|
||
|
|
||
|
(* Non-empty sequence of items *)
|
||
|
|
||
|
nseq(item):
|
||
|
item seq(item) { $1,$2 }
|
||
|
|
||
|
(* Non-empty separated sequence of items *)
|
||
|
|
||
|
nsepseq(item,sep):
|
||
|
item { $1, [] }
|
||
|
| item sep nsepseq(item,sep) { let h,t = $3 in $1, ($2,h)::t }
|
||
|
|
||
|
(* Possibly empy separated sequence of items *)
|
||
|
|
||
|
sepseq(item,sep):
|
||
|
(**) { None }
|
||
|
| nsepseq(item,sep) { Some $1 }
|
||
|
|
||
|
(* Helpers *)
|
||
|
|
||
|
%inline type_name : Ident { $1 }
|
||
|
%inline field_name : Ident { $1 }
|
||
|
%inline module_name : Constr { $1 }
|
||
|
%inline struct_name : Ident { $1 }
|
||
|
|
||
|
(* Non-empty comma-separated values (at least two values) *)
|
||
|
|
||
|
tuple(item):
|
||
|
item COMMA nsepseq(item,COMMA) {
|
||
|
let h,t = $3 in $1,($2,h)::t
|
||
|
}
|
||
|
|
||
|
(* Possibly empty semicolon-separated values between brackets *)
|
||
|
|
||
|
list(item):
|
||
|
LBRACKET sep_or_term_list(item, COMMA) RBRACKET {
|
||
|
let elements, terminator = $2 in
|
||
|
{ value =
|
||
|
{
|
||
|
compound = Brackets ($1,$3);
|
||
|
elements = Some elements;
|
||
|
terminator;
|
||
|
};
|
||
|
region = cover $1 $3
|
||
|
}
|
||
|
}
|
||
|
| LBRACKET RBRACKET {
|
||
|
let value = {
|
||
|
compound = Brackets ($1,$2);
|
||
|
elements = None;
|
||
|
terminator = None} in
|
||
|
let region = cover $1 $2
|
||
|
in {value; region}
|
||
|
}
|
||
|
|
||
|
(* Main *)
|
||
|
|
||
|
contract:
|
||
|
declarations EOF {
|
||
|
{decl = $1; eof=$2} }
|
||
|
|
||
|
declarations:
|
||
|
declaration { $1,[] : AST.declaration Utils.nseq }
|
||
|
| declaration declarations { Utils.nseq_cons $1 $2 }
|
||
|
|
||
|
declaration:
|
||
|
| type_decl SEMI { TypeDecl $1 }
|
||
|
| let_declaration SEMI { Let $1 }
|
||
|
|
||
|
(* Type declarations *)
|
||
|
|
||
|
type_decl:
|
||
|
Type type_name EQ type_expr {
|
||
|
let region = cover $1 (type_expr_to_region $4) in
|
||
|
let value = {
|
||
|
kwd_type = $1;
|
||
|
name = $2;
|
||
|
eq = $3;
|
||
|
type_expr = $4;
|
||
|
}
|
||
|
in {region; value}
|
||
|
}
|
||
|
|
||
|
type_expr:
|
||
|
cartesian { $1 }
|
||
|
| sum_type { TSum $1 }
|
||
|
| record_type { TRecord $1 }
|
||
|
|
||
|
cartesian:
|
||
|
fun_type COMMA nsepseq(fun_type,COMMA) {
|
||
|
let value = Utils.nsepseq_cons $1 $2 $3 in
|
||
|
let region = nsepseq_to_region type_expr_to_region value
|
||
|
in TProd {region; value}
|
||
|
}
|
||
|
| fun_type { ($1 : type_expr) }
|
||
|
|
||
|
fun_type:
|
||
|
core_type {
|
||
|
$1
|
||
|
}
|
||
|
| core_type ARROW fun_type {
|
||
|
let region = cover (type_expr_to_region $1) (type_expr_to_region $3) in
|
||
|
TFun {region; value = ($1, $2, $3)}
|
||
|
}
|
||
|
|
||
|
core_type:
|
||
|
type_name {
|
||
|
TVar $1
|
||
|
}
|
||
|
| module_name DOT type_name {
|
||
|
let module_name = $1.value in
|
||
|
let type_name = $3.value in
|
||
|
let value = module_name ^ "." ^ type_name in
|
||
|
let region = cover $1.region $3.region
|
||
|
in
|
||
|
TVar {region; value}
|
||
|
}
|
||
|
| type_constr LPAR nsepseq(core_type, COMMA) RPAR {
|
||
|
let arg_val = $3 in
|
||
|
let constr = $1 in
|
||
|
let start = $1.region in
|
||
|
let stop = $4 in
|
||
|
let region = cover start stop in
|
||
|
let lpar, rpar = $2, $4 in
|
||
|
TApp Region.{value = constr, {
|
||
|
value = {
|
||
|
lpar;
|
||
|
rpar;
|
||
|
inside = arg_val
|
||
|
};
|
||
|
region = cover lpar rpar;
|
||
|
}; region}
|
||
|
}
|
||
|
| par (type_expr) {
|
||
|
TPar $1
|
||
|
}
|
||
|
|
||
|
type_constr:
|
||
|
type_name { $1 }
|
||
|
|
||
|
sum_type:
|
||
|
VBAR nsepseq(variant,VBAR) {
|
||
|
let region = nsepseq_to_region (fun x -> x.region) $2
|
||
|
in {region; value = $2}
|
||
|
}
|
||
|
|
||
|
variant:
|
||
|
Constr LPAR cartesian RPAR {
|
||
|
let region = cover $1.region $4
|
||
|
and value = {constr = $1; arg = Some ($2, $3)}
|
||
|
in {region; value}
|
||
|
}
|
||
|
| Constr {
|
||
|
{region=$1.region; value= {constr=$1; arg=None}} }
|
||
|
|
||
|
record_type:
|
||
|
LBRACE sep_or_term_list(field_decl,COMMA) RBRACE {
|
||
|
let ne_elements, terminator = $2 in
|
||
|
let region = cover $1 $3
|
||
|
and value = {
|
||
|
compound = Braces ($1,$3);
|
||
|
ne_elements;
|
||
|
terminator;
|
||
|
}
|
||
|
in {region; value}
|
||
|
}
|
||
|
|
||
|
type_expr_field:
|
||
|
core_type { $1 }
|
||
|
| sum_type { TSum $1 }
|
||
|
| record_type { TRecord $1 }
|
||
|
|
||
|
field_decl:
|
||
|
field_name {
|
||
|
let value = {field_name = $1; colon = Region.ghost; field_type = TVar $1}
|
||
|
in {region = $1.region; value}
|
||
|
}
|
||
|
| field_name COLON type_expr_field {
|
||
|
let stop = type_expr_to_region $3 in
|
||
|
let region = cover $1.region stop
|
||
|
and value = {field_name = $1; colon = $2; field_type = $3}
|
||
|
in {region; value}
|
||
|
}
|
||
|
|
||
|
(* Top-level non-recursive definitions *)
|
||
|
|
||
|
let_declaration:
|
||
|
Let let_binding {
|
||
|
let kwd_let = $1 in
|
||
|
let binding, (region: Region.region) = $2 in
|
||
|
{value = kwd_let, binding; region}
|
||
|
}
|
||
|
|
||
|
es6_func:
|
||
|
ARROW expr {
|
||
|
$1, $2
|
||
|
}
|
||
|
|
||
|
let_binding:
|
||
|
| Ident type_annotation? EQ expr {
|
||
|
let pattern = PVar $1 in
|
||
|
let start = pattern_to_region pattern in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover start stop in
|
||
|
({binders = pattern, []; lhs_type=$2; eq=$3; let_rhs=$4}, region)
|
||
|
}
|
||
|
| tuple(sub_irrefutable) type_annotation? EQ expr {
|
||
|
let h, t = $1 in
|
||
|
let start = pattern_to_region h in
|
||
|
let stop = last (fun (region, _) -> region) t in
|
||
|
let region = cover start stop in
|
||
|
let pattern = PTuple { value = $1; region } in
|
||
|
let start = region in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover start stop in
|
||
|
({binders = pattern, []; lhs_type=$2; eq=$3; let_rhs=$4}, region)
|
||
|
}
|
||
|
| WILD type_annotation? EQ expr {
|
||
|
let pattern = PWild $1 in
|
||
|
let start = pattern_to_region pattern in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover start stop in
|
||
|
({binders = pattern, []; lhs_type=$2; eq=$3; let_rhs=$4}, region)
|
||
|
}
|
||
|
| unit type_annotation? EQ expr {
|
||
|
let pattern = PUnit $1 in
|
||
|
let start = pattern_to_region pattern in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover start stop in
|
||
|
({binders = pattern, []; lhs_type=$2; eq=$3; let_rhs=$4}, region)
|
||
|
}
|
||
|
| record_pattern type_annotation? EQ expr {
|
||
|
let pattern = PRecord $1 in
|
||
|
let start = pattern_to_region pattern in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover start stop in
|
||
|
({binders = pattern, []; lhs_type=$2; eq=$3; let_rhs=$4}, region)
|
||
|
}
|
||
|
| par(closed_irrefutable) type_annotation? EQ expr {
|
||
|
let pattern = PPar $1 in
|
||
|
let start = pattern_to_region pattern in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover start stop in
|
||
|
({binders = pattern, []; lhs_type=$2; eq=$3; let_rhs=$4}, region)
|
||
|
}
|
||
|
|
||
|
type_annotation:
|
||
|
COLON type_expr { $1,$2 }
|
||
|
|
||
|
(* Patterns *)
|
||
|
|
||
|
irrefutable:
|
||
|
tuple(sub_irrefutable) {
|
||
|
let h, t = $1 in
|
||
|
let start = pattern_to_region h in
|
||
|
let stop = last (fun (region, _) -> region) t in
|
||
|
let region = cover start stop in
|
||
|
PTuple { value = $1; region }
|
||
|
}
|
||
|
| sub_irrefutable { $1 }
|
||
|
|
||
|
sub_irrefutable:
|
||
|
Ident { PVar $1 }
|
||
|
| WILD { PWild $1 }
|
||
|
| unit { PUnit $1 }
|
||
|
| record_pattern { PRecord $1 }
|
||
|
| par(closed_irrefutable) { PPar $1 }
|
||
|
|
||
|
closed_irrefutable:
|
||
|
irrefutable { $1 }
|
||
|
| constr_pattern { PConstr $1 }
|
||
|
| typed_pattern { PTyped $1 }
|
||
|
|
||
|
typed_pattern:
|
||
|
irrefutable COLON type_expr {
|
||
|
let start = pattern_to_region $1 in
|
||
|
let stop = type_expr_to_region $3 in
|
||
|
let region = cover start stop in
|
||
|
{
|
||
|
value = {
|
||
|
pattern = $1;
|
||
|
colon = $2;
|
||
|
type_expr = $3
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pattern:
|
||
|
LBRACKET sub_pattern COMMA DOTDOTDOT sub_pattern RBRACKET {
|
||
|
let start = pattern_to_region $2 in
|
||
|
let stop = pattern_to_region $5 in
|
||
|
let region = cover start stop in
|
||
|
let val_ = {value = $2, $3, $5; region} in
|
||
|
PList (PCons val_)
|
||
|
}
|
||
|
| tuple(sub_pattern) {
|
||
|
let h, t = $1 in
|
||
|
let start = pattern_to_region h in
|
||
|
let stop = last (fun (region, _) -> region) t in
|
||
|
let region = cover start stop in
|
||
|
PTuple { value = $1; region }
|
||
|
}
|
||
|
| core_pattern { $1 }
|
||
|
|
||
|
sub_pattern:
|
||
|
par(sub_pattern) { PPar $1 }
|
||
|
| core_pattern { $1 }
|
||
|
|
||
|
core_pattern:
|
||
|
Ident { PVar $1 }
|
||
|
| WILD { PWild $1 }
|
||
|
| unit { PUnit $1 }
|
||
|
| Int { PInt $1 }
|
||
|
| True { PTrue $1 }
|
||
|
| False { PFalse $1 }
|
||
|
| Str { PString $1 }
|
||
|
| par(ptuple) { PPar $1 }
|
||
|
| list(sub_pattern) { PList (PListComp $1) }
|
||
|
| constr_pattern { PConstr $1 }
|
||
|
| record_pattern { PRecord $1 }
|
||
|
|
||
|
record_pattern:
|
||
|
LBRACE sep_or_term_list(field_pattern,COMMA) RBRACE {
|
||
|
let ne_elements, terminator = $2 in
|
||
|
let region = cover $1 $3 in
|
||
|
let value = {
|
||
|
compound = Braces ($1,$3);
|
||
|
ne_elements;
|
||
|
terminator;
|
||
|
}
|
||
|
in
|
||
|
{region; value}
|
||
|
}
|
||
|
|
||
|
field_pattern:
|
||
|
field_name EQ sub_pattern {
|
||
|
let start = $1.region in
|
||
|
let stop = pattern_to_region $3 in
|
||
|
let region = cover start stop in
|
||
|
{ value = {field_name=$1; eq=$2; pattern=$3}; region }
|
||
|
}
|
||
|
|
||
|
constr_pattern:
|
||
|
C_None { PNone $1 }
|
||
|
| C_Some sub_pattern {
|
||
|
let stop = pattern_to_region $2 in
|
||
|
let region = cover $1 stop
|
||
|
and value = $1, $2
|
||
|
in PSomeApp {value; region}
|
||
|
}
|
||
|
| Constr {
|
||
|
PConstrApp { value = $1, None; region = $1.region } }
|
||
|
| Constr sub_pattern {
|
||
|
let region = cover $1.region (pattern_to_region $2) in
|
||
|
PConstrApp { value = $1, Some $2; region }
|
||
|
}
|
||
|
|
||
|
|
||
|
ptuple:
|
||
|
tuple(sub_pattern) {
|
||
|
let h, t = $1 in
|
||
|
let start = pattern_to_region h in
|
||
|
let stop = last (fun (region, _) -> region) t in
|
||
|
let region = cover start stop in
|
||
|
PTuple { value = $1; region }
|
||
|
}
|
||
|
|
||
|
unit:
|
||
|
LPAR RPAR {
|
||
|
let the_unit = ghost, ghost in
|
||
|
let region = cover $1 $2 in
|
||
|
{ value = the_unit; region }
|
||
|
}
|
||
|
|
||
|
(* Expressions *)
|
||
|
|
||
|
interactive_expr:
|
||
|
expr EOF { $1 }
|
||
|
|
||
|
expr:
|
||
|
base_cond__open(expr) { $1 }
|
||
|
| switch_expr(base_cond) { ECase $1 }
|
||
|
|
||
|
|
||
|
base_cond__open(x):
|
||
|
base_expr(x)
|
||
|
| conditional(x) { $1 }
|
||
|
|
||
|
base_cond:
|
||
|
base_cond__open(base_cond) { $1 }
|
||
|
|
||
|
type_expr_simple_args:
|
||
|
LPAR nsepseq(type_expr_simple, COMMA) RPAR {
|
||
|
$1, $2, $3
|
||
|
}
|
||
|
|
||
|
type_expr_simple:
|
||
|
core_expr_2 type_expr_simple_args? {
|
||
|
let args = $2 in
|
||
|
let constr = match $1 with
|
||
|
| EVar i -> i
|
||
|
| EProj {value = {struct_name; field_path; _}; region} ->
|
||
|
let path =
|
||
|
(Utils.nsepseq_foldl
|
||
|
(fun a e ->
|
||
|
match e with
|
||
|
| FieldName v -> a ^ "." ^ v.value
|
||
|
| Component {value = c, _; _} -> a ^ "." ^ c
|
||
|
)
|
||
|
struct_name.value
|
||
|
field_path
|
||
|
)
|
||
|
in
|
||
|
{value = path; region }
|
||
|
| EArith (Mutez {value = s, _; region })
|
||
|
| EArith (Int {value = s, _; region })
|
||
|
| EArith (Nat {value = s, _; region }) -> { value = s; region }
|
||
|
| EString (StrLit {value = s; region}) -> { value = s; region }
|
||
|
| ELogic (BoolExpr (True t)) -> { value = "true"; region = t }
|
||
|
| ELogic (BoolExpr (False f)) -> { value = "false"; region = f }
|
||
|
| _ -> failwith "Not supported"
|
||
|
in
|
||
|
match args with
|
||
|
Some (lpar, args, rpar) -> (
|
||
|
let start = expr_to_region $1 in
|
||
|
let stop = rpar in
|
||
|
let region = cover start stop in
|
||
|
TApp {
|
||
|
value = constr, {
|
||
|
value = {
|
||
|
inside = args;
|
||
|
lpar;
|
||
|
rpar
|
||
|
};
|
||
|
region};
|
||
|
region}
|
||
|
)
|
||
|
| None -> TVar constr
|
||
|
}
|
||
|
| LPAR nsepseq(type_expr_simple, COMMA) RPAR {
|
||
|
TProd {value = $2; region = cover $1 $3}
|
||
|
}
|
||
|
| LPAR type_expr_simple ARROW type_expr_simple RPAR {
|
||
|
TFun {value = $2, $3, $4; region = cover $1 $5}
|
||
|
}
|
||
|
|
||
|
type_annotation_simple:
|
||
|
COLON type_expr_simple { $2 }
|
||
|
|
||
|
fun_expr:
|
||
|
disj_expr_level es6_func {
|
||
|
let arrow, body = $2 in
|
||
|
let kwd_fun = Region.ghost in
|
||
|
let start = expr_to_region $1 in
|
||
|
let stop = expr_to_region body in
|
||
|
let region = cover start stop in
|
||
|
let rec arg_to_pattern = (function
|
||
|
| EVar val_ -> PVar val_
|
||
|
| EAnnot {value = (EVar v, typ); region} ->
|
||
|
PTyped {value = {
|
||
|
pattern = PVar v;
|
||
|
colon = Region.ghost;
|
||
|
type_expr = typ;
|
||
|
} ; region}
|
||
|
| EPar {value = {inside; lpar; rpar}; region} ->
|
||
|
PPar {value = {inside = arg_to_pattern inside; lpar; rpar}; region}
|
||
|
| EUnit u -> PUnit u
|
||
|
| _ -> failwith "Not supported"
|
||
|
)
|
||
|
in
|
||
|
let fun_args_to_pattern = (function
|
||
|
| EAnnot {value = (ETuple {value = fun_args; _}, _); _} -> (* ((foo:x, bar) : type) *)
|
||
|
let bindings = List.map (fun arg -> arg_to_pattern (snd arg)) (snd fun_args) in
|
||
|
(arg_to_pattern (fst fun_args), bindings)
|
||
|
| EAnnot {value = (EPar {value = {inside = fun_arg ; _}; _}, _); _} -> (* ((foo:x, bar) : type) *)
|
||
|
(arg_to_pattern fun_arg, [])
|
||
|
| EPar {value = {inside = fun_arg; _ }; _} ->
|
||
|
(arg_to_pattern fun_arg, [])
|
||
|
| EAnnot e -> (arg_to_pattern (EAnnot e), [])
|
||
|
| ETuple {value = fun_args; _} ->
|
||
|
let bindings = List.map (fun arg -> arg_to_pattern (snd arg)) (snd fun_args) in
|
||
|
(arg_to_pattern (fst fun_args), bindings)
|
||
|
| EUnit e ->
|
||
|
(arg_to_pattern (EUnit e), [])
|
||
|
| _ -> failwith "Not supported"
|
||
|
)
|
||
|
in
|
||
|
let binders = fun_args_to_pattern $1 in
|
||
|
let f = {
|
||
|
kwd_fun ;
|
||
|
binders ;
|
||
|
lhs_type = None;
|
||
|
arrow ;
|
||
|
body ;
|
||
|
} in
|
||
|
EFun { region; value=f }
|
||
|
}
|
||
|
|
||
|
base_expr(right_expr):
|
||
|
let_expr(right_expr)
|
||
|
| disj_expr_level { $1 }
|
||
|
| fun_expr { $1 }
|
||
|
|
||
|
conditional(right_expr):
|
||
|
if_then_else(right_expr)
|
||
|
| if_then(right_expr) { ECond $1 }
|
||
|
|
||
|
parenthesized_expr:
|
||
|
braces (expr) { $1.value.inside }
|
||
|
| par (expr) { $1.value.inside }
|
||
|
|
||
|
if_then(right_expr):
|
||
|
If parenthesized_expr LBRACE closed_if RBRACE {
|
||
|
let the_unit = ghost, ghost in
|
||
|
let ifnot = EUnit {region=ghost; value=the_unit} in
|
||
|
let region = cover $1 $5 in
|
||
|
{
|
||
|
value = {
|
||
|
kwd_if = $1;
|
||
|
test = $2;
|
||
|
kwd_then = $3;
|
||
|
ifso = $4;
|
||
|
kwd_else = Region.ghost;
|
||
|
ifnot;
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if_then_else(right_expr):
|
||
|
If parenthesized_expr LBRACE closed_if SEMI RBRACE Else LBRACE right_expr SEMI RBRACE {
|
||
|
let region = cover $1 $11 in
|
||
|
{
|
||
|
value = {
|
||
|
kwd_if = $1;
|
||
|
test = $2;
|
||
|
kwd_then = $3;
|
||
|
ifso = $4;
|
||
|
kwd_else = $6;
|
||
|
ifnot = $9
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
|
||
|
base_if_then_else__open(x):
|
||
|
base_expr(x) { $1 }
|
||
|
| if_then_else(x) { ECond $1 }
|
||
|
|
||
|
base_if_then_else:
|
||
|
base_if_then_else__open(base_if_then_else) { $1 }
|
||
|
|
||
|
closed_if:
|
||
|
base_if_then_else__open(closed_if) { $1 }
|
||
|
| switch_expr(base_if_then_else) { ECase $1 }
|
||
|
|
||
|
switch_expr(right_expr):
|
||
|
Switch switch_expr_ LBRACE cases(right_expr) RBRACE {
|
||
|
let cases = $4 in
|
||
|
let start = $1 in
|
||
|
let stop = $5 in
|
||
|
let region = cover start stop in
|
||
|
{ value = {
|
||
|
kwd_match = $1;
|
||
|
expr = $2;
|
||
|
lead_vbar = None;
|
||
|
kwd_with = Region.ghost;
|
||
|
cases = {
|
||
|
value = cases;
|
||
|
region = nsepseq_to_region (fun {region; _} -> region) $4
|
||
|
};
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch_expr_:
|
||
|
| par(expr) {
|
||
|
$1.value.inside
|
||
|
}
|
||
|
| core_expr_2 {
|
||
|
$1
|
||
|
}
|
||
|
|
||
|
cases(right_expr):
|
||
|
nseq(case_clause(right_expr)) {
|
||
|
let (hd, tl) = $1 in
|
||
|
hd, (List.map (fun f -> expr_to_region f.value.rhs, f) tl)
|
||
|
}
|
||
|
|
||
|
case_clause(right_expr):
|
||
|
VBAR pattern ARROW right_expr SEMI? {
|
||
|
let region = cover (pattern_to_region $2) (expr_to_region $4) in
|
||
|
{value =
|
||
|
{
|
||
|
pattern = $2;
|
||
|
arrow = $3;
|
||
|
rhs=$4
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let_expr(right_expr):
|
||
|
Let let_binding SEMI right_expr {
|
||
|
let kwd_let = $1 in
|
||
|
let (binding: let_binding), _ = $2 in
|
||
|
let kwd_in = $3 in
|
||
|
let body = $4 in
|
||
|
let stop = expr_to_region $4 in
|
||
|
let region = cover $1 stop in
|
||
|
let let_in = {kwd_let; binding; kwd_in; body}
|
||
|
in ELetIn {region; value=let_in} }
|
||
|
|
||
|
disj_expr_level:
|
||
|
disj_expr { ELogic (BoolExpr (Or $1)) }
|
||
|
| conj_expr_level { $1 }
|
||
|
| par(tuple(disj_expr_level)) type_annotation_simple? {
|
||
|
let region = $1.region in
|
||
|
let tuple = ETuple {value=$1.value.inside; region} in
|
||
|
let region = match $2 with
|
||
|
| Some s -> cover $1.region (type_expr_to_region s)
|
||
|
| None -> region
|
||
|
in
|
||
|
match $2 with
|
||
|
| Some typ -> EAnnot({value = tuple, typ; region})
|
||
|
| None -> tuple
|
||
|
}
|
||
|
|
||
|
bin_op(arg1,op,arg2):
|
||
|
arg1 op arg2 {
|
||
|
let start = expr_to_region $1 in
|
||
|
let stop = expr_to_region $3 in
|
||
|
let region = cover start stop in
|
||
|
{ value = { arg1=$1; op=$2; arg2=$3}; region }
|
||
|
}
|
||
|
|
||
|
disj_expr:
|
||
|
bin_op(disj_expr_level, BOOL_OR, conj_expr_level)
|
||
|
| bin_op(disj_expr_level, Or, conj_expr_level) { $1 }
|
||
|
|
||
|
conj_expr_level:
|
||
|
conj_expr { ELogic (BoolExpr (And $1)) }
|
||
|
| comp_expr_level { $1 }
|
||
|
|
||
|
conj_expr:
|
||
|
bin_op(conj_expr_level, BOOL_AND, comp_expr_level) { $1 }
|
||
|
|
||
|
comp_expr_level:
|
||
|
lt_expr { ELogic (CompExpr (Lt $1)) }
|
||
|
| le_expr { ELogic (CompExpr (Leq $1)) }
|
||
|
| gt_expr { ELogic (CompExpr (Gt $1)) }
|
||
|
| ge_expr { ELogic (CompExpr (Geq $1)) }
|
||
|
| eq_expr { ELogic (CompExpr (Equal $1)) }
|
||
|
| ne_expr { ELogic (CompExpr (Neq $1)) }
|
||
|
| cat_expr_level { $1 }
|
||
|
|
||
|
lt_expr:
|
||
|
bin_op(comp_expr_level, LT, cat_expr_level) { $1 }
|
||
|
|
||
|
le_expr:
|
||
|
bin_op(comp_expr_level, LE, cat_expr_level) { $1 }
|
||
|
|
||
|
gt_expr:
|
||
|
bin_op(comp_expr_level, GT, cat_expr_level) { $1 }
|
||
|
|
||
|
ge_expr:
|
||
|
bin_op(comp_expr_level, GE, cat_expr_level) { $1 }
|
||
|
|
||
|
eq_expr:
|
||
|
bin_op(comp_expr_level, EQEQ, cat_expr_level) { $1 }
|
||
|
|
||
|
ne_expr:
|
||
|
bin_op(comp_expr_level, NE, cat_expr_level) { $1 }
|
||
|
|
||
|
cat_expr_level:
|
||
|
cat_expr { EString (Cat $1) }
|
||
|
| add_expr_level { $1 }
|
||
|
|
||
|
cat_expr:
|
||
|
bin_op(add_expr_level, CAT, add_expr_level) { $1 }
|
||
|
|
||
|
add_expr_level:
|
||
|
plus_expr { EArith (Add $1) }
|
||
|
| minus_expr { EArith (Sub $1) }
|
||
|
| mult_expr_level { $1 }
|
||
|
|
||
|
plus_expr:
|
||
|
bin_op(add_expr_level, PLUS, mult_expr_level) { $1 }
|
||
|
|
||
|
minus_expr:
|
||
|
bin_op(add_expr_level, MINUS, mult_expr_level) { $1 }
|
||
|
|
||
|
mult_expr_level:
|
||
|
times_expr { EArith (Mult $1) }
|
||
|
| div_expr { EArith (Div $1) }
|
||
|
| mod_expr { EArith (Mod $1) }
|
||
|
| unary_expr_level { $1 }
|
||
|
|
||
|
times_expr:
|
||
|
bin_op(mult_expr_level, TIMES, unary_expr_level) { $1 }
|
||
|
|
||
|
div_expr:
|
||
|
bin_op(mult_expr_level, SLASH, unary_expr_level) { $1 }
|
||
|
|
||
|
mod_expr:
|
||
|
bin_op(mult_expr_level, Mod, unary_expr_level) { $1 }
|
||
|
|
||
|
unary_expr_level:
|
||
|
MINUS call_expr_level {
|
||
|
let start = $1 in
|
||
|
let end_ = expr_to_region $2 in
|
||
|
let region = cover start end_
|
||
|
and value = {op = $1; arg = $2}
|
||
|
in EArith (Neg {region; value})
|
||
|
}
|
||
|
| NOT call_expr_level {
|
||
|
let start = $1 in
|
||
|
let end_ = expr_to_region $2 in
|
||
|
let region = cover start end_
|
||
|
and value = {op = $1; arg = $2} in
|
||
|
ELogic (BoolExpr (Not ({region; value})))
|
||
|
}
|
||
|
| call_expr_level {
|
||
|
$1
|
||
|
}
|
||
|
|
||
|
call_expr_level:
|
||
|
call_expr_level_in type_annotation_simple? {
|
||
|
let region = match $2 with
|
||
|
| Some s -> cover (expr_to_region $1) (type_expr_to_region s)
|
||
|
| None -> expr_to_region $1
|
||
|
in
|
||
|
match $2 with
|
||
|
| Some t ->
|
||
|
EAnnot { value = $1, t; region }
|
||
|
| None -> $1
|
||
|
}
|
||
|
|
||
|
call_expr_level_in:
|
||
|
call_expr { $1 }
|
||
|
| constr_expr { $1 }
|
||
|
| core_expr { $1 }
|
||
|
|
||
|
constr_expr:
|
||
|
C_None {
|
||
|
EConstr (ENone $1)
|
||
|
}
|
||
|
| C_Some core_expr {
|
||
|
let region = cover $1 (expr_to_region $2)
|
||
|
in EConstr (ESomeApp {value = $1,$2; region})
|
||
|
}
|
||
|
| Constr core_expr? {
|
||
|
let start = $1.region in
|
||
|
let stop = match $2 with
|
||
|
| Some c -> expr_to_region c
|
||
|
| None -> start
|
||
|
in
|
||
|
let region = cover start stop in
|
||
|
EConstr (EConstrApp { value = $1,$2; region})
|
||
|
}
|
||
|
|
||
|
call_expr:
|
||
|
core_expr LPAR nsepseq(expr, COMMA) RPAR {
|
||
|
let start = expr_to_region $1 in
|
||
|
let stop = $4 in
|
||
|
let region = cover start stop in
|
||
|
let hd, tl = $3 in
|
||
|
let tl = (List.map (fun (_, a) -> a) tl) in
|
||
|
ECall { value = $1, (hd, tl); region }
|
||
|
}
|
||
|
| core_expr unit {
|
||
|
let start = expr_to_region $1 in
|
||
|
let stop = $2.region in
|
||
|
let region = cover start stop in
|
||
|
ECall { value = $1, (EUnit $2, []); region }
|
||
|
}
|
||
|
|
||
|
core_expr_2:
|
||
|
Int { EArith (Int $1) }
|
||
|
| Mtz { EArith (Mutez $1) }
|
||
|
| Nat { EArith (Nat $1) }
|
||
|
| Ident | module_field { EVar $1 }
|
||
|
| projection { EProj $1 }
|
||
|
| Str { EString (StrLit $1) }
|
||
|
| unit { EUnit $1 }
|
||
|
| False { ELogic (BoolExpr (False $1)) }
|
||
|
| True { ELogic (BoolExpr (True $1)) }
|
||
|
| list(expr) { EList (EListComp $1) }
|
||
|
|
||
|
list_or_spread:
|
||
|
LBRACKET expr COMMA sep_or_term_list(expr, COMMA) RBRACKET {
|
||
|
let (e, terminator) = $4 in
|
||
|
let e = Utils.nsepseq_cons $2 $3 e in
|
||
|
EList (EListComp ({ value =
|
||
|
{
|
||
|
compound = Brackets ($1,$5);
|
||
|
elements = Some e;
|
||
|
terminator;
|
||
|
};
|
||
|
region = cover $1 $5
|
||
|
}))
|
||
|
}
|
||
|
| LBRACKET expr COMMA DOTDOTDOT expr RBRACKET {
|
||
|
let region = cover $1 $6 in
|
||
|
EList (ECons {value={arg1=$2; op=$4; arg2=$5}; region})
|
||
|
}
|
||
|
| LBRACKET expr RBRACKET {
|
||
|
EList (EListComp ({ value =
|
||
|
{
|
||
|
compound = Brackets ($1,$3);
|
||
|
elements = Some ($2, []);
|
||
|
terminator = None;
|
||
|
};
|
||
|
region = cover $1 $3
|
||
|
}))
|
||
|
}
|
||
|
| LBRACKET RBRACKET {
|
||
|
let value = {
|
||
|
compound = Brackets ($1,$2);
|
||
|
elements = None;
|
||
|
terminator = None} in
|
||
|
let region = cover $1 $2
|
||
|
in EList (EListComp ( {value; region}))
|
||
|
}
|
||
|
|
||
|
core_expr:
|
||
|
Int { EArith (Int $1) }
|
||
|
| Mtz { EArith (Mutez $1) }
|
||
|
| Nat { EArith (Nat $1) }
|
||
|
| Ident | module_field { EVar $1 }
|
||
|
| projection { EProj $1 }
|
||
|
| Str { EString (StrLit $1) }
|
||
|
| unit { EUnit $1 }
|
||
|
| False { ELogic (BoolExpr (False $1)) }
|
||
|
| True { ELogic (BoolExpr (True $1)) }
|
||
|
| list_or_spread { $1 }
|
||
|
| par(expr) { EPar $1 }
|
||
|
| sequence_or_record { $1 }
|
||
|
|
||
|
module_field:
|
||
|
module_name DOT field_name {
|
||
|
let region = cover $1.region $3.region in
|
||
|
{ value = $1.value ^ "." ^ $3.value; region }
|
||
|
}
|
||
|
|
||
|
selection:
|
||
|
| LBRACKET Int RBRACKET selection {
|
||
|
let r, (h, t) = $4 in
|
||
|
let result:((selection, dot) Utils.nsepseq) = (Component $2), (Region.ghost, h) :: t in
|
||
|
r, result
|
||
|
}
|
||
|
| DOT field_name selection {
|
||
|
let r, (h, t) = $3 in
|
||
|
let result:((selection, dot) Utils.nsepseq) = (FieldName $2), ($1, h) :: t in
|
||
|
r, result
|
||
|
}
|
||
|
| DOT field_name {
|
||
|
$1, ((FieldName $2), [])
|
||
|
}
|
||
|
| LBRACKET Int RBRACKET {
|
||
|
Region.ghost, ((Component $2), [])
|
||
|
}
|
||
|
|
||
|
projection:
|
||
|
struct_name selection {
|
||
|
let start = $1.region in
|
||
|
let stop = nsepseq_to_region (function
|
||
|
| FieldName f -> f.region
|
||
|
| Component c -> c.region) (snd $2)
|
||
|
in
|
||
|
let region = cover start stop in
|
||
|
{ value =
|
||
|
{
|
||
|
struct_name = $1;
|
||
|
selector = fst $2;
|
||
|
field_path = snd $2
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
| module_name DOT field_name selection {
|
||
|
let module_name = $1 in
|
||
|
let field_name = $3 in
|
||
|
let value = module_name.value ^ "." ^ field_name.value in
|
||
|
let struct_name = {$1 with value} in
|
||
|
let start = $1.region in
|
||
|
let stop = nsepseq_to_region (function
|
||
|
| FieldName f -> f.region
|
||
|
| Component c -> c.region) (snd $4)
|
||
|
in
|
||
|
let region = cover start stop in
|
||
|
{ value =
|
||
|
{
|
||
|
struct_name;
|
||
|
selector = fst $4;
|
||
|
field_path = snd $4
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sequence_or_record_in:
|
||
|
expr SEMI sep_or_term_list(expr,SEMI) {
|
||
|
let (e, _region) = $3 in
|
||
|
let e = Utils.nsepseq_cons $1 $2 e in
|
||
|
PaSequence { s_elts = e; s_terminator = None}
|
||
|
}
|
||
|
| field_assignment COMMA sep_or_term_list(field_assignment,COMMA) {
|
||
|
let (e, _region) = $3 in
|
||
|
let e = Utils.nsepseq_cons $1 $2 e in
|
||
|
PaRecord { r_elts = e; r_terminator = None}
|
||
|
}
|
||
|
| expr SEMI? {
|
||
|
PaSingleExpr $1
|
||
|
}
|
||
|
|
||
|
sequence_or_record:
|
||
|
LBRACE sequence_or_record_in RBRACE {
|
||
|
let compound = Braces($1, $3) in
|
||
|
let region = cover $1 $3 in
|
||
|
match $2 with
|
||
|
| PaSequence s -> (
|
||
|
let value: expr injection = {
|
||
|
compound;
|
||
|
elements = Some s.s_elts;
|
||
|
terminator = s.s_terminator;
|
||
|
}
|
||
|
in
|
||
|
ESeq {value; region}
|
||
|
)
|
||
|
| PaRecord r -> (
|
||
|
let value: field_assign reg ne_injection = {
|
||
|
compound;
|
||
|
ne_elements = r.r_elts;
|
||
|
terminator = r.r_terminator;
|
||
|
}
|
||
|
in
|
||
|
ERecord {value; region}
|
||
|
)
|
||
|
| PaSingleExpr e -> e
|
||
|
}
|
||
|
|
||
|
field_assignment:
|
||
|
field_name {
|
||
|
{ value =
|
||
|
{
|
||
|
field_name = $1;
|
||
|
assignment = Region.ghost;
|
||
|
field_expr = EVar $1
|
||
|
};
|
||
|
region = $1.region
|
||
|
}
|
||
|
}
|
||
|
| field_name COLON expr {
|
||
|
let start = $1.region in
|
||
|
let stop = expr_to_region $3 in
|
||
|
let region = cover start stop in
|
||
|
{ value =
|
||
|
{
|
||
|
field_name = $1;
|
||
|
assignment = $2;
|
||
|
field_expr = $3
|
||
|
};
|
||
|
region
|
||
|
}
|
||
|
}
|