initial commit
This commit is contained in:
commit
1edfd8ea06
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
_build/*
|
||||||
|
*/_build
|
||||||
|
.merlin
|
||||||
|
*/.merlin
|
||||||
|
*.install
|
||||||
|
*/*.install
|
20
README_INSTALL
Normal file
20
README_INSTALL
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
switch=titi
|
||||||
|
cd src/ligo
|
||||||
|
sudo apt -y install libev-dev libhidapi-dev
|
||||||
|
opam init
|
||||||
|
eval $(opam env)
|
||||||
|
opam switch create $switch ocaml-base-compiler.4.06.1
|
||||||
|
eval $(opam env --switch=$switch --set-switch)
|
||||||
|
opam repository add new-tezos https://gitlab.com/gabriel.alfour/new-tezos-opam-repository.git
|
||||||
|
|
||||||
|
# si une build a déjà été tentée, il vaut mieux git add tout ce qui est utile et git clean -dfx pour supprimer tout le reste (dune 1.7 crée des fichiers non compatibles avec dune 1.6)
|
||||||
|
opam install -y ocplib-endian alcotest
|
||||||
|
|
||||||
|
(cd ligo-parser && opam install -y .)
|
||||||
|
eval $(opam env)
|
||||||
|
(cd ligo-helpers && opam install -y .)
|
||||||
|
eval $(opam env)
|
||||||
|
(opam install -y .)
|
||||||
|
eval $(opam env)
|
||||||
|
opam install merlin ocp-indent ledit
|
||||||
|
opam user-setup install
|
21
TODO.txt
Normal file
21
TODO.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Main
|
||||||
|
|
||||||
|
## Back-end
|
||||||
|
|
||||||
|
- Replace Mini_c environments with stacks
|
||||||
|
+ Compiler_environment : bad pack make first element deepest
|
||||||
|
+ Add types to pack and unpack
|
||||||
|
- Think about Coq
|
||||||
|
|
||||||
|
## Amendments
|
||||||
|
|
||||||
|
- Bubble_n
|
||||||
|
- Partial application
|
||||||
|
- Type size limit (1.000 -> 10.000)
|
||||||
|
|
||||||
|
# PPX
|
||||||
|
|
||||||
|
## Deriving
|
||||||
|
|
||||||
|
- Generate ADT helpers (this removes 90% of Combinators and a lot of maintenance when modifying ASTs)
|
||||||
|
- Generate option helpers (this makes writing main much easier, much like one would in an untyped language)
|
119
ast_simplified/PP.ml
Normal file
119
ast_simplified/PP.ml
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
open Types
|
||||||
|
open PP_helpers
|
||||||
|
open Format
|
||||||
|
|
||||||
|
let list_sep_d x ppf lst = match lst with
|
||||||
|
| [] -> ()
|
||||||
|
| _ -> fprintf ppf "@; @[<v>%a@]@;" (list_sep x (tag "@;")) lst
|
||||||
|
|
||||||
|
let smap_sep_d x ppf m =
|
||||||
|
if Map.String.is_empty m
|
||||||
|
then ()
|
||||||
|
else fprintf ppf "@; @[<v>%a@]@;" (smap_sep x (tag "@;")) m
|
||||||
|
|
||||||
|
let rec type_expression ppf (te:type_expression) = match te with
|
||||||
|
| T_tuple lst -> fprintf ppf "tuple[%a]" (list_sep_d type_expression) lst
|
||||||
|
| T_sum m -> fprintf ppf "sum[%a]" (smap_sep_d type_expression) m
|
||||||
|
| T_record m -> fprintf ppf "record[%a]" (smap_sep_d type_expression) m
|
||||||
|
| T_function (p, r) -> fprintf ppf "%a -> %a" type_expression p type_expression r
|
||||||
|
| T_variable name -> fprintf ppf "%s" name
|
||||||
|
| T_constant (name, lst) -> fprintf ppf "%s(%a)" name (list_sep_d type_expression) lst
|
||||||
|
|
||||||
|
let literal ppf (l:literal) = match l with
|
||||||
|
| Literal_unit -> fprintf ppf "Unit"
|
||||||
|
| Literal_bool b -> fprintf ppf "%b" b
|
||||||
|
| Literal_int n -> fprintf ppf "%d" n
|
||||||
|
| Literal_nat n -> fprintf ppf "+%d" n
|
||||||
|
| Literal_tez n -> fprintf ppf "%dtz" n
|
||||||
|
| Literal_string s -> fprintf ppf "%S" s
|
||||||
|
| Literal_bytes b -> fprintf ppf "0x%s" @@ Bytes.to_string @@ Bytes.escaped b
|
||||||
|
| Literal_address s -> fprintf ppf "@%S" s
|
||||||
|
| Literal_operation _ -> fprintf ppf "Operation(...bytes)"
|
||||||
|
|
||||||
|
let rec expression ppf (e:expression) = match e with
|
||||||
|
| E_literal l -> literal ppf l
|
||||||
|
| E_variable name -> fprintf ppf "%s" name
|
||||||
|
| E_application (f, arg) -> fprintf ppf "(%a)@(%a)" annotated_expression f annotated_expression arg
|
||||||
|
| E_constructor (name, ae) -> fprintf ppf "%s(%a)" name annotated_expression ae
|
||||||
|
| E_constant (name, lst) -> fprintf ppf "%s(%a)" name (list_sep_d annotated_expression) lst
|
||||||
|
| E_tuple lst -> fprintf ppf "tuple[%a]" (list_sep_d annotated_expression) lst
|
||||||
|
| E_accessor (ae, p) -> fprintf ppf "%a.%a" annotated_expression ae access_path p
|
||||||
|
| E_record m -> fprintf ppf "record[%a]" (smap_sep_d annotated_expression) m
|
||||||
|
| E_map m -> fprintf ppf "map[%a]" (list_sep_d assoc_annotated_expression) m
|
||||||
|
| E_list lst -> fprintf ppf "list[%a]" (list_sep_d annotated_expression) lst
|
||||||
|
| E_look_up (ds, ind) -> fprintf ppf "(%a)[%a]" annotated_expression ds annotated_expression ind
|
||||||
|
| E_lambda {binder;input_type;output_type;result;body} ->
|
||||||
|
fprintf ppf "lambda (%s:%a) : %a {@; @[<v>%a@]@;} return %a"
|
||||||
|
binder type_expression input_type type_expression output_type
|
||||||
|
block body annotated_expression result
|
||||||
|
| E_matching (ae, m) ->
|
||||||
|
fprintf ppf "match %a with %a" annotated_expression ae (matching annotated_expression) m
|
||||||
|
| E_failwith ae ->
|
||||||
|
fprintf ppf "failwith %a" annotated_expression ae
|
||||||
|
|
||||||
|
and assoc_annotated_expression ppf : (ae * ae) -> unit = fun (a, b) ->
|
||||||
|
fprintf ppf "%a -> %a" annotated_expression a annotated_expression b
|
||||||
|
|
||||||
|
and access ppf (a:access) =
|
||||||
|
match a with
|
||||||
|
| Access_tuple n -> fprintf ppf "%d" n
|
||||||
|
| Access_record s -> fprintf ppf "%s" s
|
||||||
|
| Access_map s -> fprintf ppf "(%a)" annotated_expression s
|
||||||
|
|
||||||
|
and access_path ppf (p:access_path) =
|
||||||
|
fprintf ppf "%a" (list_sep access (const ".")) p
|
||||||
|
|
||||||
|
and type_annotation ppf (ta:type_expression option) = match ta with
|
||||||
|
| None -> fprintf ppf ""
|
||||||
|
| Some t -> type_expression ppf t
|
||||||
|
|
||||||
|
and annotated_expression ppf (ae:annotated_expression) = match ae.type_annotation with
|
||||||
|
| None -> fprintf ppf "%a" expression ae.expression
|
||||||
|
| Some t -> fprintf ppf "(%a) : %a" expression ae.expression type_expression t
|
||||||
|
|
||||||
|
and value : _ -> value -> unit = fun x -> annotated_expression x
|
||||||
|
|
||||||
|
and block ppf (b:block) = (list_sep instruction (tag "@;")) ppf b
|
||||||
|
|
||||||
|
and single_record_patch ppf ((p, ae) : string * ae) =
|
||||||
|
fprintf ppf "%s <- %a" p annotated_expression ae
|
||||||
|
|
||||||
|
and single_tuple_patch ppf ((p, ae) : int * ae) =
|
||||||
|
fprintf ppf "%d <- %a" p annotated_expression ae
|
||||||
|
|
||||||
|
and matching_variant_case : type a . (_ -> a -> unit) -> _ -> (constructor_name * name) * a -> unit =
|
||||||
|
fun f ppf ((c,n),a) ->
|
||||||
|
fprintf ppf "| %s %s -> %a" c n f a
|
||||||
|
|
||||||
|
and matching : type a . (formatter -> a -> unit) -> formatter -> a matching -> unit =
|
||||||
|
fun f ppf m -> match m with
|
||||||
|
| Match_tuple (lst, b) ->
|
||||||
|
fprintf ppf "let (%a) = %a" (list_sep_d string) lst f b
|
||||||
|
| Match_variant lst ->
|
||||||
|
fprintf ppf "%a" (list_sep (matching_variant_case f) (tag "@.")) lst
|
||||||
|
| Match_bool {match_true ; match_false} ->
|
||||||
|
fprintf ppf "| True -> %a @.| False -> %a" f match_true f match_false
|
||||||
|
| Match_list {match_nil ; match_cons = (hd, tl, match_cons)} ->
|
||||||
|
fprintf ppf "| Nil -> %a @.| %s :: %s -> %a" f match_nil hd tl f match_cons
|
||||||
|
| Match_option {match_none ; match_some = (some, match_some)} ->
|
||||||
|
fprintf ppf "| None -> %a @.| Some %s -> %a" f match_none some f match_some
|
||||||
|
|
||||||
|
and instruction ppf (i:instruction) = match i with
|
||||||
|
| I_skip -> fprintf ppf "skip"
|
||||||
|
| I_do ae -> fprintf ppf "do %a" annotated_expression ae
|
||||||
|
| I_record_patch (name, path, lst) -> fprintf ppf "%s.%a[%a]" name access_path path (list_sep_d single_record_patch) lst
|
||||||
|
| I_tuple_patch (name, path, lst) -> fprintf ppf "%s.%a[%a]" name access_path path (list_sep_d single_tuple_patch) lst
|
||||||
|
| I_loop (cond, b) -> fprintf ppf "while (%a) { %a }" annotated_expression cond block b
|
||||||
|
| I_assignment {name;annotated_expression = ae} ->
|
||||||
|
fprintf ppf "%s := %a" name annotated_expression ae
|
||||||
|
| I_matching (ae, m) ->
|
||||||
|
fprintf ppf "match %a with %a" annotated_expression ae (matching block) m
|
||||||
|
|
||||||
|
let declaration ppf (d:declaration) = match d with
|
||||||
|
| Declaration_type {type_name ; type_expression = te} ->
|
||||||
|
fprintf ppf "type %s = %a" type_name type_expression te
|
||||||
|
| Declaration_constant {name ; annotated_expression = ae} ->
|
||||||
|
fprintf ppf "const %s = %a" name annotated_expression ae
|
||||||
|
|
||||||
|
let program ppf (p:program) =
|
||||||
|
fprintf ppf "@[<v>%a@]" (list_sep declaration (tag "@;")) (List.map Location.unwrap p)
|
8
ast_simplified/ast_simplified.ml
Normal file
8
ast_simplified/ast_simplified.ml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
include Types
|
||||||
|
include Misc
|
||||||
|
include Combinators
|
||||||
|
|
||||||
|
module Types = Types
|
||||||
|
module Misc = Misc
|
||||||
|
module PP = PP
|
||||||
|
module Combinators = Combinators
|
186
ast_simplified/combinators.ml
Normal file
186
ast_simplified/combinators.ml
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
open Types
|
||||||
|
open Simple_utils.Trace
|
||||||
|
module Option = Simple_utils.Option
|
||||||
|
|
||||||
|
module SMap = Map.String
|
||||||
|
|
||||||
|
let get_name : named_expression -> string = fun x -> x.name
|
||||||
|
let get_type_name : named_type_expression -> string = fun x -> x.type_name
|
||||||
|
let get_type_annotation (x:annotated_expression) = x.type_annotation
|
||||||
|
let get_expression (x:annotated_expression) = x.expression
|
||||||
|
|
||||||
|
let i_assignment : _ -> instruction = fun x -> I_assignment x
|
||||||
|
let named_expression name annotated_expression = { name ; annotated_expression }
|
||||||
|
let named_typed_expression name expression ty = { name ; annotated_expression = { expression ; type_annotation = Some ty } }
|
||||||
|
let typed_expression expression ty = { expression ; type_annotation = Some ty }
|
||||||
|
let untyped_expression expression = { expression ; type_annotation = None }
|
||||||
|
|
||||||
|
let get_untyped_expression : annotated_expression -> expression result = fun ae ->
|
||||||
|
let%bind () =
|
||||||
|
trace_strong (simple_error "expression is typed") @@
|
||||||
|
Assert.assert_none ae.type_annotation in
|
||||||
|
ok ae.expression
|
||||||
|
|
||||||
|
let t_bool : type_expression = T_constant ("bool", [])
|
||||||
|
let t_string : type_expression = T_constant ("string", [])
|
||||||
|
let t_bytes : type_expression = T_constant ("bytes", [])
|
||||||
|
let t_int : type_expression = T_constant ("int", [])
|
||||||
|
let t_operation : type_expression = T_constant ("operation", [])
|
||||||
|
let t_nat : type_expression = T_constant ("nat", [])
|
||||||
|
let t_tez : type_expression = T_constant ("tez", [])
|
||||||
|
let t_unit : type_expression = T_constant ("unit", [])
|
||||||
|
let t_address : type_expression = T_constant ("address", [])
|
||||||
|
let t_option o : type_expression = T_constant ("option", [o])
|
||||||
|
let t_list t : type_expression = T_constant ("list", [t])
|
||||||
|
let t_variable n : type_expression = T_variable n
|
||||||
|
let t_tuple lst : type_expression = T_tuple lst
|
||||||
|
let t_pair (a , b) = t_tuple [a ; b]
|
||||||
|
let t_record m : type_expression = (T_record m)
|
||||||
|
|
||||||
|
let t_record_ez lst =
|
||||||
|
let m = SMap.of_list lst in
|
||||||
|
t_record m
|
||||||
|
|
||||||
|
let t_sum m : type_expression = T_sum m
|
||||||
|
let ez_t_sum (lst:(string * type_expression) list) : type_expression =
|
||||||
|
let aux prev (k, v) = SMap.add k v prev in
|
||||||
|
let map = List.fold_left aux SMap.empty lst in
|
||||||
|
T_sum map
|
||||||
|
|
||||||
|
let t_function param result : type_expression = T_function (param, result)
|
||||||
|
let t_map key value = (T_constant ("map", [key ; value]))
|
||||||
|
|
||||||
|
let make_e_a ?type_annotation expression = {expression ; type_annotation}
|
||||||
|
let make_e_a_full expression type_annotation = make_e_a ~type_annotation expression
|
||||||
|
|
||||||
|
let make_name (s : string) : name = s
|
||||||
|
|
||||||
|
let e_var (s : string) : expression = E_variable s
|
||||||
|
|
||||||
|
let e_unit () : expression = E_literal (Literal_unit)
|
||||||
|
let e_int n : expression = E_literal (Literal_int n)
|
||||||
|
let e_nat n : expression = E_literal (Literal_nat n)
|
||||||
|
let e_bool b : expression = E_literal (Literal_bool b)
|
||||||
|
let e_string s : expression = E_literal (Literal_string s)
|
||||||
|
let e_address s : expression = E_literal (Literal_address s)
|
||||||
|
let e_tez s : expression = E_literal (Literal_tez s)
|
||||||
|
let e_bytes b : expression = E_literal (Literal_bytes (Bytes.of_string b))
|
||||||
|
let e_record map : expression = E_record map
|
||||||
|
let e_tuple lst : expression = E_tuple lst
|
||||||
|
let e_some s : expression = E_constant ("SOME", [s])
|
||||||
|
let e_none : expression = E_constant ("NONE", [])
|
||||||
|
let e_map lst : expression = E_map lst
|
||||||
|
let e_list lst : expression = E_list lst
|
||||||
|
let e_pair a b : expression = E_tuple [a; b]
|
||||||
|
let e_constructor s a : expression = E_constructor (s , a)
|
||||||
|
let e_match a b : expression = E_matching (a , b)
|
||||||
|
let e_match_bool a b c : expression = e_match a (Match_bool {match_true = b ; match_false = c})
|
||||||
|
let e_accessor a b = E_accessor (a , b)
|
||||||
|
let e_accessor_props a b = e_accessor a (List.map (fun x -> Access_record x) b)
|
||||||
|
let e_variable v = E_variable v
|
||||||
|
let e_failwith v = E_failwith v
|
||||||
|
|
||||||
|
let e_a_unit : annotated_expression = make_e_a_full (e_unit ()) t_unit
|
||||||
|
let e_a_string s : annotated_expression = make_e_a_full (e_string s) t_string
|
||||||
|
let e_a_int n : annotated_expression = make_e_a_full (e_int n) t_int
|
||||||
|
let e_a_nat n : annotated_expression = make_e_a_full (e_nat n) t_nat
|
||||||
|
let e_a_bool b : annotated_expression = make_e_a_full (e_bool b) t_bool
|
||||||
|
let e_a_list lst : annotated_expression = make_e_a (e_list lst)
|
||||||
|
let e_a_constructor s a : annotated_expression = make_e_a (e_constructor s a)
|
||||||
|
let e_a_address x = make_e_a_full (e_address x) t_address
|
||||||
|
let e_a_tez x = make_e_a_full (e_tez x) t_tez
|
||||||
|
|
||||||
|
let e_a_record r =
|
||||||
|
let type_annotation = Option.(
|
||||||
|
map ~f:t_record (bind_map_smap get_type_annotation r)
|
||||||
|
) in
|
||||||
|
make_e_a ?type_annotation (e_record r)
|
||||||
|
|
||||||
|
let ez_e_a_record lst =
|
||||||
|
let aux prev (k, v) = SMap.add k v prev in
|
||||||
|
let map = List.fold_left aux SMap.empty lst in
|
||||||
|
e_a_record map
|
||||||
|
|
||||||
|
let e_a_tuple lst =
|
||||||
|
let type_annotation = Option.(
|
||||||
|
map ~f:t_tuple (bind_map_list get_type_annotation lst)
|
||||||
|
) in
|
||||||
|
make_e_a ?type_annotation (e_tuple lst)
|
||||||
|
|
||||||
|
let e_a_pair a b =
|
||||||
|
let type_annotation = Option.(
|
||||||
|
map ~f:t_pair
|
||||||
|
@@ bind_map_pair get_type_annotation (a , b)
|
||||||
|
) in
|
||||||
|
make_e_a ?type_annotation (e_pair a b)
|
||||||
|
|
||||||
|
let e_a_some opt =
|
||||||
|
let type_annotation = Option.(
|
||||||
|
map ~f:t_option (get_type_annotation opt)
|
||||||
|
) in
|
||||||
|
make_e_a ?type_annotation (e_some opt)
|
||||||
|
|
||||||
|
let e_a_typed_none t_opt =
|
||||||
|
let type_annotation = t_option t_opt in
|
||||||
|
make_e_a ~type_annotation e_none
|
||||||
|
|
||||||
|
let e_a_typed_list lst t =
|
||||||
|
make_e_a ~type_annotation:(t_list t) (e_list lst)
|
||||||
|
|
||||||
|
let e_a_map lst k v = make_e_a ~type_annotation:(t_map k v) (e_map lst)
|
||||||
|
|
||||||
|
let e_lambda (binder : string)
|
||||||
|
(input_type : type_expression)
|
||||||
|
(output_type : type_expression)
|
||||||
|
(result : expression)
|
||||||
|
(body : block)
|
||||||
|
: expression =
|
||||||
|
E_lambda {
|
||||||
|
binder = (make_name binder) ;
|
||||||
|
input_type = input_type ;
|
||||||
|
output_type = output_type ;
|
||||||
|
result = (make_e_a result) ;
|
||||||
|
body ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e_tuple (lst : ae list) : expression = E_tuple lst
|
||||||
|
let ez_e_tuple (lst : expression list) : expression =
|
||||||
|
e_tuple (List.map make_e_a lst)
|
||||||
|
|
||||||
|
let e_constructor (s : string) (e : ae) : expression = E_constructor (make_name s, e)
|
||||||
|
|
||||||
|
let e_record (lst : (string * ae) list) : expression =
|
||||||
|
let aux prev (k, v) = SMap.add k v prev in
|
||||||
|
let map = List.fold_left aux SMap.empty lst in
|
||||||
|
E_record map
|
||||||
|
|
||||||
|
let ez_e_record (lst : (string * expression) list) : expression =
|
||||||
|
(* TODO: define a correct implementation of List.map
|
||||||
|
* (an implementation that does not fail with stack overflow) *)
|
||||||
|
e_record (List.map (fun (s,e) -> (s, make_e_a e)) lst)
|
||||||
|
|
||||||
|
|
||||||
|
let get_a_accessor = fun t ->
|
||||||
|
match t.expression with
|
||||||
|
| E_accessor (a , b) -> ok (a , b)
|
||||||
|
| _ -> simple_fail "not an accessor"
|
||||||
|
|
||||||
|
let assert_a_accessor = fun t ->
|
||||||
|
let%bind _ = get_a_accessor t in
|
||||||
|
ok ()
|
||||||
|
|
||||||
|
let get_access_record : access -> string result = fun a ->
|
||||||
|
match a with
|
||||||
|
| Access_tuple _
|
||||||
|
| Access_map _ -> simple_fail "not an access record"
|
||||||
|
| Access_record s -> ok s
|
||||||
|
|
||||||
|
let get_a_pair = fun t ->
|
||||||
|
match t.expression with
|
||||||
|
| E_tuple [a ; b] -> ok (a , b)
|
||||||
|
| _ -> simple_fail "not a pair"
|
||||||
|
|
||||||
|
let get_a_list = fun t ->
|
||||||
|
match t.expression with
|
||||||
|
| E_list lst -> ok lst
|
||||||
|
| _ -> simple_fail "not a pair"
|
12
ast_simplified/dune
Normal file
12
ast_simplified/dune
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
(library
|
||||||
|
(name ast_simplified)
|
||||||
|
(public_name ligo.ast_simplified)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -open Simple_utils ))
|
||||||
|
)
|
258
ast_simplified/misc.ml
Normal file
258
ast_simplified/misc.ml
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
open Trace
|
||||||
|
open Types
|
||||||
|
|
||||||
|
let assert_literal_eq (a, b : literal * literal) : unit result =
|
||||||
|
match (a, b) with
|
||||||
|
| Literal_bool a, Literal_bool b when a = b -> ok ()
|
||||||
|
| Literal_bool _, Literal_bool _ -> simple_fail "different bools"
|
||||||
|
| Literal_bool _, _ -> simple_fail "bool vs non-bool"
|
||||||
|
| Literal_int a, Literal_int b when a = b -> ok ()
|
||||||
|
| Literal_int _, Literal_int _ -> simple_fail "different ints"
|
||||||
|
| Literal_int _, _ -> simple_fail "int vs non-int"
|
||||||
|
| Literal_nat a, Literal_nat b when a = b -> ok ()
|
||||||
|
| Literal_nat _, Literal_nat _ -> simple_fail "different nats"
|
||||||
|
| Literal_nat _, _ -> simple_fail "nat vs non-nat"
|
||||||
|
| Literal_tez a, Literal_tez b when a = b -> ok ()
|
||||||
|
| Literal_tez _, Literal_tez _ -> simple_fail "different tezs"
|
||||||
|
| Literal_tez _, _ -> simple_fail "tez vs non-tez"
|
||||||
|
| Literal_string a, Literal_string b when a = b -> ok ()
|
||||||
|
| Literal_string _, Literal_string _ -> simple_fail "different strings"
|
||||||
|
| Literal_string _, _ -> simple_fail "string vs non-string"
|
||||||
|
| Literal_bytes a, Literal_bytes b when a = b -> ok ()
|
||||||
|
| Literal_bytes _, Literal_bytes _ -> simple_fail "different bytess"
|
||||||
|
| Literal_bytes _, _ -> simple_fail "bytes vs non-bytes"
|
||||||
|
| Literal_unit, Literal_unit -> ok ()
|
||||||
|
| Literal_unit, _ -> simple_fail "unit vs non-unit"
|
||||||
|
| Literal_address a, Literal_address b when a = b -> ok ()
|
||||||
|
| Literal_address _, Literal_address _ -> simple_fail "different addresss"
|
||||||
|
| Literal_address _, _ -> simple_fail "address vs non-address"
|
||||||
|
| Literal_operation _, Literal_operation _ -> simple_fail "can't compare operations"
|
||||||
|
| Literal_operation _, _ -> simple_fail "operation vs non-operation"
|
||||||
|
|
||||||
|
|
||||||
|
let rec assert_value_eq (a, b: (value*value)) : unit result =
|
||||||
|
let error_content () =
|
||||||
|
Format.asprintf "\n@[<v>- %a@;- %a]" PP.value a PP.value b
|
||||||
|
in
|
||||||
|
trace (fun () -> error (thunk "not equal") error_content ()) @@
|
||||||
|
match (a.expression, b.expression) with
|
||||||
|
| E_literal a, E_literal b ->
|
||||||
|
assert_literal_eq (a, b)
|
||||||
|
| E_constant (ca, lsta), E_constant (cb, lstb) when ca = cb -> (
|
||||||
|
let%bind lst =
|
||||||
|
generic_try (simple_error "constants with different number of elements")
|
||||||
|
(fun () -> List.combine lsta lstb) in
|
||||||
|
let%bind _all = bind_list @@ List.map assert_value_eq lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_constant _, E_constant _ ->
|
||||||
|
simple_fail "different constants"
|
||||||
|
| E_constant _, _ ->
|
||||||
|
let error_content () =
|
||||||
|
Format.asprintf "%a vs %a"
|
||||||
|
PP.annotated_expression a
|
||||||
|
PP.annotated_expression b
|
||||||
|
in
|
||||||
|
fail @@ (fun () -> error (thunk "comparing constant with other stuff") error_content ())
|
||||||
|
|
||||||
|
| E_constructor (ca, a), E_constructor (cb, b) when ca = cb -> (
|
||||||
|
let%bind _eq = assert_value_eq (a, b) in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_constructor _, E_constructor _ ->
|
||||||
|
simple_fail "different constructors"
|
||||||
|
| E_constructor _, _ ->
|
||||||
|
simple_fail "comparing constructor with other stuff"
|
||||||
|
|
||||||
|
| E_tuple lsta, E_tuple lstb -> (
|
||||||
|
let%bind lst =
|
||||||
|
generic_try (simple_error "tuples with different number of elements")
|
||||||
|
(fun () -> List.combine lsta lstb) in
|
||||||
|
let%bind _all = bind_list @@ List.map assert_value_eq lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_tuple _, _ ->
|
||||||
|
simple_fail "comparing tuple with other stuff"
|
||||||
|
|
||||||
|
| E_record sma, E_record smb -> (
|
||||||
|
let aux _ a b =
|
||||||
|
match a, b with
|
||||||
|
| Some a, Some b -> Some (assert_value_eq (a, b))
|
||||||
|
| _ -> Some (simple_fail "different record keys")
|
||||||
|
in
|
||||||
|
let%bind _all = bind_smap @@ Map.String.merge aux sma smb in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_record _, _ ->
|
||||||
|
simple_fail "comparing record with other stuff"
|
||||||
|
|
||||||
|
| E_map lsta, E_map lstb -> (
|
||||||
|
let%bind lst = generic_try (simple_error "maps of different lengths")
|
||||||
|
(fun () ->
|
||||||
|
let lsta' = List.sort compare lsta in
|
||||||
|
let lstb' = List.sort compare lstb in
|
||||||
|
List.combine lsta' lstb') in
|
||||||
|
let aux = fun ((ka, va), (kb, vb)) ->
|
||||||
|
let%bind _ = assert_value_eq (ka, kb) in
|
||||||
|
let%bind _ = assert_value_eq (va, vb) in
|
||||||
|
ok () in
|
||||||
|
let%bind _all = bind_map_list aux lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_map _, _ ->
|
||||||
|
simple_fail "comparing map with other stuff"
|
||||||
|
|
||||||
|
| E_list lsta, E_list lstb -> (
|
||||||
|
let%bind lst =
|
||||||
|
generic_try (simple_error "list of different lengths")
|
||||||
|
(fun () -> List.combine lsta lstb) in
|
||||||
|
let%bind _all = bind_map_list assert_value_eq lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_list _, _ ->
|
||||||
|
simple_fail "comparing list with other stuff"
|
||||||
|
|
||||||
|
| _, _ -> simple_fail "comparing not a value"
|
||||||
|
|
||||||
|
|
||||||
|
(* module Rename = struct
|
||||||
|
* open Trace
|
||||||
|
*
|
||||||
|
* module Type = struct
|
||||||
|
* (\* Type renaming, not needed. Yet. *\)
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
* module Value = struct
|
||||||
|
* type renaming = string * (string * access_path) (\* src -> dst *\)
|
||||||
|
* type renamings = renaming list
|
||||||
|
* let filter (r:renamings) (s:string) : renamings =
|
||||||
|
* List.filter (fun (x, _) -> not (x = s)) r
|
||||||
|
* let filters (r:renamings) (ss:string list) : renamings =
|
||||||
|
* List.filter (fun (x, _) -> not (List.mem x ss)) r
|
||||||
|
*
|
||||||
|
* let rec rename_instruction (r:renamings) (i:instruction) : instruction result =
|
||||||
|
* match i with
|
||||||
|
* | I_assignment ({name;annotated_expression = e} as a) -> (
|
||||||
|
* match List.assoc_opt name r with
|
||||||
|
* | None ->
|
||||||
|
* let%bind annotated_expression = rename_annotated_expression (filter r name) e in
|
||||||
|
* ok (I_assignment {a with annotated_expression})
|
||||||
|
* | Some (name', lst) -> (
|
||||||
|
* let%bind annotated_expression = rename_annotated_expression r e in
|
||||||
|
* match lst with
|
||||||
|
* | [] -> ok (I_assignment {name = name' ; annotated_expression})
|
||||||
|
* | lst ->
|
||||||
|
* let (hds, tl) =
|
||||||
|
* let open List in
|
||||||
|
* let r = rev lst in
|
||||||
|
* rev @@ tl r, hd r
|
||||||
|
* in
|
||||||
|
* let%bind tl' = match tl with
|
||||||
|
* | Access_record n -> ok n
|
||||||
|
* | Access_tuple _ -> simple_fail "no support for renaming into tuples yet" in
|
||||||
|
* ok (I_record_patch (name', hds, [tl', annotated_expression]))
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* | I_skip -> ok I_skip
|
||||||
|
* | I_fail e ->
|
||||||
|
* let%bind e' = rename_annotated_expression r e in
|
||||||
|
* ok (I_fail e')
|
||||||
|
* | I_loop (cond, body) ->
|
||||||
|
* let%bind cond' = rename_annotated_expression r cond in
|
||||||
|
* let%bind body' = rename_block r body in
|
||||||
|
* ok (I_loop (cond', body'))
|
||||||
|
* | I_matching (ae, m) ->
|
||||||
|
* let%bind ae' = rename_annotated_expression r ae in
|
||||||
|
* let%bind m' = rename_matching rename_block r m in
|
||||||
|
* ok (I_matching (ae', m'))
|
||||||
|
* | I_record_patch (v, path, lst) ->
|
||||||
|
* let aux (x, y) =
|
||||||
|
* let%bind y' = rename_annotated_expression (filter r v) y in
|
||||||
|
* ok (x, y') in
|
||||||
|
* let%bind lst' = bind_map_list aux lst in
|
||||||
|
* match List.assoc_opt v r with
|
||||||
|
* | None -> (
|
||||||
|
* ok (I_record_patch (v, path, lst'))
|
||||||
|
* )
|
||||||
|
* | Some (v', path') -> (
|
||||||
|
* ok (I_record_patch (v', path' @ path, lst'))
|
||||||
|
* )
|
||||||
|
* and rename_block (r:renamings) (bl:block) : block result =
|
||||||
|
* bind_map_list (rename_instruction r) bl
|
||||||
|
*
|
||||||
|
* and rename_matching : type a . (renamings -> a -> a result) -> renamings -> a matching -> a matching result =
|
||||||
|
* fun f r m ->
|
||||||
|
* match m with
|
||||||
|
* | Match_bool { match_true = mt ; match_false = mf } ->
|
||||||
|
* let%bind match_true = f r mt in
|
||||||
|
* let%bind match_false = f r mf in
|
||||||
|
* ok (Match_bool {match_true ; match_false})
|
||||||
|
* | Match_option { match_none = mn ; match_some = (some, ms) } ->
|
||||||
|
* let%bind match_none = f r mn in
|
||||||
|
* let%bind ms' = f (filter r some) ms in
|
||||||
|
* ok (Match_option {match_none ; match_some = (some, ms')})
|
||||||
|
* | Match_list { match_nil = mn ; match_cons = (hd, tl, mc) } ->
|
||||||
|
* let%bind match_nil = f r mn in
|
||||||
|
* let%bind mc' = f (filters r [hd;tl]) mc in
|
||||||
|
* ok (Match_list {match_nil ; match_cons = (hd, tl, mc')})
|
||||||
|
* | Match_tuple (lst, body) ->
|
||||||
|
* let%bind body' = f (filters r lst) body in
|
||||||
|
* ok (Match_tuple (lst, body'))
|
||||||
|
*
|
||||||
|
* and rename_matching_instruction = fun x -> rename_matching rename_block x
|
||||||
|
*
|
||||||
|
* and rename_matching_expr = fun x -> rename_matching rename_expression x
|
||||||
|
*
|
||||||
|
* and rename_annotated_expression (r:renamings) (ae:annotated_expression) : annotated_expression result =
|
||||||
|
* let%bind expression = rename_expression r ae.expression in
|
||||||
|
* ok {ae with expression}
|
||||||
|
*
|
||||||
|
* and rename_expression : renamings -> expression -> expression result = fun r e ->
|
||||||
|
* match e with
|
||||||
|
* | E_literal _ as l -> ok l
|
||||||
|
* | E_constant (name, lst) ->
|
||||||
|
* let%bind lst' = bind_map_list (rename_annotated_expression r) lst in
|
||||||
|
* ok (E_constant (name, lst'))
|
||||||
|
* | E_constructor (name, ae) ->
|
||||||
|
* let%bind ae' = rename_annotated_expression r ae in
|
||||||
|
* ok (E_constructor (name, ae'))
|
||||||
|
* | E_variable v -> (
|
||||||
|
* match List.assoc_opt v r with
|
||||||
|
* | None -> ok (E_variable v)
|
||||||
|
* | Some (name, path) -> ok (E_accessor (ae (E_variable (name)), path))
|
||||||
|
* )
|
||||||
|
* | E_lambda ({binder;body;result} as l) ->
|
||||||
|
* let r' = filter r binder in
|
||||||
|
* let%bind body = rename_block r' body in
|
||||||
|
* let%bind result = rename_annotated_expression r' result in
|
||||||
|
* ok (E_lambda {l with body ; result})
|
||||||
|
* | E_application (f, arg) ->
|
||||||
|
* let%bind f' = rename_annotated_expression r f in
|
||||||
|
* let%bind arg' = rename_annotated_expression r arg in
|
||||||
|
* ok (E_application (f', arg'))
|
||||||
|
* | E_tuple lst ->
|
||||||
|
* let%bind lst' = bind_map_list (rename_annotated_expression r) lst in
|
||||||
|
* ok (E_tuple lst')
|
||||||
|
* | E_accessor (ae, p) ->
|
||||||
|
* let%bind ae' = rename_annotated_expression r ae in
|
||||||
|
* ok (E_accessor (ae', p))
|
||||||
|
* | E_record sm ->
|
||||||
|
* let%bind sm' = bind_smap
|
||||||
|
* @@ SMap.map (rename_annotated_expression r) sm in
|
||||||
|
* ok (E_record sm')
|
||||||
|
* | E_map m ->
|
||||||
|
* let%bind m' = bind_map_list
|
||||||
|
* (fun (x, y) -> bind_map_pair (rename_annotated_expression r) (x, y)) m in
|
||||||
|
* ok (E_map m')
|
||||||
|
* | E_list lst ->
|
||||||
|
* let%bind lst' = bind_map_list (rename_annotated_expression r) lst in
|
||||||
|
* ok (E_list lst')
|
||||||
|
* | E_look_up m ->
|
||||||
|
* let%bind m' = bind_map_pair (rename_annotated_expression r) m in
|
||||||
|
* ok (E_look_up m')
|
||||||
|
* | E_matching (ae, m) ->
|
||||||
|
* let%bind ae' = rename_annotated_expression r ae in
|
||||||
|
* let%bind m' = rename_matching rename_annotated_expression r m in
|
||||||
|
* ok (E_matching (ae', m'))
|
||||||
|
* end
|
||||||
|
* end *)
|
126
ast_simplified/types.ml
Normal file
126
ast_simplified/types.ml
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
module Map = Simple_utils.Map
|
||||||
|
module Location = Simple_utils.Location
|
||||||
|
|
||||||
|
type name = string
|
||||||
|
type type_name = string
|
||||||
|
type constructor_name = string
|
||||||
|
|
||||||
|
type 'a name_map = 'a Map.String.t
|
||||||
|
type 'a type_name_map = 'a Map.String.t
|
||||||
|
|
||||||
|
type program = declaration Location.wrap list
|
||||||
|
|
||||||
|
and declaration =
|
||||||
|
| Declaration_type of named_type_expression
|
||||||
|
| Declaration_constant of named_expression
|
||||||
|
(* | Macro_declaration of macro_declaration *)
|
||||||
|
|
||||||
|
and value = annotated_expression
|
||||||
|
|
||||||
|
and annotated_expression = {
|
||||||
|
expression: expression ;
|
||||||
|
type_annotation: te option ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and named_expression = {
|
||||||
|
name: name ;
|
||||||
|
annotated_expression: ae ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and named_type_expression = {
|
||||||
|
type_name: type_name ;
|
||||||
|
type_expression: type_expression ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and te = type_expression
|
||||||
|
and ae = annotated_expression
|
||||||
|
and te_map = type_expression type_name_map
|
||||||
|
and ae_map = annotated_expression name_map
|
||||||
|
|
||||||
|
and type_expression =
|
||||||
|
| T_tuple of te list
|
||||||
|
| T_sum of te_map
|
||||||
|
| T_record of te_map
|
||||||
|
| T_function of te * te
|
||||||
|
| T_variable of type_name
|
||||||
|
| T_constant of type_name * te list
|
||||||
|
|
||||||
|
and lambda = {
|
||||||
|
binder: name ;
|
||||||
|
input_type: type_expression ;
|
||||||
|
output_type: type_expression ;
|
||||||
|
result: ae ;
|
||||||
|
body: block ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and expression =
|
||||||
|
(* Base *)
|
||||||
|
| E_literal of literal
|
||||||
|
| E_constant of (name * ae list) (* For language constants, like (Cons hd tl) or (plus i j) *)
|
||||||
|
| E_variable of name
|
||||||
|
| E_lambda of lambda
|
||||||
|
| E_application of (ae * ae)
|
||||||
|
(* E_Tuple *)
|
||||||
|
| E_tuple of ae list
|
||||||
|
(* Sum *)
|
||||||
|
| E_constructor of (name * ae) (* For user defined constructors *)
|
||||||
|
(* E_record *)
|
||||||
|
| E_record of ae_map
|
||||||
|
| E_accessor of (ae * access_path)
|
||||||
|
(* Data Structures *)
|
||||||
|
| E_map of (ae * ae) list
|
||||||
|
| E_list of ae list
|
||||||
|
| E_look_up of (ae * ae)
|
||||||
|
(* Matching *)
|
||||||
|
| E_matching of (ae * matching_expr)
|
||||||
|
| E_failwith of ae
|
||||||
|
|
||||||
|
and access =
|
||||||
|
| Access_tuple of int
|
||||||
|
| Access_record of string
|
||||||
|
| Access_map of ae
|
||||||
|
|
||||||
|
and access_path = access list
|
||||||
|
|
||||||
|
and literal =
|
||||||
|
| Literal_unit
|
||||||
|
| Literal_bool of bool
|
||||||
|
| Literal_int of int
|
||||||
|
| Literal_nat of int
|
||||||
|
| Literal_tez of int
|
||||||
|
| Literal_string of string
|
||||||
|
| Literal_bytes of bytes
|
||||||
|
| Literal_address of string
|
||||||
|
| Literal_operation of Memory_proto_alpha.Alpha_context.packed_internal_operation
|
||||||
|
|
||||||
|
and block = instruction list
|
||||||
|
and b = block
|
||||||
|
|
||||||
|
and instruction =
|
||||||
|
| I_assignment of named_expression
|
||||||
|
| I_matching of ae * matching_instr
|
||||||
|
| I_loop of ae * b
|
||||||
|
| I_skip
|
||||||
|
| I_do of ae
|
||||||
|
| I_record_patch of (name * access_path * (string * ae) list)
|
||||||
|
| I_tuple_patch of (name * access_path * (int * ae) list)
|
||||||
|
|
||||||
|
and 'a matching =
|
||||||
|
| Match_bool of {
|
||||||
|
match_true : 'a ;
|
||||||
|
match_false : 'a ;
|
||||||
|
}
|
||||||
|
| Match_list of {
|
||||||
|
match_nil : 'a ;
|
||||||
|
match_cons : name * name * 'a ;
|
||||||
|
}
|
||||||
|
| Match_option of {
|
||||||
|
match_none : 'a ;
|
||||||
|
match_some : name * 'a ;
|
||||||
|
}
|
||||||
|
| Match_tuple of name list * 'a
|
||||||
|
| Match_variant of ((constructor_name * name) * 'a) list
|
||||||
|
|
||||||
|
and matching_instr = b matching
|
||||||
|
|
||||||
|
and matching_expr = annotated_expression matching
|
115
ast_typed/PP.ml
Normal file
115
ast_typed/PP.ml
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
open Types
|
||||||
|
open Format
|
||||||
|
open PP_helpers
|
||||||
|
|
||||||
|
let list_sep_d x = list_sep x (const " , ")
|
||||||
|
let smap_sep_d x = smap_sep x (const " , ")
|
||||||
|
|
||||||
|
|
||||||
|
let rec type_value' ppf (tv':type_value') : unit =
|
||||||
|
match tv' with
|
||||||
|
| T_tuple lst -> fprintf ppf "tuple[%a]" (list_sep_d type_value) lst
|
||||||
|
| T_sum m -> fprintf ppf "sum[%a]" (smap_sep_d type_value) m
|
||||||
|
| T_record m -> fprintf ppf "record[%a]" (smap_sep_d type_value) m
|
||||||
|
| T_function (a, b) -> fprintf ppf "%a -> %a" type_value a type_value b
|
||||||
|
| T_constant (c, []) -> fprintf ppf "%s" c
|
||||||
|
| T_constant (c, n) -> fprintf ppf "%s(%a)" c (list_sep_d type_value) n
|
||||||
|
|
||||||
|
and type_value ppf (tv:type_value) : unit =
|
||||||
|
type_value' ppf tv.type_value'
|
||||||
|
|
||||||
|
let rec annotated_expression ppf (ae:annotated_expression) : unit =
|
||||||
|
match ae.type_annotation.simplified with
|
||||||
|
| Some _ -> fprintf ppf "@[<v>%a:%a@]" expression ae.expression type_value ae.type_annotation
|
||||||
|
| _ -> fprintf ppf "@[<v>%a@]" expression ae.expression
|
||||||
|
|
||||||
|
and lambda ppf l =
|
||||||
|
let {binder;input_type;output_type;result;body} = l in
|
||||||
|
fprintf ppf "lambda (%s:%a) : %a {@; @[<v>%a@]@;} return %a"
|
||||||
|
binder type_value input_type type_value output_type
|
||||||
|
block body annotated_expression result
|
||||||
|
|
||||||
|
and expression ppf (e:expression) : unit =
|
||||||
|
match e with
|
||||||
|
| E_literal l -> literal ppf l
|
||||||
|
| E_constant (c, lst) -> fprintf ppf "%s(%a)" c (list_sep_d annotated_expression) lst
|
||||||
|
| E_constructor (c, lst) -> fprintf ppf "%s(%a)" c annotated_expression lst
|
||||||
|
| E_variable a -> fprintf ppf "%s" a
|
||||||
|
| E_application (f, arg) -> fprintf ppf "(%a) (%a)" annotated_expression f annotated_expression arg
|
||||||
|
| E_lambda l -> fprintf ppf "%a" lambda l
|
||||||
|
| E_tuple_accessor (ae, i) -> fprintf ppf "%a.%d" annotated_expression ae i
|
||||||
|
| E_record_accessor (ae, s) -> fprintf ppf "%a.%s" annotated_expression ae s
|
||||||
|
| E_tuple lst -> fprintf ppf "tuple[@; @[<v>%a@]@;]" (list_sep annotated_expression (tag ",@;")) lst
|
||||||
|
| E_record m -> fprintf ppf "record[%a]" (smap_sep_d annotated_expression) m
|
||||||
|
| E_map m -> fprintf ppf "map[@; @[<v>%a@]@;]" (list_sep assoc_annotated_expression (tag ",@;")) m
|
||||||
|
| E_list m -> fprintf ppf "list[@; @[<v>%a@]@;]" (list_sep annotated_expression (tag ",@;")) m
|
||||||
|
| E_look_up (ds, i) -> fprintf ppf "(%a)[%a]" annotated_expression ds annotated_expression i
|
||||||
|
| E_matching (ae, m) ->
|
||||||
|
fprintf ppf "match %a with %a" annotated_expression ae (matching annotated_expression) m
|
||||||
|
| E_failwith ae -> fprintf ppf "failwith %a" annotated_expression ae
|
||||||
|
|
||||||
|
and value ppf v = annotated_expression ppf v
|
||||||
|
|
||||||
|
and assoc_annotated_expression ppf : (ae * ae) -> unit = fun (a, b) ->
|
||||||
|
fprintf ppf "%a -> %a" annotated_expression a annotated_expression b
|
||||||
|
|
||||||
|
and literal ppf (l:literal) : unit =
|
||||||
|
match l with
|
||||||
|
| Literal_unit -> fprintf ppf "unit"
|
||||||
|
| Literal_bool b -> fprintf ppf "%b" b
|
||||||
|
| Literal_int n -> fprintf ppf "%d" n
|
||||||
|
| Literal_nat n -> fprintf ppf "+%d" n
|
||||||
|
| Literal_tez n -> fprintf ppf "%dtz" n
|
||||||
|
| Literal_string s -> fprintf ppf "%s" s
|
||||||
|
| Literal_bytes b -> fprintf ppf "0x%s" @@ Bytes.to_string @@ Bytes.escaped b
|
||||||
|
| Literal_address s -> fprintf ppf "@%s" s
|
||||||
|
| Literal_operation _ -> fprintf ppf "Operation(...bytes)"
|
||||||
|
|
||||||
|
and block ppf (b:block) = (list_sep instruction (tag "@;")) ppf b
|
||||||
|
|
||||||
|
and single_record_patch ppf ((s, ae) : string * ae) =
|
||||||
|
fprintf ppf "%s <- %a" s annotated_expression ae
|
||||||
|
|
||||||
|
and matching_variant_case : type a . (_ -> a -> unit) -> _ -> (constructor_name * name) * a -> unit =
|
||||||
|
fun f ppf ((c,n),a) ->
|
||||||
|
fprintf ppf "| %s %s -> %a" c n f a
|
||||||
|
|
||||||
|
and matching : type a . (formatter -> a -> unit) -> _ -> a matching -> unit = fun f ppf m -> match m with
|
||||||
|
| Match_tuple (lst, b) ->
|
||||||
|
fprintf ppf "let (%a) = %a" (list_sep_d (fun ppf -> fprintf ppf "%s")) lst f b
|
||||||
|
| Match_variant (lst , _) ->
|
||||||
|
fprintf ppf "%a" (list_sep (matching_variant_case f) (tag "@.")) lst
|
||||||
|
| Match_bool {match_true ; match_false} ->
|
||||||
|
fprintf ppf "| True -> %a @.| False -> %a" f match_true f match_false
|
||||||
|
| Match_list {match_nil ; match_cons = (hd, tl, match_cons)} ->
|
||||||
|
fprintf ppf "| Nil -> %a @.| %s :: %s -> %a" f match_nil hd tl f match_cons
|
||||||
|
| Match_option {match_none ; match_some = (some, match_some)} ->
|
||||||
|
fprintf ppf "| None -> %a @.| Some %s -> %a" f match_none (fst some) f match_some
|
||||||
|
|
||||||
|
and pre_access ppf (a:access) = match a with
|
||||||
|
| Access_record n -> fprintf ppf ".%s" n
|
||||||
|
| Access_tuple i -> fprintf ppf ".%d" i
|
||||||
|
| Access_map n -> fprintf ppf ".%a" annotated_expression n
|
||||||
|
|
||||||
|
and instruction ppf (i:instruction) = match i with
|
||||||
|
| I_skip -> fprintf ppf "skip"
|
||||||
|
| I_do ae -> fprintf ppf "do %a" annotated_expression ae
|
||||||
|
| I_loop (cond, b) -> fprintf ppf "while (%a) {@; @[<v>%a@]@;}" annotated_expression cond block b
|
||||||
|
| I_declaration {name;annotated_expression = ae} ->
|
||||||
|
fprintf ppf "let %s = %a" name annotated_expression ae
|
||||||
|
| I_assignment {name;annotated_expression = ae} ->
|
||||||
|
fprintf ppf "%s := %a" name annotated_expression ae
|
||||||
|
| I_matching (ae, m) ->
|
||||||
|
fprintf ppf "match %a with %a" annotated_expression ae (matching block) m
|
||||||
|
| I_patch (s, p, e) ->
|
||||||
|
fprintf ppf "%s%a := %a"
|
||||||
|
s.type_name (fun ppf -> List.iter (pre_access ppf)) p
|
||||||
|
annotated_expression e
|
||||||
|
|
||||||
|
let declaration ppf (d:declaration) =
|
||||||
|
match d with
|
||||||
|
| Declaration_constant ({name ; annotated_expression = ae} , _) ->
|
||||||
|
fprintf ppf "const %s = %a" name annotated_expression ae
|
||||||
|
|
||||||
|
let program ppf (p:program) =
|
||||||
|
fprintf ppf "@[<v>%a@]" (list_sep declaration (tag "@;")) (List.map Location.unwrap p)
|
12
ast_typed/ast_typed.ml
Normal file
12
ast_typed/ast_typed.ml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module Types = Types
|
||||||
|
module Environment = Environment
|
||||||
|
module PP = PP
|
||||||
|
module Combinators = struct
|
||||||
|
include Combinators
|
||||||
|
include Combinators_environment
|
||||||
|
end
|
||||||
|
module Misc = Misc
|
||||||
|
|
||||||
|
include Types
|
||||||
|
include Misc
|
||||||
|
include Combinators
|
213
ast_typed/combinators.ml
Normal file
213
ast_typed/combinators.ml
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
open Trace
|
||||||
|
open Types
|
||||||
|
|
||||||
|
let make_t type_value' simplified = { type_value' ; simplified }
|
||||||
|
let make_a_e expression type_annotation environment = { expression ; type_annotation ; dummy_field = () ; environment }
|
||||||
|
let make_n_e name a_e = { name ; annotated_expression = a_e }
|
||||||
|
|
||||||
|
let t_bool ?s () : type_value = make_t (T_constant ("bool", [])) s
|
||||||
|
let t_string ?s () : type_value = make_t (T_constant ("string", [])) s
|
||||||
|
let t_bytes ?s () : type_value = make_t (T_constant ("bytes", [])) s
|
||||||
|
let t_int ?s () : type_value = make_t (T_constant ("int", [])) s
|
||||||
|
let t_address ?s () : type_value = make_t (T_constant ("address", [])) s
|
||||||
|
let t_operation ?s () : type_value = make_t (T_constant ("operation", [])) s
|
||||||
|
let t_nat ?s () : type_value = make_t (T_constant ("nat", [])) s
|
||||||
|
let t_tez ?s () : type_value = make_t (T_constant ("tez", [])) s
|
||||||
|
let t_unit ?s () : type_value = make_t (T_constant ("unit", [])) s
|
||||||
|
let t_option o ?s () : type_value = make_t (T_constant ("option", [o])) s
|
||||||
|
let t_tuple lst ?s () : type_value = make_t (T_tuple lst) s
|
||||||
|
let t_list t ?s () : type_value = make_t (T_constant ("list", [t])) s
|
||||||
|
let t_contract t ?s () : type_value = make_t (T_constant ("contract", [t])) s
|
||||||
|
let t_pair a b ?s () = t_tuple [a ; b] ?s ()
|
||||||
|
|
||||||
|
|
||||||
|
let t_record m ?s () : type_value = make_t (T_record m) s
|
||||||
|
let make_t_ez_record (lst:(string * type_value) list) : type_value =
|
||||||
|
let aux prev (k, v) = SMap.add k v prev in
|
||||||
|
let map = List.fold_left aux SMap.empty lst in
|
||||||
|
make_t (T_record map) None
|
||||||
|
let ez_t_record lst ?s () : type_value =
|
||||||
|
let m = SMap.of_list lst in
|
||||||
|
t_record m ?s ()
|
||||||
|
|
||||||
|
let t_map key value ?s () = make_t (T_constant ("map", [key ; value])) s
|
||||||
|
|
||||||
|
let t_sum m ?s () : type_value = make_t (T_sum m) s
|
||||||
|
let make_t_ez_sum (lst:(string * type_value) list) : type_value =
|
||||||
|
let aux prev (k, v) = SMap.add k v prev in
|
||||||
|
let map = List.fold_left aux SMap.empty lst in
|
||||||
|
make_t (T_sum map) None
|
||||||
|
|
||||||
|
let t_function param result ?s () : type_value = make_t (T_function (param, result)) s
|
||||||
|
let t_shallow_closure param result ?s () : type_value = make_t (T_function (param, result)) s
|
||||||
|
|
||||||
|
let get_type_annotation (x:annotated_expression) = x.type_annotation
|
||||||
|
let get_type' (x:type_value) = x.type_value'
|
||||||
|
let get_environment (x:annotated_expression) = x.environment
|
||||||
|
let get_expression (x:annotated_expression) = x.expression
|
||||||
|
|
||||||
|
let get_t_bool (t:type_value) : unit result = match t.type_value' with
|
||||||
|
| T_constant ("bool", []) -> ok ()
|
||||||
|
| _ -> simple_fail "not a bool"
|
||||||
|
|
||||||
|
let get_t_unit (t:type_value) : unit result = match t.type_value' with
|
||||||
|
| T_constant ("unit", []) -> ok ()
|
||||||
|
| _ -> simple_fail "not a unit"
|
||||||
|
|
||||||
|
let get_t_tez (t:type_value) : unit result = match t.type_value' with
|
||||||
|
| T_constant ("tez", []) -> ok ()
|
||||||
|
| _ -> simple_fail "not a tez"
|
||||||
|
|
||||||
|
let get_t_contract (t:type_value) : type_value result = match t.type_value' with
|
||||||
|
| T_constant ("contract", [x]) -> ok x
|
||||||
|
| _ -> simple_fail "not a contract"
|
||||||
|
|
||||||
|
let get_t_option (t:type_value) : type_value result = match t.type_value' with
|
||||||
|
| T_constant ("option", [o]) -> ok o
|
||||||
|
| _ -> simple_fail "not a option"
|
||||||
|
|
||||||
|
let get_t_list (t:type_value) : type_value result = match t.type_value' with
|
||||||
|
| T_constant ("list", [o]) -> ok o
|
||||||
|
| _ -> simple_fail "not a list"
|
||||||
|
|
||||||
|
let get_t_tuple (t:type_value) : type_value list result = match t.type_value' with
|
||||||
|
| T_tuple lst -> ok lst
|
||||||
|
| _ -> simple_fail "not a tuple"
|
||||||
|
|
||||||
|
let get_t_pair (t:type_value) : (type_value * type_value) result = match t.type_value' with
|
||||||
|
| T_tuple lst ->
|
||||||
|
let%bind () =
|
||||||
|
trace_strong (simple_error "not a pair") @@
|
||||||
|
Assert.assert_list_size lst 2 in
|
||||||
|
ok List.(nth lst 0 , nth lst 1)
|
||||||
|
| _ -> simple_fail "not a tuple"
|
||||||
|
|
||||||
|
let get_t_function (t:type_value) : (type_value * type_value) result = match t.type_value' with
|
||||||
|
| T_function ar -> ok ar
|
||||||
|
| _ -> simple_fail "not a tuple"
|
||||||
|
|
||||||
|
let get_t_sum (t:type_value) : type_value SMap.t result = match t.type_value' with
|
||||||
|
| T_sum m -> ok m
|
||||||
|
| _ -> simple_fail "not a sum"
|
||||||
|
|
||||||
|
let get_t_record (t:type_value) : type_value SMap.t result = match t.type_value' with
|
||||||
|
| T_record m -> ok m
|
||||||
|
| _ -> simple_fail "not a record type"
|
||||||
|
|
||||||
|
let get_t_map (t:type_value) : (type_value * type_value) result =
|
||||||
|
match t.type_value' with
|
||||||
|
| T_constant ("map", [k;v]) -> ok (k, v)
|
||||||
|
| _ -> simple_fail "get: not a map"
|
||||||
|
|
||||||
|
let get_t_map_key : type_value -> type_value result = fun t ->
|
||||||
|
let%bind (key , _) = get_t_map t in
|
||||||
|
ok key
|
||||||
|
|
||||||
|
let get_t_map_value : type_value -> type_value result = fun t ->
|
||||||
|
let%bind (_ , value) = get_t_map t in
|
||||||
|
ok value
|
||||||
|
|
||||||
|
let assert_t_tez :type_value -> unit result = get_t_tez
|
||||||
|
|
||||||
|
let assert_t_map (t:type_value) : unit result =
|
||||||
|
match t.type_value' with
|
||||||
|
| T_constant ("map", [_ ; _]) -> ok ()
|
||||||
|
| _ -> simple_fail "not a map"
|
||||||
|
|
||||||
|
let assert_t_list (t:type_value) : unit result =
|
||||||
|
match t.type_value' with
|
||||||
|
| T_constant ("list", [_]) -> ok ()
|
||||||
|
| _ -> simple_fail "assert: not a list"
|
||||||
|
|
||||||
|
let assert_t_operation (t:type_value) : unit result =
|
||||||
|
match t.type_value' with
|
||||||
|
| T_constant ("operation" , []) -> ok ()
|
||||||
|
| _ -> simple_fail "assert: not an operation"
|
||||||
|
|
||||||
|
let assert_t_list_operation (t : type_value) : unit result =
|
||||||
|
let%bind t' = get_t_list t in
|
||||||
|
assert_t_operation t'
|
||||||
|
|
||||||
|
let assert_t_int : type_value -> unit result = fun t -> match t.type_value' with
|
||||||
|
| T_constant ("int", []) -> ok ()
|
||||||
|
| _ -> simple_fail "not an int"
|
||||||
|
|
||||||
|
let assert_t_nat : type_value -> unit result = fun t -> match t.type_value' with
|
||||||
|
| T_constant ("nat", []) -> ok ()
|
||||||
|
| _ -> simple_fail "not an nat"
|
||||||
|
|
||||||
|
let assert_t_bool : type_value -> unit result = fun v -> get_t_bool v
|
||||||
|
let assert_t_unit : type_value -> unit result = fun v -> get_t_unit v
|
||||||
|
|
||||||
|
let e_record map : expression = E_record map
|
||||||
|
let ez_e_record (lst : (string * ae) list) : expression =
|
||||||
|
let aux prev (k, v) = SMap.add k v prev in
|
||||||
|
let map = List.fold_left aux SMap.empty lst in
|
||||||
|
e_record map
|
||||||
|
let e_some s : expression = E_constant ("SOME", [s])
|
||||||
|
let e_none : expression = E_constant ("NONE", [])
|
||||||
|
|
||||||
|
let e_map lst : expression = E_map lst
|
||||||
|
|
||||||
|
let e_unit : expression = E_literal (Literal_unit)
|
||||||
|
let e_int n : expression = E_literal (Literal_int n)
|
||||||
|
let e_nat n : expression = E_literal (Literal_nat n)
|
||||||
|
let e_tez n : expression = E_literal (Literal_tez n)
|
||||||
|
let e_bool b : expression = E_literal (Literal_bool b)
|
||||||
|
let e_string s : expression = E_literal (Literal_string s)
|
||||||
|
let e_address s : expression = E_literal (Literal_address s)
|
||||||
|
let e_operation s : expression = E_literal (Literal_operation s)
|
||||||
|
let e_lambda l : expression = E_lambda l
|
||||||
|
let e_pair a b : expression = E_tuple [a; b]
|
||||||
|
let e_application a b : expression = E_application (a , b)
|
||||||
|
let e_variable v : expression = E_variable v
|
||||||
|
let e_list lst : expression = E_list lst
|
||||||
|
|
||||||
|
let e_a_unit = make_a_e e_unit (t_unit ())
|
||||||
|
let e_a_int n = make_a_e (e_int n) (t_int ())
|
||||||
|
let e_a_nat n = make_a_e (e_nat n) (t_nat ())
|
||||||
|
let e_a_tez n = make_a_e (e_tez n) (t_tez ())
|
||||||
|
let e_a_bool b = make_a_e (e_bool b) (t_bool ())
|
||||||
|
let e_a_string s = make_a_e (e_string s) (t_string ())
|
||||||
|
let e_a_address s = make_a_e (e_address s) (t_address ())
|
||||||
|
let e_a_pair a b = make_a_e (e_pair a b) (t_pair a.type_annotation b.type_annotation ())
|
||||||
|
let e_a_some s = make_a_e (e_some s) (t_option s.type_annotation ())
|
||||||
|
let e_a_lambda l = make_a_e (e_lambda l) (t_function l.input_type l.output_type ())
|
||||||
|
let e_a_none t = make_a_e e_none (t_option t ())
|
||||||
|
let e_a_tuple lst = make_a_e (E_tuple lst) (t_tuple (List.map get_type_annotation lst) ())
|
||||||
|
let e_a_record r = make_a_e (e_record r) (t_record (SMap.map get_type_annotation r) ())
|
||||||
|
let e_a_application a b = make_a_e (e_application a b) (get_type_annotation b)
|
||||||
|
let e_a_variable v ty = make_a_e (e_variable v) ty
|
||||||
|
let ez_e_a_record r = make_a_e (ez_e_record r) (ez_t_record (List.map (fun (x, y) -> x, y.type_annotation) r) ())
|
||||||
|
let e_a_map lst k v = make_a_e (e_map lst) (t_map k v ())
|
||||||
|
let e_a_list lst t = make_a_e (e_list lst) (t_list t ())
|
||||||
|
|
||||||
|
let get_a_int (t:annotated_expression) =
|
||||||
|
match t.expression with
|
||||||
|
| E_literal (Literal_int n) -> ok n
|
||||||
|
| _ -> simple_fail "not an int"
|
||||||
|
|
||||||
|
let get_a_unit (t:annotated_expression) =
|
||||||
|
match t.expression with
|
||||||
|
| E_literal (Literal_unit) -> ok ()
|
||||||
|
| _ -> simple_fail "not a unit"
|
||||||
|
|
||||||
|
let get_a_bool (t:annotated_expression) =
|
||||||
|
match t.expression with
|
||||||
|
| E_literal (Literal_bool b) -> ok b
|
||||||
|
| _ -> simple_fail "not a bool"
|
||||||
|
|
||||||
|
|
||||||
|
let get_a_record_accessor = fun t ->
|
||||||
|
match t.expression with
|
||||||
|
| E_record_accessor (a , b) -> ok (a , b)
|
||||||
|
| _ -> simple_fail "not an accessor"
|
||||||
|
|
||||||
|
let get_declaration_by_name : program -> string -> declaration result = fun p name ->
|
||||||
|
let aux : declaration -> bool = fun declaration ->
|
||||||
|
match declaration with
|
||||||
|
| Declaration_constant (d , _) -> d.name = name
|
||||||
|
in
|
||||||
|
trace_option (simple_error "no declaration with given name") @@
|
||||||
|
List.find_opt aux @@ List.map Location.unwrap p
|
||||||
|
|
28
ast_typed/combinators_environment.ml
Normal file
28
ast_typed/combinators_environment.ml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
open Types
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
let make_a_e_empty expression type_annotation = make_a_e expression type_annotation Environment.full_empty
|
||||||
|
|
||||||
|
let e_a_empty_unit = e_a_unit Environment.full_empty
|
||||||
|
let e_a_empty_int n = e_a_int n Environment.full_empty
|
||||||
|
let e_a_empty_nat n = e_a_nat n Environment.full_empty
|
||||||
|
let e_a_empty_tez n = e_a_tez n Environment.full_empty
|
||||||
|
let e_a_empty_bool b = e_a_bool b Environment.full_empty
|
||||||
|
let e_a_empty_string s = e_a_string s Environment.full_empty
|
||||||
|
let e_a_empty_address s = e_a_address s Environment.full_empty
|
||||||
|
let e_a_empty_pair a b = e_a_pair a b Environment.full_empty
|
||||||
|
let e_a_empty_some s = e_a_some s Environment.full_empty
|
||||||
|
let e_a_empty_none t = e_a_none t Environment.full_empty
|
||||||
|
let e_a_empty_tuple lst = e_a_tuple lst Environment.full_empty
|
||||||
|
let e_a_empty_record r = e_a_record r Environment.full_empty
|
||||||
|
let e_a_empty_map lst k v = e_a_map lst k v Environment.full_empty
|
||||||
|
let e_a_empty_list lst t = e_a_list lst t Environment.full_empty
|
||||||
|
let ez_e_a_empty_record r = ez_e_a_record r Environment.full_empty
|
||||||
|
let e_a_empty_lambda l = e_a_lambda l Environment.full_empty
|
||||||
|
|
||||||
|
open Environment
|
||||||
|
|
||||||
|
let env_sum_type ?(env = full_empty)
|
||||||
|
?(name = "a_sum_type")
|
||||||
|
(lst : (string * type_value) list) =
|
||||||
|
add_type name (make_t_ez_sum lst) env
|
13
ast_typed/dune
Normal file
13
ast_typed/dune
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
(library
|
||||||
|
(name ast_typed)
|
||||||
|
(public_name ligo.ast_typed)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
ast_simplified ; Is that a good idea?
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -open Simple_utils))
|
||||||
|
)
|
79
ast_typed/environment.ml
Normal file
79
ast_typed/environment.ml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
open Types
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
type element = environment_element
|
||||||
|
let make_element : type_value -> full_environment -> environment_element_definition -> element =
|
||||||
|
fun type_value source_environment definition -> {type_value ; source_environment ; definition}
|
||||||
|
|
||||||
|
let make_element_binder = fun t s -> make_element t s ED_binder
|
||||||
|
let make_element_declaration = fun t s d -> make_element t s (ED_declaration d)
|
||||||
|
|
||||||
|
module Small = struct
|
||||||
|
type t = small_environment
|
||||||
|
|
||||||
|
let empty : t = ([] , [])
|
||||||
|
|
||||||
|
let get_environment : t -> environment = fst
|
||||||
|
let get_type_environment : t -> type_environment = snd
|
||||||
|
let map_environment : _ -> t -> t = fun f (a , b) -> (f a , b)
|
||||||
|
let map_type_environment : _ -> t -> t = fun f (a , b) -> (a , f b)
|
||||||
|
|
||||||
|
let add : string -> element -> t -> t = fun k v -> map_environment (fun x -> (k , v) :: x)
|
||||||
|
let add_type : string -> type_value -> t -> t = fun k v -> map_type_environment (fun x -> (k , v) :: x)
|
||||||
|
let get_opt : string -> t -> element option = fun k x -> List.assoc_opt k (get_environment x)
|
||||||
|
let get_type_opt : string -> t -> type_value option = fun k x -> List.assoc_opt k (get_type_environment x)
|
||||||
|
end
|
||||||
|
|
||||||
|
type t = full_environment
|
||||||
|
let empty : environment = Small.(get_environment empty)
|
||||||
|
let full_empty : t = List.Ne.singleton Small.empty
|
||||||
|
let add : string -> element -> t -> t = fun k v -> List.Ne.hd_map (Small.add k v)
|
||||||
|
let add_ez_binder : string -> type_value -> t -> t = fun k v e ->
|
||||||
|
List.Ne.hd_map (Small.add k (make_element_binder v e)) e
|
||||||
|
let add_ez_declaration : string -> type_value -> expression -> t -> t = fun k v expr e ->
|
||||||
|
List.Ne.hd_map (Small.add k (make_element_declaration v e expr)) e
|
||||||
|
let add_ez_ae : string -> annotated_expression -> t -> t = fun k ae e ->
|
||||||
|
add_ez_declaration k (get_type_annotation ae) (get_expression ae) e
|
||||||
|
let add_type : string -> type_value -> t -> t = fun k v -> List.Ne.hd_map (Small.add_type k v)
|
||||||
|
let get_opt : string -> t -> element option = fun k x -> List.Ne.find_map (Small.get_opt k) x
|
||||||
|
let get_type_opt : string -> t -> type_value option = fun k x -> List.Ne.find_map (Small.get_type_opt k) x
|
||||||
|
|
||||||
|
let get_constructor : string -> t -> (type_value * type_value) option = fun k x -> (* Left is the constructor, right is the sum type *)
|
||||||
|
let aux = fun x ->
|
||||||
|
let aux = fun (_type_name , x) ->
|
||||||
|
match x.type_value' with
|
||||||
|
| T_sum m when Map.String.mem k m -> Some (Map.String.find k m , x)
|
||||||
|
| _ -> None
|
||||||
|
in
|
||||||
|
List.find_map aux (Small.get_type_environment x) in
|
||||||
|
List.Ne.find_map aux x
|
||||||
|
|
||||||
|
|
||||||
|
module PP = struct
|
||||||
|
open Format
|
||||||
|
open PP_helpers
|
||||||
|
|
||||||
|
let list_sep_scope x = list_sep x (const " | ")
|
||||||
|
|
||||||
|
let environment_element = fun ppf (k , (ele : environment_element)) ->
|
||||||
|
fprintf ppf "%s -> %a" k PP.type_value ele.type_value
|
||||||
|
|
||||||
|
let type_environment_element = fun ppf (k , tv) ->
|
||||||
|
fprintf ppf "%s -> %a" k PP.type_value tv
|
||||||
|
|
||||||
|
let environment : _ -> environment -> unit = fun ppf lst ->
|
||||||
|
fprintf ppf "E[%a]" (list_sep environment_element (const " , ")) lst
|
||||||
|
|
||||||
|
let type_environment = fun ppf lst ->
|
||||||
|
fprintf ppf "T[%a]" (list_sep type_environment_element (const " , ")) lst
|
||||||
|
|
||||||
|
let small_environment : _ -> small_environment -> unit = fun ppf e ->
|
||||||
|
fprintf ppf "- %a\t%a"
|
||||||
|
environment (Small.get_environment e)
|
||||||
|
type_environment (Small.get_type_environment e)
|
||||||
|
|
||||||
|
let full_environment : _ -> full_environment -> unit = fun ppf e ->
|
||||||
|
fprintf ppf "@[%a]"
|
||||||
|
(ne_list_sep small_environment (tag "@;")) e
|
||||||
|
end
|
||||||
|
|
417
ast_typed/misc.ml
Normal file
417
ast_typed/misc.ml
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
open Trace
|
||||||
|
open Types
|
||||||
|
|
||||||
|
module Errors = struct
|
||||||
|
let different_kinds a b () =
|
||||||
|
let title = (thunk "different kinds") in
|
||||||
|
let full () = Format.asprintf "(%a) VS (%a)" PP.type_value a PP.type_value b in
|
||||||
|
error title full ()
|
||||||
|
|
||||||
|
let different_constants a b () =
|
||||||
|
let title = (thunk "different constants") in
|
||||||
|
let full () = Format.asprintf "%s VS %s" a b in
|
||||||
|
error title full ()
|
||||||
|
|
||||||
|
let different_size_type name a b () =
|
||||||
|
let title () = name ^ " have different sizes" in
|
||||||
|
let full () = Format.asprintf "%a VS %a" PP.type_value a PP.type_value b in
|
||||||
|
error title full ()
|
||||||
|
|
||||||
|
let different_size_constants = different_size_type "constants"
|
||||||
|
|
||||||
|
let different_size_tuples = different_size_type "tuples"
|
||||||
|
|
||||||
|
let different_size_sums = different_size_type "sums"
|
||||||
|
|
||||||
|
let different_size_records = different_size_type "records"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Free_variables = struct
|
||||||
|
|
||||||
|
type bindings = string list
|
||||||
|
let mem : string -> bindings -> bool = List.mem
|
||||||
|
let singleton : string -> bindings = fun s -> [ s ]
|
||||||
|
let union : bindings -> bindings -> bindings = (@)
|
||||||
|
let unions : bindings list -> bindings = List.concat
|
||||||
|
let empty : bindings = []
|
||||||
|
let of_list : string list -> bindings = fun x -> x
|
||||||
|
|
||||||
|
let rec expression : bindings -> expression -> bindings = fun b e ->
|
||||||
|
let self = annotated_expression b in
|
||||||
|
match e with
|
||||||
|
| E_lambda l -> lambda b l
|
||||||
|
| E_literal _ -> empty
|
||||||
|
| E_constant (_ , lst) -> unions @@ List.map self lst
|
||||||
|
| E_variable name -> (
|
||||||
|
match mem name b with
|
||||||
|
| true -> empty
|
||||||
|
| false -> singleton name
|
||||||
|
)
|
||||||
|
| E_application (a, b) -> unions @@ List.map self [ a ; b ]
|
||||||
|
| E_tuple lst -> unions @@ List.map self lst
|
||||||
|
| E_constructor (_ , a) -> self a
|
||||||
|
| E_record m -> unions @@ List.map self @@ Map.String.to_list m
|
||||||
|
| E_record_accessor (a, _) -> self a
|
||||||
|
| E_tuple_accessor (a, _) -> self a
|
||||||
|
| E_list lst -> unions @@ List.map self lst
|
||||||
|
| E_map m -> unions @@ List.map self @@ List.concat @@ List.map (fun (a, b) -> [ a ; b ]) m
|
||||||
|
| E_look_up (a , b) -> unions @@ List.map self [ a ; b ]
|
||||||
|
| E_matching (a , cs) -> union (self a) (matching_expression b cs)
|
||||||
|
| E_failwith a -> self a
|
||||||
|
|
||||||
|
and lambda : bindings -> lambda -> bindings = fun b l ->
|
||||||
|
let b' = union (singleton l.binder) b in
|
||||||
|
let (b'', frees) = block' b' l.body in
|
||||||
|
union (annotated_expression b'' l.result) frees
|
||||||
|
|
||||||
|
and annotated_expression : bindings -> annotated_expression -> bindings = fun b ae ->
|
||||||
|
expression b ae.expression
|
||||||
|
|
||||||
|
and instruction' : bindings -> instruction -> bindings * bindings = fun b i ->
|
||||||
|
match i with
|
||||||
|
| I_declaration n -> union (singleton n.name) b , (annotated_expression b n.annotated_expression)
|
||||||
|
| I_assignment n -> b , (annotated_expression b n.annotated_expression)
|
||||||
|
| I_skip -> b , empty
|
||||||
|
| I_do e -> b , annotated_expression b e
|
||||||
|
| I_loop (a , bl) -> b , union (annotated_expression b a) (block b bl)
|
||||||
|
| I_patch (_ , _ , a) -> b , annotated_expression b a
|
||||||
|
| I_matching (a , cs) -> b , union (annotated_expression b a) (matching_block b cs)
|
||||||
|
|
||||||
|
and block' : bindings -> block -> (bindings * bindings) = fun b bl ->
|
||||||
|
let aux = fun (binds, frees) cur ->
|
||||||
|
let (binds', frees') = instruction' binds cur in
|
||||||
|
(binds', union frees frees') in
|
||||||
|
List.fold_left aux (b , []) bl
|
||||||
|
|
||||||
|
and block : bindings -> block -> bindings = fun b bl ->
|
||||||
|
let (_ , frees) = block' b bl in
|
||||||
|
frees
|
||||||
|
|
||||||
|
and matching_variant_case : type a . (bindings -> a -> bindings) -> bindings -> ((constructor_name * name) * a) -> bindings = fun f b ((_,n),c) ->
|
||||||
|
f (union (singleton n) b) c
|
||||||
|
|
||||||
|
and matching : type a . (bindings -> a -> bindings) -> bindings -> a matching -> bindings = fun f b m ->
|
||||||
|
match m with
|
||||||
|
| Match_bool { match_true = t ; match_false = fa } -> union (f b t) (f b fa)
|
||||||
|
| Match_list { match_nil = n ; match_cons = (hd, tl, c) } -> union (f b n) (f (union (of_list [hd ; tl]) b) c)
|
||||||
|
| Match_option { match_none = n ; match_some = ((opt, _), s) } -> union (f b n) (f (union (singleton opt) b) s)
|
||||||
|
| Match_tuple (lst , a) -> f (union (of_list lst) b) a
|
||||||
|
| Match_variant (lst , _) -> unions @@ List.map (matching_variant_case f b) lst
|
||||||
|
|
||||||
|
and matching_expression = fun x -> matching annotated_expression x
|
||||||
|
|
||||||
|
and matching_block = fun x -> matching block x
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
(* module Dependencies = struct
|
||||||
|
*
|
||||||
|
* type bindings = string list
|
||||||
|
* let mem : string -> bindings -> bool = List.mem
|
||||||
|
* let singleton : string -> bindings = fun s -> [ s ]
|
||||||
|
* let union : bindings -> bindings -> bindings = (@)
|
||||||
|
* let unions : bindings list -> bindings = List.concat
|
||||||
|
* let empty : bindings = []
|
||||||
|
* let of_list : string list -> bindings = fun x -> x
|
||||||
|
*
|
||||||
|
* let rec expression : bindings -> full_environment -> expression -> bindings = fun b _env e ->
|
||||||
|
* let self = annotated_expression b in
|
||||||
|
* match e with
|
||||||
|
* | E_lambda l ->
|
||||||
|
* let b' = union (singleton l.binder) b in
|
||||||
|
* let (b'', frees) = block' b' l.body in
|
||||||
|
* union (annotated_expression b'' l.result) frees
|
||||||
|
* | E_literal _ -> empty
|
||||||
|
* | E_constant (_ , lst) -> unions @@ List.map self lst
|
||||||
|
* | E_variable name -> (
|
||||||
|
* match mem name b with
|
||||||
|
* | true -> empty
|
||||||
|
* | false -> singleton name
|
||||||
|
* )
|
||||||
|
* | E_application (a, b) -> unions @@ List.map self [ a ; b ]
|
||||||
|
* | E_tuple lst -> unions @@ List.map self lst
|
||||||
|
* | E_constructor (_ , a) -> self a
|
||||||
|
* | E_record m -> unions @@ List.map self @@ Map.String.to_list m
|
||||||
|
* | E_record_accessor (a, _) -> self a
|
||||||
|
* | E_tuple_accessor (a, _) -> self a
|
||||||
|
* | E_list lst -> unions @@ List.map self lst
|
||||||
|
* | E_map m -> unions @@ List.map self @@ List.concat @@ List.map (fun (a, b) -> [ a ; b ]) m
|
||||||
|
* | E_look_up (a , b) -> unions @@ List.map self [ a ; b ]
|
||||||
|
* | E_matching (a , cs) -> union (self a) (matching_expression b cs)
|
||||||
|
* | E_failwith a -> self a
|
||||||
|
*
|
||||||
|
* and annotated_expression : bindings -> annotated_expression -> bindings = fun b ae ->
|
||||||
|
* let open Combinators in
|
||||||
|
* expression b (get_environment ae) (get_expression ae)
|
||||||
|
*
|
||||||
|
* and instruction' : bindings -> instruction -> bindings * bindings = fun b i ->
|
||||||
|
* match i with
|
||||||
|
* | I_declaration n -> union (singleton n.name) b , (annotated_expression b n.annotated_expression)
|
||||||
|
* | I_assignment n -> b , (annotated_expression b n.annotated_expression)
|
||||||
|
* | I_skip -> b , empty
|
||||||
|
* | I_do e -> b , annotated_expression b e
|
||||||
|
* | I_loop (a , bl) -> b , union (annotated_expression b a) (block b bl)
|
||||||
|
* | I_patch (_ , _ , a) -> b , annotated_expression b a
|
||||||
|
* | I_matching (a , cs) -> b , union (annotated_expression b a) (matching_block b cs)
|
||||||
|
*
|
||||||
|
* and block' : bindings -> block -> (bindings * bindings) = fun b bl ->
|
||||||
|
* let aux = fun (binds, frees) cur ->
|
||||||
|
* let (binds', frees') = instruction' binds cur in
|
||||||
|
* (binds', union frees frees') in
|
||||||
|
* List.fold_left aux (b , []) bl
|
||||||
|
*
|
||||||
|
* and block : bindings -> block -> bindings = fun b bl ->
|
||||||
|
* let (_ , frees) = block' b bl in
|
||||||
|
* frees
|
||||||
|
*
|
||||||
|
* and matching_variant_case : type a . (bindings -> a -> bindings) -> bindings -> ((constructor_name * name) * a) -> bindings = fun f b ((_,n),c) ->
|
||||||
|
* f (union (singleton n) b) c
|
||||||
|
*
|
||||||
|
* and matching : type a . (bindings -> a -> bindings) -> bindings -> a matching -> bindings = fun f b m ->
|
||||||
|
* match m with
|
||||||
|
* | Match_bool { match_true = t ; match_false = fa } -> union (f b t) (f b fa)
|
||||||
|
* | Match_list { match_nil = n ; match_cons = (hd, tl, c) } -> union (f b n) (f (union (of_list [hd ; tl]) b) c)
|
||||||
|
* | Match_option { match_none = n ; match_some = ((opt, _), s) } -> union (f b n) (f (union (singleton opt) b) s)
|
||||||
|
* | Match_tuple (lst , a) -> f (union (of_list lst) b) a
|
||||||
|
* | Match_variant (lst , _) -> unions @@ List.map (matching_variant_case f b) lst
|
||||||
|
*
|
||||||
|
* and matching_expression = fun x -> matching annotated_expression x
|
||||||
|
*
|
||||||
|
* and matching_block = fun x -> matching block x
|
||||||
|
*
|
||||||
|
* end *)
|
||||||
|
|
||||||
|
|
||||||
|
open Errors
|
||||||
|
|
||||||
|
let rec assert_type_value_eq (a, b: (type_value * type_value)) : unit result = match (a.type_value', b.type_value') with
|
||||||
|
| T_tuple ta, T_tuple tb -> (
|
||||||
|
let%bind _ =
|
||||||
|
trace_strong (fun () -> (different_size_tuples a b ()))
|
||||||
|
@@ Assert.assert_true List.(length ta = length tb) in
|
||||||
|
bind_list_iter assert_type_value_eq (List.combine ta tb)
|
||||||
|
)
|
||||||
|
| T_tuple _, _ -> fail @@ different_kinds a b
|
||||||
|
| T_constant (ca, lsta), T_constant (cb, lstb) -> (
|
||||||
|
let%bind _ =
|
||||||
|
trace_strong (different_size_constants a b)
|
||||||
|
@@ Assert.assert_true List.(length lsta = length lstb) in
|
||||||
|
let%bind _ =
|
||||||
|
trace_strong (different_constants ca cb)
|
||||||
|
@@ Assert.assert_true (ca = cb) in
|
||||||
|
trace (simple_error "constant sub-expression")
|
||||||
|
@@ bind_list_iter assert_type_value_eq (List.combine lsta lstb)
|
||||||
|
)
|
||||||
|
| T_constant _, _ -> fail @@ different_kinds a b
|
||||||
|
| T_sum sa, T_sum sb -> (
|
||||||
|
let sa' = SMap.to_kv_list sa in
|
||||||
|
let sb' = SMap.to_kv_list sb in
|
||||||
|
let aux ((ka, va), (kb, vb)) =
|
||||||
|
let%bind _ =
|
||||||
|
Assert.assert_true ~msg:"different keys in sum types"
|
||||||
|
@@ (ka = kb) in
|
||||||
|
assert_type_value_eq (va, vb)
|
||||||
|
in
|
||||||
|
let%bind _ =
|
||||||
|
trace_strong (different_size_sums a b)
|
||||||
|
@@ Assert.assert_list_same_size sa' sb' in
|
||||||
|
trace (simple_error "sum type") @@
|
||||||
|
bind_list_iter aux (List.combine sa' sb')
|
||||||
|
|
||||||
|
)
|
||||||
|
| T_sum _, _ -> fail @@ different_kinds a b
|
||||||
|
| T_record ra, T_record rb -> (
|
||||||
|
let ra' = SMap.to_kv_list ra in
|
||||||
|
let rb' = SMap.to_kv_list rb in
|
||||||
|
let aux ((ka, va), (kb, vb)) =
|
||||||
|
let%bind _ =
|
||||||
|
let error =
|
||||||
|
let title () = "different props in record" in
|
||||||
|
let content () = Format.asprintf "%s vs %s" ka kb in
|
||||||
|
error title content in
|
||||||
|
trace_strong error @@
|
||||||
|
Assert.assert_true (ka = kb) in
|
||||||
|
assert_type_value_eq (va, vb)
|
||||||
|
in
|
||||||
|
let%bind _ =
|
||||||
|
trace_strong (different_size_records a b)
|
||||||
|
@@ Assert.assert_list_same_size ra' rb' in
|
||||||
|
trace (simple_error "record type")
|
||||||
|
@@ bind_list_iter aux (List.combine ra' rb')
|
||||||
|
|
||||||
|
)
|
||||||
|
| T_record _, _ -> fail @@ different_kinds a b
|
||||||
|
| T_function (param, result), T_function (param', result') ->
|
||||||
|
let%bind _ = assert_type_value_eq (param, param') in
|
||||||
|
let%bind _ = assert_type_value_eq (result, result') in
|
||||||
|
ok ()
|
||||||
|
| T_function _, _ -> fail @@ different_kinds a b
|
||||||
|
|
||||||
|
(* No information about what made it fail *)
|
||||||
|
let type_value_eq ab = Trace.to_bool @@ assert_type_value_eq ab
|
||||||
|
|
||||||
|
let assert_literal_eq (a, b : literal * literal) : unit result =
|
||||||
|
match (a, b) with
|
||||||
|
| Literal_bool a, Literal_bool b when a = b -> ok ()
|
||||||
|
| Literal_bool _, Literal_bool _ -> simple_fail "different bools"
|
||||||
|
| Literal_bool _, _ -> simple_fail "bool vs non-bool"
|
||||||
|
| Literal_int a, Literal_int b when a = b -> ok ()
|
||||||
|
| Literal_int _, Literal_int _ -> simple_fail "different ints"
|
||||||
|
| Literal_int _, _ -> simple_fail "int vs non-int"
|
||||||
|
| Literal_nat a, Literal_nat b when a = b -> ok ()
|
||||||
|
| Literal_nat _, Literal_nat _ -> simple_fail "different nats"
|
||||||
|
| Literal_nat _, _ -> simple_fail "nat vs non-nat"
|
||||||
|
| Literal_tez a, Literal_tez b when a = b -> ok ()
|
||||||
|
| Literal_tez _, Literal_tez _ -> simple_fail "different tezs"
|
||||||
|
| Literal_tez _, _ -> simple_fail "tez vs non-tez"
|
||||||
|
| Literal_string a, Literal_string b when a = b -> ok ()
|
||||||
|
| Literal_string _, Literal_string _ -> simple_fail "different strings"
|
||||||
|
| Literal_string _, _ -> simple_fail "string vs non-string"
|
||||||
|
| Literal_bytes a, Literal_bytes b when a = b -> ok ()
|
||||||
|
| Literal_bytes _, Literal_bytes _ -> simple_fail "different bytess"
|
||||||
|
| Literal_bytes _, _ -> simple_fail "bytes vs non-bytes"
|
||||||
|
| Literal_unit, Literal_unit -> ok ()
|
||||||
|
| Literal_unit, _ -> simple_fail "unit vs non-unit"
|
||||||
|
| Literal_address a, Literal_address b when a = b -> ok ()
|
||||||
|
| Literal_address _, Literal_address _ -> simple_fail "different addresss"
|
||||||
|
| Literal_address _, _ -> simple_fail "address vs non-address"
|
||||||
|
| Literal_operation _, Literal_operation _ -> simple_fail "can't compare operations"
|
||||||
|
| Literal_operation _, _ -> simple_fail "operation vs non-operation"
|
||||||
|
|
||||||
|
|
||||||
|
let rec assert_value_eq (a, b: (value*value)) : unit result =
|
||||||
|
let error_content () =
|
||||||
|
Format.asprintf "\n%a vs %a" PP.value a PP.value b
|
||||||
|
in
|
||||||
|
trace (fun () -> error (thunk "not equal") error_content ()) @@
|
||||||
|
match (a.expression, b.expression) with
|
||||||
|
| E_literal a, E_literal b ->
|
||||||
|
assert_literal_eq (a, b)
|
||||||
|
| E_constant (ca, lsta), E_constant (cb, lstb) when ca = cb -> (
|
||||||
|
let%bind lst =
|
||||||
|
generic_try (simple_error "constants with different number of elements")
|
||||||
|
(fun () -> List.combine lsta lstb) in
|
||||||
|
let%bind _all = bind_list @@ List.map assert_value_eq lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_constant _, E_constant _ ->
|
||||||
|
simple_fail "different constants"
|
||||||
|
| E_constant _, _ ->
|
||||||
|
let error_content () =
|
||||||
|
Format.asprintf "%a vs %a"
|
||||||
|
PP.annotated_expression a
|
||||||
|
PP.annotated_expression b
|
||||||
|
in
|
||||||
|
fail @@ (fun () -> error (thunk "comparing constant with other stuff") error_content ())
|
||||||
|
|
||||||
|
| E_constructor (ca, a), E_constructor (cb, b) when ca = cb -> (
|
||||||
|
let%bind _eq = assert_value_eq (a, b) in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_constructor _, E_constructor _ ->
|
||||||
|
simple_fail "different constructors"
|
||||||
|
| E_constructor _, _ ->
|
||||||
|
simple_fail "comparing constructor with other stuff"
|
||||||
|
|
||||||
|
| E_tuple lsta, E_tuple lstb -> (
|
||||||
|
let%bind lst =
|
||||||
|
generic_try (simple_error "tuples with different number of elements")
|
||||||
|
(fun () -> List.combine lsta lstb) in
|
||||||
|
let%bind _all = bind_list @@ List.map assert_value_eq lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_tuple _, _ ->
|
||||||
|
simple_fail "comparing tuple with other stuff"
|
||||||
|
|
||||||
|
| E_record sma, E_record smb -> (
|
||||||
|
let aux _ a b =
|
||||||
|
match a, b with
|
||||||
|
| Some a, Some b -> Some (assert_value_eq (a, b))
|
||||||
|
| _ -> Some (simple_fail "different record keys")
|
||||||
|
in
|
||||||
|
let%bind _all = bind_smap @@ SMap.merge aux sma smb in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_record _, _ ->
|
||||||
|
simple_fail "comparing record with other stuff"
|
||||||
|
|
||||||
|
| E_map lsta, E_map lstb -> (
|
||||||
|
let%bind lst = generic_try (simple_error "maps of different lengths")
|
||||||
|
(fun () ->
|
||||||
|
let lsta' = List.sort compare lsta in
|
||||||
|
let lstb' = List.sort compare lstb in
|
||||||
|
List.combine lsta' lstb') in
|
||||||
|
let aux = fun ((ka, va), (kb, vb)) ->
|
||||||
|
let%bind _ = assert_value_eq (ka, kb) in
|
||||||
|
let%bind _ = assert_value_eq (va, vb) in
|
||||||
|
ok () in
|
||||||
|
let%bind _all = bind_map_list aux lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_map _, _ ->
|
||||||
|
simple_fail "comparing map with other stuff"
|
||||||
|
|
||||||
|
| E_list lsta, E_list lstb -> (
|
||||||
|
let%bind lst =
|
||||||
|
generic_try (simple_error "list of different lengths")
|
||||||
|
(fun () -> List.combine lsta lstb) in
|
||||||
|
let%bind _all = bind_map_list assert_value_eq lst in
|
||||||
|
ok ()
|
||||||
|
)
|
||||||
|
| E_list _, _ ->
|
||||||
|
simple_fail "comparing list with other stuff"
|
||||||
|
|
||||||
|
| _, _ -> simple_fail "comparing not a value"
|
||||||
|
|
||||||
|
let merge_annotation (a:type_value option) (b:type_value option) : type_value result =
|
||||||
|
match a, b with
|
||||||
|
| None, None -> simple_fail "no annotation"
|
||||||
|
| Some a, None -> ok a
|
||||||
|
| None, Some b -> ok b
|
||||||
|
| Some a, Some b ->
|
||||||
|
let%bind _ = assert_type_value_eq (a, b) in
|
||||||
|
match a.simplified, b.simplified with
|
||||||
|
| _, None -> ok a
|
||||||
|
| _, Some _ -> ok b
|
||||||
|
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
let program_to_main : program -> string -> lambda result = fun p s ->
|
||||||
|
let%bind (main , input_type , output_type) =
|
||||||
|
let pred = fun d ->
|
||||||
|
match d with
|
||||||
|
| Declaration_constant (d , _) when d.name = s -> Some d.annotated_expression
|
||||||
|
| Declaration_constant _ -> None
|
||||||
|
in
|
||||||
|
let%bind main =
|
||||||
|
trace_option (simple_error "no main with given name") @@
|
||||||
|
List.find_map (Function.compose pred Location.unwrap) p in
|
||||||
|
let%bind (input_ty , output_ty) =
|
||||||
|
match (get_type' @@ get_type_annotation main) with
|
||||||
|
| T_function (i , o) -> ok (i , o)
|
||||||
|
| _ -> simple_fail "program main isn't a function" in
|
||||||
|
ok (main , input_ty , output_ty)
|
||||||
|
in
|
||||||
|
let body =
|
||||||
|
let aux : declaration -> instruction = fun d ->
|
||||||
|
match d with
|
||||||
|
| Declaration_constant (d , _) -> I_declaration d in
|
||||||
|
List.map (Function.compose aux Location.unwrap) p in
|
||||||
|
let env =
|
||||||
|
let aux = fun _ d ->
|
||||||
|
match d with
|
||||||
|
| Declaration_constant (_ , env) -> env in
|
||||||
|
List.fold_left aux Environment.full_empty (List.map Location.unwrap p) in
|
||||||
|
let binder = "@contract_input" in
|
||||||
|
let result =
|
||||||
|
let input_expr = e_a_variable binder input_type env in
|
||||||
|
let main_expr = e_a_variable s (get_type_annotation main) env in
|
||||||
|
e_a_application main_expr input_expr env in
|
||||||
|
ok {
|
||||||
|
binder ;
|
||||||
|
input_type ;
|
||||||
|
output_type ;
|
||||||
|
body ;
|
||||||
|
result ;
|
||||||
|
}
|
169
ast_typed/types.ml
Normal file
169
ast_typed/types.ml
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
[@@@warning "-30"]
|
||||||
|
|
||||||
|
module S = Ast_simplified
|
||||||
|
|
||||||
|
module SMap = Map.String
|
||||||
|
|
||||||
|
type name = string
|
||||||
|
type type_name = string
|
||||||
|
type constructor_name = string
|
||||||
|
|
||||||
|
type 'a name_map = 'a SMap.t
|
||||||
|
type 'a type_name_map = 'a SMap.t
|
||||||
|
|
||||||
|
type program = declaration Location.wrap list
|
||||||
|
|
||||||
|
and declaration =
|
||||||
|
| Declaration_constant of (named_expression * full_environment)
|
||||||
|
(* | Macro_declaration of macro_declaration *)
|
||||||
|
|
||||||
|
and environment_element_definition =
|
||||||
|
| ED_binder
|
||||||
|
| ED_declaration of expression
|
||||||
|
|
||||||
|
and environment_element = {
|
||||||
|
type_value : type_value ;
|
||||||
|
source_environment : full_environment ;
|
||||||
|
definition : environment_element_definition ;
|
||||||
|
}
|
||||||
|
and environment = (string * environment_element) list
|
||||||
|
and type_environment = (string * type_value) list
|
||||||
|
and small_environment = (environment * type_environment)
|
||||||
|
and full_environment = small_environment List.Ne.t
|
||||||
|
|
||||||
|
and annotated_expression = {
|
||||||
|
expression: expression ;
|
||||||
|
type_annotation: tv ;
|
||||||
|
environment: full_environment ;
|
||||||
|
dummy_field: unit ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and named_expression = {
|
||||||
|
name: name ;
|
||||||
|
annotated_expression: ae ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and tv = type_value
|
||||||
|
and ae = annotated_expression
|
||||||
|
and tv_map = type_value type_name_map
|
||||||
|
and ae_map = annotated_expression name_map
|
||||||
|
|
||||||
|
and type_value' =
|
||||||
|
| T_tuple of tv list
|
||||||
|
| T_sum of tv_map
|
||||||
|
| T_record of tv_map
|
||||||
|
| T_constant of type_name * tv list
|
||||||
|
| T_function of (tv * tv)
|
||||||
|
|
||||||
|
and type_value = {
|
||||||
|
type_value' : type_value' ;
|
||||||
|
simplified : S.type_expression option ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and named_type_value = {
|
||||||
|
type_name: name ;
|
||||||
|
type_value : type_value ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and lambda = {
|
||||||
|
binder: name ;
|
||||||
|
input_type: tv ;
|
||||||
|
output_type: tv ;
|
||||||
|
result: ae ;
|
||||||
|
body: block ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and expression =
|
||||||
|
(* Base *)
|
||||||
|
| E_literal of literal
|
||||||
|
| E_constant of (name * ae list) (* For language constants, like (Cons hd tl) or (plus i j) *)
|
||||||
|
| E_variable of name
|
||||||
|
| E_application of (ae * ae)
|
||||||
|
| E_lambda of lambda
|
||||||
|
(* Tuple *)
|
||||||
|
| E_tuple of ae list
|
||||||
|
| E_tuple_accessor of (ae * int) (* Access n'th tuple's element *)
|
||||||
|
(* Sum *)
|
||||||
|
| E_constructor of (name * ae) (* For user defined constructors *)
|
||||||
|
(* Record *)
|
||||||
|
| E_record of ae_map
|
||||||
|
| E_record_accessor of (ae * string)
|
||||||
|
(* Data Structures *)
|
||||||
|
| E_map of (ae * ae) list
|
||||||
|
| E_list of ae list
|
||||||
|
| E_look_up of (ae * ae)
|
||||||
|
(* Advanced *)
|
||||||
|
| E_matching of (ae * matching_expr)
|
||||||
|
| E_failwith of ae
|
||||||
|
|
||||||
|
and value = annotated_expression (* todo (for refactoring) *)
|
||||||
|
|
||||||
|
and literal =
|
||||||
|
| Literal_unit
|
||||||
|
| Literal_bool of bool
|
||||||
|
| Literal_int of int
|
||||||
|
| Literal_nat of int
|
||||||
|
| Literal_tez of int
|
||||||
|
| Literal_string of string
|
||||||
|
| Literal_bytes of bytes
|
||||||
|
| Literal_address of string
|
||||||
|
| Literal_operation of Memory_proto_alpha.Alpha_context.packed_internal_operation
|
||||||
|
|
||||||
|
and block = instruction list
|
||||||
|
and b = block
|
||||||
|
|
||||||
|
and instruction =
|
||||||
|
| I_declaration of named_expression
|
||||||
|
| I_assignment of named_expression
|
||||||
|
| I_matching of ae * matching_instr
|
||||||
|
| I_loop of ae * b
|
||||||
|
| I_do of ae
|
||||||
|
| I_skip
|
||||||
|
| I_patch of named_type_value * access_path * ae
|
||||||
|
|
||||||
|
and access =
|
||||||
|
| Access_tuple of int
|
||||||
|
| Access_record of string
|
||||||
|
| Access_map of ae
|
||||||
|
|
||||||
|
and access_path = access list
|
||||||
|
|
||||||
|
and 'a matching =
|
||||||
|
| Match_bool of {
|
||||||
|
match_true : 'a ;
|
||||||
|
match_false : 'a ;
|
||||||
|
}
|
||||||
|
| Match_list of {
|
||||||
|
match_nil : 'a ;
|
||||||
|
match_cons : name * name * 'a ;
|
||||||
|
}
|
||||||
|
| Match_option of {
|
||||||
|
match_none : 'a ;
|
||||||
|
match_some : (name * type_value) * 'a ;
|
||||||
|
}
|
||||||
|
| Match_tuple of (name list * 'a)
|
||||||
|
| Match_variant of (((constructor_name * name) * 'a) list * type_value)
|
||||||
|
|
||||||
|
and matching_instr = b matching
|
||||||
|
|
||||||
|
and matching_expr = ae matching
|
||||||
|
|
||||||
|
open Trace
|
||||||
|
|
||||||
|
let get_entry (p:program) (entry : string) : annotated_expression result =
|
||||||
|
let aux (d:declaration) =
|
||||||
|
match d with
|
||||||
|
| Declaration_constant ({name ; annotated_expression} , _) when entry = name -> Some annotated_expression
|
||||||
|
| Declaration_constant _ -> None
|
||||||
|
in
|
||||||
|
let%bind result =
|
||||||
|
trace_option (simple_error "no entry point with given name") @@
|
||||||
|
List.find_map aux (List.map Location.unwrap p) in
|
||||||
|
ok result
|
||||||
|
|
||||||
|
let get_functional_entry (p:program) (entry : string) : (lambda * type_value) result =
|
||||||
|
let%bind entry = get_entry p entry in
|
||||||
|
match entry.expression with
|
||||||
|
| E_lambda l -> ok (l, entry.type_annotation)
|
||||||
|
| _ -> simple_fail "given entry point is not functional"
|
||||||
|
|
107
bin/cli.ml
Normal file
107
bin/cli.ml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
open Cmdliner
|
||||||
|
open Trace
|
||||||
|
|
||||||
|
let toplevel x =
|
||||||
|
match x with
|
||||||
|
| Trace.Ok ((), annotations) -> ignore annotations; ()
|
||||||
|
| Errors ss ->
|
||||||
|
Format.printf "Errors: %a\n%!" errors_pp @@ List.map (fun f -> f()) ss
|
||||||
|
|
||||||
|
let main =
|
||||||
|
let term = Term.(const print_endline $ const "Ligo needs a command. Do ligo --help") in
|
||||||
|
(term , Term.info "ligo")
|
||||||
|
|
||||||
|
let compile_file =
|
||||||
|
let f source entry_point =
|
||||||
|
toplevel @@
|
||||||
|
let%bind contract =
|
||||||
|
trace (simple_error "compile michelson") @@
|
||||||
|
Ligo.Contract.compile_contract_file source entry_point in
|
||||||
|
Format.printf "Contract:\n%s\n" contract ;
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
let term =
|
||||||
|
let source =
|
||||||
|
let open Arg in
|
||||||
|
let info =
|
||||||
|
let docv = "SOURCE_FILE" in
|
||||||
|
let doc = "$(docv) is the path to the .ligo file of the contract." in
|
||||||
|
info ~docv ~doc [] in
|
||||||
|
required @@ pos 0 (some string) None info in
|
||||||
|
let entry_point =
|
||||||
|
let open Arg in
|
||||||
|
let info =
|
||||||
|
let docv = "ENTRY_POINT" in
|
||||||
|
let doc = "$(docv) is entry-point that will be compiled." in
|
||||||
|
info ~docv ~doc [] in
|
||||||
|
value @@ pos 1 string "main" info in
|
||||||
|
Term.(const f $ source $ entry_point) in
|
||||||
|
let docs = "Compile contracts." in
|
||||||
|
(term , Term.info ~docs "compile-contract")
|
||||||
|
|
||||||
|
let compile_parameter =
|
||||||
|
let f source entry_point expression =
|
||||||
|
toplevel @@
|
||||||
|
let%bind value =
|
||||||
|
trace (simple_error "compile-input") @@
|
||||||
|
Ligo.Contract.compile_contract_parameter source entry_point expression in
|
||||||
|
Format.printf "Input:\n%s\n" value;
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
let term =
|
||||||
|
let source =
|
||||||
|
let open Arg in
|
||||||
|
let docv = "SOURCE_FILE" in
|
||||||
|
let doc = "$(docv) is the path to the .ligo file of the contract." in
|
||||||
|
let info = info ~docv ~doc [] in
|
||||||
|
required @@ pos 0 (some string) None info in
|
||||||
|
let entry_point =
|
||||||
|
let open Arg in
|
||||||
|
let docv = "ENTRY_POINT" in
|
||||||
|
let doc = "$(docv) is the entry-point of the contract." in
|
||||||
|
let info = info ~docv ~doc [] in
|
||||||
|
required @@ pos 1 (some string) None info in
|
||||||
|
let expression =
|
||||||
|
let open Arg in
|
||||||
|
let docv = "EXPRESSION" in
|
||||||
|
let doc = "$(docv) is the expression that will be compiled." in
|
||||||
|
let info = info ~docv ~doc [] in
|
||||||
|
required @@ pos 2 (some string) None info in
|
||||||
|
Term.(const f $ source $ entry_point $ expression) in
|
||||||
|
let docs = "Compile contracts parameters." in
|
||||||
|
(term , Term.info ~docs "compile-parameter")
|
||||||
|
|
||||||
|
let compile_storage =
|
||||||
|
let f source entry_point expression =
|
||||||
|
toplevel @@
|
||||||
|
let%bind value =
|
||||||
|
trace (simple_error "compile-storage") @@
|
||||||
|
Ligo.Contract.compile_contract_storage source entry_point expression in
|
||||||
|
Format.printf "Storage:\n%s\n" value;
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
let term =
|
||||||
|
let source =
|
||||||
|
let open Arg in
|
||||||
|
let docv = "SOURCE_FILE" in
|
||||||
|
let doc = "$(docv) is the path to the .ligo file of the contract." in
|
||||||
|
let info = info ~docv ~doc [] in
|
||||||
|
required @@ pos 0 (some string) None info in
|
||||||
|
let entry_point =
|
||||||
|
let open Arg in
|
||||||
|
let docv = "ENTRY_POINT" in
|
||||||
|
let doc = "$(docv) is the entry-point of the contract." in
|
||||||
|
let info = info ~docv ~doc [] in
|
||||||
|
required @@ pos 1 (some string) None info in
|
||||||
|
let expression =
|
||||||
|
let open Arg in
|
||||||
|
let docv = "EXPRESSION" in
|
||||||
|
let doc = "$(docv) is the expression that will be compiled." in
|
||||||
|
let info = info ~docv ~doc [] in
|
||||||
|
required @@ pos 2 (some string) None info in
|
||||||
|
Term.(const f $ source $ entry_point $ expression) in
|
||||||
|
let docs = "Compile contracts storage." in
|
||||||
|
(term , Term.info ~docs "compile-storage")
|
||||||
|
|
||||||
|
|
||||||
|
let () = Term.exit @@ Term.eval_choice main [compile_file ; compile_parameter ; compile_storage]
|
14
bin/dune
Normal file
14
bin/dune
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
(executable
|
||||||
|
(name cli)
|
||||||
|
(public_name ligo)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
cmdliner
|
||||||
|
ligo
|
||||||
|
)
|
||||||
|
(package ligo)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -open Simple_utils))
|
||||||
|
)
|
6
compiler/compiler.ml
Normal file
6
compiler/compiler.ml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module Uncompiler = Uncompiler
|
||||||
|
module Program = Compiler_program
|
||||||
|
module Type = Compiler_type
|
||||||
|
module Environment = Compiler_environment
|
||||||
|
|
||||||
|
include Program
|
277
compiler/compiler_environment.ml
Normal file
277
compiler/compiler_environment.ml
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
open Trace
|
||||||
|
open Mini_c
|
||||||
|
open Environment
|
||||||
|
open Micheline.Michelson
|
||||||
|
open Memory_proto_alpha.Script_ir_translator
|
||||||
|
|
||||||
|
module Stack = Meta_michelson.Stack
|
||||||
|
|
||||||
|
let get : environment -> string -> michelson result = fun e s ->
|
||||||
|
let%bind (type_value , position) =
|
||||||
|
let error =
|
||||||
|
let title () = "Environment.get" in
|
||||||
|
let content () = Format.asprintf "%s in %a"
|
||||||
|
s PP.environment e in
|
||||||
|
error title content in
|
||||||
|
generic_try error @@
|
||||||
|
(fun () -> Environment.get_i s e) in
|
||||||
|
let rec aux = fun n ->
|
||||||
|
match n with
|
||||||
|
| 0 -> i_dup
|
||||||
|
| n -> seq [
|
||||||
|
dip @@ aux (n - 1) ;
|
||||||
|
i_swap ;
|
||||||
|
]
|
||||||
|
in
|
||||||
|
let code = aux position in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let error () = ok @@ simple_error "error producing Env.get" in
|
||||||
|
let%bind (Stack.Ex_stack_ty input_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let%bind (Ex_ty ty) = Compiler_type.Ty.type_ type_value in
|
||||||
|
let output_stack_ty = Stack.(ty @: input_stack_ty) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
let set : environment -> string -> michelson result = fun e s ->
|
||||||
|
let%bind (type_value , position) =
|
||||||
|
generic_try (simple_error "Environment.get") @@
|
||||||
|
(fun () -> Environment.get_i s e) in
|
||||||
|
let rec aux = fun n ->
|
||||||
|
match n with
|
||||||
|
| 0 -> dip i_drop
|
||||||
|
| n -> seq [
|
||||||
|
i_swap ;
|
||||||
|
dip (aux (n - 1)) ;
|
||||||
|
]
|
||||||
|
in
|
||||||
|
let code = aux position in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let error () = ok @@ simple_error "error producing Env.set" in
|
||||||
|
let%bind (Stack.Ex_stack_ty env_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let%bind (Ex_ty ty) = Compiler_type.Ty.type_ type_value in
|
||||||
|
let input_stack_ty = Stack.(ty @: env_stack_ty) in
|
||||||
|
let output_stack_ty = env_stack_ty in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
let add : environment -> (string * type_value) -> michelson result = fun e (_s , type_value) ->
|
||||||
|
let code = seq [] in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let error () = ok @@ simple_error "error producing Env.get" in
|
||||||
|
let%bind (Stack.Ex_stack_ty env_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let%bind (Ex_ty ty) = Compiler_type.Ty.type_ type_value in
|
||||||
|
let input_stack_ty = Stack.(ty @: env_stack_ty) in
|
||||||
|
let output_stack_ty = Stack.(ty @: env_stack_ty) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
let select : environment -> string list -> michelson result = fun e lst ->
|
||||||
|
let module L = Logger.Stateful() in
|
||||||
|
let e_lst =
|
||||||
|
let e_lst = Environment.to_list e in
|
||||||
|
let aux selector (s , _) =
|
||||||
|
L.log @@ Format.asprintf "Selector : %a\n" PP_helpers.(list_sep string (const " , ")) selector ;
|
||||||
|
match List.mem s selector with
|
||||||
|
| true -> List.remove_element s selector , true
|
||||||
|
| false -> selector , false in
|
||||||
|
let e_lst' = List.fold_map_right aux lst e_lst in
|
||||||
|
let e_lst'' = List.combine e_lst e_lst' in
|
||||||
|
e_lst'' in
|
||||||
|
let code =
|
||||||
|
let aux = fun code (_ , b) ->
|
||||||
|
match b with
|
||||||
|
| false -> seq [dip code ; i_drop]
|
||||||
|
| true -> dip code
|
||||||
|
in
|
||||||
|
List.fold_right' aux (seq []) e_lst in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let%bind (Stack.Ex_stack_ty input_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let e' =
|
||||||
|
Environment.of_list
|
||||||
|
@@ List.map fst
|
||||||
|
@@ List.filter snd
|
||||||
|
@@ e_lst
|
||||||
|
in
|
||||||
|
let%bind (Stack.Ex_stack_ty output_stack_ty) = Compiler_type.Ty.environment e' in
|
||||||
|
let error () =
|
||||||
|
let title () = "error producing Env.select" in
|
||||||
|
let content () = Format.asprintf "\nInput : %a\nOutput : %a\nList : {%a}\nCode : %a\nLog : %s\n"
|
||||||
|
PP.environment e
|
||||||
|
PP.environment e'
|
||||||
|
PP_helpers.(list_sep (pair PP.environment_element bool) (const " || ")) e_lst
|
||||||
|
Micheline.Michelson.pp code
|
||||||
|
(L.get ())
|
||||||
|
in
|
||||||
|
ok @@ (error title content) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
let clear : environment -> michelson result = fun e -> select e []
|
||||||
|
|
||||||
|
let select_env : environment -> environment -> michelson result = fun e e' ->
|
||||||
|
let lst = Environment.get_names e' in
|
||||||
|
select e lst
|
||||||
|
|
||||||
|
let pack : environment -> michelson result = fun e ->
|
||||||
|
let%bind () =
|
||||||
|
trace_strong (simple_error "pack empty env") @@
|
||||||
|
Assert.assert_true (List.length e <> 0) in
|
||||||
|
let code = seq @@ List.map (Function.constant i_pair) @@ List.tl e in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let%bind (Stack.Ex_stack_ty input_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let repr = Environment.closure_representation e in
|
||||||
|
let%bind (Ex_ty output_ty) = Compiler_type.Ty.type_ repr in
|
||||||
|
let output_stack_ty = Stack.(output_ty @: nil) in
|
||||||
|
let error () =
|
||||||
|
let title () = "error producing Env.pack" in
|
||||||
|
let content () = Format.asprintf ""
|
||||||
|
in
|
||||||
|
ok @@ (error title content) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
let unpack : environment -> michelson result = fun e ->
|
||||||
|
let%bind () =
|
||||||
|
trace_strong (simple_error "unpack empty env") @@
|
||||||
|
Assert.assert_true (List.length e <> 0) in
|
||||||
|
|
||||||
|
let l = List.length e - 1 in
|
||||||
|
let rec aux n =
|
||||||
|
match n with
|
||||||
|
| 0 -> seq []
|
||||||
|
| n -> seq [
|
||||||
|
i_unpair ;
|
||||||
|
dip (aux (n - 1)) ;
|
||||||
|
] in
|
||||||
|
let code = aux l in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let%bind (Stack.Ex_stack_ty output_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let repr = Environment.closure_representation e in
|
||||||
|
let%bind (Ex_ty input_ty) = Compiler_type.Ty.type_ repr in
|
||||||
|
let input_stack_ty = Stack.(input_ty @: nil) in
|
||||||
|
let error () =
|
||||||
|
let title () = "error producing Env.unpack" in
|
||||||
|
let content () = Format.asprintf "\nEnvironment:%a\nType Representation:%a\nCode:%a\n"
|
||||||
|
PP.environment e
|
||||||
|
PP.type_ repr
|
||||||
|
Micheline.Michelson.pp code
|
||||||
|
in
|
||||||
|
ok @@ (error title content) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
|
||||||
|
let pack_select : environment -> string list -> michelson result = fun e lst ->
|
||||||
|
let module L = Logger.Stateful() in
|
||||||
|
let e_lst =
|
||||||
|
let e_lst = Environment.to_list e in
|
||||||
|
let aux selector (s , _) =
|
||||||
|
L.log @@ Format.asprintf "Selector : %a\n" PP_helpers.(list_sep string (const " , ")) selector ;
|
||||||
|
match List.mem s selector with
|
||||||
|
| true -> List.remove_element s selector , true
|
||||||
|
| false -> selector , false in
|
||||||
|
let e_lst' = List.fold_map_right aux lst e_lst in
|
||||||
|
let e_lst'' = List.combine e_lst e_lst' in
|
||||||
|
e_lst'' in
|
||||||
|
let (_ , code) =
|
||||||
|
let aux = fun (first , code) (_ , b) ->
|
||||||
|
match b with
|
||||||
|
| false -> (first , seq [dip code ; i_swap])
|
||||||
|
| true -> (false ,
|
||||||
|
match first with
|
||||||
|
| true -> i_dup
|
||||||
|
| false -> seq [dip code ; i_dup ; dip i_pair ; i_swap]
|
||||||
|
)
|
||||||
|
in
|
||||||
|
List.fold_right' aux (true , seq []) e_lst in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let%bind (Stack.Ex_stack_ty input_stack_ty) = Compiler_type.Ty.environment e in
|
||||||
|
let e' =
|
||||||
|
Environment.of_list
|
||||||
|
@@ List.map fst
|
||||||
|
@@ List.filter snd
|
||||||
|
@@ e_lst
|
||||||
|
in
|
||||||
|
let%bind (Ex_ty output_ty) = Compiler_type.Ty.environment_representation e' in
|
||||||
|
let output_stack_ty = Stack.(output_ty @: input_stack_ty) in
|
||||||
|
let error () =
|
||||||
|
let title () = "error producing Env.pack_select" in
|
||||||
|
let content () = Format.asprintf "\nInput : %a\nOutput : %a\nList : {%a}\nCode : %a\nLog : %s\n"
|
||||||
|
PP.environment e
|
||||||
|
PP.environment e'
|
||||||
|
PP_helpers.(list_sep (pair PP.environment_element bool) (const " || ")) e_lst
|
||||||
|
Micheline.Michelson.pp code
|
||||||
|
(L.get ())
|
||||||
|
in
|
||||||
|
ok @@ (error title content) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
let add_packed_anon : environment -> type_value -> michelson result = fun e type_value ->
|
||||||
|
let code = seq [i_pair] in
|
||||||
|
|
||||||
|
let%bind () =
|
||||||
|
let error () = ok @@ simple_error "error producing add packed" in
|
||||||
|
let%bind (Ex_ty input_ty) = Compiler_type.Ty.environment_representation e in
|
||||||
|
let e' = Environment.add ("_add_packed_anon" , type_value) e in
|
||||||
|
let%bind (Ex_ty output_ty) = Compiler_type.Ty.environment_representation e' in
|
||||||
|
let%bind (Ex_ty ty) = Compiler_type.Ty.type_ type_value in
|
||||||
|
let input_stack_ty = Stack.(ty @: input_ty @: nil) in
|
||||||
|
let output_stack_ty = Stack.(output_ty @: nil) in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r error @@
|
||||||
|
Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
540
compiler/compiler_program.ml
Normal file
540
compiler/compiler_program.ml
Normal file
@ -0,0 +1,540 @@
|
|||||||
|
open Trace
|
||||||
|
open Mini_c
|
||||||
|
|
||||||
|
module Michelson = Micheline.Michelson
|
||||||
|
open Michelson
|
||||||
|
module Stack = Meta_michelson.Stack
|
||||||
|
module Contract_types = Meta_michelson.Types
|
||||||
|
|
||||||
|
open Memory_proto_alpha.Script_ir_translator
|
||||||
|
|
||||||
|
open Operators.Compiler
|
||||||
|
|
||||||
|
let get_predicate : string -> type_value -> expression list -> predicate result = fun s ty lst ->
|
||||||
|
match Map.String.find_opt s Operators.Compiler.predicates with
|
||||||
|
| Some x -> ok x
|
||||||
|
| None -> (
|
||||||
|
match s with
|
||||||
|
| "MAP_REMOVE" ->
|
||||||
|
let%bind v = match lst with
|
||||||
|
| [ _ ; expr ] ->
|
||||||
|
let%bind (_, v) = Mini_c.Combinators.(get_t_map (Expression.get_type expr)) in
|
||||||
|
ok v
|
||||||
|
| _ -> simple_fail "mini_c . MAP_REMOVE" in
|
||||||
|
let%bind v_ty = Compiler_type.type_ v in
|
||||||
|
ok @@ simple_binary @@ seq [dip (i_none v_ty) ; prim I_UPDATE ]
|
||||||
|
| "LEFT" ->
|
||||||
|
let%bind r = match lst with
|
||||||
|
| [ _ ] -> get_t_right ty
|
||||||
|
| _ -> simple_fail "mini_c . LEFT" in
|
||||||
|
let%bind r_ty = Compiler_type.type_ r in
|
||||||
|
ok @@ simple_unary @@ prim ~children:[r_ty] I_LEFT
|
||||||
|
| "RIGHT" ->
|
||||||
|
let%bind l = match lst with
|
||||||
|
| [ _ ] -> get_t_left ty
|
||||||
|
| _ -> simple_fail "mini_c . RIGHT" in
|
||||||
|
let%bind l_ty = Compiler_type.type_ l in
|
||||||
|
ok @@ simple_unary @@ prim ~children:[l_ty] I_RIGHT
|
||||||
|
| "CONTRACT" ->
|
||||||
|
let%bind r = match lst with
|
||||||
|
| [ _ ] -> get_t_contract ty
|
||||||
|
| _ -> simple_fail "mini_c . CONTRACT" in
|
||||||
|
let%bind r_ty = Compiler_type.type_ r in
|
||||||
|
ok @@ simple_unary @@ seq [
|
||||||
|
prim ~children:[r_ty] I_CONTRACT ;
|
||||||
|
i_assert_some_msg (i_push_string "bad address for get_contract") ;
|
||||||
|
]
|
||||||
|
| x -> simple_fail ("predicate \"" ^ x ^ "\" doesn't exist")
|
||||||
|
)
|
||||||
|
|
||||||
|
let rec translate_value (v:value) : michelson result = match v with
|
||||||
|
| D_bool b -> ok @@ prim (if b then D_True else D_False)
|
||||||
|
| D_int n -> ok @@ int (Z.of_int n)
|
||||||
|
| D_nat n -> ok @@ int (Z.of_int n)
|
||||||
|
| D_tez n -> ok @@ int (Z.of_int n)
|
||||||
|
| D_string s -> ok @@ string s
|
||||||
|
| D_bytes s -> ok @@ bytes (Tezos_stdlib.MBytes.of_bytes s)
|
||||||
|
| D_unit -> ok @@ prim D_Unit
|
||||||
|
| D_pair (a, b) -> (
|
||||||
|
let%bind a = translate_value a in
|
||||||
|
let%bind b = translate_value b in
|
||||||
|
ok @@ prim ~children:[a;b] D_Pair
|
||||||
|
)
|
||||||
|
| D_left a -> translate_value a >>? fun a -> ok @@ prim ~children:[a] D_Left
|
||||||
|
| D_right b -> translate_value b >>? fun b -> ok @@ prim ~children:[b] D_Right
|
||||||
|
| D_function anon -> translate_function anon
|
||||||
|
| D_none -> ok @@ prim D_None
|
||||||
|
| D_some s ->
|
||||||
|
let%bind s' = translate_value s in
|
||||||
|
ok @@ prim ~children:[s'] D_Some
|
||||||
|
| D_map lst ->
|
||||||
|
let%bind lst' = bind_map_list (bind_map_pair translate_value) lst in
|
||||||
|
let aux (a, b) = prim ~children:[a;b] D_Elt in
|
||||||
|
ok @@ seq @@ List.map aux lst'
|
||||||
|
| D_list lst ->
|
||||||
|
let%bind lst' = bind_map_list translate_value lst in
|
||||||
|
ok @@ seq lst'
|
||||||
|
| D_operation _ ->
|
||||||
|
simple_fail "can't compile an operation"
|
||||||
|
|
||||||
|
and translate_function (content:anon_function) : michelson result =
|
||||||
|
let%bind body = translate_quote_body content in
|
||||||
|
ok @@ seq [ body ]
|
||||||
|
|
||||||
|
and translate_expression ?(first=false) (expr:expression) (env:environment) : (michelson * environment) result =
|
||||||
|
let (expr' , ty) = Combinators.Expression.(get_content expr , get_type expr) in
|
||||||
|
let error_message () = Format.asprintf "%a" PP.expression expr in
|
||||||
|
|
||||||
|
let return ?env' code =
|
||||||
|
let env' =
|
||||||
|
let default = env in
|
||||||
|
Environment.add ("_tmp_expression" , ty) @@ Option.unopt ~default env' in
|
||||||
|
let%bind (Stack.Ex_stack_ty input_stack_ty) = Compiler_type.Ty.environment env in
|
||||||
|
let%bind output_type = Compiler_type.type_ ty in
|
||||||
|
let%bind (Stack.Ex_stack_ty output_stack_ty) = Compiler_type.Ty.environment env' in
|
||||||
|
let error_message () =
|
||||||
|
let%bind schema_michelsons = Compiler_type.environment env in
|
||||||
|
ok @@ Format.asprintf
|
||||||
|
"expression : %a\ncode : %a\nschema type : %a\noutput type : %a"
|
||||||
|
PP.expression expr
|
||||||
|
Michelson.pp code
|
||||||
|
PP_helpers.(list_sep Michelson.pp (const ".")) schema_michelsons
|
||||||
|
Michelson.pp output_type
|
||||||
|
in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r
|
||||||
|
(fun () ->
|
||||||
|
let%bind error_message = error_message () in
|
||||||
|
ok @@ (fun () -> error (thunk "error parsing expression code")
|
||||||
|
(fun () -> error_message)
|
||||||
|
())) @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty
|
||||||
|
in
|
||||||
|
ok (code , env')
|
||||||
|
in
|
||||||
|
|
||||||
|
trace (error (thunk "compiling expression") error_message) @@
|
||||||
|
match expr' with
|
||||||
|
| E_capture_environment c ->
|
||||||
|
let%bind code = Compiler_environment.pack_select env c in
|
||||||
|
return @@ code
|
||||||
|
| E_literal v ->
|
||||||
|
let%bind v = translate_value v in
|
||||||
|
let%bind t = Compiler_type.type_ ty in
|
||||||
|
return @@ i_push t v
|
||||||
|
| E_application(f, arg) -> (
|
||||||
|
match Combinators.Expression.get_type f with
|
||||||
|
| T_function _ -> (
|
||||||
|
trace (simple_error "Compiling quote application") @@
|
||||||
|
let%bind (f , env') = translate_expression ~first f env in
|
||||||
|
let%bind (arg , _) = translate_expression arg env' in
|
||||||
|
return @@ seq [
|
||||||
|
i_comment "quote application" ;
|
||||||
|
i_comment "get f" ;
|
||||||
|
f ;
|
||||||
|
i_comment "get arg" ;
|
||||||
|
arg ;
|
||||||
|
prim I_EXEC ;
|
||||||
|
]
|
||||||
|
)
|
||||||
|
| T_deep_closure (small_env, input_ty , _) -> (
|
||||||
|
trace (simple_error "Compiling deep closure application") @@
|
||||||
|
let%bind (arg' , env') = translate_expression arg env in
|
||||||
|
let%bind (f' , env'') = translate_expression f env' in
|
||||||
|
let%bind f_ty = Compiler_type.type_ f.type_value in
|
||||||
|
let%bind append_closure = Compiler_environment.add_packed_anon small_env input_ty in
|
||||||
|
let error =
|
||||||
|
let error_title () = "michelson type-checking closure application" in
|
||||||
|
let error_content () =
|
||||||
|
Format.asprintf "\nEnv. %a\nEnv'. %a\nEnv''. %a\nclosure. %a ; %a ; %a\narg. %a\n"
|
||||||
|
PP.environment env
|
||||||
|
PP.environment env'
|
||||||
|
PP.environment env''
|
||||||
|
PP.expression_with_type f Michelson.pp f_ty Michelson.pp f'
|
||||||
|
PP.expression_with_type arg
|
||||||
|
in
|
||||||
|
error error_title error_content
|
||||||
|
in
|
||||||
|
trace error @@
|
||||||
|
return @@ seq [
|
||||||
|
i_comment "closure application" ;
|
||||||
|
i_comment "arg" ;
|
||||||
|
arg' ;
|
||||||
|
i_comment "f'" ;
|
||||||
|
f' ; i_unpair ;
|
||||||
|
i_comment "append" ;
|
||||||
|
dip @@ seq [i_swap ; append_closure] ;
|
||||||
|
i_comment "exec" ;
|
||||||
|
i_swap ; i_exec ;
|
||||||
|
]
|
||||||
|
)
|
||||||
|
| _ -> simple_fail "E_applicationing something not appliable"
|
||||||
|
)
|
||||||
|
| E_variable x ->
|
||||||
|
let%bind code = Compiler_environment.get env x in
|
||||||
|
return code
|
||||||
|
| E_constant(str, lst) ->
|
||||||
|
let module L = Logger.Stateful() in
|
||||||
|
let%bind lst' =
|
||||||
|
let aux env expr =
|
||||||
|
let%bind (code , env') = translate_expression expr env in
|
||||||
|
L.log @@ Format.asprintf "\n%a -> %a in %a\n"
|
||||||
|
PP.expression expr
|
||||||
|
Michelson.pp code
|
||||||
|
PP.environment env ;
|
||||||
|
ok (env' , code)
|
||||||
|
in
|
||||||
|
bind_fold_map_right_list aux env lst in
|
||||||
|
let%bind predicate = get_predicate str ty lst in
|
||||||
|
let pre_code = seq @@ List.rev lst' in
|
||||||
|
let%bind code = match (predicate, List.length lst) with
|
||||||
|
| Constant c, 0 -> ok @@ seq [
|
||||||
|
pre_code ;
|
||||||
|
c ;
|
||||||
|
]
|
||||||
|
| Unary f, 1 -> ok @@ seq [
|
||||||
|
pre_code ;
|
||||||
|
f ;
|
||||||
|
]
|
||||||
|
| Binary f, 2 -> ok @@ seq [
|
||||||
|
pre_code ;
|
||||||
|
f ;
|
||||||
|
]
|
||||||
|
| Ternary f, 3 -> ok @@ seq [
|
||||||
|
pre_code ;
|
||||||
|
f ;
|
||||||
|
]
|
||||||
|
| _ -> simple_fail "bad arity"
|
||||||
|
in
|
||||||
|
let error =
|
||||||
|
let title () = "error compiling constant" in
|
||||||
|
let content () = L.get () in
|
||||||
|
error title content in
|
||||||
|
trace error @@
|
||||||
|
return code
|
||||||
|
| E_empty_map sd ->
|
||||||
|
let%bind (src, dst) = bind_map_pair Compiler_type.type_ sd in
|
||||||
|
return @@ i_empty_map src dst
|
||||||
|
| E_empty_list t ->
|
||||||
|
let%bind t' = Compiler_type.type_ t in
|
||||||
|
return @@ i_nil t'
|
||||||
|
| E_make_none o ->
|
||||||
|
let%bind o' = Compiler_type.type_ o in
|
||||||
|
return @@ i_none o'
|
||||||
|
| E_Cond (c, a, b) -> (
|
||||||
|
let%bind (c' , env') = translate_expression c env in
|
||||||
|
let%bind (a' , _) = translate_expression a env' in
|
||||||
|
let%bind (b' , _) = translate_expression b env' in
|
||||||
|
let%bind code = ok (seq [
|
||||||
|
c' ;
|
||||||
|
i_if a' b' ;
|
||||||
|
]) in
|
||||||
|
return code
|
||||||
|
)
|
||||||
|
| E_if_none (c, n, (_ , s)) -> (
|
||||||
|
let%bind (c' , _env') = translate_expression c env in
|
||||||
|
let%bind (n' , _) = translate_expression n n.environment in
|
||||||
|
let%bind (s' , _) = translate_expression s s.environment in
|
||||||
|
let%bind restrict_s = Compiler_environment.select_env s.environment env in
|
||||||
|
let%bind code = ok (seq [
|
||||||
|
c' ;
|
||||||
|
i_if_none n' (seq [
|
||||||
|
s' ;
|
||||||
|
restrict_s ;
|
||||||
|
])
|
||||||
|
;
|
||||||
|
]) in
|
||||||
|
return code
|
||||||
|
)
|
||||||
|
| E_if_left (c, (_ , l), (_ , r)) -> (
|
||||||
|
let%bind (c' , _env') = translate_expression c env in
|
||||||
|
let%bind (l' , _) = translate_expression l l.environment in
|
||||||
|
let%bind (r' , _) = translate_expression r r.environment in
|
||||||
|
let%bind restrict_l = Compiler_environment.select_env l.environment env in
|
||||||
|
let%bind restrict_r = Compiler_environment.select_env r.environment env in
|
||||||
|
let%bind code = ok (seq [
|
||||||
|
c' ;
|
||||||
|
i_if_left (seq [
|
||||||
|
l' ;
|
||||||
|
i_comment "restrict left" ;
|
||||||
|
dip restrict_l ;
|
||||||
|
]) (seq [
|
||||||
|
r' ;
|
||||||
|
i_comment "restrict right" ;
|
||||||
|
dip restrict_r ;
|
||||||
|
])
|
||||||
|
;
|
||||||
|
]) in
|
||||||
|
return code
|
||||||
|
)
|
||||||
|
| E_let_in (v, expr , body) -> (
|
||||||
|
let%bind (expr' , _) = translate_expression expr env in
|
||||||
|
let env' = Environment.add v env in
|
||||||
|
let%bind (body' , _) = translate_expression body env' in
|
||||||
|
let%bind restrict = Compiler_environment.select_env env' env in
|
||||||
|
let%bind code = ok (seq [
|
||||||
|
expr' ;
|
||||||
|
body' ;
|
||||||
|
i_comment "restrict let" ;
|
||||||
|
dip restrict ;
|
||||||
|
]) in
|
||||||
|
return code
|
||||||
|
)
|
||||||
|
|
||||||
|
and translate_statement ((s', w_env) as s:statement) : michelson result =
|
||||||
|
let error_message () = Format.asprintf "%a" PP.statement s in
|
||||||
|
let return code =
|
||||||
|
let%bind (Stack.Ex_stack_ty input_stack_ty) = Compiler_type.Ty.environment w_env.pre_environment in
|
||||||
|
let%bind (Stack.Ex_stack_ty output_stack_ty) = Compiler_type.Ty.environment w_env.post_environment in
|
||||||
|
let error_message () =
|
||||||
|
let%bind pre_env_michelson = Compiler_type.environment w_env.pre_environment in
|
||||||
|
let%bind post_env_michelson = Compiler_type.environment w_env.post_environment in
|
||||||
|
ok @@ Format.asprintf
|
||||||
|
"statement : %a\ncode : %a\npre type : %a\npost type : %a\n"
|
||||||
|
PP.statement s
|
||||||
|
Michelson.pp code
|
||||||
|
PP_helpers.(list_sep Michelson.pp (const " ; ")) pre_env_michelson
|
||||||
|
PP_helpers.(list_sep Michelson.pp (const " ; ")) post_env_michelson
|
||||||
|
in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt_r (fun () -> let%bind error_message = error_message () in
|
||||||
|
ok (fun () -> error (thunk "error parsing statement code")
|
||||||
|
(fun () -> error_message)
|
||||||
|
())) @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.parse_michelson_fail code
|
||||||
|
input_stack_ty output_stack_ty
|
||||||
|
in
|
||||||
|
ok code
|
||||||
|
in
|
||||||
|
|
||||||
|
trace (fun () -> error (thunk "compiling statement") error_message ()) @@ match s' with
|
||||||
|
| S_environment_add _ ->
|
||||||
|
simple_fail "add not ready yet"
|
||||||
|
| S_environment_select sub_env ->
|
||||||
|
let%bind code = Compiler_environment.select_env w_env.pre_environment sub_env in
|
||||||
|
return code
|
||||||
|
| S_environment_load (expr , env) ->
|
||||||
|
let%bind (expr' , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind clear = Compiler_environment.select w_env.pre_environment [] in
|
||||||
|
let%bind unpack = Compiler_environment.unpack env in
|
||||||
|
return @@ seq [
|
||||||
|
expr' ;
|
||||||
|
dip clear ;
|
||||||
|
unpack ;
|
||||||
|
]
|
||||||
|
| S_declaration (s, expr) ->
|
||||||
|
let tv = Combinators.Expression.get_type expr in
|
||||||
|
let%bind (expr , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind add = Compiler_environment.add w_env.pre_environment (s, tv) in
|
||||||
|
return @@ seq [
|
||||||
|
i_comment "declaration" ;
|
||||||
|
seq [
|
||||||
|
i_comment "expr" ;
|
||||||
|
expr ;
|
||||||
|
] ;
|
||||||
|
seq [
|
||||||
|
i_comment "env <- env . expr" ;
|
||||||
|
add ;
|
||||||
|
];
|
||||||
|
]
|
||||||
|
| S_assignment (s, expr) ->
|
||||||
|
let%bind (expr , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind set = Compiler_environment.set w_env.pre_environment s in
|
||||||
|
return @@ seq [
|
||||||
|
i_comment "assignment" ;
|
||||||
|
seq [
|
||||||
|
i_comment "expr" ;
|
||||||
|
expr ;
|
||||||
|
] ;
|
||||||
|
seq [
|
||||||
|
i_comment "env <- env . expr" ;
|
||||||
|
set ;
|
||||||
|
];
|
||||||
|
]
|
||||||
|
| S_cond (expr, a, b) ->
|
||||||
|
let%bind (expr , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind a' = translate_regular_block a in
|
||||||
|
let%bind b' = translate_regular_block b in
|
||||||
|
return @@ seq [
|
||||||
|
expr ;
|
||||||
|
prim ~children:[seq [a'];seq [b']] I_IF ;
|
||||||
|
]
|
||||||
|
| S_do expr -> (
|
||||||
|
match Combinators.Expression.get_content expr with
|
||||||
|
| E_constant ("FAILWITH" , [ fw ] ) -> (
|
||||||
|
let%bind (fw' , _) = translate_expression fw w_env.pre_environment in
|
||||||
|
return @@ seq [
|
||||||
|
fw' ;
|
||||||
|
i_failwith ;
|
||||||
|
]
|
||||||
|
)
|
||||||
|
| _ -> (
|
||||||
|
let%bind (expr' , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
return @@ seq [
|
||||||
|
expr' ;
|
||||||
|
i_drop ;
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| S_if_none (expr, none, ((name, tv), some)) ->
|
||||||
|
let%bind (expr , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind none' = translate_regular_block none in
|
||||||
|
let%bind some' = translate_regular_block some in
|
||||||
|
let%bind add =
|
||||||
|
let env' = w_env.pre_environment in
|
||||||
|
Compiler_environment.add env' (name, tv) in
|
||||||
|
let%bind restrict_s = Compiler_environment.select_env (snd some).post_environment w_env.pre_environment in
|
||||||
|
return @@ seq [
|
||||||
|
expr ;
|
||||||
|
prim ~children:[
|
||||||
|
seq [none'] ;
|
||||||
|
seq [add ; some' ; restrict_s] ;
|
||||||
|
] I_IF_NONE
|
||||||
|
]
|
||||||
|
| S_while (expr, block) ->
|
||||||
|
let%bind (expr , _) = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind block' = translate_regular_block block in
|
||||||
|
let%bind restrict_block =
|
||||||
|
let env_while = (snd block).pre_environment in
|
||||||
|
Compiler_environment.select_env (snd block).post_environment env_while in
|
||||||
|
return @@ seq [
|
||||||
|
expr ;
|
||||||
|
prim ~children:[seq [
|
||||||
|
block' ;
|
||||||
|
restrict_block ;
|
||||||
|
expr]] I_LOOP ;
|
||||||
|
]
|
||||||
|
| S_patch (name, lrs, expr) ->
|
||||||
|
let%bind (expr' , env') = translate_expression expr w_env.pre_environment in
|
||||||
|
let%bind get_code = Compiler_environment.get env' name in
|
||||||
|
let modify_code =
|
||||||
|
let aux acc step = match step with
|
||||||
|
| `Left -> seq [dip i_unpair ; acc ; i_pair]
|
||||||
|
| `Right -> seq [dip i_unpiar ; acc ; i_piar]
|
||||||
|
in
|
||||||
|
let init = dip i_drop in
|
||||||
|
List.fold_right' aux init lrs
|
||||||
|
in
|
||||||
|
let%bind set_code = Compiler_environment.set w_env.pre_environment name in
|
||||||
|
let error =
|
||||||
|
let title () = "michelson type-checking patch" in
|
||||||
|
let content () =
|
||||||
|
let aux ppf = function
|
||||||
|
| `Left -> Format.fprintf ppf "left"
|
||||||
|
| `Right -> Format.fprintf ppf "right" in
|
||||||
|
Format.asprintf "Sub path: %a\n"
|
||||||
|
PP_helpers.(list_sep aux (const " , ")) lrs
|
||||||
|
in
|
||||||
|
error title content in
|
||||||
|
trace error @@
|
||||||
|
return @@ seq [
|
||||||
|
expr' ;
|
||||||
|
get_code ;
|
||||||
|
i_swap ; modify_code ;
|
||||||
|
set_code ;
|
||||||
|
]
|
||||||
|
|
||||||
|
and translate_regular_block ((b, env):block) : michelson result =
|
||||||
|
let aux prev statement =
|
||||||
|
let%bind (lst : michelson list) = prev in
|
||||||
|
let%bind instruction = translate_statement statement in
|
||||||
|
ok (instruction :: lst)
|
||||||
|
in
|
||||||
|
let%bind codes =
|
||||||
|
let error_message () =
|
||||||
|
let%bind schema_michelsons = Compiler_type.environment env.pre_environment in
|
||||||
|
ok @@ Format.asprintf "\nblock : %a\nschema : %a\n"
|
||||||
|
PP.block (b, env)
|
||||||
|
PP_helpers.(list_sep Michelson.pp (const " ; ")) schema_michelsons
|
||||||
|
in
|
||||||
|
trace_r (fun () ->
|
||||||
|
let%bind error_message = error_message () in
|
||||||
|
ok (fun () -> error (thunk "compiling regular block")
|
||||||
|
(fun () -> error_message)
|
||||||
|
())) @@
|
||||||
|
List.fold_left aux (ok []) b in
|
||||||
|
let code = seq (List.rev codes) in
|
||||||
|
ok code
|
||||||
|
|
||||||
|
and translate_quote_body ({body;result} as f:anon_function) : michelson result =
|
||||||
|
let%bind body' = translate_regular_block body in
|
||||||
|
let%bind (expr , _) = translate_expression result (snd body).post_environment in
|
||||||
|
let%bind restrict = Compiler_environment.clear (snd body).post_environment in
|
||||||
|
let code = seq [
|
||||||
|
i_comment "function body" ;
|
||||||
|
body' ;
|
||||||
|
i_comment "function result" ;
|
||||||
|
expr ;
|
||||||
|
dip restrict ;
|
||||||
|
] in
|
||||||
|
|
||||||
|
let%bind _assert_type =
|
||||||
|
let%bind (Ex_ty input_ty) = Compiler_type.Ty.type_ f.input in
|
||||||
|
let%bind (Ex_ty output_ty) = Compiler_type.Ty.type_ f.output in
|
||||||
|
let input_stack_ty = Stack.(input_ty @: nil) in
|
||||||
|
let output_stack_ty = Stack.(output_ty @: nil) in
|
||||||
|
let error_message () =
|
||||||
|
Format.asprintf
|
||||||
|
"\ncode : %a\ninput : %a\noutput : %a\nenv : %a\n"
|
||||||
|
Tezos_utils.Micheline.Michelson.pp code
|
||||||
|
PP.type_ f.input
|
||||||
|
PP.type_ f.output
|
||||||
|
PP.environment (snd body).post_environment
|
||||||
|
in
|
||||||
|
let%bind _ =
|
||||||
|
Trace.trace_tzresult_lwt (
|
||||||
|
error (thunk "error parsing quote code") error_message
|
||||||
|
) @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.parse_michelson code
|
||||||
|
input_stack_ty output_stack_ty
|
||||||
|
in
|
||||||
|
ok ()
|
||||||
|
in
|
||||||
|
|
||||||
|
ok code
|
||||||
|
|
||||||
|
type compiled_program = {
|
||||||
|
input : ex_ty ;
|
||||||
|
output : ex_ty ;
|
||||||
|
body : michelson ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let get_main : program -> string -> anon_function result = fun p entry ->
|
||||||
|
let is_main (((name , expr), _):toplevel_statement) =
|
||||||
|
match Combinators.Expression.(get_content expr , get_type expr)with
|
||||||
|
| (E_literal (D_function content) , T_function _)
|
||||||
|
when name = entry ->
|
||||||
|
Some content
|
||||||
|
| _ -> None
|
||||||
|
in
|
||||||
|
let%bind main =
|
||||||
|
trace_option (simple_error "no functional entry") @@
|
||||||
|
List.find_map is_main p
|
||||||
|
in
|
||||||
|
ok main
|
||||||
|
|
||||||
|
let translate_program (p:program) (entry:string) : compiled_program result =
|
||||||
|
let%bind main = get_main p entry in
|
||||||
|
let {input;output} : anon_function = main in
|
||||||
|
let%bind body = translate_quote_body main in
|
||||||
|
let%bind input = Compiler_type.Ty.type_ input in
|
||||||
|
let%bind output = Compiler_type.Ty.type_ output in
|
||||||
|
ok ({input;output;body}:compiled_program)
|
||||||
|
|
||||||
|
let translate_entry (p:anon_function) : compiled_program result =
|
||||||
|
let {input;output} : anon_function = p in
|
||||||
|
let%bind body =
|
||||||
|
trace (simple_error "compile entry body") @@
|
||||||
|
translate_quote_body p in
|
||||||
|
let%bind input = Compiler_type.Ty.type_ input in
|
||||||
|
let%bind output = Compiler_type.Ty.type_ output in
|
||||||
|
ok ({input;output;body}:compiled_program)
|
||||||
|
|
||||||
|
let translate_contract : anon_function -> michelson result = fun f ->
|
||||||
|
let%bind compiled_program = translate_entry f in
|
||||||
|
let%bind (param_ty , storage_ty) = Combinators.get_t_pair f.input in
|
||||||
|
let%bind param_michelson = Compiler_type.type_ param_ty in
|
||||||
|
let%bind storage_michelson = Compiler_type.type_ storage_ty in
|
||||||
|
let contract = Michelson.contract param_michelson storage_michelson compiled_program.body in
|
||||||
|
ok contract
|
173
compiler/compiler_type.ml
Normal file
173
compiler/compiler_type.ml
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
open Trace
|
||||||
|
open Mini_c.Types
|
||||||
|
|
||||||
|
open Tezos_utils.Memory_proto_alpha
|
||||||
|
open Script_ir_translator
|
||||||
|
|
||||||
|
module O = Tezos_utils.Micheline.Michelson
|
||||||
|
module Contract_types = Meta_michelson.Types
|
||||||
|
|
||||||
|
module Ty = struct
|
||||||
|
|
||||||
|
let not_comparable name () = error (thunk "not a comparable type") (fun () -> name) ()
|
||||||
|
|
||||||
|
let comparable_type_base : type_base -> ex_comparable_ty result = fun tb ->
|
||||||
|
let open Contract_types in
|
||||||
|
let return x = ok @@ Ex_comparable_ty x in
|
||||||
|
match tb with
|
||||||
|
| Base_unit -> fail (not_comparable "unit")
|
||||||
|
| Base_bool -> fail (not_comparable "bool")
|
||||||
|
| Base_nat -> return nat_k
|
||||||
|
| Base_tez -> return tez_k
|
||||||
|
| Base_int -> return int_k
|
||||||
|
| Base_string -> return string_k
|
||||||
|
| Base_address -> return address_k
|
||||||
|
| Base_bytes -> return bytes_k
|
||||||
|
| Base_operation -> fail (not_comparable "operation")
|
||||||
|
|
||||||
|
let comparable_type : type_value -> ex_comparable_ty result = fun tv ->
|
||||||
|
match tv with
|
||||||
|
| T_base b -> comparable_type_base b
|
||||||
|
| T_deep_closure _ -> fail (not_comparable "deep closure")
|
||||||
|
| T_function _ -> fail (not_comparable "function")
|
||||||
|
| T_or _ -> fail (not_comparable "or")
|
||||||
|
| T_pair _ -> fail (not_comparable "pair")
|
||||||
|
| T_map _ -> fail (not_comparable "map")
|
||||||
|
| T_list _ -> fail (not_comparable "list")
|
||||||
|
| T_option _ -> fail (not_comparable "option")
|
||||||
|
| T_contract _ -> fail (not_comparable "contract")
|
||||||
|
|
||||||
|
let base_type : type_base -> ex_ty result = fun b ->
|
||||||
|
let open Contract_types in
|
||||||
|
let return x = ok @@ Ex_ty x in
|
||||||
|
match b with
|
||||||
|
| Base_unit -> return unit
|
||||||
|
| Base_bool -> return bool
|
||||||
|
| Base_int -> return int
|
||||||
|
| Base_nat -> return nat
|
||||||
|
| Base_tez -> return tez
|
||||||
|
| Base_string -> return string
|
||||||
|
| Base_address -> return address
|
||||||
|
| Base_bytes -> return bytes
|
||||||
|
| Base_operation -> return operation
|
||||||
|
|
||||||
|
let rec type_ : type_value -> ex_ty result =
|
||||||
|
function
|
||||||
|
| T_base b -> base_type b
|
||||||
|
| T_pair (t, t') -> (
|
||||||
|
type_ t >>? fun (Ex_ty t) ->
|
||||||
|
type_ t' >>? fun (Ex_ty t') ->
|
||||||
|
ok @@ Ex_ty (Contract_types.pair t t')
|
||||||
|
)
|
||||||
|
| T_or (t, t') -> (
|
||||||
|
type_ t >>? fun (Ex_ty t) ->
|
||||||
|
type_ t' >>? fun (Ex_ty t') ->
|
||||||
|
ok @@ Ex_ty (Contract_types.union t t')
|
||||||
|
)
|
||||||
|
| T_function (arg, ret) ->
|
||||||
|
let%bind (Ex_ty arg) = type_ arg in
|
||||||
|
let%bind (Ex_ty ret) = type_ ret in
|
||||||
|
ok @@ Ex_ty (Contract_types.lambda arg ret)
|
||||||
|
| T_deep_closure (c, arg, ret) ->
|
||||||
|
let%bind (Ex_ty capture) = environment_representation c in
|
||||||
|
let%bind (Ex_ty arg) = type_ arg in
|
||||||
|
let%bind (Ex_ty ret) = type_ ret in
|
||||||
|
ok @@ Ex_ty Contract_types.(pair (lambda (pair arg capture) ret) capture)
|
||||||
|
| T_map (k, v) ->
|
||||||
|
let%bind (Ex_comparable_ty k') = comparable_type k in
|
||||||
|
let%bind (Ex_ty v') = type_ v in
|
||||||
|
ok @@ Ex_ty Contract_types.(map k' v')
|
||||||
|
| T_list t ->
|
||||||
|
let%bind (Ex_ty t') = type_ t in
|
||||||
|
ok @@ Ex_ty Contract_types.(list t')
|
||||||
|
| T_option t ->
|
||||||
|
let%bind (Ex_ty t') = type_ t in
|
||||||
|
ok @@ Ex_ty Contract_types.(option t')
|
||||||
|
| T_contract t ->
|
||||||
|
let%bind (Ex_ty t') = type_ t in
|
||||||
|
ok @@ Ex_ty Contract_types.(contract t')
|
||||||
|
|
||||||
|
and environment_representation = function
|
||||||
|
| [] -> ok @@ Ex_ty Contract_types.unit
|
||||||
|
| [a] -> type_ @@ snd a
|
||||||
|
| a::b ->
|
||||||
|
let%bind (Ex_ty a) = type_ @@ snd a in
|
||||||
|
let%bind (Ex_ty b) = environment_representation b in
|
||||||
|
ok @@ Ex_ty (Contract_types.pair a b)
|
||||||
|
|
||||||
|
and environment : environment -> Meta_michelson.Stack.ex_stack_ty result = fun env ->
|
||||||
|
let open Meta_michelson in
|
||||||
|
let%bind lst =
|
||||||
|
bind_map_list type_
|
||||||
|
@@ List.map snd env in
|
||||||
|
let aux (Stack.Ex_stack_ty st) (Ex_ty cur) =
|
||||||
|
Stack.Ex_stack_ty (Stack.stack cur st)
|
||||||
|
in
|
||||||
|
ok @@ List.fold_right' aux (Ex_stack_ty Stack.nil) lst
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
let base_type : type_base -> O.michelson result =
|
||||||
|
function
|
||||||
|
| Base_unit -> ok @@ O.prim T_unit
|
||||||
|
| Base_bool -> ok @@ O.prim T_bool
|
||||||
|
| Base_int -> ok @@ O.prim T_int
|
||||||
|
| Base_nat -> ok @@ O.prim T_nat
|
||||||
|
| Base_tez -> ok @@ O.prim T_mutez
|
||||||
|
| Base_string -> ok @@ O.prim T_string
|
||||||
|
| Base_address -> ok @@ O.prim T_address
|
||||||
|
| Base_bytes -> ok @@ O.prim T_bytes
|
||||||
|
| Base_operation -> ok @@ O.prim T_operation
|
||||||
|
|
||||||
|
let rec type_ : type_value -> O.michelson result =
|
||||||
|
function
|
||||||
|
| T_base b -> base_type b
|
||||||
|
| T_pair (t, t') -> (
|
||||||
|
type_ t >>? fun t ->
|
||||||
|
type_ t' >>? fun t' ->
|
||||||
|
ok @@ O.prim ~children:[t;t'] O.T_pair
|
||||||
|
)
|
||||||
|
| T_or (t, t') -> (
|
||||||
|
type_ t >>? fun t ->
|
||||||
|
type_ t' >>? fun t' ->
|
||||||
|
ok @@ O.prim ~children:[t;t'] O.T_or
|
||||||
|
)
|
||||||
|
| T_map kv ->
|
||||||
|
let%bind (k', v') = bind_map_pair type_ kv in
|
||||||
|
ok @@ O.prim ~children:[k';v'] O.T_map
|
||||||
|
| T_list t ->
|
||||||
|
let%bind t' = type_ t in
|
||||||
|
ok @@ O.prim ~children:[t'] O.T_list
|
||||||
|
| T_option o ->
|
||||||
|
let%bind o' = type_ o in
|
||||||
|
ok @@ O.prim ~children:[o'] O.T_option
|
||||||
|
| T_contract o ->
|
||||||
|
let%bind o' = type_ o in
|
||||||
|
ok @@ O.prim ~children:[o'] O.T_contract
|
||||||
|
| T_function (arg, ret) ->
|
||||||
|
let%bind arg = type_ arg in
|
||||||
|
let%bind ret = type_ ret in
|
||||||
|
ok @@ O.prim ~children:[arg;ret] T_lambda
|
||||||
|
| T_deep_closure (c, arg, ret) ->
|
||||||
|
let%bind capture = environment_closure c in
|
||||||
|
let%bind arg = type_ arg in
|
||||||
|
let%bind ret = type_ ret in
|
||||||
|
ok @@ O.t_pair (O.t_lambda (O.t_pair arg capture) ret) capture
|
||||||
|
|
||||||
|
and environment_element (name, tyv) =
|
||||||
|
let%bind michelson_type = type_ tyv in
|
||||||
|
ok @@ O.annotate ("@" ^ name) michelson_type
|
||||||
|
|
||||||
|
and environment = fun env ->
|
||||||
|
bind_map_list type_
|
||||||
|
@@ List.map snd env
|
||||||
|
|
||||||
|
and environment_closure =
|
||||||
|
function
|
||||||
|
| [] -> simple_fail "Type of empty env"
|
||||||
|
| [a] -> type_ @@ snd a
|
||||||
|
| a :: b ->
|
||||||
|
let%bind a = type_ @@ snd a in
|
||||||
|
let%bind b = environment_closure b in
|
||||||
|
ok @@ O.t_pair a b
|
15
compiler/dune
Normal file
15
compiler/dune
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
(library
|
||||||
|
(name compiler)
|
||||||
|
(public_name ligo.compiler)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
meta_michelson
|
||||||
|
mini_c
|
||||||
|
operators
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils -open Tezos_utils ))
|
||||||
|
)
|
91
compiler/uncompiler.ml
Normal file
91
compiler/uncompiler.ml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
open Trace
|
||||||
|
open Mini_c.Types
|
||||||
|
open Memory_proto_alpha
|
||||||
|
open Script_typed_ir
|
||||||
|
open Script_ir_translator
|
||||||
|
|
||||||
|
let rec translate_value (Ex_typed_value (ty, value)) : value result =
|
||||||
|
match (ty, value) with
|
||||||
|
| Pair_t ((a_ty, _, _), (b_ty, _, _), _), (a, b) -> (
|
||||||
|
let%bind a = translate_value @@ Ex_typed_value(a_ty, a) in
|
||||||
|
let%bind b = translate_value @@ Ex_typed_value(b_ty, b) in
|
||||||
|
ok @@ D_pair(a, b)
|
||||||
|
)
|
||||||
|
| Union_t ((a_ty, _), _, _), L a -> (
|
||||||
|
let%bind a = translate_value @@ Ex_typed_value(a_ty, a) in
|
||||||
|
ok @@ D_left a
|
||||||
|
)
|
||||||
|
| Union_t (_, (b_ty, _), _), R b -> (
|
||||||
|
let%bind b = translate_value @@ Ex_typed_value(b_ty, b) in
|
||||||
|
ok @@ D_right b
|
||||||
|
)
|
||||||
|
| (Int_t _), n ->
|
||||||
|
let%bind n =
|
||||||
|
trace_option (simple_error "too big to fit an int") @@
|
||||||
|
Alpha_context.Script_int.to_int n in
|
||||||
|
ok @@ D_int n
|
||||||
|
| (Nat_t _), n ->
|
||||||
|
let%bind n =
|
||||||
|
trace_option (simple_error "too big to fit an int") @@
|
||||||
|
Alpha_context.Script_int.to_int n in
|
||||||
|
ok @@ D_nat n
|
||||||
|
| (Mutez_t _), n ->
|
||||||
|
let%bind n =
|
||||||
|
generic_try (simple_error "too big to fit an int") @@
|
||||||
|
(fun () -> Int64.to_int @@ Alpha_context.Tez.to_mutez n) in
|
||||||
|
ok @@ D_nat n
|
||||||
|
| (Bool_t _), b ->
|
||||||
|
ok @@ D_bool b
|
||||||
|
| (String_t _), s ->
|
||||||
|
ok @@ D_string s
|
||||||
|
| (Address_t _), s ->
|
||||||
|
ok @@ D_string (Alpha_context.Contract.to_b58check s)
|
||||||
|
| (Unit_t _), () ->
|
||||||
|
ok @@ D_unit
|
||||||
|
| (Option_t _), None ->
|
||||||
|
ok @@ D_none
|
||||||
|
| (Option_t ((o_ty, _), _, _)), Some s ->
|
||||||
|
let%bind s' = translate_value @@ Ex_typed_value (o_ty, s) in
|
||||||
|
ok @@ D_some s'
|
||||||
|
| (Map_t (k_cty, v_ty, _)), m ->
|
||||||
|
let k_ty = Script_ir_translator.ty_of_comparable_ty k_cty in
|
||||||
|
let lst =
|
||||||
|
let aux k v acc = (k, v) :: acc in
|
||||||
|
let lst = Script_ir_translator.map_fold aux m [] in
|
||||||
|
List.rev lst in
|
||||||
|
let%bind lst' =
|
||||||
|
let aux (k, v) =
|
||||||
|
let%bind k' = translate_value (Ex_typed_value (k_ty, k)) in
|
||||||
|
let%bind v' = translate_value (Ex_typed_value (v_ty, v)) in
|
||||||
|
ok (k', v')
|
||||||
|
in
|
||||||
|
bind_map_list aux lst
|
||||||
|
in
|
||||||
|
ok @@ D_map lst'
|
||||||
|
| (List_t (ty, _)), lst ->
|
||||||
|
let lst' =
|
||||||
|
let aux acc cur = cur :: acc in
|
||||||
|
let lst = List.fold_left aux lst [] in
|
||||||
|
List.rev lst in
|
||||||
|
let%bind lst'' =
|
||||||
|
let aux = fun t -> translate_value (Ex_typed_value (ty, t)) in
|
||||||
|
bind_map_list aux lst'
|
||||||
|
in
|
||||||
|
ok @@ D_list lst''
|
||||||
|
| (Operation_t _) , op ->
|
||||||
|
ok @@ D_operation op
|
||||||
|
| ty, v ->
|
||||||
|
let%bind error =
|
||||||
|
let%bind m_data =
|
||||||
|
trace_tzresult_lwt (simple_error "unparsing unrecognized data") @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.unparse_michelson_data ty v in
|
||||||
|
let%bind m_ty =
|
||||||
|
trace_tzresult_lwt (simple_error "unparsing unrecognized data") @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.unparse_michelson_ty ty in
|
||||||
|
let error_content () =
|
||||||
|
Format.asprintf "%a : %a"
|
||||||
|
Michelson.pp m_data
|
||||||
|
Michelson.pp m_ty in
|
||||||
|
ok @@ (fun () -> error (thunk "this value can't be transpiled back yet") error_content ())
|
||||||
|
in
|
||||||
|
fail error
|
5
contracts/annotation.ligo
Normal file
5
contracts/annotation.ligo
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const lst : list(int) = list [] ;
|
||||||
|
|
||||||
|
const address : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ;
|
||||||
|
|
||||||
|
const address_2 : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ;
|
17
contracts/arithmetic.ligo
Normal file
17
contracts/arithmetic.ligo
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
function mod_op (const n : int) : nat is
|
||||||
|
begin skip end with n mod 42
|
||||||
|
|
||||||
|
function plus_op (const n : int) : int is
|
||||||
|
begin skip end with n + 42
|
||||||
|
|
||||||
|
function minus_op (const n : int) : int is
|
||||||
|
begin skip end with n - 42
|
||||||
|
|
||||||
|
function times_op (const n : int) : int is
|
||||||
|
begin skip end with n * 42
|
||||||
|
|
||||||
|
function div_op (const n : int) : int is
|
||||||
|
begin skip end with n / 2
|
||||||
|
|
||||||
|
function int_op (const n : nat) : int is
|
||||||
|
block { skip } with int(n)
|
3
contracts/basic.mligo
Normal file
3
contracts/basic.mligo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
type toto = int
|
||||||
|
|
||||||
|
let foo : toto = 42 + 127
|
11
contracts/boolean_operators.ligo
Normal file
11
contracts/boolean_operators.ligo
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
function or_true (const b : bool) : bool is
|
||||||
|
begin skip end with b or True
|
||||||
|
|
||||||
|
function or_false (const b : bool) : bool is
|
||||||
|
begin skip end with b or False
|
||||||
|
|
||||||
|
function and_true (const b : bool) : bool is
|
||||||
|
begin skip end with b and True
|
||||||
|
|
||||||
|
function and_false (const b : bool) : bool is
|
||||||
|
begin skip end with b and False
|
11
contracts/closure.ligo
Normal file
11
contracts/closure.ligo
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
function foo (const i : int) : int is
|
||||||
|
function bar (const j : int) : int is
|
||||||
|
block { skip } with i + j ;
|
||||||
|
block { skip } with bar (i)
|
||||||
|
|
||||||
|
function toto (const i : int) : int is
|
||||||
|
function tata (const j : int) : int is
|
||||||
|
block { skip } with i + j ;
|
||||||
|
function titi (const j : int) : int is
|
||||||
|
block { skip } with i + j ;
|
||||||
|
block { skip } with tata(i) + titi(i)
|
98
contracts/coase.ligo
Normal file
98
contracts/coase.ligo
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright Coase, Inc 2019
|
||||||
|
|
||||||
|
type card_pattern_id is nat
|
||||||
|
type card_pattern is record [
|
||||||
|
coefficient : tez ;
|
||||||
|
quantity : nat ;
|
||||||
|
]
|
||||||
|
|
||||||
|
type card_patterns is map(card_pattern_id , card_pattern)
|
||||||
|
|
||||||
|
type card_id is nat
|
||||||
|
type card is record [
|
||||||
|
card_owner : address ;
|
||||||
|
card_pattern : card_pattern_id ;
|
||||||
|
]
|
||||||
|
type cards is map(card_id , card)
|
||||||
|
|
||||||
|
type storage_type is record [
|
||||||
|
cards : cards ;
|
||||||
|
card_patterns : card_patterns ;
|
||||||
|
next_id : nat ;
|
||||||
|
]
|
||||||
|
|
||||||
|
type action_buy_single is record [
|
||||||
|
card_to_buy : card_pattern_id ;
|
||||||
|
]
|
||||||
|
type action_sell_single is record [
|
||||||
|
card_to_sell : card_id ;
|
||||||
|
]
|
||||||
|
type action_transfer_single is record [
|
||||||
|
card_to_transfer : card_id ;
|
||||||
|
destination : address ;
|
||||||
|
]
|
||||||
|
|
||||||
|
type action is
|
||||||
|
| Buy_single of action_buy_single
|
||||||
|
| Sell_single of action_sell_single
|
||||||
|
| Transfer_single of action_transfer_single
|
||||||
|
|
||||||
|
function transfer_single(const action : action_transfer_single ; const s : storage_type) : (list(operation) * storage_type) is
|
||||||
|
begin
|
||||||
|
const cards : cards = s.cards ;
|
||||||
|
const card : card = get_force(action.card_to_transfer , cards) ;
|
||||||
|
if (card.card_owner =/= source) then fail "This card doesn't belong to you" else skip ;
|
||||||
|
card.card_owner := action.destination ;
|
||||||
|
cards[action.card_to_transfer] := card ;
|
||||||
|
s.cards := cards ;
|
||||||
|
const operations : list(operation) = nil ;
|
||||||
|
end with (operations , s) ;
|
||||||
|
|
||||||
|
function sell_single(const action : action_sell_single ; const s : storage_type) : (list(operation) * storage_type) is
|
||||||
|
begin
|
||||||
|
const card : card = get_force(action.card_to_sell , s.cards) ;
|
||||||
|
if (card.card_owner =/= source) then fail "This card doesn't belong to you" else skip ;
|
||||||
|
const card_pattern : card_pattern = get_force(card.card_pattern , s.card_patterns) ;
|
||||||
|
card_pattern.quantity := abs(card_pattern.quantity - 1n);
|
||||||
|
const card_patterns : card_patterns = s.card_patterns ;
|
||||||
|
card_patterns[card.card_pattern] := card_pattern ;
|
||||||
|
s.card_patterns := card_patterns ;
|
||||||
|
const cards : cards = s.cards ;
|
||||||
|
remove action.card_to_sell from map cards ;
|
||||||
|
s.cards := cards ;
|
||||||
|
const price : tez = card_pattern.coefficient * card_pattern.quantity ;
|
||||||
|
const receiver : contract(unit) = get_contract(source) ;
|
||||||
|
const op : operation = transaction(unit , price , receiver) ;
|
||||||
|
const operations : list(operation) = list op end ;
|
||||||
|
end with (operations , s)
|
||||||
|
|
||||||
|
function buy_single(const action : action_buy_single ; const s : storage_type) : (list(operation) * storage_type) is
|
||||||
|
begin
|
||||||
|
// Check funds
|
||||||
|
const card_pattern : card_pattern = get_force(action.card_to_buy , s.card_patterns) ;
|
||||||
|
const price : tez = card_pattern.coefficient * (card_pattern.quantity + 1n) ;
|
||||||
|
if (price > amount) then fail "Not enough money" else skip ;
|
||||||
|
// Administrative procedure
|
||||||
|
const operations : list(operation) = nil ;
|
||||||
|
// Increase quantity
|
||||||
|
card_pattern.quantity := card_pattern.quantity + 1n ;
|
||||||
|
const card_patterns : card_patterns = s.card_patterns ;
|
||||||
|
card_patterns[action.card_to_buy] := card_pattern ;
|
||||||
|
s.card_patterns := card_patterns ;
|
||||||
|
// Add card
|
||||||
|
const cards : cards = s.cards ;
|
||||||
|
cards[s.next_id] := record
|
||||||
|
card_owner = source ;
|
||||||
|
card_pattern = action.card_to_buy ;
|
||||||
|
end ;
|
||||||
|
s.cards := cards ;
|
||||||
|
s.next_id := s.next_id + 1n ;
|
||||||
|
end with (operations , s)
|
||||||
|
|
||||||
|
function main(const action : action ; const s : storage_type) : (list(operation) * storage_type) is
|
||||||
|
block {skip} with
|
||||||
|
case action of
|
||||||
|
| Buy_single bs -> buy_single (bs , s)
|
||||||
|
| Sell_single as -> sell_single (as , s)
|
||||||
|
| Transfer_single at -> transfer_single (at , s)
|
||||||
|
end
|
8
contracts/condition.ligo
Normal file
8
contracts/condition.ligo
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
function main (const i : int) : int is
|
||||||
|
var result : int := 23 ;
|
||||||
|
begin
|
||||||
|
if i = 2 then
|
||||||
|
result := 42
|
||||||
|
else
|
||||||
|
result := 0
|
||||||
|
end with result
|
6
contracts/counter.ligo
Normal file
6
contracts/counter.ligo
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
type some_type is int
|
||||||
|
|
||||||
|
function main (const p : int ; const s : some_type) : (list(operation) * int) is
|
||||||
|
block { skip } // skip is a do nothing instruction, needed for empty blocks
|
||||||
|
with ((nil : list(operation)), p + s)
|
||||||
|
|
4
contracts/counter.mligo
Normal file
4
contracts/counter.mligo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
type storage = int
|
||||||
|
|
||||||
|
let%entry main (p:int) storage =
|
||||||
|
(list [] : operation list , p + storage)
|
6
contracts/declarations.ligo
Normal file
6
contracts/declarations.ligo
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const foo : int = 42
|
||||||
|
|
||||||
|
function main (const i : int) : int is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with i + foo
|
16
contracts/dispatch-counter.ligo
Normal file
16
contracts/dispatch-counter.ligo
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
type action is
|
||||||
|
| Increment of int
|
||||||
|
| Decrement of int
|
||||||
|
|
||||||
|
function increment(const i : int ; const n : int) : int is
|
||||||
|
block { skip } with (i + n)
|
||||||
|
|
||||||
|
function decrement(const i : int ; const n : int) : int is
|
||||||
|
block { skip } with (i - n)
|
||||||
|
|
||||||
|
function main (const p : action ; const s : int) : (list(operation) * int) is
|
||||||
|
block {skip} with ((nil : list(operation)),
|
||||||
|
case p of
|
||||||
|
| Increment n -> increment(s , n)
|
||||||
|
| Decrement n -> decrement(s , n)
|
||||||
|
end)
|
7
contracts/function-complex.ligo
Normal file
7
contracts/function-complex.ligo
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
function main (const i : int) : int is
|
||||||
|
var j : int := 0 ;
|
||||||
|
var k : int := 1 ;
|
||||||
|
begin
|
||||||
|
j := k + i ;
|
||||||
|
k := i + j ;
|
||||||
|
end with (k + j)
|
8
contracts/function-shared.ligo
Normal file
8
contracts/function-shared.ligo
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
function inc ( const i : int ) : int is
|
||||||
|
block { skip } with i + 1
|
||||||
|
|
||||||
|
function double_inc ( const i : int ) : int is
|
||||||
|
block { skip } with inc(i + 1)
|
||||||
|
|
||||||
|
function foo ( const i : int ) : int is
|
||||||
|
block { skip } with inc(i) + double_inc(i)
|
4
contracts/function.ligo
Normal file
4
contracts/function.ligo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
function main (const i : int) : int is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with i
|
6
contracts/heap-instance.ligo
Normal file
6
contracts/heap-instance.ligo
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
type heap_element is int * string
|
||||||
|
|
||||||
|
function heap_element_lt(const x : heap_element ; const y : heap_element) : bool is
|
||||||
|
block { skip } with x.0 < y.0
|
||||||
|
|
||||||
|
#include "heap.ligo"
|
90
contracts/heap.ligo
Normal file
90
contracts/heap.ligo
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
type heap is map(nat, heap_element) ;
|
||||||
|
|
||||||
|
function is_empty (const h : heap) : bool is
|
||||||
|
block {skip} with size(h) = 0n
|
||||||
|
|
||||||
|
function get_top (const h : heap) : heap_element is
|
||||||
|
block {skip} with get_force(1n, h)
|
||||||
|
|
||||||
|
function pop_switch (const h : heap) : heap is
|
||||||
|
block {
|
||||||
|
const result : heap_element = get_top (h) ;
|
||||||
|
const s : nat = size(h) ;
|
||||||
|
const last : heap_element = get_force(s, h) ;
|
||||||
|
remove 1n from map h ;
|
||||||
|
h[1n] := last ;
|
||||||
|
} with h
|
||||||
|
|
||||||
|
function pop_ (const h : heap) : nat is
|
||||||
|
begin
|
||||||
|
const result : heap_element = get_top (h) ;
|
||||||
|
const s : nat = size(h) ;
|
||||||
|
var current : heap_element := get_force(s, h) ;
|
||||||
|
const i : nat = 1n ;
|
||||||
|
const left : nat = 2n * i ;
|
||||||
|
const right : nat = left + 1n ;
|
||||||
|
remove 1n from map h ;
|
||||||
|
h[1n] := current ;
|
||||||
|
var largest : nat := i ;
|
||||||
|
if (left <= s and heap_element_lt(get_force(s , h) , get_force(left , h))) then
|
||||||
|
largest := left
|
||||||
|
else if (right <= s and heap_element_lt(get_force(s , h) , get_force(right , h))) then
|
||||||
|
largest := right
|
||||||
|
else skip
|
||||||
|
end with largest
|
||||||
|
|
||||||
|
function insert (const h : heap ; const e : heap_element) : heap is
|
||||||
|
begin
|
||||||
|
var i : nat := size(h) + 1n ;
|
||||||
|
h[i] := e ;
|
||||||
|
var largest : nat := i ;
|
||||||
|
var parent : nat := 0n ;
|
||||||
|
while (largest =/= i) block {
|
||||||
|
parent := i / 2n ;
|
||||||
|
largest := i ;
|
||||||
|
if (parent >= 1n) then block {
|
||||||
|
if (heap_element_lt(get_force(parent , h) , get_force(i , h))) then block {
|
||||||
|
largest := parent ;
|
||||||
|
const tmp : heap_element = get_force(i , h) ;
|
||||||
|
h[i] := get_force(parent , h) ;
|
||||||
|
h[parent] := tmp ;
|
||||||
|
} else skip
|
||||||
|
} else skip
|
||||||
|
}
|
||||||
|
end with h
|
||||||
|
|
||||||
|
function pop (const h : heap) : (heap * heap_element * nat) is
|
||||||
|
begin
|
||||||
|
const result : heap_element = get_top (h) ;
|
||||||
|
var s : nat := size(h) ;
|
||||||
|
const last : heap_element = get_force(s, h) ;
|
||||||
|
remove s from map h ;
|
||||||
|
h[1n] := last ;
|
||||||
|
s := size(h) ;
|
||||||
|
var i : nat := 0n ;
|
||||||
|
var largest : nat := 1n ;
|
||||||
|
var left : nat := 0n ;
|
||||||
|
var right : nat := 0n ;
|
||||||
|
var c : nat := 0n ;
|
||||||
|
while (largest =/= i) block {
|
||||||
|
c := c + 1n ;
|
||||||
|
i := largest ;
|
||||||
|
left := 2n * i ;
|
||||||
|
right := left + 1n ;
|
||||||
|
if (left <= s) then begin
|
||||||
|
if (heap_element_lt(get_force(left , h) , get_force(i , h))) then begin
|
||||||
|
largest := left ;
|
||||||
|
const tmp : heap_element = get_force(i , h) ;
|
||||||
|
h[i] := get_force(left , h) ;
|
||||||
|
h[left] := tmp ;
|
||||||
|
end else skip ;
|
||||||
|
end else if (right <= s) then begin
|
||||||
|
if (heap_element_lt(get_force(right , h) , get_force(i , h))) then begin
|
||||||
|
largest := right ;
|
||||||
|
const tmp : heap_element = get_force(i , h) ;
|
||||||
|
h[i] := get_force(right , h) ;
|
||||||
|
h[left] := tmp ;
|
||||||
|
end else skip ;
|
||||||
|
end else skip ;
|
||||||
|
}
|
||||||
|
end with (h , result , c)
|
6
contracts/high-order.ligo
Normal file
6
contracts/high-order.ligo
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
function foobar (const i : int) : int is
|
||||||
|
function foo (const i : int) : int is
|
||||||
|
block { skip } with i ;
|
||||||
|
function bar (const f : int -> int) : int is
|
||||||
|
block { skip } with f ( i ) ;
|
||||||
|
block { skip } with bar (foo) ;
|
1
contracts/included.ligo
Normal file
1
contracts/included.ligo
Normal file
@ -0,0 +1 @@
|
|||||||
|
const foo : int = 144
|
3
contracts/includer.ligo
Normal file
3
contracts/includer.ligo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "included.ligo"
|
||||||
|
|
||||||
|
const bar : int = foo
|
19
contracts/list.ligo
Normal file
19
contracts/list.ligo
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
type foobar is list(int)
|
||||||
|
|
||||||
|
const fb : foobar = list
|
||||||
|
23 ;
|
||||||
|
42 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function size_ (const m : foobar) : nat is
|
||||||
|
block {skip} with (size(m))
|
||||||
|
|
||||||
|
// function hdf (const m : foobar) : int is begin skip end with hd(m)
|
||||||
|
|
||||||
|
const bl : foobar = list
|
||||||
|
144 ;
|
||||||
|
51 ;
|
||||||
|
42 ;
|
||||||
|
120 ;
|
||||||
|
421 ;
|
||||||
|
end
|
19
contracts/loop.ligo
Normal file
19
contracts/loop.ligo
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
function counter (var n : nat) : nat is block {
|
||||||
|
var i : nat := 0n ;
|
||||||
|
while (i < n) block {
|
||||||
|
i := i + 1n ;
|
||||||
|
}
|
||||||
|
} with i
|
||||||
|
|
||||||
|
function sum (var n : nat) : nat is block {
|
||||||
|
var i : nat := 0n ;
|
||||||
|
var r : nat := 0n ;
|
||||||
|
while (i < n) block {
|
||||||
|
i := i + 1n ;
|
||||||
|
r := r + i ;
|
||||||
|
}
|
||||||
|
} with r
|
||||||
|
|
||||||
|
function dummy (const n : nat) : nat is block {
|
||||||
|
while (False) block { skip }
|
||||||
|
} with n
|
33
contracts/map.ligo
Normal file
33
contracts/map.ligo
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
type foobar is map(int, int)
|
||||||
|
|
||||||
|
const fb : foobar = map
|
||||||
|
23 -> 0 ;
|
||||||
|
42 -> 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function set_ (var n : int ; var m : foobar) : foobar is block {
|
||||||
|
m[23] := n ;
|
||||||
|
} with m
|
||||||
|
|
||||||
|
|
||||||
|
function rm (var m : foobar) : foobar is block {
|
||||||
|
remove 42 from map m
|
||||||
|
} with m
|
||||||
|
|
||||||
|
function size_ (const m : foobar) : nat is
|
||||||
|
block {skip} with (size(m))
|
||||||
|
|
||||||
|
function gf (const m : foobar) : int is begin skip end with get_force(23, m)
|
||||||
|
|
||||||
|
function get (const m : foobar) : option(int) is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with m[42]
|
||||||
|
|
||||||
|
const bm : foobar = map
|
||||||
|
144 -> 23 ;
|
||||||
|
51 -> 23 ;
|
||||||
|
42 -> 23 ;
|
||||||
|
120 -> 23 ;
|
||||||
|
421 -> 23 ;
|
||||||
|
end
|
31
contracts/match.ligo
Normal file
31
contracts/match.ligo
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
function match_bool (const i : int) : int is
|
||||||
|
var result : int := 23 ;
|
||||||
|
begin
|
||||||
|
case i = 2 of
|
||||||
|
| True -> result := 42
|
||||||
|
| False -> result := 0
|
||||||
|
end
|
||||||
|
end with result
|
||||||
|
|
||||||
|
function match_option (const o : option(int)) : int is
|
||||||
|
var result : int := 23 ;
|
||||||
|
begin
|
||||||
|
case o of
|
||||||
|
| None -> skip
|
||||||
|
| Some(s) -> result := s
|
||||||
|
end
|
||||||
|
end with result
|
||||||
|
|
||||||
|
function match_expr_bool (const i : int) : int is
|
||||||
|
begin skip end with
|
||||||
|
case i = 2 of
|
||||||
|
| True -> 42
|
||||||
|
| False -> 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function match_expr_option (const o : option(int)) : int is
|
||||||
|
begin skip end with
|
||||||
|
case o of
|
||||||
|
| None -> 42
|
||||||
|
| Some(s) -> s
|
||||||
|
end
|
8
contracts/multiple-parameters.ligo
Normal file
8
contracts/multiple-parameters.ligo
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
function ab(const a : int; const b : int) : int is
|
||||||
|
begin skip end with (a + b)
|
||||||
|
|
||||||
|
function abcd(const a : int; const b : int; const c : int; const d : int) : int is
|
||||||
|
begin skip end with (a + b + c + d + 2)
|
||||||
|
|
||||||
|
function abcde(const a : int; const b : int; const c : int; const d : int; const e : int) : int is
|
||||||
|
begin skip end with (c + e + 3)
|
21
contracts/new-syntax.mligo
Normal file
21
contracts/new-syntax.mligo
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
(** Type of storage for this contract *)
|
||||||
|
type storage = {
|
||||||
|
challenge : string ;
|
||||||
|
}
|
||||||
|
|
||||||
|
(** Initial storage *)
|
||||||
|
let%init storage = {
|
||||||
|
challenge = "" ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type param = {
|
||||||
|
new_challenge : string ;
|
||||||
|
attempt : bytes ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let%entry attempt (p:param) storage =
|
||||||
|
if Crypto.hash (Bytes.pack p.attempt) <> Bytes.pack storage.challenge then failwith "Failed challenge" ;
|
||||||
|
let contract : unit contract = Operation.get_contract sender in
|
||||||
|
let transfer : operation = Operation.transaction (unit , contract , 10.00tz) in
|
||||||
|
let storage : storage = storage.challenge <- p.new_challenge in
|
||||||
|
((list [] : operation list), storage)
|
4
contracts/option.ligo
Normal file
4
contracts/option.ligo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
type foobar is option(int)
|
||||||
|
|
||||||
|
const s : foobar = Some(42)
|
||||||
|
const n : foobar = None
|
8
contracts/quote-declaration.ligo
Normal file
8
contracts/quote-declaration.ligo
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
function foo (const input : int) : int is begin
|
||||||
|
skip
|
||||||
|
end with (input + 42)
|
||||||
|
|
||||||
|
function main (const i : int) : int is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with i + foo (i)
|
13
contracts/quote-declarations.ligo
Normal file
13
contracts/quote-declarations.ligo
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
function foo (const input : int) : int is begin
|
||||||
|
skip
|
||||||
|
end with (input + 23)
|
||||||
|
|
||||||
|
function bar (const input : int) : int is begin
|
||||||
|
skip
|
||||||
|
end with (input + 51)
|
||||||
|
|
||||||
|
|
||||||
|
function main (const i : int) : int is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with foo (i) + bar (i)
|
56
contracts/record.ligo
Normal file
56
contracts/record.ligo
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
type foobar is record
|
||||||
|
foo : int ;
|
||||||
|
bar : int ;
|
||||||
|
end
|
||||||
|
|
||||||
|
const fb : foobar = record
|
||||||
|
foo = 0 ;
|
||||||
|
bar = 0 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
type abc is record
|
||||||
|
a : int ;
|
||||||
|
b : int ;
|
||||||
|
c : int ;
|
||||||
|
end
|
||||||
|
|
||||||
|
const abc : abc = record
|
||||||
|
a = 42 ;
|
||||||
|
b = 142 ;
|
||||||
|
c = 242 ;
|
||||||
|
end
|
||||||
|
|
||||||
|
const a : int = abc.a ;
|
||||||
|
const b : int = abc.b ;
|
||||||
|
const c : int = abc.c ;
|
||||||
|
|
||||||
|
function projection (const r : foobar) : int is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with r.foo + r.bar
|
||||||
|
|
||||||
|
function modify (const r : foobar) : foobar is
|
||||||
|
block {
|
||||||
|
r.foo := 256 ;
|
||||||
|
} with r
|
||||||
|
|
||||||
|
function modify_abc (const r : abc) : abc is
|
||||||
|
block {
|
||||||
|
r.b := 2048 ;
|
||||||
|
} with r
|
||||||
|
|
||||||
|
type big_record is record
|
||||||
|
a : int ;
|
||||||
|
b : int ;
|
||||||
|
c : int ;
|
||||||
|
d : int ;
|
||||||
|
e : int ;
|
||||||
|
end
|
||||||
|
|
||||||
|
const br : big_record = record
|
||||||
|
a = 23 ;
|
||||||
|
b = 23 ;
|
||||||
|
c = 23 ;
|
||||||
|
d = 23 ;
|
||||||
|
e = 23 ;
|
||||||
|
end
|
4
contracts/shadow.ligo
Normal file
4
contracts/shadow.ligo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
function foo (const i : int) : int is
|
||||||
|
function bar (const i : int) : int is
|
||||||
|
block { skip } with i ;
|
||||||
|
block { skip } with bar (0)
|
1
contracts/string.ligo
Normal file
1
contracts/string.ligo
Normal file
@ -0,0 +1 @@
|
|||||||
|
const s : string = "toto"
|
10
contracts/super-counter.ligo
Normal file
10
contracts/super-counter.ligo
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
type action is
|
||||||
|
| Increment of int
|
||||||
|
| Decrement of int
|
||||||
|
|
||||||
|
function main (const p : action ; const s : int) : (list(operation) * int) is
|
||||||
|
block {skip} with ((nil : list(operation)),
|
||||||
|
case p of
|
||||||
|
| Increment n -> s + n
|
||||||
|
| Decrement n -> s - n
|
||||||
|
end)
|
6
contracts/toto.ligo
Normal file
6
contracts/toto.ligo
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
type toto is record
|
||||||
|
a : nat ;
|
||||||
|
b : nat
|
||||||
|
end
|
||||||
|
|
||||||
|
const foo : int = 3
|
22
contracts/tuple.ligo
Normal file
22
contracts/tuple.ligo
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
type abc is (int * int * int)
|
||||||
|
|
||||||
|
function projection_abc (const tpl : abc) : int is
|
||||||
|
block { skip } with tpl.1
|
||||||
|
|
||||||
|
function modify_abc (const tpl : abc) : abc is
|
||||||
|
block {
|
||||||
|
tpl.1 := 2048 ;
|
||||||
|
} with tpl
|
||||||
|
|
||||||
|
type foobar is (int * int)
|
||||||
|
|
||||||
|
const fb : foobar = (0, 0)
|
||||||
|
|
||||||
|
function projection (const tpl : foobar) : int is
|
||||||
|
begin
|
||||||
|
skip
|
||||||
|
end with tpl.0 + tpl.1
|
||||||
|
|
||||||
|
type big_tuple is (int * int * int * int * int)
|
||||||
|
|
||||||
|
const br : big_tuple = (23, 23, 23, 23, 23)
|
1
contracts/unit.ligo
Normal file
1
contracts/unit.ligo
Normal file
@ -0,0 +1 @@
|
|||||||
|
const u : unit = unit
|
11
contracts/variant-matching.ligo
Normal file
11
contracts/variant-matching.ligo
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
type foobar is
|
||||||
|
| Foo of int
|
||||||
|
| Bar of bool
|
||||||
|
| Kee of nat
|
||||||
|
|
||||||
|
function fb(const p : foobar) : int is
|
||||||
|
block { skip } with (case p of
|
||||||
|
| Foo (n) -> n
|
||||||
|
| Bar (t) -> 42
|
||||||
|
| Kee (n) -> 23
|
||||||
|
end)
|
10
contracts/variant.ligo
Normal file
10
contracts/variant.ligo
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
type foobar is
|
||||||
|
| Foo of int
|
||||||
|
| Bar of bool
|
||||||
|
| Kee of nat
|
||||||
|
|
||||||
|
const foo : foobar = Foo (42)
|
||||||
|
|
||||||
|
const bar : foobar = Bar (True)
|
||||||
|
|
||||||
|
const kee : foobar = Kee (23n)
|
25
dune
Normal file
25
dune
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
(library
|
||||||
|
(name ligo)
|
||||||
|
(public_name ligo)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
tezos-micheline
|
||||||
|
meta_michelson
|
||||||
|
main
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
( name ligo-test)
|
||||||
|
(action (run test/test.exe))
|
||||||
|
(deps (glob_files contracts/*))
|
||||||
|
)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
(name runtest)
|
||||||
|
(deps (alias ligo-test))
|
||||||
|
)
|
2
dune-project
Normal file
2
dune-project
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
(lang dune 1.6)
|
||||||
|
(using menhir 2.0)
|
28
ligo.opam
Normal file
28
ligo.opam
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: "ligo"
|
||||||
|
opam-version: "2.0"
|
||||||
|
version: "1.0"
|
||||||
|
maintainer: "gabriel.alfour@gmail.com"
|
||||||
|
authors: [ "Galfour" ]
|
||||||
|
homepage: "https://gitlab.com/gabriel.alfour/tezos"
|
||||||
|
bug-reports: "https://gitlab.com/gabriel.alfour/tezos/issues"
|
||||||
|
synopsis: "A higher-level language which compiles to Michelson"
|
||||||
|
dev-repo: "git+https://gitlab.com/gabriel.alfour/tezos.git"
|
||||||
|
license: "MIT"
|
||||||
|
depends: [
|
||||||
|
"ocamlfind" { build }
|
||||||
|
"dune" { build & >= "1.0.1" }
|
||||||
|
"menhir"
|
||||||
|
"ppx_let"
|
||||||
|
"ppx_deriving"
|
||||||
|
"tezos-utils"
|
||||||
|
"yojson"
|
||||||
|
"alcotest" { with-test }
|
||||||
|
]
|
||||||
|
build: [
|
||||||
|
[ "dune" "build" "-p" name "-j" jobs ]
|
||||||
|
# needed in the repository, but must not be present in the local ligo.opam [ "mv" "src/ligo/ligo.install" "." ]
|
||||||
|
]
|
||||||
|
|
||||||
|
url {
|
||||||
|
src: "https://gitlab.com/gabriel.alfour/tezos/-/archive/master/tezos.tar.gz"
|
||||||
|
}
|
178
main/contract.ml
Normal file
178
main/contract.ml
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
open Trace
|
||||||
|
|
||||||
|
include struct
|
||||||
|
open Ast_simplified
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
let assert_entry_point_defined : program -> string -> unit result =
|
||||||
|
fun program entry_point ->
|
||||||
|
let aux : declaration -> bool = fun declaration ->
|
||||||
|
match declaration with
|
||||||
|
| Declaration_type _ -> false
|
||||||
|
| Declaration_constant ne -> get_name ne = entry_point
|
||||||
|
in
|
||||||
|
trace_strong (simple_error "no entry-point with given name") @@
|
||||||
|
Assert.assert_true @@ List.exists aux @@ List.map Location.unwrap program
|
||||||
|
end
|
||||||
|
|
||||||
|
include struct
|
||||||
|
open Ast_typed
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
let get_entry_point_type : type_value -> (type_value * type_value) result = fun t ->
|
||||||
|
let%bind (arg , result) =
|
||||||
|
trace_strong (simple_error "entry-point doesn't have a function type") @@
|
||||||
|
get_t_function t in
|
||||||
|
let%bind (arg' , storage_param) =
|
||||||
|
trace_strong (simple_error "entry-point doesn't have 2 parameters") @@
|
||||||
|
get_t_pair arg in
|
||||||
|
let%bind (ops , storage_result) =
|
||||||
|
trace_strong (simple_error "entry-point doesn't have 2 results") @@
|
||||||
|
get_t_pair result in
|
||||||
|
let%bind () =
|
||||||
|
trace_strong (simple_error "entry-point doesn't have a list of operation as first result") @@
|
||||||
|
assert_t_list_operation ops in
|
||||||
|
let%bind () =
|
||||||
|
trace_strong (simple_error "entry-point doesn't identitcal type (storage) for second parameter and second result") @@
|
||||||
|
assert_type_value_eq (storage_param , storage_result) in
|
||||||
|
ok (arg' , storage_param)
|
||||||
|
|
||||||
|
let get_entry_point : program -> string -> (type_value * type_value) result = fun p e ->
|
||||||
|
let%bind declaration = get_declaration_by_name p e in
|
||||||
|
match declaration with
|
||||||
|
| Declaration_constant (d , _) -> get_entry_point_type d.annotated_expression.type_annotation
|
||||||
|
|
||||||
|
let assert_valid_entry_point = fun p e ->
|
||||||
|
let%bind _ = get_entry_point p e in
|
||||||
|
ok ()
|
||||||
|
end
|
||||||
|
|
||||||
|
let transpile_value
|
||||||
|
(e:Ast_typed.annotated_expression) : Mini_c.value result =
|
||||||
|
let%bind f =
|
||||||
|
let open Transpiler in
|
||||||
|
let (f , _) = functionalize e in
|
||||||
|
let%bind main = translate_main f in
|
||||||
|
ok main
|
||||||
|
in
|
||||||
|
|
||||||
|
let input = Mini_c.Combinators.d_unit in
|
||||||
|
let%bind r = Run_mini_c.run_entry f input in
|
||||||
|
ok r
|
||||||
|
|
||||||
|
let compile_contract_file : string -> string -> string result = fun source entry_point ->
|
||||||
|
let%bind raw =
|
||||||
|
trace (simple_error "parsing") @@
|
||||||
|
Parser.parse_file source in
|
||||||
|
let%bind simplified =
|
||||||
|
trace (simple_error "simplifying") @@
|
||||||
|
Simplify.Pascaligo.simpl_program raw in
|
||||||
|
let%bind () =
|
||||||
|
assert_entry_point_defined simplified entry_point in
|
||||||
|
let%bind typed =
|
||||||
|
trace (simple_error "typing") @@
|
||||||
|
Typer.type_program simplified in
|
||||||
|
let%bind mini_c =
|
||||||
|
trace (simple_error "transpiling") @@
|
||||||
|
Transpiler.translate_entry typed entry_point in
|
||||||
|
let%bind michelson =
|
||||||
|
trace (simple_error "compiling") @@
|
||||||
|
Compiler.translate_contract mini_c in
|
||||||
|
let str =
|
||||||
|
Format.asprintf "%a" Micheline.Michelson.pp_stripped michelson in
|
||||||
|
ok str
|
||||||
|
|
||||||
|
let compile_contract_parameter : string -> string -> string -> string result = fun source entry_point expression ->
|
||||||
|
let%bind (program , parameter_tv) =
|
||||||
|
let%bind raw =
|
||||||
|
trace (simple_error "parsing file") @@
|
||||||
|
Parser.parse_file source in
|
||||||
|
let%bind simplified =
|
||||||
|
trace (simple_error "simplifying file") @@
|
||||||
|
Simplify.Pascaligo.simpl_program raw in
|
||||||
|
let%bind () =
|
||||||
|
assert_entry_point_defined simplified entry_point in
|
||||||
|
let%bind typed =
|
||||||
|
trace (simple_error "typing file") @@
|
||||||
|
Typer.type_program simplified in
|
||||||
|
let%bind (param_ty , _) =
|
||||||
|
get_entry_point typed entry_point in
|
||||||
|
ok (typed , param_ty)
|
||||||
|
in
|
||||||
|
let%bind expr =
|
||||||
|
let%bind raw =
|
||||||
|
trace (simple_error "parsing expression") @@
|
||||||
|
Parser.parse_expression expression in
|
||||||
|
let%bind simplified =
|
||||||
|
trace (simple_error "simplifying expression") @@
|
||||||
|
Simplify.Pascaligo.simpl_expression raw in
|
||||||
|
let%bind typed =
|
||||||
|
let env =
|
||||||
|
let last_declaration = Location.unwrap List.(hd @@ rev program) in
|
||||||
|
match last_declaration with
|
||||||
|
| Declaration_constant (_ , env) -> env
|
||||||
|
in
|
||||||
|
trace (simple_error "typing expression") @@
|
||||||
|
Typer.type_annotated_expression env simplified in
|
||||||
|
let%bind () =
|
||||||
|
trace (simple_error "expression type doesn't match type parameter") @@
|
||||||
|
Ast_typed.assert_type_value_eq (parameter_tv , typed.type_annotation) in
|
||||||
|
let%bind mini_c =
|
||||||
|
trace (simple_error "transpiling expression") @@
|
||||||
|
transpile_value typed in
|
||||||
|
let%bind michelson =
|
||||||
|
trace (simple_error "compiling expression") @@
|
||||||
|
Compiler.translate_value mini_c in
|
||||||
|
let str =
|
||||||
|
Format.asprintf "%a" Micheline.Michelson.pp_stripped michelson in
|
||||||
|
ok str
|
||||||
|
in
|
||||||
|
ok expr
|
||||||
|
|
||||||
|
|
||||||
|
let compile_contract_storage : string -> string -> string -> string result = fun source entry_point expression ->
|
||||||
|
let%bind (program , storage_tv) =
|
||||||
|
let%bind raw =
|
||||||
|
trace (simple_error "parsing file") @@
|
||||||
|
Parser.parse_file source in
|
||||||
|
let%bind simplified =
|
||||||
|
trace (simple_error "simplifying file") @@
|
||||||
|
Simplify.Pascaligo.simpl_program raw in
|
||||||
|
let%bind () =
|
||||||
|
assert_entry_point_defined simplified entry_point in
|
||||||
|
let%bind typed =
|
||||||
|
trace (simple_error "typing file") @@
|
||||||
|
Typer.type_program simplified in
|
||||||
|
let%bind (_ , storage_ty) =
|
||||||
|
get_entry_point typed entry_point in
|
||||||
|
ok (typed , storage_ty)
|
||||||
|
in
|
||||||
|
let%bind expr =
|
||||||
|
let%bind raw =
|
||||||
|
trace (simple_error "parsing expression") @@
|
||||||
|
Parser.parse_expression expression in
|
||||||
|
let%bind simplified =
|
||||||
|
trace (simple_error "simplifying expression") @@
|
||||||
|
Simplify.Pascaligo.simpl_expression raw in
|
||||||
|
let%bind typed =
|
||||||
|
let env =
|
||||||
|
let last_declaration = Location.unwrap List.(hd @@ rev program) in
|
||||||
|
match last_declaration with
|
||||||
|
| Declaration_constant (_ , env) -> env
|
||||||
|
in
|
||||||
|
trace (simple_error "typing expression") @@
|
||||||
|
Typer.type_annotated_expression env simplified in
|
||||||
|
let%bind () =
|
||||||
|
trace (simple_error "expression type doesn't match type storage") @@
|
||||||
|
Ast_typed.assert_type_value_eq (storage_tv , typed.type_annotation) in
|
||||||
|
let%bind mini_c =
|
||||||
|
trace (simple_error "transpiling expression") @@
|
||||||
|
transpile_value typed in
|
||||||
|
let%bind michelson =
|
||||||
|
trace (simple_error "compiling expression") @@
|
||||||
|
Compiler.translate_value mini_c in
|
||||||
|
let str =
|
||||||
|
Format.asprintf "%a" Micheline.Michelson.pp_stripped michelson in
|
||||||
|
ok str
|
||||||
|
in
|
||||||
|
ok expr
|
21
main/dune
Normal file
21
main/dune
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
(library
|
||||||
|
(name main)
|
||||||
|
(public_name ligo.main)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
parser
|
||||||
|
simplify
|
||||||
|
ast_simplified
|
||||||
|
typer
|
||||||
|
ast_typed
|
||||||
|
transpiler
|
||||||
|
mini_c
|
||||||
|
operators
|
||||||
|
compiler
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils -open Tezos_utils ))
|
||||||
|
)
|
197
main/main.ml
Normal file
197
main/main.ml
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
module Run_mini_c = Run_mini_c
|
||||||
|
|
||||||
|
open Trace
|
||||||
|
module Parser = Parser
|
||||||
|
module AST_Raw = Parser.Pascaligo.AST
|
||||||
|
module AST_Simplified = Ast_simplified
|
||||||
|
module AST_Typed = Ast_typed
|
||||||
|
module Mini_c = Mini_c
|
||||||
|
module Typer = Typer
|
||||||
|
module Transpiler = Transpiler
|
||||||
|
(* module Parser_multifix = Multifix
|
||||||
|
* module Simplify_multifix = Simplify_multifix *)
|
||||||
|
|
||||||
|
|
||||||
|
let simplify (p:AST_Raw.t) : Ast_simplified.program result = Simplify.Pascaligo.simpl_program p
|
||||||
|
let simplify_expr (e:AST_Raw.expr) : Ast_simplified.annotated_expression result = Simplify.Pascaligo.simpl_expression e
|
||||||
|
let unparse_simplified_expr (e:AST_Simplified.annotated_expression) : string result =
|
||||||
|
ok @@ Format.asprintf "%a" AST_Simplified.PP.annotated_expression e
|
||||||
|
|
||||||
|
let type_ (p:AST_Simplified.program) : AST_Typed.program result = Typer.type_program p
|
||||||
|
let type_expression ?(env:Typer.Environment.t = Typer.Environment.full_empty)
|
||||||
|
(e:AST_Simplified.annotated_expression) : AST_Typed.annotated_expression result =
|
||||||
|
Typer.type_annotated_expression env e
|
||||||
|
let untype_expression (e:AST_Typed.annotated_expression) : AST_Simplified.annotated_expression result = Typer.untype_annotated_expression e
|
||||||
|
|
||||||
|
let transpile (p:AST_Typed.program) : Mini_c.program result = Transpiler.translate_program p
|
||||||
|
let transpile_entry (p:AST_Typed.program) (name:string) : Mini_c.anon_function result = Transpiler.translate_entry p name
|
||||||
|
let transpile_expression ?(env:Mini_c.Environment.t = Mini_c.Environment.empty)
|
||||||
|
(e:AST_Typed.annotated_expression) : Mini_c.expression result = Transpiler.translate_annotated_expression env e
|
||||||
|
let transpile_value
|
||||||
|
(e:AST_Typed.annotated_expression) : Mini_c.value result =
|
||||||
|
let%bind f =
|
||||||
|
let open Transpiler in
|
||||||
|
let (f , _) = functionalize e in
|
||||||
|
let%bind main = translate_main f in
|
||||||
|
ok main
|
||||||
|
in
|
||||||
|
|
||||||
|
let input = Mini_c.Combinators.d_unit in
|
||||||
|
let%bind r = Run_mini_c.run_entry f input in
|
||||||
|
ok r
|
||||||
|
|
||||||
|
let untranspile_value (v : Mini_c.value) (e:AST_Typed.type_value) : AST_Typed.annotated_expression result =
|
||||||
|
Transpiler.untranspile v e
|
||||||
|
|
||||||
|
let compile : Mini_c.program -> string -> Compiler.Program.compiled_program result = Compiler.Program.translate_program
|
||||||
|
|
||||||
|
let type_file ?(debug_simplify = false) ?(debug_typed = false)
|
||||||
|
(path:string) : AST_Typed.program result =
|
||||||
|
let%bind raw = Parser.parse_file path in
|
||||||
|
let%bind simpl =
|
||||||
|
trace (simple_error "simplifying") @@
|
||||||
|
simplify raw in
|
||||||
|
(if debug_simplify then
|
||||||
|
Format.(printf "Simplified : %a\n%!" AST_Simplified.PP.program simpl)
|
||||||
|
) ;
|
||||||
|
let%bind typed =
|
||||||
|
trace (simple_error "typing") @@
|
||||||
|
type_ simpl in
|
||||||
|
(if debug_typed then (
|
||||||
|
Format.(printf "Typed : %a\n%!" AST_Typed.PP.program typed)
|
||||||
|
)) ;
|
||||||
|
ok typed
|
||||||
|
|
||||||
|
|
||||||
|
let easy_evaluate_typed (entry:string) (program:AST_Typed.program) : AST_Typed.annotated_expression result =
|
||||||
|
let%bind result =
|
||||||
|
let%bind mini_c_main =
|
||||||
|
transpile_entry program entry in
|
||||||
|
Run_mini_c.run_entry mini_c_main (Mini_c.Combinators.d_unit) in
|
||||||
|
let%bind typed_result =
|
||||||
|
let%bind typed_main = Ast_typed.get_entry program entry in
|
||||||
|
untranspile_value result typed_main.type_annotation in
|
||||||
|
ok typed_result
|
||||||
|
|
||||||
|
let easy_evaluate_typed_simplified (entry:string) (program:AST_Typed.program) : Ast_simplified.annotated_expression result =
|
||||||
|
let%bind result =
|
||||||
|
let%bind mini_c_main =
|
||||||
|
transpile_entry program entry in
|
||||||
|
Run_mini_c.run_entry mini_c_main (Mini_c.Combinators.d_unit) in
|
||||||
|
let%bind typed_result =
|
||||||
|
let%bind typed_main = Ast_typed.get_entry program entry in
|
||||||
|
untranspile_value result typed_main.type_annotation in
|
||||||
|
let%bind annotated_result = untype_expression typed_result in
|
||||||
|
ok annotated_result
|
||||||
|
|
||||||
|
let easy_evaluate_typed = trace_f_2_ez easy_evaluate_typed (thunk "easy evaluate typed")
|
||||||
|
|
||||||
|
let easy_run_typed
|
||||||
|
?(debug_mini_c = false) ?options (entry:string)
|
||||||
|
(program:AST_Typed.program) (input:AST_Typed.annotated_expression) : AST_Typed.annotated_expression result =
|
||||||
|
let%bind () =
|
||||||
|
let open Ast_typed in
|
||||||
|
let%bind (Declaration_constant (d , _)) = get_declaration_by_name program entry in
|
||||||
|
let%bind (arg_ty , _) =
|
||||||
|
trace_strong (simple_error "entry-point doesn't have a function type") @@
|
||||||
|
get_t_function @@ get_type_annotation d.annotated_expression in
|
||||||
|
Ast_typed.assert_type_value_eq (arg_ty , (Ast_typed.get_type_annotation input))
|
||||||
|
in
|
||||||
|
|
||||||
|
let%bind mini_c_main =
|
||||||
|
trace (simple_error "transpile mini_c entry") @@
|
||||||
|
transpile_entry program entry in
|
||||||
|
(if debug_mini_c then
|
||||||
|
Format.(printf "Mini_c : %a\n%!" Mini_c.PP.function_ mini_c_main)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
let%bind mini_c_value = transpile_value input in
|
||||||
|
|
||||||
|
let%bind mini_c_result =
|
||||||
|
let error =
|
||||||
|
let title () = "run Mini_c" in
|
||||||
|
let content () =
|
||||||
|
Format.asprintf "\n%a" Mini_c.PP.function_ mini_c_main
|
||||||
|
in
|
||||||
|
error title content in
|
||||||
|
trace error @@
|
||||||
|
Run_mini_c.run_entry ?options mini_c_main mini_c_value in
|
||||||
|
let%bind typed_result =
|
||||||
|
let%bind main_result_type =
|
||||||
|
let%bind typed_main = Ast_typed.get_functional_entry program entry in
|
||||||
|
match (snd typed_main).type_value' with
|
||||||
|
| T_function (_, result) -> ok result
|
||||||
|
| _ -> simple_fail "main doesn't have fun type" in
|
||||||
|
untranspile_value mini_c_result main_result_type in
|
||||||
|
ok typed_result
|
||||||
|
|
||||||
|
let easy_run_typed_simplified
|
||||||
|
?(debug_mini_c = false) ?(debug_michelson = false) ?options (entry:string)
|
||||||
|
(program:AST_Typed.program) (input:Ast_simplified.annotated_expression) : Ast_simplified.annotated_expression result =
|
||||||
|
let%bind mini_c_main =
|
||||||
|
trace (simple_error "transpile mini_c entry") @@
|
||||||
|
transpile_entry program entry in
|
||||||
|
(if debug_mini_c then
|
||||||
|
Format.(printf "Mini_c : %a\n%!" Mini_c.PP.function_ mini_c_main)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
let%bind typed_value =
|
||||||
|
let env =
|
||||||
|
let last_declaration = Location.unwrap List.(hd @@ rev program) in
|
||||||
|
match last_declaration with
|
||||||
|
| Declaration_constant (_ , env) -> env
|
||||||
|
in
|
||||||
|
type_expression ~env input in
|
||||||
|
let%bind mini_c_value = transpile_value typed_value in
|
||||||
|
|
||||||
|
let%bind mini_c_result =
|
||||||
|
let error =
|
||||||
|
let title () = "run Mini_c" in
|
||||||
|
let content () =
|
||||||
|
Format.asprintf "\n%a" Mini_c.PP.function_ mini_c_main
|
||||||
|
in
|
||||||
|
error title content in
|
||||||
|
trace error @@
|
||||||
|
Run_mini_c.run_entry ~debug_michelson ?options mini_c_main mini_c_value in
|
||||||
|
let%bind typed_result =
|
||||||
|
let%bind main_result_type =
|
||||||
|
let%bind typed_main = Ast_typed.get_functional_entry program entry in
|
||||||
|
match (snd typed_main).type_value' with
|
||||||
|
| T_function (_, result) -> ok result
|
||||||
|
| _ -> simple_fail "main doesn't have fun type" in
|
||||||
|
untranspile_value mini_c_result main_result_type in
|
||||||
|
let%bind annotated_result = untype_expression typed_result in
|
||||||
|
ok annotated_result
|
||||||
|
|
||||||
|
let easy_run_main_typed
|
||||||
|
?(debug_mini_c = false)
|
||||||
|
(program:AST_Typed.program) (input:AST_Typed.annotated_expression) : AST_Typed.annotated_expression result =
|
||||||
|
easy_run_typed ~debug_mini_c "main" program input
|
||||||
|
|
||||||
|
let easy_run_main (path:string) (input:string) : AST_Typed.annotated_expression result =
|
||||||
|
let%bind typed = type_file path in
|
||||||
|
|
||||||
|
let%bind raw_expr = Parser.parse_expression input in
|
||||||
|
let%bind simpl_expr = simplify_expr raw_expr in
|
||||||
|
let%bind typed_expr = type_expression simpl_expr in
|
||||||
|
easy_run_main_typed typed typed_expr
|
||||||
|
|
||||||
|
let compile_file (source: string) (entry_point:string) : Micheline.Michelson.t result =
|
||||||
|
let%bind raw =
|
||||||
|
trace (simple_error "parsing") @@
|
||||||
|
Parser.parse_file source in
|
||||||
|
let%bind simplified =
|
||||||
|
trace (simple_error "simplifying") @@
|
||||||
|
simplify raw in
|
||||||
|
let%bind typed =
|
||||||
|
trace (simple_error "typing") @@
|
||||||
|
type_ simplified in
|
||||||
|
let%bind mini_c =
|
||||||
|
trace (simple_error "transpiling") @@
|
||||||
|
transpile typed in
|
||||||
|
let%bind {body = michelson} =
|
||||||
|
trace (simple_error "compiling") @@
|
||||||
|
compile mini_c entry_point in
|
||||||
|
ok michelson
|
||||||
|
|
||||||
|
module Contract = Contract
|
60
main/run_mini_c.ml
Normal file
60
main/run_mini_c.ml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
open Trace
|
||||||
|
open Mini_c
|
||||||
|
open! Compiler.Program
|
||||||
|
open Memory_proto_alpha.Script_ir_translator
|
||||||
|
|
||||||
|
let run_aux ?options (program:compiled_program) (input_michelson:Michelson.t) : ex_typed_value result =
|
||||||
|
let Compiler.Program.{input;output;body} : compiled_program = program in
|
||||||
|
let (Ex_ty input_ty) = input in
|
||||||
|
let (Ex_ty output_ty) = output in
|
||||||
|
let%bind input =
|
||||||
|
Trace.trace_tzresult_lwt (simple_error "error parsing input") @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.parse_michelson_data input_michelson input_ty in
|
||||||
|
let body = Michelson.strip_annots body in
|
||||||
|
let%bind descr =
|
||||||
|
Trace.trace_tzresult_lwt (simple_error "error parsing program code") @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.parse_michelson body
|
||||||
|
(Stack.(input_ty @: nil)) (Stack.(output_ty @: nil)) in
|
||||||
|
let open! Memory_proto_alpha.Script_interpreter in
|
||||||
|
let%bind (Item(output, Empty)) =
|
||||||
|
Trace.trace_tzresult_lwt (simple_error "error of execution") @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.interpret ?options descr (Item(input, Empty)) in
|
||||||
|
ok (Ex_typed_value (output_ty, output))
|
||||||
|
|
||||||
|
let run_node (program:program) (input:Michelson.t) : Michelson.t result =
|
||||||
|
let%bind compiled = translate_program program "main" in
|
||||||
|
let%bind (Ex_typed_value (output_ty, output)) = run_aux compiled input in
|
||||||
|
let%bind output =
|
||||||
|
Trace.trace_tzresult_lwt (simple_error "error unparsing output") @@
|
||||||
|
Tezos_utils.Memory_proto_alpha.unparse_michelson_data output_ty output in
|
||||||
|
ok output
|
||||||
|
|
||||||
|
let run_entry ?(debug_michelson = false) ?options (entry:anon_function) (input:value) : value result =
|
||||||
|
let%bind compiled =
|
||||||
|
let error =
|
||||||
|
let title () = "compile entry" in
|
||||||
|
let content () =
|
||||||
|
Format.asprintf "%a" PP.function_ entry
|
||||||
|
in
|
||||||
|
error title content in
|
||||||
|
trace error @@
|
||||||
|
translate_entry entry in
|
||||||
|
if debug_michelson then Format.printf "Program: %a\n" Michelson.pp compiled.body ;
|
||||||
|
let%bind input_michelson = translate_value input in
|
||||||
|
let%bind ex_ty_value = run_aux ?options compiled input_michelson in
|
||||||
|
let%bind (result : value) = Compiler.Uncompiler.translate_value ex_ty_value in
|
||||||
|
ok result
|
||||||
|
|
||||||
|
let run (program:program) (input:value) : value result =
|
||||||
|
let%bind input_michelson = translate_value input in
|
||||||
|
let%bind compiled = translate_program program "main" in
|
||||||
|
let%bind ex_ty_value = run_aux compiled input_michelson in
|
||||||
|
let%bind (result : value) = Compiler.Uncompiler.translate_value ex_ty_value in
|
||||||
|
ok result
|
||||||
|
|
||||||
|
let expression_to_value (e:expression) : value result =
|
||||||
|
match (Combinators.Expression.get_content e) with
|
||||||
|
| E_literal v -> ok v
|
||||||
|
| _ -> fail
|
||||||
|
@@ error (thunk "not a value")
|
||||||
|
@@ (fun () -> Format.asprintf "%a" PP.expression e)
|
30
meta_michelson/alpha_wrap.ml
Normal file
30
meta_michelson/alpha_wrap.ml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
open Tezos_utils.Error_monad
|
||||||
|
|
||||||
|
let dummy_environment = force_lwt ~msg:"getting dummy env" @@ Misc.init_environment ()
|
||||||
|
|
||||||
|
let tc = dummy_environment.tezos_context
|
||||||
|
|
||||||
|
module Proto_alpha = Tezos_utils.Memory_proto_alpha
|
||||||
|
open Proto_alpha
|
||||||
|
open Alpha_context
|
||||||
|
open Alpha_environment
|
||||||
|
|
||||||
|
let pack ty v = fst @@ force_lwt_alpha ~msg:"packing" @@ Script_ir_translator.pack_data tc ty v
|
||||||
|
let unpack_opt (type a) : a Script_typed_ir.ty -> MBytes.t -> a option = fun ty bytes ->
|
||||||
|
force_lwt ~msg:"unpacking : parse" (
|
||||||
|
if Compare.Int.(MBytes.length bytes >= 1) &&
|
||||||
|
Compare.Int.(MBytes.get_uint8 bytes 0 = 0x05) then
|
||||||
|
let bytes = MBytes.sub bytes 1 (MBytes.length bytes - 1) in
|
||||||
|
match Data_encoding.Binary.of_bytes Script.expr_encoding bytes with
|
||||||
|
| None -> return None
|
||||||
|
| Some expr ->
|
||||||
|
Script_ir_translator.parse_data tc ty (Micheline.root expr) >>=?? fun x -> return (Some (fst x))
|
||||||
|
else
|
||||||
|
return None
|
||||||
|
)
|
||||||
|
|
||||||
|
let unpack ty a = match unpack_opt ty a with
|
||||||
|
| None -> raise @@ Failure "unpacking : of_bytes"
|
||||||
|
| Some x -> x
|
||||||
|
|
||||||
|
let blake2b b = Alpha_environment.Raw_hashes.blake2b b
|
316
meta_michelson/contract.ml
Normal file
316
meta_michelson/contract.ml
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
open Misc
|
||||||
|
|
||||||
|
open Tezos_utils.Error_monad
|
||||||
|
open Memory_proto_alpha
|
||||||
|
open Alpha_context
|
||||||
|
|
||||||
|
open Script_ir_translator
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
module Option = Simple_utils.Option
|
||||||
|
module Cast = Tezos_utils.Cast
|
||||||
|
|
||||||
|
type ('param, 'storage) toplevel = {
|
||||||
|
param_type : 'param ty ;
|
||||||
|
storage_type : 'storage ty ;
|
||||||
|
code : ('param * 'storage, packed_internal_operation list * 'storage) lambda
|
||||||
|
}
|
||||||
|
|
||||||
|
type ex_toplevel =
|
||||||
|
Ex_toplevel : ('a, 'b) toplevel -> ex_toplevel
|
||||||
|
|
||||||
|
let get_toplevel ?environment toplevel_path claimed_storage_type claimed_parameter_type =
|
||||||
|
let toplevel_str = Streams.read_file toplevel_path in
|
||||||
|
contextualize ?environment ~msg:"toplevel" @@ fun {tezos_context = context ; _ } ->
|
||||||
|
let toplevel_expr = Cast.tl_of_string toplevel_str in
|
||||||
|
let (param_ty_node, storage_ty_node, code_field) =
|
||||||
|
force_ok_alpha ~msg:"parsing toplevel" @@
|
||||||
|
parse_toplevel toplevel_expr in
|
||||||
|
let (Ex_ty param_type, _) =
|
||||||
|
force_ok_alpha ~msg:"parse arg ty" @@
|
||||||
|
Script_ir_translator.parse_ty context ~allow_big_map:false ~allow_operation:false param_ty_node in
|
||||||
|
let (Ex_ty storage_type, _) =
|
||||||
|
force_ok_alpha ~msg:"parse storage ty" @@
|
||||||
|
parse_storage_ty context storage_ty_node in
|
||||||
|
let _ = force_ok_alpha ~msg:"storage eq" @@ Script_ir_translator.ty_eq context storage_type claimed_storage_type in
|
||||||
|
let _ = force_ok_alpha ~msg:"param eq" @@ Script_ir_translator.ty_eq context param_type claimed_parameter_type in
|
||||||
|
let param_type_full = Pair_t ((claimed_parameter_type, None, None),
|
||||||
|
(claimed_storage_type, None, None), None) in
|
||||||
|
let ret_type_full =
|
||||||
|
Pair_t ((List_t (Operation_t None, None), None, None),
|
||||||
|
(claimed_storage_type, None, None), None) in
|
||||||
|
parse_returning (Toplevel { storage_type = claimed_storage_type ; param_type = claimed_parameter_type })
|
||||||
|
context (param_type_full, None) ret_type_full code_field >>=?? fun (code, _) ->
|
||||||
|
Error_monad.return {
|
||||||
|
param_type = claimed_parameter_type;
|
||||||
|
storage_type = claimed_storage_type;
|
||||||
|
code ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let make_toplevel code storage_type param_type =
|
||||||
|
{ param_type ; storage_type ; code }
|
||||||
|
|
||||||
|
module type ENVIRONMENT = sig
|
||||||
|
val identities : identity list
|
||||||
|
val tezos_context : t
|
||||||
|
end
|
||||||
|
|
||||||
|
type ex_typed_stack = Ex_typed_stack : ('a stack_ty * 'a Script_interpreter.stack) -> ex_typed_stack
|
||||||
|
|
||||||
|
open Error_monad
|
||||||
|
|
||||||
|
module Step (Env: ENVIRONMENT) = struct
|
||||||
|
open Env
|
||||||
|
|
||||||
|
type config = {
|
||||||
|
source : Contract.t option ;
|
||||||
|
payer : Contract.t option ;
|
||||||
|
self : Contract.t option ;
|
||||||
|
visitor : (Script_interpreter.ex_descr_stack -> unit) option ;
|
||||||
|
timestamp : Script_timestamp.t option ;
|
||||||
|
debug_visitor : (ex_typed_stack -> unit) option ;
|
||||||
|
amount : Tez.t option ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let no_config = {
|
||||||
|
source = None ;
|
||||||
|
payer = None ;
|
||||||
|
self = None ;
|
||||||
|
visitor = None ;
|
||||||
|
debug_visitor = None ;
|
||||||
|
timestamp = None ;
|
||||||
|
amount = None ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let of_param base param = match param with
|
||||||
|
| None -> base
|
||||||
|
| Some _ as x -> x
|
||||||
|
|
||||||
|
let make_config ?base_config ?source ?payer ?self ?visitor ?debug_visitor ?timestamp ?amount () =
|
||||||
|
let base_config = Option.unopt ~default:no_config base_config in {
|
||||||
|
source = Option.first_some source base_config.source ;
|
||||||
|
payer = Option.first_some payer base_config.payer ;
|
||||||
|
self = Option.first_some self base_config.self ;
|
||||||
|
visitor = Option.first_some visitor base_config.visitor ;
|
||||||
|
debug_visitor = Option.first_some debug_visitor base_config.debug_visitor ;
|
||||||
|
timestamp = Option.first_some timestamp base_config.timestamp ;
|
||||||
|
amount = Option.first_some amount base_config.amount ;
|
||||||
|
}
|
||||||
|
|
||||||
|
open Error_monad
|
||||||
|
|
||||||
|
let debug_visitor ?f () =
|
||||||
|
let open Script_interpreter in
|
||||||
|
let aux (Ex_descr_stack (descr, stack)) =
|
||||||
|
(match (descr.instr, descr.bef) with
|
||||||
|
| Nop, Item_t (String_t _, stack_ty, _) -> (
|
||||||
|
let (Item (s, stack)) = stack in
|
||||||
|
if s = "_debug"
|
||||||
|
then (
|
||||||
|
match f with
|
||||||
|
| None -> Format.printf "debug: %s\n%!" @@ Cast.stack_to_string stack_ty stack
|
||||||
|
| Some f -> f (Ex_typed_stack(stack_ty, stack))
|
||||||
|
) else ()
|
||||||
|
)
|
||||||
|
| _ -> ()) ;
|
||||||
|
() in
|
||||||
|
aux
|
||||||
|
|
||||||
|
let step_lwt ?(config=no_config) (stack:'a Script_interpreter.stack) (code:('a, 'b) descr) =
|
||||||
|
let source = Option.unopt
|
||||||
|
~default:(List.nth identities 0).implicit_contract config.source in
|
||||||
|
let payer = Option.unopt
|
||||||
|
~default:(List.nth identities 1).implicit_contract config.payer in
|
||||||
|
let self = Option.unopt
|
||||||
|
~default:(List.nth identities 2).implicit_contract config.self in
|
||||||
|
let amount = Option.unopt ~default:(Tez.one) config.amount in
|
||||||
|
let visitor =
|
||||||
|
let default = debug_visitor ?f:config.debug_visitor () in
|
||||||
|
Option.unopt ~default config.visitor in
|
||||||
|
let tezos_context = match config.timestamp with
|
||||||
|
| None -> tezos_context
|
||||||
|
| Some s -> Alpha_context.Script_timestamp.set_now tezos_context s in
|
||||||
|
Script_interpreter.step tezos_context ~source ~payer ~self ~visitor amount code stack >>=?? fun (stack, _) ->
|
||||||
|
return stack
|
||||||
|
|
||||||
|
let step_1_2 ?config (a:'a) (descr:('a * end_of_stack, 'b * ('c * end_of_stack)) descr) =
|
||||||
|
let open Script_interpreter in
|
||||||
|
step_lwt ?config (Item(a, Empty)) descr >>=? fun (Item(b, Item(c, Empty))) ->
|
||||||
|
return (b, c)
|
||||||
|
|
||||||
|
let step_3_1 ?config (a:'a) (b:'b) (c:'c)
|
||||||
|
(descr:('a * ('b * ('c * end_of_stack)), 'd * end_of_stack) descr) =
|
||||||
|
let open Script_interpreter in
|
||||||
|
step_lwt ?config (Item(a, Item(b, Item(c, Empty)))) descr >>=? fun (Item(d, Empty)) ->
|
||||||
|
return d
|
||||||
|
|
||||||
|
let step_2_1 ?config (a:'a) (b:'b) (descr:('a * ('b * end_of_stack), 'c * end_of_stack) descr) =
|
||||||
|
let open Script_interpreter in
|
||||||
|
step_lwt ?config (Item(a, Item(b, Empty))) descr >>=? fun (Item(c, Empty)) ->
|
||||||
|
return c
|
||||||
|
|
||||||
|
let step_1_1 ?config (a:'a) (descr:('a * end_of_stack, 'b * end_of_stack) descr) =
|
||||||
|
let open Script_interpreter in
|
||||||
|
step_lwt ?config (Item(a, Empty)) descr >>=? fun (Item(b, Empty)) ->
|
||||||
|
return b
|
||||||
|
|
||||||
|
let step_value ?config (a:'a) (descr:('a * end_of_stack, 'a * end_of_stack) descr) =
|
||||||
|
step_1_1 ?config a descr
|
||||||
|
|
||||||
|
let step ?config stack code =
|
||||||
|
force_lwt ~msg:"running a step" @@ step_lwt ?config stack code
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
let run_lwt_full ?source ?payer ?self toplevel storage param {identities ; tezos_context = context} =
|
||||||
|
let { code ; _ } : (_, _) toplevel = toplevel in
|
||||||
|
|
||||||
|
let source = Option.unopt
|
||||||
|
~default:(List.nth identities 0).implicit_contract source in
|
||||||
|
let payer = Option.unopt
|
||||||
|
~default:(List.nth identities 1).implicit_contract payer in
|
||||||
|
let self = Option.unopt
|
||||||
|
~default:(List.nth identities 2).implicit_contract self in
|
||||||
|
let amount = Tez.one in
|
||||||
|
|
||||||
|
Script_interpreter.interp context ~source ~payer ~self amount code (param, storage)
|
||||||
|
>>=?? fun ((ops, storage), new_ctxt) ->
|
||||||
|
let gas = Alpha_context.Gas.consumed ~since:context ~until:new_ctxt in
|
||||||
|
return (storage, ops, gas)
|
||||||
|
|
||||||
|
let run_lwt ?source ?payer ?self toplevel storage param env =
|
||||||
|
run_lwt_full ?source ?payer ?self toplevel storage param env >>=? fun (storage, _ops, _gas) ->
|
||||||
|
return storage
|
||||||
|
|
||||||
|
let run ?environment toplevel storage param =
|
||||||
|
contextualize ?environment ~msg:"run toplevel" @@ run_lwt toplevel storage param
|
||||||
|
|
||||||
|
let run_node ?environment toplevel storage_node param_node =
|
||||||
|
contextualize ?environment ~msg:"run toplevel" @@ fun {tezos_context = context ; _} ->
|
||||||
|
let {param_type ; storage_type ; _ } = toplevel in
|
||||||
|
parse_data context param_type param_node >>=?? fun (param, _) ->
|
||||||
|
parse_data context storage_type storage_node >>=?? fun (storage, _) ->
|
||||||
|
let storage = run toplevel storage param in
|
||||||
|
unparse_data context Readable storage_type storage >>=?? fun (storage_node, _) ->
|
||||||
|
return storage_node
|
||||||
|
|
||||||
|
let run_str toplevel storage_str param_str =
|
||||||
|
let param_node = Cast.node_of_string param_str in
|
||||||
|
let storage_node = Cast.node_of_string storage_str in
|
||||||
|
run_node toplevel storage_node param_node
|
||||||
|
|
||||||
|
type input = {
|
||||||
|
toplevel_path : string ;
|
||||||
|
storage : string ;
|
||||||
|
parameter : string
|
||||||
|
}
|
||||||
|
|
||||||
|
let parse_json json_str : input =
|
||||||
|
let json = force_ok_str ~msg:"main_contract: invalid json" @@ Tezos_utils.Data_encoding.Json.from_string json_str in
|
||||||
|
let json = match json with
|
||||||
|
| `O json -> json
|
||||||
|
| _ -> raise @@ Failure "main_contract: not recorD"
|
||||||
|
in
|
||||||
|
let open Json in
|
||||||
|
let toplevel_path = force_string ~msg:"main_contract, top_level" @@ List.assoc "top_level" json in
|
||||||
|
let parameter = force_string ~msg:"main_contract, param" @@ List.assoc "param" json in
|
||||||
|
let storage = force_string ~msg:"main_contract, storage" @@ List.assoc "storage" json in
|
||||||
|
{ toplevel_path ; storage ; parameter }
|
||||||
|
|
||||||
|
let generate_json (storage_node:Script.node) : string =
|
||||||
|
let storage_expr = Tezos_micheline.Micheline.strip_locations storage_node in
|
||||||
|
let json = Data_encoding.Json.construct Script.expr_encoding storage_expr in
|
||||||
|
Format.fprintf Format.str_formatter "%a" Data_encoding.Json.pp json ;
|
||||||
|
Format.flush_str_formatter ()
|
||||||
|
|
||||||
|
module Types = struct
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
let union a b = Union_t ((a, None), (b, None), None)
|
||||||
|
let assert_union = function
|
||||||
|
| Union_t ((a, _), (b, _), _) -> (a, b)
|
||||||
|
| _ -> assert false
|
||||||
|
|
||||||
|
let pair a b = Pair_t ((a, None, None), (b, None, None), None)
|
||||||
|
let assert_pair = function
|
||||||
|
| Pair_t ((a, _, _), ((b, _, _)), _) -> (a, b)
|
||||||
|
| _ -> assert false
|
||||||
|
let assert_pair_ex ?(msg="assert pair") (Ex_ty ty) = match ty with
|
||||||
|
| Pair_t ((a, _, _), ((b, _, _)), _) -> (Ex_ty a, Ex_ty b)
|
||||||
|
| _ -> raise (Failure msg)
|
||||||
|
|
||||||
|
let unit = Unit_t None
|
||||||
|
|
||||||
|
let bytes = Bytes_t None
|
||||||
|
let bytes_k = Bytes_key None
|
||||||
|
|
||||||
|
let nat = Nat_t None
|
||||||
|
let tez = Mutez_t None
|
||||||
|
let int = Int_t None
|
||||||
|
let nat_k = Nat_key None
|
||||||
|
let tez_k = Mutez_key None
|
||||||
|
let int_k = Int_key None
|
||||||
|
|
||||||
|
let big_map k v = Big_map_t (k, v, None)
|
||||||
|
|
||||||
|
let signature = Signature_t None
|
||||||
|
let operation = Operation_t None
|
||||||
|
|
||||||
|
let bool = Bool_t None
|
||||||
|
|
||||||
|
let mutez = Mutez_t None
|
||||||
|
|
||||||
|
let string = String_t None
|
||||||
|
let string_k = String_key None
|
||||||
|
let address_k = Address_key None
|
||||||
|
|
||||||
|
let key = Key_t None
|
||||||
|
|
||||||
|
let list a = List_t (a, None)
|
||||||
|
let assert_list = function
|
||||||
|
| List_t (a, _) -> a
|
||||||
|
| _ -> assert false
|
||||||
|
|
||||||
|
let option a = Option_t ((a, None), None, None)
|
||||||
|
let contract a = Contract_t (a, None)
|
||||||
|
let assert_option = function
|
||||||
|
| Option_t ((a, _), _, _) -> a
|
||||||
|
| _ -> assert false
|
||||||
|
|
||||||
|
let address = Address_t None
|
||||||
|
|
||||||
|
let lambda a b = Lambda_t (a, b, None)
|
||||||
|
let assert_lambda = function
|
||||||
|
| Lambda_t (a, b, _) -> (a, b)
|
||||||
|
| _ -> assert false
|
||||||
|
type ex_lambda = Ex_lambda : (_, _) lambda ty -> ex_lambda
|
||||||
|
let is_lambda : type a . a ty -> ex_lambda option = function
|
||||||
|
| Lambda_t (_, _, _) as x -> Some (Ex_lambda x)
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let timestamp = Timestamp_t None
|
||||||
|
let timestamp_k = Timestamp_key None
|
||||||
|
|
||||||
|
let map a b = Map_t (a, b, None)
|
||||||
|
|
||||||
|
let assert_type (_:'a ty) (_:'a) = ()
|
||||||
|
end
|
||||||
|
|
||||||
|
module Values = struct
|
||||||
|
let empty_map t = empty_map t
|
||||||
|
|
||||||
|
let empty_big_map key_type comparable_key_ty value_type : ('a, 'b) big_map = {
|
||||||
|
key_type ; value_type ; diff = empty_map comparable_key_ty ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let int n = Script_int.of_int n
|
||||||
|
|
||||||
|
let nat n = Script_int.abs @@ Script_int.of_int n
|
||||||
|
let nat_to_int n = Option.unopt_exn @@ Script_int.to_int n
|
||||||
|
|
||||||
|
let tez n = Option.unopt_exn @@ Tez.of_mutez @@ Int64.of_int n
|
||||||
|
|
||||||
|
let left a = L a
|
||||||
|
|
||||||
|
let right b = R b
|
||||||
|
end
|
10
meta_michelson/dune
Normal file
10
meta_michelson/dune
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
(library
|
||||||
|
(name meta_michelson)
|
||||||
|
(public_name ligo.meta_michelson)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
michelson-parser
|
||||||
|
tezos-micheline
|
||||||
|
)
|
||||||
|
)
|
7
meta_michelson/json.ml
Normal file
7
meta_michelson/json.ml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
let force_record ~msg json = match json with
|
||||||
|
| `O json -> json
|
||||||
|
| _ -> raise @@ Failure ("not json record : " ^ msg)
|
||||||
|
|
||||||
|
let force_string ~msg json = match json with
|
||||||
|
| `String str -> str
|
||||||
|
| _ -> raise @@ Failure ("not json str : " ^ msg)
|
12
meta_michelson/meta_michelson.ml
Normal file
12
meta_michelson/meta_michelson.ml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module Run = struct
|
||||||
|
open Contract
|
||||||
|
let run_lwt_full = run_lwt_full
|
||||||
|
let run_lwt = run_lwt
|
||||||
|
let run_str = run_str
|
||||||
|
let run_node = run_node
|
||||||
|
let run = run
|
||||||
|
end
|
||||||
|
module Stack = Michelson_wrap.Stack
|
||||||
|
module Values = Contract.Values
|
||||||
|
module Types = Contract.Types
|
||||||
|
|
514
meta_michelson/michelson_wrap.ml
Normal file
514
meta_michelson/michelson_wrap.ml
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
open Tezos_utils.Memory_proto_alpha
|
||||||
|
module AC = Alpha_context
|
||||||
|
|
||||||
|
module Types = Contract.Types
|
||||||
|
module Option = Simple_utils.Option
|
||||||
|
module MBytes = Alpha_environment.MBytes
|
||||||
|
|
||||||
|
module Stack = struct
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
let descr bef aft instr =
|
||||||
|
{
|
||||||
|
loc = 0 ;
|
||||||
|
bef ; aft ; instr
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonrec 'a ty = 'a ty
|
||||||
|
type 'a t = 'a stack_ty
|
||||||
|
type nonrec ('a, 'b) descr = ('a, 'b) descr
|
||||||
|
type ('a, 'b) code = ('a t) -> ('a, 'b) descr
|
||||||
|
|
||||||
|
type ex_stack_ty = Ex_stack_ty : 'a t -> ex_stack_ty
|
||||||
|
type ex_descr = Ex_descr : ('a, 'b) descr -> ex_descr
|
||||||
|
type ex_code = Ex_code : ('a, 'b) code -> ex_code
|
||||||
|
|
||||||
|
let stack ?annot a b = Item_t (a, b, annot)
|
||||||
|
let unstack (item: (('a * 'rest) stack_ty)) : ('a ty * 'rest stack_ty) =
|
||||||
|
let Item_t (hd, tl, _) = item in
|
||||||
|
(hd, tl)
|
||||||
|
|
||||||
|
let nil = Empty_t
|
||||||
|
let head x = fst @@ unstack x
|
||||||
|
let tail x = snd @@ unstack x
|
||||||
|
|
||||||
|
let seq a b bef =
|
||||||
|
let a_descr = a bef in
|
||||||
|
let b_descr = b a_descr.aft in
|
||||||
|
let aft = b_descr.aft in
|
||||||
|
descr bef aft @@ Seq (a_descr, b_descr)
|
||||||
|
|
||||||
|
let (@>) (stack : 'b t) (code : ('a, 'b) code) = code stack
|
||||||
|
let (@|) = seq
|
||||||
|
let (@:) = stack
|
||||||
|
|
||||||
|
let (!:) : ('a, 'b) descr -> ('a, 'b) code = fun d _ -> d
|
||||||
|
|
||||||
|
let (<.) (stack:'a t) (code: ('a, 'b) code): ('a, 'b) descr = code stack
|
||||||
|
|
||||||
|
let (<::) : ('a, 'b) descr -> ('b, 'c) descr -> ('a, 'c) descr = fun ab bc ->
|
||||||
|
descr ab.bef bc.aft @@ Seq(ab, bc)
|
||||||
|
|
||||||
|
let (<:) (ab_descr:('a, 'b) descr) (code:('b, 'c) code) : ('a, 'c) descr =
|
||||||
|
let bc_descr = code ab_descr.aft in
|
||||||
|
ab_descr <:: bc_descr
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
open Stack
|
||||||
|
|
||||||
|
type nat = AC.Script_int.n AC.Script_int.num
|
||||||
|
type int_num = AC.Script_int.z AC.Script_int.num
|
||||||
|
type bytes = MBytes.t
|
||||||
|
type address = AC.Contract.t Script_typed_ir.ty
|
||||||
|
type mutez = AC.Tez.t Script_typed_ir.ty
|
||||||
|
|
||||||
|
|
||||||
|
module Stack_ops = struct
|
||||||
|
open Script_typed_ir
|
||||||
|
let dup : ('a * 'rest, 'a * ('a * 'rest)) code = fun bef ->
|
||||||
|
let Item_t (ty, rest, _) = bef in
|
||||||
|
descr bef (Item_t (ty, Item_t (ty, rest, None), None)) Dup
|
||||||
|
|
||||||
|
let drop : ('a * 'rest, 'rest) code = fun bef ->
|
||||||
|
let aft = snd @@ unstack bef in
|
||||||
|
descr bef aft Drop
|
||||||
|
|
||||||
|
let swap (bef : (('a * ('b * 'c)) stack_ty)) =
|
||||||
|
let Item_t (a, Item_t (b, rest, _), _) = bef in
|
||||||
|
descr bef (Item_t (b, (Item_t (a, rest, None)), None)) Swap
|
||||||
|
|
||||||
|
let dip code (bef : ('ty * 'rest) stack_ty) =
|
||||||
|
let Item_t (ty, rest, _) = bef in
|
||||||
|
let applied = code rest in
|
||||||
|
let aft = Item_t (ty, applied.aft, None) in
|
||||||
|
descr bef aft (Dip (code rest))
|
||||||
|
|
||||||
|
let noop : ('r, 'r) code = fun bef ->
|
||||||
|
descr bef bef Nop
|
||||||
|
|
||||||
|
let exec : (_, _) code = fun bef ->
|
||||||
|
let lambda = head @@ tail bef in
|
||||||
|
let (_, ret) = Types.assert_lambda lambda in
|
||||||
|
let aft = ret @: (tail @@ tail bef) in
|
||||||
|
descr bef aft Exec
|
||||||
|
|
||||||
|
let fail aft : ('a * 'r, 'b) code = fun bef ->
|
||||||
|
let head = fst @@ unstack bef in
|
||||||
|
descr bef aft (Failwith head)
|
||||||
|
|
||||||
|
let push_string str (bef : 'rest stack_ty) : (_, (string * 'rest)) descr =
|
||||||
|
let aft = Item_t (Types.string, bef, None) in
|
||||||
|
descr bef aft (Const (str))
|
||||||
|
|
||||||
|
let push_none (a:'a ty) : ('rest, 'a option * 'rest) code = fun r ->
|
||||||
|
let aft = stack (Types.option a) r in
|
||||||
|
descr r aft (Const None)
|
||||||
|
|
||||||
|
let push_unit : ('rest, unit * 'rest) code = fun r ->
|
||||||
|
let aft = stack Types.unit r in
|
||||||
|
descr r aft (Const ())
|
||||||
|
|
||||||
|
let push_nat n (bef : 'rest stack_ty) : (_, (nat * 'rest)) descr =
|
||||||
|
let aft = Item_t (Types.nat, bef, None) in
|
||||||
|
descr bef aft (Const (Contract.Values.nat n))
|
||||||
|
|
||||||
|
let push_int n (bef : 'rest stack_ty) : (_, (int_num * 'rest)) descr =
|
||||||
|
let aft = Types.int @: bef in
|
||||||
|
descr bef aft (Const (Contract.Values.int n))
|
||||||
|
|
||||||
|
let push_tez n (bef : 'rest stack_ty) : (_, (AC.Tez.tez * 'rest)) descr =
|
||||||
|
let aft = Types.mutez @: bef in
|
||||||
|
descr bef aft (Const (Contract.Values.tez n))
|
||||||
|
|
||||||
|
let push_bool b : ('s, bool * 's) code = fun bef ->
|
||||||
|
let aft = stack Types.bool bef in
|
||||||
|
descr bef aft (Const b)
|
||||||
|
|
||||||
|
let push_generic ty v : ('s, _ * 's) code = fun bef ->
|
||||||
|
let aft = stack ty bef in
|
||||||
|
descr bef aft (Const v)
|
||||||
|
|
||||||
|
let failstring str aft =
|
||||||
|
push_string str @| fail aft
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Stack_shortcuts = struct
|
||||||
|
open Stack_ops
|
||||||
|
|
||||||
|
let diip c x = dip (dip c) x
|
||||||
|
let diiip c x = dip (diip c) x
|
||||||
|
let diiiip c x = dip (diiip c) x
|
||||||
|
|
||||||
|
let bubble_1 = swap
|
||||||
|
let bubble_down_1 = swap
|
||||||
|
|
||||||
|
let bubble_2 : ('a * ('b * ('c * 'r)), 'c * ('a * ('b * 'r))) code = fun bef ->
|
||||||
|
bef <. dip swap <: swap
|
||||||
|
let bubble_down_2 : ('a * ('b * ('c * 'r)), ('b * ('c * ('a * 'r)))) code = fun bef ->
|
||||||
|
bef <. swap <: dip swap
|
||||||
|
|
||||||
|
let bubble_3 : ('a * ('b * ('c * ('d * 'r))), 'd * ('a * ('b * ('c * 'r)))) code = fun bef ->
|
||||||
|
bef <. diip swap <: dip swap <: swap
|
||||||
|
|
||||||
|
let keep_1 : type r s . ('a * r, s) code -> ('a * r, 'a * s) code = fun code bef ->
|
||||||
|
bef <. dup <: dip code
|
||||||
|
|
||||||
|
let save_1_1 : type r . ('a * r, 'b * r) code -> ('a * r, 'b * ('a * r)) code = fun code s ->
|
||||||
|
s <. keep_1 code <: swap
|
||||||
|
|
||||||
|
let keep_2 : type r s . ('a * ('b * r), s) code -> ('a * ('b * r), ('a * ('b * s))) code = fun code bef ->
|
||||||
|
(dup @| dip (swap @| dup @| dip (swap @| code))) bef
|
||||||
|
|
||||||
|
let keep_2_1 : type r s . ('a * ('b * r), s) code -> ('a * ('b * r), 'b * s) code = fun code bef ->
|
||||||
|
(dip dup @| swap @| dip code) bef
|
||||||
|
|
||||||
|
let relativize_1_1 : ('a * unit, 'b * unit) descr -> ('a * 'r, 'b * 'r) code = fun d s ->
|
||||||
|
let aft = head d.aft @: tail s in
|
||||||
|
descr s aft d.instr
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Pair_ops = struct
|
||||||
|
let car (bef : (('a * 'b) * 'rest) Stack.t) =
|
||||||
|
let (pair, rest) = unstack bef in
|
||||||
|
let (a, _) = Contract.Types.assert_pair pair in
|
||||||
|
descr bef (stack a rest) Car
|
||||||
|
|
||||||
|
let cdr (bef : (('a * 'b) * 'rest) Stack.t) =
|
||||||
|
let (pair, rest) = unstack bef in
|
||||||
|
let (_, b) = Contract.Types.assert_pair pair in
|
||||||
|
descr bef (stack b rest) Cdr
|
||||||
|
|
||||||
|
let pair (bef : ('a * ('b * 'rest)) Stack.t) =
|
||||||
|
let (a, rest) = unstack bef in
|
||||||
|
let (b, rest) = unstack rest in
|
||||||
|
let aft = (Types.pair a b) @: rest in
|
||||||
|
descr bef aft Cons_pair
|
||||||
|
|
||||||
|
open Stack_ops
|
||||||
|
let carcdr s = s <. car <: Stack_ops.dip cdr
|
||||||
|
|
||||||
|
let cdrcar s = s <. cdr <: dip car
|
||||||
|
|
||||||
|
let cdrcdr s = s <. cdr <: dip cdr
|
||||||
|
|
||||||
|
let carcar s = s <. car <: dip car
|
||||||
|
|
||||||
|
let cdar s = s <. cdr <: car
|
||||||
|
|
||||||
|
let unpair s = s <. dup <: car <: dip cdr
|
||||||
|
end
|
||||||
|
|
||||||
|
module Option_ops = struct
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
let cons bef =
|
||||||
|
let (hd, tl) = unstack bef in
|
||||||
|
descr bef (stack (Contract.Types.option hd) tl) Cons_some
|
||||||
|
|
||||||
|
let cond ?target none_branch some_branch : ('a option * 'r, 'b) code = fun bef ->
|
||||||
|
let (a_opt, base) = unstack bef in
|
||||||
|
let a = Types.assert_option a_opt in
|
||||||
|
let target = Option.unopt ~default:(none_branch base).aft target in
|
||||||
|
descr bef target (If_none (none_branch base, some_branch (stack a base)))
|
||||||
|
|
||||||
|
let force_some ?msg : ('a option * 'r, 'a * 'r) code = fun s ->
|
||||||
|
let (a_opt, base) = unstack s in
|
||||||
|
let a = Types.assert_option a_opt in
|
||||||
|
let target = a @: base in
|
||||||
|
cond ~target
|
||||||
|
(Stack_ops.failstring ("force_some : " ^ Option.unopt ~default:"" msg) target)
|
||||||
|
Stack_ops.noop s
|
||||||
|
end
|
||||||
|
|
||||||
|
module Union_ops = struct
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
let left (b:'b ty) : ('a * 'r, ('a, 'b) union * 'r) code = fun bef ->
|
||||||
|
let (a, base) = unstack bef in
|
||||||
|
let aft = Types.union a b @: base in
|
||||||
|
descr bef aft Left
|
||||||
|
|
||||||
|
let right (a:'a ty) : ('b * 'r, ('a, 'b) union * 'r) code = fun bef ->
|
||||||
|
let (b, base) = unstack bef in
|
||||||
|
let aft = Types.union a b @: base in
|
||||||
|
descr bef aft Right
|
||||||
|
|
||||||
|
|
||||||
|
let loop ?after (code: ('a * 'r, ('a, 'b) union * 'r) code): (('a, 'b) union * 'r, 'b * 'r) code = fun bef ->
|
||||||
|
let (union, base) = unstack bef in
|
||||||
|
let (a, b) = Types.assert_union union in
|
||||||
|
let code_stack = a @: base in
|
||||||
|
let aft = Option.unopt ~default:(b @: base) after in
|
||||||
|
descr bef aft (Loop_left (code code_stack))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Arithmetic = struct
|
||||||
|
let neq : (int_num * 'r, bool *'r) code = fun bef ->
|
||||||
|
let aft = stack Types.bool @@ snd @@ unstack bef in
|
||||||
|
descr bef aft Neq
|
||||||
|
|
||||||
|
let neg : (int_num * 'r, int_num *'r) code = fun bef ->
|
||||||
|
let aft = stack Types.int @@ snd @@ unstack bef in
|
||||||
|
descr bef aft Neg_int
|
||||||
|
|
||||||
|
let abs : (int_num * 'r, nat *'r) code = fun bef ->
|
||||||
|
let aft = stack Types.nat @@ snd @@ unstack bef in
|
||||||
|
descr bef aft Abs_int
|
||||||
|
|
||||||
|
let int : (nat * 'r, int_num*'r) code = fun bef ->
|
||||||
|
let aft = stack Types.int @@ snd @@ unstack bef in
|
||||||
|
descr bef aft Int_nat
|
||||||
|
|
||||||
|
let nat_opt : (int_num * 'r, nat option * 'r) code = fun bef ->
|
||||||
|
let aft = stack Types.(option nat) @@ tail bef in
|
||||||
|
descr bef aft Is_nat
|
||||||
|
|
||||||
|
let nat_neq = fun s -> (int @| neq) s
|
||||||
|
|
||||||
|
let add_natnat (bef : (nat * (nat * 'rest)) Stack.t) =
|
||||||
|
let (nat, rest) = unstack bef in
|
||||||
|
let rest = tail rest in
|
||||||
|
let aft = stack nat rest in
|
||||||
|
descr bef aft Add_natnat
|
||||||
|
|
||||||
|
let add_intint (bef : (int_num * (int_num * 'rest)) Stack.t) =
|
||||||
|
let (nat, rest) = unstack bef in
|
||||||
|
let rest = tail rest in
|
||||||
|
let aft = stack nat rest in
|
||||||
|
descr bef aft Add_intint
|
||||||
|
|
||||||
|
let add_teztez : (AC.Tez.tez * (AC.Tez.tez * 'rest), _) code = fun bef ->
|
||||||
|
let aft = tail bef in
|
||||||
|
descr bef aft Add_tez
|
||||||
|
|
||||||
|
let mul_natnat (bef : (nat * (nat * 'rest)) Stack.t) =
|
||||||
|
let nat = head bef in
|
||||||
|
let rest = tail @@ tail bef in
|
||||||
|
let aft = stack nat rest in
|
||||||
|
descr bef aft Mul_natnat
|
||||||
|
|
||||||
|
let mul_intint (bef : (int_num * (int_num * 'rest)) Stack.t) =
|
||||||
|
let nat = head bef in
|
||||||
|
let rest = tail @@ tail bef in
|
||||||
|
let aft = stack nat rest in
|
||||||
|
descr bef aft Mul_intint
|
||||||
|
|
||||||
|
let sub_intint : (int_num * (int_num * 'r), int_num * 'r) code = fun bef ->
|
||||||
|
let aft = tail bef in
|
||||||
|
descr bef aft Sub_int
|
||||||
|
|
||||||
|
let sub_natnat : (nat * (nat * 'r), int_num * 'r) code =
|
||||||
|
fun bef -> bef <. int <: Stack_ops.dip int <: sub_intint
|
||||||
|
|
||||||
|
let ediv : (nat * (nat * 'r), (nat * nat) option * 'r) code = fun s ->
|
||||||
|
let (n, base) = unstack @@ snd @@ unstack s in
|
||||||
|
let aft = Types.option (Types.pair n n) @: base in
|
||||||
|
descr s aft Ediv_natnat
|
||||||
|
|
||||||
|
let ediv_tez = fun s ->
|
||||||
|
let aft = Types.(option @@ pair (head s) (head s)) @: tail @@ tail s in
|
||||||
|
descr s aft Ediv_teznat
|
||||||
|
|
||||||
|
open Option_ops
|
||||||
|
let force_ediv x = x <. ediv <: force_some
|
||||||
|
let force_ediv_tez x = (ediv_tez @| force_some) x
|
||||||
|
|
||||||
|
open Pair_ops
|
||||||
|
let div x = x <. force_ediv <: car
|
||||||
|
|
||||||
|
open Stack_ops
|
||||||
|
let div_n n s = s <. push_nat n <: swap <: div
|
||||||
|
let add_n n s = s <. push_nat n <: swap <: add_natnat
|
||||||
|
let add_teztez_n n s = s <. push_tez n <: swap <: add_teztez
|
||||||
|
let sub_n n s = s <. push_nat n <: swap <: sub_natnat
|
||||||
|
|
||||||
|
let force_nat s = s <. nat_opt <: force_some ~msg:"force nat"
|
||||||
|
end
|
||||||
|
|
||||||
|
module Boolean = struct
|
||||||
|
let bool_and (type r) : (bool * (bool * r), bool * r) code = fun bef ->
|
||||||
|
let aft = Types.bool @: tail @@ tail bef in
|
||||||
|
descr bef aft And
|
||||||
|
|
||||||
|
let bool_or (type r) : (bool * (bool * r), bool * r) code = fun bef ->
|
||||||
|
let aft = Types.bool @: tail @@ tail bef in
|
||||||
|
descr bef aft Or
|
||||||
|
|
||||||
|
open Script_typed_ir
|
||||||
|
let cond ?target true_branch false_branch : (bool * 'r, 's) code = fun bef ->
|
||||||
|
let base = tail bef in
|
||||||
|
let aft = Option.unopt ~default:((true_branch base).aft) target in
|
||||||
|
descr bef aft (If (true_branch base, false_branch base))
|
||||||
|
|
||||||
|
let loop (code : ('s, bool * 's) code) : ((bool * 's), 's) code = fun bef ->
|
||||||
|
let aft = tail bef in
|
||||||
|
descr bef aft @@ Loop (code aft)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Comparison_ops = struct
|
||||||
|
let cmp c_ty : _ code = fun bef ->
|
||||||
|
let aft = stack Contract.Types.int @@ tail @@ tail @@ bef in
|
||||||
|
descr bef aft (Compare c_ty)
|
||||||
|
|
||||||
|
let cmp_bytes = fun x -> cmp (Bytes_key None) x
|
||||||
|
|
||||||
|
let eq : (int_num * 'r, bool *'r) code = fun bef ->
|
||||||
|
let aft = stack Contract.Types.bool @@ snd @@ unstack bef in
|
||||||
|
descr bef aft Eq
|
||||||
|
|
||||||
|
open Arithmetic
|
||||||
|
let eq_n n s = s <. sub_n n <: eq
|
||||||
|
|
||||||
|
let ge : (int_num * 'r, bool * 'r) code = fun bef ->
|
||||||
|
let base = tail bef in
|
||||||
|
let aft = stack Types.bool base in
|
||||||
|
descr bef aft Ge
|
||||||
|
|
||||||
|
let gt : (int_num * 'r, bool * 'r) code = fun bef ->
|
||||||
|
let base = tail bef in
|
||||||
|
let aft = stack Types.bool base in
|
||||||
|
descr bef aft Gt
|
||||||
|
|
||||||
|
let lt : (int_num * 'r, bool * 'r) code = fun bef ->
|
||||||
|
let base = tail bef in
|
||||||
|
let aft = stack Types.bool base in
|
||||||
|
descr bef aft Lt
|
||||||
|
|
||||||
|
let gt_nat s = s <. int <: gt
|
||||||
|
|
||||||
|
open Stack_ops
|
||||||
|
let assert_positive_nat s = s <. dup <: gt_nat <: Boolean.cond noop (failstring "positive" s)
|
||||||
|
|
||||||
|
let cmp_ge_nat : (nat * (nat * 'r), bool * 'r) code = fun bef ->
|
||||||
|
bef <. sub_natnat <: ge
|
||||||
|
|
||||||
|
let cmp_ge_timestamp : (AC.Script_timestamp.t * (AC.Script_timestamp.t * 'r), bool * 'r) code = fun bef ->
|
||||||
|
bef <. cmp Types.timestamp_k <: ge
|
||||||
|
|
||||||
|
let assert_cmp_ge_nat : (nat * (nat * 'r), 'r) code = fun bef ->
|
||||||
|
bef <. cmp_ge_nat <: Boolean.cond noop (failstring "assert cmp ge nat" (tail @@ tail bef))
|
||||||
|
|
||||||
|
let assert_cmp_ge_timestamp : (AC.Script_timestamp.t * (AC.Script_timestamp.t * 'r), 'r) code = fun bef ->
|
||||||
|
bef <. cmp_ge_timestamp <: Boolean.cond noop (failstring "assert cmp ge timestamp" (tail @@ tail bef))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
module Bytes = struct
|
||||||
|
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
let pack (ty:'a ty) : ('a * 'r, bytes * 'r) code = fun bef ->
|
||||||
|
let aft = stack Types.bytes @@ tail bef in
|
||||||
|
descr bef aft (Pack ty)
|
||||||
|
|
||||||
|
let unpack_opt : type a . a ty -> (bytes * 'r, a option * 'r) code = fun ty bef ->
|
||||||
|
let aft = stack (Types.option ty) (tail bef) in
|
||||||
|
descr bef aft (Unpack ty)
|
||||||
|
|
||||||
|
let unpack ty s = s <. unpack_opt ty <: Option_ops.force_some
|
||||||
|
|
||||||
|
let concat : (MBytes.t * (MBytes.t * 'rest), MBytes.t * 'rest) code = fun bef ->
|
||||||
|
let aft = tail bef in
|
||||||
|
descr bef aft Concat_bytes_pair
|
||||||
|
|
||||||
|
let sha256 : (MBytes.t * 'rest, MBytes.t * 'rest) code = fun bef ->
|
||||||
|
descr bef bef Sha256
|
||||||
|
|
||||||
|
let blake2b : (MBytes.t * 'rest, MBytes.t * 'rest) code = fun bef ->
|
||||||
|
descr bef bef Blake2b
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
module Map = struct
|
||||||
|
open Script_typed_ir
|
||||||
|
|
||||||
|
type ('a, 'b) t = ('a, 'b) map
|
||||||
|
|
||||||
|
let empty c_ty = Script_ir_translator.empty_map c_ty
|
||||||
|
let set (type a b) m (k:a) (v:b) = Script_ir_translator.map_update k (Some v) m
|
||||||
|
|
||||||
|
module Ops = struct
|
||||||
|
let update (bef : (('a * ('b option * (('a, 'b) map * ('rest)))) Stack.t)) : (_, ('a, 'b) map * 'rest) descr =
|
||||||
|
let Item_t (_, Item_t (_, Item_t (map, rest, _), _), _) = bef in
|
||||||
|
let aft = Item_t (map, rest, None) in
|
||||||
|
descr bef aft Map_update
|
||||||
|
|
||||||
|
let get : ?a:('a ty) -> 'b ty -> ('a * (('a, 'b) map * 'r), 'b option * 'r) code = fun ?a b bef ->
|
||||||
|
let _ = a in
|
||||||
|
let base = snd @@ unstack @@ snd @@ unstack bef in
|
||||||
|
let aft = stack (Types.option b) base in
|
||||||
|
descr bef aft Map_get
|
||||||
|
|
||||||
|
let big_get : 'a ty -> 'b ty -> ('a * (('a, 'b) big_map * 'r), 'b option * 'r) code = fun _a b bef ->
|
||||||
|
let base = snd @@ unstack @@ snd @@ unstack bef in
|
||||||
|
let aft = stack (Types.option b) base in
|
||||||
|
descr bef aft Big_map_get
|
||||||
|
|
||||||
|
let big_update : ('a * ('b option * (('a, 'b) big_map * 'r)), ('a, 'b) big_map * 'r) code = fun bef ->
|
||||||
|
let base = tail @@ tail bef in
|
||||||
|
descr bef base Big_map_update
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module List_ops = struct
|
||||||
|
let nil ele bef =
|
||||||
|
let aft = stack (Types.list ele) bef in
|
||||||
|
descr bef aft Nil
|
||||||
|
|
||||||
|
let cons bef =
|
||||||
|
let aft = tail bef in
|
||||||
|
descr bef aft Cons_list
|
||||||
|
|
||||||
|
let cond ~target cons_branch nil_branch bef =
|
||||||
|
let (lst, aft) = unstack bef in
|
||||||
|
let a = Types.assert_list lst in
|
||||||
|
let cons_descr = cons_branch (a @: Types.list a @: aft) in
|
||||||
|
let nil_descr = nil_branch aft in
|
||||||
|
descr bef target (If_cons (cons_descr, nil_descr))
|
||||||
|
|
||||||
|
let list_iter : type a r . (a * r, r) code -> (a list * r, r) code = fun code bef ->
|
||||||
|
let (a_lst, aft) = unstack bef in
|
||||||
|
let a = Types.assert_list a_lst in
|
||||||
|
descr bef aft (List_iter (code (a @: aft)))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Tez = struct
|
||||||
|
|
||||||
|
let amount : ('r, AC.Tez.t * 'r) code = fun bef ->
|
||||||
|
let aft = Types.mutez @: bef in
|
||||||
|
descr bef aft Amount
|
||||||
|
|
||||||
|
open Bytes
|
||||||
|
|
||||||
|
let tez_nat s = s <. pack Types.mutez <: unpack Types.nat
|
||||||
|
let amount_nat s = s <. amount <: pack Types.mutez <: unpack Types.nat
|
||||||
|
end
|
||||||
|
|
||||||
|
module Misc = struct
|
||||||
|
|
||||||
|
open Stack_ops
|
||||||
|
open Stack_shortcuts
|
||||||
|
open Comparison_ops
|
||||||
|
let min_nat : (nat * (nat * 'r), nat * 'r) code = fun s ->
|
||||||
|
s <.
|
||||||
|
keep_2 cmp_ge_nat <: bubble_2 <:
|
||||||
|
Boolean.cond drop (dip drop)
|
||||||
|
|
||||||
|
let debug ~msg () s = s <. push_string msg <: push_string "_debug" <: noop <: drop <: drop
|
||||||
|
|
||||||
|
let debug_msg msg = debug ~msg ()
|
||||||
|
|
||||||
|
let now : ('r, AC.Script_timestamp.t * 'r) code = fun bef ->
|
||||||
|
let aft = stack Types.timestamp bef in
|
||||||
|
descr bef aft Now
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
302
meta_michelson/misc.ml
Normal file
302
meta_michelson/misc.ml
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
module Signature = Tezos_base.TzPervasives.Signature
|
||||||
|
open Tezos_utils.Memory_proto_alpha
|
||||||
|
module Data_encoding = Alpha_environment.Data_encoding
|
||||||
|
module MBytes = Alpha_environment.MBytes
|
||||||
|
module Error_monad = Tezos_utils.Error_monad
|
||||||
|
open Error_monad
|
||||||
|
|
||||||
|
module Context_init = struct
|
||||||
|
|
||||||
|
type account = {
|
||||||
|
pkh : Signature.Public_key_hash.t ;
|
||||||
|
pk : Signature.Public_key.t ;
|
||||||
|
sk : Signature.Secret_key.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let generate_accounts n : (account * Tez_repr.t) list =
|
||||||
|
let amount = Tez_repr.of_mutez_exn 4_000_000_000_000L in
|
||||||
|
List.map (fun _ ->
|
||||||
|
let (pkh, pk, sk) = Signature.generate_key () in
|
||||||
|
let account = { pkh ; pk ; sk } in
|
||||||
|
account, amount)
|
||||||
|
(Simple_utils.List.range n)
|
||||||
|
|
||||||
|
let make_shell
|
||||||
|
~level ~predecessor ~timestamp ~fitness ~operations_hash =
|
||||||
|
Tezos_base.Block_header.{
|
||||||
|
level ;
|
||||||
|
predecessor ;
|
||||||
|
timestamp ;
|
||||||
|
fitness ;
|
||||||
|
operations_hash ;
|
||||||
|
(* We don't care of the following values, only the shell validates them. *)
|
||||||
|
proto_level = 0 ;
|
||||||
|
validation_passes = 0 ;
|
||||||
|
context = Alpha_environment.Context_hash.zero ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_proof_of_work_nonce =
|
||||||
|
MBytes.create Alpha_context.Constants.proof_of_work_nonce_size
|
||||||
|
|
||||||
|
let protocol_param_key = [ "protocol_parameters" ]
|
||||||
|
|
||||||
|
let check_constants_consistency constants =
|
||||||
|
let open Constants_repr in
|
||||||
|
let open Error_monad in
|
||||||
|
let { blocks_per_cycle ; blocks_per_commitment ;
|
||||||
|
blocks_per_roll_snapshot ; _ } = constants in
|
||||||
|
Error_monad.unless (blocks_per_commitment <= blocks_per_cycle)
|
||||||
|
(fun () -> failwith "Inconsistent constants : blocks per commitment must be \
|
||||||
|
less than blocks per cycle") >>=? fun () ->
|
||||||
|
Error_monad.unless (blocks_per_cycle >= blocks_per_roll_snapshot)
|
||||||
|
(fun () -> failwith "Inconsistent constants : blocks per cycle \
|
||||||
|
must be superior than blocks per roll snapshot") >>=?
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
let initial_context
|
||||||
|
constants
|
||||||
|
header
|
||||||
|
commitments
|
||||||
|
initial_accounts
|
||||||
|
security_deposit_ramp_up_cycles
|
||||||
|
no_reward_cycles
|
||||||
|
=
|
||||||
|
let open Tezos_base.TzPervasives.Error_monad in
|
||||||
|
let bootstrap_accounts =
|
||||||
|
List.map (fun ({ pk ; pkh ; _ }, amount) ->
|
||||||
|
let open! Parameters_repr in
|
||||||
|
{ public_key_hash = pkh ; public_key = Some pk ; amount }
|
||||||
|
) initial_accounts
|
||||||
|
in
|
||||||
|
let json =
|
||||||
|
Data_encoding.Json.construct
|
||||||
|
Parameters_repr.encoding
|
||||||
|
Parameters_repr.{
|
||||||
|
bootstrap_accounts ;
|
||||||
|
bootstrap_contracts = [] ;
|
||||||
|
commitments ;
|
||||||
|
constants ;
|
||||||
|
security_deposit_ramp_up_cycles ;
|
||||||
|
no_reward_cycles ;
|
||||||
|
}
|
||||||
|
in
|
||||||
|
let proto_params =
|
||||||
|
Data_encoding.Binary.to_bytes_exn Data_encoding.json json
|
||||||
|
in
|
||||||
|
Tezos_protocol_environment_memory.Context.(
|
||||||
|
set empty ["version"] (MBytes.of_string "genesis")
|
||||||
|
) >>= fun ctxt ->
|
||||||
|
Tezos_protocol_environment_memory.Context.(
|
||||||
|
set ctxt protocol_param_key proto_params
|
||||||
|
) >>= fun ctxt ->
|
||||||
|
Main.init ctxt header
|
||||||
|
>|= Alpha_environment.wrap_error >>=? fun { context; _ } ->
|
||||||
|
return context
|
||||||
|
|
||||||
|
let genesis
|
||||||
|
?(preserved_cycles = Constants_repr.default.preserved_cycles)
|
||||||
|
?(blocks_per_cycle = Constants_repr.default.blocks_per_cycle)
|
||||||
|
?(blocks_per_commitment = Constants_repr.default.blocks_per_commitment)
|
||||||
|
?(blocks_per_roll_snapshot = Constants_repr.default.blocks_per_roll_snapshot)
|
||||||
|
?(blocks_per_voting_period = Constants_repr.default.blocks_per_voting_period)
|
||||||
|
?(time_between_blocks = Constants_repr.default.time_between_blocks)
|
||||||
|
?(endorsers_per_block = Constants_repr.default.endorsers_per_block)
|
||||||
|
?(hard_gas_limit_per_operation = Constants_repr.default.hard_gas_limit_per_operation)
|
||||||
|
?(hard_gas_limit_per_block = Constants_repr.default.hard_gas_limit_per_block)
|
||||||
|
?(proof_of_work_threshold = Int64.(neg one))
|
||||||
|
?(tokens_per_roll = Constants_repr.default.tokens_per_roll)
|
||||||
|
?(michelson_maximum_type_size = Constants_repr.default.michelson_maximum_type_size)
|
||||||
|
?(seed_nonce_revelation_tip = Constants_repr.default.seed_nonce_revelation_tip)
|
||||||
|
?(origination_size = Constants_repr.default.origination_size)
|
||||||
|
?(block_security_deposit = Constants_repr.default.block_security_deposit)
|
||||||
|
?(endorsement_security_deposit = Constants_repr.default.endorsement_security_deposit)
|
||||||
|
?(block_reward = Constants_repr.default.block_reward)
|
||||||
|
?(endorsement_reward = Constants_repr.default.endorsement_reward)
|
||||||
|
?(cost_per_byte = Constants_repr.default.cost_per_byte)
|
||||||
|
?(hard_storage_limit_per_operation = Constants_repr.default.hard_storage_limit_per_operation)
|
||||||
|
?(commitments = [])
|
||||||
|
?(security_deposit_ramp_up_cycles = None)
|
||||||
|
?(no_reward_cycles = None)
|
||||||
|
(initial_accounts : (account * Tez_repr.t) list)
|
||||||
|
=
|
||||||
|
if initial_accounts = [] then
|
||||||
|
Pervasives.failwith "Must have one account with a roll to bake";
|
||||||
|
|
||||||
|
(* Check there is at least one roll *)
|
||||||
|
let open Tezos_base.TzPervasives.Error_monad in
|
||||||
|
begin try
|
||||||
|
let (>>?=) x y = match x with
|
||||||
|
| Ok(a) -> y a
|
||||||
|
| Error(b) -> fail @@ List.hd b in
|
||||||
|
fold_left_s (fun acc (_, amount) ->
|
||||||
|
Alpha_environment.wrap_error @@
|
||||||
|
Tez_repr.(+?) acc amount >>?= fun acc ->
|
||||||
|
if acc >= tokens_per_roll then
|
||||||
|
raise Exit
|
||||||
|
else return acc
|
||||||
|
) Tez_repr.zero initial_accounts >>=? fun _ ->
|
||||||
|
failwith "Insufficient tokens in initial accounts to create one roll"
|
||||||
|
with Exit -> return ()
|
||||||
|
end >>=? fun () ->
|
||||||
|
|
||||||
|
let constants : Constants_repr.parametric = {
|
||||||
|
preserved_cycles ;
|
||||||
|
blocks_per_cycle ;
|
||||||
|
blocks_per_commitment ;
|
||||||
|
blocks_per_roll_snapshot ;
|
||||||
|
blocks_per_voting_period ;
|
||||||
|
time_between_blocks ;
|
||||||
|
endorsers_per_block ;
|
||||||
|
hard_gas_limit_per_operation ;
|
||||||
|
hard_gas_limit_per_block ;
|
||||||
|
proof_of_work_threshold ;
|
||||||
|
tokens_per_roll ;
|
||||||
|
michelson_maximum_type_size ;
|
||||||
|
seed_nonce_revelation_tip ;
|
||||||
|
origination_size ;
|
||||||
|
block_security_deposit ;
|
||||||
|
endorsement_security_deposit ;
|
||||||
|
block_reward ;
|
||||||
|
endorsement_reward ;
|
||||||
|
cost_per_byte ;
|
||||||
|
hard_storage_limit_per_operation ;
|
||||||
|
} in
|
||||||
|
check_constants_consistency constants >>=? fun () ->
|
||||||
|
|
||||||
|
let hash =
|
||||||
|
Alpha_environment.Block_hash.of_b58check_exn "BLockGenesisGenesisGenesisGenesisGenesisCCCCCeZiLHU"
|
||||||
|
in
|
||||||
|
let shell = make_shell
|
||||||
|
~level:0l
|
||||||
|
~predecessor:hash
|
||||||
|
~timestamp:Tezos_utils.Time.epoch
|
||||||
|
~fitness: (Fitness_repr.from_int64 0L)
|
||||||
|
~operations_hash: Alpha_environment.Operation_list_list_hash.zero in
|
||||||
|
initial_context
|
||||||
|
constants
|
||||||
|
shell
|
||||||
|
commitments
|
||||||
|
initial_accounts
|
||||||
|
security_deposit_ramp_up_cycles
|
||||||
|
no_reward_cycles
|
||||||
|
>>=? fun context ->
|
||||||
|
return (context, shell, hash)
|
||||||
|
|
||||||
|
let init
|
||||||
|
?(slow=false)
|
||||||
|
?preserved_cycles
|
||||||
|
?endorsers_per_block
|
||||||
|
?commitments
|
||||||
|
n =
|
||||||
|
let open Error_monad in
|
||||||
|
let accounts = generate_accounts n in
|
||||||
|
let contracts = List.map (fun (a, _) ->
|
||||||
|
Alpha_context.Contract.implicit_contract (a.pkh)) accounts in
|
||||||
|
begin
|
||||||
|
if slow then
|
||||||
|
genesis
|
||||||
|
?preserved_cycles
|
||||||
|
?endorsers_per_block
|
||||||
|
?commitments
|
||||||
|
accounts
|
||||||
|
else
|
||||||
|
genesis
|
||||||
|
?preserved_cycles
|
||||||
|
~blocks_per_cycle:32l
|
||||||
|
~blocks_per_commitment:4l
|
||||||
|
~blocks_per_roll_snapshot:8l
|
||||||
|
~blocks_per_voting_period:(Int32.mul 32l 8l)
|
||||||
|
?endorsers_per_block
|
||||||
|
?commitments
|
||||||
|
accounts
|
||||||
|
end >>=? fun ctxt ->
|
||||||
|
return (ctxt, accounts, contracts)
|
||||||
|
|
||||||
|
let contents
|
||||||
|
?(proof_of_work_nonce = default_proof_of_work_nonce)
|
||||||
|
?(priority = 0) ?seed_nonce_hash () =
|
||||||
|
Alpha_context.Block_header.({
|
||||||
|
priority ;
|
||||||
|
proof_of_work_nonce ;
|
||||||
|
seed_nonce_hash ;
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
let begin_construction ?(priority=0) ~timestamp ~(header:Alpha_context.Block_header.shell_header) ~hash ctxt =
|
||||||
|
let contents = contents ~priority () in
|
||||||
|
let protocol_data =
|
||||||
|
let open! Alpha_context.Block_header in {
|
||||||
|
contents ;
|
||||||
|
signature = Signature.zero ;
|
||||||
|
} in
|
||||||
|
let header = {
|
||||||
|
Alpha_context.Block_header.shell = {
|
||||||
|
predecessor = hash ;
|
||||||
|
proto_level = header.proto_level ;
|
||||||
|
validation_passes = header.validation_passes ;
|
||||||
|
fitness = header.fitness ;
|
||||||
|
timestamp ;
|
||||||
|
level = header.level ;
|
||||||
|
context = Alpha_environment.Context_hash.zero ;
|
||||||
|
operations_hash = Alpha_environment.Operation_list_list_hash.zero ;
|
||||||
|
} ;
|
||||||
|
protocol_data = {
|
||||||
|
contents ;
|
||||||
|
signature = Signature.zero ;
|
||||||
|
} ;
|
||||||
|
} in
|
||||||
|
Main.begin_construction
|
||||||
|
~chain_id: Alpha_environment.Chain_id.zero
|
||||||
|
~predecessor_context: ctxt
|
||||||
|
~predecessor_timestamp: header.shell.timestamp
|
||||||
|
~predecessor_fitness: header.shell.fitness
|
||||||
|
~predecessor_level: header.shell.level
|
||||||
|
~predecessor:hash
|
||||||
|
~timestamp
|
||||||
|
~protocol_data
|
||||||
|
() >>= fun x -> Lwt.return @@ Alpha_environment.wrap_error x >>=? fun state ->
|
||||||
|
return state.ctxt
|
||||||
|
|
||||||
|
let main n =
|
||||||
|
init n >>=? fun ((ctxt, header, hash), accounts, contracts) ->
|
||||||
|
let timestamp = Tezos_base.Time.now () in
|
||||||
|
begin_construction ~timestamp ~header ~hash ctxt >>=? fun ctxt ->
|
||||||
|
return (ctxt, accounts, contracts)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
type identity = {
|
||||||
|
public_key_hash : Signature.public_key_hash;
|
||||||
|
public_key : Signature.public_key;
|
||||||
|
secret_key : Signature.secret_key;
|
||||||
|
implicit_contract : Alpha_context.Contract.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
type environment = {
|
||||||
|
tezos_context : Alpha_context.t ;
|
||||||
|
identities : identity list ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let init_environment () =
|
||||||
|
Context_init.main 10 >>=? fun (tezos_context, accounts, contracts) ->
|
||||||
|
let accounts = List.map fst accounts in
|
||||||
|
let tezos_context = Alpha_context.Gas.set_limit tezos_context @@ Z.of_int 350000 in
|
||||||
|
let identities =
|
||||||
|
List.map (fun ((a:Context_init.account), c) -> {
|
||||||
|
public_key = a.pk ;
|
||||||
|
public_key_hash = a.pkh ;
|
||||||
|
secret_key = a.sk ;
|
||||||
|
implicit_contract = c ;
|
||||||
|
}) @@
|
||||||
|
List.combine accounts contracts in
|
||||||
|
return {tezos_context ; identities}
|
||||||
|
|
||||||
|
let contextualize ~msg ?environment f =
|
||||||
|
let lwt =
|
||||||
|
let environment = match environment with
|
||||||
|
| None -> init_environment ()
|
||||||
|
| Some x -> return x in
|
||||||
|
environment >>=? f
|
||||||
|
in
|
||||||
|
force_ok ~msg @@ Lwt_main.run lwt
|
18
meta_michelson/streams.ml
Normal file
18
meta_michelson/streams.ml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
let read_file f =
|
||||||
|
let ic = open_in f in
|
||||||
|
let n = in_channel_length ic in
|
||||||
|
let s = Bytes.create n in
|
||||||
|
really_input ic s 0 n;
|
||||||
|
close_in ic;
|
||||||
|
Bytes.to_string s
|
||||||
|
|
||||||
|
let read_lines filename =
|
||||||
|
let lines = ref [] in
|
||||||
|
let chan = open_in filename in
|
||||||
|
try
|
||||||
|
while true; do
|
||||||
|
lines := input_line chan :: !lines
|
||||||
|
done; !lines
|
||||||
|
with End_of_file ->
|
||||||
|
close_in chan;
|
||||||
|
List.rev !lines
|
120
mini_c/PP.ml
Normal file
120
mini_c/PP.ml
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
open Simple_utils.PP_helpers
|
||||||
|
open Types
|
||||||
|
open Format
|
||||||
|
|
||||||
|
let list_sep_d x = list_sep x (const " , ")
|
||||||
|
|
||||||
|
let space_sep ppf () = fprintf ppf " "
|
||||||
|
|
||||||
|
let lr = fun ppf -> function `Left -> fprintf ppf "L" | `Right -> fprintf ppf "R"
|
||||||
|
|
||||||
|
let type_base ppf : type_base -> _ = function
|
||||||
|
| Base_unit -> fprintf ppf "unit"
|
||||||
|
| Base_bool -> fprintf ppf "bool"
|
||||||
|
| Base_int -> fprintf ppf "int"
|
||||||
|
| Base_nat -> fprintf ppf "nat"
|
||||||
|
| Base_tez -> fprintf ppf "tez"
|
||||||
|
| Base_string -> fprintf ppf "string"
|
||||||
|
| Base_address -> fprintf ppf "address"
|
||||||
|
| Base_bytes -> fprintf ppf "bytes"
|
||||||
|
| Base_operation -> fprintf ppf "operation"
|
||||||
|
|
||||||
|
let rec type_ ppf : type_value -> _ = function
|
||||||
|
| T_or(a, b) -> fprintf ppf "(%a) | (%a)" type_ a type_ b
|
||||||
|
| T_pair(a, b) -> fprintf ppf "(%a) & (%a)" type_ a type_ b
|
||||||
|
| T_base b -> type_base ppf b
|
||||||
|
| T_function(a, b) -> fprintf ppf "(%a) -> (%a)" type_ a type_ b
|
||||||
|
| T_map(k, v) -> fprintf ppf "map(%a -> %a)" type_ k type_ v
|
||||||
|
| T_list(t) -> fprintf ppf "list(%a)" type_ t
|
||||||
|
| T_option(o) -> fprintf ppf "option(%a)" type_ o
|
||||||
|
| T_contract(t) -> fprintf ppf "contract(%a)" type_ t
|
||||||
|
| T_deep_closure(c, arg, ret) ->
|
||||||
|
fprintf ppf "[%a](%a)->(%a)"
|
||||||
|
environment c
|
||||||
|
type_ arg type_ ret
|
||||||
|
|
||||||
|
and environment_element ppf ((s, tv) : environment_element) =
|
||||||
|
Format.fprintf ppf "%s : %a" s type_ tv
|
||||||
|
|
||||||
|
and environment ppf (x:environment) =
|
||||||
|
fprintf ppf "Env[%a]" (list_sep_d environment_element) x
|
||||||
|
|
||||||
|
let rec value ppf : value -> unit = function
|
||||||
|
| D_bool b -> fprintf ppf "%b" b
|
||||||
|
| D_operation _ -> fprintf ppf "operation[...bytes]"
|
||||||
|
| D_int n -> fprintf ppf "%d" n
|
||||||
|
| D_nat n -> fprintf ppf "+%d" n
|
||||||
|
| D_tez n -> fprintf ppf "%dtz" n
|
||||||
|
| D_unit -> fprintf ppf " "
|
||||||
|
| D_string s -> fprintf ppf "\"%s\"" s
|
||||||
|
| D_bytes _ -> fprintf ppf "[bytes]"
|
||||||
|
| D_pair (a, b) -> fprintf ppf "(%a), (%a)" value a value b
|
||||||
|
| D_left a -> fprintf ppf "L(%a)" value a
|
||||||
|
| D_right b -> fprintf ppf "R(%a)" value b
|
||||||
|
| D_function x -> function_ ppf x
|
||||||
|
| D_none -> fprintf ppf "None"
|
||||||
|
| D_some s -> fprintf ppf "Some (%a)" value s
|
||||||
|
| D_map m -> fprintf ppf "Map[%a]" (list_sep_d value_assoc) m
|
||||||
|
| D_list lst -> fprintf ppf "List[%a]" (list_sep_d value) lst
|
||||||
|
|
||||||
|
and value_assoc ppf : (value * value) -> unit = fun (a, b) ->
|
||||||
|
fprintf ppf "%a -> %a" value a value b
|
||||||
|
|
||||||
|
and expression' ppf (e:expression') = match e with
|
||||||
|
| E_capture_environment s -> fprintf ppf "capture(%a)" (list_sep string (const " ; ")) s
|
||||||
|
| E_variable v -> fprintf ppf "%s" v
|
||||||
|
| E_application(a, b) -> fprintf ppf "(%a)@(%a)" expression a expression b
|
||||||
|
| E_constant(p, lst) -> fprintf ppf "%s %a" p (pp_print_list ~pp_sep:space_sep expression) lst
|
||||||
|
| E_literal v -> fprintf ppf "%a" value v
|
||||||
|
| E_empty_map _ -> fprintf ppf "map[]"
|
||||||
|
| E_empty_list _ -> fprintf ppf "list[]"
|
||||||
|
| E_make_none _ -> fprintf ppf "none"
|
||||||
|
| E_Cond (c, a, b) -> fprintf ppf "%a ? %a : %a" expression c expression a expression b
|
||||||
|
| E_if_none (c, n, ((name, _) , s)) -> fprintf ppf "%a ?? %a : %s -> %a" expression c expression n name expression s
|
||||||
|
| E_if_left (c, ((name_l, _) , l), ((name_r, _) , r)) ->
|
||||||
|
fprintf ppf "%a ?? %s -> %a : %s -> %a" expression c name_l expression l name_r expression r
|
||||||
|
| E_let_in ((name , _) , expr , body) ->
|
||||||
|
fprintf ppf "let %s = %a in %a" name expression expr expression body
|
||||||
|
|
||||||
|
and expression : _ -> expression -> _ = fun ppf e ->
|
||||||
|
expression' ppf e.content
|
||||||
|
|
||||||
|
and expression_with_type : _ -> expression -> _ = fun ppf e ->
|
||||||
|
fprintf ppf "%a : %a"
|
||||||
|
expression' e.content
|
||||||
|
type_ e.type_value
|
||||||
|
|
||||||
|
and function_ ppf ({binder ; input ; output ; body ; result}:anon_function) =
|
||||||
|
fprintf ppf "fun (%s:%a) : %a %a return %a"
|
||||||
|
binder
|
||||||
|
type_ input
|
||||||
|
type_ output
|
||||||
|
block body
|
||||||
|
expression result
|
||||||
|
|
||||||
|
and assignment ppf ((n, e):assignment) = fprintf ppf "%s = %a;" n expression e
|
||||||
|
|
||||||
|
and declaration ppf ((n, e):assignment) = fprintf ppf "let %s = %a;" n expression e
|
||||||
|
|
||||||
|
and statement ppf ((s, _) : statement) = match s with
|
||||||
|
| S_environment_load _ -> fprintf ppf "load env"
|
||||||
|
| S_environment_select _ -> fprintf ppf "select env"
|
||||||
|
| S_environment_add (name, tv) -> fprintf ppf "add %s %a" name type_ tv
|
||||||
|
| S_declaration ass -> declaration ppf ass
|
||||||
|
| S_assignment ass -> assignment ppf ass
|
||||||
|
| S_do e -> fprintf ppf "do %a" expression e
|
||||||
|
| S_cond (expr, i, e) -> fprintf ppf "if (%a) %a %a" expression expr block i block e
|
||||||
|
| S_patch (r, path, e) ->
|
||||||
|
fprintf ppf "%s.%a := %a" r (list_sep lr (const ".")) path expression e
|
||||||
|
| S_if_none (expr, none, ((name, _), some)) -> fprintf ppf "if_none (%a) %a %s->%a" expression expr block none name block some
|
||||||
|
| S_while (e, b) -> fprintf ppf "while (%a) %a" expression e block b
|
||||||
|
|
||||||
|
and block ppf ((b, _):block) =
|
||||||
|
match b with
|
||||||
|
| [] -> fprintf ppf "{}"
|
||||||
|
| b -> fprintf ppf "{@; @[<v>%a@]@;}" (pp_print_list ~pp_sep:(tag "@;") statement) b
|
||||||
|
|
||||||
|
let tl_statement ppf (ass, _) = assignment ppf ass
|
||||||
|
|
||||||
|
let program ppf (p:program) =
|
||||||
|
fprintf ppf "Program:\n---\n%a" (pp_print_list ~pp_sep:pp_print_newline tl_statement) p
|
161
mini_c/combinators.ml
Normal file
161
mini_c/combinators.ml
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
open Trace
|
||||||
|
open Types
|
||||||
|
|
||||||
|
module Expression = struct
|
||||||
|
type t' = expression'
|
||||||
|
type t = expression
|
||||||
|
|
||||||
|
let get_content : t -> t' = fun e -> e.content
|
||||||
|
let get_type : t -> type_value = fun e -> e.type_value
|
||||||
|
let get_environment : t -> environment = fun e -> e.environment
|
||||||
|
let is_toplevel : t -> bool = fun e -> e.is_toplevel
|
||||||
|
|
||||||
|
let make = fun ?(itl = false) e' t env -> {
|
||||||
|
content = e' ;
|
||||||
|
type_value = t ;
|
||||||
|
environment = env ;
|
||||||
|
is_toplevel = itl ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let make_tpl = fun ?(itl = false) (e' , t , env) -> {
|
||||||
|
content = e' ;
|
||||||
|
type_value = t ;
|
||||||
|
environment = env ;
|
||||||
|
is_toplevel = itl ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pair : t -> t -> t' = fun a b -> E_constant ("PAIR" , [ a ; b ])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
let get_bool (v:value) = match v with
|
||||||
|
| D_bool b -> ok b
|
||||||
|
| _ -> simple_fail "not a bool"
|
||||||
|
|
||||||
|
let get_int (v:value) = match v with
|
||||||
|
| D_int n -> ok n
|
||||||
|
| _ -> simple_fail "not an int"
|
||||||
|
|
||||||
|
let get_nat (v:value) = match v with
|
||||||
|
| D_nat n -> ok n
|
||||||
|
| _ -> simple_fail "not a nat"
|
||||||
|
|
||||||
|
let get_string (v:value) = match v with
|
||||||
|
| D_string s -> ok s
|
||||||
|
| _ -> simple_fail "not a string"
|
||||||
|
|
||||||
|
let get_bytes (v:value) = match v with
|
||||||
|
| D_bytes b -> ok b
|
||||||
|
| _ -> simple_fail "not a bytes"
|
||||||
|
|
||||||
|
let get_unit (v:value) = match v with
|
||||||
|
| D_unit -> ok ()
|
||||||
|
| _ -> simple_fail "not a unit"
|
||||||
|
|
||||||
|
let get_option (v:value) = match v with
|
||||||
|
| D_none -> ok None
|
||||||
|
| D_some s -> ok (Some s)
|
||||||
|
| _ -> simple_fail "not an option"
|
||||||
|
|
||||||
|
let get_map (v:value) = match v with
|
||||||
|
| D_map lst -> ok lst
|
||||||
|
| _ -> simple_fail "not a map"
|
||||||
|
|
||||||
|
let get_list (v:value) = match v with
|
||||||
|
| D_list lst -> ok lst
|
||||||
|
| _ -> simple_fail "not a list"
|
||||||
|
|
||||||
|
let get_t_option (v:type_value) = match v with
|
||||||
|
| T_option t -> ok t
|
||||||
|
| _ -> simple_fail "not an option"
|
||||||
|
|
||||||
|
let get_pair (v:value) = match v with
|
||||||
|
| D_pair (a, b) -> ok (a, b)
|
||||||
|
| _ -> simple_fail "not a pair"
|
||||||
|
|
||||||
|
let get_t_pair (t:type_value) = match t with
|
||||||
|
| T_pair (a, b) -> ok (a, b)
|
||||||
|
| _ -> simple_fail "not a type pair"
|
||||||
|
|
||||||
|
let get_t_map (t:type_value) = match t with
|
||||||
|
| T_map kv -> ok kv
|
||||||
|
| _ -> simple_fail "not a type map"
|
||||||
|
|
||||||
|
let get_t_list (t:type_value) = match t with
|
||||||
|
| T_list t -> ok t
|
||||||
|
| _ -> simple_fail "not a type list"
|
||||||
|
|
||||||
|
let get_left (v:value) = match v with
|
||||||
|
| D_left b -> ok b
|
||||||
|
| _ -> simple_fail "not a left"
|
||||||
|
|
||||||
|
let get_right (v:value) = match v with
|
||||||
|
| D_right b -> ok b
|
||||||
|
| _ -> simple_fail "not a right"
|
||||||
|
|
||||||
|
let get_or (v:value) = match v with
|
||||||
|
| D_left b -> ok (false, b)
|
||||||
|
| D_right b -> ok (true, b)
|
||||||
|
| _ -> simple_fail "not a left/right"
|
||||||
|
|
||||||
|
let wrong_type name t =
|
||||||
|
let title () = "not a " ^ name in
|
||||||
|
let content () = Format.asprintf "%a" PP.type_ t in
|
||||||
|
error title content
|
||||||
|
|
||||||
|
let get_t_left t = match t with
|
||||||
|
| T_or (a , _) -> ok a
|
||||||
|
| _ -> fail @@ wrong_type "union" t
|
||||||
|
|
||||||
|
let get_t_right t = match t with
|
||||||
|
| T_or (_ , b) -> ok b
|
||||||
|
| _ -> fail @@ wrong_type "union" t
|
||||||
|
|
||||||
|
let get_t_contract t = match t with
|
||||||
|
| T_contract x -> ok x
|
||||||
|
| _ -> fail @@ wrong_type "contract" t
|
||||||
|
|
||||||
|
let get_t_operation t = match t with
|
||||||
|
| T_base Base_operation -> ok ()
|
||||||
|
| _ -> fail @@ wrong_type "operation" t
|
||||||
|
|
||||||
|
let get_operation (v:value) = match v with
|
||||||
|
| D_operation x -> ok x
|
||||||
|
| _ -> simple_fail "not an operation"
|
||||||
|
|
||||||
|
|
||||||
|
let get_last_statement ((b', _):block) : statement result =
|
||||||
|
let aux lst = match lst with
|
||||||
|
| [] -> simple_fail "get_last: empty list"
|
||||||
|
| lst -> ok List.(nth lst (length lst - 1)) in
|
||||||
|
aux b'
|
||||||
|
|
||||||
|
let t_int : type_value = T_base Base_int
|
||||||
|
let t_nat : type_value = T_base Base_nat
|
||||||
|
|
||||||
|
let t_function x y : type_value = T_function ( x , y )
|
||||||
|
let t_deep_closure x y z : type_value = T_deep_closure ( x , y , z )
|
||||||
|
let t_pair x y : type_value = T_pair ( x , y )
|
||||||
|
let t_union x y : type_value = T_or ( x , y )
|
||||||
|
|
||||||
|
let quote binder input output body result : anon_function =
|
||||||
|
{
|
||||||
|
binder ; input ; output ;
|
||||||
|
body ; result ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let basic_quote i o b : anon_function result =
|
||||||
|
let%bind (_, e) = get_last_statement b in
|
||||||
|
let r : expression = Expression.make_tpl (E_variable "output", o, e.post_environment) in
|
||||||
|
ok @@ quote "input" i o b r
|
||||||
|
|
||||||
|
let basic_int_quote b : anon_function result =
|
||||||
|
basic_quote t_int t_int b
|
||||||
|
|
||||||
|
let e_int expr env : expression = Expression.make_tpl (expr, t_int, env)
|
||||||
|
let e_var_int name env : expression = e_int (E_variable name) env
|
||||||
|
|
||||||
|
let d_unit : value = D_unit
|
||||||
|
|
||||||
|
let environment_wrap pre_environment post_environment = { pre_environment ; post_environment }
|
||||||
|
let id_environment_wrap e = environment_wrap e e
|
52
mini_c/combinators_smart.ml
Normal file
52
mini_c/combinators_smart.ml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
open Trace
|
||||||
|
open Types
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
let basic_int_quote_env : environment =
|
||||||
|
let e = Environment.empty in
|
||||||
|
Environment.add ("input", t_int) e
|
||||||
|
|
||||||
|
let statement s' env : statement =
|
||||||
|
match s' with
|
||||||
|
| S_environment_load (_ , env') -> s', environment_wrap env env'
|
||||||
|
| S_environment_select env' -> s', environment_wrap env env'
|
||||||
|
| S_environment_add (name, tv) -> s' , environment_wrap env (Environment.add (name , tv) env)
|
||||||
|
| S_cond _ -> s' , id_environment_wrap env
|
||||||
|
| S_do _ -> s' , id_environment_wrap env
|
||||||
|
| S_if_none _ -> s' , id_environment_wrap env
|
||||||
|
| S_while _ -> s' , id_environment_wrap env
|
||||||
|
| S_patch _ -> s' , id_environment_wrap env
|
||||||
|
| S_declaration (name , e) -> s', environment_wrap env (Environment.add (name , (Expression.get_type e)) env)
|
||||||
|
| S_assignment (name , e) -> s', environment_wrap env (Environment.add (name , (Expression.get_type e)) env)
|
||||||
|
|
||||||
|
let block (statements:statement list) : block result =
|
||||||
|
match statements with
|
||||||
|
| [] -> simple_fail "no statements in block"
|
||||||
|
| lst ->
|
||||||
|
let first = List.hd lst in
|
||||||
|
let last = List.(nth lst (length lst - 1)) in
|
||||||
|
ok (lst, environment_wrap (snd first).pre_environment (snd last).post_environment)
|
||||||
|
|
||||||
|
let append_statement' : block -> statement' -> block = fun b s' ->
|
||||||
|
let b_wrap = snd b in
|
||||||
|
let s = statement s' b_wrap.post_environment in
|
||||||
|
let s_wrap = snd s in
|
||||||
|
let b_wrap' = { b_wrap with post_environment = s_wrap.post_environment } in
|
||||||
|
let b_content = fst b in
|
||||||
|
(b_content @ [s], b_wrap')
|
||||||
|
|
||||||
|
let prepend_statement : statement -> block -> block = fun s b ->
|
||||||
|
let s_wrap = snd s in
|
||||||
|
let b_wrap = snd b in
|
||||||
|
let b_wrap' = { b_wrap with pre_environment = s_wrap.pre_environment } in
|
||||||
|
let b_content = fst b in
|
||||||
|
(s :: b_content, b_wrap')
|
||||||
|
|
||||||
|
let statements (lst:(environment -> statement) list) e : statement list =
|
||||||
|
let rec aux lst e = match lst with
|
||||||
|
| [] -> []
|
||||||
|
| hd :: tl ->
|
||||||
|
let s = hd e in
|
||||||
|
s :: aux tl (snd s).post_environment
|
||||||
|
in
|
||||||
|
aux lst e
|
13
mini_c/dune
Normal file
13
mini_c/dune
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
(library
|
||||||
|
(name mini_c)
|
||||||
|
(public_name ligo.mini_c)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
meta_michelson
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils ))
|
||||||
|
)
|
61
mini_c/environment.ml
Normal file
61
mini_c/environment.ml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
(* open Trace *)
|
||||||
|
open Types
|
||||||
|
|
||||||
|
(* module type ENVIRONMENT = sig
|
||||||
|
* type element = environment_element
|
||||||
|
* type t = environment
|
||||||
|
*
|
||||||
|
* val empty : t
|
||||||
|
* val add : element -> t -> t
|
||||||
|
* val concat : t list -> t
|
||||||
|
* val get_opt : string -> t -> type_value option
|
||||||
|
* val get_i : string -> t -> (type_value * int)
|
||||||
|
* val of_list : element list -> t
|
||||||
|
* val closure_representation : t -> type_value
|
||||||
|
* end *)
|
||||||
|
|
||||||
|
module Environment (* : ENVIRONMENT *) = struct
|
||||||
|
type element = environment_element
|
||||||
|
type t = environment
|
||||||
|
|
||||||
|
let empty : t = []
|
||||||
|
let add : element -> t -> t = List.cons
|
||||||
|
let concat : t list -> t = List.concat
|
||||||
|
let get_opt : string -> t -> type_value option = List.assoc_opt
|
||||||
|
let has : string -> t -> bool = fun s t ->
|
||||||
|
match get_opt s t with
|
||||||
|
| None -> false
|
||||||
|
| Some _ -> true
|
||||||
|
let get_i : string -> t -> (type_value * int) = List.assoc_i
|
||||||
|
let of_list : element list -> t = fun x -> x
|
||||||
|
let to_list : t -> element list = fun x -> x
|
||||||
|
let get_names : t -> string list = List.map fst
|
||||||
|
let remove : int -> t -> t = List.remove
|
||||||
|
|
||||||
|
let select : string list -> t -> t = fun lst env ->
|
||||||
|
let e_lst =
|
||||||
|
let e_lst = to_list env in
|
||||||
|
let aux selector (s , _) =
|
||||||
|
match List.mem s selector with
|
||||||
|
| true -> List.remove_element s selector , true
|
||||||
|
| false -> selector , false in
|
||||||
|
let e_lst' = List.fold_map_right aux lst e_lst in
|
||||||
|
let e_lst'' = List.combine e_lst e_lst' in
|
||||||
|
e_lst'' in
|
||||||
|
of_list
|
||||||
|
@@ List.map fst
|
||||||
|
@@ List.filter snd
|
||||||
|
@@ e_lst
|
||||||
|
|
||||||
|
|
||||||
|
let fold : _ -> 'a -> t -> 'a = List.fold_left
|
||||||
|
let filter : _ -> t -> t = List.filter
|
||||||
|
|
||||||
|
let closure_representation : t -> type_value = fun t ->
|
||||||
|
match t with
|
||||||
|
| [] -> T_base Base_unit
|
||||||
|
| [ a ] -> snd a
|
||||||
|
| hd :: tl -> List.fold_left (fun acc cur -> T_pair (acc , snd cur)) (snd hd) tl
|
||||||
|
end
|
||||||
|
|
||||||
|
include Environment
|
10
mini_c/mini_c.ml
Normal file
10
mini_c/mini_c.ml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module Types = Types
|
||||||
|
include Types
|
||||||
|
|
||||||
|
module PP = PP
|
||||||
|
module Combinators = struct
|
||||||
|
include Combinators
|
||||||
|
include Combinators_smart
|
||||||
|
end
|
||||||
|
include Combinators
|
||||||
|
module Environment = Environment
|
109
mini_c/types.ml
Normal file
109
mini_c/types.ml
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
type type_name = string
|
||||||
|
|
||||||
|
type type_base =
|
||||||
|
| Base_unit
|
||||||
|
| Base_bool
|
||||||
|
| Base_int | Base_nat | Base_tez
|
||||||
|
| Base_string | Base_bytes | Base_address
|
||||||
|
| Base_operation
|
||||||
|
|
||||||
|
type type_value =
|
||||||
|
| T_pair of (type_value * type_value)
|
||||||
|
| T_or of type_value * type_value
|
||||||
|
| T_function of type_value * type_value
|
||||||
|
| T_deep_closure of environment * type_value * type_value
|
||||||
|
| T_base of type_base
|
||||||
|
| T_map of (type_value * type_value)
|
||||||
|
| T_list of type_value
|
||||||
|
| T_contract of type_value
|
||||||
|
| T_option of type_value
|
||||||
|
|
||||||
|
and environment_element = string * type_value
|
||||||
|
|
||||||
|
and environment = environment_element list
|
||||||
|
|
||||||
|
type environment_wrap = {
|
||||||
|
pre_environment : environment ;
|
||||||
|
post_environment : environment ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type var_name = string
|
||||||
|
type fun_name = string
|
||||||
|
|
||||||
|
type value =
|
||||||
|
| D_unit
|
||||||
|
| D_bool of bool
|
||||||
|
| D_nat of int
|
||||||
|
| D_tez of int
|
||||||
|
| D_int of int
|
||||||
|
| D_string of string
|
||||||
|
| D_bytes of bytes
|
||||||
|
| D_pair of value * value
|
||||||
|
| D_left of value
|
||||||
|
| D_right of value
|
||||||
|
| D_some of value
|
||||||
|
| D_none
|
||||||
|
| D_map of (value * value) list
|
||||||
|
| D_list of value list
|
||||||
|
(* | `Macro of anon_macro ... The future. *)
|
||||||
|
| D_function of anon_function
|
||||||
|
| D_operation of Memory_proto_alpha.Alpha_context.packed_internal_operation
|
||||||
|
|
||||||
|
and selector = var_name list
|
||||||
|
|
||||||
|
and expression' =
|
||||||
|
| E_literal of value
|
||||||
|
| E_capture_environment of selector
|
||||||
|
| E_constant of string * expression list
|
||||||
|
| E_application of expression * expression
|
||||||
|
| E_variable of var_name
|
||||||
|
| E_empty_map of (type_value * type_value)
|
||||||
|
| E_empty_list of type_value
|
||||||
|
| E_make_none of type_value
|
||||||
|
| E_Cond of expression * expression * expression
|
||||||
|
| E_if_none of expression * expression * ((var_name * type_value) * expression)
|
||||||
|
| E_if_left of expression * ((var_name * type_value) * expression) * ((var_name * type_value) * expression)
|
||||||
|
| E_let_in of ((var_name * type_value) * expression * expression)
|
||||||
|
|
||||||
|
and expression = {
|
||||||
|
content : expression' ;
|
||||||
|
type_value : type_value ;
|
||||||
|
environment : environment ; (* Environment in which the expressions are evaluated *)
|
||||||
|
is_toplevel : bool ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and assignment = var_name * expression
|
||||||
|
|
||||||
|
and statement' =
|
||||||
|
| S_environment_select of environment
|
||||||
|
| S_environment_load of (expression * environment)
|
||||||
|
| S_environment_add of (var_name * type_value)
|
||||||
|
| S_declaration of assignment (* First assignment *)
|
||||||
|
| S_assignment of assignment
|
||||||
|
| S_do of expression
|
||||||
|
| S_cond of expression * block * block
|
||||||
|
| S_patch of string * [`Left | `Right] list * expression
|
||||||
|
| S_if_none of expression * block * ((var_name * type_value) * block)
|
||||||
|
| S_while of expression * block
|
||||||
|
|
||||||
|
and statement = statement' * environment_wrap
|
||||||
|
|
||||||
|
and toplevel_statement = assignment * environment_wrap
|
||||||
|
|
||||||
|
and anon_function = {
|
||||||
|
binder : string ;
|
||||||
|
input : type_value ;
|
||||||
|
output : type_value ;
|
||||||
|
body : block ;
|
||||||
|
result : expression ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and capture =
|
||||||
|
| No_capture (* For functions that don't capture their environments. Quotes. *)
|
||||||
|
| Deep_capture of environment (* Retrieves only the values it needs. Multiple SETs on init. Lighter GETs and SETs at use. *)
|
||||||
|
|
||||||
|
and block' = statement list
|
||||||
|
|
||||||
|
and block = block' * environment_wrap
|
||||||
|
|
||||||
|
and program = toplevel_statement list
|
14
operators/dune
Normal file
14
operators/dune
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
(library
|
||||||
|
(name operators)
|
||||||
|
(public_name ligo.operators)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
ast_typed
|
||||||
|
mini_c
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -open Simple_utils ))
|
||||||
|
)
|
407
operators/operators.ml
Normal file
407
operators/operators.ml
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
open Trace
|
||||||
|
|
||||||
|
module Simplify = struct
|
||||||
|
|
||||||
|
let type_constants = [
|
||||||
|
("unit" , 0) ;
|
||||||
|
("string" , 0) ;
|
||||||
|
("bytes" , 0) ;
|
||||||
|
("nat" , 0) ;
|
||||||
|
("int" , 0) ;
|
||||||
|
("tez" , 0) ;
|
||||||
|
("bool" , 0) ;
|
||||||
|
("operation" , 0) ;
|
||||||
|
("address" , 0) ;
|
||||||
|
("contract" , 1) ;
|
||||||
|
("list" , 1) ;
|
||||||
|
("option" , 1) ;
|
||||||
|
("set" , 1) ;
|
||||||
|
("map" , 2) ;
|
||||||
|
("big_map" , 2) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let constants = [
|
||||||
|
("get_force" , 2) ;
|
||||||
|
("transaction" , 3) ;
|
||||||
|
("get_contract" , 1) ;
|
||||||
|
("size" , 1) ;
|
||||||
|
("int" , 1) ;
|
||||||
|
("abs" , 1) ;
|
||||||
|
("amount" , 0) ;
|
||||||
|
("unit" , 0) ;
|
||||||
|
("source" , 0) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
module Camligo = struct
|
||||||
|
let constants = [
|
||||||
|
("Bytes.pack" , 1) ;
|
||||||
|
("Crypto.hash" , 1) ;
|
||||||
|
("Operation.transaction" , 3) ;
|
||||||
|
("Operation.get_contract" , 1) ;
|
||||||
|
("sender" , 0) ;
|
||||||
|
("unit" , 0) ;
|
||||||
|
("source" , 0) ;
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Typer = struct
|
||||||
|
module Errors = struct
|
||||||
|
let wrong_param_number = fun name ->
|
||||||
|
let title () = "wrong number of params" in
|
||||||
|
let full () = name in
|
||||||
|
error title full
|
||||||
|
end
|
||||||
|
|
||||||
|
open Ast_typed
|
||||||
|
|
||||||
|
type typer_predicate = type_value list -> bool
|
||||||
|
type type_result = string * type_value
|
||||||
|
type typer' = type_value list -> type_value option -> type_result result
|
||||||
|
type typer = string * int * (typer_predicate * typer') list
|
||||||
|
|
||||||
|
let predicate_0 : typer_predicate = fun lst ->
|
||||||
|
match lst with
|
||||||
|
| [] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let predicate_1 : (type_value -> bool) -> typer_predicate = fun f lst ->
|
||||||
|
match lst with
|
||||||
|
| [ a ] -> f a
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let predicate_2 : (type_value -> type_value -> bool) -> typer_predicate = fun f lst ->
|
||||||
|
match lst with
|
||||||
|
| [ a ; b ] -> f a b
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let predicate_3 : (type_value -> type_value -> type_value -> bool) -> typer_predicate = fun f lst ->
|
||||||
|
match lst with
|
||||||
|
| [ a ; b ; c ] -> f a b c
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let true_1 = predicate_1 (fun _ -> true)
|
||||||
|
let true_2 = predicate_2 (fun _ _ -> true)
|
||||||
|
let true_3 = predicate_3 (fun _ _ _ -> true)
|
||||||
|
|
||||||
|
let eq_1 : type_value -> typer_predicate = fun v ->
|
||||||
|
let aux = fun a -> type_value_eq (a, v) in
|
||||||
|
predicate_1 aux
|
||||||
|
|
||||||
|
let eq_2 : type_value -> typer_predicate = fun v ->
|
||||||
|
let aux = fun a b -> type_value_eq (a, v) && type_value_eq (b, v) in
|
||||||
|
predicate_2 aux
|
||||||
|
|
||||||
|
let typer'_0 : (type_value option -> type_result result) -> typer' = fun f lst tv ->
|
||||||
|
match lst with
|
||||||
|
| [] -> f tv
|
||||||
|
| _ -> simple_fail "!!!"
|
||||||
|
|
||||||
|
let typer'_1 : (type_value -> type_result result) -> typer' = fun f lst _ ->
|
||||||
|
match lst with
|
||||||
|
| [ a ] -> f a
|
||||||
|
| _ -> simple_fail "!!!"
|
||||||
|
|
||||||
|
let typer'_1_opt : (type_value -> type_value option -> type_result result) -> typer' = fun f lst tv_opt ->
|
||||||
|
match lst with
|
||||||
|
| [ a ] -> f a tv_opt
|
||||||
|
| _ -> simple_fail "!!!"
|
||||||
|
|
||||||
|
let typer'_2 : (type_value -> type_value -> type_result result) -> typer' = fun f lst _ ->
|
||||||
|
match lst with
|
||||||
|
| [ a ; b ] -> f a b
|
||||||
|
| _ -> simple_fail "!!!"
|
||||||
|
|
||||||
|
let typer'_3 : (type_value -> type_value -> type_value -> type_result result) -> typer' = fun f lst _ ->
|
||||||
|
match lst with
|
||||||
|
| [ a ; b ; c ] -> f a b c
|
||||||
|
| _ -> simple_fail "!!!"
|
||||||
|
|
||||||
|
let typer_constant cst : typer' = fun _ _ -> ok cst
|
||||||
|
|
||||||
|
let constant_2 : string -> type_value -> typer' = fun s tv ->
|
||||||
|
let aux = fun _ _ -> ok (s, tv) in
|
||||||
|
typer'_2 aux
|
||||||
|
|
||||||
|
let make_2 : string -> _ list -> typer = fun name pfs ->
|
||||||
|
(name , 2 , List.map (Tuple.map_h_2 predicate_2 typer'_2) pfs)
|
||||||
|
|
||||||
|
let same_2 : string -> (string * type_value) list -> typer = fun s lst ->
|
||||||
|
let aux (s, tv) = eq_2 tv, constant_2 s tv in
|
||||||
|
(s , 2 , List.map aux lst)
|
||||||
|
|
||||||
|
let very_same_2 : string -> type_value -> typer = fun s tv -> same_2 s [s , tv]
|
||||||
|
|
||||||
|
open Combinators
|
||||||
|
|
||||||
|
let comparator : string -> typer = fun s -> s , 2 , [
|
||||||
|
(eq_2 (t_int ()), constant_2 s (t_bool ())) ;
|
||||||
|
(eq_2 (t_nat ()), constant_2 s (t_bool ())) ;
|
||||||
|
(eq_2 (t_tez ()), constant_2 s (t_bool ())) ;
|
||||||
|
(eq_2 (t_bytes ()), constant_2 s (t_bool ())) ;
|
||||||
|
(eq_2 (t_string ()), constant_2 s (t_bool ())) ;
|
||||||
|
(eq_2 (t_address ()), constant_2 s (t_bool ())) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let boolean_operator_2 : string -> typer = fun s -> very_same_2 s (t_bool ())
|
||||||
|
|
||||||
|
let none = "NONE" , 0 , [
|
||||||
|
predicate_0 , typer'_0 (fun tv_opt -> match tv_opt with
|
||||||
|
| None -> simple_fail "untyped NONE"
|
||||||
|
| Some t -> ok ("NONE", t))
|
||||||
|
]
|
||||||
|
|
||||||
|
let sub = "SUB" , 2 , [
|
||||||
|
eq_2 (t_int ()) , constant_2 "SUB_INT" (t_int ()) ;
|
||||||
|
eq_2 (t_nat ()) , constant_2 "SUB_NAT" (t_int ()) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let some = "SOME" , 1 , [
|
||||||
|
true_1 , typer'_1 (fun s -> ok ("SOME", t_option s ())) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let map_remove : typer = "MAP_REMOVE" , 2 , [
|
||||||
|
(true_2 , typer'_2 (fun k m ->
|
||||||
|
let%bind (src, _) = get_t_map m in
|
||||||
|
let%bind () = assert_type_value_eq (src, k) in
|
||||||
|
ok ("MAP_REMOVE", m)
|
||||||
|
))
|
||||||
|
]
|
||||||
|
|
||||||
|
let map_update : typer = "MAP_UPDATE" , 3 , [
|
||||||
|
(true_3 , typer'_3 (fun k v m ->
|
||||||
|
let%bind (src, dst) = get_t_map m in
|
||||||
|
let%bind () = assert_type_value_eq (src, k) in
|
||||||
|
let%bind () = assert_type_value_eq (dst, v) in
|
||||||
|
ok ("MAP_UPDATE", m)))
|
||||||
|
]
|
||||||
|
|
||||||
|
let size : typer = "size" , 1 , [
|
||||||
|
(true_1, typer'_1 (fun t ->
|
||||||
|
let%bind () = bind_or (assert_t_map t, assert_t_list t) in
|
||||||
|
ok ("SIZE", t_nat ())))
|
||||||
|
]
|
||||||
|
|
||||||
|
let get_force : typer = "get_force" , 2 , [
|
||||||
|
(true_2, typer'_2 (fun i_ty m_ty ->
|
||||||
|
let%bind (src, dst) = get_t_map m_ty in
|
||||||
|
let%bind _ = assert_type_value_eq (src, i_ty) in
|
||||||
|
ok ("GET_FORCE", dst)))
|
||||||
|
]
|
||||||
|
|
||||||
|
let int : typer = "int" , 1 , [
|
||||||
|
(eq_1 (t_nat ()), typer_constant ("INT" , t_int ()))
|
||||||
|
]
|
||||||
|
|
||||||
|
let bytes_pack : typer = "Bytes.pack" , 1 , [
|
||||||
|
(true_1 , typer'_1 (fun _ -> ok ("PACK" , t_bytes ())))
|
||||||
|
]
|
||||||
|
|
||||||
|
let bytes_unpack = "Bytes.unpack" , 1 , [
|
||||||
|
eq_1 (t_bytes ()) , typer'_1_opt (fun _ tv_opt -> match tv_opt with
|
||||||
|
| None -> simple_fail "untyped UNPACK"
|
||||||
|
| Some t -> ok ("UNPACK", t))
|
||||||
|
]
|
||||||
|
|
||||||
|
let crypto_hash = "Crypto.hash" , 1 , [
|
||||||
|
eq_1 (t_bytes ()) , typer_constant ("HASH" , t_bytes ()) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let sender = "sender" , 0 , [
|
||||||
|
predicate_0 , typer_constant ("SENDER", t_address ())
|
||||||
|
]
|
||||||
|
|
||||||
|
let source = "source" , 0 , [
|
||||||
|
predicate_0 , typer_constant ("SOURCE", t_address ())
|
||||||
|
]
|
||||||
|
|
||||||
|
let unit = "unit" , 0 , [
|
||||||
|
predicate_0 , typer_constant ("UNIT", t_unit ())
|
||||||
|
]
|
||||||
|
|
||||||
|
let amount = "amount" , 0 , [
|
||||||
|
predicate_0 , typer_constant ("AMOUNT", t_tez ())
|
||||||
|
]
|
||||||
|
|
||||||
|
let transaction = "Operation.transaction" , 3 , [
|
||||||
|
true_3 , typer'_3 (
|
||||||
|
fun param amount contract ->
|
||||||
|
let%bind () =
|
||||||
|
assert_t_tez amount in
|
||||||
|
let%bind contract_param =
|
||||||
|
get_t_contract contract in
|
||||||
|
let%bind () =
|
||||||
|
assert_type_value_eq (param , contract_param) in
|
||||||
|
ok ("TRANSFER_TOKENS" , t_operation ())
|
||||||
|
)
|
||||||
|
]
|
||||||
|
let transaction' = "transaction" , 3 , [
|
||||||
|
true_3 , typer'_3 (
|
||||||
|
fun param amount contract ->
|
||||||
|
let%bind () =
|
||||||
|
assert_t_tez amount in
|
||||||
|
let%bind contract_param =
|
||||||
|
get_t_contract contract in
|
||||||
|
let%bind () =
|
||||||
|
assert_type_value_eq (param , contract_param) in
|
||||||
|
ok ("TRANSFER_TOKENS" , t_operation ())
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
let get_contract = "Operation.get_contract" , 1 , [
|
||||||
|
eq_1 (t_address ()) , typer'_1_opt (
|
||||||
|
fun _ tv_opt ->
|
||||||
|
let%bind tv =
|
||||||
|
trace_option (simple_error "get_contract needs a type annotation") tv_opt in
|
||||||
|
let%bind tv' =
|
||||||
|
trace_strong (simple_error "get_contract has a not-contract annotation") @@
|
||||||
|
get_t_contract tv in
|
||||||
|
ok ("CONTRACT" , t_contract tv' ())
|
||||||
|
)
|
||||||
|
]
|
||||||
|
let get_contract' = "get_contract" , 1 , [
|
||||||
|
eq_1 (t_address ()) , typer'_1_opt (
|
||||||
|
fun _ tv_opt ->
|
||||||
|
let%bind tv =
|
||||||
|
trace_option (simple_error "get_contract needs a type annotation") tv_opt in
|
||||||
|
let%bind tv' =
|
||||||
|
trace_strong (simple_error "get_contract has a not-contract annotation") @@
|
||||||
|
get_t_contract tv in
|
||||||
|
ok ("CONTRACT" , t_contract tv' ())
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
let num_2 : typer_predicate =
|
||||||
|
let aux = fun a b ->
|
||||||
|
(type_value_eq (a , t_int ()) || type_value_eq (a , t_nat ())) &&
|
||||||
|
(type_value_eq (b , t_int ()) || type_value_eq (b , t_nat ())) in
|
||||||
|
predicate_2 aux
|
||||||
|
|
||||||
|
let mod_ = "MOD" , 2 , [
|
||||||
|
num_2 , constant_2 "MOD" (t_nat ()) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let abs = "abs" , 1 , [
|
||||||
|
eq_1 (t_int ()) , typer_constant ("ABS" , (t_nat ())) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let times = "TIMES" , 2 , [
|
||||||
|
(eq_2 (t_nat ()) , constant_2 "TIMES_NAT" (t_nat ())) ;
|
||||||
|
(num_2 , constant_2 "TIMES_INT" (t_int ())) ;
|
||||||
|
(
|
||||||
|
let aux a b =
|
||||||
|
(type_value_eq (a , t_nat ()) && type_value_eq (b , t_tez ())) ||
|
||||||
|
(type_value_eq (b , t_nat ()) && type_value_eq (a , t_tez ())) in
|
||||||
|
predicate_2 aux , constant_2 "TIMES_TEZ" (t_tez ())
|
||||||
|
) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let constant_typers =
|
||||||
|
let typer_to_kv : typer -> (string * _) = fun (a, b, c) -> (a, (b, c)) in
|
||||||
|
Map.String.of_list
|
||||||
|
@@ List.map typer_to_kv [
|
||||||
|
same_2 "ADD" [
|
||||||
|
("ADD_INT" , t_int ()) ;
|
||||||
|
("ADD_NAT" , t_nat ()) ;
|
||||||
|
("CONCAT" , t_string ()) ;
|
||||||
|
] ;
|
||||||
|
times ;
|
||||||
|
same_2 "DIV" [
|
||||||
|
("DIV_INT" , t_int ()) ;
|
||||||
|
("DIV_NAT" , t_nat ()) ;
|
||||||
|
] ;
|
||||||
|
mod_ ;
|
||||||
|
sub ;
|
||||||
|
none ;
|
||||||
|
some ;
|
||||||
|
comparator "EQ" ;
|
||||||
|
comparator "NEQ" ;
|
||||||
|
comparator "LT" ;
|
||||||
|
comparator "GT" ;
|
||||||
|
comparator "LE" ;
|
||||||
|
comparator "GE" ;
|
||||||
|
boolean_operator_2 "OR" ;
|
||||||
|
boolean_operator_2 "AND" ;
|
||||||
|
map_remove ;
|
||||||
|
map_update ;
|
||||||
|
int ;
|
||||||
|
size ;
|
||||||
|
get_force ;
|
||||||
|
bytes_pack ;
|
||||||
|
bytes_unpack ;
|
||||||
|
crypto_hash ;
|
||||||
|
sender ;
|
||||||
|
source ;
|
||||||
|
unit ;
|
||||||
|
amount ;
|
||||||
|
transaction ;
|
||||||
|
transaction' ;
|
||||||
|
get_contract ;
|
||||||
|
get_contract' ;
|
||||||
|
abs ;
|
||||||
|
]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Compiler = struct
|
||||||
|
|
||||||
|
module Michelson = Tezos_utils.Micheline.Michelson
|
||||||
|
open Michelson
|
||||||
|
|
||||||
|
type predicate =
|
||||||
|
| Constant of michelson
|
||||||
|
| Unary of michelson
|
||||||
|
| Binary of michelson
|
||||||
|
| Ternary of michelson
|
||||||
|
|
||||||
|
let simple_constant c = Constant c
|
||||||
|
|
||||||
|
let simple_unary c = Unary c
|
||||||
|
|
||||||
|
let simple_binary c = Binary c
|
||||||
|
|
||||||
|
let simple_ternary c = Ternary c
|
||||||
|
|
||||||
|
let predicates = Map.String.of_list [
|
||||||
|
("ADD_INT" , simple_binary @@ prim I_ADD) ;
|
||||||
|
("ADD_NAT" , simple_binary @@ prim I_ADD) ;
|
||||||
|
("SUB_INT" , simple_binary @@ prim I_SUB) ;
|
||||||
|
("SUB_NAT" , simple_binary @@ prim I_SUB) ;
|
||||||
|
("TIMES_INT" , simple_binary @@ prim I_MUL) ;
|
||||||
|
("TIMES_NAT" , simple_binary @@ prim I_MUL) ;
|
||||||
|
("TIMES_TEZ" , simple_binary @@ prim I_MUL) ;
|
||||||
|
("DIV_INT" , simple_binary @@ seq [prim I_EDIV ; i_assert_some_msg (i_push_string "DIV by 0") ; i_car]) ;
|
||||||
|
("DIV_NAT" , simple_binary @@ seq [prim I_EDIV ; i_assert_some_msg (i_push_string "DIV by 0") ; i_car]) ;
|
||||||
|
("MOD" , simple_binary @@ seq [prim I_EDIV ; i_assert_some_msg (i_push_string "MOD by 0") ; i_cdr]) ;
|
||||||
|
("NEG" , simple_unary @@ prim I_NEG) ;
|
||||||
|
("OR" , simple_binary @@ prim I_OR) ;
|
||||||
|
("AND" , simple_binary @@ prim I_AND) ;
|
||||||
|
("PAIR" , simple_binary @@ prim I_PAIR) ;
|
||||||
|
("CAR" , simple_unary @@ prim I_CAR) ;
|
||||||
|
("CDR" , simple_unary @@ prim I_CDR) ;
|
||||||
|
("EQ" , simple_binary @@ seq [prim I_COMPARE ; prim I_EQ]) ;
|
||||||
|
("NEQ" , simple_binary @@ seq [prim I_COMPARE ; prim I_NEQ]) ;
|
||||||
|
("LT" , simple_binary @@ seq [prim I_COMPARE ; prim I_LT]) ;
|
||||||
|
("LE" , simple_binary @@ seq [prim I_COMPARE ; prim I_LE]) ;
|
||||||
|
("GT" , simple_binary @@ seq [prim I_COMPARE ; prim I_GT]) ;
|
||||||
|
("GE" , simple_binary @@ seq [prim I_COMPARE ; prim I_GE]) ;
|
||||||
|
("UPDATE" , simple_ternary @@ prim I_UPDATE) ;
|
||||||
|
("SOME" , simple_unary @@ prim I_SOME) ;
|
||||||
|
("GET_FORCE" , simple_binary @@ seq [prim I_GET ; i_assert_some_msg (i_push_string "GET_FORCE")]) ;
|
||||||
|
("GET" , simple_binary @@ prim I_GET) ;
|
||||||
|
("SIZE" , simple_unary @@ prim I_SIZE) ;
|
||||||
|
("FAILWITH" , simple_unary @@ prim I_FAILWITH) ;
|
||||||
|
("ASSERT" , simple_binary @@ i_if (seq [i_failwith]) (seq [i_drop ; i_push_unit])) ;
|
||||||
|
("INT" , simple_unary @@ prim I_INT) ;
|
||||||
|
("ABS" , simple_unary @@ prim I_ABS) ;
|
||||||
|
("CONS" , simple_binary @@ prim I_CONS) ;
|
||||||
|
("UNIT" , simple_constant @@ prim I_UNIT) ;
|
||||||
|
("AMOUNT" , simple_constant @@ prim I_AMOUNT) ;
|
||||||
|
("TRANSFER_TOKENS" , simple_ternary @@ prim I_TRANSFER_TOKENS) ;
|
||||||
|
("SOURCE" , simple_constant @@ prim I_SOURCE) ;
|
||||||
|
("SENDER" , simple_constant @@ prim I_SENDER) ;
|
||||||
|
( "MAP_UPDATE" , simple_ternary @@ seq [dip (i_some) ; prim I_UPDATE ]) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
end
|
2
parser/camligo/.gitignore
vendored
Normal file
2
parser/camligo/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ast_generated.ml
|
||||||
|
parser_generated.mly
|
1
parser/camligo/ast.ml
Normal file
1
parser/camligo/ast.ml
Normal file
@ -0,0 +1 @@
|
|||||||
|
include Ast_generated
|
60
parser/camligo/dune
Normal file
60
parser/camligo/dune
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
(library
|
||||||
|
(name parser_camligo)
|
||||||
|
(public_name ligo.parser.camligo)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
lex
|
||||||
|
)
|
||||||
|
(modules ast ast_generated parser user)
|
||||||
|
(flags (:standard -w +1..62-4-9-44-40-42-48@39@33 -open Simple_utils -open Tezos_utils ))
|
||||||
|
(preprocess
|
||||||
|
(pps
|
||||||
|
simple-utils.ppx_let_generalized
|
||||||
|
ppx_deriving.std
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Generating parser
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets parser.ml parser.mli)
|
||||||
|
(deps parser_generated.mly ast.ml)
|
||||||
|
(action (system "menhir --explain --external-tokens Lex.Token lex/token.mly parser_generated.mly --base parser"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets parser_generated.mly)
|
||||||
|
(deps partial_parser.mly pre_parser.mly)
|
||||||
|
(action (system "cat pre_parser.mly partial_parser.mly > parser_generated.mly"))
|
||||||
|
(mode promote-until-clean)
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets partial_parser.mly)
|
||||||
|
(deps generator.exe)
|
||||||
|
(action (system "./generator.exe parser > partial_parser.mly"))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Generating AST
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets ast_generated.ml)
|
||||||
|
(deps generator.exe)
|
||||||
|
(action (system "./generator.exe ast > ast_generated.ml"))
|
||||||
|
(mode promote-until-clean)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Generating Generator
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name generator)
|
||||||
|
(libraries
|
||||||
|
ocamlgraph
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
lex
|
||||||
|
)
|
||||||
|
(modules generator)
|
||||||
|
)
|
739
parser/camligo/generator.ml
Normal file
739
parser/camligo/generator.ml
Normal file
@ -0,0 +1,739 @@
|
|||||||
|
open Simple_utils
|
||||||
|
|
||||||
|
type 'a name = {
|
||||||
|
content : 'a ;
|
||||||
|
name : string ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let make_name name content = { name ; content }
|
||||||
|
let destruct {name ; content} = (name, content)
|
||||||
|
let get_name x = x.name
|
||||||
|
let get_content x = x.content
|
||||||
|
|
||||||
|
module Token = Lex.Token
|
||||||
|
type token = Token.token
|
||||||
|
|
||||||
|
module O = struct
|
||||||
|
|
||||||
|
type list_mode =
|
||||||
|
| Trail of token
|
||||||
|
| Trail_option of token
|
||||||
|
| Trail_force of token
|
||||||
|
| Trail_force_ne of token
|
||||||
|
| Lead of token
|
||||||
|
| Lead_ne of token
|
||||||
|
| Separated of token
|
||||||
|
| Separated_ne of token
|
||||||
|
| Separated_nene of token
|
||||||
|
| Naked
|
||||||
|
| Naked_ne
|
||||||
|
|
||||||
|
type 'a list_element = list_mode * 'a
|
||||||
|
|
||||||
|
type rhs_element = [
|
||||||
|
| `Named of string
|
||||||
|
| `Token of token
|
||||||
|
| `List of string list_element
|
||||||
|
| `Option of string
|
||||||
|
]
|
||||||
|
|
||||||
|
type rhs = rhs_element list name
|
||||||
|
type rule = rhs list name
|
||||||
|
|
||||||
|
type manual_rule_content = {
|
||||||
|
menhir_codes : string list ;
|
||||||
|
ast_code : string ;
|
||||||
|
}
|
||||||
|
type manual_rule = manual_rule_content name
|
||||||
|
|
||||||
|
type singleton =
|
||||||
|
| Manual of manual_rule
|
||||||
|
| Generated of rule
|
||||||
|
|
||||||
|
type name_element = [
|
||||||
|
| `Named of string
|
||||||
|
| `Current
|
||||||
|
| `Lower
|
||||||
|
]
|
||||||
|
|
||||||
|
type element = [
|
||||||
|
| `Named of string
|
||||||
|
| `Token of token
|
||||||
|
| `List of name_element list_element
|
||||||
|
| `Current
|
||||||
|
| `Lower
|
||||||
|
]
|
||||||
|
|
||||||
|
type operator = element list
|
||||||
|
type n_operator = operator name
|
||||||
|
|
||||||
|
type n_operators = n_operator list
|
||||||
|
type level = n_operators name
|
||||||
|
type level_list = level list
|
||||||
|
type levels = level List.Ne.t
|
||||||
|
|
||||||
|
type hierarchy = {
|
||||||
|
prefix : string ;
|
||||||
|
levels : levels ;
|
||||||
|
auxiliary_rules : rule list ;
|
||||||
|
}
|
||||||
|
type n_hierarchy = hierarchy name
|
||||||
|
let make_hierarchy prefix levels auxiliary_rules : hierarchy = { levels ; auxiliary_rules ; prefix }
|
||||||
|
|
||||||
|
type language = {
|
||||||
|
entry_point : string ;
|
||||||
|
singletons : singleton list ;
|
||||||
|
hierarchies : n_hierarchy list ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let get_op : n_operator -> operator = get_content
|
||||||
|
|
||||||
|
let manual_singleton name menhir_codes ast_code : singleton = Manual (make_name name {menhir_codes ; ast_code})
|
||||||
|
let rule_singleton rule : singleton = Generated rule
|
||||||
|
let language entry_point singletons hierarchies = {entry_point ; singletons ; hierarchies}
|
||||||
|
|
||||||
|
let name_hierarchy name prefix : n_operators list -> rule list -> n_hierarchy = fun nopss rules ->
|
||||||
|
let nopss' = List.Ne.of_list nopss in
|
||||||
|
let name_i : int -> n_operators -> level = fun i x ->
|
||||||
|
let first = get_name (List.hd x) in
|
||||||
|
let name' = Format.asprintf "%s_%d_%s" name i first in
|
||||||
|
make_name name' x in
|
||||||
|
let levels : levels = List.Ne.mapi name_i nopss' in
|
||||||
|
make_name name @@ make_hierarchy prefix levels rules
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Check = struct
|
||||||
|
open O
|
||||||
|
|
||||||
|
let well_formed : language -> unit = fun l ->
|
||||||
|
let elements : element list -> unit = fun es ->
|
||||||
|
let rec aux = fun es ->
|
||||||
|
match es with
|
||||||
|
| [] -> ()
|
||||||
|
| [ _ ] -> ()
|
||||||
|
| (`List _ | `Named _ | `Current | `Lower) :: (`List _ | `Named _ | `Current | `Lower) :: _ ->
|
||||||
|
raise (Failure "two non-token separated ops in a row")
|
||||||
|
| _ :: tl -> aux tl
|
||||||
|
in
|
||||||
|
(if (List.length es < 2) then raise (Failure "operator is too short")) ;
|
||||||
|
aux es in
|
||||||
|
let op : n_operator -> unit = fun x -> elements @@ get_content x in
|
||||||
|
let level : level -> unit = fun l -> List.iter op @@ get_content l in
|
||||||
|
let hierarchy : n_hierarchy -> unit = fun h -> List.Ne.iter level @@ h.content.levels in
|
||||||
|
List.iter hierarchy l.hierarchies
|
||||||
|
|
||||||
|
let associativity : language -> unit = fun l ->
|
||||||
|
let level : level -> unit = fun l ->
|
||||||
|
let aux : ([`Left | `Right | `None] as 'a) -> n_operator -> 'a = fun ass nop ->
|
||||||
|
let op = get_content nop in
|
||||||
|
match ass, List.hd op, List.nth op (List.length op - 1) with
|
||||||
|
| _, `Lower, `Lower -> raise (Failure "double assoc")
|
||||||
|
| `None, `Lower, _ -> `Left
|
||||||
|
| `None, _, `Lower -> `Right
|
||||||
|
| `Left, _, `Lower -> raise (Failure "different assocs")
|
||||||
|
| `Right, `Lower, _ -> raise (Failure "different assocs")
|
||||||
|
| m, _, _ -> m
|
||||||
|
in
|
||||||
|
let _assert = List.fold_left aux `None (get_content l) in
|
||||||
|
()
|
||||||
|
in
|
||||||
|
let hierarchy : n_hierarchy -> unit = fun h ->
|
||||||
|
List.Ne.iter level h.content.levels in
|
||||||
|
List.iter hierarchy l.hierarchies
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
let make_constructor : _ -> (string * string) -> unit = fun ppf (gr, rhs) ->
|
||||||
|
let gr = String.capitalize_ascii gr in
|
||||||
|
match rhs with
|
||||||
|
| "" -> Format.fprintf ppf "%s" gr
|
||||||
|
| s -> Format.fprintf ppf "%s_%s" gr s
|
||||||
|
|
||||||
|
let make_operator : _ -> (string * string) -> unit = fun ppf (prefix, op) ->
|
||||||
|
Format.fprintf ppf "%s_%s" prefix op
|
||||||
|
|
||||||
|
module Print_AST = struct
|
||||||
|
open Format
|
||||||
|
open PP_helpers
|
||||||
|
|
||||||
|
let manual_rule : _ -> O.manual_rule -> _ = fun ppf mr ->
|
||||||
|
fprintf ppf "%s = %s" mr.name mr.content.ast_code
|
||||||
|
|
||||||
|
let generated_rule : _ -> O.rule -> _ = fun ppf gr ->
|
||||||
|
let aux : _ -> O.rhs -> _ = fun ppf rhs ->
|
||||||
|
let type_elements =
|
||||||
|
let aux : O.rhs_element -> string option = fun e ->
|
||||||
|
match e with
|
||||||
|
| `Named s -> Some (s ^ " Location.wrap")
|
||||||
|
| `List ( _, s) -> Some ("(" ^ s ^ " Location.wrap list)")
|
||||||
|
| `Option s -> Some ("(" ^ s ^ " Location.wrap option)")
|
||||||
|
| `Token _ -> None
|
||||||
|
in
|
||||||
|
List.filter_map aux rhs.content in
|
||||||
|
let type_element = fun ppf te -> fprintf ppf "%s" te in
|
||||||
|
fprintf ppf "| %a of (%a)"
|
||||||
|
make_constructor (gr.name, rhs.name)
|
||||||
|
(list_sep type_element (const " * ")) type_elements
|
||||||
|
in
|
||||||
|
fprintf ppf "%s =@. @[<v>%a@]" gr.name
|
||||||
|
(list_sep aux new_line) gr.content
|
||||||
|
|
||||||
|
let singleton : _ -> O.singleton -> _ = fun ppf s ->
|
||||||
|
match s with
|
||||||
|
| Manual s -> manual_rule ppf s
|
||||||
|
| Generated s -> generated_rule ppf s
|
||||||
|
|
||||||
|
let singletons : _ -> O.singleton list -> _ = fun ppf ss ->
|
||||||
|
match ss with
|
||||||
|
| [] -> ()
|
||||||
|
| hd :: tl ->
|
||||||
|
fprintf ppf "%a\n" (prepend "type " (singleton)) hd ;
|
||||||
|
fprintf ppf "%a" (list_sep (prepend "and " (singleton)) (const "\n")) tl
|
||||||
|
|
||||||
|
let n_operator prefix level_name : _ -> O.n_operator -> _ = fun ppf nop ->
|
||||||
|
let type_elements =
|
||||||
|
let aux : O.element -> string option = fun e ->
|
||||||
|
match e with
|
||||||
|
| `Named s -> Some (s ^ " Location.wrap")
|
||||||
|
| `List ( _, s) -> Some ("(" ^ (match s with
|
||||||
|
| `Lower | `Current -> level_name |`Named s -> s
|
||||||
|
) ^ " Location.wrap list)")
|
||||||
|
| `Token _ -> None
|
||||||
|
| `Current | `Lower -> Some (level_name ^ " Location.wrap") in
|
||||||
|
List.filter_map aux (get_content nop) in
|
||||||
|
let type_element = fun ppf te -> fprintf ppf "%s" te in
|
||||||
|
fprintf ppf "| %a of (%a)"
|
||||||
|
make_operator (prefix, nop.name)
|
||||||
|
(list_sep type_element (const " * ")) type_elements
|
||||||
|
|
||||||
|
let n_hierarchy t : _ -> O.n_hierarchy -> _ = fun ppf nh ->
|
||||||
|
let levels = List.Ne.map get_content ((get_content nh).levels) in
|
||||||
|
let nops = List.Ne.concat levels in
|
||||||
|
let name = get_name nh in
|
||||||
|
fprintf ppf "%s %s =@.@[%a@] [@@@@deriving show]" t
|
||||||
|
name
|
||||||
|
(list_sep (n_operator nh.content.prefix name) new_line) nops
|
||||||
|
|
||||||
|
let n_hierarchies (first:bool) : _ -> O.n_hierarchy list -> _ = fun ppf ss ->
|
||||||
|
match ss with
|
||||||
|
| [] -> ()
|
||||||
|
| hd :: tl ->
|
||||||
|
fprintf ppf "%a\n" (n_hierarchy (if first then "type" else "and")) hd ;
|
||||||
|
fprintf ppf "%a" (list_sep (n_hierarchy "and") (const "\n")) tl
|
||||||
|
|
||||||
|
let language : _ -> O.language -> _ = fun ppf l ->
|
||||||
|
fprintf ppf "%a@.@." comment "Language" ;
|
||||||
|
let first = List.length l.singletons = 0 in
|
||||||
|
fprintf ppf " %a@.%a@.@." comment "Singletons" singletons l.singletons ;
|
||||||
|
fprintf ppf " %a@.%a@." comment "Hierarchies" (n_hierarchies first) l.hierarchies ;
|
||||||
|
fprintf ppf " %a@.type entry_point = %s Location.wrap@.@." comment "Entry point" l.entry_point ;
|
||||||
|
()
|
||||||
|
end
|
||||||
|
|
||||||
|
module Print_Grammar = struct
|
||||||
|
open Format
|
||||||
|
open PP_helpers
|
||||||
|
|
||||||
|
let letters = [| "a" ; "b" ; "c" ; "d" ; "e" ; "f" ; "g" ; "h" ; "i" ; "j" |]
|
||||||
|
|
||||||
|
|
||||||
|
let manual_rule : _ -> O.manual_rule -> _ = fun ppf mr ->
|
||||||
|
let {name;content} = mr in
|
||||||
|
fprintf ppf "%s:@. @[<v>%a@]" name (list_sep string new_line) content.menhir_codes
|
||||||
|
|
||||||
|
let generated_rule : _ -> O.rule -> _ = fun ppf gr ->
|
||||||
|
let aux_rule : _ -> O.rhs -> _ = fun ppf rhs ->
|
||||||
|
let i = ref 0 in
|
||||||
|
let aux : _ -> O.rhs_element -> _ = fun ppf e ->
|
||||||
|
(match e with
|
||||||
|
| `Named s -> fprintf ppf "%s = wrap(%s)" letters.(!i) s
|
||||||
|
| `Option s -> fprintf ppf "%s = option(wrap(%s))" letters.(!i) s
|
||||||
|
| `List (mode, s) ->
|
||||||
|
fprintf ppf "%s = %swrap(%s))"
|
||||||
|
letters.(!i)
|
||||||
|
(match mode with
|
||||||
|
| Naked -> "naked_list("
|
||||||
|
| Naked_ne -> "naked_list_ne("
|
||||||
|
| Lead s -> "lead_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Lead_ne s -> "lead_list_ne(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail s -> "trail_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail_option s -> "trail_option_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail_force s -> "trail_force_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail_force_ne s -> "trail_force_list_ne(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Separated s -> "separated_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Separated_ne s -> "separated_list_ne(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Separated_nene s -> "separated_list_nene(" ^ (Token.to_string s) ^ ","
|
||||||
|
)
|
||||||
|
s
|
||||||
|
| `Token t -> i := !i - 1 ; string ppf @@ Token.to_string t) ;
|
||||||
|
i := !i + 1
|
||||||
|
in
|
||||||
|
fprintf ppf "%a" (list_sep aux (const " ")) rhs.content in
|
||||||
|
let aux_code : _ -> O.rhs -> _ = fun ppf rhs ->
|
||||||
|
let i = ref 0 in
|
||||||
|
let aux : O.rhs_element -> _ = fun e ->
|
||||||
|
let s = (match e with
|
||||||
|
| `Named _ | `List _ | `Option _ -> Some (letters.(!i))
|
||||||
|
| `Token _ -> i := !i - 1 ; None) in
|
||||||
|
i := !i + 1 ; s
|
||||||
|
in
|
||||||
|
let content = List.filter_map aux rhs.content in
|
||||||
|
fprintf ppf "%a (%a)" make_constructor (gr.name, rhs.name) (list_sep string (const " , ")) content
|
||||||
|
in
|
||||||
|
let aux : _ -> O.rhs -> _ = fun ppf rhs ->
|
||||||
|
fprintf ppf "| %a { %a }"
|
||||||
|
aux_rule rhs
|
||||||
|
aux_code rhs in
|
||||||
|
fprintf ppf "%s:@.%a" gr.name (list_sep aux (const "\n")) gr.content
|
||||||
|
|
||||||
|
let singleton : _ -> O.singleton -> _ = fun ppf s ->
|
||||||
|
match s with
|
||||||
|
| Manual s -> manual_rule ppf s
|
||||||
|
| Generated s -> generated_rule ppf s
|
||||||
|
|
||||||
|
|
||||||
|
let n_operator_rule prev_lvl_name cur_lvl_name : _ -> O.n_operator -> _ = fun ppf nop ->
|
||||||
|
let i = ref 0 in
|
||||||
|
let element : _ -> O.element -> _ = fun ppf element ->
|
||||||
|
(match element with
|
||||||
|
| `Token t -> i := !i - 1 ; string ppf @@ Token.to_string t
|
||||||
|
| `List (mode, content) ->
|
||||||
|
fprintf ppf "%s = %swrap(%s))"
|
||||||
|
letters.(!i)
|
||||||
|
(match mode with
|
||||||
|
| Naked -> "naked_list("
|
||||||
|
| Naked_ne -> "naked_list_ne("
|
||||||
|
| Lead s -> "lead_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Lead_ne s -> "lead_list_ne(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail s -> "trail_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail_option s -> "trail_option_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail_force s -> "trail_force_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Trail_force_ne s -> "trail_force_list_ne(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Separated s -> "separated_list(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Separated_ne s -> "separated_list_ne(" ^ (Token.to_string s) ^ ","
|
||||||
|
| Separated_nene s -> "separated_list_nene(" ^ (Token.to_string s) ^ ","
|
||||||
|
)
|
||||||
|
(match content with | `Lower -> prev_lvl_name | `Named s -> s | `Current -> cur_lvl_name)
|
||||||
|
| `Named n ->
|
||||||
|
fprintf ppf "%s = wrap(%s)" letters.(!i) n
|
||||||
|
| `Current ->
|
||||||
|
fprintf ppf "%s = wrap(%s)" letters.(!i) cur_lvl_name
|
||||||
|
| `Lower ->
|
||||||
|
fprintf ppf "%s = wrap(%s)" letters.(!i) prev_lvl_name
|
||||||
|
) ;
|
||||||
|
i := !i + 1
|
||||||
|
in
|
||||||
|
(list_sep element (const " ")) ppf (get_content nop)
|
||||||
|
|
||||||
|
let n_operator_code prefix : _ -> O.n_operator -> _ = fun ppf nop ->
|
||||||
|
let (name, elements) = destruct nop in
|
||||||
|
let elements' =
|
||||||
|
let i = ref 0 in
|
||||||
|
let aux : O.element -> _ = fun e ->
|
||||||
|
let r =
|
||||||
|
match e with
|
||||||
|
| `Token _ -> i := !i - 1 ; None
|
||||||
|
| `List _ | `Named _ | `Current | `Lower -> Some letters.(!i)
|
||||||
|
in i := !i + 1 ; r
|
||||||
|
in
|
||||||
|
List.filter_map aux elements in
|
||||||
|
fprintf ppf "%a (%a)" make_operator (prefix, name) (list_sep string (const " , ")) elements'
|
||||||
|
|
||||||
|
let n_operator prefix prev_lvl_name cur_lvl_name : _ -> O.n_operator -> _ = fun ppf nop ->
|
||||||
|
let name = get_name nop in
|
||||||
|
fprintf ppf "%a@;| %a { %a }" comment name
|
||||||
|
(n_operator_rule prev_lvl_name cur_lvl_name) nop
|
||||||
|
(n_operator_code prefix) nop
|
||||||
|
|
||||||
|
let level prefix prev_lvl_name : _ -> O.level -> _ = fun ppf l ->
|
||||||
|
let name = get_name l in
|
||||||
|
match prev_lvl_name with
|
||||||
|
| "" -> (
|
||||||
|
fprintf ppf "%s :@. @[<v>%a@]" name
|
||||||
|
(list_sep (n_operator prefix prev_lvl_name name) new_line) (get_content l) ;
|
||||||
|
)
|
||||||
|
| _ -> (
|
||||||
|
fprintf ppf "%s :@. @[<v>%a@;| %s { $1 }@]" name
|
||||||
|
(list_sep (n_operator prefix prev_lvl_name name) new_line) (get_content l)
|
||||||
|
prev_lvl_name
|
||||||
|
)
|
||||||
|
|
||||||
|
let n_hierarchy : _ -> O.n_hierarchy -> _ = fun ppf nh ->
|
||||||
|
let name = get_name nh in
|
||||||
|
let top_level = get_name @@ List.Ne.hd nh.content.levels in
|
||||||
|
fprintf ppf "%a@.%%inline %s : %s { $1 }@.@;" comment ("Top-level for " ^ name) name top_level;
|
||||||
|
let (hd, tl) = List.Ne.rev (get_content nh).levels in
|
||||||
|
fprintf ppf "%a" (level nh.content.prefix "") hd ;
|
||||||
|
let aux prev_name lvl =
|
||||||
|
new_lines 2 ppf () ;
|
||||||
|
fprintf ppf "%a" (level nh.content.prefix prev_name) lvl ;
|
||||||
|
get_name lvl
|
||||||
|
in
|
||||||
|
let _last_name = List.fold_left aux (get_name hd) tl in
|
||||||
|
()
|
||||||
|
|
||||||
|
let language : _ -> O.language -> _ = fun ppf l ->
|
||||||
|
fprintf ppf "%a@.@." comment "Generated Language" ;
|
||||||
|
fprintf ppf "entry_point : wrap(%s) EOF { $1 }@.@." l.entry_point ;
|
||||||
|
fprintf ppf "%a@.@." comment "Singletons" ;
|
||||||
|
fprintf ppf "@[%a@]@.@." (list_sep singleton new_line) l.singletons ;
|
||||||
|
fprintf ppf "%a@.@." comment "Hierarchies" ;
|
||||||
|
fprintf ppf "@[%a@]" (list_sep n_hierarchy new_line) l.hierarchies ;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
let infix : string -> [`Left | `Right] -> token -> O.n_operator = fun name assoc t ->
|
||||||
|
match assoc with
|
||||||
|
| `Left -> make_name name [`Current ; `Token t ; `Lower]
|
||||||
|
| `Right -> make_name name [`Lower ; `Token t ; `Current]
|
||||||
|
|
||||||
|
(* Ocaml is bad *)
|
||||||
|
let empty_infix : string -> [`Left | `Right] -> O.n_operator = fun name assoc ->
|
||||||
|
match assoc with
|
||||||
|
| `Left -> make_name name [`Current ; `Lower]
|
||||||
|
| `Right -> make_name name [`Lower ; `Current]
|
||||||
|
|
||||||
|
|
||||||
|
let paren : string -> string -> O.n_operator = fun constructor_name name ->
|
||||||
|
make_name constructor_name [`Token Token.LPAREN ; `Named name ; `Token Token.RPAREN]
|
||||||
|
|
||||||
|
let expression_name = "expression"
|
||||||
|
let type_expression_name = "type_expression"
|
||||||
|
let restricted_type_expression_name = "restricted_type_expression"
|
||||||
|
let program_name = "program"
|
||||||
|
let variable_name = "variable"
|
||||||
|
let pattern_name = "pattern"
|
||||||
|
let constructor_name = "constructor"
|
||||||
|
let int_name = "int_"
|
||||||
|
let tz_name = "tz_"
|
||||||
|
let unit_name = "unit_"
|
||||||
|
let string_name = "string_"
|
||||||
|
|
||||||
|
let variable = O.manual_singleton variable_name ["| NAME { $1 }"] "string"
|
||||||
|
let int = O.manual_singleton int_name ["| INT { $1 }"] "int"
|
||||||
|
let tz = O.manual_singleton tz_name ["| TZ { $1 }"] "int"
|
||||||
|
let unit = O.manual_singleton unit_name ["| UNIT { () }"] "unit"
|
||||||
|
let string = O.manual_singleton string_name ["| STRING { $1 }"] "string"
|
||||||
|
let constructor = O.manual_singleton constructor_name ["| CONSTRUCTOR_NAME { $1 }"] "string"
|
||||||
|
|
||||||
|
module Pattern = struct
|
||||||
|
|
||||||
|
open Token
|
||||||
|
open O
|
||||||
|
|
||||||
|
let application = empty_infix "application" `Left
|
||||||
|
|
||||||
|
let data_structure : O.n_operator = make_name "data_structure" [
|
||||||
|
`Named variable_name ; `Token LSQUARE ; `List (Lead SEMICOLON, `Current) ; `Token RSQUARE ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let record_element : O.rule = make_name "p_record_element" [
|
||||||
|
make_name "" [`Named variable_name ; `Token EQUAL ; `Named pattern_name]
|
||||||
|
]
|
||||||
|
|
||||||
|
let record : O.n_operator = make_name "record" [
|
||||||
|
`Token LBRACKET ;
|
||||||
|
`List (Trail SEMICOLON, `Named record_element.name) ;
|
||||||
|
`Token RBRACKET ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let pair = infix "pair" `Left COMMA
|
||||||
|
let type_annotation = make_name "type_annotation" [
|
||||||
|
`Current ; `Token COLON ; `Named restricted_type_expression_name
|
||||||
|
]
|
||||||
|
|
||||||
|
let variable : O.n_operator = make_name "variable" [ `Named variable_name ]
|
||||||
|
let constructor : O.n_operator = make_name "constructor" [ `Named constructor_name ]
|
||||||
|
|
||||||
|
let module_ident : O.n_operator = make_name "module_ident" [
|
||||||
|
`List (Trail_force_ne DOT, `Named constructor_name) ; `Named variable_name ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let unit : O.n_operator = make_name "unit" [ `Named unit_name ]
|
||||||
|
|
||||||
|
let restricted_pattern_name = "restricted_pattern"
|
||||||
|
|
||||||
|
let restricted_pattern = O.name_hierarchy restricted_pattern_name "Pr" [
|
||||||
|
[variable ; unit] ;
|
||||||
|
[paren "restrict" pattern_name]
|
||||||
|
] []
|
||||||
|
|
||||||
|
let main = O.name_hierarchy pattern_name "P" [
|
||||||
|
[record] ;
|
||||||
|
[type_annotation] ;
|
||||||
|
[pair] ;
|
||||||
|
[data_structure] ;
|
||||||
|
[application] ;
|
||||||
|
[variable ; constructor ; module_ident ; unit] ;
|
||||||
|
[paren "paren" pattern_name]
|
||||||
|
] []
|
||||||
|
|
||||||
|
let singletons = [O.rule_singleton record_element]
|
||||||
|
end
|
||||||
|
|
||||||
|
module Expression = struct
|
||||||
|
|
||||||
|
open Token
|
||||||
|
open O
|
||||||
|
|
||||||
|
let application = empty_infix "application" `Right
|
||||||
|
|
||||||
|
let type_annotation = make_name "type_annotation" [
|
||||||
|
`Current ; `Token COLON ; `Named restricted_type_expression_name
|
||||||
|
]
|
||||||
|
|
||||||
|
let data_structure : O.n_operator = make_name "data_structure" [
|
||||||
|
`Named variable_name ; `Token LSQUARE ; `List (Trail SEMICOLON, `Current) ; `Token RSQUARE ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let fun_ : O.n_operator = make_name "fun" [
|
||||||
|
`Token FUN ; `Named pattern_name ;
|
||||||
|
`Token ARROW ; `Current ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let let_in : O.n_operator = make_name "let_in" [
|
||||||
|
`Token LET ; `Named pattern_name ;
|
||||||
|
`Token EQUAL ; `Current ;
|
||||||
|
`Token IN ; `Current ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let no_seq_name = "expression_no_seq"
|
||||||
|
let no_match_name = "expression_no_match"
|
||||||
|
|
||||||
|
let record_element : O.rule = make_name "e_record_element" [
|
||||||
|
make_name "record_explicit" [`Named variable_name ; `Token EQUAL ; `Named no_seq_name] ;
|
||||||
|
make_name "record_implicit" [`Named variable_name ] ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let record : O.n_operator = make_name "record" [
|
||||||
|
`Token LBRACKET ;
|
||||||
|
`List (Trail SEMICOLON, `Named record_element.name) ;
|
||||||
|
`Token RBRACKET ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let ite : O.n_operator = make_name "ifthenelse" [
|
||||||
|
`Token IF ;
|
||||||
|
`Current ;
|
||||||
|
`Token THEN ;
|
||||||
|
`Lower ;
|
||||||
|
`Token ELSE ;
|
||||||
|
`Current ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let it : O.n_operator = make_name "ifthen" [
|
||||||
|
`Token IF ;
|
||||||
|
`Current ;
|
||||||
|
`Token THEN ;
|
||||||
|
`Lower ;
|
||||||
|
]
|
||||||
|
|
||||||
|
(* let sequence = infix "sequence" `Left SEMICOLON *)
|
||||||
|
let sequence = make_name "sequence" [
|
||||||
|
`List (Separated_nene SEMICOLON , `Lower)
|
||||||
|
]
|
||||||
|
|
||||||
|
let match_clause = make_name "e_match_clause" [
|
||||||
|
make_name "" [`Named pattern_name ; `Token ARROW ; `Named no_match_name]
|
||||||
|
]
|
||||||
|
let match_with = make_name "match" [
|
||||||
|
`Token MATCH ; `Current ; `Token WITH ;
|
||||||
|
`List (Lead_ne VBAR, `Named match_clause.name) ;
|
||||||
|
]
|
||||||
|
let lt = infix "lt" `Left LT
|
||||||
|
let le = infix "le" `Left LE
|
||||||
|
let gt = infix "gt" `Left GT
|
||||||
|
let eq = infix "eq" `Left EQUAL
|
||||||
|
let neq = infix "neq" `Left UNEQUAL
|
||||||
|
|
||||||
|
let cons = infix "cons" `Left DOUBLE_COLON
|
||||||
|
|
||||||
|
let addition = infix "addition" `Left PLUS
|
||||||
|
let substraction = infix "substraction" `Left MINUS
|
||||||
|
|
||||||
|
let multiplication = infix "multiplication" `Left TIMES
|
||||||
|
let division = infix "division" `Left DIV
|
||||||
|
|
||||||
|
let arith_variable : O.n_operator = make_name "variable" [ `Named variable_name ]
|
||||||
|
let int : O.n_operator = make_name "int" [ `Named int_name ]
|
||||||
|
let tz : O.n_operator = make_name "tz" [ `Named tz_name ]
|
||||||
|
let unit : O.n_operator = make_name "unit" [ `Named unit_name ]
|
||||||
|
let string : O.n_operator = make_name "string" [ `Named string_name ]
|
||||||
|
let constructor : O.n_operator = make_name "constructor" [ `Named constructor_name ]
|
||||||
|
|
||||||
|
let module_ident : O.n_operator = make_name "module_ident" [
|
||||||
|
`List (Trail_force_ne DOT, `Named constructor_name) ; `Named variable_name ;
|
||||||
|
]
|
||||||
|
let access : O.n_operator = infix "access" `Right DOT
|
||||||
|
let accessor : O.n_operator = make_name "accessor" [
|
||||||
|
`Named variable_name ; `List (Lead_ne DOT, `Named variable_name) ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let assignment : O.n_operator = infix "assign" `Left LEFT_ARROW
|
||||||
|
|
||||||
|
let tuple = make_name "tuple" [
|
||||||
|
`List (Separated_nene COMMA, `Lower)
|
||||||
|
]
|
||||||
|
|
||||||
|
let name = make_name "name" [`Token TILDE ; `Current]
|
||||||
|
|
||||||
|
let main_hierarchy_name = "expression_main"
|
||||||
|
|
||||||
|
let main_hierarchy = O.name_hierarchy main_hierarchy_name "Eh" [
|
||||||
|
[tuple] ;
|
||||||
|
[type_annotation] ;
|
||||||
|
[lt ; le ; gt ; eq ; neq] ;
|
||||||
|
[assignment] ;
|
||||||
|
[cons] ;
|
||||||
|
[addition ; substraction] ;
|
||||||
|
[multiplication ; division] ;
|
||||||
|
[application] ;
|
||||||
|
[data_structure] ;
|
||||||
|
[name] ;
|
||||||
|
[arith_variable ; constructor ; module_ident ; accessor ; int ; unit ; string ; tz] ;
|
||||||
|
[paren "bottom" expression_name] ;
|
||||||
|
] []
|
||||||
|
|
||||||
|
let no_sequence_expression = O.name_hierarchy no_seq_name "Es" [
|
||||||
|
[let_in ; fun_ ; record ; ite ; it ; match_with] ;
|
||||||
|
[make_name "main" [`Named main_hierarchy_name]] ;
|
||||||
|
] []
|
||||||
|
|
||||||
|
let no_match_expression = O.name_hierarchy no_match_name "Em" [
|
||||||
|
[let_in ; fun_ ; record ; ite ; it ] ;
|
||||||
|
[make_name "main" [`Named main_hierarchy_name]] ;
|
||||||
|
] []
|
||||||
|
|
||||||
|
let expression = O.name_hierarchy expression_name "E" [
|
||||||
|
[sequence] ;
|
||||||
|
[let_in ; fun_ ; record ; ite ; it ; match_with] ;
|
||||||
|
[make_name "main" [`Named main_hierarchy_name]] ;
|
||||||
|
] []
|
||||||
|
|
||||||
|
let singletons = List.map O.rule_singleton [record_element ; match_clause]
|
||||||
|
end
|
||||||
|
|
||||||
|
module Type_expression = struct
|
||||||
|
|
||||||
|
open Token
|
||||||
|
open O
|
||||||
|
|
||||||
|
let record_element : O.rule = make_name "t_record_element" [
|
||||||
|
make_name "" [`Named variable_name ; `Token COLON ; `Named type_expression_name]
|
||||||
|
]
|
||||||
|
|
||||||
|
let record : O.n_operator = make_name "record" [
|
||||||
|
`Token LBRACKET ;
|
||||||
|
`List (Trail SEMICOLON, `Named record_element.name) ;
|
||||||
|
`Token RBRACKET ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let application = empty_infix "application" `Right
|
||||||
|
|
||||||
|
let tuple = make_name "tuple" [
|
||||||
|
`List (Separated_nene COMMA, `Lower)
|
||||||
|
]
|
||||||
|
|
||||||
|
let type_variable : O.n_operator = make_name "variable" [ `Named variable_name ]
|
||||||
|
|
||||||
|
let restricted_type_expression = O.name_hierarchy restricted_type_expression_name "Tr" [
|
||||||
|
[application] ;
|
||||||
|
[type_variable] ;
|
||||||
|
[paren "paren" type_expression_name] ;
|
||||||
|
] []
|
||||||
|
|
||||||
|
let type_expression = O.name_hierarchy type_expression_name "T" [
|
||||||
|
[record] ;
|
||||||
|
[tuple] ;
|
||||||
|
[application] ;
|
||||||
|
[type_variable] ;
|
||||||
|
[paren "paren" type_expression_name]
|
||||||
|
] []
|
||||||
|
|
||||||
|
let singletons = [O.rule_singleton record_element]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Program = struct
|
||||||
|
|
||||||
|
open Token
|
||||||
|
open O
|
||||||
|
|
||||||
|
let statement_name = "statement"
|
||||||
|
|
||||||
|
let program : O.rule = make_name program_name [make_name "" [
|
||||||
|
`List (Trail_option DOUBLE_SEMICOLON, statement_name)
|
||||||
|
]]
|
||||||
|
|
||||||
|
let param_name = "param"
|
||||||
|
|
||||||
|
let param : O.rule = make_name param_name [
|
||||||
|
make_name "restricted_pattern" [ `Named Pattern.restricted_pattern_name ] ;
|
||||||
|
make_name "implicit_named_param" [ `Token TILDE ; `Named variable_name ] ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let type_annotation_name = "type_annotation_"
|
||||||
|
let type_annotation : O.rule = make_name type_annotation_name [
|
||||||
|
make_name "" [ `Token COLON ; `Named type_expression_name ] ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let let_content_name = "let_content"
|
||||||
|
let let_content : O.rule = make_name let_content_name [
|
||||||
|
make_name "" [
|
||||||
|
`Named variable_name ;
|
||||||
|
`List (Naked, param_name) ;
|
||||||
|
`Option type_annotation_name ;
|
||||||
|
`Token EQUAL ;
|
||||||
|
`Named expression_name ;
|
||||||
|
] ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let statement : O.rule = make_name statement_name [
|
||||||
|
make_name "variable_declaration" [`Token LET ; `Named let_content_name] ;
|
||||||
|
make_name "init_declaration" [`Token LET_INIT ; `Named let_content_name] ;
|
||||||
|
make_name "entry_declaration" [`Token LET_ENTRY ; `Named let_content_name] ;
|
||||||
|
make_name "type_declaration" [`Token TYPE ; `Named variable_name ; `Token EQUAL ; `Named type_expression_name] ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let singletons = List.map O.rule_singleton [
|
||||||
|
let_content ;
|
||||||
|
type_annotation ;
|
||||||
|
program ;
|
||||||
|
statement ;
|
||||||
|
param ;
|
||||||
|
]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
let language = O.language program_name (
|
||||||
|
variable :: constructor :: int :: unit :: string :: tz ::
|
||||||
|
Program.singletons @
|
||||||
|
Pattern.singletons @
|
||||||
|
Expression.singletons @
|
||||||
|
Type_expression.singletons
|
||||||
|
) [
|
||||||
|
Pattern.main ;
|
||||||
|
Pattern.restricted_pattern ;
|
||||||
|
Expression.main_hierarchy ;
|
||||||
|
Expression.no_sequence_expression ;
|
||||||
|
Expression.no_match_expression ;
|
||||||
|
Expression.expression ;
|
||||||
|
Type_expression.restricted_type_expression ;
|
||||||
|
Type_expression.type_expression ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let argn = Array.length Sys.argv in
|
||||||
|
if argn = 1 then exit 1 ;
|
||||||
|
let arg = Sys.argv.(1) in
|
||||||
|
match arg with
|
||||||
|
| "parser" -> (
|
||||||
|
Format.printf "%a@.%a\n" PP_helpers.comment "Full Grammar" Print_Grammar.language language
|
||||||
|
)
|
||||||
|
| "ast" -> (
|
||||||
|
Format.printf "%a@.%a\n" PP_helpers.comment "AST" Print_AST.language language
|
||||||
|
)
|
||||||
|
| _ -> exit 1
|
||||||
|
|
54
parser/camligo/lex/dune
Normal file
54
parser/camligo/lex/dune
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
(library
|
||||||
|
(name lex)
|
||||||
|
(public_name ligo.multifix.lex)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
)
|
||||||
|
(modules token token_type lexer)
|
||||||
|
)
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name generator)
|
||||||
|
(libraries
|
||||||
|
str
|
||||||
|
simple-utils
|
||||||
|
)
|
||||||
|
(modules generator)
|
||||||
|
(flags (:standard -w +1..62-4-9-44-40-42-48@39@33 ))
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets token.mly)
|
||||||
|
(deps generator.exe)
|
||||||
|
(action (system "./generator.exe mly > token.mly"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets token.ml)
|
||||||
|
(deps generator.exe)
|
||||||
|
(action (system "./generator.exe ml > token.ml"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets lexer.mll)
|
||||||
|
(deps generator.exe)
|
||||||
|
(action (system "./generator.exe mll > lexer.mll"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets token_type.ml token_type.mli)
|
||||||
|
(deps token.mly)
|
||||||
|
(action (system "menhir --only-tokens token.mly --base token_type"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(alias
|
||||||
|
(name lexer.mll)
|
||||||
|
(deps token.ml)
|
||||||
|
)
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets lexer.ml)
|
||||||
|
(deps token.ml lexer.mll)
|
||||||
|
(action (system "ocamllex lexer.mll"))
|
||||||
|
)
|
185
parser/camligo/lex/generator.ml
Normal file
185
parser/camligo/lex/generator.ml
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
type pre_token = {
|
||||||
|
name : string ;
|
||||||
|
pattern : string ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let make name pattern = { name ; pattern }
|
||||||
|
|
||||||
|
let keyword = fun k ->
|
||||||
|
let regexp = Str.regexp "[^0-9a-zA-Z]" in
|
||||||
|
let constructor_name =
|
||||||
|
Str.global_replace regexp "_"
|
||||||
|
@@ String.uppercase_ascii k
|
||||||
|
in
|
||||||
|
make constructor_name k
|
||||||
|
let symbol = fun sym name -> make name sym
|
||||||
|
|
||||||
|
module Print_mly = struct
|
||||||
|
open Format
|
||||||
|
|
||||||
|
let token = fun ppf pre_token ->
|
||||||
|
fprintf ppf "%%token %s" pre_token.name
|
||||||
|
|
||||||
|
let tokens = fun ppf tokens ->
|
||||||
|
let open Simple_utils.PP_helpers in
|
||||||
|
fprintf ppf "%%token EOF\n" ;
|
||||||
|
fprintf ppf "%%token <int> INT\n" ;
|
||||||
|
fprintf ppf "%%token <int> NAT\n" ;
|
||||||
|
fprintf ppf "%%token <int> TZ\n" ;
|
||||||
|
fprintf ppf "%%token <string> STRING\n" ;
|
||||||
|
fprintf ppf "%%token <string> NAME\n" ;
|
||||||
|
fprintf ppf "%%token <string> CONSTRUCTOR_NAME\n" ;
|
||||||
|
fprintf ppf "\n%a\n\n" (list_sep token (const "\n")) tokens ;
|
||||||
|
fprintf ppf "%%%%\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
module Print_mll = struct
|
||||||
|
open Format
|
||||||
|
|
||||||
|
let token = fun ppf {name;pattern} ->
|
||||||
|
fprintf ppf "| \"%s\" { %s }" pattern name
|
||||||
|
|
||||||
|
let pre =
|
||||||
|
{pre|{
|
||||||
|
open Token
|
||||||
|
|
||||||
|
exception Error of string
|
||||||
|
exception Unexpected_character of string
|
||||||
|
}
|
||||||
|
|
||||||
|
(* This rule analyzes a single line and turns it into a stream of
|
||||||
|
tokens. *)
|
||||||
|
|
||||||
|
rule token = parse
|
||||||
|
(*
|
||||||
|
| "//" ([^ '\n']* ) (['\n' '\r']+)
|
||||||
|
{ Lexing.new_line lexbuf ; token lexbuf }
|
||||||
|
*)
|
||||||
|
| ('\r'? '\n' '\r'?)
|
||||||
|
{ Lexing.new_line lexbuf; token lexbuf }
|
||||||
|
| '"' { string "" lexbuf }
|
||||||
|
| [' ' '\t']
|
||||||
|
{ token lexbuf }
|
||||||
|
| (['0'-'9']+ as i) 'p'
|
||||||
|
{ NAT (int_of_string i) }
|
||||||
|
| (['0'-'9']+ as n) '.' (['0'-'9']['0'-'9'] as d) "tz" { TZ ((int_of_string n) * 100 + (int_of_string d)) }
|
||||||
|
| (['0'-'9']+ as i)
|
||||||
|
{ INT (int_of_string i) }
|
||||||
|
|pre}
|
||||||
|
let post =
|
||||||
|
{post|
|
||||||
|
| (['a'-'z''_']['a'-'z''A'-'Z''0'-'9''_']*) as v
|
||||||
|
{ NAME v }
|
||||||
|
| (['A'-'Z']['a'-'z''A'-'Z''0'-'9''_']*) as v
|
||||||
|
{ CONSTRUCTOR_NAME v }
|
||||||
|
| eof { EOF }
|
||||||
|
| "(*" { comment 1 lexbuf }
|
||||||
|
| _
|
||||||
|
{ raise (Unexpected_character (Printf.sprintf "At offset %d: unexpected character.\n" (Lexing.lexeme_start lexbuf))) }
|
||||||
|
|
||||||
|
and string s = parse
|
||||||
|
| "\\\"" { string (s ^ "\"") lexbuf }
|
||||||
|
| "\\\\" { string (s ^ "\\") lexbuf }
|
||||||
|
| '"' { STRING s }
|
||||||
|
| eof { raise (Unexpected_character "missing string terminator") }
|
||||||
|
| _ as c { string (s ^ (String.make 1 c)) lexbuf }
|
||||||
|
|
||||||
|
|
||||||
|
and comment n = parse
|
||||||
|
| "*)" { if n = 1 then token lexbuf else comment (n - 1) lexbuf }
|
||||||
|
| "(*" { comment (n + 1) lexbuf }
|
||||||
|
| '"' ( [^ '"' '\\'] | ( '\\' [^ '"'] ) ) '"' { comment n lexbuf }
|
||||||
|
| eof { raise (Unexpected_character "missing comment terminator") }
|
||||||
|
| ('\r'? '\n' '\r'?) { Lexing.new_line lexbuf; comment n lexbuf }
|
||||||
|
| _ { comment n lexbuf }
|
||||||
|
|
||||||
|
|post}
|
||||||
|
let tokens = fun ppf tokens ->
|
||||||
|
let open Simple_utils.PP_helpers in
|
||||||
|
fprintf ppf "%s%a\n%s" pre (list_sep token (const "\n")) tokens post
|
||||||
|
end
|
||||||
|
|
||||||
|
module Print_ml = struct
|
||||||
|
open Format
|
||||||
|
|
||||||
|
let token = fun ppf {name} ->
|
||||||
|
fprintf ppf " | %s -> \"%s\"" name name
|
||||||
|
|
||||||
|
let pre =
|
||||||
|
{pre|include Token_type
|
||||||
|
|
||||||
|
let to_string : token -> string = function
|
||||||
|
| STRING _ -> "STRING"
|
||||||
|
| NAME _ -> "NAME s"
|
||||||
|
| CONSTRUCTOR_NAME _ -> "CONSTRUCTOR_NAME s"
|
||||||
|
| INT _ -> "INT n"
|
||||||
|
| NAT _ -> "NAT n"
|
||||||
|
| TZ _ -> "TZ n"
|
||||||
|
| EOF -> "EOF"
|
||||||
|
|pre}
|
||||||
|
|
||||||
|
let tokens = fun ppf tokens ->
|
||||||
|
let open Simple_utils.PP_helpers in
|
||||||
|
fprintf ppf "%s%a" pre (list_sep token (const "\n")) tokens
|
||||||
|
end
|
||||||
|
|
||||||
|
let tokens = [
|
||||||
|
keyword "let%init" ;
|
||||||
|
keyword "let%entry" ;
|
||||||
|
keyword "let" ;
|
||||||
|
keyword "type" ;
|
||||||
|
keyword "in" ;
|
||||||
|
keyword "if" ;
|
||||||
|
keyword "then" ;
|
||||||
|
keyword "else" ;
|
||||||
|
(* keyword "block" ;
|
||||||
|
* keyword "for" ;
|
||||||
|
* keyword "const" ; *)
|
||||||
|
keyword "fun" ;
|
||||||
|
keyword "match" ;
|
||||||
|
keyword "with" ;
|
||||||
|
symbol "()" "UNIT" ;
|
||||||
|
symbol "+" "PLUS" ;
|
||||||
|
symbol "~" "TILDE" ;
|
||||||
|
symbol "->" "ARROW" ;
|
||||||
|
symbol "<-" "LEFT_ARROW" ;
|
||||||
|
symbol "<=" "LE" ;
|
||||||
|
symbol "<>" "UNEQUAL" ;
|
||||||
|
symbol "<" "LT" ;
|
||||||
|
symbol ">" "GT" ;
|
||||||
|
symbol "-" "MINUS" ;
|
||||||
|
symbol "*" "TIMES" ;
|
||||||
|
symbol "/" "DIV" ;
|
||||||
|
symbol "=" "EQUAL" ;
|
||||||
|
symbol "|" "VBAR" ;
|
||||||
|
symbol "[" "LSQUARE" ;
|
||||||
|
symbol "]" "RSQUARE" ;
|
||||||
|
symbol "(" "LPAREN" ;
|
||||||
|
symbol ")" "RPAREN" ;
|
||||||
|
symbol "{" "LBRACKET" ;
|
||||||
|
symbol "}" "RBRACKET" ;
|
||||||
|
symbol ";;" "DOUBLE_SEMICOLON" ;
|
||||||
|
symbol ";" "SEMICOLON" ;
|
||||||
|
symbol "::" "DOUBLE_COLON" ;
|
||||||
|
symbol ":" "COLON" ;
|
||||||
|
symbol "," "COMMA" ;
|
||||||
|
symbol "." "DOT" ;
|
||||||
|
]
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let argn = Array.length Sys.argv in
|
||||||
|
if argn = 1 then exit 1 ;
|
||||||
|
let arg = Sys.argv.(1) in
|
||||||
|
let open Simple_utils.PP_helpers in
|
||||||
|
match arg with
|
||||||
|
| "mll" -> (
|
||||||
|
Format.printf "%a@.%a\n" comment "Generated .mll" Print_mll.tokens tokens
|
||||||
|
)
|
||||||
|
| "mly" -> (
|
||||||
|
Format.printf "%a@.%a\n" comment "Generated .mly" Print_mly.tokens tokens
|
||||||
|
)
|
||||||
|
| "ml" -> (
|
||||||
|
Format.printf "%a@.%a\n" comment "Generated .ml" Print_ml.tokens tokens
|
||||||
|
)
|
||||||
|
| _ -> exit 1
|
||||||
|
|
25
parser/camligo/location.ml
Normal file
25
parser/camligo/location.ml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
type file_location = {
|
||||||
|
filename : string ;
|
||||||
|
start_line : int ;
|
||||||
|
start_column : int ;
|
||||||
|
end_line : int ;
|
||||||
|
end_column : int ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type virtual_location = string
|
||||||
|
|
||||||
|
type t =
|
||||||
|
| File of file_location
|
||||||
|
| Virtual of virtual_location
|
||||||
|
|
||||||
|
let make (start_pos:Lexing.position) (end_pos:Lexing.position) : t =
|
||||||
|
let filename = start_pos.pos_fname in
|
||||||
|
let start_line = start_pos.pos_lnum in
|
||||||
|
let end_line = end_pos.pos_lnum in
|
||||||
|
let start_column = start_pos.pos_cnum - start_pos.pos_bol in
|
||||||
|
let end_column = end_pos.pos_cnum - end_pos.pos_bol in
|
||||||
|
File { filename ; start_line ; start_column ; end_line ; end_column }
|
||||||
|
|
||||||
|
let virtual_location s = Virtual s
|
||||||
|
let dummy = virtual_location "dummy"
|
||||||
|
|
3
parser/camligo/parser_camligo.ml
Normal file
3
parser/camligo/parser_camligo.ml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module Ast = Ast
|
||||||
|
module Parser = Parser
|
||||||
|
module User = User
|
72
parser/camligo/pre_parser.mly
Normal file
72
parser/camligo/pre_parser.mly
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
%{
|
||||||
|
open Ast
|
||||||
|
%}
|
||||||
|
|
||||||
|
%start <Ast.entry_point> entry_point
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
naked_list(X):
|
||||||
|
| { [] }
|
||||||
|
| x = X xs = naked_list(X) { x :: xs }
|
||||||
|
|
||||||
|
naked_list_ne(X):
|
||||||
|
| x = X { [ x ] }
|
||||||
|
| x = X xs = naked_list_ne(X) { x :: xs }
|
||||||
|
|
||||||
|
trail_list(separator, X):
|
||||||
|
| { [] }
|
||||||
|
| trail_list_content(separator, X) { $1 }
|
||||||
|
|
||||||
|
trail_list_content(separator, X):
|
||||||
|
| x = trail_list_last(separator, X) { x }
|
||||||
|
| x = X separator xs = trail_list_content(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
trail_list_last(separator, X):
|
||||||
|
| x = X option(separator) { [ x ] }
|
||||||
|
|
||||||
|
trail_force_list(separator, X):
|
||||||
|
| { [] }
|
||||||
|
| x = X separator xs = trail_force_list(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
trail_force_list_ne(separator, X):
|
||||||
|
| x = X separator { [ x ] }
|
||||||
|
| x = X separator xs = trail_force_list_ne(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
trail_option_list(separator, X):
|
||||||
|
| { [] }
|
||||||
|
| trail_option_list_content(separator, X) { $1 }
|
||||||
|
|
||||||
|
trail_option_list_content(separator, X):
|
||||||
|
| x = trail_option_list_last(separator, X) { x }
|
||||||
|
| x = X option(separator) xs = trail_option_list_content(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
trail_option_list_last(separator, X):
|
||||||
|
| x = X option(separator) { [ x ] }
|
||||||
|
|
||||||
|
lead_list_ne(separator, X):
|
||||||
|
| separator x = X { [x] }
|
||||||
|
| separator x = X xs = lead_list_ne(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
lead_list(separator, X):
|
||||||
|
| { [] }
|
||||||
|
| lead_list_content(separator, X) { $1 }
|
||||||
|
|
||||||
|
lead_list_content(separator, X):
|
||||||
|
| x = lead_list_first(separator, X) { x }
|
||||||
|
| xs = lead_list_content(separator, X) separator x = X { xs @ [ x ] }
|
||||||
|
|
||||||
|
lead_list_first (separator, X):
|
||||||
|
| option(separator) x = X { [ x ] }
|
||||||
|
|
||||||
|
separated_list_ne(separator, X):
|
||||||
|
| x = X { [x] }
|
||||||
|
| x = X separator xs = separated_list_ne(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
separated_list_nene(separator, X):
|
||||||
|
| x = X separator y = X { [x ; y] }
|
||||||
|
| x = X separator xs = separated_list_nene(separator, X) { x :: xs }
|
||||||
|
|
||||||
|
|
||||||
|
%inline wrap(X):
|
||||||
|
| x = X { let loc = Location.make $startpos $endpos in Location.wrap ~loc x }
|
40
parser/camligo/user.ml
Normal file
40
parser/camligo/user.ml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
open! Trace
|
||||||
|
|
||||||
|
let parse_file (source: string) : Ast.entry_point result =
|
||||||
|
(* let pp_input =
|
||||||
|
* let prefix = Filename.(source |> basename |> remove_extension)
|
||||||
|
* and suffix = ".pp.ligo"
|
||||||
|
* in prefix ^ suffix in
|
||||||
|
*
|
||||||
|
* let cpp_cmd = Printf.sprintf "cpp -traditional-cpp %s > %s"
|
||||||
|
* source pp_input in
|
||||||
|
* let%bind () = sys_command cpp_cmd in
|
||||||
|
*
|
||||||
|
* let%bind channel =
|
||||||
|
* generic_try (simple_error "error opening file") @@
|
||||||
|
* (fun () -> open_in pp_input) in *)
|
||||||
|
let%bind channel =
|
||||||
|
generic_try (simple_error "error opening file") @@
|
||||||
|
(fun () -> open_in source) in
|
||||||
|
let lexbuf = Lexing.from_channel channel in
|
||||||
|
let module Lexer = Lex.Lexer in
|
||||||
|
(specific_try (fun () -> fun e ->
|
||||||
|
let error s () =
|
||||||
|
let start = Lexing.lexeme_start_p lexbuf in
|
||||||
|
let end_ = Lexing.lexeme_end_p lexbuf in
|
||||||
|
let str () = Format.sprintf
|
||||||
|
"at \"%s\" from (%d, %d) to (%d, %d)\n"
|
||||||
|
(Lexing.lexeme lexbuf)
|
||||||
|
start.pos_lnum (start.pos_cnum - start.pos_bol)
|
||||||
|
end_.pos_lnum (end_.pos_cnum - end_.pos_bol) in
|
||||||
|
error s str () in
|
||||||
|
match e with
|
||||||
|
| Parser.Error -> (fun () -> error (thunk "Parse") ())
|
||||||
|
| Lexer.Error s -> (fun () -> error (fun () -> "Lexer " ^ s) ())
|
||||||
|
| Lexer.Unexpected_character s -> error (fun () -> "Unexpected char " ^ s) (* TODO: this allows injection of ANSI escape codes in error messages, fix this. *)
|
||||||
|
| _ -> simple_error "unrecognized parse_ error"
|
||||||
|
)) @@ (fun () ->
|
||||||
|
let raw = Parser.entry_point Lexer.token lexbuf in
|
||||||
|
raw
|
||||||
|
) >>? fun raw ->
|
||||||
|
ok raw
|
14
parser/dune
Normal file
14
parser/dune
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
(library
|
||||||
|
(name parser)
|
||||||
|
(public_name ligo.parser)
|
||||||
|
(libraries
|
||||||
|
simple-utils
|
||||||
|
tezos-utils
|
||||||
|
parser_pascaligo
|
||||||
|
parser_camligo
|
||||||
|
)
|
||||||
|
(preprocess
|
||||||
|
(pps simple-utils.ppx_let_generalized)
|
||||||
|
)
|
||||||
|
(flags (:standard -open Simple_utils ))
|
||||||
|
)
|
116
parser/parser.ml
Normal file
116
parser/parser.ml
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
open Trace
|
||||||
|
|
||||||
|
module Pascaligo = Parser_pascaligo
|
||||||
|
module Camligo = Parser_camligo
|
||||||
|
|
||||||
|
open Parser_pascaligo
|
||||||
|
module AST_Raw = Parser_pascaligo.AST
|
||||||
|
|
||||||
|
|
||||||
|
let parse_file (source: string) : AST_Raw.t result =
|
||||||
|
let pp_input =
|
||||||
|
let prefix = Filename.(source |> basename |> remove_extension)
|
||||||
|
and suffix = ".pp.ligo"
|
||||||
|
in prefix ^ suffix in
|
||||||
|
|
||||||
|
let cpp_cmd = Printf.sprintf "cpp -traditional-cpp %s > %s"
|
||||||
|
source pp_input in
|
||||||
|
let%bind () = sys_command cpp_cmd in
|
||||||
|
|
||||||
|
let%bind channel =
|
||||||
|
generic_try (simple_error "error opening file") @@
|
||||||
|
(fun () -> open_in pp_input) in
|
||||||
|
let lexbuf = Lexing.from_channel channel in
|
||||||
|
let module Lexer = Lexer.Make(LexToken) in
|
||||||
|
let Lexer.{read ; close} =
|
||||||
|
Lexer.open_token_stream None in
|
||||||
|
specific_try (fun () -> function
|
||||||
|
| Parser.Error -> (
|
||||||
|
let start = Lexing.lexeme_start_p lexbuf in
|
||||||
|
let end_ = Lexing.lexeme_end_p lexbuf in
|
||||||
|
let str = Format.sprintf
|
||||||
|
"Parse error at \"%s\" from (%d, %d) to (%d, %d). In file \"%s|%s\"\n"
|
||||||
|
(Lexing.lexeme lexbuf)
|
||||||
|
start.pos_lnum (start.pos_cnum - start.pos_bol)
|
||||||
|
end_.pos_lnum (end_.pos_cnum - end_.pos_bol)
|
||||||
|
start.pos_fname source
|
||||||
|
in
|
||||||
|
simple_error str
|
||||||
|
)
|
||||||
|
| exn ->
|
||||||
|
let start = Lexing.lexeme_start_p lexbuf in
|
||||||
|
let end_ = Lexing.lexeme_end_p lexbuf in
|
||||||
|
let str = Format.sprintf
|
||||||
|
"Unrecognized error (%s) at \"%s\" from (%d, %d) to (%d, %d). In file \"%s|%s\"\n"
|
||||||
|
(Printexc.to_string exn)
|
||||||
|
(Lexing.lexeme lexbuf)
|
||||||
|
start.pos_lnum (start.pos_cnum - start.pos_bol)
|
||||||
|
end_.pos_lnum (end_.pos_cnum - end_.pos_bol)
|
||||||
|
start.pos_fname source
|
||||||
|
in
|
||||||
|
simple_error str
|
||||||
|
) @@ (fun () ->
|
||||||
|
let raw = Parser.contract read lexbuf in
|
||||||
|
close () ;
|
||||||
|
raw
|
||||||
|
) >>? fun raw ->
|
||||||
|
ok raw
|
||||||
|
|
||||||
|
let parse_string (s:string) : AST_Raw.t result =
|
||||||
|
let lexbuf = Lexing.from_string s in
|
||||||
|
let module Lexer = Lexer.Make(LexToken) in
|
||||||
|
let Lexer.{read ; close} =
|
||||||
|
Lexer.open_token_stream None in
|
||||||
|
specific_try (fun () -> function
|
||||||
|
| Parser.Error -> (
|
||||||
|
let start = Lexing.lexeme_start_p lexbuf in
|
||||||
|
let end_ = Lexing.lexeme_end_p lexbuf in
|
||||||
|
let str = Format.sprintf
|
||||||
|
"Parse error at \"%s\" from (%d, %d) to (%d, %d)\n"
|
||||||
|
(Lexing.lexeme lexbuf)
|
||||||
|
start.pos_lnum (start.pos_cnum - start.pos_bol)
|
||||||
|
end_.pos_lnum (end_.pos_cnum - end_.pos_bol) in
|
||||||
|
simple_error str
|
||||||
|
)
|
||||||
|
| _ -> simple_error "unrecognized parse_ error"
|
||||||
|
) @@ (fun () ->
|
||||||
|
let raw = Parser.contract read lexbuf in
|
||||||
|
close () ;
|
||||||
|
raw
|
||||||
|
) >>? fun raw ->
|
||||||
|
ok raw
|
||||||
|
|
||||||
|
let parse_expression (s:string) : AST_Raw.expr result =
|
||||||
|
let lexbuf = Lexing.from_string s in
|
||||||
|
let module Lexer = Lexer.Make(LexToken) in
|
||||||
|
let Lexer.{read ; close} =
|
||||||
|
Lexer.open_token_stream None in
|
||||||
|
specific_try (fun () -> function
|
||||||
|
| Parser.Error -> (
|
||||||
|
let start = Lexing.lexeme_start_p lexbuf in
|
||||||
|
let end_ = Lexing.lexeme_end_p lexbuf in
|
||||||
|
let str = Format.sprintf
|
||||||
|
"Parse error at \"%s\" from (%d, %d) to (%d, %d)\n"
|
||||||
|
(Lexing.lexeme lexbuf)
|
||||||
|
start.pos_lnum (start.pos_cnum - start.pos_bol)
|
||||||
|
end_.pos_lnum (end_.pos_cnum - end_.pos_bol) in
|
||||||
|
simple_error str
|
||||||
|
)
|
||||||
|
| exn ->
|
||||||
|
let start = Lexing.lexeme_start_p lexbuf in
|
||||||
|
let end_ = Lexing.lexeme_end_p lexbuf in
|
||||||
|
let str = Format.sprintf
|
||||||
|
"Unrecognized error (%s) at \"%s\" from (%d, %d) to (%d, %d). In expression \"%s|%s\"\n"
|
||||||
|
(Printexc.to_string exn)
|
||||||
|
(Lexing.lexeme lexbuf)
|
||||||
|
start.pos_lnum (start.pos_cnum - start.pos_bol)
|
||||||
|
end_.pos_lnum (end_.pos_cnum - end_.pos_bol)
|
||||||
|
start.pos_fname s
|
||||||
|
in
|
||||||
|
simple_error str
|
||||||
|
) @@ (fun () ->
|
||||||
|
let raw = Parser.interactive_expr read lexbuf in
|
||||||
|
close () ;
|
||||||
|
raw
|
||||||
|
) >>? fun raw ->
|
||||||
|
ok raw
|
1
parser/pascaligo/.Lexer.ml.tag
Normal file
1
parser/pascaligo/.Lexer.ml.tag
Normal file
@ -0,0 +1 @@
|
|||||||
|
ocamlc: -w -42
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user