2020-01-09 02:35:09 +04:00
|
|
|
[@@@warning "-42"]
|
|
|
|
|
2020-04-07 20:33:46 +04:00
|
|
|
module Region = Simple_utils.Region
|
2020-01-10 18:32:54 +04:00
|
|
|
|
2020-01-08 19:39:52 +04:00
|
|
|
type t =
|
2020-01-09 02:35:09 +04:00
|
|
|
Reserved_name of AST.variable
|
|
|
|
| Duplicate_parameter of AST.variable
|
|
|
|
| Duplicate_variant of AST.variable
|
|
|
|
| Non_linear_pattern of AST.variable
|
2020-01-09 17:26:47 +04:00
|
|
|
| Duplicate_field of AST.variable
|
2020-01-08 19:39:52 +04:00
|
|
|
|
|
|
|
type error = t
|
|
|
|
|
|
|
|
exception Error of t
|
2020-01-09 02:35:09 +04:00
|
|
|
|
|
|
|
open Region
|
|
|
|
|
|
|
|
(* Useful modules *)
|
|
|
|
|
|
|
|
module SSet = Utils.String.Set
|
|
|
|
|
|
|
|
module Ord =
|
|
|
|
struct
|
|
|
|
type t = AST.variable
|
|
|
|
let compare v1 v2 =
|
|
|
|
compare v1.value v2.value
|
|
|
|
end
|
|
|
|
|
|
|
|
module VarSet = Set.Make (Ord)
|
|
|
|
|
|
|
|
(* Checking the definition of reserved names (shadowing) *)
|
|
|
|
|
|
|
|
let reserved =
|
|
|
|
let open SSet in
|
|
|
|
empty
|
|
|
|
|> add "get_force"
|
|
|
|
|> add "get_chain_id"
|
|
|
|
|> add "transaction"
|
|
|
|
|> add "get_contract"
|
|
|
|
|> add "get_entrypoint"
|
|
|
|
|> add "size"
|
|
|
|
|> add "int"
|
|
|
|
|> add "abs"
|
|
|
|
|> add "is_nat"
|
|
|
|
|> add "amount"
|
|
|
|
|> add "balance"
|
|
|
|
|> add "now"
|
|
|
|
|> add "unit"
|
|
|
|
|> add "source"
|
|
|
|
|> add "sender"
|
|
|
|
|> add "failwith"
|
|
|
|
|> add "bitwise_or"
|
|
|
|
|> add "bitwise_and"
|
|
|
|
|> add "bitwise_xor"
|
|
|
|
|> add "string_concat"
|
|
|
|
|> add "string_slice"
|
|
|
|
|> add "crypto_check"
|
|
|
|
|> add "crypto_hash_key"
|
|
|
|
|> add "bytes_concat"
|
|
|
|
|> add "bytes_slice"
|
|
|
|
|> add "bytes_pack"
|
|
|
|
|> add "bytes_unpack"
|
|
|
|
|> add "set_empty"
|
|
|
|
|> add "set_mem"
|
|
|
|
|> add "set_add"
|
|
|
|
|> add "set_remove"
|
|
|
|
|> add "set_iter"
|
|
|
|
|> add "set_fold"
|
|
|
|
|> add "list_iter"
|
|
|
|
|> add "list_fold"
|
|
|
|
|> add "list_map"
|
|
|
|
|> add "map_iter"
|
|
|
|
|> add "map_map"
|
|
|
|
|> add "map_fold"
|
|
|
|
|> add "map_remove"
|
|
|
|
|> add "map_update"
|
|
|
|
|> add "map_get"
|
|
|
|
|> add "map_mem"
|
|
|
|
|> add "sha_256"
|
|
|
|
|> add "sha_512"
|
|
|
|
|> add "blake2b"
|
|
|
|
|> add "cons"
|
2020-01-09 17:26:47 +04:00
|
|
|
|> add "address"
|
|
|
|
|> add "self_address"
|
|
|
|
|> add "implicit_account"
|
|
|
|
|> add "set_delegate"
|
2020-01-09 02:35:09 +04:00
|
|
|
|
|
|
|
let check_reserved_names vars =
|
|
|
|
let is_reserved elt = SSet.mem elt.value reserved in
|
|
|
|
let inter = VarSet.filter is_reserved vars in
|
|
|
|
if not (VarSet.is_empty inter) then
|
|
|
|
let clash = VarSet.choose inter in
|
|
|
|
raise (Error (Reserved_name clash))
|
|
|
|
else vars
|
|
|
|
|
|
|
|
let check_reserved_name var =
|
|
|
|
if SSet.mem var.value reserved then
|
|
|
|
raise (Error (Reserved_name var))
|
|
|
|
|
|
|
|
(* Checking the linearity of patterns *)
|
|
|
|
|
|
|
|
open! AST
|
|
|
|
|
|
|
|
let rec vars_of_pattern env = function
|
|
|
|
PConstr p -> vars_of_pconstr env p
|
|
|
|
| PWild _ | PInt _ | PNat _ | PBytes _ | PString _ -> env
|
|
|
|
| PList l -> vars_of_plist env l
|
|
|
|
| PTuple t -> vars_of_ptuple env t.value
|
|
|
|
| PVar var ->
|
|
|
|
if VarSet.mem var env then
|
|
|
|
raise (Error (Non_linear_pattern var))
|
|
|
|
else VarSet.add var env
|
|
|
|
|
|
|
|
and vars_of_pconstr env = function
|
|
|
|
PUnit _ | PFalse _ | PTrue _ | PNone _ -> env
|
|
|
|
| PSomeApp {value=_, {value={inside; _};_}; _} ->
|
|
|
|
vars_of_pattern env inside
|
|
|
|
| PConstrApp {value=_, Some tuple; _} ->
|
|
|
|
vars_of_ptuple env tuple.value
|
|
|
|
| PConstrApp {value=_,None; _} -> env
|
|
|
|
|
|
|
|
and vars_of_plist env = function
|
|
|
|
PListComp {value; _} ->
|
|
|
|
vars_of_pinj env value
|
|
|
|
| PNil _ ->
|
|
|
|
env
|
|
|
|
| PParCons {value={inside; _}; _} ->
|
|
|
|
let head, _, tail = inside in
|
|
|
|
vars_of_pattern (vars_of_pattern env head) tail
|
|
|
|
| PCons {value; _} ->
|
|
|
|
Utils.nsepseq_foldl vars_of_pattern env value
|
|
|
|
|
|
|
|
and vars_of_pinj env inj =
|
|
|
|
Utils.sepseq_foldl vars_of_pattern env inj.elements
|
|
|
|
|
|
|
|
and vars_of_ptuple env {inside; _} =
|
|
|
|
Utils.nsepseq_foldl vars_of_pattern env inside
|
|
|
|
|
|
|
|
let check_linearity = vars_of_pattern VarSet.empty
|
|
|
|
|
|
|
|
(* Checking patterns *)
|
|
|
|
|
|
|
|
let check_pattern p =
|
|
|
|
check_linearity p |> check_reserved_names |> ignore
|
|
|
|
|
|
|
|
(* Checking variants for duplicates *)
|
|
|
|
|
|
|
|
let check_variants variants =
|
|
|
|
let add acc {value; _} =
|
|
|
|
if VarSet.mem value.constr acc then
|
|
|
|
raise (Error (Duplicate_variant value.constr))
|
|
|
|
else VarSet.add value.constr acc in
|
|
|
|
let variants =
|
|
|
|
List.fold_left add VarSet.empty variants
|
|
|
|
in ignore variants
|
|
|
|
|
|
|
|
(* Checking parameters *)
|
|
|
|
|
|
|
|
let check_parameters params =
|
|
|
|
let add acc = function
|
|
|
|
ParamConst {value; _} ->
|
2020-02-05 21:09:45 +04:00
|
|
|
check_reserved_name value.var;
|
2020-01-09 02:35:09 +04:00
|
|
|
if VarSet.mem value.var acc then
|
|
|
|
raise (Error (Duplicate_parameter value.var))
|
|
|
|
else VarSet.add value.var acc
|
|
|
|
| ParamVar {value; _} ->
|
2020-02-05 21:09:45 +04:00
|
|
|
check_reserved_name value.var;
|
2020-01-09 02:35:09 +04:00
|
|
|
if VarSet.mem value.var acc then
|
|
|
|
raise (Error (Duplicate_parameter value.var))
|
|
|
|
else VarSet.add value.var acc in
|
|
|
|
let params =
|
|
|
|
List.fold_left add VarSet.empty params
|
|
|
|
in ignore params
|
2020-01-09 17:26:47 +04:00
|
|
|
|
|
|
|
(* Checking record fields *)
|
|
|
|
|
|
|
|
let check_fields fields =
|
|
|
|
let add acc {value; _} =
|
|
|
|
if VarSet.mem (value: field_decl).field_name acc then
|
|
|
|
raise (Error (Duplicate_field value.field_name))
|
|
|
|
else VarSet.add value.field_name acc in
|
|
|
|
let fields =
|
|
|
|
List.fold_left add VarSet.empty fields
|
|
|
|
in ignore fields
|