diff --git a/.gitignore b/.gitignore index ced532fda..9053b2cbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ /_build/ dune-project *~ +*.merlin cache/* Version.ml /_opam/ +/*.pp.ligo **/.DS_Store \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fd988aca4..1fa3cd9ec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,9 +50,6 @@ stages: services: - docker:dind -.docker_build: &docker_build - script: - - docker build -t $LIGO_REGISTRY_IMAGE:next -f ./docker/Dockerfile . .before_script: &before_script before_script: @@ -74,17 +71,6 @@ local-dune-job: - scripts/build_ligo_local.sh - dune build @ligo-test -# TODO: uncomment this - -# TODO -# local-repo-job: -# <<: *before_script -# stage: test -# script: -# - scripts/install_vendors_deps.sh -# # TODO: also try from time to time with --build-test -# - opam install -y ligo - remote-repo-job: <<: *before_script stage: test @@ -107,7 +93,9 @@ remote-repo-job: build-current-docker-image: stage: build_docker <<: *docker - <<: *docker_build + script: + - docker build -t $LIGO_REGISTRY_IMAGE:next -f ./docker/Dockerfile . + - sh scripts/test_cli.sh except: - master - dev @@ -117,8 +105,9 @@ build-current-docker-image: build-and-publish-latest-docker-image: stage: build_and_deploy_docker <<: *docker - <<: *docker_build - after_script: + script: + - docker build -t $LIGO_REGISTRY_IMAGE:next -f ./docker/Dockerfile . + - sh scripts/test_cli.sh - docker login -u $LIGO_REGISTRY_USER -p $LIGO_REGISTRY_PASSWORD - docker push $LIGO_REGISTRY_IMAGE:next only: diff --git a/gitlab-pages/website/pages/en/versions.js b/gitlab-pages/website/pages/en/versions.js index 4cc1bd3b5..6abeaa02e 100644 --- a/gitlab-pages/website/pages/en/versions.js +++ b/gitlab-pages/website/pages/en/versions.js @@ -18,15 +18,13 @@ const versions = require(`${CWD}/versions.json`); function Versions(props) { const {config: siteConfig} = props; const latestVersion = versions[0]; - const repoUrl = `https://github.com/${siteConfig.organizationName}/${ - siteConfig.projectName - }`; + const repoUrl = `${siteConfig.repoUrl}`; return (
-

{siteConfig.title} Versions

+

{siteConfig.title} Versions

Current version

diff --git a/scripts/ligo_ci.sh b/scripts/ligo_ci.sh new file mode 100755 index 000000000..a39da5873 --- /dev/null +++ b/scripts/ligo_ci.sh @@ -0,0 +1 @@ +docker run -i -v "$PWD":"$PWD" -w "$PWD" ligolang/ligo:next "$@" \ No newline at end of file diff --git a/scripts/test_cli.sh b/scripts/test_cli.sh new file mode 100755 index 000000000..ad83f2e64 --- /dev/null +++ b/scripts/test_cli.sh @@ -0,0 +1,29 @@ +#!/bin/sh +set -e +compiled_contract=$(./scripts/ligo_ci.sh compile-contract src/test/contracts/website2.ligo main); +compiled_storage=$(./scripts/ligo_ci.sh compile-storage src/test/contracts/website2.ligo main 1); +compiled_parameter=$(./scripts/ligo_ci.sh compile-parameter src/test/contracts/website2.ligo main "Increment(1)"); +dry_run_output=$(./scripts/ligo_ci.sh dry-run src/test/contracts/website2.ligo main "Increment(1)" 1); + +expected_compiled_parameter="(Right 1)"; +expected_compiled_storage=1; +expected_dry_run_output="tuple[ list[] + 2 +]"; + +if [ "$compiled_storage" != "$expected_compiled_storage" ]; then + echo "Expected $expected_compiled_storage as compile-storage output, got $compiled_storage instead"; + exit 1; +fi + +if [ "$compiled_parameter" != "$expected_compiled_parameter" ]; then + echo "Expected $expected_compiled_parameter as compile-parameter output, got $compiled_parameter instead"; + exit 1; +fi + +if [ "$dry_run_output" != "$expected_dry_run_output" ]; then + echo "Expected $expected_dry_run_output as dry-run output, got $dry_run_output instead"; + exit 1; +fi + +echo "CLI tests passed"; diff --git a/src/bin/cli.ml b/src/bin/cli.ml index 11777b504..31e9261ab 100644 --- a/src/bin/cli.ml +++ b/src/bin/cli.ml @@ -37,6 +37,14 @@ let syntax = info ~docv ~doc ["syntax" ; "s"] in value @@ opt string "auto" info +let bigmap = + let open Arg in + let info = + let docv = "BIGMAP" in + let doc = "$(docv) is necessary when your storage embeds a big_map." in + info ~docv ~doc ["bigmap"] in + value @@ flag info + let amount = let open Arg in let info = @@ -45,98 +53,124 @@ let amount = info ~docv ~doc ["amount"] in value @@ opt string "0" info +let display_format = + let open Arg in + let info = + let docv = "DISPLAY_FORMAT" in + let doc = "$(docv) is the format that will be used by the CLI. Available formats are 'dev', 'json', and 'human-readable' (default). When human-readable lacks details (we are still tweaking it), please contact us and use another format in the meanwhile." in + info ~docv ~doc ["format" ; "display-format"] in + value @@ opt string "human-readable" info + +let michelson_code_format = + let open Arg in + let info = + let docv = "MICHELSON_FORMAT" in + let doc = "$(docv) is the format that will be used by compile-contract for the resulting Michelson. Available formats are 'micheline', and 'michelson' (default). Micheline is the format used by [XXX]." in + info ~docv ~doc ["michelson-format"] in + value @@ opt string "michelson" info + let compile_file = - let f source entry_point syntax = - toplevel @@ + let f source entry_point syntax display_format michelson_format = + toplevel ~display_format @@ + let%bind michelson_format = Main.Display.michelson_format_of_string michelson_format in let%bind contract = trace (simple_info "compiling contract to michelson") @@ - Ligo.Run.compile_contract_file source entry_point (Syntax_name syntax) in - Format.printf "%s\n" contract ; - ok () + Ligo.Compile.Of_source.compile_file_contract_entry source entry_point (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" (Main.Display.michelson_pp michelson_format) contract in let term = - Term.(const f $ source 0 $ entry_point 1 $ syntax) in + Term.(const f $ source 0 $ entry_point 1 $ syntax $ display_format $ michelson_code_format) in let cmdname = "compile-contract" in let docs = "Subcommand: compile a contract. See `ligo " ^ cmdname ^ " --help' for a list of options specific to this subcommand." in (term , Term.info ~docs cmdname) let compile_parameter = - let f source entry_point expression syntax = - toplevel @@ + let f source entry_point expression syntax display_format = + toplevel ~display_format @@ let%bind value = trace (simple_error "compile-input") @@ - Ligo.Run.compile_contract_parameter source entry_point expression (Syntax_name syntax) in - Format.printf "%s\n" value; - ok () + Ligo.Run.Of_source.compile_file_contract_parameter source entry_point expression (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" Tezos_utils.Michelson.pp value in let term = - Term.(const f $ source 0 $ entry_point 1 $ expression "PARAMETER" 2 $ syntax) in + Term.(const f $ source 0 $ entry_point 1 $ expression "PARAMETER" 2 $ syntax $ display_format) in let cmdname = "compile-parameter" in let docs = "Subcommand: compile parameters to a michelson expression. The resulting michelson expression can be passed as an argument in a transaction which calls a contract. See `ligo " ^ cmdname ^ " --help' for a list of options specific to this subcommand." in (term , Term.info ~docs cmdname) let compile_storage = - let f source entry_point expression syntax = - toplevel @@ + let f source entry_point expression syntax display_format bigmap = + toplevel ~display_format @@ let%bind value = trace (simple_error "compile-storage") @@ - Ligo.Run.compile_contract_storage source entry_point expression (Syntax_name syntax) in - Format.printf "%s\n" value; - ok () + Ligo.Run.Of_source.compile_file_contract_storage ~value:bigmap source entry_point expression (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" Tezos_utils.Michelson.pp value in let term = - Term.(const f $ source 0 $ entry_point 1 $ expression "STORAGE" 2 $ syntax) in + Term.(const f $ source 0 $ entry_point 1 $ expression "STORAGE" 2 $ syntax $ display_format $ bigmap) in let cmdname = "compile-storage" in let docs = "Subcommand: compile an initial storage in ligo syntax to a michelson expression. The resulting michelson expression can be passed as an argument in a transaction which originates a contract. See `ligo " ^ cmdname ^ " --help' for a list of options specific to this subcommand." in (term , Term.info ~docs cmdname) let dry_run = - let f source entry_point storage input amount syntax = - toplevel @@ + let f source entry_point storage input amount syntax display_format bigmap = + toplevel ~display_format @@ let%bind output = - Ligo.Run.run_contract ~amount source entry_point storage input (Syntax_name syntax) in - Format.printf "%a\n" Ast_simplified.PP.expression output ; - ok () + Ligo.Run.Of_source.run_contract ~amount ~storage_value:bigmap source entry_point storage input (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" Ast_simplified.PP.expression output in let term = - Term.(const f $ source 0 $ entry_point 1 $ expression "PARAMETER" 2 $ expression "STORAGE" 3 $ amount $ syntax) in + Term.(const f $ source 0 $ entry_point 1 $ expression "PARAMETER" 2 $ expression "STORAGE" 3 $ amount $ syntax $ display_format $ bigmap) in let cmdname = "dry-run" in let docs = "Subcommand: run a smart-contract with the given storage and input." in (term , Term.info ~docs cmdname) let run_function = - let f source entry_point parameter amount syntax = - toplevel @@ + let f source entry_point parameter amount syntax display_format = + toplevel ~display_format @@ let%bind output = - Ligo.Run.run_function ~amount source entry_point parameter (Syntax_name syntax) in - Format.printf "%a\n" Ast_simplified.PP.expression output ; - ok () + Ligo.Run.Of_source.run_function_entry ~amount source entry_point parameter (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" Ast_simplified.PP.expression output in let term = - Term.(const f $ source 0 $ entry_point 1 $ expression "PARAMETER" 2 $ amount $ syntax) in + Term.(const f $ source 0 $ entry_point 1 $ expression "PARAMETER" 2 $ amount $ syntax $ display_format) in let cmdname = "run-function" in let docs = "Subcommand: run a function with the given parameter." in (term , Term.info ~docs cmdname) let evaluate_value = - let f source entry_point amount syntax = - toplevel @@ + let f source entry_point amount syntax display_format = + toplevel ~display_format @@ let%bind output = - Ligo.Run.evaluate_value ~amount source entry_point (Syntax_name syntax) in - Format.printf "%a\n" Ast_simplified.PP.expression output ; - ok () + Ligo.Run.Of_source.evaluate_entry ~amount source entry_point (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" Ast_simplified.PP.expression output in let term = - Term.(const f $ source 0 $ entry_point 1 $ amount $ syntax) in + Term.(const f $ source 0 $ entry_point 1 $ amount $ syntax $ display_format) in let cmdname = "evaluate-value" in let docs = "Subcommand: evaluate a given definition." in (term , Term.info ~docs cmdname) +let compile_expression = + let f expression syntax display_format = + toplevel ~display_format @@ + let%bind value = + trace (simple_error "compile-input") @@ + Ligo.Run.Of_source.compile_expression expression (Syntax_name syntax) in + ok @@ Format.asprintf "%a\n" Tezos_utils.Michelson.pp value + in + let term = + Term.(const f $ expression "" 0 $ syntax $ display_format) in + let cmdname = "compile-expression" in + let docs = "Subcommand: compile to a michelson value." in + (term , Term.info ~docs cmdname) + let () = Term.exit @@ Term.eval_choice main [ compile_file ; compile_parameter ; compile_storage ; + compile_expression ; dry_run ; run_function ; evaluate_value ; diff --git a/src/bin/cli_helpers.ml b/src/bin/cli_helpers.ml index 068f2bf1d..7057e0975 100644 --- a/src/bin/cli_helpers.ml +++ b/src/bin/cli_helpers.ml @@ -1,9 +1,16 @@ open Trace +open Main.Display -let toplevel x = +let toplevel ~(display_format : string) (x : string result) = + let display_format = + try display_format_of_string display_format + with _ -> ( + Format.printf "bad display format %s, try looking at DISPLAY_FORMAT in the man (--help)." display_format ; + failwith "Display format" + ) + in match x with - | Trace.Ok ((), annotations) -> ignore annotations; () - | Error ss -> ( - Format.printf "%a%!" Ligo.Display.error_pp (ss ()) - ) - + | Ok _ -> Format.printf "%a\n%!" (formatted_string_result_pp display_format) x + | Error _ -> + Format.eprintf "%a\n%!" (formatted_string_result_pp display_format) x ; + exit 1 diff --git a/src/contracts/annotation.ligo b/src/contracts/annotation.ligo deleted file mode 100644 index 1cae3ffe9..000000000 --- a/src/contracts/annotation.ligo +++ /dev/null @@ -1,5 +0,0 @@ -const lst : list(int) = list [] ; - -const address : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ; - -const address_2 : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ; diff --git a/src/contracts/closure-3.ligo b/src/contracts/closure-3.ligo deleted file mode 100644 index 71fb67269..000000000 --- a/src/contracts/closure-3.ligo +++ /dev/null @@ -1,6 +0,0 @@ -function foobar(const i : int) : int is - const j : int = 3 ; - const k : int = 4 ; - function toto(const l : int) : int is - block { skip } with i + j + k + l; - block { skip } with toto(42) diff --git a/src/contracts/error_type.ligo b/src/contracts/error_type.ligo deleted file mode 100644 index 79e114388..000000000 --- a/src/contracts/error_type.ligo +++ /dev/null @@ -1 +0,0 @@ -const foo : nat = 42 + "bar" \ No newline at end of file diff --git a/src/contracts/included.ligo b/src/contracts/included.ligo deleted file mode 100644 index 3f0a2d1ca..000000000 --- a/src/contracts/included.ligo +++ /dev/null @@ -1 +0,0 @@ -const foo : int = 144 diff --git a/src/contracts/includer.ligo b/src/contracts/includer.ligo deleted file mode 100644 index e68975796..000000000 --- a/src/contracts/includer.ligo +++ /dev/null @@ -1,3 +0,0 @@ -#include "included.ligo" - -const bar : int = foo diff --git a/src/contracts/list.mligo b/src/contracts/list.mligo deleted file mode 100644 index 31e2f7d50..000000000 --- a/src/contracts/list.mligo +++ /dev/null @@ -1,10 +0,0 @@ -type storage = int * int list - -type param = int list - -let%entry main (p : param) storage = - let storage = - match p with - [] -> storage - | hd::tl -> storage.(0) + hd, tl - in (([] : operation list), storage) diff --git a/src/contracts/set_arithmetic-1.ligo b/src/contracts/set_arithmetic-1.ligo deleted file mode 100644 index 2397f72b5..000000000 --- a/src/contracts/set_arithmetic-1.ligo +++ /dev/null @@ -1,9 +0,0 @@ -function iter_op (const s : set(int)) : int is - var r : int := 0 ; - function aggregate (const i : int) : unit is - begin - r := r + i ; - end with unit - begin - set_iter(s , aggregate) ; - end with r diff --git a/src/dune b/src/dune index c2f58b54f..de5be01e6 100644 --- a/src/dune +++ b/src/dune @@ -12,20 +12,3 @@ (pps ppx_let) ) ) - -(alias - (name ligo-test) - (action (run test/test.exe)) - (deps (glob_files contracts/*)) -) - -(alias - (name runtest) - (deps (alias ligo-test)) -) - -(alias - (name manual-test) - (action (run test/manual_test.exe)) - (deps (glob_files contracts/*)) -) diff --git a/src/main/compile/dune b/src/main/compile/dune new file mode 100644 index 000000000..705ed50b9 --- /dev/null +++ b/src/main/compile/dune @@ -0,0 +1,22 @@ +(library + (name compile) + (public_name ligo.compile) + (libraries + simple-utils + tezos-utils + parser + simplify + ast_simplified + self_ast_simplified + typer + ast_typed + transpiler + mini_c + compiler + self_michelson + ) + (preprocess + (pps ppx_let) + ) + (flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils -open Tezos_utils )) +) diff --git a/src/main/compile/helpers.ml b/src/main/compile/helpers.ml new file mode 100644 index 000000000..663c989e7 --- /dev/null +++ b/src/main/compile/helpers.ml @@ -0,0 +1,76 @@ +open Trace + +type s_syntax = Syntax_name of string +type v_syntax = Pascaligo | Cameligo + +let syntax_to_variant : s_syntax -> string option -> v_syntax result = + fun syntax source_filename -> + let subr s n = + String.sub s (String.length s - n) n in + let endswith s suffix = + let suffixlen = String.length suffix in + ( String.length s >= suffixlen + && String.equal (subr s suffixlen) suffix) + in + let (Syntax_name syntax) = syntax in + match (syntax , source_filename) with + | "auto" , Some sf when endswith sf ".ligo" -> ok Pascaligo + | "auto" , Some sf when endswith sf ".mligo" -> ok Cameligo + | "auto" , _ -> simple_fail "cannot auto-detect syntax, pleas use -s name_of_syntax" + | "pascaligo" , _ -> ok Pascaligo + | "cameligo" , _ -> ok Cameligo + | _ -> simple_fail "unrecognized parser" + +let parsify_pascaligo = fun source -> + let%bind raw = + trace (simple_error "parsing") @@ + Parser.Pascaligo.parse_file source in + let%bind simplified = + trace (simple_error "simplifying") @@ + Simplify.Pascaligo.simpl_program raw in + ok simplified + +let parsify_expression_pascaligo = fun source -> + let%bind raw = + trace (simple_error "parsing expression") @@ + Parser.Pascaligo.parse_expression source in + let%bind simplified = + trace (simple_error "simplifying expression") @@ + Simplify.Pascaligo.simpl_expression raw in + ok simplified + +let parsify_ligodity = fun source -> + let%bind raw = + trace (simple_error "parsing") @@ + Parser.Ligodity.parse_file source in + let%bind simplified = + trace (simple_error "simplifying") @@ + Simplify.Ligodity.simpl_program raw in + ok simplified + +let parsify_expression_ligodity = fun source -> + let%bind raw = + trace (simple_error "parsing expression") @@ + Parser.Ligodity.parse_expression source in + let%bind simplified = + trace (simple_error "simplifying expression") @@ + Simplify.Ligodity.simpl_expression raw in + ok simplified + +let parsify = fun (syntax : v_syntax) source_filename -> + let%bind parsify = match syntax with + | Pascaligo -> ok parsify_pascaligo + | Cameligo -> ok parsify_ligodity + in + let%bind parsified = parsify source_filename in + let%bind applied = Self_ast_simplified.all_program parsified in + ok applied + +let parsify_expression = fun syntax source -> + let%bind parsify = match syntax with + | Pascaligo -> ok parsify_expression_pascaligo + | Cameligo -> ok parsify_expression_ligodity + in + let%bind parsified = parsify source in + let%bind applied = Self_ast_simplified.all_expression parsified in + ok applied diff --git a/src/main/compile/of_mini_c.ml b/src/main/compile/of_mini_c.ml new file mode 100644 index 000000000..296e4d814 --- /dev/null +++ b/src/main/compile/of_mini_c.ml @@ -0,0 +1,56 @@ +open Trace +open Mini_c +open Tezos_utils + +let compile_value : value -> type_value -> Michelson.t result = fun x a -> + let%bind body = Compiler.Program.translate_value x a in + let body = Self_michelson.optimize body in + ok body + +let compile_expression_as_value : expression -> _ result = fun e -> + let%bind value = expression_to_value e in + let%bind result = compile_value value e.type_value in + let result = Self_michelson.optimize result in + ok result + +let compile_expression_as_function : expression -> _ result = fun e -> + let (input , output) = t_unit , e.type_value in + let%bind body = Compiler.Program.translate_expression e Compiler.Environment.empty in + let body = Self_michelson.optimize body in + let body = Michelson.(seq [ i_drop ; body ]) in + let%bind (input , output) = bind_map_pair Compiler.Type.Ty.type_ (input , output) in + let open! Compiler.Program in + ok { input ; output ; body } + +let compile_function = fun e -> + let%bind (input , output) = get_t_function e.type_value in + let%bind body = get_function e in + let%bind body = compile_value body (t_function input output) in + let body = Self_michelson.optimize body in + let%bind (input , output) = bind_map_pair Compiler.Type.Ty.type_ (input , output) in + let open! Compiler.Program in + ok { input ; output ; body } + +let compile_expression_as_function_entry = fun program name -> + let%bind aggregated = aggregate_entry program name true in + compile_function aggregated + +let compile_function_entry = fun program name -> + let%bind aggregated = aggregate_entry program name false in + compile_function aggregated + +let compile_contract_entry = fun program name -> + let%bind aggregated = aggregate_entry program name false in + let%bind compiled = compile_function aggregated in + let%bind (param_ty , storage_ty) = + let%bind fun_ty = get_t_function aggregated.type_value in + Mini_c.get_t_pair (fst fun_ty) + 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.body in + ok contract + + +let uncompile_value : Proto_alpha_utils.Memory_proto_alpha.X.ex_typed_value -> value result = fun x -> + Compiler.Uncompiler.translate_value x diff --git a/src/main/compile/of_simplified.ml b/src/main/compile/of_simplified.ml new file mode 100644 index 000000000..cf8bc00fd --- /dev/null +++ b/src/main/compile/of_simplified.ml @@ -0,0 +1,40 @@ +open Ast_simplified +open Trace +open Tezos_utils + +let compile_contract_entry (program : program) entry_point = + let%bind prog_typed = Typer.type_program program in + Of_typed.compile_contract_entry prog_typed entry_point + +let compile_function_entry (program : program) entry_point : _ result = + let%bind prog_typed = Typer.type_program program in + Of_typed.compile_function_entry prog_typed entry_point + +let compile_expression_as_function_entry (program : program) entry_point : _ result = + let%bind typed_program = Typer.type_program program in + Of_typed.compile_expression_as_function_entry typed_program entry_point + +let compile_expression_as_value ?(env = Ast_typed.Environment.full_empty) ae : Michelson.t result = + let%bind typed = Typer.type_expression env ae in + Of_typed.compile_expression_as_value typed + +let compile_expression_as_function ?(env = Ast_typed.Environment.full_empty) ae : _ result = + let%bind typed = Typer.type_expression env ae in + Of_typed.compile_expression_as_function typed + +let uncompile_typed_program_entry_expression_result program entry ex_ty_value = + let%bind output_type = + let%bind entry_expression = Ast_typed.get_entry program entry in + ok entry_expression.type_annotation + in + let%bind typed = Of_typed.uncompile_value ex_ty_value output_type in + Typer.untype_expression typed + +let uncompile_typed_program_entry_function_result program entry ex_ty_value = + let%bind output_type = + let%bind entry_expression = Ast_typed.get_entry program entry in + let%bind (_ , output_type) = Ast_typed.get_t_function entry_expression.type_annotation in + ok output_type + in + let%bind typed = Of_typed.uncompile_value ex_ty_value output_type in + Typer.untype_expression typed diff --git a/src/main/compile/of_source.ml b/src/main/compile/of_source.ml new file mode 100644 index 000000000..f7576ec19 --- /dev/null +++ b/src/main/compile/of_source.ml @@ -0,0 +1,39 @@ +open Trace +open Helpers + +let parse_file_program source_filename syntax = + let%bind syntax = syntax_to_variant syntax (Some source_filename) in + let%bind simplified = parsify syntax source_filename in + ok simplified + +let compile_file_entry : string -> string -> s_syntax -> _ result = + fun source_filename entry_point syntax -> + let%bind simplified = parse_file_program source_filename syntax in + Of_simplified.compile_function_entry simplified entry_point + +let compile_file_contract_entry : string -> string -> s_syntax -> _ result = + fun source_filename entry_point syntax -> + let%bind simplified = parse_file_program source_filename syntax in + let%bind compiled_contract = Of_simplified.compile_contract_entry simplified entry_point in + ok compiled_contract + +let compile_expression_as_function : string -> s_syntax -> _ result = + fun expression syntax -> + let%bind syntax = syntax_to_variant syntax None in + let%bind simplified = parsify_expression syntax expression in + Of_simplified.compile_expression_as_function simplified + +let type_file ?(debug_simplify = false) ?(debug_typed = false) + syntax (source_filename:string) : Ast_typed.program result = + let%bind syntax = syntax_to_variant syntax (Some source_filename) in + let%bind simpl = parsify syntax source_filename in + (if debug_simplify then + Format.(printf "Simplified : %a\n%!" Ast_simplified.PP.program simpl) + ) ; + let%bind typed = + trace (simple_error "typing") @@ + Typer.type_program simpl in + (if debug_typed then ( + Format.(printf "Typed : %a\n%!" Ast_typed.PP.program typed) + )) ; + ok typed diff --git a/src/main/compile/of_typed.ml b/src/main/compile/of_typed.ml new file mode 100644 index 000000000..79ca90040 --- /dev/null +++ b/src/main/compile/of_typed.ml @@ -0,0 +1,57 @@ +open Trace +open Ast_typed +open Tezos_utils + + +let compile_expression_as_value : annotated_expression -> Michelson.t result = fun e -> + let%bind mini_c_expression = Transpiler.transpile_annotated_expression e in + let%bind expr = Of_mini_c.compile_expression_as_value mini_c_expression in + ok expr + +let compile_expression_as_function : annotated_expression -> _ result = fun e -> + let%bind mini_c_expression = Transpiler.transpile_annotated_expression e in + let%bind expr = Of_mini_c.compile_expression_as_function mini_c_expression in + ok expr + +let compile_function : annotated_expression -> _ result = fun e -> + let%bind mini_c_expression = Transpiler.transpile_annotated_expression e in + let%bind expr = Of_mini_c.compile_function mini_c_expression in + ok expr + +(* + val compile_value : annotated_expression -> Michelson.t result + This requires writing a function + `transpile_expression_as_value : annotated_expression -> Mini_c.value result` + *) + +let compile_function_entry : program -> string -> _ = fun p entry -> + let%bind prog_mini_c = Transpiler.transpile_program p in + Of_mini_c.compile_function_entry prog_mini_c entry + +let compile_contract_entry : program -> string -> _ = fun p entry -> + let%bind prog_mini_c = Transpiler.transpile_program p in + Of_mini_c.compile_contract_entry prog_mini_c entry + +let compile_expression_as_function_entry : program -> string -> _ = fun p entry -> + let%bind prog_mini_c = Transpiler.transpile_program p in + Of_mini_c.compile_expression_as_function_entry prog_mini_c entry + +let uncompile_value : _ -> _ -> annotated_expression result = fun x ty -> + let%bind mini_c = Of_mini_c.uncompile_value x in + let%bind typed = Transpiler.untranspile mini_c ty in + ok typed + +let uncompile_entry_function_result = fun program entry ex_ty_value -> + let%bind output_type = + let%bind entry_expression = get_entry program entry in + let%bind (_ , output_type) = get_t_function entry_expression.type_annotation in + ok output_type + in + uncompile_value ex_ty_value output_type + +let uncompile_entry_expression_result = fun program entry ex_ty_value -> + let%bind output_type = + let%bind entry_expression = get_entry program entry in + ok entry_expression.type_annotation + in + uncompile_value ex_ty_value output_type diff --git a/src/main/display.ml b/src/main/display.ml index ab35528cb..93eebbfe9 100644 --- a/src/main/display.ml +++ b/src/main/display.ml @@ -1,8 +1,6 @@ -open Trace +open! Trace -let dev = false - -let rec error_pp out (e : error) = +let rec error_pp ?(dev = false) out (e : error) = let open JSON_string_utils in let message = let opt = e |> member "message" |> string in @@ -50,7 +48,69 @@ let rec error_pp out (e : error) = print "%s%s%s%s%s" location title error_code message data ) else ( print "%s%s%s.\n%s%s\n%a\n%a\n" title error_code message data location - (Format.pp_print_list error_pp) infos - (Format.pp_print_list error_pp) children + (Format.pp_print_list (error_pp ~dev)) infos + (Format.pp_print_list (error_pp ~dev)) children ) +let result_pp_hr f out (r : _ result) = + match r with + | Ok (s , _) -> Format.fprintf out "%a" f s + | Error e -> Format.fprintf out "%a" (error_pp ~dev:false) (e ()) + +let string_result_pp_hr = result_pp_hr (fun out s -> Format.fprintf out "%s" s) + +let result_pp_dev f out (r : _ result) = + match r with + | Ok (s , _) -> Format.fprintf out "%a" f s + | Error e -> Format.fprintf out "%a" (error_pp ~dev:false) (e ()) + +let string_result_pp_dev = result_pp_hr (fun out s -> Format.fprintf out "%s" s) + +let json_pp out x = Format.fprintf out "%s" (J.to_string x) + +let string_result_pp_json out (r : string result) = + let status_json status content : J.t = `Assoc ([ + ("status" , `String status) ; + ("content" , content) ; + ]) in + match r with + | Ok (x , _) -> ( + Format.fprintf out "%a" json_pp (status_json "ok" (`String x)) + ) + | Error e -> ( + Format.fprintf out "%a" json_pp (status_json "error" (e ())) + ) + +type display_format = [ + | `Human_readable + | `Json + | `Dev +] + +let display_format_of_string = fun s : display_format -> + match s with + | "dev" -> `Dev + | "json" -> `Json + | "human-readable" -> `Human_readable + | _ -> failwith "bad display_format" + +let formatted_string_result_pp (display_format : display_format) = + match display_format with + | `Human_readable -> string_result_pp_hr + | `Dev -> string_result_pp_dev + | `Json -> string_result_pp_json + +type michelson_format = [ + | `Michelson + | `Micheline +] + +let michelson_format_of_string = fun s : michelson_format result -> + match s with + | "michelson" -> ok `Michelson + | "micheline" -> ok `Micheline + | _ -> simple_fail "bad michelson format" + +let michelson_pp (mf : michelson_format) = match mf with + | `Michelson -> Michelson.pp + | `Micheline -> Michelson.pp_json diff --git a/src/main/dune b/src/main/dune index 747afb217..f4bfd2efd 100644 --- a/src/main/dune +++ b/src/main/dune @@ -2,17 +2,8 @@ (name main) (public_name ligo.main) (libraries - simple-utils - tezos-utils - parser - simplify - ast_simplified - typer - ast_typed - transpiler - mini_c - operators - compiler + run + compile ) (preprocess (pps ppx_let) diff --git a/src/main/main.ml b/src/main/main.ml index 1c4afcd58..e5214bc31 100644 --- a/src/main/main.ml +++ b/src/main/main.ml @@ -1,137 +1,3 @@ -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 Run = struct - include Run_source - include Run_simplified - include Run_typed - include Run_mini_c -end - +module Run = Run +module Compile = Compile module Display = Display - -(* 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.expression result = Simplify.Pascaligo.simpl_expression e - * let unparse_simplified_expr (e:AST_Simplified.expression) : string result = - * ok @@ Format.asprintf "%a" AST_Simplified.PP.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.expression) : AST_Typed.annotated_expression result = - * Typer.type_expression env e - * let untype_expression (e:AST_Typed.annotated_expression) : AST_Simplified.expression result = Typer.untype_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 (e:AST_Typed.annotated_expression) : Mini_c.expression result = Transpiler.translate_annotated_expression e - * - * 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 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 = 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.expression) : Ast_simplified.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 (_ , (_ , post_env)) -> post_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 *) - - -(* module Contract = Contract *) diff --git a/src/main/run/dune b/src/main/run/dune new file mode 100644 index 000000000..34f7986af --- /dev/null +++ b/src/main/run/dune @@ -0,0 +1,22 @@ +(library + (name run) + (public_name ligo.run) + (libraries + simple-utils + tezos-utils + parser + simplify + ast_simplified + typer + ast_typed + transpiler + mini_c + operators + compiler + compile + ) + (preprocess + (pps ppx_let) + ) + (flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils -open Tezos_utils )) +) diff --git a/src/main/run/of_michelson.ml b/src/main/run/of_michelson.ml new file mode 100644 index 000000000..220bc26c2 --- /dev/null +++ b/src/main/run/of_michelson.ml @@ -0,0 +1,47 @@ +open Proto_alpha_utils +open Trace +open Compiler.Program +open Memory_proto_alpha.Protocol.Script_ir_translator +open Memory_proto_alpha.X + +type options = Memory_proto_alpha.options + +let run ?options (* ?(is_input_value = false) *) (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_ty_mich = + * Trace.trace_tzresult_lwt (simple_error "error unparsing input ty") @@ + * Memory_proto_alpha.unparse_michelson_ty input_ty in + * let%bind output_ty_mich = + * Trace.trace_tzresult_lwt (simple_error "error unparsing output ty") @@ + * Memory_proto_alpha.unparse_michelson_ty output_ty in + * Format.printf "code: %a\n" Michelson.pp program.body ; + * Format.printf "input_ty: %a\n" Michelson.pp input_ty_mich ; + * Format.printf "output_ty: %a\n" Michelson.pp output_ty_mich ; + * Format.printf "input: %a\n" Michelson.pp input_michelson ; *) + let%bind input = + Trace.trace_tzresult_lwt (simple_error "error parsing input") @@ + Memory_proto_alpha.parse_michelson_data input_michelson input_ty + in + let body = Michelson.(strip_nops @@ strip_annots body) in + let%bind descr = + Trace.trace_tzresult_lwt (simple_error "error parsing program code") @@ + Memory_proto_alpha.parse_michelson body + (Item_t (input_ty, Empty_t, None)) (Item_t (output_ty, Empty_t, None)) in + let open! Memory_proto_alpha.Protocol.Script_interpreter in + let%bind (Item(output, Empty)) = + Trace.trace_tzresult_lwt (simple_error "error of execution") @@ + Memory_proto_alpha.interpret ?options descr (Item(input, Empty)) in + ok (Ex_typed_value (output_ty, output)) + +let evaluate ?options program = run ?options program Michelson.d_unit + +let ex_value_ty_to_michelson (v : ex_typed_value) : Michelson.t result = + let (Ex_typed_value (value , ty)) = v in + Trace.trace_tzresult_lwt (simple_error "error unparsing michelson result") @@ + Memory_proto_alpha.unparse_michelson_data value ty + +let evaluate_michelson ?options program = + let%bind etv = evaluate ?options program in + ex_value_ty_to_michelson etv diff --git a/src/main/run/of_mini_c.ml b/src/main/run/of_mini_c.ml new file mode 100644 index 000000000..131bf4ac5 --- /dev/null +++ b/src/main/run/of_mini_c.ml @@ -0,0 +1,53 @@ +open Proto_alpha_utils +open Memory_proto_alpha.X +open Trace +open Mini_c +open! Compiler.Program + +module Errors = struct + + let entry_error = + simple_error "error translating entry point" + +end + +type options = { + entry_point : anon_function ; + input_type : type_value ; + output_type : type_value ; + input : value ; + michelson_options : Of_michelson.options ; +} + +let evaluate ?options expression = + let%bind code = Compile.Of_mini_c.compile_expression_as_function expression in + let%bind ex_ty_value = Of_michelson.evaluate ?options code in + Compile.Of_mini_c.uncompile_value ex_ty_value + +let evaluate_entry ?options program entry = + let%bind code = Compile.Of_mini_c.compile_expression_as_function_entry program entry in + let%bind ex_ty_value = Of_michelson.evaluate ?options code in + Compile.Of_mini_c.uncompile_value ex_ty_value + +let run_function ?options expression input ty = + let%bind code = Compile.Of_mini_c.compile_function expression in + let%bind input = Compile.Of_mini_c.compile_value input ty in + let%bind ex_ty_value = Of_michelson.run ?options code input in + Compile.Of_mini_c.uncompile_value ex_ty_value + +let run_function_value ?options expression input ty = + let%bind code = Compile.Of_mini_c.compile_function expression in + let%bind input = Compile.Of_mini_c.compile_value input ty in + let%bind ex_ty_value = Of_michelson.run ?options code input in + Compile.Of_mini_c.uncompile_value ex_ty_value + +let run_function_entry ?options program entry input = + let%bind code = Compile.Of_mini_c.compile_function_entry program entry in + let%bind input_michelson = + let%bind code = Compile.Of_mini_c.compile_expression_as_function input in + let%bind (Ex_typed_value (ty , value)) = Of_michelson.evaluate ?options code in + Trace.trace_tzresult_lwt (simple_error "error unparsing input") @@ + Memory_proto_alpha.unparse_michelson_data ty value + in + let%bind ex_ty_value = Of_michelson.run ?options code input_michelson in + Compile.Of_mini_c.uncompile_value ex_ty_value diff --git a/src/main/run/of_simplified.ml b/src/main/run/of_simplified.ml new file mode 100644 index 000000000..4bc7729b8 --- /dev/null +++ b/src/main/run/of_simplified.ml @@ -0,0 +1,32 @@ +open Trace +open Ast_simplified + +let compile_expression ?(value = false) ?env expr = + if value + then ( + Compile.Of_simplified.compile_expression_as_value ?env expr + ) + else ( + let%bind code = Compile.Of_simplified.compile_expression_as_function ?env expr in + Of_michelson.evaluate_michelson code + ) + +let run_typed_program + ?options ?input_to_value + (program : Ast_typed.program) (entry : string) + (input : expression) : expression result = + let%bind code = Compile.Of_typed.compile_function_entry program entry in + let%bind input = + let env = Ast_typed.program_environment program in + compile_expression ?value:input_to_value ~env input + in + let%bind ex_ty_value = Of_michelson.run ?options code input in + Compile.Of_simplified.uncompile_typed_program_entry_function_result program entry ex_ty_value + +let evaluate_typed_program_entry + ?options + (program : Ast_typed.program) (entry : string) + : Ast_simplified.expression result = + let%bind code = Compile.Of_typed.compile_expression_as_function_entry program entry in + let%bind ex_ty_value = Of_michelson.evaluate ?options code in + Compile.Of_simplified.uncompile_typed_program_entry_expression_result program entry ex_ty_value diff --git a/src/main/run/of_source.ml b/src/main/run/of_source.ml new file mode 100644 index 000000000..f9a8e776c --- /dev/null +++ b/src/main/run/of_source.ml @@ -0,0 +1,137 @@ +open Trace + +include struct + open Ast_simplified + + 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 (name , _ , _) -> name = 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 identical 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 + +(* open Tezos_utils *) + +let compile_file_contract_parameter : string -> string -> string -> Compile.Helpers.s_syntax -> Michelson.t result = + fun source_filename _entry_point expression syntax -> + let%bind program = Compile.Of_source.type_file syntax source_filename in + let env = Ast_typed.program_environment program in + let%bind syntax = Compile.Helpers.syntax_to_variant syntax (Some source_filename) in + let%bind simplified = Compile.Helpers.parsify_expression syntax expression in + Of_simplified.compile_expression simplified ~env + +let compile_file_expression : string -> string -> string -> Compile.Helpers.s_syntax -> Michelson.t result = + fun source_filename _entry_point expression syntax -> + let%bind program = Compile.Of_source.type_file syntax source_filename in + let env = Ast_typed.program_environment program in + let%bind syntax = Compile.Helpers.syntax_to_variant syntax (Some source_filename) in + let%bind simplified = Compile.Helpers.parsify_expression syntax expression in + Of_simplified.compile_expression simplified ~env + +let compile_expression : string -> Compile.Helpers.s_syntax -> Michelson.t result = + fun expression syntax -> + let%bind syntax = Compile.Helpers.syntax_to_variant syntax None in + let%bind simplified = Compile.Helpers.parsify_expression syntax expression in + Of_simplified.compile_expression simplified + +let compile_file_contract_storage ~value : string -> string -> string -> Compile.Helpers.s_syntax -> Michelson.t result = + fun source_filename _entry_point expression syntax -> + let%bind program = Compile.Of_source.type_file syntax source_filename in + let env = Ast_typed.program_environment program in + let%bind syntax = Compile.Helpers.syntax_to_variant syntax (Some source_filename) in + let%bind simplified = Compile.Helpers.parsify_expression syntax expression in + Of_simplified.compile_expression ~value simplified ~env + +let compile_file_contract_args = + fun ?value source_filename _entry_point storage parameter syntax -> + let%bind program = Compile.Of_source.type_file syntax source_filename in + let env = Ast_typed.program_environment program in + let%bind syntax = Compile.Helpers.syntax_to_variant syntax (Some source_filename) in + let%bind storage_simplified = Compile.Helpers.parsify_expression syntax storage in + let%bind parameter_simplified = Compile.Helpers.parsify_expression syntax parameter in + let args = Ast_simplified.e_pair storage_simplified parameter_simplified in + Of_simplified.compile_expression ?value args ~env + + +let run_contract ?amount ?storage_value source_filename entry_point storage parameter syntax = + let%bind program = Compile.Of_source.type_file syntax source_filename in + let%bind code = Compile.Of_typed.compile_function_entry program entry_point in + let%bind args = compile_file_contract_args ?value:storage_value source_filename entry_point storage parameter syntax in + let%bind ex_value_ty = + let options = + let open Proto_alpha_utils.Memory_proto_alpha in + let amount = Option.bind (fun amount -> Protocol.Alpha_context.Tez.of_string amount) amount in + (make_options ?amount ()) + in + Of_michelson.run ~options code args + in + Compile.Of_simplified.uncompile_typed_program_entry_function_result program entry_point ex_value_ty + +let run_function_entry ?amount source_filename entry_point input syntax = + let%bind program = Compile.Of_source.type_file syntax source_filename in + let%bind code = Compile.Of_typed.compile_function_entry program entry_point in + let%bind args = compile_file_expression source_filename entry_point input syntax in + let%bind ex_value_ty = + let options = + let open Proto_alpha_utils.Memory_proto_alpha in + let amount = Option.bind (fun amount -> Protocol.Alpha_context.Tez.of_string amount) amount in + (make_options ?amount ()) + in + Of_michelson.run ~options code args + in + Compile.Of_simplified.uncompile_typed_program_entry_function_result program entry_point ex_value_ty + +let evaluate_entry ?amount source_filename entry_point syntax = + let%bind program = Compile.Of_source.type_file syntax source_filename in + let%bind code = Compile.Of_typed.compile_expression_as_function_entry program entry_point in + let%bind ex_value_ty = + let options = + let open Proto_alpha_utils.Memory_proto_alpha in + let amount = Option.bind (fun amount -> Protocol.Alpha_context.Tez.of_string amount) amount in + (make_options ?amount ()) + in + Of_michelson.evaluate ~options code + in + Compile.Of_simplified.uncompile_typed_program_entry_expression_result program entry_point ex_value_ty + +let evaluate_michelson expression syntax = + let%bind code = Compile.Of_source.compile_expression_as_function expression syntax in + Of_michelson.evaluate_michelson code + + diff --git a/src/main/run/of_typed.ml b/src/main/run/of_typed.ml new file mode 100644 index 000000000..644e99d26 --- /dev/null +++ b/src/main/run/of_typed.ml @@ -0,0 +1,42 @@ +open Trace +open Ast_typed + +let compile_expression ?(value = false) expr = + if value + then ( + Compile.Of_typed.compile_expression_as_value expr + ) + else ( + let%bind code = Compile.Of_typed.compile_expression_as_function expr in + Of_michelson.evaluate_michelson code + ) + +let run_function ?options f input = + let%bind code = Compile.Of_typed.compile_function f in + let%bind input = compile_expression input in + let%bind ex_ty_value = Of_michelson.run ?options code input in + let%bind ty = + let%bind (_ , output_ty) = get_t_function f.type_annotation in + ok output_ty + in + Compile.Of_typed.uncompile_value ex_ty_value ty + +let run_entry + ?options (entry : string) + (program : Ast_typed.program) (input : Ast_typed.annotated_expression) : Ast_typed.annotated_expression result = + let%bind code = Compile.Of_typed.compile_function_entry program entry in + let%bind input = + compile_expression input + in + let%bind ex_ty_value = Of_michelson.run ?options code input in + Compile.Of_typed.uncompile_entry_function_result program entry ex_ty_value + +let evaluate ?options (e : annotated_expression) : annotated_expression result = + let%bind code = Compile.Of_typed.compile_expression_as_function e in + let%bind ex_ty_value = Of_michelson.evaluate ?options code in + Compile.Of_typed.uncompile_value ex_ty_value e.type_annotation + +let evaluate_entry ?options program entry = + let%bind code = Compile.Of_typed.compile_expression_as_function_entry program entry in + let%bind ex_ty_value = Of_michelson.evaluate ?options code in + Compile.Of_typed.uncompile_entry_expression_result program entry ex_ty_value diff --git a/src/main/run/run.ml b/src/main/run/run.ml new file mode 100644 index 000000000..2436e3455 --- /dev/null +++ b/src/main/run/run.ml @@ -0,0 +1,5 @@ +module Of_source = Of_source +module Of_typed = Of_typed +module Of_simplified = Of_simplified +module Of_mini_c = Of_mini_c +module Of_michelson = Of_michelson diff --git a/src/main/run_mini_c.ml b/src/main/run_mini_c.ml deleted file mode 100644 index d13b4cc54..000000000 --- a/src/main/run_mini_c.ml +++ /dev/null @@ -1,55 +0,0 @@ -open Proto_alpha_utils -open Trace -open Mini_c -open! Compiler.Program -open Memory_proto_alpha.Protocol.Script_ir_translator -open Memory_proto_alpha.X - -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") @@ - 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") @@ - Memory_proto_alpha.parse_michelson body - (Item_t (input_ty, Empty_t, None)) (Item_t (output_ty, Empty_t, None)) in - let open! Memory_proto_alpha.Protocol.Script_interpreter in - let%bind (Item(output, Empty)) = - Trace.trace_tzresult_lwt (simple_error "error of execution") @@ - Memory_proto_alpha.interpret ?options descr (Item(input, Empty)) in - ok (Ex_typed_value (output_ty, output)) - -let run_entry ?(debug_michelson = false) ?options (entry:anon_function) ty (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 ty in - let%bind input_michelson = translate_value input (fst ty) in - if debug_michelson then ( - Format.printf "Program: %a\n" Michelson.pp compiled.body ; - Format.printf "Expression: %a\n" PP.expression entry.result ; - Format.printf "Input: %a\n" PP.value input ; - Format.printf "Input Type: %a\n" PP.type_ (fst ty) ; - Format.printf "Compiled Input: %a\n" Michelson.pp input_michelson ; - ) ; - let%bind ex_ty_value = run_aux ?options compiled input_michelson in - if debug_michelson then ( - let (Ex_typed_value (ty , v)) = ex_ty_value in - ignore @@ - let%bind michelson_value = - trace_tzresult_lwt (simple_error "debugging run_mini_c") @@ - Proto_alpha_utils.Memory_proto_alpha.unparse_michelson_data ty v in - Format.printf "Compiled Output: %a\n" Michelson.pp michelson_value ; - ok () - ) ; - let%bind (result : value) = Compiler.Uncompiler.translate_value ex_ty_value in - ok result diff --git a/src/main/run_simplified.ml b/src/main/run_simplified.ml deleted file mode 100644 index 4faf34aaf..000000000 --- a/src/main/run_simplified.ml +++ /dev/null @@ -1,27 +0,0 @@ -open Trace - -let run_simplityped - ?options - ?(debug_mini_c = false) ?(debug_michelson = false) - (program : Ast_typed.program) (entry : string) - (input : Ast_simplified.expression) : Ast_simplified.expression result = - let%bind typed_input = - let env = - let last_declaration = Location.unwrap List.(hd @@ rev program) in - match last_declaration with - | Declaration_constant (_ , (_ , post_env)) -> post_env - in - Typer.type_expression env input in - let%bind typed_result = - Run_typed.run_typed ?options ~debug_mini_c ~debug_michelson entry program typed_input in - let%bind annotated_result = Typer.untype_expression typed_result in - ok annotated_result - -let evaluate_simplityped - ?options - ?(debug_mini_c = false) ?(debug_michelson = false) - (program : Ast_typed.program) (entry : string) - : Ast_simplified.expression result = - let%bind typed_result = Run_typed.evaluate_typed ?options ~debug_mini_c ~debug_michelson entry program in - let%bind annotated_result = Typer.untype_expression typed_result in - ok annotated_result diff --git a/src/main/run_source.ml b/src/main/run_source.ml deleted file mode 100644 index 10904914a..000000000 --- a/src/main/run_source.ml +++ /dev/null @@ -1,286 +0,0 @@ -open Trace - -include struct - open Ast_simplified - - 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 (name , _ , _) -> name = 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 , ty) = - let open Transpiler in - let (f , _) = functionalize e in - let%bind main = translate_main f e.location in - ok main - in - - let input = Mini_c.Combinators.d_unit in - let%bind r = Run_mini_c.run_entry f ty input in - ok (r , snd ty) - -let parsify_pascaligo = fun source -> - let%bind raw = - trace (simple_error "parsing") @@ - Parser.Pascaligo.parse_file source in - let%bind simplified = - trace (simple_error "simplifying") @@ - Simplify.Pascaligo.simpl_program raw in - ok simplified - -let parsify_expression_pascaligo = fun source -> - let%bind raw = - trace (simple_error "parsing expression") @@ - Parser.Pascaligo.parse_expression source in - let%bind simplified = - trace (simple_error "simplifying expression") @@ - Simplify.Pascaligo.simpl_expression raw in - ok simplified - -let parsify_ligodity = fun source -> - let%bind raw = - trace (simple_error "parsing") @@ - Parser.Ligodity.parse_file source in - let%bind simplified = - trace (simple_error "simplifying") @@ - Simplify.Ligodity.simpl_program raw in - ok simplified - -let parsify_expression_ligodity = fun source -> - let%bind raw = - trace (simple_error "parsing expression") @@ - Parser.Ligodity.parse_expression source in - let%bind simplified = - trace (simple_error "simplifying expression") @@ - Simplify.Ligodity.simpl_expression raw in - ok simplified - -type s_syntax = Syntax_name of string -type v_syntax = [`pascaligo | `cameligo ] - -let syntax_to_variant : s_syntax -> string option -> v_syntax result = - fun syntax source_filename -> - let subr s n = - String.sub s (String.length s - n) n in - let endswith s suffix = - let suffixlen = String.length suffix in - ( String.length s >= suffixlen - && String.equal (subr s suffixlen) suffix) - in - match syntax with - Syntax_name syntax -> - begin - if String.equal syntax "auto" then - begin - match source_filename with - | Some source_filename - when endswith source_filename ".ligo" - -> ok `pascaligo - | Some source_filename - when endswith source_filename ".mligo" - -> ok `cameligo - | _ -> simple_fail "cannot auto-detect syntax, pleas use -s name_of_syntax" - end - else if String.equal syntax "pascaligo" then ok `pascaligo - else if String.equal syntax "cameligo" then ok `cameligo - else simple_fail "unrecognized parser" - end - -let parsify = fun (syntax : v_syntax) source_filename -> - let%bind parsify = match syntax with - | `pascaligo -> ok parsify_pascaligo - | `cameligo -> ok parsify_ligodity - in - parsify source_filename - -let parsify_expression = fun syntax source -> - let%bind parsify = match syntax with - | `pascaligo -> ok parsify_expression_pascaligo - | `cameligo -> ok parsify_expression_ligodity - in - parsify source - -let compile_contract_file : string -> string -> s_syntax -> string result = fun source_filename entry_point syntax -> - let%bind syntax = syntax_to_variant syntax (Some source_filename) in - let%bind simplified = parsify syntax source_filename 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 , mini_c_ty) = - trace (simple_error "transpiling") @@ - Transpiler.translate_entry typed entry_point in - let%bind michelson = - trace (simple_error "compiling") @@ - Compiler.translate_contract mini_c mini_c_ty in - let str = - Format.asprintf "%a" Michelson.pp_stripped michelson in - ok str - -let compile_contract_parameter : string -> string -> string -> s_syntax -> string result = fun source_filename entry_point expression syntax -> - let%bind syntax = syntax_to_variant syntax (Some source_filename) in - let%bind (program , parameter_tv) = - let%bind simplified = parsify syntax source_filename 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 typed = - let%bind simplified = parsify_expression syntax expression in - let env = - let last_declaration = Location.unwrap List.(hd @@ rev program) in - match last_declaration with - | Declaration_constant (_ , (_ , post_env)) -> post_env - in - trace (simple_error "typing expression") @@ - Typer.type_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 , mini_c_ty) = - trace (simple_error "transpiling expression") @@ - transpile_value typed in - let%bind michelson = - trace (simple_error "compiling expression") @@ - Compiler.translate_value mini_c mini_c_ty in - let str = - Format.asprintf "%a" Michelson.pp_stripped michelson in - ok str - in - ok expr - - -let compile_contract_storage : string -> string -> string -> s_syntax -> string result = fun source_filename entry_point expression syntax -> - let%bind syntax = syntax_to_variant syntax (Some source_filename) in - let%bind (program , storage_tv) = - let%bind simplified = parsify syntax source_filename 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 simplified = parsify_expression syntax expression in - let%bind typed = - let env = - let last_declaration = Location.unwrap List.(hd @@ rev program) in - match last_declaration with - | Declaration_constant (_ , (_ , post_env)) -> post_env - in - trace (simple_error "typing expression") @@ - Typer.type_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 , mini_c_ty) = - trace (simple_error "transpiling expression") @@ - transpile_value typed in - let%bind michelson = - trace (simple_error "compiling expression") @@ - Compiler.translate_value mini_c mini_c_ty in - let str = - Format.asprintf "%a" Michelson.pp_stripped michelson in - ok str - in - ok expr - -let type_file ?(debug_simplify = false) ?(debug_typed = false) - syntax (source_filename:string) : Ast_typed.program result = - let%bind simpl = parsify syntax source_filename in - (if debug_simplify then - Format.(printf "Simplified : %a\n%!" Ast_simplified.PP.program simpl) - ) ; - let%bind typed = - trace (simple_error "typing") @@ - Typer.type_program simpl in - (if debug_typed then ( - Format.(printf "Typed : %a\n%!" Ast_typed.PP.program typed) - )) ; - ok typed - -let run_contract ?amount source_filename entry_point storage input syntax = - let%bind syntax = syntax_to_variant syntax (Some source_filename) in - let%bind typed = - type_file syntax source_filename in - let%bind storage_simpl = - parsify_expression syntax storage in - let%bind input_simpl = - parsify_expression syntax input in - let options = - let open Proto_alpha_utils.Memory_proto_alpha in - let amount = Option.bind (fun amount -> Protocol.Alpha_context.Tez.of_string amount) amount in - (make_options ?amount ()) in - Run_simplified.run_simplityped ~options typed entry_point (Ast_simplified.e_pair storage_simpl input_simpl) - -let run_function ?amount source_filename entry_point parameter syntax = - let%bind syntax = syntax_to_variant syntax (Some source_filename) in - let%bind typed = - type_file syntax source_filename in - let%bind parameter' = - parsify_expression syntax parameter in - let options = - let open Proto_alpha_utils.Memory_proto_alpha in - let amount = Option.bind (fun amount -> Protocol.Alpha_context.Tez.of_string amount) amount in - (make_options ?amount ()) in - Run_simplified.run_simplityped ~options typed entry_point parameter' - -let evaluate_value ?amount source_filename entry_point syntax = - let%bind syntax = syntax_to_variant syntax (Some source_filename) in - let%bind typed = - type_file syntax source_filename in - let options = - let open Proto_alpha_utils.Memory_proto_alpha in - let amount = Option.bind (fun amount -> Protocol.Alpha_context.Tez.of_string amount) amount in - (make_options ?amount ()) in - Run_simplified.evaluate_simplityped ~options typed entry_point diff --git a/src/main/run_typed.ml b/src/main/run_typed.ml deleted file mode 100644 index fc136c63c..000000000 --- a/src/main/run_typed.ml +++ /dev/null @@ -1,70 +0,0 @@ -open Trace - -let transpile_value - (e:Ast_typed.annotated_expression) : Mini_c.value result = - let%bind (f , ty) = - let open Transpiler in - let (f , _) = functionalize e in - let%bind main = translate_main f e.location in - ok main - in - - let input = Mini_c.Combinators.d_unit in - let%bind r = Run_mini_c.run_entry f ty input in - ok r - -let evaluate_typed - ?(debug_mini_c = false) ?(debug_michelson = false) - ?options (entry:string) (program:Ast_typed.program) : Ast_typed.annotated_expression result = - trace (simple_error "easy evaluate typed") @@ - let%bind result = - let%bind (mini_c_main , ty) = - Transpiler.translate_entry program entry in - (if debug_mini_c then - Format.(printf "Mini_c : %a\n%!" Mini_c.PP.function_ mini_c_main) - ) ; - Run_mini_c.run_entry ?options ~debug_michelson mini_c_main ty (Mini_c.Combinators.d_unit) - in - let%bind typed_result = - let%bind typed_main = Ast_typed.get_entry program entry in - Transpiler.untranspile result typed_main.type_annotation in - ok typed_result - -let run_typed - ?(debug_mini_c = false) ?(debug_michelson = 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 , ty) = - trace (simple_error "transpile mini_c entry") @@ - Transpiler.translate_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 ~debug_michelson ?options mini_c_main ty 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 - Transpiler.untranspile mini_c_result main_result_type in - ok typed_result diff --git a/src/parser/camligo/.gitignore b/src/passes/1-parser/camligo/.gitignore similarity index 100% rename from src/parser/camligo/.gitignore rename to src/passes/1-parser/camligo/.gitignore diff --git a/src/parser/camligo/ast.ml b/src/passes/1-parser/camligo/ast.ml similarity index 100% rename from src/parser/camligo/ast.ml rename to src/passes/1-parser/camligo/ast.ml diff --git a/src/parser/camligo/dune b/src/passes/1-parser/camligo/dune similarity index 100% rename from src/parser/camligo/dune rename to src/passes/1-parser/camligo/dune diff --git a/src/parser/camligo/generator.ml b/src/passes/1-parser/camligo/generator.ml similarity index 100% rename from src/parser/camligo/generator.ml rename to src/passes/1-parser/camligo/generator.ml diff --git a/src/parser/camligo/lex/dune b/src/passes/1-parser/camligo/lex/dune similarity index 100% rename from src/parser/camligo/lex/dune rename to src/passes/1-parser/camligo/lex/dune diff --git a/src/parser/camligo/lex/generator.ml b/src/passes/1-parser/camligo/lex/generator.ml similarity index 100% rename from src/parser/camligo/lex/generator.ml rename to src/passes/1-parser/camligo/lex/generator.ml diff --git a/src/parser/camligo/location.ml b/src/passes/1-parser/camligo/location.ml similarity index 100% rename from src/parser/camligo/location.ml rename to src/passes/1-parser/camligo/location.ml diff --git a/src/parser/camligo/parser_camligo.ml b/src/passes/1-parser/camligo/parser_camligo.ml similarity index 100% rename from src/parser/camligo/parser_camligo.ml rename to src/passes/1-parser/camligo/parser_camligo.ml diff --git a/src/parser/camligo/pre_parser.mly b/src/passes/1-parser/camligo/pre_parser.mly similarity index 100% rename from src/parser/camligo/pre_parser.mly rename to src/passes/1-parser/camligo/pre_parser.mly diff --git a/src/parser/camligo/user.ml b/src/passes/1-parser/camligo/user.ml similarity index 100% rename from src/parser/camligo/user.ml rename to src/passes/1-parser/camligo/user.ml diff --git a/src/parser/dune b/src/passes/1-parser/dune similarity index 100% rename from src/parser/dune rename to src/passes/1-parser/dune diff --git a/src/parser/generator/doc/essai.ml b/src/passes/1-parser/generator/doc/essai.ml similarity index 100% rename from src/parser/generator/doc/essai.ml rename to src/passes/1-parser/generator/doc/essai.ml diff --git a/src/parser/generator/doc/mini_ml.bnf b/src/passes/1-parser/generator/doc/mini_ml.bnf similarity index 100% rename from src/parser/generator/doc/mini_ml.bnf rename to src/passes/1-parser/generator/doc/mini_ml.bnf diff --git a/src/parser/generator/doc/mini_ml2.bnf b/src/passes/1-parser/generator/doc/mini_ml2.bnf similarity index 100% rename from src/parser/generator/doc/mini_ml2.bnf rename to src/passes/1-parser/generator/doc/mini_ml2.bnf diff --git a/src/parser/generator/doc/mini_ml3.bnf b/src/passes/1-parser/generator/doc/mini_ml3.bnf similarity index 100% rename from src/parser/generator/doc/mini_ml3.bnf rename to src/passes/1-parser/generator/doc/mini_ml3.bnf diff --git a/src/parser/generator/doc/mini_ml4.bnf b/src/passes/1-parser/generator/doc/mini_ml4.bnf similarity index 100% rename from src/parser/generator/doc/mini_ml4.bnf rename to src/passes/1-parser/generator/doc/mini_ml4.bnf diff --git a/src/parser/ligodity.ml b/src/passes/1-parser/ligodity.ml similarity index 100% rename from src/parser/ligodity.ml rename to src/passes/1-parser/ligodity.ml diff --git a/src/parser/ligodity/.AST.ml.tag b/src/passes/1-parser/ligodity/.AST.ml.tag similarity index 100% rename from src/parser/ligodity/.AST.ml.tag rename to src/passes/1-parser/ligodity/.AST.ml.tag diff --git a/src/parser/ligodity/.Eval.ml.tag b/src/passes/1-parser/ligodity/.Eval.ml.tag similarity index 100% rename from src/parser/ligodity/.Eval.ml.tag rename to src/passes/1-parser/ligodity/.Eval.ml.tag diff --git a/src/parser/ligodity/.EvalMain.ml.tag b/src/passes/1-parser/ligodity/.EvalMain.ml.tag similarity index 100% rename from src/parser/ligodity/.EvalMain.ml.tag rename to src/passes/1-parser/ligodity/.EvalMain.ml.tag diff --git a/src/parser/ligodity/.Lexer.ml.tag b/src/passes/1-parser/ligodity/.Lexer.ml.tag similarity index 100% rename from src/parser/ligodity/.Lexer.ml.tag rename to src/passes/1-parser/ligodity/.Lexer.ml.tag diff --git a/src/parser/ligodity/.LexerMain.tag b/src/passes/1-parser/ligodity/.LexerMain.tag similarity index 100% rename from src/parser/ligodity/.LexerMain.tag rename to src/passes/1-parser/ligodity/.LexerMain.tag diff --git a/src/parser/ligodity/.Parser.ml.tag b/src/passes/1-parser/ligodity/.Parser.ml.tag similarity index 100% rename from src/parser/ligodity/.Parser.ml.tag rename to src/passes/1-parser/ligodity/.Parser.ml.tag diff --git a/src/parser/ligodity/.Parser.mly.tag b/src/passes/1-parser/ligodity/.Parser.mly.tag similarity index 100% rename from src/parser/ligodity/.Parser.mly.tag rename to src/passes/1-parser/ligodity/.Parser.mly.tag diff --git a/src/parser/ligodity/.ParserMain.tag b/src/passes/1-parser/ligodity/.ParserMain.tag similarity index 100% rename from src/parser/ligodity/.ParserMain.tag rename to src/passes/1-parser/ligodity/.ParserMain.tag diff --git a/src/parser/ligodity/.links b/src/passes/1-parser/ligodity/.links similarity index 100% rename from src/parser/ligodity/.links rename to src/passes/1-parser/ligodity/.links diff --git a/src/parser/ligodity/AST.ml b/src/passes/1-parser/ligodity/AST.ml similarity index 100% rename from src/parser/ligodity/AST.ml rename to src/passes/1-parser/ligodity/AST.ml diff --git a/src/parser/ligodity/AST.mli b/src/passes/1-parser/ligodity/AST.mli similarity index 100% rename from src/parser/ligodity/AST.mli rename to src/passes/1-parser/ligodity/AST.mli diff --git a/src/parser/ligodity/EvalOpt.ml b/src/passes/1-parser/ligodity/EvalOpt.ml similarity index 100% rename from src/parser/ligodity/EvalOpt.ml rename to src/passes/1-parser/ligodity/EvalOpt.ml diff --git a/src/parser/ligodity/EvalOpt.mli b/src/passes/1-parser/ligodity/EvalOpt.mli similarity index 100% rename from src/parser/ligodity/EvalOpt.mli rename to src/passes/1-parser/ligodity/EvalOpt.mli diff --git a/src/parser/ligodity/Lexer.mli b/src/passes/1-parser/ligodity/Lexer.mli similarity index 100% rename from src/parser/ligodity/Lexer.mli rename to src/passes/1-parser/ligodity/Lexer.mli diff --git a/src/parser/ligodity/Lexer.mll b/src/passes/1-parser/ligodity/Lexer.mll similarity index 100% rename from src/parser/ligodity/Lexer.mll rename to src/passes/1-parser/ligodity/Lexer.mll diff --git a/src/parser/ligodity/LexerMain.ml b/src/passes/1-parser/ligodity/LexerMain.ml similarity index 100% rename from src/parser/ligodity/LexerMain.ml rename to src/passes/1-parser/ligodity/LexerMain.ml diff --git a/src/parser/ligodity/ParToken.mly b/src/passes/1-parser/ligodity/ParToken.mly similarity index 100% rename from src/parser/ligodity/ParToken.mly rename to src/passes/1-parser/ligodity/ParToken.mly diff --git a/src/parser/ligodity/Parser.mly b/src/passes/1-parser/ligodity/Parser.mly similarity index 100% rename from src/parser/ligodity/Parser.mly rename to src/passes/1-parser/ligodity/Parser.mly diff --git a/src/parser/ligodity/ParserMain.ml b/src/passes/1-parser/ligodity/ParserMain.ml similarity index 100% rename from src/parser/ligodity/ParserMain.ml rename to src/passes/1-parser/ligodity/ParserMain.ml diff --git a/src/parser/ligodity/Stubs/Simple_utils.ml b/src/passes/1-parser/ligodity/Stubs/Simple_utils.ml similarity index 100% rename from src/parser/ligodity/Stubs/Simple_utils.ml rename to src/passes/1-parser/ligodity/Stubs/Simple_utils.ml diff --git a/src/parser/ligodity/Tests/match.mml b/src/passes/1-parser/ligodity/Tests/match.mml similarity index 100% rename from src/parser/ligodity/Tests/match.mml rename to src/passes/1-parser/ligodity/Tests/match.mml diff --git a/src/parser/ligodity/Token.ml b/src/passes/1-parser/ligodity/Token.ml similarity index 100% rename from src/parser/ligodity/Token.ml rename to src/passes/1-parser/ligodity/Token.ml diff --git a/src/parser/ligodity/Token.mli b/src/passes/1-parser/ligodity/Token.mli similarity index 100% rename from src/parser/ligodity/Token.mli rename to src/passes/1-parser/ligodity/Token.mli diff --git a/src/parser/ligodity/Utils.ml b/src/passes/1-parser/ligodity/Utils.ml similarity index 100% rename from src/parser/ligodity/Utils.ml rename to src/passes/1-parser/ligodity/Utils.ml diff --git a/src/parser/ligodity/Utils.mli b/src/passes/1-parser/ligodity/Utils.mli similarity index 100% rename from src/parser/ligodity/Utils.mli rename to src/passes/1-parser/ligodity/Utils.mli diff --git a/src/parser/ligodity/check_dot_git_is_dir.sh b/src/passes/1-parser/ligodity/check_dot_git_is_dir.sh similarity index 100% rename from src/parser/ligodity/check_dot_git_is_dir.sh rename to src/passes/1-parser/ligodity/check_dot_git_is_dir.sh diff --git a/src/parser/ligodity/dune b/src/passes/1-parser/ligodity/dune similarity index 100% rename from src/parser/ligodity/dune rename to src/passes/1-parser/ligodity/dune diff --git a/src/parser/ligodity/ligodity.ml b/src/passes/1-parser/ligodity/ligodity.ml similarity index 100% rename from src/parser/ligodity/ligodity.ml rename to src/passes/1-parser/ligodity/ligodity.ml diff --git a/src/parser/parser.ml b/src/passes/1-parser/parser.ml similarity index 100% rename from src/parser/parser.ml rename to src/passes/1-parser/parser.ml diff --git a/src/parser/pascaligo.ml b/src/passes/1-parser/pascaligo.ml similarity index 98% rename from src/parser/pascaligo.ml rename to src/passes/1-parser/pascaligo.ml index 1f95166e2..9fffdcb46 100644 --- a/src/parser/pascaligo.ml +++ b/src/passes/1-parser/pascaligo.ml @@ -4,7 +4,7 @@ module Parser = Parser_pascaligo.Parser module AST = Parser_pascaligo.AST module ParserLog = Parser_pascaligo.ParserLog -let parse_file (source: string) : AST.t result = +let parse_file (source: string) : AST.t result = let pp_input = let prefix = Filename.(source |> basename |> remove_extension) and suffix = ".pp.ligo" diff --git a/src/parser/pascaligo/.Lexer.ml.tag b/src/passes/1-parser/pascaligo/.Lexer.ml.tag similarity index 100% rename from src/parser/pascaligo/.Lexer.ml.tag rename to src/passes/1-parser/pascaligo/.Lexer.ml.tag diff --git a/src/parser/pascaligo/.LexerMain.tag b/src/passes/1-parser/pascaligo/.LexerMain.tag similarity index 100% rename from src/parser/pascaligo/.LexerMain.tag rename to src/passes/1-parser/pascaligo/.LexerMain.tag diff --git a/src/parser/pascaligo/.Parser.mly.tag b/src/passes/1-parser/pascaligo/.Parser.mly.tag similarity index 100% rename from src/parser/pascaligo/.Parser.mly.tag rename to src/passes/1-parser/pascaligo/.Parser.mly.tag diff --git a/src/parser/pascaligo/.ParserMain.tag b/src/passes/1-parser/pascaligo/.ParserMain.tag similarity index 100% rename from src/parser/pascaligo/.ParserMain.tag rename to src/passes/1-parser/pascaligo/.ParserMain.tag diff --git a/src/parser/pascaligo/.gitignore b/src/passes/1-parser/pascaligo/.gitignore similarity index 100% rename from src/parser/pascaligo/.gitignore rename to src/passes/1-parser/pascaligo/.gitignore diff --git a/src/parser/pascaligo/.links b/src/passes/1-parser/pascaligo/.links similarity index 100% rename from src/parser/pascaligo/.links rename to src/passes/1-parser/pascaligo/.links diff --git a/src/parser/pascaligo/AST.ml b/src/passes/1-parser/pascaligo/AST.ml similarity index 100% rename from src/parser/pascaligo/AST.ml rename to src/passes/1-parser/pascaligo/AST.ml diff --git a/src/parser/pascaligo/AST.mli b/src/passes/1-parser/pascaligo/AST.mli similarity index 100% rename from src/parser/pascaligo/AST.mli rename to src/passes/1-parser/pascaligo/AST.mli diff --git a/src/parser/pascaligo/Doc/pascaligo.txt b/src/passes/1-parser/pascaligo/Doc/pascaligo.txt similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo.txt rename to src/passes/1-parser/pascaligo/Doc/pascaligo.txt diff --git a/src/parser/pascaligo/Doc/pascaligo_01.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_01.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_01.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_01.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_02.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_02.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_02.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_02.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_03.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_03.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_03.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_03.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_04.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_04.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_04.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_04.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_05.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_05.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_05.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_05.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_06.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_06.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_06.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_06.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_07.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_07.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_07.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_07.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_08.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_08.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_08.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_08.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_09.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_09.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_09.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_09.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_10.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_10.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_10.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_10.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_11.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_11.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_11.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_11.bnf diff --git a/src/parser/pascaligo/Doc/pascaligo_12.bnf b/src/passes/1-parser/pascaligo/Doc/pascaligo_12.bnf similarity index 100% rename from src/parser/pascaligo/Doc/pascaligo_12.bnf rename to src/passes/1-parser/pascaligo/Doc/pascaligo_12.bnf diff --git a/src/parser/pascaligo/LexToken.mli b/src/passes/1-parser/pascaligo/LexToken.mli similarity index 100% rename from src/parser/pascaligo/LexToken.mli rename to src/passes/1-parser/pascaligo/LexToken.mli diff --git a/src/parser/pascaligo/LexToken.mll b/src/passes/1-parser/pascaligo/LexToken.mll similarity index 100% rename from src/parser/pascaligo/LexToken.mll rename to src/passes/1-parser/pascaligo/LexToken.mll diff --git a/src/parser/pascaligo/LexerMain.ml b/src/passes/1-parser/pascaligo/LexerMain.ml similarity index 100% rename from src/parser/pascaligo/LexerMain.ml rename to src/passes/1-parser/pascaligo/LexerMain.ml diff --git a/src/parser/pascaligo/ParToken.mly b/src/passes/1-parser/pascaligo/ParToken.mly similarity index 100% rename from src/parser/pascaligo/ParToken.mly rename to src/passes/1-parser/pascaligo/ParToken.mly diff --git a/src/parser/pascaligo/Parser.mly b/src/passes/1-parser/pascaligo/Parser.mly similarity index 100% rename from src/parser/pascaligo/Parser.mly rename to src/passes/1-parser/pascaligo/Parser.mly diff --git a/src/parser/pascaligo/ParserLog.ml b/src/passes/1-parser/pascaligo/ParserLog.ml similarity index 100% rename from src/parser/pascaligo/ParserLog.ml rename to src/passes/1-parser/pascaligo/ParserLog.ml diff --git a/src/parser/pascaligo/ParserLog.mli b/src/passes/1-parser/pascaligo/ParserLog.mli similarity index 100% rename from src/parser/pascaligo/ParserLog.mli rename to src/passes/1-parser/pascaligo/ParserLog.mli diff --git a/src/parser/pascaligo/ParserMain.ml b/src/passes/1-parser/pascaligo/ParserMain.ml similarity index 100% rename from src/parser/pascaligo/ParserMain.ml rename to src/passes/1-parser/pascaligo/ParserMain.ml diff --git a/src/parser/pascaligo/Stubs/Simple_utils.ml b/src/passes/1-parser/pascaligo/Stubs/Simple_utils.ml similarity index 100% rename from src/parser/pascaligo/Stubs/Simple_utils.ml rename to src/passes/1-parser/pascaligo/Stubs/Simple_utils.ml diff --git a/src/parser/pascaligo/Tests/a.ligo b/src/passes/1-parser/pascaligo/Tests/a.ligo similarity index 100% rename from src/parser/pascaligo/Tests/a.ligo rename to src/passes/1-parser/pascaligo/Tests/a.ligo diff --git a/src/parser/pascaligo/Tests/crowdfunding.ligo b/src/passes/1-parser/pascaligo/Tests/crowdfunding.ligo similarity index 100% rename from src/parser/pascaligo/Tests/crowdfunding.ligo rename to src/passes/1-parser/pascaligo/Tests/crowdfunding.ligo diff --git a/src/parser/pascaligo/check_dot_git_is_dir.sh b/src/passes/1-parser/pascaligo/check_dot_git_is_dir.sh similarity index 100% rename from src/parser/pascaligo/check_dot_git_is_dir.sh rename to src/passes/1-parser/pascaligo/check_dot_git_is_dir.sh diff --git a/src/parser/pascaligo/dune b/src/passes/1-parser/pascaligo/dune similarity index 100% rename from src/parser/pascaligo/dune rename to src/passes/1-parser/pascaligo/dune diff --git a/src/parser/pascaligo/pascaligo.ml b/src/passes/1-parser/pascaligo/pascaligo.ml similarity index 100% rename from src/parser/pascaligo/pascaligo.ml rename to src/passes/1-parser/pascaligo/pascaligo.ml diff --git a/src/parser/shared/.links b/src/passes/1-parser/shared/.links similarity index 100% rename from src/parser/shared/.links rename to src/passes/1-parser/shared/.links diff --git a/src/parser/shared/Doc/shared.txt b/src/passes/1-parser/shared/Doc/shared.txt similarity index 100% rename from src/parser/shared/Doc/shared.txt rename to src/passes/1-parser/shared/Doc/shared.txt diff --git a/src/parser/shared/Error.mli b/src/passes/1-parser/shared/Error.mli similarity index 100% rename from src/parser/shared/Error.mli rename to src/passes/1-parser/shared/Error.mli diff --git a/src/parser/shared/EvalOpt.ml b/src/passes/1-parser/shared/EvalOpt.ml similarity index 100% rename from src/parser/shared/EvalOpt.ml rename to src/passes/1-parser/shared/EvalOpt.ml diff --git a/src/parser/shared/EvalOpt.mli b/src/passes/1-parser/shared/EvalOpt.mli similarity index 100% rename from src/parser/shared/EvalOpt.mli rename to src/passes/1-parser/shared/EvalOpt.mli diff --git a/src/parser/shared/FQueue.ml b/src/passes/1-parser/shared/FQueue.ml similarity index 100% rename from src/parser/shared/FQueue.ml rename to src/passes/1-parser/shared/FQueue.ml diff --git a/src/parser/shared/FQueue.mli b/src/passes/1-parser/shared/FQueue.mli similarity index 100% rename from src/parser/shared/FQueue.mli rename to src/passes/1-parser/shared/FQueue.mli diff --git a/src/parser/shared/Lexer.mli b/src/passes/1-parser/shared/Lexer.mli similarity index 100% rename from src/parser/shared/Lexer.mli rename to src/passes/1-parser/shared/Lexer.mli diff --git a/src/parser/shared/Lexer.mll b/src/passes/1-parser/shared/Lexer.mll similarity index 100% rename from src/parser/shared/Lexer.mll rename to src/passes/1-parser/shared/Lexer.mll diff --git a/src/parser/shared/LexerLog.ml b/src/passes/1-parser/shared/LexerLog.ml similarity index 100% rename from src/parser/shared/LexerLog.ml rename to src/passes/1-parser/shared/LexerLog.ml diff --git a/src/parser/shared/LexerLog.mli b/src/passes/1-parser/shared/LexerLog.mli similarity index 100% rename from src/parser/shared/LexerLog.mli rename to src/passes/1-parser/shared/LexerLog.mli diff --git a/src/parser/shared/Markup.ml b/src/passes/1-parser/shared/Markup.ml similarity index 100% rename from src/parser/shared/Markup.ml rename to src/passes/1-parser/shared/Markup.ml diff --git a/src/parser/shared/Markup.mli b/src/passes/1-parser/shared/Markup.mli similarity index 100% rename from src/parser/shared/Markup.mli rename to src/passes/1-parser/shared/Markup.mli diff --git a/src/parser/shared/Utils.ml b/src/passes/1-parser/shared/Utils.ml similarity index 100% rename from src/parser/shared/Utils.ml rename to src/passes/1-parser/shared/Utils.ml diff --git a/src/parser/shared/Utils.mli b/src/passes/1-parser/shared/Utils.mli similarity index 100% rename from src/parser/shared/Utils.mli rename to src/passes/1-parser/shared/Utils.mli diff --git a/src/parser/shared/dune b/src/passes/1-parser/shared/dune similarity index 100% rename from src/parser/shared/dune rename to src/passes/1-parser/shared/dune diff --git a/src/simplify/camligo.ml.old b/src/passes/2-simplify/camligo.ml.old similarity index 100% rename from src/simplify/camligo.ml.old rename to src/passes/2-simplify/camligo.ml.old diff --git a/src/simplify/dune b/src/passes/2-simplify/dune similarity index 100% rename from src/simplify/dune rename to src/passes/2-simplify/dune diff --git a/src/simplify/ligodity.ml b/src/passes/2-simplify/ligodity.ml similarity index 92% rename from src/simplify/ligodity.ml rename to src/passes/2-simplify/ligodity.ml index 34866fd91..879579e9f 100644 --- a/src/simplify/ligodity.ml +++ b/src/passes/2-simplify/ligodity.ml @@ -162,7 +162,6 @@ module Errors = struct let message () = "a map definition is a list of pairs" in info title message - let corner_case ~loc message = let title () = "corner case" in let content () = "We don't have a good error message for this case. \ @@ -405,6 +404,9 @@ let rec simpl_expression : | "Some" -> ( return @@ e_some ~loc arg ) + | "None" -> ( + return @@ e_none ~loc () + ) | _ -> ( return @@ e_constructor ~loc c_name arg ) @@ -432,7 +434,7 @@ let rec simpl_expression : | EArith (Mtz n) -> ( let (n , loc) = r_split n in let n = Z.to_int @@ snd @@ n in - return @@ e_literal ~loc (Literal_tez n) + return @@ e_literal ~loc (Literal_mutez n) ) | EArith _ as e -> fail @@ unsupported_arith_op e @@ -700,6 +702,24 @@ and simpl_cases : type a . (Raw.pattern * a) list -> a matching result = ) | _ -> fail @@ only_constructors t in + let rec get_constr_opt (t:Raw.pattern) = + match t with + | PPar p -> get_constr_opt p.value.inside + | PConstr v -> ( + let (const , pat_opt) = v.value in + let%bind var_opt = + match pat_opt with + | None -> ok None + | Some pat -> ( + let%bind single_pat = get_single pat in + let%bind var = get_var single_pat in + ok (Some var) + ) + in + ok (const.value , var_opt) + ) + | _ -> fail @@ only_constructors t + in let%bind patterns = let aux (x , y) = let xs = get_tuple x in @@ -728,21 +748,44 @@ and simpl_cases : type a . (Raw.pattern * a) list -> a matching result = ok @@ Match_list {match_cons = (a, b, cons) ; match_nil = nil} ) | lst -> ( - trace (simple_info "currently, only booleans, lists and constructors \ - are supported in patterns") @@ - let%bind constrs = + let error x = + let title () = "Pattern" in + let content () = + Format.asprintf "Pattern : %a" (PP_helpers.printer Raw.print_pattern) x in + error title content + in + let as_variant () = + trace (simple_info "currently, only booleans, lists, options, and constructors \ + are supported in patterns") @@ + let%bind constrs = + let aux (x , y) = + let%bind x' = + trace (error x) @@ + get_constr x + in + ok (x' , y) + in + bind_map_list aux lst + in + ok @@ Match_variant constrs + in + let as_option () = let aux (x , y) = - let error = - let title () = "Pattern" in - let content () = - Format.asprintf "Pattern : %a" (PP_helpers.printer Raw.print_pattern) x in - error title content in let%bind x' = - trace error @@ - get_constr x in - ok (x' , y) in - bind_map_list aux lst in - ok @@ Match_variant constrs + trace (error x) @@ + get_constr_opt x + in + ok (x' , y) + in + let%bind constrs = bind_map_list aux lst in + match constrs with + | [ (("Some" , Some some_var) , some_expr) ; (("None" , None) , none_expr) ] + | [ (("None" , None) , none_expr) ; (("Some" , Some some_var) , some_expr) ] -> ( + ok @@ Match_option { match_some = (some_var , some_expr) ; match_none = none_expr } + ) + | _ -> simple_fail "bad option pattern" + in + bind_or (as_option () , as_variant ()) ) let simpl_program : Raw.ast -> program result = fun t -> diff --git a/src/simplify/pascaligo.ml b/src/passes/2-simplify/pascaligo.ml similarity index 93% rename from src/simplify/pascaligo.ml rename to src/passes/2-simplify/pascaligo.ml index 4aeab4d2a..5380e9f0e 100644 --- a/src/simplify/pascaligo.ml +++ b/src/passes/2-simplify/pascaligo.ml @@ -247,7 +247,9 @@ module Errors = struct let pattern_loc = Raw.pattern_to_region p in let data = [ ("pattern_loc", - fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc) + fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc) ; + ("pattern", + fun () -> Format.asprintf "%a" (Simple_utils.PP_helpers.printer Parser.Pascaligo.ParserLog.print_pattern) p) ; ] in error ~data title message @@ -301,17 +303,31 @@ open Operators.Simplify.Pascaligo let r_split = Location.r_split -let return expr = ok @@ fun expr'_opt -> - let expr = expr in - match expr'_opt with - | None -> ok @@ expr - | Some expr' -> ok @@ e_sequence expr expr' +(* + Statements can't be simplified in isolation. `a ; b ; c` can get simplified either + as `let x = expr in (b ; c)` if `a` is a ` const x = expr` declaration or as + `sequence(a , sequence(b , c))` for everything else. + Because of this, simplifying sequences depend on their contents. To avoid peeking in + their contents, we instead simplify sequences elements as functions from their next + elements to the actual result. + For `return_let_in`, if there is no follow-up element, an error is triggered, as + you can't have `let x = expr in ...` with no `...`. A cleaner option might be to add + a `unit` instead of erroring. + + `return_statement` is used for non-let_in statements. +*) let return_let_in ?loc binder rhs = ok @@ fun expr'_opt -> match expr'_opt with | None -> fail @@ corner_case ~loc:__LOC__ "missing return" | Some expr' -> ok @@ e_let_in ?loc binder rhs expr' +let return_statement expr = ok @@ fun expr'_opt -> + let expr = expr in + match expr'_opt with + | None -> ok @@ expr + | Some expr' -> ok @@ e_sequence expr expr' + let rec simpl_type_expression (t:Raw.type_expr) : type_expression result = match t with | TPar x -> simpl_type_expression x.value.inside @@ -336,10 +352,13 @@ let rec simpl_type_expression (t:Raw.type_expr) : type_expression result = ok @@ T_constant (cst , lst') | TProd p -> let%bind tpl = simpl_list_type_expression - @@ npseq_to_list p.value in + @@ npseq_to_list p.value in ok tpl | TRecord r -> - let aux = fun (x, y) -> let%bind y = simpl_type_expression y in ok (x, y) in + let aux = fun (x, y) -> + let%bind y = simpl_type_expression y in + ok (x, y) + in let apply = fun (x:Raw.field_decl Raw.reg) -> (x.value.field_name.value, x.value.field_type) in let%bind lst = bind_list @@ -373,34 +392,30 @@ and simpl_list_type_expression (lst:Raw.type_expr list) : type_expression result let%bind lst = bind_list @@ List.map simpl_type_expression lst in ok @@ T_tuple lst +let simpl_projection : Raw.projection Region.reg -> _ = fun p -> + let (p' , loc) = r_split p in + let var = + let name = p'.struct_name.value in + e_variable name in + let path = p'.field_path in + let path' = + let aux (s:Raw.selection) = + match s with + | FieldName property -> Access_record property.value + | Component index -> Access_tuple (Z.to_int (snd index.value)) + in + List.map aux @@ npseq_to_list path in + ok @@ e_accessor ~loc var path' + + let rec simpl_expression (t:Raw.expr) : expr result = let return x = ok x in - let simpl_projection = fun (p : Raw.projection Region.reg) -> - let (p' , loc) = r_split p in - let var = - let name = p'.struct_name.value in - e_variable name in - let path = p'.field_path in - let path' = - let aux (s:Raw.selection) = - match s with - | FieldName property -> Access_record property.value - | Component index -> Access_tuple (Z.to_int (snd index.value)) - in - List.map aux @@ npseq_to_list path in - return @@ e_accessor ~loc var path' - in match t with | EAnnot a -> ( let ((expr , type_expr) , loc) = r_split a in let%bind expr' = simpl_expression expr in let%bind type_expr' = simpl_type_expression type_expr in - match (Location.unwrap expr', type_expr') with - | (E_literal (Literal_string str) , T_constant ("bytes" , [])) -> - trace_strong (bad_bytes loc str) @@ - e_bytes ~loc str - | _ -> - return @@ e_annotation ~loc expr' type_expr' + return @@ e_annotation ~loc expr' type_expr' ) | EVar c -> ( let (c' , loc) = r_split c in @@ -485,7 +500,7 @@ let rec simpl_expression (t:Raw.expr) : expr result = | EArith (Mtz n) -> ( let (n , loc) = r_split n in let n = Z.to_int @@ snd @@ n in - return @@ e_literal ~loc (Literal_tez n) + return @@ e_literal ~loc (Literal_mutez n) ) | EArith (Neg e) -> simpl_unop "NEG" e | EString (String s) -> @@ -767,31 +782,25 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu match List.assoc_opt f constants with | None -> let%bind arg = simpl_tuple_expression ~loc:args_loc args' in - return @@ e_application ~loc (e_variable ~loc:f_loc f) arg + return_statement @@ e_application ~loc (e_variable ~loc:f_loc f) arg | Some s -> let%bind lst = bind_map_list simpl_expression args' in - return @@ e_constant ~loc s lst + return_statement @@ e_constant ~loc s lst ) | Fail e -> ( let%bind expr = simpl_expression e.value.fail_expr in - return @@ e_failwith expr + return_statement @@ e_failwith expr ) | Skip reg -> ( let loc = Location.lift reg in - return @@ e_skip ~loc () + return_statement @@ e_skip ~loc () ) | Loop (While l) -> let l = l.value in let%bind cond = simpl_expression l.cond in let%bind body = simpl_block l.block.value in let%bind body = body None in - return @@ e_loop cond body - (* | Loop (For (ForCollect x)) -> ( - * let (x' , loc) = r_split x in - * let%bind expr = simpl_expression x'.expr in - * let%bind body = simpl_block x'.block.value in - * ok _ - * ) *) + return_statement @@ e_loop cond body | Loop (For (ForInt {region; _} | ForCollect {region ; _})) -> fail @@ unsupported_for_loops region | Cond c -> ( @@ -805,7 +814,7 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu | ClauseBlock b -> simpl_statements @@ fst b.value.inside in let%bind match_true = match_true None in let%bind match_false = match_false None in - return @@ e_matching expr ~loc (Match_bool {match_true; match_false}) + return_statement @@ e_matching expr ~loc (Match_bool {match_true; match_false}) ) | Assign a -> ( let (a , loc) = r_split a in @@ -816,7 +825,7 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu match a.lhs with | Path path -> ( let (name , path') = simpl_path path in - return @@ e_assign ~loc name path' value_expr + return_statement @@ e_assign ~loc name path' value_expr ) | MapPath v -> ( let v' = v.value in @@ -826,7 +835,7 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu let%bind key_expr = simpl_expression v'.index.value.inside in let old_expr = e_variable name.value in let expr' = e_map_add key_expr value_expr old_expr in - return @@ e_assign ~loc name.value [] expr' + return_statement @@ e_assign ~loc name.value [] expr' ) ) | CaseInstr c -> ( @@ -841,7 +850,7 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu @@ List.map aux @@ npseq_to_list c.cases.value in let%bind m = simpl_cases cases in - return @@ e_matching ~loc expr m + return_statement @@ e_matching ~loc expr m ) | RecordPatch r -> ( let r = r.value in @@ -858,14 +867,13 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu e_assign ~loc name (access_path @ [ Access_record access ]) v in let assigns = List.map aux inj in match assigns with - (* E_sequence (E_skip, E_skip) ? *) | [] -> fail @@ unsupported_empty_record_patch r.record_inj | hd :: tl -> ( let aux acc cur = e_sequence acc cur in ok @@ List.fold_left aux hd tl ) in - return @@ expr + return_statement @@ expr ) | MapPatch patch -> fail @@ unsupported_map_patches patch @@ -879,7 +887,7 @@ and simpl_single_instruction : Raw.single_instr -> (_ -> expression result) resu | Path path -> fail @@ unsupported_deep_map_rm path in let%bind key' = simpl_expression key in let expr = e_constant ~loc "MAP_REMOVE" [key' ; e_variable map] in - return @@ e_assign ~loc map [] expr + return_statement @@ e_assign ~loc map [] expr ) | SetRemove r -> fail @@ unsupported_set_removal r @@ -908,7 +916,6 @@ and simpl_cases : type a . (Raw.pattern * a) list -> a matching result = fun t - | p -> fail @@ unsupported_non_var_pattern p in let get_tuple (t: Raw.pattern) = match t with - | PCons v -> npseq_to_list v.value | PTuple v -> npseq_to_list v.value.inside | x -> [ x ] in let get_single (t: Raw.pattern) = @@ -917,6 +924,15 @@ and simpl_cases : type a . (Raw.pattern * a) list -> a matching result = fun t - trace_strong (unsupported_tuple_pattern t) @@ Assert.assert_list_size t' 1 in ok (List.hd t') in + let get_toplevel (t : Raw.pattern) = + match t with + | PCons x -> ( + let (x' , lst) = x.value in + match lst with + | [] -> ok x' + | _ -> ok t + ) + | _ -> fail @@ corner_case ~loc:__LOC__ "unexpected pattern" in let get_constr (t: Raw.pattern) = match t with | PConstr v -> ( @@ -937,10 +953,8 @@ and simpl_cases : type a . (Raw.pattern * a) list -> a matching result = fun t - | _ -> fail @@ only_constructors t in let%bind patterns = let aux (x , y) = - let xs = get_tuple x in - trace_strong (unsupported_tuple_pattern x) @@ - Assert.assert_list_size xs 1 >>? fun () -> - ok (List.hd xs , y) + let%bind x' = get_toplevel x in + ok (x' , y) in bind_map_list aux t in match patterns with | [(PFalse _ , f) ; (PTrue _ , t)] diff --git a/src/simplify/simplify.ml b/src/passes/2-simplify/simplify.ml similarity index 100% rename from src/simplify/simplify.ml rename to src/passes/2-simplify/simplify.ml diff --git a/src/passes/3-self_ast_simplified/dune b/src/passes/3-self_ast_simplified/dune new file mode 100644 index 000000000..39eacaf3e --- /dev/null +++ b/src/passes/3-self_ast_simplified/dune @@ -0,0 +1,12 @@ +(library + (name self_ast_simplified) + (public_name ligo.self_ast_simplified) + (libraries + simple-utils + ast_simplified + ) + (preprocess + (pps ppx_let) + ) + (flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils )) +) diff --git a/src/passes/3-self_ast_simplified/helpers.ml b/src/passes/3-self_ast_simplified/helpers.ml new file mode 100644 index 000000000..505264b80 --- /dev/null +++ b/src/passes/3-self_ast_simplified/helpers.ml @@ -0,0 +1,142 @@ +open Ast_simplified +open Trace + +type mapper = expression -> expression result + +let rec map_expression : mapper -> expression -> expression result = fun f e -> + let self = map_expression f in + let%bind e' = f e in + let return expression = ok { e' with expression } in + match e'.expression with + | E_list lst -> ( + let%bind lst' = bind_map_list self lst in + return @@ E_list lst' + ) + | E_set lst -> ( + let%bind lst' = bind_map_list self lst in + return @@ E_set lst' + ) + | E_map lst -> ( + let%bind lst' = bind_map_list (bind_map_pair self) lst in + return @@ E_map lst' + ) + | E_big_map lst -> ( + let%bind lst' = bind_map_list (bind_map_pair self) lst in + return @@ E_big_map lst' + ) + | E_sequence ab -> ( + let%bind ab' = bind_map_pair self ab in + return @@ E_sequence ab' + ) + | E_look_up ab -> ( + let%bind ab' = bind_map_pair self ab in + return @@ E_look_up ab' + ) + | E_loop ab -> ( + let%bind ab' = bind_map_pair self ab in + return @@ E_loop ab' + ) + | E_annotation (e , t) -> ( + let%bind e' = self e in + return @@ E_annotation (e' , t) + ) + | E_assign (name , path , e) -> ( + let%bind e' = self e in + let%bind path' = map_path f path in + return @@ E_assign (name , path' , e') + ) + | E_failwith e -> ( + let%bind e' = self e in + return @@ E_failwith e' + ) + | E_matching (e , cases) -> ( + let%bind e' = self e in + let%bind cases' = map_cases f cases in + return @@ E_matching (e' , cases') + ) + | E_accessor (e , path) -> ( + let%bind e' = self e in + let%bind path' = map_path f path in + return @@ E_accessor (e' , path') + ) + | E_record m -> ( + let%bind m' = bind_map_smap self m in + return @@ E_record m' + ) + | E_constructor (name , e) -> ( + let%bind e' = self e in + return @@ E_constructor (name , e') + ) + | E_tuple lst -> ( + let%bind lst' = bind_map_list self lst in + return @@ E_tuple lst' + ) + | E_application ab -> ( + let%bind ab' = bind_map_pair self ab in + return @@ E_application ab' + ) + | E_let_in { binder ; rhs ; result } -> ( + let%bind rhs = self rhs in + let%bind result = self result in + return @@ E_let_in { binder ; rhs ; result } + ) + | E_lambda { binder ; input_type ; output_type ; result } -> ( + let%bind result = self result in + return @@ E_lambda { binder ; input_type ; output_type ; result } + ) + | E_constant (name , lst) -> ( + let%bind lst' = bind_map_list self lst in + return @@ E_constant (name , lst') + ) + | E_literal _ | E_variable _ | E_skip as e' -> return e' + +and map_path : mapper -> access_path -> access_path result = fun f p -> bind_map_list (map_access f) p + +and map_access : mapper -> access -> access result = fun f a -> + match a with + | Access_map e -> ( + let%bind e' = map_expression f e in + ok @@ Access_map e' + ) + | a -> ok a + +and map_cases : mapper -> matching_expr -> matching_expr result = fun f m -> + match m with + | Match_bool { match_true ; match_false } -> ( + let%bind match_true = map_expression f match_true in + let%bind match_false = map_expression f match_false in + ok @@ Match_bool { match_true ; match_false } + ) + | Match_list { match_nil ; match_cons = (hd , tl , cons) } -> ( + let%bind match_nil = map_expression f match_nil in + let%bind cons = map_expression f cons in + ok @@ Match_list { match_nil ; match_cons = (hd , tl , cons) } + ) + | Match_option { match_none ; match_some = (name , some) } -> ( + let%bind match_none = map_expression f match_none in + let%bind some = map_expression f some in + ok @@ Match_option { match_none ; match_some = (name , some) } + ) + | Match_tuple (names , e) -> ( + let%bind e' = map_expression f e in + ok @@ Match_tuple (names , e') + ) + | Match_variant lst -> ( + let aux ((a , b) , e) = + let%bind e' = map_expression f e in + ok ((a , b) , e') + in + let%bind lst' = bind_map_list aux lst in + ok @@ Match_variant lst' + ) + +and map_program : mapper -> program -> program result = fun m p -> + let aux = fun (x : declaration) -> + match x with + | Declaration_constant (t , o , e) -> ( + let%bind e' = map_expression m e in + ok (Declaration_constant (t , o , e')) + ) + | Declaration_type _ -> ok x + in + bind_map_list (bind_map_location aux) p diff --git a/src/passes/3-self_ast_simplified/literals.ml b/src/passes/3-self_ast_simplified/literals.ml new file mode 100644 index 000000000..5d7be25b6 --- /dev/null +++ b/src/passes/3-self_ast_simplified/literals.ml @@ -0,0 +1,53 @@ +open Ast_simplified +open Trace + +let peephole_expression : expression -> expression result = fun e -> + let return expression = ok { e with expression } in + match e.expression with + | E_constant ("MAP_LITERAL" , lst) -> ( + let%bind elt = + trace_option (simple_error "map literal expects a single parameter") @@ + List.to_singleton lst + in + let%bind lst = + trace (simple_error "map literal expects a list as parameter") @@ + get_e_list elt.expression + in + let aux = fun (e : expression) -> + trace (simple_error "map literal expects a list of pairs as parameter") @@ + let%bind tpl = get_e_tuple e.expression in + let%bind (a , b) = + trace_option (simple_error "of pairs") @@ + List.to_pair tpl + in + ok (a , b) + in + let%bind pairs = bind_map_list aux lst in + return @@ E_map pairs + ) + | E_constant ("MAP_EMPTY" , lst) -> ( + let%bind () = + trace_strong (simple_error "MAP_EMPTY expects no parameter") @@ + Assert.assert_list_empty lst + in + return @@ E_map [] + ) + | E_constant ("SET_LITERAL" , lst) -> ( + let%bind elt = + trace_option (simple_error "map literal expects a single parameter") @@ + List.to_singleton lst + in + let%bind lst = + trace (simple_error "map literal expects a list as parameter") @@ + get_e_list elt.expression + in + return @@ E_set lst + ) + | E_constant ("SET_EMPTY" , lst) -> ( + let%bind () = + trace_strong (simple_error "SET_EMPTY expects no parameter") @@ + Assert.assert_list_empty lst + in + return @@ E_set [] + ) + | e -> return e diff --git a/src/passes/3-self_ast_simplified/main.ml b/src/passes/3-self_ast_simplified/main.ml new file mode 100644 index 000000000..e69de29bb diff --git a/src/passes/3-self_ast_simplified/none_variant.ml b/src/passes/3-self_ast_simplified/none_variant.ml new file mode 100644 index 000000000..d64350a81 --- /dev/null +++ b/src/passes/3-self_ast_simplified/none_variant.ml @@ -0,0 +1,9 @@ +open Ast_simplified +open Trace + +let peephole_expression : expression -> expression result = fun e -> + let return expression = ok { e with expression } in + match e.expression with + | E_constructor ("Some" , e) -> return @@ E_constant ("SOME" , [ e ]) + | E_constructor ("None" , _) -> return @@ E_constant ("NONE" , [ ]) + | e -> return e diff --git a/src/passes/3-self_ast_simplified/self_ast_simplified.ml b/src/passes/3-self_ast_simplified/self_ast_simplified.ml new file mode 100644 index 000000000..aa18b4a8c --- /dev/null +++ b/src/passes/3-self_ast_simplified/self_ast_simplified.ml @@ -0,0 +1,23 @@ +open Trace + +let all = [ + Tezos_type_annotation.peephole_expression ; + None_variant.peephole_expression ; + Literals.peephole_expression ; +] + +let rec bind_chain : ('a -> 'a result) list -> 'a -> 'a result = fun fs x -> + match fs with + | [] -> ok x + | hd :: tl -> ( + let aux : 'a -> 'a result = fun x -> bind (bind_chain tl) (hd x) in + bind aux (ok x) + ) + +let all_program = + let all_p = List.map Helpers.map_program all in + bind_chain all_p + +let all_expression = + let all_p = List.map Helpers.map_expression all in + bind_chain all_p diff --git a/src/passes/3-self_ast_simplified/tezos_type_annotation.ml b/src/passes/3-self_ast_simplified/tezos_type_annotation.ml new file mode 100644 index 000000000..cf664cfab --- /dev/null +++ b/src/passes/3-self_ast_simplified/tezos_type_annotation.ml @@ -0,0 +1,16 @@ +open Ast_simplified +open Trace + +let peephole_expression : expression -> expression result = fun e -> + let return expression = ok { e with expression } in + match e.expression with + | E_annotation (e' , t) as e -> ( + match (e'.expression , t) with + | (E_literal (Literal_string str) , T_constant ("address" , [])) -> return @@ E_literal (Literal_address str) + | (E_literal (Literal_string str) , T_constant ("bytes" , [])) -> ( + let%bind e' = e'_bytes str in + return e' + ) + | _ -> return e + ) + | e -> return e diff --git a/src/typer/dune b/src/passes/4-typer/dune similarity index 100% rename from src/typer/dune rename to src/passes/4-typer/dune diff --git a/src/typer/typer.ml b/src/passes/4-typer/typer.ml similarity index 92% rename from src/typer/typer.ml rename to src/passes/4-typer/typer.ml index 5c962cc10..5c87cfe62 100644 --- a/src/typer/typer.ml +++ b/src/passes/4-typer/typer.ml @@ -274,7 +274,7 @@ and type_match : type i o . (environment -> i -> o result) -> environment -> O.t let e' = Environment.add_ez_binder hd t_list e in let e' = Environment.add_ez_binder tl t e' in let%bind b' = f e' b in - ok (O.Match_list {match_nil ; match_cons = (hd, tl, b')}) + ok (O.Match_list {match_nil ; match_cons = (((hd , t_list), (tl , t)), b')}) | Match_tuple (lst, b) -> let%bind t_tuple = trace_strong (match_error ~expected:i ~actual:t loc) @@ -382,19 +382,19 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a match tv_opt with | None -> ok () | Some tv' -> O.assert_type_value_eq (tv' , tv) in - let location = Location.get_location ae in + let location = ae.location in ok @@ make_a_e ~location expr tv e in let main_error = let title () = "typing expression" in let content () = "" in let data = [ ("expression" , fun () -> Format.asprintf "%a" I.PP.expression ae) ; - ("location" , fun () -> Format.asprintf "%a" Location.pp @@ Location.get_location ae) ; + ("location" , fun () -> Format.asprintf "%a" Location.pp ae.location) ; ("misc" , fun () -> L.get ()) ; ] in error ~data title content in trace main_error @@ - match Location.unwrap ae with + match ae.expression with (* Basic *) | E_failwith _ -> fail @@ needs_annotation ae "the failwith keyword" | E_variable name -> @@ -406,12 +406,8 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a return (E_literal (Literal_bool b)) (t_bool ()) | E_literal Literal_unit | E_skip -> return (E_literal (Literal_unit)) (t_unit ()) - | E_literal (Literal_string s) -> ( - L.log (Format.asprintf "literal_string option type: %a" PP_helpers.(option O.PP.type_value) tv_opt) ; - match Option.map Ast_typed.get_type' tv_opt with - | Some (T_constant ("address" , [])) -> return (E_literal (Literal_address s)) (t_address ()) - | _ -> return (E_literal (Literal_string s)) (t_string ()) - ) + | E_literal (Literal_string s) -> + return (E_literal (Literal_string s)) (t_string ()) | E_literal (Literal_bytes s) -> return (E_literal (Literal_bytes s)) (t_bytes ()) | E_literal (Literal_int n) -> @@ -420,8 +416,8 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a return (E_literal (Literal_nat n)) (t_nat ()) | E_literal (Literal_timestamp n) -> return (E_literal (Literal_timestamp n)) (t_timestamp ()) - | E_literal (Literal_tez n) -> - return (E_literal (Literal_tez n)) (t_tez ()) + | E_literal (Literal_mutez n) -> + return (E_literal (Literal_mutez n)) (t_tez ()) | E_literal (Literal_address s) -> return (e_address s) (t_address ()) | E_literal (Literal_operation op) -> @@ -451,7 +447,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a ) | Access_map ae' -> ( let%bind ae'' = type_expression e ae' in - let%bind (k , v) = get_t_map prev.type_annotation in + let%bind (k , v) = bind_map_or (get_t_map , get_t_big_map) prev.type_annotation in let%bind () = Ast_typed.assert_type_value_eq (k , get_type_annotation ae'') in return (E_look_up (prev , ae'')) v @@ -459,7 +455,6 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a in trace (simple_info "accessing") @@ bind_fold_list aux e' path - (* Sum *) | E_constructor (c, expr) -> let%bind (c_tv, sum_tv) = @@ -556,6 +551,36 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a ok (t_map key_type value_type ()) in return (E_map lst') tv + | E_big_map lst -> + let%bind lst' = bind_map_list (bind_map_pair (type_expression e)) lst in + let%bind tv = + let aux opt c = + match opt with + | None -> ok (Some c) + | Some c' -> + let%bind _eq = Ast_typed.assert_type_value_eq (c, c') in + ok (Some c') in + let%bind key_type = + let%bind sub = + bind_fold_list aux None + @@ List.map get_type_annotation + @@ List.map fst lst' in + let%bind annot = bind_map_option get_t_big_map_key tv_opt in + trace (simple_info "empty map expression without a type annotation") @@ + O.merge_annotation annot sub (needs_annotation ae "this map literal") + in + let%bind value_type = + let%bind sub = + bind_fold_list aux None + @@ List.map get_type_annotation + @@ List.map snd lst' in + let%bind annot = bind_map_option get_t_big_map_value tv_opt in + trace (simple_info "empty map expression without a type annotation") @@ + O.merge_annotation annot sub (needs_annotation ae "this map literal") + in + ok (t_big_map key_type value_type ()) + in + return (E_big_map lst') tv | E_lambda { binder ; input_type ; @@ -569,9 +594,9 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a match input_type with | Some ty -> ok ty | None -> ( - match Location.unwrap result with + match result.expression with | I.E_let_in li -> ( - match Location.unwrap li.rhs with + match li.rhs.expression with | I.E_variable name when name = (fst binder) -> ( match snd li.binder with | Some ty -> ok ty @@ -587,9 +612,9 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a bind_map_option (evaluate_type e) output_type in let e' = Environment.add_ez_binder (fst binder) input_type e in - let%bind result = type_expression ?tv_opt:output_type e' result in - let output_type = result.type_annotation in - return (E_lambda {binder = fst binder;input_type;output_type;result}) (t_function input_type output_type ()) + let%bind body = type_expression ?tv_opt:output_type e' result in + let output_type = body.type_annotation in + return (E_lambda {binder = fst binder ; body}) (t_function input_type output_type ()) ) | E_constant (name, lst) -> let%bind lst' = bind_list @@ List.map (type_expression e) lst in @@ -614,7 +639,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a return (E_application (f' , arg)) tv | E_look_up dsi -> let%bind (ds, ind) = bind_map_pair (type_expression e) dsi in - let%bind (src, dst) = get_t_map ds.type_annotation in + let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) ds.type_annotation in let%bind _ = O.assert_type_value_eq (ind.type_annotation, src) in return (E_look_up (ds , ind)) (t_option dst ()) (* Advanced *) @@ -651,7 +676,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a let aux (cur:O.value O.matching) = match cur with | Match_bool { match_true ; match_false } -> [ match_true ; match_false ] - | Match_list { match_nil ; match_cons = (_ , _ , match_cons) } -> [ match_nil ; match_cons ] + | Match_list { match_nil ; match_cons = ((_ , _) , match_cons) } -> [ match_nil ; match_cons ] | Match_option { match_none ; match_some = (_ , match_some) } -> [ match_none ; match_some ] | Match_tuple (_ , match_tuple) -> [ match_tuple ] | Match_variant (lst , _) -> List.map snd lst in @@ -778,7 +803,7 @@ let untype_literal (l:O.literal) : I.literal result = | Literal_bool b -> ok (Literal_bool b) | Literal_nat n -> ok (Literal_nat n) | Literal_timestamp n -> ok (Literal_timestamp n) - | Literal_tez n -> ok (Literal_tez n) + | Literal_mutez n -> ok (Literal_mutez n) | Literal_int n -> ok (Literal_int n) | Literal_string s -> ok (Literal_string s) | Literal_bytes b -> ok (Literal_bytes b) @@ -801,11 +826,12 @@ let rec untype_expression (e:O.annotated_expression) : (I.expression) result = let%bind f' = untype_expression f in let%bind arg' = untype_expression arg in return (e_application f' arg') - | E_lambda {binder;input_type;output_type;result} -> - let%bind input_type = untype_type_value input_type in - let%bind output_type = untype_type_value output_type in - let%bind result = untype_expression result in + | E_lambda {binder ; body} -> ( + let%bind io = get_t_function e.type_annotation in + let%bind (input_type , output_type) = bind_map_pair untype_type_value io in + let%bind result = untype_expression body in return (e_lambda binder (Some input_type) (Some output_type) result) + ) | E_tuple lst -> let%bind lst' = bind_list @@ List.map untype_expression lst in @@ -826,6 +852,9 @@ let rec untype_expression (e:O.annotated_expression) : (I.expression) result = | E_map m -> let%bind m' = bind_map_list (bind_map_pair untype_expression) m in return (e_map m') + | E_big_map m -> + let%bind m' = bind_map_list (bind_map_pair untype_expression) m in + return (e_big_map m') | E_list lst -> let%bind lst' = bind_map_list untype_expression lst in return (e_list lst') @@ -866,10 +895,10 @@ and untype_matching : type o i . (o -> i result) -> o O.matching -> (i I.matchin let%bind some = f some in let match_some = fst v, some in ok @@ Match_option {match_none ; match_some} - | Match_list {match_nil ; match_cons = (hd, tl, cons)} -> + | Match_list {match_nil ; match_cons = (((hd_name , _) , (tl_name , _)), cons)} -> let%bind match_nil = f match_nil in let%bind cons = f cons in - let match_cons = hd, tl, cons in + let match_cons = hd_name , tl_name , cons in ok @@ Match_list {match_nil ; match_cons} | Match_variant (lst , _) -> let aux ((a,b),c) = diff --git a/src/transpiler/dune b/src/passes/6-transpiler/dune similarity index 100% rename from src/transpiler/dune rename to src/passes/6-transpiler/dune diff --git a/src/passes/6-transpiler/helpers.ml b/src/passes/6-transpiler/helpers.ml new file mode 100644 index 000000000..2609123eb --- /dev/null +++ b/src/passes/6-transpiler/helpers.ml @@ -0,0 +1,49 @@ +module AST = Ast_typed +module Append_tree = Tree.Append + +open Trace +open Mini_c + +let list_of_map m = List.rev @@ Map.String.fold (fun _ v prev -> v :: prev) m [] +let kv_list_of_map m = List.rev @@ Map.String.fold (fun k v prev -> (k, v) :: prev) m [] +let map_of_kv_list lst = + let open AST.SMap in + List.fold_left (fun prev (k, v) -> add k v prev) empty lst + +let extract_constructor (v : value) (tree : _ Append_tree.t') : (string * value * AST.type_value) result = + let open Append_tree in + let rec aux tv : (string * value * AST.type_value) result= + match tv with + | Leaf (k, t), v -> ok (k, v, t) + | Node {a}, D_left v -> aux (a, v) + | Node {b}, D_right v -> aux (b, v) + | _ -> fail @@ internal_assertion_failure "bad constructor path" + in + let%bind (s, v, t) = aux (tree, v) in + ok (s, v, t) + +let extract_tuple (v : value) (tree : AST.type_value Append_tree.t') : ((value * AST.type_value) list) result = + let open Append_tree in + let rec aux tv : ((value * AST.type_value) list) result = + match tv with + | Leaf t, v -> ok @@ [v, t] + | Node {a;b}, D_pair (va, vb) -> + let%bind a' = aux (a, va) in + let%bind b' = aux (b, vb) in + ok (a' @ b') + | _ -> fail @@ internal_assertion_failure "bad tuple path" + in + aux (tree, v) + +let extract_record (v : value) (tree : _ Append_tree.t') : (_ list) result = + let open Append_tree in + let rec aux tv : ((string * (value * AST.type_value)) list) result = + match tv with + | Leaf (s, t), v -> ok @@ [s, (v, t)] + | Node {a;b}, D_pair (va, vb) -> + let%bind a' = aux (a, va) in + let%bind b' = aux (b, vb) in + ok (a' @ b') + | _ -> fail @@ internal_assertion_failure "bad record path" + in + aux (tree, v) diff --git a/src/transpiler/transpiler.ml b/src/passes/6-transpiler/transpiler.ml similarity index 61% rename from src/transpiler/transpiler.ml rename to src/passes/6-transpiler/transpiler.ml index 7d4db9321..ef3207d2b 100644 --- a/src/transpiler/transpiler.ml +++ b/src/passes/6-transpiler/transpiler.ml @@ -1,20 +1,16 @@ open! Trace +open Helpers module AST = Ast_typed module Append_tree = Tree.Append open AST.Combinators open Mini_c -open Combinators + +let untranspile = Untranspiler.untranspile let temp_unwrap_loc = Location.unwrap let temp_unwrap_loc_list = List.map Location.unwrap -let list_of_map m = List.rev @@ Map.String.fold (fun _ v prev -> v :: prev) m [] -let kv_list_of_map m = List.rev @@ Map.String.fold (fun k v prev -> (k, v) :: prev) m [] -let map_of_kv_list lst = - let open AST.SMap in - List.fold_left (fun prev (k, v) -> add k v prev) empty lst - module Errors = struct let corner_case ~loc message = let title () = "corner case" in @@ -58,6 +54,15 @@ them. please report this to the developers." in ] in error ~data title content + let bad_big_map location = + let title () = "bad arguments for main" in + let content () = "only one big_map per program which must appear + on the left hand side of a pair in the contract's storage" in + let data = [ + ("location" , fun () -> Format.asprintf "%a" Location.pp location) ; + ] in + error ~data title content + let missing_entry_point name = let title () = "missing entry point" in let content () = "no entry point with the given name" in @@ -95,7 +100,7 @@ them. please report this to the developers." in end open Errors -let rec translate_type (t:AST.type_value) : type_value result = +let rec transpile_type (t:AST.type_value) : type_value result = match t.type_value' with | T_constant ("bool", []) -> ok (T_base Base_bool) | T_constant ("int", []) -> ok (T_base Base_int) @@ -108,19 +113,22 @@ let rec translate_type (t:AST.type_value) : type_value result = | T_constant ("unit", []) -> ok (T_base Base_unit) | T_constant ("operation", []) -> ok (T_base Base_operation) | T_constant ("contract", [x]) -> - let%bind x' = translate_type x in + let%bind x' = transpile_type x in ok (T_contract x') | T_constant ("map", [key;value]) -> - let%bind kv' = bind_map_pair translate_type (key, value) in + let%bind kv' = bind_map_pair transpile_type (key, value) in ok (T_map kv') + | T_constant ("big_map", [key;value] ) -> + let%bind kv' = bind_map_pair transpile_type (key, value) in + ok (T_big_map kv') | T_constant ("list", [t]) -> - let%bind t' = translate_type t in + let%bind t' = transpile_type t in ok (T_list t') | T_constant ("set", [t]) -> - let%bind t' = translate_type t in + let%bind t' = transpile_type t in ok (T_set t') | T_constant ("option", [o]) -> - let%bind o' = translate_type o in + let%bind o' = transpile_type o in ok (T_option o') | T_constant (name , _lst) -> fail @@ unrecognized_type_constant name | T_sum m -> @@ -130,7 +138,7 @@ let rec translate_type (t:AST.type_value) : type_value result = let%bind b = b in ok (T_or (a, b)) in - Append_tree.fold_ne translate_type aux node + Append_tree.fold_ne transpile_type aux node | T_record m -> let node = Append_tree.of_list @@ list_of_map m in let aux a b : type_value result = @@ -138,7 +146,7 @@ let rec translate_type (t:AST.type_value) : type_value result = let%bind b = b in ok (T_pair (a, b)) in - Append_tree.fold_ne translate_type aux node + Append_tree.fold_ne transpile_type aux node | T_tuple lst -> let node = Append_tree.of_list lst in let aux a b : type_value result = @@ -146,10 +154,10 @@ let rec translate_type (t:AST.type_value) : type_value result = let%bind b = b in ok (T_pair (a, b)) in - Append_tree.fold_ne translate_type aux node + Append_tree.fold_ne transpile_type aux node | T_function (param, result) -> ( - let%bind param' = translate_type param in - let%bind result' = translate_type result in + let%bind param' = transpile_type param in + let%bind result' = transpile_type result in ok (T_function (param', result')) ) @@ -191,12 +199,12 @@ let record_access_to_lr : type_value -> type_value AST.type_name_map -> string - bind_fold_list aux (ty , []) lr_path in ok lst -let rec translate_literal : AST.literal -> value = fun l -> match l with +let rec transpile_literal : AST.literal -> value = fun l -> match l with | Literal_bool b -> D_bool b | Literal_int n -> D_int n | Literal_nat n -> D_nat n | Literal_timestamp n -> D_timestamp n - | Literal_tez n -> D_tez n + | Literal_mutez n -> D_mutez n | Literal_bytes s -> D_bytes s | Literal_string s -> D_string s | Literal_address s -> D_string s @@ -206,12 +214,12 @@ let rec translate_literal : AST.literal -> value = fun l -> match l with and transpile_environment_element_type : AST.environment_element -> type_value result = fun ele -> match (AST.get_type' ele.type_value , ele.definition) with | (AST.T_function (f , arg) , ED_declaration (ae , ((_ :: _) as captured_variables)) ) -> - let%bind f' = translate_type f in - let%bind arg' = translate_type arg in + let%bind f' = transpile_type f in + let%bind arg' = transpile_type arg in let%bind env' = transpile_environment ae.environment in let sub_env = Mini_c.Environment.select captured_variables env' in ok @@ Combinators.t_deep_closure sub_env f' arg' - | _ -> translate_type ele.type_value + | _ -> transpile_type ele.type_value and transpile_small_environment : AST.small_environment -> Environment.t result = fun x -> let x' = AST.Environment.Small.get_environment x in @@ -231,10 +239,10 @@ and tree_of_sum : AST.type_value -> (type_name * AST.type_value) Append_tree.t r let%bind map_tv = get_t_sum t in ok @@ Append_tree.of_list @@ kv_list_of_map map_tv -and translate_annotated_expression (ae:AST.annotated_expression) : expression result = - let%bind tv = translate_type ae.type_annotation in +and transpile_annotated_expression (ae:AST.annotated_expression) : expression result = + let%bind tv = transpile_type ae.type_annotation in let return ?(tv = tv) expr = ok @@ Combinators.Expression.make_tpl (expr, tv) in - let f = translate_annotated_expression in + let f = transpile_annotated_expression in let info = let title () = "translating expression" in let content () = Format.asprintf "%a" Location.pp ae.location in @@ -242,14 +250,14 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re trace info @@ match ae.expression with | E_let_in {binder; rhs; result} -> - let%bind rhs' = translate_annotated_expression rhs in - let%bind result' = translate_annotated_expression result in + let%bind rhs' = transpile_annotated_expression rhs in + let%bind result' = transpile_annotated_expression result in return (E_let_in ((binder, rhs'.type_value), rhs', result')) | E_failwith ae -> ( - let%bind ae' = translate_annotated_expression ae in + let%bind ae' = transpile_annotated_expression ae in return @@ E_constant ("FAILWITH" , [ae']) ) - | E_literal l -> return @@ E_literal (translate_literal l) + | E_literal l -> return @@ E_literal (transpile_literal l) | E_variable name -> ( let%bind ele = trace_option (corner_case ~loc:__LOC__ "name not in environment") @@ @@ -258,11 +266,11 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re return ~tv @@ E_variable name ) | E_application (a, b) -> - let%bind a = translate_annotated_expression a in - let%bind b = translate_annotated_expression b in + let%bind a = transpile_annotated_expression a in + let%bind b = transpile_annotated_expression b in return @@ E_application (a, b) | E_constructor (m, param) -> ( - let%bind param' = translate_annotated_expression param in + let%bind param' = transpile_annotated_expression param in let (param'_expr , param'_tv) = Combinators.Expression.(get_content param' , get_type param') in let%bind node_tv = trace_strong (corner_case ~loc:__LOC__ "getting lr tree") @@ @@ -274,7 +282,7 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re @@ AST.assert_type_value_eq (tv, param.type_annotation) in ok (Some (param'_expr), param'_tv) ) else ( - let%bind tv = translate_type tv in + let%bind tv = transpile_type tv in ok (None, tv) ) in let node a b : (expression' option * type_value) result = @@ -302,14 +310,14 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re let tv = T_pair (a_ty , b_ty) in return ~tv @@ E_constant ("PAIR", [a; b]) in - Append_tree.fold_ne (translate_annotated_expression) aux node + Append_tree.fold_ne (transpile_annotated_expression) aux node ) | E_tuple_accessor (tpl, ind) -> ( - let%bind ty' = translate_type tpl.type_annotation in + let%bind ty' = transpile_type tpl.type_annotation in let%bind ty_lst = trace_strong (corner_case ~loc:__LOC__ "not a tuple") @@ get_t_tuple tpl.type_annotation in - let%bind ty'_lst = bind_map_list translate_type ty_lst in + let%bind ty'_lst = bind_map_list transpile_type ty_lst in let%bind path = trace_strong (corner_case ~loc:__LOC__ "tuple access") @@ tuple_access_to_lr ty' ty'_lst ind in @@ -318,7 +326,7 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re | `Left -> "CAR" | `Right -> "CDR" in Combinators.Expression.make_tpl (E_constant (c, [pred]) , ty) in - let%bind tpl' = translate_annotated_expression tpl in + let%bind tpl' = transpile_annotated_expression tpl in let expr = List.fold_left aux tpl' path in ok expr ) @@ -333,14 +341,14 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re return ~tv @@ E_constant ("PAIR", [a; b]) in trace_strong (corner_case ~loc:__LOC__ "record build") @@ - Append_tree.fold_ne (translate_annotated_expression) aux node + Append_tree.fold_ne (transpile_annotated_expression) aux node ) | E_record_accessor (record, property) -> - let%bind ty' = translate_type (get_type_annotation record) in + let%bind ty' = transpile_type (get_type_annotation record) in let%bind ty_smap = trace_strong (corner_case ~loc:__LOC__ "not a record") @@ get_t_record (get_type_annotation record) in - let%bind ty'_smap = bind_map_smap translate_type ty_smap in + let%bind ty'_smap = bind_map_smap transpile_type ty_smap in let%bind path = trace_strong (corner_case ~loc:__LOC__ "record access") @@ record_access_to_lr ty' ty'_smap property in @@ -349,51 +357,60 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re | `Left -> "CAR" | `Right -> "CDR" in Combinators.Expression.make_tpl (E_constant (c, [pred]) , ty) in - let%bind record' = translate_annotated_expression record in + let%bind record' = transpile_annotated_expression record in let expr = List.fold_left aux record' path in ok expr | E_constant (name , lst) -> ( - let (iter , map) = - let iterator name = fun (lst : AST.annotated_expression list) -> match lst with - | [i ; f] -> ( - let%bind f' = match f.expression with - | E_lambda l -> ( - let%bind body' = translate_annotated_expression l.result in - let%bind input' = translate_type l.input_type in - ok ((l.binder , input') , body') - ) - | E_variable v -> ( - let%bind elt = - trace_option (corner_case ~loc:__LOC__ "missing var") @@ - AST.Environment.get_opt v f.environment in - match elt.definition with - | ED_declaration (f , _) -> ( - match f.expression with - | E_lambda l -> ( - let%bind body' = translate_annotated_expression l.result in - let%bind input' = translate_type l.input_type in - ok ((l.binder , input') , body') - ) - | _ -> fail @@ unsupported_iterator f.location - ) - | _ -> fail @@ unsupported_iterator f.location - ) - | _ -> fail @@ unsupported_iterator f.location - in - let%bind i' = translate_annotated_expression i in - return @@ E_iterator (name , f' , i') - ) - | _ -> fail @@ corner_case ~loc:__LOC__ "bad iterator arity" + let iterator_generator iterator_name = + let lambda_to_iterator_body (f : AST.annotated_expression) (l : AST.lambda) = + let%bind body' = transpile_annotated_expression l.body in + let%bind (input , _) = AST.get_t_function f.type_annotation in + let%bind input' = transpile_type input in + ok ((l.binder , input') , body') in - iterator "ITER" , iterator "MAP" in + let expression_to_iterator_body (f : AST.annotated_expression) = + match f.expression with + | E_lambda l -> lambda_to_iterator_body f l + | E_variable v -> ( + let%bind elt = + trace_option (corner_case ~loc:__LOC__ "missing var") @@ + AST.Environment.get_opt v f.environment in + match elt.definition with + | ED_declaration (f , _) -> ( + match f.expression with + | E_lambda l -> lambda_to_iterator_body f l + | _ -> fail @@ unsupported_iterator f.location + ) + | _ -> fail @@ unsupported_iterator f.location + ) + | _ -> fail @@ unsupported_iterator f.location + in + fun (lst : AST.annotated_expression list) -> match (lst , iterator_name) with + | [i ; f] , "ITER" | [i ; f] , "MAP" -> ( + let%bind f' = expression_to_iterator_body f in + let%bind i' = transpile_annotated_expression i in + return @@ E_iterator (iterator_name , f' , i') + ) + | [ collection ; initial ; f ] , "FOLD" -> ( + let%bind f' = expression_to_iterator_body f in + let%bind initial' = transpile_annotated_expression initial in + let%bind collection' = transpile_annotated_expression collection in + return @@ E_fold (f' , collection' , initial') + ) + | _ -> fail @@ corner_case ~loc:__LOC__ ("bad iterator arity:" ^ iterator_name) + in + let (iter , map , fold) = iterator_generator "ITER" , iterator_generator "MAP" , iterator_generator "FOLD" in match (name , lst) with | ("SET_ITER" , lst) -> iter lst | ("LIST_ITER" , lst) -> iter lst | ("MAP_ITER" , lst) -> iter lst | ("LIST_MAP" , lst) -> map lst | ("MAP_MAP" , lst) -> map lst + | ("LIST_FOLD" , lst) -> fold lst + | ("SET_FOLD" , lst) -> fold lst + | ("MAP_FOLD" , lst) -> fold lst | _ -> ( - let%bind lst' = bind_map_list (translate_annotated_expression) lst in + let%bind lst' = bind_map_list (transpile_annotated_expression) lst in return @@ E_constant (name , lst') ) ) @@ -401,12 +418,13 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re let%bind env = trace_strong (corner_case ~loc:__LOC__ "environment") @@ transpile_environment ae.environment in - translate_lambda env l + let%bind io = AST.get_t_function ae.type_annotation in + transpile_lambda env l io | E_list lst -> ( let%bind t = trace_strong (corner_case ~loc:__LOC__ "not a list") @@ - Mini_c.Combinators.get_t_list tv in - let%bind lst' = bind_map_list (translate_annotated_expression) lst in + get_t_list tv in + let%bind lst' = bind_map_list (transpile_annotated_expression) lst in let aux : expression -> expression -> expression result = fun prev cur -> return @@ E_constant ("CONS", [cur ; prev]) in let%bind (init : expression) = return @@ E_make_empty_list t in @@ -415,8 +433,8 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re | E_set lst -> ( let%bind t = trace_strong (corner_case ~loc:__LOC__ "not a set") @@ - Mini_c.Combinators.get_t_set tv in - let%bind lst' = bind_map_list (translate_annotated_expression) lst in + get_t_set tv in + let%bind lst' = bind_map_list (transpile_annotated_expression) lst in let aux : expression -> expression -> expression result = fun prev cur -> return @@ E_constant ("SET_ADD", [cur ; prev]) in let%bind (init : expression) = return @@ E_make_empty_set t in @@ -430,7 +448,21 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re let%bind prev' = prev in let%bind (k', v') = let v' = e_a_some v ae.environment in - bind_map_pair (translate_annotated_expression) (k , v') in + bind_map_pair (transpile_annotated_expression) (k , v') in + return @@ E_constant ("UPDATE", [k' ; v' ; prev']) + in + let init = return @@ E_make_empty_map (src, dst) in + List.fold_left aux init m + ) + | E_big_map m -> ( + let%bind (src, dst) = + trace_strong (corner_case ~loc:__LOC__ "not a map") @@ + Mini_c.Combinators.get_t_big_map tv in + let aux : expression result -> (AST.ae * AST.ae) -> expression result = fun prev (k, v) -> + let%bind prev' = prev in + let%bind (k', v') = + let v' = e_a_some v ae.environment in + bind_map_pair (transpile_annotated_expression) (k , v') in return @@ E_constant ("UPDATE", [k' ; v' ; prev']) in let init = return @@ E_make_empty_map (src, dst) in @@ -441,26 +473,26 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re return @@ E_constant ("MAP_GET", [i' ; ds']) ) | E_sequence (a , b) -> ( - let%bind a' = translate_annotated_expression a in - let%bind b' = translate_annotated_expression b in + let%bind a' = transpile_annotated_expression a in + let%bind b' = transpile_annotated_expression b in return @@ E_sequence (a' , b') ) | E_loop (expr , body) -> ( - let%bind expr' = translate_annotated_expression expr in - let%bind body' = translate_annotated_expression body in + let%bind expr' = transpile_annotated_expression expr in + let%bind body' = transpile_annotated_expression body in return @@ E_while (expr' , body') ) | E_assign (typed_name , path , expr) -> ( let ty = typed_name.type_value in let aux : ((AST.type_value * [`Left | `Right] list) as 'a) -> AST.access -> 'a result = fun (prev, acc) cur -> - let%bind ty' = translate_type prev in + let%bind ty' = transpile_type prev in match cur with | Access_tuple ind -> ( let%bind ty_lst = trace_strong (corner_case ~loc:__LOC__ "not a tuple") @@ AST.Combinators.get_t_tuple prev in - let%bind ty'_lst = bind_map_list translate_type ty_lst in + let%bind ty'_lst = bind_map_list transpile_type ty_lst in let%bind path = tuple_access_to_lr ty' ty'_lst ind in let path' = List.map snd path in ok (List.nth ty_lst ind, acc @ path') @@ -469,7 +501,7 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re let%bind ty_map = trace_strong (corner_case ~loc:__LOC__ "not a record") @@ AST.Combinators.get_t_record prev in - let%bind ty'_map = bind_map_smap translate_type ty_map in + let%bind ty'_map = bind_map_smap transpile_type ty_map in let%bind path = record_access_to_lr ty' ty'_map prop in let path' = List.map snd path in ok (Map.String.find prop ty_map, acc @ path') @@ -477,22 +509,36 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re | Access_map _k -> fail (corner_case ~loc:__LOC__ "no patch for map yet") in let%bind (_, path) = bind_fold_right_list aux (ty, []) path in - let%bind expr' = translate_annotated_expression expr in + let%bind expr' = transpile_annotated_expression expr in return (E_assignment (typed_name.type_name, path, expr')) ) | E_matching (expr, m) -> ( - let%bind expr' = translate_annotated_expression expr in + let%bind expr' = transpile_annotated_expression expr in match m with | Match_bool {match_true ; match_false} -> - let%bind (t , f) = bind_map_pair (translate_annotated_expression) (match_true, match_false) in + let%bind (t , f) = bind_map_pair (transpile_annotated_expression) (match_true, match_false) in return @@ E_if_bool (expr', t, f) | Match_option { match_none; match_some = ((name, tv), s) } -> - let%bind n = translate_annotated_expression match_none in + let%bind n = transpile_annotated_expression match_none in let%bind (tv' , s') = - let%bind tv' = translate_type tv in - let%bind s' = translate_annotated_expression s in - ok (tv' , s') in + let%bind tv' = transpile_type tv in + let%bind s' = transpile_annotated_expression s in + ok (tv' , s') + in return @@ E_if_none (expr' , n , ((name , tv') , s')) + | Match_list { + match_nil ; + match_cons = (((hd_name , hd_ty) , (tl_name , tl_ty)) , match_cons) ; + } -> ( + let%bind nil = transpile_annotated_expression match_nil in + let%bind cons = + let%bind hd_ty' = transpile_type hd_ty in + let%bind tl_ty' = transpile_type tl_ty in + let%bind match_cons' = transpile_annotated_expression match_cons in + ok (((hd_name , hd_ty') , (tl_name , tl_ty')) , match_cons') + in + return @@ E_if_cons (expr' , nil , cons) + ) | Match_variant (lst , variant) -> ( let%bind tree = trace_strong (corner_case ~loc:__LOC__ "getting lr tree") @@ @@ -504,7 +550,7 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re let rec aux t = match (t : _ Append_tree.t') with | Leaf (name , tv) -> - let%bind tv' = translate_type tv in + let%bind tv' = transpile_type tv in ok (`Leaf name , tv') | Node {a ; b} -> let%bind a' = aux a in @@ -520,7 +566,7 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re let%bind ((_ , name) , body) = trace_option (corner_case ~loc:__LOC__ "missing match clause") @@ List.find_opt (fun ((constructor_name' , _) , _) -> constructor_name' = constructor_name) lst in - let%bind body' = translate_annotated_expression body in + let%bind body' = transpile_annotated_expression body in return @@ E_let_in ((name , tv) , top , body') ) | ((`Node (a , b)) , tv) -> @@ -541,110 +587,82 @@ and translate_annotated_expression (ae:AST.annotated_expression) : expression re trace_strong (corner_case ~loc:__LOC__ "building constructor") @@ aux expr' tree'' ) - | AST.Match_list _ -> fail @@ unsupported_pattern_matching "list" ae.location | AST.Match_tuple _ -> fail @@ unsupported_pattern_matching "tuple" ae.location ) -and translate_lambda_deep : Mini_c.Environment.t -> AST.lambda -> Mini_c.expression result = fun env l -> - let { binder ; input_type ; output_type ; result } : AST.lambda = l in +and transpile_lambda_deep : Mini_c.Environment.t -> AST.lambda -> _ -> Mini_c.expression result = + fun env l (input_type , output_type)-> + let { binder ; body } : AST.lambda = l in (* Deep capture. Capture the relevant part of the environment. *) let%bind c_env = let free_variables = Ast_typed.Free_variables.lambda [] l in let sub_env = Mini_c.Environment.select free_variables env in ok sub_env in let%bind (f_expr' , input_tv , output_tv) = - let%bind raw_input = translate_type input_type in - let%bind output = translate_type output_type in - let%bind result = translate_annotated_expression result in - let expr' = E_closure { binder ; result } in + let%bind raw_input = transpile_type input_type in + let%bind output = transpile_type output_type in + let%bind body = transpile_annotated_expression body in + let expr' = E_closure { binder ; body } in ok (expr' , raw_input , output) in let tv = Mini_c.t_deep_closure c_env input_tv output_tv in ok @@ Expression.make_tpl (f_expr' , tv) -and translate_lambda env l = - let { binder ; input_type ; output_type ; result } : AST.lambda = l in - (* Try to translate it in an empty env, if it succeeds, transpiles it as a quote value, else, as a closure expression. *) - let fvs = AST.Free_variables.(annotated_expression (singleton binder) result) in +and transpile_lambda env l (input_type , output_type) = + let { binder ; body } : AST.lambda = l in + let fvs = AST.Free_variables.(annotated_expression (singleton binder) body) in let%bind result = match fvs with | [] -> ( - let%bind result' = translate_annotated_expression result in - let result' = ez_e_return result' in - let%bind input = translate_type input_type in - let%bind output = translate_type output_type in + let%bind result' = transpile_annotated_expression body in + let%bind input = transpile_type input_type in + let%bind output = transpile_type output_type in let tv = Combinators.t_function input output in - let content = D_function {binder;result=result'} in + let content = D_function { binder ; body = result'} in ok @@ Combinators.Expression.make_tpl (E_literal content , tv) ) | _ -> ( - translate_lambda_deep env l + transpile_lambda_deep env l (input_type , output_type) ) in ok result -let translate_declaration env (d:AST.declaration) : toplevel_statement result = +let transpile_declaration env (d:AST.declaration) : toplevel_statement result = match d with | Declaration_constant ({name;annotated_expression} , _) -> - let%bind expression = translate_annotated_expression annotated_expression in + let%bind expression = transpile_annotated_expression annotated_expression in let tv = Combinators.Expression.get_type expression in let env' = Environment.add (name, tv) env in ok @@ ((name, expression), environment_wrap env env') -let translate_program (lst:AST.program) : program result = +let transpile_program (lst : AST.program) : program result = let aux (prev:(toplevel_statement list * Environment.t) result) cur = - let%bind (tl, env) = prev in - let%bind ((_, env') as cur') = translate_declaration env cur in - ok (cur' :: tl, env'.post_environment) + let%bind (hds, env) = prev in + let%bind ((_, env') as cur') = transpile_declaration env cur in + ok (hds @ [ cur' ], env'.post_environment) in let%bind (statements, _) = List.fold_left aux (ok ([], Environment.empty)) (temp_unwrap_loc_list lst) in ok statements -let translate_main (l:AST.lambda) loc : (anon_function * _) result = - let%bind expr = translate_lambda Environment.empty l in - match expr.content , expr.type_value with - | E_literal (D_function f) , T_function ty -> ok (f , ty) - | _ -> fail @@ not_functional_main loc - -(* From an expression [expr], build the expression [fun () -> expr] *) -let functionalize (e:AST.annotated_expression) : AST.lambda * AST.type_value = - let t = e.type_annotation in - let open! AST in - { - binder = "_" ; - input_type = Combinators.t_unit () ; - output_type = t ; - result = e ; - }, Combinators.(t_function (t_unit ()) t ()) - -let translate_entry (lst:AST.program) (name:string) : (anon_function * _) result = - let rec aux acc (lst:AST.program) = - let%bind acc = acc in - match lst with - | [] -> fail @@ missing_entry_point name - | hd :: tl -> ( - let (AST.Declaration_constant (an , (pre_env , _))) = temp_unwrap_loc hd in - match an.name = name with - | false -> ( - let next = fun expr -> - let cur = e_a_let_in an.name an.annotated_expression expr pre_env in - acc cur in - aux (ok next) tl - ) - | true -> ( - match an.annotated_expression.expression with - | E_lambda l -> - let l' = { l with result = acc l.result } in - translate_main l' an.annotated_expression.location - | _ -> - let (l , _) = functionalize an.annotated_expression in - let l' = { l with result = acc l.result } in - translate_main l' an.annotated_expression.location - ) - ) +(* check whether the storage contains a big_map, if yes, check that + it appears on the left hand side of a pair *) +let check_storage f ty loc : (anon_function * _) result = + let rec aux (t:type_value) on_big_map = + match t with + | T_big_map _ -> on_big_map + | T_pair (a , b) -> (aux a true) && (aux b false) + | T_or (a,b) -> (aux a false) && (aux b false) + | T_function (a,b) -> (aux a false) && (aux b false) + | T_deep_closure (_,a,b) -> (aux a false) && (aux b false) + | T_map (a,b) -> (aux a false) && (aux b false) + | T_list a -> (aux a false) + | T_set a -> (aux a false) + | T_contract a -> (aux a false) + | T_option a -> (aux a false) + | _ -> true in - let%bind l = aux (ok (fun x -> x)) lst in - ok l - -open Combinators + match f.body.type_value with + | T_pair (_, storage) -> + if aux storage false then ok (f, ty) else fail @@ bad_big_map loc + | _ -> ok (f, ty) let extract_constructor (v : value) (tree : _ Append_tree.t') : (string * value * AST.type_value) result = let open Append_tree in @@ -683,146 +701,3 @@ let extract_record (v : value) (tree : _ Append_tree.t') : (_ list) result = | _ -> fail @@ internal_assertion_failure "bad record path" in aux (tree, v) - -let rec untranspile (v : value) (t : AST.type_value) : AST.annotated_expression result = - let open! AST in - let return e = ok (make_a_e_empty e t) in - match t.type_value' with - | T_constant ("unit", []) -> ( - let%bind () = - trace_strong (wrong_mini_c_value "unit" v) @@ - get_unit v in - return (E_literal Literal_unit) - ) - | T_constant ("bool", []) -> ( - let%bind b = - trace_strong (wrong_mini_c_value "bool" v) @@ - get_bool v in - return (E_literal (Literal_bool b)) - ) - | T_constant ("int", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "int" v) @@ - get_int v in - return (E_literal (Literal_int n)) - ) - | T_constant ("nat", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "nat" v) @@ - get_nat v in - return (E_literal (Literal_nat n)) - ) - | T_constant ("timestamp", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "timestamp" v) @@ - get_timestamp v in - return (E_literal (Literal_timestamp n)) - ) - | T_constant ("tez", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "tez" v) @@ - get_nat v in - return (E_literal (Literal_tez n)) - ) - | T_constant ("string", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "string" v) @@ - get_string v in - return (E_literal (Literal_string n)) - ) - | T_constant ("bytes", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "bytes" v) @@ - get_bytes v in - return (E_literal (Literal_bytes n)) - ) - | T_constant ("address", []) -> ( - let%bind n = - trace_strong (wrong_mini_c_value "address" v) @@ - get_string v in - return (E_literal (Literal_address n)) - ) - | T_constant ("option", [o]) -> ( - let%bind opt = - trace_strong (wrong_mini_c_value "option" v) @@ - get_option v in - match opt with - | None -> ok (e_a_empty_none o) - | Some s -> - let%bind s' = untranspile s o in - ok (e_a_empty_some s') - ) - | T_constant ("map", [k_ty;v_ty]) -> ( - let%bind lst = - trace_strong (wrong_mini_c_value "map" v) @@ - get_map v in - let%bind lst' = - let aux = fun (k, v) -> - let%bind k' = untranspile k k_ty in - let%bind v' = untranspile v v_ty in - ok (k', v') in - bind_map_list aux lst in - return (E_map lst') - ) - | T_constant ("list", [ty]) -> ( - let%bind lst = - trace_strong (wrong_mini_c_value "list" v) @@ - get_list v in - let%bind lst' = - let aux = fun e -> untranspile e ty in - bind_map_list aux lst in - return (E_list lst') - ) - | T_constant ("set", [ty]) -> ( - let%bind lst = - trace_strong (wrong_mini_c_value "set" v) @@ - get_set v in - let%bind lst' = - let aux = fun e -> untranspile e ty in - bind_map_list aux lst in - return (E_set lst') - ) - | T_constant ("contract" , [_ty]) -> - fail @@ bad_untranspile "contract" v - | T_constant ("operation" , []) -> ( - let%bind op = - trace_strong (wrong_mini_c_value "operation" v) @@ - get_operation v in - return (E_literal (Literal_operation op)) - ) - | T_constant (name , _lst) -> - fail @@ unknown_untranspile name v - | T_sum m -> - let lst = kv_list_of_map m in - let%bind node = match Append_tree.of_list lst with - | Empty -> fail @@ corner_case ~loc:__LOC__ "empty sum type" - | Full t -> ok t - in - let%bind (name, v, tv) = - trace_strong (corner_case ~loc:__LOC__ "sum extract constructor") @@ - extract_constructor v node in - let%bind sub = untranspile v tv in - return (E_constructor (name, sub)) - | T_tuple lst -> - let%bind node = match Append_tree.of_list lst with - | Empty -> fail @@ corner_case ~loc:__LOC__ "empty tuple" - | Full t -> ok t in - let%bind tpl = - trace_strong (corner_case ~loc:__LOC__ "tuple extract") @@ - extract_tuple v node in - let%bind tpl' = bind_list - @@ List.map (fun (x, y) -> untranspile x y) tpl in - return (E_tuple tpl') - | T_record m -> - let lst = kv_list_of_map m in - let%bind node = match Append_tree.of_list lst with - | Empty -> fail @@ corner_case ~loc:__LOC__ "empty record" - | Full t -> ok t in - let%bind lst = - trace_strong (corner_case ~loc:__LOC__ "record extract") @@ - extract_record v node in - let%bind lst = bind_list - @@ List.map (fun (x, (y, z)) -> let%bind yz = untranspile y z in ok (x, yz)) lst in - let m' = map_of_kv_list lst in - return (E_record m') - | T_function _ -> fail @@ bad_untranspile "function" v diff --git a/src/passes/6-transpiler/untranspiler.ml b/src/passes/6-transpiler/untranspiler.ml new file mode 100644 index 000000000..78c41cca8 --- /dev/null +++ b/src/passes/6-transpiler/untranspiler.ml @@ -0,0 +1,205 @@ +open Helpers + +module AST = Ast_typed +module Append_tree = Tree.Append +open Mini_c +open Trace + +module Errors = struct + + let corner_case ~loc message = + let title () = "corner case" in + let content () = "we don't have a good error message for this case. we are +striving find ways to better report them and find the use-cases that generate +them. please report this to the developers." in + let data = [ + ("location" , fun () -> loc) ; + ("message" , fun () -> message) ; + ] in + error ~data title content + + let wrong_mini_c_value expected_type actual = + let title () = "illed typed intermediary value" in + let content () = "type of intermediary value doesn't match what was expected" in + let data = [ + ("expected_type" , fun () -> expected_type) ; + ("actual" , fun () -> Format.asprintf "%a" Mini_c.PP.value actual ) ; + ] in + error ~data title content + + let bad_untranspile bad_type value = + let title () = "untranspiling bad value" in + let content () = Format.asprintf "can not untranspile %s" bad_type in + let data = [ + ("bad_type" , fun () -> bad_type) ; + ("value" , fun () -> Format.asprintf "%a" Mini_c.PP.value value) ; + ] in + error ~data title content + + let unknown_untranspile unknown_type value = + let title () = "untranspiling unknown value" in + let content () = Format.asprintf "can not untranspile %s" unknown_type in + let data = [ + ("unknown_type" , fun () -> unknown_type) ; + ("value" , fun () -> Format.asprintf "%a" Mini_c.PP.value value) ; + ] in + error ~data title content + +end + +open Errors + +let rec untranspile (v : value) (t : AST.type_value) : AST.annotated_expression result = + let open! AST in + let return e = ok (make_a_e_empty e t) in + match t.type_value' with + | T_constant ("unit", []) -> ( + let%bind () = + trace_strong (wrong_mini_c_value "unit" v) @@ + get_unit v in + return (E_literal Literal_unit) + ) + | T_constant ("bool", []) -> ( + let%bind b = + trace_strong (wrong_mini_c_value "bool" v) @@ + get_bool v in + return (E_literal (Literal_bool b)) + ) + | T_constant ("int", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "int" v) @@ + get_int v in + return (E_literal (Literal_int n)) + ) + | T_constant ("nat", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "nat" v) @@ + get_nat v in + return (E_literal (Literal_nat n)) + ) + | T_constant ("timestamp", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "timestamp" v) @@ + get_timestamp v in + return (E_literal (Literal_timestamp n)) + ) + | T_constant ("tez", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "tez" v) @@ + get_mutez v in + return (E_literal (Literal_mutez n)) + ) + | T_constant ("string", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "string" v) @@ + get_string v in + return (E_literal (Literal_string n)) + ) + | T_constant ("bytes", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "bytes" v) @@ + get_bytes v in + return (E_literal (Literal_bytes n)) + ) + | T_constant ("address", []) -> ( + let%bind n = + trace_strong (wrong_mini_c_value "address" v) @@ + get_string v in + return (E_literal (Literal_address n)) + ) + | T_constant ("option", [o]) -> ( + let%bind opt = + trace_strong (wrong_mini_c_value "option" v) @@ + get_option v in + match opt with + | None -> ok (e_a_empty_none o) + | Some s -> + let%bind s' = untranspile s o in + ok (e_a_empty_some s') + ) + | T_constant ("map", [k_ty;v_ty]) -> ( + let%bind lst = + trace_strong (wrong_mini_c_value "map" v) @@ + get_map v in + let%bind lst' = + let aux = fun (k, v) -> + let%bind k' = untranspile k k_ty in + let%bind v' = untranspile v v_ty in + ok (k', v') in + bind_map_list aux lst in + return (E_map lst') + ) + | T_constant ("big_map", [k_ty;v_ty]) -> ( + let%bind lst = + trace_strong (wrong_mini_c_value "big_map" v) @@ + get_big_map v in + let%bind lst' = + let aux = fun (k, v) -> + let%bind k' = untranspile k k_ty in + let%bind v' = untranspile v v_ty in + ok (k', v') in + bind_map_list aux lst in + return (E_big_map lst') + ) + | T_constant ("list", [ty]) -> ( + let%bind lst = + trace_strong (wrong_mini_c_value "list" v) @@ + get_list v in + let%bind lst' = + let aux = fun e -> untranspile e ty in + bind_map_list aux lst in + return (E_list lst') + ) + | T_constant ("set", [ty]) -> ( + let%bind lst = + trace_strong (wrong_mini_c_value "set" v) @@ + get_set v in + let%bind lst' = + let aux = fun e -> untranspile e ty in + bind_map_list aux lst in + return (E_set lst') + ) + | T_constant ("contract" , [_ty]) -> + fail @@ bad_untranspile "contract" v + | T_constant ("operation" , []) -> ( + let%bind op = + trace_strong (wrong_mini_c_value "operation" v) @@ + get_operation v in + return (E_literal (Literal_operation op)) + ) + | T_constant (name , _lst) -> + fail @@ unknown_untranspile name v + | T_sum m -> + let lst = kv_list_of_map m in + let%bind node = match Append_tree.of_list lst with + | Empty -> fail @@ corner_case ~loc:__LOC__ "empty sum type" + | Full t -> ok t + in + let%bind (name, v, tv) = + trace_strong (corner_case ~loc:__LOC__ "sum extract constructor") @@ + extract_constructor v node in + let%bind sub = untranspile v tv in + return (E_constructor (name, sub)) + | T_tuple lst -> + let%bind node = match Append_tree.of_list lst with + | Empty -> fail @@ corner_case ~loc:__LOC__ "empty tuple" + | Full t -> ok t in + let%bind tpl = + trace_strong (corner_case ~loc:__LOC__ "tuple extract") @@ + extract_tuple v node in + let%bind tpl' = bind_list + @@ List.map (fun (x, y) -> untranspile x y) tpl in + return (E_tuple tpl') + | T_record m -> + let lst = kv_list_of_map m in + let%bind node = match Append_tree.of_list lst with + | Empty -> fail @@ corner_case ~loc:__LOC__ "empty record" + | Full t -> ok t in + let%bind lst = + trace_strong (corner_case ~loc:__LOC__ "record extract") @@ + extract_record v node in + let%bind lst = bind_list + @@ List.map (fun (x, (y, z)) -> let%bind yz = untranspile y z in ok (x, yz)) lst in + let m' = map_of_kv_list lst in + return (E_record m') + | T_function _ -> fail @@ bad_untranspile "function" v diff --git a/src/compiler/compiler.ml b/src/passes/8-compiler/compiler.ml similarity index 100% rename from src/compiler/compiler.ml rename to src/passes/8-compiler/compiler.ml diff --git a/src/compiler/compiler_environment.ml b/src/passes/8-compiler/compiler_environment.ml similarity index 98% rename from src/compiler/compiler_environment.ml rename to src/passes/8-compiler/compiler_environment.ml index c5fcd040b..a196d9c49 100644 --- a/src/compiler/compiler_environment.ml +++ b/src/passes/8-compiler/compiler_environment.ml @@ -3,6 +3,8 @@ open Mini_c open Environment open Michelson +let empty : environment = [] + let get : environment -> string -> michelson result = fun e s -> let%bind (_ , position) = let error = diff --git a/src/compiler/compiler_program.ml b/src/passes/8-compiler/compiler_program.ml similarity index 88% rename from src/compiler/compiler_program.ml rename to src/passes/8-compiler/compiler_program.ml index 789000391..ef3d19395 100644 --- a/src/compiler/compiler_program.ml +++ b/src/passes/8-compiler/compiler_program.ml @@ -1,14 +1,11 @@ open Trace open Mini_c - open Michelson - open Memory_proto_alpha.Protocol.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 +let get_operator : string -> type_value -> expression list -> predicate result = fun s ty lst -> + match Map.String.find_opt s Operators.Compiler.operators with | Some x -> ok x | None -> ( match s with @@ -35,7 +32,7 @@ let get_predicate : string -> type_value -> expression list -> predicate result | "MAP_REMOVE" -> let%bind v = match lst with | [ _ ; expr ] -> - let%bind (_, v) = Mini_c.Combinators.(get_t_map (Expression.get_type expr)) in + let%bind (_, v) = Mini_c.Combinators.(bind_map_or (get_t_map , get_t_big_map) (Expression.get_type expr)) in ok v | _ -> simple_fail "mini_c . MAP_REMOVE" in let%bind v_ty = Compiler_type.type_ v in @@ -69,7 +66,7 @@ let rec translate_value (v:value) ty : michelson result = match v with | D_int n -> ok @@ int (Z.of_int n) | D_nat n -> ok @@ int (Z.of_int n) | D_timestamp n -> ok @@ int (Z.of_int n) - | D_tez n -> ok @@ int (Z.of_int n) + | D_mutez 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 @@ -107,6 +104,15 @@ let rec translate_value (v:value) ty : michelson result = match v with let aux (a, b) = prim ~children:[a;b] D_Elt in ok @@ seq @@ List.map aux sorted ) + | D_big_map lst -> ( + let%bind (k_ty , v_ty) = get_t_big_map ty in + let%bind lst' = + let aux (k , v) = bind_pair (translate_value k k_ty , translate_value v v_ty) in + bind_map_list aux lst in + let sorted = List.sort (fun (x , _) (y , _) -> compare x y) lst' in + let aux (a, b) = prim ~children:[a;b] D_Elt in + ok @@ seq @@ List.map aux sorted + ) | D_list lst -> ( let%bind e_ty = get_t_list ty in let%bind lst' = bind_map_list (fun x -> translate_value x e_ty) lst in @@ -196,7 +202,7 @@ and translate_expression (expr:expression) (env:environment) : michelson result PP.environment env ; ok (seq [ expr_code ; dip code ]) in bind_fold_right_list aux (seq []) lst in - let%bind predicate = get_predicate str ty lst in + let%bind predicate = get_operator str ty lst in let%bind code = match (predicate, List.length lst) with | Constant c, 0 -> ok @@ seq [ pre_code ; @@ -259,6 +265,24 @@ and translate_expression (expr:expression) (env:environment) : michelson result ]) in return code ) + | E_if_cons (cond , nil , ((hd , tl) , cons)) -> ( + let%bind cond' = translate_expression cond env in + let%bind nil' = translate_expression nil env in + let s_env = + Environment.add hd + @@ Environment.add tl env + in + let%bind s' = translate_expression cons s_env in + let%bind code = ok (seq [ + cond' ; + i_if_cons (seq [ + s' ; + dip (seq [ i_drop ; i_drop ]) ; + ]) nil' + ; + ]) in + return code + ) | E_if_left (c, (l_ntv , l), (r_ntv , r)) -> ( let%bind c' = translate_expression c env in let l_env = Environment.add l_ntv env in @@ -315,6 +339,20 @@ and translate_expression (expr:expression) (env:environment) : michelson result fail error ) ) + | E_fold ((v , body) , collection , initial) -> ( + let%bind collection' = translate_expression collection env in + let%bind initial' = translate_expression initial env in + let%bind body' = translate_expression body (Environment.add v env) in + let code = seq [ + collection' ; + dip initial' ; + i_iter (seq [ + i_swap ; + i_pair ; body' ; dip i_drop ; + ]) ; + ] in + ok code + ) | E_assignment (name , lrs , expr) -> ( let%bind expr' = translate_expression expr env in let%bind get_code = Compiler_environment.get env name in @@ -364,10 +402,10 @@ and translate_expression (expr:expression) (env:environment) : michelson result ] ) -and translate_function_body ({result ; binder} : anon_function) lst input : michelson result = +and translate_function_body ({body ; binder} : anon_function) lst input : michelson result = let pre_env = Environment.of_list lst in let env = Environment.(add (binder , input) pre_env) in - let%bind expr_code = translate_expression result env in + let%bind expr_code = translate_expression body env in let%bind unpack_closure_code = Compiler_environment.unpack_closure pre_env in let code = seq [ i_comment "unpack closure env" ; diff --git a/src/compiler/compiler_type.ml b/src/passes/8-compiler/compiler_type.ml similarity index 95% rename from src/compiler/compiler_type.ml rename to src/passes/8-compiler/compiler_type.ml index 4596bd74d..b22a0d2ef 100644 --- a/src/compiler/compiler_type.ml +++ b/src/passes/8-compiler/compiler_type.ml @@ -70,6 +70,7 @@ module Ty = struct | T_or _ -> fail (not_comparable "or") | T_pair _ -> fail (not_comparable "pair") | T_map _ -> fail (not_comparable "map") + | T_big_map _ -> fail (not_comparable "big_map") | T_list _ -> fail (not_comparable "list") | T_set _ -> fail (not_comparable "set") | T_option _ -> fail (not_comparable "option") @@ -116,6 +117,10 @@ module Ty = struct let%bind (Ex_comparable_ty k') = comparable_type k in let%bind (Ex_ty v') = type_ v in ok @@ Ex_ty (map k' v') + | T_big_map (k, v) -> + let%bind (Ex_comparable_ty k') = comparable_type k in + let%bind (Ex_ty v') = type_ v in + ok @@ Ex_ty (big_map k' v') | T_list t -> let%bind (Ex_ty t') = type_ t in ok @@ Ex_ty (list t') @@ -184,6 +189,9 @@ let rec type_ : type_value -> O.michelson result = | T_map kv -> let%bind (k', v') = bind_map_pair type_ kv in ok @@ O.prim ~children:[k';v'] O.T_map + | T_big_map kv -> + let%bind (k', v') = bind_map_pair type_ kv in + ok @@ O.prim ~children:[k';v'] O.T_big_map | T_list t -> let%bind t' = type_ t in ok @@ O.prim ~children:[t'] O.T_list diff --git a/src/compiler/dune b/src/passes/8-compiler/dune similarity index 100% rename from src/compiler/dune rename to src/passes/8-compiler/dune diff --git a/src/compiler/uncompiler.ml b/src/passes/8-compiler/uncompiler.ml similarity index 70% rename from src/compiler/uncompiler.ml rename to src/passes/8-compiler/uncompiler.ml index c0f8aa16b..310d3a72f 100644 --- a/src/compiler/uncompiler.ml +++ b/src/passes/8-compiler/uncompiler.ml @@ -6,19 +6,19 @@ open Protocol open Script_typed_ir open Script_ir_translator -let rec translate_value (Ex_typed_value (ty, value)) : value result = +let rec translate_value ?bm_opt (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 + let%bind a = translate_value ?bm_opt @@ Ex_typed_value(a_ty, a) in + let%bind b = translate_value ?bm_opt @@ 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 + let%bind a = translate_value ?bm_opt @@ 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 + let%bind b = translate_value ?bm_opt @@ Ex_typed_value(b_ty, b) in ok @@ D_right b ) | (Int_t _), n -> @@ -40,7 +40,7 @@ let rec translate_value (Ex_typed_value (ty, value)) : value result = 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 + ok @@ D_mutez n | (Bool_t _), b -> ok @@ D_bool b | (String_t _), s -> @@ -71,6 +71,30 @@ let rec translate_value (Ex_typed_value (ty, value)) : value result = bind_map_list aux lst in ok @@ D_map lst' + | (Big_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.diff [] in + List.rev lst in + let%bind original_big_map = + match bm_opt with + | Some (D_big_map l) -> ok @@ l + | _ -> ok [] + (* | _ -> fail @@ simple_error "Do not have access to the original big_map" . When does this matter? *) + in + let%bind lst' = + let aux orig (k, v) = + let%bind k' = translate_value (Ex_typed_value (k_ty, k)) in + let orig_rem = List.remove_assoc k' orig in + match v with + | Some vadd -> + let%bind v' = translate_value (Ex_typed_value (v_ty, vadd)) in + if (List.mem_assoc k' orig) then ok @@ (k', v')::orig_rem + else ok @@ (k', v')::orig + | None -> ok orig_rem in + bind_fold_list aux original_big_map lst in + ok @@ D_big_map lst' | (List_t (ty, _)), lst -> let%bind lst' = let aux = fun t -> translate_value (Ex_typed_value (ty, t)) in diff --git a/src/passes/9-self_michelson/dune b/src/passes/9-self_michelson/dune new file mode 100644 index 000000000..047fe33a4 --- /dev/null +++ b/src/passes/9-self_michelson/dune @@ -0,0 +1,12 @@ +(library + (name self_michelson) + (public_name ligo.self_michelson) + (libraries + simple-utils + tezos-utils + ) + (preprocess + (pps ppx_let) + ) + (flags (:standard -w +1..62-4-9-44-40-42-48-30@39@33 -open Simple_utils )) +) diff --git a/src/passes/9-self_michelson/helpers.ml b/src/passes/9-self_michelson/helpers.ml new file mode 100644 index 000000000..4ce8670c1 --- /dev/null +++ b/src/passes/9-self_michelson/helpers.ml @@ -0,0 +1,19 @@ +open Trace +open Tezos_utils +open Michelson +open Tezos_micheline.Micheline + +type mapper = michelson -> michelson result +let rec map_expression : mapper -> michelson -> michelson result = fun f e -> + let self = map_expression f in + let%bind e' = f e in + match e' with + | Prim (l , p , lst , a) -> ( + let%bind lst' = bind_map_list self lst in + ok @@ Prim (l , p , lst' , a) + ) + | Seq (l , lst) -> ( + let%bind lst' = bind_map_list self lst in + ok @@ Seq (l , lst') + ) + | x -> ok x diff --git a/src/passes/9-self_michelson/main.ml b/src/passes/9-self_michelson/main.ml new file mode 100644 index 000000000..e69de29bb diff --git a/src/passes/9-self_michelson/self_michelson.ml b/src/passes/9-self_michelson/self_michelson.ml new file mode 100644 index 000000000..3085376e3 --- /dev/null +++ b/src/passes/9-self_michelson/self_michelson.ml @@ -0,0 +1,387 @@ +(* This file attempts to optimize Michelson code. The goal is to + reduce the code size (the size of the binary Micheline.) + + I have ignored the 'execution gas' completely, because it seems + that users will encounter code size problems earlier and more + often. +*) + +open Tezos_micheline.Micheline +open Tezos_utils.Michelson + +(* `arity p` should be `Some n` only if p is (always) an instruction + which removes n items from the stack and uses them to push 1 item, + without effects other than gas consumption. It must never fail. *) + +let arity : prim -> int option = function + | I_PACK -> Some 1 + | I_UNPACK -> Some 1 + | I_BLAKE2B -> Some 1 + | I_SHA256 -> Some 1 + | I_SHA512 -> Some 1 + | I_ABS -> Some 1 + | I_ADD -> None (* can fail for tez *) + | I_AMOUNT -> Some 0 + | I_AND -> Some 2 + | I_BALANCE -> Some 0 + | I_CAR -> Some 1 + | I_CDR -> Some 1 + | I_CHECK_SIGNATURE -> Some 3 + | I_COMPARE -> Some 2 + | I_CONCAT -> None (* sometimes 1, sometimes 2 :( *) + | I_CONS -> Some 2 + | I_CREATE_ACCOUNT -> None (* effects, kind of *) + | I_CREATE_CONTRACT -> None (* effects, kind of *) + | I_IMPLICIT_ACCOUNT -> Some 1 + | I_DIP -> None + | I_DROP -> None + | I_DUP -> None + | I_EDIV -> Some 2 + | I_EMPTY_MAP -> Some 0 + | I_EMPTY_SET -> Some 0 + | I_EQ -> Some 1 + | I_EXEC -> None (* effects *) + | I_FAILWITH -> None + | I_GE -> Some 1 + | I_GET -> Some 2 + | I_GT -> Some 1 + | I_HASH_KEY -> Some 1 + | I_IF -> None + | I_IF_CONS -> None + | I_IF_LEFT -> None + | I_IF_NONE -> None + | I_INT -> Some 1 + | I_LAMBDA -> Some 0 + | I_LE -> Some 1 + | I_LEFT -> Some 1 + | I_LOOP -> None + | I_LSL -> Some 1 + | I_LSR -> Some 1 + | I_LT -> Some 1 + | I_MAP -> None + | I_MEM -> Some 2 + | I_MUL -> None (* can fail for tez *) + | I_NEG -> Some 1 + | I_NEQ -> Some 1 + | I_NIL -> Some 0 + | I_NONE -> Some 0 + | I_NOT -> Some 1 + | I_NOW -> Some 0 + | I_OR -> Some 2 + | I_PAIR -> Some 2 + | I_PUSH -> Some 0 + | I_RIGHT -> Some 1 + | I_SIZE -> Some 1 + | I_SOME -> Some 1 + | I_SOURCE -> Some 0 + | I_SENDER -> Some 0 + | I_SELF -> Some 0 + | I_SLICE -> Some 3 + | I_STEPS_TO_QUOTA -> Some 0 + | I_SUB -> None (* can fail for tez *) + | I_SWAP -> None + | I_TRANSFER_TOKENS -> None (* effects, kind of *) + | I_SET_DELEGATE -> None (* effects, kind of *) + | I_UNIT -> Some 0 + | I_UPDATE -> Some 3 + | I_XOR -> Some 2 + | I_ITER -> None + | I_LOOP_LEFT -> None + | I_ADDRESS -> Some 1 + | I_CONTRACT -> Some 1 + | I_ISNAT -> Some 1 + | I_CAST -> None + | I_RENAME -> None + + | K_parameter + | K_storage + | K_code + | D_False + | D_Elt + | D_Left + | D_None + | D_Pair + | D_Right + | D_Some + | D_True + | D_Unit + | T_bool + | T_contract + | T_int + | T_key + | T_key_hash + | T_lambda + | T_list + | T_map + | T_big_map + | T_nat + | T_option + | T_or + | T_pair + | T_set + | T_signature + | T_string + | T_bytes + | T_mutez + | T_timestamp + | T_unit + | T_operation + | T_address -> None + +let is_nullary_op (p : prim) : bool = + match arity p with + | Some 0 -> true + | _ -> false + +let is_unary_op (p : prim) : bool = + match arity p with + | Some 1 -> true + | _ -> false + +let is_binary_op (p : prim) : bool = + match arity p with + | Some 2 -> true + | _ -> false + +let is_ternary_op (p : prim) : bool = + match arity p with + | Some 3 -> true + | _ -> false + +let unseq : michelson -> michelson list = function + | Seq (_, args) -> args + | x -> [x] + +(* Replace `PUSH (lambda a b) {}` with `LAMBDA a b {}` *) +let rec use_lambda_instr : michelson -> michelson = + fun x -> + match x with + | Seq (l, args) -> + Seq (l, List.map use_lambda_instr args) + | Prim (_, I_PUSH, [Prim (_, T_lambda, [arg; ret], _); code], _) -> + i_lambda arg ret code + | Prim (_, I_PUSH, _, _) -> + x (* possibly missing some nested lambdas *) + | Prim (l, p, args, annot) -> + Prim (l, p, List.map use_lambda_instr args, annot) + | _ -> x + +(* This flattens nested seqs. {} is erased, { { code1 } ; { code2 } } + becomes { code1 ; code2 }, etc. This is important because each seq + costs 5 bytes, for the "Seq" tag and a 4 byte length. *) +let rec flatten_seqs : michelson -> michelson = + fun x -> + match x with + | Seq (l, args) -> + let args = List.concat @@ List.map (fun x -> unseq (flatten_seqs x)) args in + Seq (l, args) + (* Should not flatten literal seq data in PUSH. Ugh... *) + | Prim (_, I_PUSH, _, _) -> x + | Prim (l, p, args, annot) -> Prim (l, p, List.map flatten_seqs args, annot) + | _ -> x + +type peep1 = michelson -> michelson list option +type peep2 = michelson * michelson -> michelson list option +type peep3 = michelson * michelson * michelson -> michelson list option +type peep4 = michelson * michelson * michelson * michelson -> michelson list option + +let rec peep1 (f : peep1) : michelson list -> bool * michelson list = function + | [] -> (false, []) + | x1 :: xs -> + match f x1 with + | Some xs' -> let (_, xs') = peep1 f (xs' @ xs) in + (true, xs') + | None -> let (changed, xs) = peep1 f xs in + (changed, x1 :: xs) + +let rec peep2 (f : peep2) : michelson list -> bool * michelson list = function + | [] -> (false, []) + | [x] -> (false, [x]) + | x1 :: x2 :: xs -> + match f (x1, x2) with + | Some xs' -> let (_, xs') = peep2 f (xs' @ xs) in + (true, xs') + | None -> let (changed, xs') = peep2 f (x2 :: xs) in + (changed, x1 :: xs') + +let rec peep3 (f : peep3) : michelson list -> bool * michelson list = function + | [] -> (false, []) + | [x] -> (false, [x]) + | [x ; y] -> (false, [x ; y]) + | x1 :: x2 :: x3 :: xs -> + match f (x1, x2, x3) with + | Some xs' -> let (_, xs') = peep3 f (xs' @ xs) in + (true, xs') + | None -> let (changed, xs') = peep3 f (x2 :: x3 :: xs) in + (changed, x1 :: xs') + +let rec peep4 (f : peep4) : michelson list -> bool * michelson list = function + | [] -> (false, []) + | [x] -> (false, [x]) + | [x ; y] -> (false, [x ; y]) + | [x ; y ; z] -> (false, [x ; y ; z]) + | x1 :: x2 :: x3 :: x4 :: xs -> + match f (x1, x2, x3, x4) with + | Some xs' -> let (_, xs') = peep4 f (xs' @ xs) in + (true, xs') + | None -> let (changed, xs') = peep4 f (x2 :: x3 :: x4 :: xs) in + (changed, x1 :: xs') + +(* apply f to all seqs *) +let rec peephole (f : michelson list -> bool * michelson list) : michelson -> bool * michelson = + let peep_args ~seq args = + let (changed, args) = if seq + then f args + else (false, args) in + List.fold_map_acc + (fun changed1 arg -> + let (changed2, arg) = peephole f arg in + (changed1 || changed2, arg)) + changed + args in + function + | Seq (l, args) -> let (changed, args) = peep_args ~seq:true args in + (changed, Seq (l, args)) + | Prim (l, p, args, annot) -> let (changed, args) = peep_args ~seq:false args in + (changed, Prim (l, p, args, annot)) + | x -> (false, x) + +(* apply the optimizers in order *) +let rec sequence_optimizers (fs : (michelson -> bool * michelson) list) : michelson -> bool * michelson = + match fs with + | [] -> fun x -> (false, x) + | f :: fs -> fun x -> let (changed1, x) = f x in + let (changed2, x) = sequence_optimizers fs x in + (changed1 || changed2, x) + +(* take the fixed point of an optimizer (!) *) +let rec iterate_optimizer (f : michelson -> bool * michelson) : michelson -> michelson = + fun x -> + let (changed, x) = f x in + if changed + then iterate_optimizer f x + else x + +let opt_drop2 : peep2 = function + (* nullary_op ; DROP ↦ *) + | Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_nullary_op p -> Some [] + (* DUP ; DROP ↦ *) + | Prim (_, I_DUP, _, _), Prim (_, I_DROP, _, _) -> Some [] + (* unary_op ; DROP ↦ DROP *) + | Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_unary_op p -> Some [i_drop] + (* binary_op ; DROP ↦ DROP ; DROP *) + | Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_binary_op p -> Some [i_drop; i_drop] + (* ternary_op ; DROP ↦ DROP ; DROP ; DROP *) + | Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_ternary_op p -> Some [i_drop; i_drop; i_drop] + | _ -> None + +let opt_drop4 : peep4 = function + (* DUP; unary_op; SWAP; DROP ↦ unary_op *) + | Prim (_, I_DUP, _, _), + (Prim (_, p, _, _) as unary_op), + Prim (_, I_SWAP, _, _), + Prim (_, I_DROP, _, _) + when is_unary_op p -> + Some [unary_op] + | _ -> None + +let opt_dip1 : peep1 = function + (* DIP {} ↦ *) + | Prim (_, I_DIP, [Seq (_, [])], _) -> Some [] + (* DIP { nullary_op } ↦ nullary_op ; SWAP *) + | Prim (_, I_DIP, [Seq (_, [(Prim (_, p, _, _) as push)])], _) when is_nullary_op p -> + Some [push ; i_swap] + (* DIP { unary_op } ↦ SWAP ; unary_op ; SWAP *) + | Prim (_, I_DIP, [Seq (_, [(Prim (_, p, _, _) as unary_op)])], _) when is_unary_op p -> + Some [i_swap ; unary_op ; i_swap] + (* saves 5 bytes *) + (* DIP { DROP } ↦ SWAP ; DROP *) + | Prim (_, I_DIP, [Seq (_, [Prim (_, I_DROP, _, _)])], _) -> + Some [i_swap; i_drop] + (* saves 3 bytes *) + (* DIP { DROP ; DROP } ↦ SWAP ; DROP ; SWAP ; DROP *) + | Prim (_, I_DIP, [Seq (_, [Prim (_, I_DROP, _, _) ; Prim (_, I_DROP, _, _)])], _) -> + Some [i_swap; i_drop; i_swap; i_drop] + (* still saves 1 byte *) + (* DIP { DROP ; DROP ; DROP } ↦ SWAP ; DROP ; SWAP ; DROP ; SWAP ; DROP *) + | Prim (_, I_DIP, [Seq (_, [Prim (_, I_DROP, _, _) ; Prim (_, I_DROP, _, _) ; Prim (_, I_DROP, _, _)])], _) -> + Some [i_swap; i_drop; i_swap; i_drop; i_swap; i_drop] + (* after this, DIP { DROP ; ... } is smaller *) + | _ -> None + +let opt_dip2 : peep2 = function + (* combine adjacent dips, shaving a seq and enabling further + optimization inside the DIP: *) + (* DIP { code1 } ; DIP { code2 } ↦ DIP { code1 ; code2 } *) + | Prim (_, I_DIP, [Seq (_, code1)], _), Prim (_, I_DIP, [Seq (_, code2)], _) -> + Some [Prim (0, I_DIP, [Seq (0, code1 @ code2)], [])] + (* DIP { code } ; DROP ↦ DROP ; code *) + | Prim (_, I_DIP, code, _), (Prim (_, I_DROP, _, _) as drop) -> + Some (drop :: code) + (* nullary_op ; DIP { code } ↦ code ; nullary_op *) + | (Prim (_, p, _, _) as nullary_op), Prim (_, I_DIP, [Seq (_, code)], _) when is_nullary_op p -> + Some (code @ [nullary_op]) + (* DIP { code } ; unary_op ↦ unary_op ; DIP { code } *) + | (Prim (_, I_DIP, _, _) as dip), (Prim (_, p, _, _) as unary_op) when is_unary_op p -> + Some [unary_op; dip] + (* unary_op ; DIP { code } ↦ DIP { code } ; unary_op *) + (* | (Prim (_, p, _, _) as unary_op), (Prim (_, I_DIP, _, _) as dip) when is_unary_op p -> + * Some [dip; unary_op] *) + | _ -> None + +let opt_dip3 : peep3 = function + (* replace UNPAIR/UNPIAR with a smaller version *) + (* TODO probably better to implement optimal UNPAIR in the compiler *) + (* DUP ; CAR ; DIP { CDR } ↦ DUP ; CDR ; SWAP ; CAR *) + | Prim (_, I_DUP, _, _), + (Prim (_, (I_CAR | I_CDR), _, _) as proj1), + Prim (_, I_DIP, [Seq (_, [(Prim (_, (I_CAR | I_CDR), _, _) as proj2)])], _) -> + Some [ i_dup ; proj2 ; i_swap ; proj1 ] + | _ -> None + +let opt_swap2 : peep2 = function + (* SWAP ; SWAP ↦ *) + | Prim (_, I_SWAP, _, _), Prim (_, I_SWAP, _, _) -> + Some [] + (* DUP ; SWAP ↦ DUP *) + | Prim (_, I_DUP, _, _), Prim (_, I_SWAP, _, _) -> + Some [i_dup] + (* SWAP ; ADD ↦ ADD *) + (* etc *) + | Prim (_, I_SWAP, _, _), (Prim (_, (I_ADD | I_OR | I_AND | I_XOR), _, _) as comm_op) -> + Some [comm_op] + | _ -> None + +(* This "optimization" deletes dead code produced by the compiler + after a FAILWITH, which is illegal in Michelson. This means we are + thwarting the intent of the Michelson tail fail restriction -- the + LIGO _user_ might accidentally write dead code immediately after a + failure, and we will simply erase it. *) +let rec opt_tail_fail : michelson -> michelson = + function + | Seq (l, args) -> + let rec aux args = + match args with + | [] -> [] + | Prim (l, I_FAILWITH, args, annot) :: _ -> [ Prim (l, I_FAILWITH, args, annot) ] + | arg :: args -> arg :: aux args in + let args = aux args in + Seq (l, List.map opt_tail_fail args) + | Prim (l, p, args, annot) -> + Prim (l, p, List.map opt_tail_fail args, annot) + | x -> x + +let optimize : michelson -> michelson = + fun x -> + let x = use_lambda_instr x in + let x = flatten_seqs x in + let x = opt_tail_fail x in + let optimizers = [ peephole @@ peep2 opt_drop2 ; + peephole @@ peep4 opt_drop4 ; + peephole @@ peep3 opt_dip3 ; + peephole @@ peep2 opt_dip2 ; + peephole @@ peep1 opt_dip1 ; + peephole @@ peep2 opt_swap2 ; + ] in + let x = iterate_optimizer (sequence_optimizers optimizers) x in + x diff --git a/src/operators/dune b/src/passes/operators/dune similarity index 100% rename from src/operators/dune rename to src/passes/operators/dune diff --git a/src/operators/helpers.ml b/src/passes/operators/helpers.ml similarity index 98% rename from src/operators/helpers.ml rename to src/passes/operators/helpers.ml index 8fd18a16f..b588605f2 100644 --- a/src/operators/helpers.ml +++ b/src/passes/operators/helpers.ml @@ -104,7 +104,7 @@ module Typer = struct let eq_1 a cst = type_value_eq (a , cst) let eq_2 (a , b) cst = type_value_eq (a , cst) && type_value_eq (b , cst) - let assert_eq_1 a b = Assert.assert_true (eq_1 a b) + let assert_eq_1 ?msg a b = Assert.assert_true ?msg (eq_1 a b) let comparator : string -> typer = fun s -> typer_2 s @@ fun a b -> let%bind () = diff --git a/src/operators/operators.ml b/src/passes/operators/operators.ml similarity index 85% rename from src/operators/operators.ml rename to src/passes/operators/operators.ml index 61495e0e9..ceb17f17a 100644 --- a/src/operators/operators.ml +++ b/src/passes/operators/operators.ml @@ -81,10 +81,16 @@ module Simplify = struct ("set_add" , "SET_ADD") ; ("set_remove" , "SET_REMOVE") ; ("set_iter" , "SET_ITER") ; + ("set_fold" , "SET_FOLD") ; ("list_iter" , "LIST_ITER") ; + ("list_fold" , "LIST_FOLD") ; ("list_map" , "LIST_MAP") ; ("map_iter" , "MAP_ITER") ; ("map_map" , "MAP_MAP") ; + ("map_fold" , "MAP_FOLD") ; + ("map_remove" , "MAP_REMOVE") ; + ("map_update" , "MAP_UPDATE") ; + ("map_get" , "MAP_GET") ; ("sha_256" , "SHA256") ; ("sha_512" , "SHA512") ; ("blake2b" , "BLAKE2b") ; @@ -144,14 +150,21 @@ module Simplify = struct ("Set.mem" , "SET_MEM") ; ("Set.empty" , "SET_EMPTY") ; + ("Set.literal" , "SET_LITERAL") ; ("Set.add" , "SET_ADD") ; ("Set.remove" , "SET_REMOVE") ; + ("Set.fold" , "SET_FOLD") ; ("Map.find_opt" , "MAP_FIND_OPT") ; ("Map.find" , "MAP_FIND") ; ("Map.update" , "MAP_UPDATE") ; ("Map.add" , "MAP_ADD") ; ("Map.remove" , "MAP_REMOVE") ; + ("Map.iter" , "MAP_ITER") ; + ("Map.map" , "MAP_MAP") ; + ("Map.fold" , "MAP_FOLD") ; + ("Map.empty" , "MAP_EMPTY") ; + ("Map.literal" , "MAP_LITERAL" ) ; ("String.length", "SIZE") ; ("String.size", "SIZE") ; @@ -161,7 +174,9 @@ module Simplify = struct ("List.length", "SIZE") ; ("List.size", "SIZE") ; - ("List.iter", "ITER") ; + ("List.iter", "LIST_ITER") ; + ("List.map" , "LIST_MAP") ; + ("List.fold" , "LIST_FOLD") ; ("Operation.transaction" , "CALL") ; ("Operation.get_contract" , "CONTRACT") ; @@ -235,35 +250,37 @@ module Typer = struct ok tl let map_remove : typer = typer_2 "MAP_REMOVE" @@ fun k m -> - let%bind (src , _) = get_t_map m in + let%bind (src , _) = bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_value_eq (src , k) in ok m let map_add : typer = typer_3 "MAP_ADD" @@ fun k v m -> - let%bind (src, dst) = get_t_map m in + let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_value_eq (src, k) in let%bind () = assert_type_value_eq (dst, v) in ok m let map_update : typer = typer_3 "MAP_UPDATE" @@ fun k v m -> - let%bind (src, dst) = get_t_map m in + let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_value_eq (src, k) in let%bind v' = get_t_option v in let%bind () = assert_type_value_eq (dst, v') in ok m let map_mem : typer = typer_2 "MAP_MEM" @@ fun k m -> - let%bind (src, _dst) = get_t_map m in + let%bind (src, _dst) = bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_value_eq (src, k) in ok @@ t_bool () let map_find : typer = typer_2 "MAP_FIND" @@ fun k m -> - let%bind (src, dst) = get_t_map m in + let%bind (src, dst) = + trace_strong (simple_error "MAP_FIND: not map or bigmap") @@ + bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_value_eq (src, k) in ok @@ dst let map_find_opt : typer = typer_2 "MAP_FIND_OPT" @@ fun k m -> - let%bind (src, dst) = get_t_map m in + let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_value_eq (src, k) in ok @@ t_option dst () @@ -280,49 +297,10 @@ module Typer = struct let%bind () = assert_eq_1 arg (t_pair k v ()) in ok @@ t_map k res () - let map_fold : typer = typer_2 "MAP_FOLD" @@ fun f m -> - let%bind (k, v) = get_t_map m in - let%bind (arg_1 , res) = get_t_function f in - let%bind (arg_2 , res') = get_t_function res in - let%bind (arg_3 , res'') = get_t_function res' in - let%bind () = assert_eq_1 arg_1 k in - let%bind () = assert_eq_1 arg_2 v in - let%bind () = assert_eq_1 arg_3 res'' in - ok @@ res' - - let big_map_remove : typer = typer_2 "BIG_MAP_REMOVE" @@ fun k m -> - let%bind (src , _) = get_t_big_map m in - let%bind () = assert_type_value_eq (src , k) in - ok m - - let big_map_add : typer = typer_3 "BIG_MAP_ADD" @@ fun k v m -> - let%bind (src, dst) = get_t_big_map m in - let%bind () = assert_type_value_eq (src, k) in - let%bind () = assert_type_value_eq (dst, v) in - ok m - - let big_map_update : typer = typer_3 "BIG_MAP_UPDATE" @@ fun k v m -> - let%bind (src, dst) = get_t_big_map m in - let%bind () = assert_type_value_eq (src, k) in - let%bind v' = get_t_option v in - let%bind () = assert_type_value_eq (dst, v') in - ok m - - let big_map_mem : typer = typer_2 "BIG_MAP_MEM" @@ fun k m -> - let%bind (src, _dst) = get_t_big_map m in - let%bind () = assert_type_value_eq (src, k) in - ok @@ t_bool () - - let big_map_find : typer = typer_2 "BIG_MAP_FIND" @@ fun k m -> - let%bind (src, dst) = get_t_big_map m in - let%bind () = assert_type_value_eq (src, k) in - ok @@ dst - - let size = typer_1 "SIZE" @@ fun t -> let%bind () = Assert.assert_true @@ - (is_t_map t || is_t_list t || is_t_string t || is_t_bytes t || is_t_set t || is_t_big_map t) in + (is_t_map t || is_t_list t || is_t_string t || is_t_bytes t || is_t_set t ) in ok @@ t_nat () let slice = typer_3 "SLICE" @@ fun i j s -> @@ -340,11 +318,16 @@ module Typer = struct (is_t_string t) in ok @@ t_unit () - let get_force = typer_2 "MAP_GET_FORCE" @@ fun i m -> - let%bind (src, dst) = get_t_map m in + let map_get_force = typer_2 "MAP_GET_FORCE" @@ fun i m -> + let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in let%bind _ = assert_type_value_eq (src, i) in ok dst + let map_get = typer_2 "MAP_GET" @@ fun i m -> + let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in + let%bind _ = assert_type_value_eq (src, i) in + ok @@ t_option dst () + let int : typer = typer_1 "INT" @@ fun t -> let%bind () = assert_t_nat t in ok @@ t_int () @@ -512,7 +495,49 @@ module Typer = struct let%bind key = get_t_list lst in if eq_1 key arg then ok (t_list res ()) - else simple_fail "bad list iter" + else simple_fail "bad list map" + + let list_fold = typer_3 "LIST_FOLD" @@ fun lst init body -> + let%bind (arg , res) = get_t_function body in + let%bind (prec , cur) = get_t_pair arg in + let%bind key = get_t_list lst in + let msg = Format.asprintf "%a vs %a" + Ast_typed.PP.type_value key + Ast_typed.PP.type_value arg + in + trace (simple_error ("bad list fold:" ^ msg)) @@ + let%bind () = assert_eq_1 ~msg:"key cur" key cur in + let%bind () = assert_eq_1 ~msg:"prec res" prec res in + let%bind () = assert_eq_1 ~msg:"res init" res init in + ok res + + let set_fold = typer_3 "SET_FOLD" @@ fun lst init body -> + let%bind (arg , res) = get_t_function body in + let%bind (prec , cur) = get_t_pair arg in + let%bind key = get_t_set lst in + let msg = Format.asprintf "%a vs %a" + Ast_typed.PP.type_value key + Ast_typed.PP.type_value arg + in + trace (simple_error ("bad set fold:" ^ msg)) @@ + let%bind () = assert_eq_1 ~msg:"key cur" key cur in + let%bind () = assert_eq_1 ~msg:"prec res" prec res in + let%bind () = assert_eq_1 ~msg:"res init" res init in + ok res + + let map_fold = typer_3 "MAP_FOLD" @@ fun map init body -> + let%bind (arg , res) = get_t_function body in + let%bind (prec , cur) = get_t_pair arg in + let%bind (key , value) = get_t_map map in + let msg = Format.asprintf "%a vs %a" + Ast_typed.PP.type_value key + Ast_typed.PP.type_value arg + in + trace (simple_error ("bad list fold:" ^ msg)) @@ + let%bind () = assert_eq_1 ~msg:"key cur" (t_pair key value ()) cur in + let%bind () = assert_eq_1 ~msg:"prec res" prec res in + let%bind () = assert_eq_1 ~msg:"res init" res init in + ok res let not_ = typer_1 "NOT" @@ fun elt -> if eq_1 elt (t_bool ()) @@ -592,18 +617,20 @@ module Typer = struct map_map ; map_fold ; map_iter ; - map_map ; + map_get_force ; + map_get ; set_empty ; set_mem ; set_add ; set_remove ; set_iter ; + set_fold ; list_iter ; list_map ; + list_fold ; int ; size ; failwith_ ; - get_force ; bytes_pack ; bytes_unpack ; hash256 ; @@ -646,7 +673,7 @@ module Compiler = struct include Helpers.Compiler open Tezos_utils.Michelson - let predicates = Map.String.of_list [ + let operators = Map.String.of_list [ ("ADD" , simple_binary @@ prim I_ADD) ; ("SUB" , simple_binary @@ prim I_SUB) ; ("TIMES" , simple_binary @@ prim I_MUL) ; @@ -671,10 +698,13 @@ module Compiler = struct ("MAP_GET_FORCE" , simple_binary @@ seq [prim I_GET ; i_assert_some_msg (i_push_string "GET_FORCE")]) ; ("MAP_FIND" , simple_binary @@ seq [prim I_GET ; i_assert_some_msg (i_push_string "MAP FIND")]) ; ("MAP_GET" , simple_binary @@ prim I_GET) ; + ("MAP_FIND_OPT" , simple_binary @@ prim I_GET) ; + ("MAP_ADD" , simple_ternary @@ seq [dip (i_some) ; prim I_UPDATE]) ; + ("MAP_UPDATE" , simple_ternary @@ prim I_UPDATE) ; ("SIZE" , simple_unary @@ prim I_SIZE) ; ("FAILWITH" , simple_unary @@ prim I_FAILWITH) ; ("ASSERT_INFERRED" , simple_binary @@ i_if (seq [i_failwith]) (seq [i_drop ; i_push_unit])) ; - ("ASSERT" , simple_unary @@ i_if (seq [i_push_unit ; i_failwith]) (seq [i_push_unit])) ; + ("ASSERT" , simple_unary @@ i_if (seq [i_push_unit]) (seq [i_push_unit ; i_failwith])) ; ("INT" , simple_unary @@ prim I_INT) ; ("ABS" , simple_unary @@ prim I_ABS) ; ("CONS" , simple_binary @@ prim I_CONS) ; @@ -685,8 +715,6 @@ module Compiler = struct ("CALL" , simple_ternary @@ prim I_TRANSFER_TOKENS) ; ("SOURCE" , simple_constant @@ prim I_SOURCE) ; ("SENDER" , simple_constant @@ prim I_SENDER) ; - ("MAP_ADD" , simple_ternary @@ seq [dip (i_some) ; prim I_UPDATE]) ; - ("MAP_UPDATE" , simple_ternary @@ prim I_UPDATE) ; ("SET_MEM" , simple_binary @@ prim I_MEM) ; ("SET_ADD" , simple_binary @@ seq [dip (i_push (prim T_bool) (prim D_True)) ; prim I_UPDATE]) ; ("SET_REMOVE" , simple_binary @@ seq [dip (i_push (prim T_bool) (prim D_False)) ; prim I_UPDATE]) ; @@ -701,6 +729,9 @@ module Compiler = struct ("CONS" , simple_binary @@ prim I_CONS) ; ] - (* Some complex predicates will need to be added in compiler/compiler_program *) + (* + Some complex operators will need to be added in compiler/compiler_program. + All operators whose compilations involve a type are found there. + *) end diff --git a/src/ast_simplified/PP.ml b/src/stages/ast_simplified/PP.ml similarity index 96% rename from src/ast_simplified/PP.ml rename to src/stages/ast_simplified/PP.ml index 07277c664..1fb7cb18e 100644 --- a/src/ast_simplified/PP.ml +++ b/src/stages/ast_simplified/PP.ml @@ -25,13 +25,13 @@ let literal ppf (l:literal) = match l with | Literal_int n -> fprintf ppf "%d" n | Literal_nat n -> fprintf ppf "+%d" n | Literal_timestamp n -> fprintf ppf "+%d" n - | Literal_tez n -> fprintf ppf "%dtz" n + | Literal_mutez n -> fprintf ppf "%dmtz" 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 Location.unwrap e with +let rec expression ppf (e:expression) = match e.expression with | E_literal l -> literal ppf l | E_variable name -> fprintf ppf "%s" name | E_application (f, arg) -> fprintf ppf "(%a)@(%a)" expression f expression arg @@ -41,6 +41,7 @@ let rec expression ppf (e:expression) = match Location.unwrap e with | E_accessor (ae, p) -> fprintf ppf "%a.%a" expression ae access_path p | E_record m -> fprintf ppf "record[%a]" (smap_sep_d expression) m | E_map m -> fprintf ppf "map[%a]" (list_sep_d assoc_expression) m + | E_big_map m -> fprintf ppf "big_map[%a]" (list_sep_d assoc_expression) m | E_list lst -> fprintf ppf "list[%a]" (list_sep_d expression) lst | E_set lst -> fprintf ppf "set[%a]" (list_sep_d expression) lst | E_look_up (ds, ind) -> fprintf ppf "(%a)[%a]" expression ds expression ind diff --git a/src/ast_simplified/ast_simplified.ml b/src/stages/ast_simplified/ast_simplified.ml similarity index 100% rename from src/ast_simplified/ast_simplified.ml rename to src/stages/ast_simplified/ast_simplified.ml diff --git a/src/ast_simplified/combinators.ml b/src/stages/ast_simplified/combinators.ml similarity index 62% rename from src/ast_simplified/combinators.ml rename to src/stages/ast_simplified/combinators.ml index 622e1039c..0890365d1 100644 --- a/src/ast_simplified/combinators.ml +++ b/src/stages/ast_simplified/combinators.ml @@ -43,49 +43,58 @@ let ez_t_sum (lst:(string * type_expression) list) : type_expression = let t_function param result : type_expression = T_function (param, result) let t_map key value = (T_constant ("map", [key ; value])) +let t_big_map key value = (T_constant ("big_map", [key ; value])) let t_set key = (T_constant ("set", [key])) let make_name (s : string) : name = s -let e_var ?loc (s : string) : expression = Location.wrap ?loc @@ E_variable s -let e_literal ?loc l : expression = Location.wrap ?loc @@ E_literal l -let e_unit ?loc () : expression = Location.wrap ?loc @@ E_literal (Literal_unit) -let e_int ?loc n : expression = Location.wrap ?loc @@ E_literal (Literal_int n) -let e_nat ?loc n : expression = Location.wrap ?loc @@ E_literal (Literal_nat n) -let e_timestamp ?loc n : expression = Location.wrap ?loc @@ E_literal (Literal_timestamp n) -let e_bool ?loc b : expression = Location.wrap ?loc @@ E_literal (Literal_bool b) -let e_string ?loc s : expression = Location.wrap ?loc @@ E_literal (Literal_string s) -let e_address ?loc s : expression = Location.wrap ?loc @@ E_literal (Literal_address s) -let e_tez ?loc s : expression = Location.wrap ?loc @@ E_literal (Literal_tez s) -let e_bytes ?loc b : expression result = +let location_wrap ?(loc = Location.generated) expression = + let location = loc in + { location ; expression } + +let e_var ?loc (s : string) : expression = location_wrap ?loc @@ E_variable s +let e_literal ?loc l : expression = location_wrap ?loc @@ E_literal l +let e_unit ?loc () : expression = location_wrap ?loc @@ E_literal (Literal_unit) +let e_int ?loc n : expression = location_wrap ?loc @@ E_literal (Literal_int n) +let e_nat ?loc n : expression = location_wrap ?loc @@ E_literal (Literal_nat n) +let e_timestamp ?loc n : expression = location_wrap ?loc @@ E_literal (Literal_timestamp n) +let e_bool ?loc b : expression = location_wrap ?loc @@ E_literal (Literal_bool b) +let e_string ?loc s : expression = location_wrap ?loc @@ E_literal (Literal_string s) +let e_address ?loc s : expression = location_wrap ?loc @@ E_literal (Literal_address s) +let e_mutez ?loc s : expression = location_wrap ?loc @@ E_literal (Literal_mutez s) +let e'_bytes b : expression' result = let%bind bytes = generic_try (simple_error "bad hex to bytes") (fun () -> Hex.to_bytes (`Hex b)) in - ok @@ Location.wrap ?loc @@ E_literal (Literal_bytes bytes) -let e_record ?loc map : expression = Location.wrap ?loc @@ E_record map -let e_tuple ?loc lst : expression = Location.wrap ?loc @@ E_tuple lst -let e_some ?loc s : expression = Location.wrap ?loc @@ E_constant ("SOME", [s]) -let e_none ?loc () : expression = Location.wrap ?loc @@ E_constant ("NONE", []) -let e_map_add ?loc k v old : expression = Location.wrap ?loc @@ E_constant ("MAP_ADD" , [k ; v ; old]) -let e_map ?loc lst : expression = Location.wrap ?loc @@ E_map lst -let e_set ?loc lst : expression = Location.wrap ?loc @@ E_set lst -let e_list ?loc lst : expression = Location.wrap ?loc @@ E_list lst -let e_pair ?loc a b : expression = Location.wrap ?loc @@ E_tuple [a; b] -let e_constructor ?loc s a : expression = Location.wrap ?loc @@ E_constructor (s , a) -let e_matching ?loc a b : expression = Location.wrap ?loc @@ E_matching (a , b) + ok @@ E_literal (Literal_bytes bytes) +let e_bytes ?loc b : expression result = + let%bind e' = e'_bytes b in + ok @@ location_wrap ?loc e' +let e_big_map ?loc lst : expression = location_wrap ?loc @@ E_big_map lst +let e_record ?loc map : expression = location_wrap ?loc @@ E_record map +let e_tuple ?loc lst : expression = location_wrap ?loc @@ E_tuple lst +let e_some ?loc s : expression = location_wrap ?loc @@ E_constant ("SOME", [s]) +let e_none ?loc () : expression = location_wrap ?loc @@ E_constant ("NONE", []) +let e_map_add ?loc k v old : expression = location_wrap ?loc @@ E_constant ("MAP_ADD" , [k ; v ; old]) +let e_map ?loc lst : expression = location_wrap ?loc @@ E_map lst +let e_set ?loc lst : expression = location_wrap ?loc @@ E_set lst +let e_list ?loc lst : expression = location_wrap ?loc @@ E_list lst +let e_pair ?loc a b : expression = location_wrap ?loc @@ E_tuple [a; b] +let e_constructor ?loc s a : expression = location_wrap ?loc @@ E_constructor (s , a) +let e_matching ?loc a b : expression = location_wrap ?loc @@ E_matching (a , b) let e_matching_bool ?loc a b c : expression = e_matching ?loc a (Match_bool {match_true = b ; match_false = c}) -let e_accessor ?loc a b = Location.wrap ?loc @@ E_accessor (a , b) +let e_accessor ?loc a b = location_wrap ?loc @@ E_accessor (a , b) let e_accessor_props ?loc a b = e_accessor ?loc a (List.map (fun x -> Access_record x) b) -let e_variable ?loc v = Location.wrap ?loc @@ E_variable v -let e_failwith ?loc v = Location.wrap ?loc @@ E_failwith v -let e_skip ?loc () = Location.wrap ?loc @@ E_skip -let e_loop ?loc cond body = Location.wrap ?loc @@ E_loop (cond , body) -let e_sequence ?loc a b = Location.wrap ?loc @@ E_sequence (a , b) -let e_let_in ?loc binder rhs result = Location.wrap ?loc @@ E_let_in { binder ; rhs ; result } -let e_annotation ?loc expr ty = Location.wrap ?loc @@ E_annotation (expr , ty) -let e_application ?loc a b = Location.wrap ?loc @@ E_application (a , b) -let e_binop ?loc name a b = Location.wrap ?loc @@ E_constant (name , [a ; b]) -let e_constant ?loc name lst = Location.wrap ?loc @@ E_constant (name , lst) -let e_look_up ?loc x y = Location.wrap ?loc @@ E_look_up (x , y) -let e_assign ?loc a b c = Location.wrap ?loc @@ E_assign (a , b , c) +let e_variable ?loc v = location_wrap ?loc @@ E_variable v +let e_failwith ?loc v = location_wrap ?loc @@ E_failwith v +let e_skip ?loc () = location_wrap ?loc @@ E_skip +let e_loop ?loc cond body = location_wrap ?loc @@ E_loop (cond , body) +let e_sequence ?loc a b = location_wrap ?loc @@ E_sequence (a , b) +let e_let_in ?loc binder rhs result = location_wrap ?loc @@ E_let_in { binder ; rhs ; result } +let e_annotation ?loc expr ty = location_wrap ?loc @@ E_annotation (expr , ty) +let e_application ?loc a b = location_wrap ?loc @@ E_application (a , b) +let e_binop ?loc name a b = location_wrap ?loc @@ E_constant (name , [a ; b]) +let e_constant ?loc name lst = location_wrap ?loc @@ E_constant (name , lst) +let e_look_up ?loc x y = location_wrap ?loc @@ E_look_up (x , y) +let e_assign ?loc a b c = location_wrap ?loc @@ E_assign (a , b , c) let make_option_typed ?loc e t_opt = match t_opt with @@ -106,6 +115,7 @@ let e_typed_list ?loc lst t = e_annotation ?loc (e_list lst) (t_list t) let e_typed_map ?loc lst k v = e_annotation ?loc (e_map lst) (t_map k v) +let e_typed_big_map ?loc lst k v = e_annotation ?loc (e_big_map lst) (t_big_map k v) let e_typed_set ?loc lst k = e_annotation ?loc (e_set lst) (t_set k) @@ -114,14 +124,14 @@ let e_lambda ?loc (binder : string) (output_type : type_expression option) (result : expression) : expression = - Location.wrap ?loc @@ E_lambda { + location_wrap ?loc @@ E_lambda { binder = (make_name binder , input_type) ; input_type = input_type ; output_type = output_type ; result ; } -let e_record ?loc map = Location.wrap ?loc @@ E_record map +let e_record ?loc map = location_wrap ?loc @@ E_record map let e_ez_record ?loc (lst : (string * expr) list) : expression = let map = SMap.of_list lst in @@ -152,29 +162,34 @@ let get_e_list = fun t -> | E_list lst -> ok lst | _ -> simple_fail "not a list" +let get_e_tuple = fun t -> + match t with + | E_tuple lst -> ok lst + | _ -> simple_fail "not a tuple" + let get_e_failwith = fun e -> - match Location.unwrap e with + match e.expression with | E_failwith fw -> ok fw | _ -> simple_fail "not a failwith" let is_e_failwith e = to_bool @@ get_e_failwith e let extract_pair : expression -> (expression * expression) result = fun e -> - match Location.unwrap e with + match e.expression with | E_tuple [ a ; b ] -> ok (a , b) | _ -> fail @@ bad_kind "pair" e.location let extract_list : expression -> (expression list) result = fun e -> - match Location.unwrap e with + match e.expression with | E_list lst -> ok lst | _ -> fail @@ bad_kind "list" e.location let extract_record : expression -> (string * expression) list result = fun e -> - match Location.unwrap e with + match e.expression with | E_record lst -> ok @@ SMap.to_kv_list lst | _ -> fail @@ bad_kind "record" e.location let extract_map : expression -> (expression * expression) list result = fun e -> - match Location.unwrap e with + match e.expression with | E_map lst -> ok lst | _ -> fail @@ bad_kind "map" e.location diff --git a/src/ast_simplified/dune b/src/stages/ast_simplified/dune similarity index 100% rename from src/ast_simplified/dune rename to src/stages/ast_simplified/dune diff --git a/src/ast_simplified/misc.ml b/src/stages/ast_simplified/misc.ml similarity index 97% rename from src/ast_simplified/misc.ml rename to src/stages/ast_simplified/misc.ml index e1582b073..ec9044c8a 100644 --- a/src/ast_simplified/misc.ml +++ b/src/stages/ast_simplified/misc.ml @@ -45,9 +45,9 @@ let assert_literal_eq (a, b : literal * literal) : unit result = | Literal_timestamp a, Literal_timestamp b when a = b -> ok () | Literal_timestamp _, Literal_timestamp _ -> fail @@ different_literals "different timestamps" a b | Literal_timestamp _, _ -> fail @@ different_literals_because_different_types "timestamp vs non-timestamp" a b - | Literal_tez a, Literal_tez b when a = b -> ok () - | Literal_tez _, Literal_tez _ -> fail @@ different_literals "different tezs" a b - | Literal_tez _, _ -> fail @@ different_literals_because_different_types "tez vs non-tez" a b + | Literal_mutez a, Literal_mutez b when a = b -> ok () + | Literal_mutez _, Literal_mutez _ -> fail @@ different_literals "different tezs" a b + | Literal_mutez _, _ -> fail @@ different_literals_because_different_types "tez vs non-tez" a b | Literal_string a, Literal_string b when a = b -> ok () | Literal_string _, Literal_string _ -> fail @@ different_literals "different strings" a b | Literal_string _, _ -> fail @@ different_literals_because_different_types "string vs non-string" a b @@ -67,7 +67,7 @@ let rec assert_value_eq (a, b: (expression * expression )) : unit result = Format.asprintf "\n@[- %a@;- %a]" PP.expression a PP.expression b in trace (fun () -> error (thunk "not equal") error_content ()) @@ - match (Location.unwrap a , Location.unwrap b) with + match (a.expression , b.expression) with | E_literal a , E_literal b -> assert_literal_eq (a, b) | E_literal _ , _ -> @@ -120,7 +120,7 @@ let rec assert_value_eq (a, b: (expression * expression )) : unit result = | E_record _, _ -> simple_fail "comparing record with other stuff" - | E_map lsta, E_map lstb -> ( + | (E_map lsta, E_map lstb | E_big_map lsta, E_big_map lstb) -> ( let%bind lst = generic_try (simple_error "maps of different lengths") (fun () -> let lsta' = List.sort compare lsta in @@ -133,7 +133,7 @@ let rec assert_value_eq (a, b: (expression * expression )) : unit result = let%bind _all = bind_map_list aux lst in ok () ) - | E_map _, _ -> + | (E_map _ | E_big_map _), _ -> simple_fail "comparing map with other stuff" | E_list lsta, E_list lstb -> ( diff --git a/src/ast_simplified/types.ml b/src/stages/ast_simplified/types.ml similarity index 95% rename from src/ast_simplified/types.ml rename to src/stages/ast_simplified/types.ml index 88b93beda..ea42d849d 100644 --- a/src/ast_simplified/types.ml +++ b/src/stages/ast_simplified/types.ml @@ -59,6 +59,7 @@ and expression' = | E_accessor of (expr * access_path) (* Data Structures *) | E_map of (expr * expr) list + | E_big_map of (expr * expr) list | E_list of expr list | E_set of expr list | E_look_up of (expr * expr) @@ -73,7 +74,10 @@ and expression' = (* Annotate *) | E_annotation of expr * type_expression -and expression = expression' Location.wrap +and expression = { + expression : expression' ; + location : Location.t ; +} and access = | Access_tuple of int @@ -87,7 +91,7 @@ and literal = | Literal_bool of bool | Literal_int of int | Literal_nat of int - | Literal_tez of int + | Literal_mutez of int | Literal_string of string | Literal_bytes of bytes | Literal_address of string diff --git a/src/ast_typed/PP.ml b/src/stages/ast_typed/PP.ml similarity index 92% rename from src/ast_typed/PP.ml rename to src/stages/ast_typed/PP.ml index 3e8edf30c..96825ecc3 100644 --- a/src/ast_typed/PP.ml +++ b/src/stages/ast_typed/PP.ml @@ -24,10 +24,9 @@ let rec annotated_expression ppf (ae:annotated_expression) : unit = | _ -> fprintf ppf "@[%a@]" expression ae.expression and lambda ppf l = - let {binder;input_type;output_type;result} = l in - fprintf ppf "lambda (%s:%a) : %a return %a" - binder type_value input_type type_value output_type - annotated_expression result + let ({ binder ; body } : lambda) = l in + fprintf ppf "lambda (%s) -> %a" + binder annotated_expression body and expression ppf (e:expression) : unit = match e with @@ -42,6 +41,7 @@ and expression ppf (e:expression) : unit = | E_tuple lst -> fprintf ppf "tuple[@; @[%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[@; @[%a@]@;]" (list_sep assoc_annotated_expression (tag ",@;")) m + | E_big_map m -> fprintf ppf "big_map[@; @[%a@]@;]" (list_sep assoc_annotated_expression (tag ",@;")) m | E_list m -> fprintf ppf "list[@; @[%a@]@;]" (list_sep annotated_expression (tag ",@;")) m | E_set m -> fprintf ppf "set[@; @[%a@]@;]" (list_sep annotated_expression (tag ",@;")) m | E_look_up (ds, i) -> fprintf ppf "(%a)[%a]" annotated_expression ds annotated_expression i @@ -70,7 +70,7 @@ and literal ppf (l:literal) : unit = | Literal_int n -> fprintf ppf "%d" n | Literal_nat n -> fprintf ppf "+%d" n | Literal_timestamp n -> fprintf ppf "+%d" n - | Literal_tez n -> fprintf ppf "%dtz" n + | Literal_mutez n -> fprintf ppf "%dmtz" 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 @@ -90,8 +90,8 @@ and matching : type a . (formatter -> a -> unit) -> _ -> a matching -> unit = fu 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_list {match_nil ; match_cons = (((hd_name , _), (tl_name , _)), match_cons)} -> + fprintf ppf "| Nil -> %a @.| %s :: %s -> %a" f match_nil hd_name tl_name 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 diff --git a/src/ast_typed/ast_typed.ml b/src/stages/ast_typed/ast_typed.ml similarity index 100% rename from src/ast_typed/ast_typed.ml rename to src/stages/ast_typed/ast_typed.ml diff --git a/src/ast_typed/combinators.ml b/src/stages/ast_typed/combinators.ml similarity index 93% rename from src/ast_typed/combinators.ml rename to src/stages/ast_typed/combinators.ml index ec745fabc..d9dcebb73 100644 --- a/src/ast_typed/combinators.ml +++ b/src/stages/ast_typed/combinators.ml @@ -41,6 +41,7 @@ let ez_t_record lst ?s () : type_value = t_record m ?s () let t_map key value ?s () = make_t (T_constant ("map", [key ; value])) s +let t_big_map key value ?s () = make_t (T_constant ("big_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 = @@ -56,6 +57,15 @@ 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_lambda e : _ result = match e with + | E_lambda l -> ok l + | _ -> simple_fail "not a lambda" + +let get_lambda_with_type e = + match (e.expression , e.type_annotation.type_value') with + | E_lambda l , T_function io -> ok (l , io) + | _ -> simple_fail "not a lambda with functional type" + let get_t_bool (t:type_value) : unit result = match t.type_value' with | T_constant ("bool", []) -> ok () | _ -> simple_fail "not a bool" @@ -154,6 +164,14 @@ let get_t_map_value : type_value -> type_value result = fun t -> let%bind (_ , value) = get_t_map t in ok value +let get_t_big_map_key : type_value -> type_value result = fun t -> + let%bind (key , _) = get_t_big_map t in + ok key + +let get_t_big_map_value : type_value -> type_value result = fun t -> + let%bind (_ , value) = get_t_big_map t in + ok value + let assert_t_map = fun t -> let%bind _ = get_t_map t in ok () @@ -214,7 +232,7 @@ 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_mutez n : expression = E_literal (Literal_mutez 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) @@ -229,13 +247,13 @@ let e_let_in binder rhs result = E_let_in { binder ; rhs ; result } 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_mutez n = make_a_e (e_mutez 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_lambda l in_ty out_ty = make_a_e (e_lambda l) (t_function in_ty out_ty ()) 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) ()) diff --git a/src/ast_typed/combinators_environment.ml b/src/stages/ast_typed/combinators_environment.ml similarity index 89% rename from src/ast_typed/combinators_environment.ml rename to src/stages/ast_typed/combinators_environment.ml index e8ca37530..1446c8780 100644 --- a/src/ast_typed/combinators_environment.ml +++ b/src/stages/ast_typed/combinators_environment.ml @@ -6,7 +6,7 @@ let make_a_e_empty expression type_annotation = make_a_e expression type_annotat 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_mutez n = e_a_mutez 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 @@ -18,7 +18,7 @@ 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 +let e_a_empty_lambda l i o = e_a_lambda l i o Environment.full_empty open Environment diff --git a/src/ast_typed/dune b/src/stages/ast_typed/dune similarity index 100% rename from src/ast_typed/dune rename to src/stages/ast_typed/dune diff --git a/src/ast_typed/environment.ml b/src/stages/ast_typed/environment.ml similarity index 100% rename from src/ast_typed/environment.ml rename to src/stages/ast_typed/environment.ml diff --git a/src/ast_typed/misc.ml b/src/stages/ast_typed/misc.ml similarity index 92% rename from src/ast_typed/misc.ml rename to src/stages/ast_typed/misc.ml index 091531789..db33f6062 100644 --- a/src/ast_typed/misc.ml +++ b/src/stages/ast_typed/misc.ml @@ -125,6 +125,23 @@ module Errors = struct ("missing_key" , fun () -> Format.asprintf "%s" k) ] in error ~data title message () + + let missing_entry_point name = + let title () = "missing entry point" in + let content () = "no entry point with the given name" in + let data = [ + ("name" , fun () -> name) ; + ] in + error ~data title content + + let not_functional_main location = + let title () = "not functional main" in + let content () = "main should be a function" in + let data = [ + ("location" , fun () -> Format.asprintf "%a" Location.pp location) ; + ] in + error ~data title content + end module Free_variables = struct @@ -156,7 +173,7 @@ module Free_variables = struct | E_tuple_accessor (a, _) -> self a | E_list lst -> unions @@ List.map self lst | E_set lst -> unions @@ List.map self lst - | E_map m -> unions @@ List.map self @@ List.concat @@ List.map (fun (a, b) -> [ a ; b ]) m + | (E_map m | E_big_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 @@ -171,7 +188,7 @@ module Free_variables = struct and lambda : bindings -> lambda -> bindings = fun b l -> let b' = union (singleton l.binder) b in - annotated_expression b' l.result + annotated_expression b' l.body and annotated_expression : bindings -> annotated_expression -> bindings = fun b ae -> expression b ae.expression @@ -182,7 +199,7 @@ module Free_variables = struct 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_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 @@ -348,9 +365,9 @@ let assert_literal_eq (a, b : literal * literal) : unit result = | Literal_timestamp a, Literal_timestamp b when a = b -> ok () | Literal_timestamp _, Literal_timestamp _ -> fail @@ different_literals "different timestamps" a b | Literal_timestamp _, _ -> fail @@ different_literals_because_different_types "timestamp vs non-timestamp" a b - | Literal_tez a, Literal_tez b when a = b -> ok () - | Literal_tez _, Literal_tez _ -> fail @@ different_literals "different tezs" a b - | Literal_tez _, _ -> fail @@ different_literals_because_different_types "tez vs non-tez" a b + | Literal_mutez a, Literal_mutez b when a = b -> ok () + | Literal_mutez _, Literal_mutez _ -> fail @@ different_literals "different tezs" a b + | Literal_mutez _, _ -> fail @@ different_literals_because_different_types "tez vs non-tez" a b | Literal_string a, Literal_string b when a = b -> ok () | Literal_string _, Literal_string _ -> fail @@ different_literals "different strings" a b | Literal_string _, _ -> fail @@ different_literals_because_different_types "string vs non-string" a b @@ -422,7 +439,7 @@ let rec assert_value_eq (a, b: (value*value)) : unit result = | E_record _, _ -> fail @@ (different_values_because_different_types "record vs. non-record" a b) - | E_map lsta, E_map lstb -> ( + | (E_map lsta, E_map lstb | E_big_map lsta, E_big_map lstb) -> ( let%bind lst = generic_try (different_size_values "maps of different lengths" a b) (fun () -> let lsta' = List.sort compare lsta in @@ -435,7 +452,7 @@ let rec assert_value_eq (a, b: (value*value)) : unit result = let%bind _all = bind_map_list aux lst in ok () ) - | E_map _, _ -> + | (E_map _ | E_big_map _), _ -> fail @@ different_values_because_different_types "map vs. non-map" a b | E_list lsta, E_list lstb -> ( @@ -473,3 +490,18 @@ let merge_annotation (a:type_value option) (b:type_value option) err : type_valu match a.simplified, b.simplified with | _, None -> ok a | _, Some _ -> ok b + +let get_entry (lst : program) (name : string) : annotated_expression result = + trace_option (Errors.missing_entry_point name) @@ + let aux x = + let (Declaration_constant (an , _)) = Location.unwrap x in + if (an.name = name) + then Some an.annotated_expression + else None + in + List.find_map aux lst + +let program_environment (program : program) : full_environment = + let last_declaration = Location.unwrap List.(hd @@ rev program) in + match last_declaration with + | Declaration_constant (_ , (_ , post_env)) -> post_env diff --git a/src/ast_typed/misc_smart.ml b/src/stages/ast_typed/misc_smart.ml similarity index 95% rename from src/ast_typed/misc_smart.ml rename to src/stages/ast_typed/misc_smart.ml index 0d0e8cd02..10e52d2e6 100644 --- a/src/ast_typed/misc_smart.ml +++ b/src/stages/ast_typed/misc_smart.ml @@ -4,7 +4,7 @@ open Combinators open Misc let program_to_main : program -> string -> lambda result = fun p s -> - let%bind (main , input_type , output_type) = + let%bind (main , input_type , _) = let pred = fun d -> match d with | Declaration_constant (d , _) when d.name = s -> Some d.annotated_expression @@ -25,15 +25,13 @@ let program_to_main : program -> string -> lambda result = fun p s -> | Declaration_constant (_ , (_ , post_env)) -> post_env in List.fold_left aux Environment.full_empty (List.map Location.unwrap p) in let binder = "@contract_input" in - let result = + let body = 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 ; - result ; + body ; } module Captured_variables = struct @@ -80,7 +78,7 @@ module Captured_variables = struct | E_set lst -> let%bind lst' = bind_map_list self lst in ok @@ unions lst' - | E_map m -> + | (E_map m | E_big_map m) -> let%bind lst' = bind_map_list self @@ List.concat @@ List.map (fun (a, b) -> [ a ; b ]) m in ok @@ unions lst' | E_look_up (a , b) -> @@ -109,7 +107,7 @@ module Captured_variables = struct let%bind t' = f b t in let%bind fa' = f b fa in ok @@ union t' fa' - | Match_list { match_nil = n ; match_cons = (hd, tl, c) } -> + | Match_list { match_nil = n ; match_cons = (((hd, _), (tl, _)), c) } -> let%bind n' = f b n in let%bind c' = f (union (of_list [hd ; tl]) b) c in ok @@ union n' c' diff --git a/src/ast_typed/types.ml b/src/stages/ast_typed/types.ml similarity index 80% rename from src/ast_typed/types.ml rename to src/stages/ast_typed/types.ml index cf8c40fec..fc297b593 100644 --- a/src/ast_typed/types.ml +++ b/src/stages/ast_typed/types.ml @@ -69,10 +69,10 @@ and named_type_value = { } and lambda = { - binder: name ; - input_type: tv ; - output_type: tv ; - result: ae ; + binder : name ; + (* input_type: tv ; + * output_type: tv ; *) + body : ae ; } and let_in = { @@ -99,6 +99,7 @@ and expression = | E_record_accessor of (ae * string) (* Data Structures *) | E_map of (ae * ae) list + | E_big_map of (ae * ae) list | E_list of ae list | E_set of ae list | E_look_up of (ae * ae) @@ -118,7 +119,7 @@ and literal = | Literal_int of int | Literal_nat of int | Literal_timestamp of int - | Literal_tez of int + | Literal_mutez of int | Literal_string of string | Literal_bytes of bytes | Literal_address of string @@ -138,7 +139,7 @@ and 'a matching = } | Match_list of { match_nil : 'a ; - match_cons : name * name * 'a ; + match_cons : ((name * type_value) * (name * type_value)) * 'a ; } | Match_option of { match_none : 'a ; @@ -148,23 +149,3 @@ and 'a matching = | Match_variant of (((constructor_name * name) * 'a) list * type_value) 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" - diff --git a/src/mini_c/PP.ml b/src/stages/mini_c/PP.ml similarity index 87% rename from src/mini_c/PP.ml rename to src/stages/mini_c/PP.ml index 13fb005fc..660006521 100644 --- a/src/mini_c/PP.ml +++ b/src/stages/mini_c/PP.ml @@ -27,6 +27,7 @@ let rec type_ ppf : type_value -> _ = function | 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_big_map(k, v) -> fprintf ppf "big_map(%a -> %a)" type_ k type_ v | T_list(t) -> fprintf ppf "list(%a)" type_ t | T_set(t) -> fprintf ppf "set(%a)" type_ t | T_option(o) -> fprintf ppf "option(%a)" type_ o @@ -48,7 +49,7 @@ let rec value ppf : value -> unit = function | D_int n -> fprintf ppf "%d" n | D_nat n -> fprintf ppf "+%d" n | D_timestamp n -> fprintf ppf "+%d" n - | D_tez n -> fprintf ppf "%dtz" n + | D_mutez n -> fprintf ppf "%dmtz" n | D_unit -> fprintf ppf "unit" | D_string s -> fprintf ppf "\"%s\"" s | D_bytes x -> @@ -61,6 +62,7 @@ let rec value ppf : value -> unit = function | 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_big_map m -> fprintf ppf "Big_map[%a]" (list_sep_d value_assoc) m | D_list lst -> fprintf ppf "List[%a]" (list_sep_d value) lst | D_set lst -> fprintf ppf "Set[%a]" (list_sep_d value) lst @@ -69,7 +71,7 @@ and value_assoc ppf : (value * value) -> unit = fun (a, b) -> and expression' ppf (e:expression') = match e with | E_skip -> fprintf ppf "skip" - | E_closure x -> function_ ppf x + | E_closure x -> fprintf ppf "C(%a)" function_ x | E_variable v -> fprintf ppf "V(%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 @@ -80,6 +82,7 @@ and expression' ppf (e:expression') = match e with | E_make_none _ -> fprintf ppf "none" | E_if_bool (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_cons (c, n, (((hd_name, _) , (tl_name, _)) , cons)) -> fprintf ppf "%a ?? %a : (%s :: %s) -> %a" expression c expression n hd_name tl_name expression cons | 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_sequence (a , b) -> fprintf ppf "%a ;; %a" expression a expression b @@ -87,6 +90,8 @@ and expression' ppf (e:expression') = match e with fprintf ppf "let %s = %a in ( %a )" name expression expr expression body | E_iterator (s , ((name , _) , body) , expr) -> fprintf ppf "for_%s %s of %a do ( %a )" s name expression expr expression body + | E_fold (((name , _) , body) , collection , initial) -> + fprintf ppf "fold %a on %a with %s do ( %a )" expression collection expression initial name expression body | E_assignment (r , path , e) -> fprintf ppf "%s.%a := %a" r (list_sep lr (const ".")) path expression e | E_while (e , b) -> @@ -100,10 +105,10 @@ and expression_with_type : _ -> expression -> _ = fun ppf e -> expression' e.content type_ e.type_value -and function_ ppf ({binder ; result}:anon_function) = +and function_ ppf ({binder ; body}:anon_function) = fprintf ppf "fun %s -> (%a)" binder - expression result + expression body and assignment ppf ((n, e):assignment) = fprintf ppf "%s = %a;" n expression e diff --git a/src/mini_c/combinators.ml b/src/stages/mini_c/combinators.ml similarity index 75% rename from src/mini_c/combinators.ml rename to src/stages/mini_c/combinators.ml index f7342987e..094d91928 100644 --- a/src/mini_c/combinators.ml +++ b/src/stages/mini_c/combinators.ml @@ -7,18 +7,15 @@ module Expression = struct let get_content : t -> t' = fun e -> e.content let get_type : t -> type_value = fun e -> e.type_value - let is_toplevel : t -> bool = fun e -> e.is_toplevel - let make = fun ?(itl = false) e' t -> { + let make = fun e' t -> { content = e' ; type_value = t ; - is_toplevel = itl ; } - let make_tpl = fun ?(itl = false) (e' , t) -> { + let make_tpl = fun (e' , t) -> { content = e' ; type_value = t ; - is_toplevel = itl ; } let pair : t -> t -> t' = fun a b -> E_constant ("PAIR" , [ a ; b ]) @@ -37,6 +34,10 @@ let get_nat (v:value) = match v with | D_nat n -> ok n | _ -> simple_fail "not a nat" +let get_mutez (v:value) = match v with + | D_mutez n -> ok n + | _ -> simple_fail "not a mutez" + let get_timestamp (v:value) = match v with | D_timestamp n -> ok n | _ -> simple_fail "not a timestamp" @@ -62,6 +63,10 @@ let get_map (v:value) = match v with | D_map lst -> ok lst | _ -> simple_fail "not a map" +let get_big_map (v:value) = match v with + | D_big_map lst -> ok lst + | _ -> simple_fail "not a big_map" + let get_list (v:value) = match v with | D_list lst -> ok lst | _ -> simple_fail "not a list" @@ -70,6 +75,24 @@ let get_set (v:value) = match v with | D_set lst -> ok lst | _ -> simple_fail "not a set" +let get_function_with_ty (e : expression) = + match (e.content , e.type_value) with + | E_literal (D_function f) , T_function ty -> ok (f , ty) + | _ -> simple_fail "not a function with functional type" + +let get_function (e : expression) = + match (e.content) with + | E_literal (D_function f) -> ok (D_function f) + | _ -> simple_fail "not a function" + +let get_t_function tv = match tv with + | T_function ty -> ok ty + | _ -> simple_fail "not a function" + +let get_t_closure tv = match tv with + | T_deep_closure ty -> ok ty + | _ -> simple_fail "not a function" + let get_t_option (v:type_value) = match v with | T_option t -> ok t | _ -> simple_fail "not an option" @@ -90,6 +113,10 @@ let get_t_map (t:type_value) = match t with | T_map kv -> ok kv | _ -> simple_fail "not a type map" +let get_t_big_map (t:type_value) = match t with + | T_big_map kv -> ok kv + | _ -> simple_fail "not a type big_map" + let get_t_list (t:type_value) = match t with | T_list t -> ok t | _ -> simple_fail "not a type list" @@ -146,10 +173,10 @@ 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 result : anon_function = +let quote binder body : anon_function = { binder ; - result ; + body ; } @@ -157,22 +184,21 @@ let e_int expr : expression = Expression.make_tpl (expr, t_int) let e_unit : expression = Expression.make_tpl (E_literal D_unit, t_unit) let e_skip : expression = Expression.make_tpl (E_skip, t_unit) let e_var_int name : expression = e_int (E_variable name) -let e_let_int v tv expr body : expression = Expression.(make_tpl ( +let e_let_in v tv expr body : expression = Expression.(make_tpl ( E_let_in ((v , tv) , expr , body) , get_type body )) let ez_e_sequence a b : expression = Expression.(make_tpl (E_sequence (make_tpl (a , t_unit) , b) , get_type b)) -let ez_e_return e : expression = e - let d_unit : value = D_unit -let basic_quote expr : anon_function result = - ok @@ quote "input" (ez_e_return expr) +let basic_quote expr in_ty out_ty : expression result = + let expr' = E_literal (D_function (quote "input" expr)) in + ok @@ Expression.make_tpl (expr' , t_function in_ty out_ty) -let basic_int_quote expr : anon_function result = - basic_quote expr +let basic_int_quote expr : expression result = + basic_quote expr t_int t_int let environment_wrap pre_environment post_environment = { pre_environment ; post_environment } diff --git a/src/mini_c/combinators_smart.ml b/src/stages/mini_c/combinators_smart.ml similarity index 100% rename from src/mini_c/combinators_smart.ml rename to src/stages/mini_c/combinators_smart.ml diff --git a/src/mini_c/dune b/src/stages/mini_c/dune similarity index 100% rename from src/mini_c/dune rename to src/stages/mini_c/dune diff --git a/src/mini_c/environment.ml b/src/stages/mini_c/environment.ml similarity index 100% rename from src/mini_c/environment.ml rename to src/stages/mini_c/environment.ml diff --git a/src/mini_c/mini_c.ml b/src/stages/mini_c/mini_c.ml similarity index 93% rename from src/mini_c/mini_c.ml rename to src/stages/mini_c/mini_c.ml index 5f4e9f5a2..891f746d7 100644 --- a/src/mini_c/mini_c.ml +++ b/src/stages/mini_c/mini_c.ml @@ -8,3 +8,4 @@ module Combinators = struct end include Combinators module Environment = Environment +include Misc diff --git a/src/stages/mini_c/misc.ml b/src/stages/mini_c/misc.ml new file mode 100644 index 000000000..60810643c --- /dev/null +++ b/src/stages/mini_c/misc.ml @@ -0,0 +1,166 @@ +open Types +open Combinators +open Trace + +module Errors = struct + + let missing_entry_point name = + let title () = "missing entry point" in + let content () = "no entry point with the given name" in + let data = [ + ("name" , fun () -> name) ; + ] in + error ~data title content + + let not_functional_main name = + let title () = "not functional main" in + let content () = "main should be a function" in + let data = [ + ("name" , fun () -> Format.asprintf "%s" name) ; + ] in + error ~data title content + +end + +(* + Converts `expr` in `fun () -> expr`. +*) +let functionalize (body : expression) : expression = + let content = E_literal (D_function { binder = "_" ; body }) in + let type_value = t_function t_unit body.type_value in + { content ; type_value } + +let get_entry (lst : program) (name : string) : (expression * int) result = + let%bind entry_expression = + trace_option (Errors.missing_entry_point name) @@ + let aux x = + let (((decl_name , decl_expr) , _)) = x in + if (decl_name = name) + then Some decl_expr + else None + in + List.find_map aux lst + in + let entry_index = + let aux x = + let (((decl_name , _) , _)) = x in + decl_name = name + in + List.find_index aux lst + in + ok (entry_expression , entry_index) + + +(* + Assume the following code: + ``` + const x = 42 + const y = 120 + const z = 423 + const f = () -> x + y + ``` + It is transformed in: + ``` + const f = () -> + let x = 42 in + let y = 120 in + let z = 423 in + x + y + ``` + + The entry-point can be an expression, which is then functionalized if + `to_functionalize` is set to true. +*) +let aggregate_entry (lst : program) (name : string) (to_functionalize : bool) : expression result = + let%bind (entry_expression , entry_index) = get_entry lst name in + let pre_declarations = List.until entry_index lst in + let wrapper = + let aux prec cur = + let (((name , expr) , _)) = cur in + e_let_in name expr.type_value expr prec + in + fun expr -> List.fold_right' aux expr pre_declarations + in + match (entry_expression.content , to_functionalize) with + | (E_literal (D_function l) , false) -> ( + let l' = { l with body = wrapper l.body } in + let e' = { entry_expression with content = E_literal (D_function l') } in + ok e' + ) + | (E_closure l , false) -> ( + let l' = { l with body = wrapper l.body } in + let%bind t' = + let%bind (_ , input_ty , output_ty) = get_t_closure entry_expression.type_value in + ok (t_function input_ty output_ty) + in + let e' = { + content = E_literal (D_function l') ; + type_value = t' ; + } in + ok e' + ) + | (_ , true) -> ( + ok @@ functionalize @@ wrapper entry_expression + ) + | _ -> ( + Format.printf "Not functional: %a\n" PP.expression entry_expression ; + fail @@ Errors.not_functional_main name + ) + +let rec expression_to_value (exp: expression) : value result = + match exp.content with + | E_literal v -> ok @@ v + | E_constant ("map" , lst) -> + let aux el = + let%bind l = expression_to_value el in + match l with + | D_pair (a , b) -> ok @@ (a , b) + | _ -> fail @@ simple_error "??" in + let%bind lstl = bind_map_list aux lst in + ok @@ D_map lstl + | E_constant ("big_map" , lst) -> + let aux el = + let%bind l = expression_to_value el in + match l with + | D_pair (a , b) -> ok @@ (a , b) + | _ -> fail @@ simple_error "??" in + let%bind lstl = bind_map_list aux lst in + ok @@ D_big_map lstl + | E_constant ("PAIR" , fst::snd::[]) -> + let%bind fstl = expression_to_value fst in + let%bind sndl = expression_to_value snd in + ok @@ D_pair (fstl , sndl) + | E_constant ("UNIT", _) -> ok @@ D_unit + | E_constant ("UPDATE", _) -> + let rec handle_prev upd = + match upd.content with + | E_constant ("UPDATE" , [k;v;prev]) -> + begin + match v.content with + | E_constant ("SOME" , [i]) -> + let%bind kl = expression_to_value k in + let%bind il = expression_to_value i in + let%bind prevl = handle_prev prev in + ok @@ (kl,il)::prevl + | E_constant ("NONE" , []) -> + let%bind prevl = handle_prev prev in + ok @@ prevl + | _ -> failwith "UPDATE second parameter is not an option" + end + | E_make_empty_map _ -> + ok @@ [] + | _ -> failwith "Ill-constructed map" + in + begin + match exp.type_value with + | T_big_map _ -> + let%bind kvl = handle_prev exp in + ok @@ D_big_map kvl + | T_map _ -> + let%bind kvl = handle_prev exp in + ok @@ D_map kvl + | _ -> failwith "UPDATE with a non-map type_value" + end + | _ as nl -> + let expp = Format.asprintf "'%a'" PP.expression' nl in + fail @@ simple_error ("Can not convert expression "^expp^" to literal") diff --git a/src/mini_c/types.ml b/src/stages/mini_c/types.ml similarity index 86% rename from src/mini_c/types.ml rename to src/stages/mini_c/types.ml index fd0ddd021..a0a367409 100644 --- a/src/mini_c/types.ml +++ b/src/stages/mini_c/types.ml @@ -12,9 +12,10 @@ 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_deep_closure of (environment * type_value * type_value) | T_base of type_base | T_map of (type_value * type_value) + | T_big_map of (type_value * type_value) | T_list of type_value | T_set of type_value | T_contract of type_value @@ -37,7 +38,7 @@ type value = | D_bool of bool | D_nat of int | D_timestamp of int - | D_tez of int + | D_mutez of int | D_int of int | D_string of string | D_bytes of bytes @@ -47,6 +48,7 @@ type value = | D_some of value | D_none | D_map of (value * value) list + | D_big_map of (value * value) list | D_list of value list | D_set of value list (* | `Macro of anon_macro ... The future. *) @@ -67,8 +69,10 @@ and expression' = | E_make_empty_set of type_value | E_make_none of type_value | E_iterator of (string * ((var_name * type_value) * expression) * expression) + | E_fold of (((var_name * type_value) * expression) * expression * expression) | E_if_bool of expression * expression * expression | E_if_none of expression * expression * ((var_name * type_value) * expression) + | E_if_cons of (expression * expression * (((var_name * type_value) * (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) | E_sequence of (expression * expression) @@ -78,7 +82,6 @@ and expression' = and expression = { content : expression' ; type_value : type_value ; - is_toplevel : bool ; } and assignment = var_name * expression @@ -87,7 +90,7 @@ and toplevel_statement = assignment * environment_wrap and anon_function = { binder : string ; - result : expression ; + body : expression ; } and program = toplevel_statement list diff --git a/src/test/bin_tests.ml b/src/test/bin_tests.ml index 2ee1485bc..6e109d6fd 100644 --- a/src/test/bin_tests.ml +++ b/src/test/bin_tests.ml @@ -1,10 +1,9 @@ open Trace -open Ligo.Run open Test_helpers let compile_contract_basic () : unit result = let%bind _ = - compile_contract_file "./contracts/dispatch-counter.ligo" "main" (Syntax_name "pascaligo") + Ligo.Compile.Of_source.compile_file_entry "./contracts/dispatch-counter.ligo" "main" (Syntax_name "pascaligo") in ok () diff --git a/src/test/coase_tests.ml b/src/test/coase_tests.ml index 1931b9857..967130f3d 100644 --- a/src/test/coase_tests.ml +++ b/src/test/coase_tests.ml @@ -1,10 +1,9 @@ (* Copyright Coase, Inc 2019 *) open Trace -open Ligo.Run open Test_helpers -let type_file = type_file `pascaligo +let type_file = Ligo.Compile.Of_source.type_file (Syntax_name "pascaligo") let get_program = let s = ref None in @@ -48,7 +47,7 @@ let card_pattern_ty = ] let card_pattern_ez (coeff , qtt) = - card_pattern (e_tez coeff , e_nat qtt) + card_pattern (e_mutez coeff , e_nat qtt) let make_card_patterns lst = let card_pattern_id_ty = t_nat in @@ -210,9 +209,9 @@ let sell () = e_pair sell_action storage in let make_expecter : int -> expression -> unit result = fun n result -> - let%bind (ops , storage) = get_e_pair @@ Location.unwrap result in + let%bind (ops , storage) = get_e_pair result.expression in let%bind () = - let%bind lst = get_e_list @@ Location.unwrap ops in + let%bind lst = get_e_list ops.expression in Assert.assert_list_size lst 1 in let expected_storage = let cards = List.hds @@ cards_ez first_owner n in diff --git a/src/test/compiler_tests.ml b/src/test/compiler_tests.ml index 0407c281f..a93fb2ee7 100644 --- a/src/test/compiler_tests.ml +++ b/src/test/compiler_tests.ml @@ -1,11 +1,11 @@ open Trace -open Ligo.Mini_c +open Mini_c open Combinators open Test_helpers -let run_entry_int (e:anon_function) (n:int) : int result = +let run_entry_int e (n:int) : int result = let param : value = D_int n in - let%bind result = Main.Run_mini_c.run_entry e (t_int , t_int) param in + let%bind result = Run.Of_mini_c.run_function_value e param t_int in match result with | D_int n -> ok n | _ -> simple_fail "result is not an int" @@ -18,10 +18,10 @@ let identity () : unit result = let multiple_vars () : unit result = let expr = - e_let_int "a" t_int (e_var_int "input") @@ - e_let_int "b" t_int (e_var_int "input") @@ - e_let_int "c" t_int (e_var_int "a") @@ - e_let_int "output" t_int (e_var_int "c") @@ + e_let_in "a" t_int (e_var_int "input") @@ + e_let_in "b" t_int (e_var_int "input") @@ + e_let_in "c" t_int (e_var_int "a") @@ + e_let_in "output" t_int (e_var_int "c") @@ e_var_int "output" in let%bind f = basic_int_quote expr in let%bind result = run_entry_int f 42 in diff --git a/src/contracts/amount.mligo b/src/test/contracts/amount.mligo similarity index 100% rename from src/contracts/amount.mligo rename to src/test/contracts/amount.mligo diff --git a/src/test/contracts/annotation.ligo b/src/test/contracts/annotation.ligo new file mode 100644 index 000000000..1eaef7b0c --- /dev/null +++ b/src/test/contracts/annotation.ligo @@ -0,0 +1,3 @@ +const lst : list(int) = list [] ; + +const address : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ; diff --git a/src/contracts/arithmetic.ligo b/src/test/contracts/arithmetic.ligo similarity index 92% rename from src/contracts/arithmetic.ligo rename to src/test/contracts/arithmetic.ligo index efaa0e62b..1040aeebf 100644 --- a/src/contracts/arithmetic.ligo +++ b/src/test/contracts/arithmetic.ligo @@ -1,3 +1,5 @@ +// Test PascaLIGO arithmetic operators + function mod_op (const n : int) : nat is begin skip end with n mod 42 diff --git a/src/test/contracts/assert.mligo b/src/test/contracts/assert.mligo new file mode 100644 index 000000000..9b57d7c9e --- /dev/null +++ b/src/test/contracts/assert.mligo @@ -0,0 +1,3 @@ +let%entry main (p : bool) (s : unit) = + let u : unit = assert(p) in + (([] : operation list), s) diff --git a/src/contracts/assign.ligo b/src/test/contracts/assign.ligo similarity index 100% rename from src/contracts/assign.ligo rename to src/test/contracts/assign.ligo diff --git a/src/contracts/basic.mligo b/src/test/contracts/basic.mligo similarity index 100% rename from src/contracts/basic.mligo rename to src/test/contracts/basic.mligo diff --git a/src/test/contracts/big_map.ligo b/src/test/contracts/big_map.ligo new file mode 100644 index 000000000..461c2c206 --- /dev/null +++ b/src/test/contracts/big_map.ligo @@ -0,0 +1,60 @@ +type storage_ is big_map(int, int) * unit + +function main(const p : unit; const s : storage_) : list(operation) * storage_ is + var r : big_map(int, int) := s.0 ; + var toto : option (int) := Some(0); + block { + toto := r[23]; + r[2] := 444; + s.0 := r; + } + with ((nil: list(operation)), s) + +function set_ (var n : int ; var m : storage_) : storage_ is block { + var tmp : big_map(int,int) := m.0 ; + tmp[23] := n ; + m.0 := tmp ; +} with m + +function rm (var m : storage_) : storage_ is block { + var tmp : big_map(int,int) := m.0 ; + remove 42 from map tmp; + m.0 := tmp; +} with m + +function gf (const m : storage_) : int is begin skip end with get_force(23, m.0) + +function get (const m : storage_) : option(int) is + begin + skip + end with m.0[42] + +// the following is not supported (negative test cases): + +// const bm : storage_ = big_map +// 144 -> 23 ; +// 51 -> 23 ; +// 42 -> 23 ; +// 120 -> 23 ; +// 421 -> 23 ; +// end + +// type foobar is big_map(int, int) +// const fb : foobar = big_map +// 23 -> 0 ; +// 42 -> 0 ; +// end + +// function size_ (const m : storage_) : nat is +// block {skip} with (size(m.0)) + +// function iter_op (const m : storage_) : int is +// var r : int := 0 ; +// function aggregate (const i : int ; const j : int) : unit is block { r := r + i + j } with unit ; +// block { +// map_iter(m.0 , aggregate) ; +// } with r ; + +// function map_op (const m : storage_) : storage_ is +// function increment (const i : int ; const j : int) : int is block { skip } with j + 1 ; +// block { skip } with map_map(m.0 , increment) ; diff --git a/src/contracts/bitwise_arithmetic.ligo b/src/test/contracts/bitwise_arithmetic.ligo similarity index 87% rename from src/contracts/bitwise_arithmetic.ligo rename to src/test/contracts/bitwise_arithmetic.ligo index 0711b5854..282b82be9 100644 --- a/src/contracts/bitwise_arithmetic.ligo +++ b/src/test/contracts/bitwise_arithmetic.ligo @@ -1,3 +1,5 @@ +// Test PascaLIGO bitwise operators + function or_op (const n : nat) : nat is begin skip end with bitwise_or(n , 4n) diff --git a/src/contracts/boolean_operators.ligo b/src/test/contracts/boolean_operators.ligo similarity index 89% rename from src/contracts/boolean_operators.ligo rename to src/test/contracts/boolean_operators.ligo index 38b94ba02..4b53ff2d5 100644 --- a/src/contracts/boolean_operators.ligo +++ b/src/test/contracts/boolean_operators.ligo @@ -1,3 +1,5 @@ +// Test PascaLIGO boolean operators + function or_true (const b : bool) : bool is begin skip end with b or True diff --git a/src/contracts/bytes_arithmetic.ligo b/src/test/contracts/bytes_arithmetic.ligo similarity index 100% rename from src/contracts/bytes_arithmetic.ligo rename to src/test/contracts/bytes_arithmetic.ligo diff --git a/src/contracts/closure-1.ligo b/src/test/contracts/closure-1.ligo similarity index 100% rename from src/contracts/closure-1.ligo rename to src/test/contracts/closure-1.ligo diff --git a/src/contracts/closure-2.ligo b/src/test/contracts/closure-2.ligo similarity index 100% rename from src/contracts/closure-2.ligo rename to src/test/contracts/closure-2.ligo diff --git a/src/test/contracts/closure-3.ligo b/src/test/contracts/closure-3.ligo new file mode 100644 index 000000000..98ad10cb0 --- /dev/null +++ b/src/test/contracts/closure-3.ligo @@ -0,0 +1,10 @@ +// This might seem like it's covered by induction with closure-2.ligo +// But it exists to prevent a regression on the bug patched by: +// https://gitlab.com/ligolang/ligo/commit/faf3bbc06106de98189f1c1673bd57e78351dc7e + +function foobar(const i : int) : int is + const j : int = 3 ; + const k : int = 4 ; + function toto(const l : int) : int is + block { skip } with i + j + k + l; + block { skip } with toto(42) diff --git a/src/contracts/closure.ligo b/src/test/contracts/closure.ligo similarity index 100% rename from src/contracts/closure.ligo rename to src/test/contracts/closure.ligo diff --git a/src/contracts/coase.ligo b/src/test/contracts/coase.ligo similarity index 100% rename from src/contracts/coase.ligo rename to src/test/contracts/coase.ligo diff --git a/src/contracts/condition-simple.ligo b/src/test/contracts/condition-simple.ligo similarity index 65% rename from src/contracts/condition-simple.ligo rename to src/test/contracts/condition-simple.ligo index 708d4c6b5..9df22cbe3 100644 --- a/src/contracts/condition-simple.ligo +++ b/src/test/contracts/condition-simple.ligo @@ -1,3 +1,5 @@ +// Test if conditional with trivial conditions in PascaLIGO + function main (const i : int) : int is begin if 1 = 1 then diff --git a/src/contracts/condition.ligo b/src/test/contracts/condition.ligo similarity index 80% rename from src/contracts/condition.ligo rename to src/test/contracts/condition.ligo index 68c949640..98672b1c9 100644 --- a/src/contracts/condition.ligo +++ b/src/test/contracts/condition.ligo @@ -1,3 +1,5 @@ +// Test if conditional in PascaLIGO + function main (const i : int) : int is var result : int := 23 ; begin diff --git a/src/contracts/counter.ligo b/src/test/contracts/counter.ligo similarity index 100% rename from src/contracts/counter.ligo rename to src/test/contracts/counter.ligo diff --git a/src/contracts/counter.mligo b/src/test/contracts/counter.mligo similarity index 100% rename from src/contracts/counter.mligo rename to src/test/contracts/counter.mligo diff --git a/src/contracts/declaration-local.ligo b/src/test/contracts/declaration-local.ligo similarity index 57% rename from src/contracts/declaration-local.ligo rename to src/test/contracts/declaration-local.ligo index 94d443b32..97f380112 100644 --- a/src/contracts/declaration-local.ligo +++ b/src/test/contracts/declaration-local.ligo @@ -1,3 +1,5 @@ +// Test PasaLIGO variable declarations inside of a block + function main (const i : int) : int is block { const j : int = 42 ; } with j diff --git a/src/contracts/declarations.ligo b/src/test/contracts/declarations.ligo similarity index 69% rename from src/contracts/declarations.ligo rename to src/test/contracts/declarations.ligo index c153b0c57..4001fbdbf 100644 --- a/src/contracts/declarations.ligo +++ b/src/test/contracts/declarations.ligo @@ -1,3 +1,5 @@ +// Test PascaLIGO top level declarations + const foo : int = 42 function main (const i : int) : int is diff --git a/src/contracts/dispatch-counter.ligo b/src/test/contracts/dispatch-counter.ligo similarity index 100% rename from src/contracts/dispatch-counter.ligo rename to src/test/contracts/dispatch-counter.ligo diff --git a/src/contracts/error_syntax.ligo b/src/test/contracts/error_syntax.ligo similarity index 100% rename from src/contracts/error_syntax.ligo rename to src/test/contracts/error_syntax.ligo diff --git a/src/test/contracts/error_type.ligo b/src/test/contracts/error_type.ligo new file mode 100644 index 000000000..6f828b9bf --- /dev/null +++ b/src/test/contracts/error_type.ligo @@ -0,0 +1,3 @@ +// Test that PascaLIGO will reject a type declaration with improper value expression + +const foo : nat = 42 + "bar" diff --git a/src/test/contracts/failwith.ligo b/src/test/contracts/failwith.ligo new file mode 100644 index 000000000..9a59c5ec4 --- /dev/null +++ b/src/test/contracts/failwith.ligo @@ -0,0 +1,12 @@ +type param is +| Zero of nat +| Pos of nat + +function main (const p : param; const s : unit) : list(operation) * unit is + block { + case p of + | Zero (n) -> if n > 0n then failwith("fail") else skip + | Pos (n) -> if n > 0n then skip else failwith("fail") + end + } + with ((nil : list(operation)), s) diff --git a/src/contracts/failwith.mligo b/src/test/contracts/failwith.mligo similarity index 100% rename from src/contracts/failwith.mligo rename to src/test/contracts/failwith.mligo diff --git a/src/contracts/function-complex.ligo b/src/test/contracts/function-complex.ligo similarity index 66% rename from src/contracts/function-complex.ligo rename to src/test/contracts/function-complex.ligo index ec34cab7e..f1f33c74c 100644 --- a/src/contracts/function-complex.ligo +++ b/src/test/contracts/function-complex.ligo @@ -1,3 +1,5 @@ +// Test a PascaLIGO function with more complex logic than function.ligo + function main (const i : int) : int is var j : int := 0 ; var k : int := 1 ; diff --git a/src/contracts/function-shared.ligo b/src/test/contracts/function-shared.ligo similarity index 76% rename from src/contracts/function-shared.ligo rename to src/test/contracts/function-shared.ligo index c84fec402..0155b5cb1 100644 --- a/src/contracts/function-shared.ligo +++ b/src/test/contracts/function-shared.ligo @@ -1,3 +1,5 @@ +// Test a PascaLIGO function which uses other functions as subroutines + function inc ( const i : int ) : int is block { skip } with i + 1 diff --git a/src/contracts/function.ligo b/src/test/contracts/function.ligo similarity index 64% rename from src/contracts/function.ligo rename to src/test/contracts/function.ligo index 8149b2e15..27f4437ef 100644 --- a/src/contracts/function.ligo +++ b/src/test/contracts/function.ligo @@ -1,3 +1,5 @@ +// Test a trivial PascaLIGO function + function main (const i : int) : int is begin skip diff --git a/src/contracts/guess_string.mligo b/src/test/contracts/guess_string.mligo similarity index 100% rename from src/contracts/guess_string.mligo rename to src/test/contracts/guess_string.mligo diff --git a/src/contracts/heap-instance.ligo b/src/test/contracts/heap-instance.ligo similarity index 100% rename from src/contracts/heap-instance.ligo rename to src/test/contracts/heap-instance.ligo diff --git a/src/contracts/heap.ligo b/src/test/contracts/heap.ligo similarity index 95% rename from src/contracts/heap.ligo rename to src/test/contracts/heap.ligo index 23d7425b7..48130f96b 100644 --- a/src/contracts/heap.ligo +++ b/src/test/contracts/heap.ligo @@ -1,3 +1,6 @@ +// Implementation of the heap data structure in PascaLIGO +// See: https://en.wikipedia.org/wiki/Heap_%28data_structure%29 + type heap is map(nat, heap_element) ; function is_empty (const h : heap) : bool is diff --git a/src/contracts/high-order.ligo b/src/test/contracts/high-order.ligo similarity index 72% rename from src/contracts/high-order.ligo rename to src/test/contracts/high-order.ligo index 8dc7f3e4b..7c897d4ee 100644 --- a/src/contracts/high-order.ligo +++ b/src/test/contracts/high-order.ligo @@ -1,3 +1,5 @@ +// Test a PascaLIGO function which takes another PascaLIGO function as an argument + function foobar (const i : int) : int is function foo (const i : int) : int is block { skip } with i ; diff --git a/src/test/contracts/included.ligo b/src/test/contracts/included.ligo new file mode 100644 index 000000000..1ab1451af --- /dev/null +++ b/src/test/contracts/included.ligo @@ -0,0 +1,3 @@ +// Test PascaLIGO inclusion statements, see includer.ligo + +const foo : int = 144 diff --git a/src/test/contracts/includer.ligo b/src/test/contracts/includer.ligo new file mode 100644 index 000000000..3afbfaa79 --- /dev/null +++ b/src/test/contracts/includer.ligo @@ -0,0 +1,5 @@ +// Test PascaLIGO inclusion statements, see included.ligo + +#include "included.ligo" + +const bar : int = foo diff --git a/src/contracts/lambda.ligo b/src/test/contracts/lambda.ligo similarity index 100% rename from src/contracts/lambda.ligo rename to src/test/contracts/lambda.ligo diff --git a/src/contracts/lambda.mligo b/src/test/contracts/lambda.mligo similarity index 100% rename from src/contracts/lambda.mligo rename to src/test/contracts/lambda.mligo diff --git a/src/contracts/lambda2.mligo b/src/test/contracts/lambda2.mligo similarity index 100% rename from src/contracts/lambda2.mligo rename to src/test/contracts/lambda2.mligo diff --git a/src/contracts/letin.mligo b/src/test/contracts/letin.mligo similarity index 100% rename from src/contracts/letin.mligo rename to src/test/contracts/letin.mligo diff --git a/src/contracts/list.ligo b/src/test/contracts/list.ligo similarity index 92% rename from src/contracts/list.ligo rename to src/test/contracts/list.ligo index a533d12e2..0a1d0c05d 100644 --- a/src/contracts/list.ligo +++ b/src/test/contracts/list.ligo @@ -1,3 +1,5 @@ +// Test list type and related built-in functions in PascaLIGO + type foobar is list(int) const fb : foobar = list diff --git a/src/test/contracts/list.mligo b/src/test/contracts/list.mligo new file mode 100644 index 000000000..77bd98fc2 --- /dev/null +++ b/src/test/contracts/list.mligo @@ -0,0 +1,26 @@ +type storage = int * int list + +type param = int list + +let x : int list = [] +let y : int list = [ 3 ; 4 ; 5 ] +let z : int list = 2 :: y + +let%entry main (p : param) storage = + let storage = + match p with + [] -> storage + | hd::tl -> storage.(0) + hd, tl + in (([] : operation list), storage) + +let fold_op (s : int list) : int = + let aggregate = fun (prec : int) (cur : int) -> prec + cur in + List.fold s 10 aggregate + +let map_op (s : int list) : int list = + let aggregate = fun (cur : int) -> cur + 1 in + List.map s aggregate + +let iter_op (s : int list) : unit = + let do_nothing = fun (cur : int) -> unit in + List.iter s do_nothing diff --git a/src/contracts/loop.ligo b/src/test/contracts/loop.ligo similarity index 91% rename from src/contracts/loop.ligo rename to src/test/contracts/loop.ligo index 0408f85ef..fcba9fda7 100644 --- a/src/contracts/loop.ligo +++ b/src/test/contracts/loop.ligo @@ -1,3 +1,5 @@ +// Test while loops in PascaLIGO + function counter (var n : nat) : nat is block { var i : nat := 0n ; while (i < n) block { diff --git a/src/contracts/map.ligo b/src/test/contracts/map.ligo similarity index 73% rename from src/contracts/map.ligo rename to src/test/contracts/map.ligo index f0576bf54..dd6770077 100644 --- a/src/contracts/map.ligo +++ b/src/test/contracts/map.ligo @@ -1,3 +1,5 @@ +// Test map type and related built-in functions in PascaLIGO + type foobar is map(int, int) const fb : foobar = map @@ -24,6 +26,11 @@ function get (const m : foobar) : option(int) is skip end with m[42] +function get_ (const m : foobar) : option(int) is + begin + skip + end with map_get(42 , m) + const bm : foobar = map 144 -> 23 ; 51 -> 23 ; @@ -42,3 +49,7 @@ function iter_op (const m : foobar) : int is function map_op (const m : foobar) : foobar is function increment (const i : int ; const j : int) : int is block { skip } with j + 1 ; block { skip } with map_map(m , increment) ; + +function fold_op (const m : foobar) : int is + function aggregate (const i : int ; const j : (int * int)) : int is block { skip } with i + j.0 + j.1 ; + block { skip } with map_fold(m , 10 , aggregate) diff --git a/src/test/contracts/map.mligo b/src/test/contracts/map.mligo new file mode 100644 index 000000000..375a69507 --- /dev/null +++ b/src/test/contracts/map.mligo @@ -0,0 +1,7 @@ +type foobar = (int , int) map + +let foobar : foobar = Map.empty + +let foobarz : foobar = Map.literal [ (1 , 10) ; (2 , 20) ] + +let foo : int = Map.find 1 foobarz diff --git a/src/contracts/match.ligo b/src/test/contracts/match.ligo similarity index 76% rename from src/contracts/match.ligo rename to src/test/contracts/match.ligo index ff5e3a0a4..8c7ce4742 100644 --- a/src/contracts/match.ligo +++ b/src/test/contracts/match.ligo @@ -1,3 +1,5 @@ +// Test the pattern matching functionality of PascaLIGO + function match_bool (const i : int) : int is var result : int := 23 ; begin @@ -29,3 +31,10 @@ function match_expr_option (const o : option(int)) : int is | None -> 42 | Some (s) -> s end + +function match_expr_list (const l : list(int)) : int is + begin skip end with + case l of + | nil -> -1 + | hd # tl -> hd + end diff --git a/src/contracts/match.mligo b/src/test/contracts/match.mligo similarity index 100% rename from src/contracts/match.mligo rename to src/test/contracts/match.mligo diff --git a/src/contracts/match_bis.mligo b/src/test/contracts/match_bis.mligo similarity index 100% rename from src/contracts/match_bis.mligo rename to src/test/contracts/match_bis.mligo diff --git a/src/contracts/multiple-parameters.ligo b/src/test/contracts/multiple-parameters.ligo similarity index 85% rename from src/contracts/multiple-parameters.ligo rename to src/test/contracts/multiple-parameters.ligo index fe2373076..26f5daa0d 100644 --- a/src/contracts/multiple-parameters.ligo +++ b/src/test/contracts/multiple-parameters.ligo @@ -1,3 +1,5 @@ +// Test functions with several parameters in PascaLIGO + function ab(const a : int; const b : int) : int is begin skip end with (a + b) diff --git a/src/contracts/new-syntax.mligo b/src/test/contracts/new-syntax.mligo similarity index 100% rename from src/contracts/new-syntax.mligo rename to src/test/contracts/new-syntax.mligo diff --git a/src/contracts/option.ligo b/src/test/contracts/option.ligo similarity index 67% rename from src/contracts/option.ligo rename to src/test/contracts/option.ligo index 85e3396e0..c2d36439d 100644 --- a/src/contracts/option.ligo +++ b/src/test/contracts/option.ligo @@ -1,3 +1,5 @@ +// Test the option type in PascaLIGO + type foobar is option(int) const s : foobar = Some(42) diff --git a/src/test/contracts/option.mligo b/src/test/contracts/option.mligo new file mode 100644 index 000000000..034871499 --- /dev/null +++ b/src/test/contracts/option.mligo @@ -0,0 +1,4 @@ +type foobar = int option + +let s : foobar = Some 42 +let n : foobar = None diff --git a/src/contracts/parser-bad-reported-term.ligo b/src/test/contracts/parser-bad-reported-term.ligo similarity index 100% rename from src/contracts/parser-bad-reported-term.ligo rename to src/test/contracts/parser-bad-reported-term.ligo diff --git a/src/contracts/quote-declaration.ligo b/src/test/contracts/quote-declaration.ligo similarity index 100% rename from src/contracts/quote-declaration.ligo rename to src/test/contracts/quote-declaration.ligo diff --git a/src/contracts/quote-declarations.ligo b/src/test/contracts/quote-declarations.ligo similarity index 100% rename from src/contracts/quote-declarations.ligo rename to src/test/contracts/quote-declarations.ligo diff --git a/src/contracts/record.ligo b/src/test/contracts/record.ligo similarity index 95% rename from src/contracts/record.ligo rename to src/test/contracts/record.ligo index e0fbb5d04..cb578abb0 100644 --- a/src/contracts/record.ligo +++ b/src/test/contracts/record.ligo @@ -1,3 +1,5 @@ +// Test record type in PascaLIGO + type foobar is record foo : int ; bar : int ; diff --git a/src/contracts/record.mligo b/src/test/contracts/record.mligo similarity index 100% rename from src/contracts/record.mligo rename to src/test/contracts/record.mligo diff --git a/src/test/contracts/set_arithmetic-1.ligo b/src/test/contracts/set_arithmetic-1.ligo new file mode 100644 index 000000000..f5d332687 --- /dev/null +++ b/src/test/contracts/set_arithmetic-1.ligo @@ -0,0 +1,16 @@ +// Test set iteration in PascaLIGO + +function iter_op (const s : set(int)) : int is + var r : int := 0 ; + function aggregate (const i : int) : unit is + begin + r := r + i ; + end with unit + begin + set_iter(s , aggregate) ; + end with r + +function fold_op (const s : set(int)) : int is + function aggregate (const i : int ; const j : int) : int is + block { skip } with i + j + block { skip } with set_fold(s , 15 , aggregate) diff --git a/src/contracts/set_arithmetic.ligo b/src/test/contracts/set_arithmetic.ligo similarity index 89% rename from src/contracts/set_arithmetic.ligo rename to src/test/contracts/set_arithmetic.ligo index f85e42394..cd7c1175c 100644 --- a/src/contracts/set_arithmetic.ligo +++ b/src/test/contracts/set_arithmetic.ligo @@ -1,3 +1,5 @@ +// Test set type and basic operations in PascaLIGO + const s_e : set(string) = (set_empty : set(string)) const s_fb : set(string) = set [ diff --git a/src/contracts/shadow.ligo b/src/test/contracts/shadow.ligo similarity index 100% rename from src/contracts/shadow.ligo rename to src/test/contracts/shadow.ligo diff --git a/src/contracts/string.ligo b/src/test/contracts/string.ligo similarity index 100% rename from src/contracts/string.ligo rename to src/test/contracts/string.ligo diff --git a/src/contracts/string_arithmetic.ligo b/src/test/contracts/string_arithmetic.ligo similarity index 100% rename from src/contracts/string_arithmetic.ligo rename to src/test/contracts/string_arithmetic.ligo diff --git a/src/contracts/super-counter.ligo b/src/test/contracts/super-counter.ligo similarity index 100% rename from src/contracts/super-counter.ligo rename to src/test/contracts/super-counter.ligo diff --git a/src/contracts/super-counter.mligo b/src/test/contracts/super-counter.mligo similarity index 100% rename from src/contracts/super-counter.mligo rename to src/test/contracts/super-counter.mligo diff --git a/src/contracts/toto.ligo b/src/test/contracts/toto.ligo similarity index 100% rename from src/contracts/toto.ligo rename to src/test/contracts/toto.ligo diff --git a/src/contracts/tuple.ligo b/src/test/contracts/tuple.ligo similarity index 100% rename from src/contracts/tuple.ligo rename to src/test/contracts/tuple.ligo diff --git a/src/contracts/type-alias.ligo b/src/test/contracts/type-alias.ligo similarity index 100% rename from src/contracts/type-alias.ligo rename to src/test/contracts/type-alias.ligo diff --git a/src/contracts/unit.ligo b/src/test/contracts/unit.ligo similarity index 100% rename from src/contracts/unit.ligo rename to src/test/contracts/unit.ligo diff --git a/src/contracts/variant-matching.ligo b/src/test/contracts/variant-matching.ligo similarity index 100% rename from src/contracts/variant-matching.ligo rename to src/test/contracts/variant-matching.ligo diff --git a/src/contracts/variant.ligo b/src/test/contracts/variant.ligo similarity index 100% rename from src/contracts/variant.ligo rename to src/test/contracts/variant.ligo diff --git a/src/contracts/vote.mligo b/src/test/contracts/vote.mligo similarity index 100% rename from src/contracts/vote.mligo rename to src/test/contracts/vote.mligo diff --git a/src/contracts/website1.ligo b/src/test/contracts/website1.ligo similarity index 100% rename from src/contracts/website1.ligo rename to src/test/contracts/website1.ligo diff --git a/src/contracts/website2.ligo b/src/test/contracts/website2.ligo similarity index 100% rename from src/contracts/website2.ligo rename to src/test/contracts/website2.ligo diff --git a/src/test/dune b/src/test/dune index 021ae172f..dda46f5e8 100644 --- a/src/test/dune +++ b/src/test/dune @@ -10,3 +10,20 @@ ) (flags (:standard -w +1..62-4-9-44-40-42-48@39@33 -open Simple_utils )) ) + +(alias + (name ligo-test) + (action (run ./test.exe)) + (deps (glob_files contracts/*)) +) + +(alias + (name runtest) + (deps (alias ligo-test)) +) + +(alias + (name manual-test) + (action (run ./manual_test.exe)) + (deps (glob_files contracts/*)) +) diff --git a/src/test/heap_tests.ml b/src/test/heap_tests.ml index 5a6f440df..2b66de488 100644 --- a/src/test/heap_tests.ml +++ b/src/test/heap_tests.ml @@ -1,8 +1,7 @@ open Trace -open Ligo.Run open Test_helpers -let type_file = type_file `pascaligo +let type_file = Ligo.Compile.Of_source.type_file (Syntax_name "pascaligo") let get_program = let s = ref None in @@ -45,6 +44,8 @@ let dummy n = @@ range (n + 1) ) +let run_typed = Run.Of_typed.run_entry + let is_empty () : unit result = let%bind program = get_program () in let aux n = diff --git a/src/test/integration_tests.ml b/src/test/integration_tests.ml index baea8d256..10d671050 100644 --- a/src/test/integration_tests.ml +++ b/src/test/integration_tests.ml @@ -1,11 +1,10 @@ open Trace -open Ligo.Run open Test_helpers open Ast_simplified.Combinators -let mtype_file ?debug_simplify ?debug_typed = type_file ?debug_simplify ?debug_typed `cameligo -let type_file = type_file `pascaligo +let mtype_file ?debug_simplify ?debug_typed = Ligo.Compile.Of_source.type_file ?debug_simplify ?debug_typed (Syntax_name "cameligo") +let type_file = Ligo.Compile.Of_source.type_file (Syntax_name "pascaligo") let type_alias () : unit result = let%bind program = type_file "./contracts/type-alias.ligo" in @@ -29,9 +28,6 @@ let annotation () : unit result = let%bind () = expect_eq_evaluate program "address" (e_address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx") in - let%bind () = - expect_eq_evaluate program "address_2" (e_address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx") - in ok () let complex_function () : unit result = @@ -100,14 +96,21 @@ let higher_order () : unit result = let shared_function () : unit result = let%bind program = type_file "./contracts/function-shared.ligo" in + Format.printf "inc\n" ; let%bind () = let make_expect = fun n -> (n + 1) in expect_eq_n_int program "inc" make_expect in + Format.printf "double inc?\n" ; + let%bind () = + expect_eq program "double_inc" (e_int 0) (e_int 2) + in + Format.printf "double incd!\n" ; let%bind () = let make_expect = fun n -> (n + 2) in expect_eq_n_int program "double_inc" make_expect in + Format.printf "foo\n" ; let%bind () = let make_expect = fun n -> (2 * n + 3) in expect_eq program "foo" (e_int 0) (e_int @@ make_expect 0) @@ -184,9 +187,9 @@ let bytes_arithmetic () : unit result = let%bind () = expect_eq program "slice_op" tata at in let%bind () = expect_fail program "slice_op" foo in let%bind () = expect_fail program "slice_op" ba in - let%bind b1 = run_simplityped program "hasherman" foo in + let%bind b1 = Run.Of_simplified.run_typed_program program "hasherman" foo in let%bind () = expect_eq program "hasherman" foo b1 in - let%bind b3 = run_simplityped program "hasherman" foototo in + let%bind b3 = Run.Of_simplified.run_typed_program program "hasherman" foototo in let%bind () = Assert.assert_fail @@ Ast_simplified.Misc.assert_value_eq (b3 , b1) in ok () @@ -221,6 +224,11 @@ let set_arithmetic () : unit result = expect_eq program "mem_op" (e_set [e_string "foo" ; e_string "bar"]) (e_bool false) in + let%bind () = + expect_eq program_1 "fold_op" + (e_set [ e_int 4 ; e_int 10 ]) + (e_int 29) + in ok () let unit_expression () : unit result = @@ -337,6 +345,27 @@ let option () : unit result = in ok () +let moption () : unit result = + let%bind program = mtype_file "./contracts/option.mligo" in + let%bind () = + let expected = e_some (e_int 42) in + expect_eq_evaluate program "s" expected + in + let%bind () = + let expected = e_typed_none t_int in + expect_eq_evaluate program "n" expected + in + ok () + +let mmap () : unit result = + let%bind program = mtype_file "./contracts/map.mligo" in + let%bind () = expect_eq_evaluate program "foobar" + (e_annotation (e_map []) (t_map t_int t_int)) in + let%bind () = expect_eq_evaluate program "foobarz" + (e_annotation (e_map [(e_int 1 , e_int 10) ; (e_int 2 , e_int 20)]) (t_map t_int t_int)) in + let%bind () = expect_eq_evaluate program "foo" (e_int 10) in + ok () + let map () : unit result = let%bind program = type_file "./contracts/map.ligo" in let ez lst = @@ -371,6 +400,11 @@ let map () : unit result = let make_expected = fun _ -> e_some @@ e_int 4 in expect_eq_n program "get" make_input make_expected in + let%bind () = + let make_input = fun n -> ez [(23, n) ; (42, 4)] in + let make_expected = fun _ -> e_some @@ e_int 4 in + expect_eq_n program "get_" make_input make_expected + in let%bind () = let expected = ez @@ List.map (fun x -> (x, 23)) [144 ; 51 ; 42 ; 120 ; 421] in expect_eq_evaluate program "bm" expected @@ -385,6 +419,11 @@ let map () : unit result = let expected = e_int 66 in expect_eq program "iter_op" input expected in + let%bind () = + let input = ez [(1 , 10) ; (2 , 20) ; (3 , 30) ] in + let expected = e_int 76 in + expect_eq program "fold_op" input expected + in let%bind () = let input = ez [(1 , 10) ; (2 , 20) ; (3 , 30) ] in let expected = ez [(1 , 11) ; (2 , 21) ; (3 , 31) ] in @@ -392,6 +431,38 @@ let map () : unit result = in ok () +let big_map () : unit result = + let%bind program = type_file "./contracts/big_map.ligo" in + let ez lst = + let open Ast_simplified.Combinators in + let lst' = List.map (fun (x, y) -> e_int x, e_int y) lst in + e_pair (e_typed_big_map lst' t_int t_int) (e_unit ()) + in + let%bind () = + let make_input = fun n -> ez [(23, n) ; (42, 4)] in + let make_expected = e_int in + expect_eq_n ~input_to_value:true program "gf" make_input make_expected + in + let%bind () = + let make_input = fun n -> + let m = ez [(23 , 0) ; (42 , 0)] in + e_tuple [(e_int n) ; m] + in + let make_expected = fun n -> ez [(23 , n) ; (42 , 0)] in + expect_eq_n_pos_small ?input_to_value:(Some true) program "set_" make_input make_expected + in + let%bind () = + let make_input = fun n -> ez [(23, n) ; (42, 4)] in + let make_expected = fun _ -> e_some @@ e_int 4 in + expect_eq_n ?input_to_value:(Some true) program "get" make_input make_expected + in + let%bind () = + let input = ez [(23, 23) ; (42, 42)] in + let expected = ez [23, 23] in + expect_eq ?input_to_value:(Some true) program "rm" input expected + in + ok () + let list () : unit result = let%bind program = type_file "./contracts/list.ligo" in let ez lst = @@ -502,6 +573,13 @@ let matching () : unit result = bind_iter_list aux [Some 0 ; Some 2 ; Some 42 ; Some 163 ; Some (-1) ; None] in + let%bind () = + let aux lst = e_annotation (e_list @@ List.map e_int lst) (t_list t_int) in + let%bind () = expect_eq program "match_expr_list" (aux [ 14 ; 2 ; 3 ]) (e_int 14) in + let%bind () = expect_eq program "match_expr_list" (aux [ 13 ; 2 ; 3 ]) (e_int 13) in + let%bind () = expect_eq program "match_expr_list" (aux []) (e_int (-1)) in + ok () + in ok () let declarations () : unit result = @@ -565,11 +643,28 @@ let dispatch_counter_contract () : unit result = e_pair (e_typed_list [] t_operation) (e_int (op 42 n)) in expect_eq_n program "main" make_input make_expected +let failwith_ligo () : unit result = + let%bind program = type_file "./contracts/failwith.ligo" in + let should_fail = expect_fail program "main" in + let should_work input = expect_eq program "main" input (e_pair (e_typed_list [] t_operation) (e_unit ())) in + let%bind _ = should_work (e_pair (e_constructor "Zero" (e_nat 0)) (e_unit ())) in + let%bind _ = should_fail (e_pair (e_constructor "Zero" (e_nat 1)) (e_unit ())) in + let%bind _ = should_work (e_pair (e_constructor "Pos" (e_nat 1)) (e_unit ())) in + let%bind _ = should_fail (e_pair (e_constructor "Pos" (e_nat 0)) (e_unit ())) in + ok () + let failwith_mligo () : unit result = let%bind program = mtype_file "./contracts/failwith.mligo" in let make_input = e_pair (e_unit ()) (e_unit ()) in + expect_fail program "main" make_input + +let assert_mligo () : unit result = + let%bind program = mtype_file "./contracts/assert.mligo" in + let make_input b = e_pair (e_bool b) (e_unit ()) in let make_expected = e_pair (e_typed_list [] t_operation) (e_unit ()) in - expect_eq program "main" make_input make_expected + let%bind _ = expect_fail program "main" (make_input false) in + let%bind _ = expect_eq program "main" (make_input true) make_expected in + ok () let guess_the_hash_mligo () : unit result = let%bind program = mtype_file "./contracts/new-syntax.mligo" in @@ -585,9 +680,9 @@ let guess_string_mligo () : unit result = let basic_mligo () : unit result = let%bind typed = mtype_file ~debug_simplify:true "./contracts/basic.mligo" in - let%bind result = evaluate_typed "foo" typed in - Ligo.AST_Typed.assert_value_eq - (Ligo.AST_Typed.Combinators.e_a_empty_int (42 + 127), result) + let%bind result = Run.Of_typed.evaluate_entry typed "foo" in + Ast_typed.assert_value_eq + (Ast_typed.Combinators.e_a_empty_int (42 + 127), result) let counter_mligo () : unit result = let%bind program = mtype_file "./contracts/counter.mligo" in @@ -620,13 +715,24 @@ let match_matej () : unit result = let mligo_list () : unit result = let%bind program = mtype_file "./contracts/list.mligo" in - let make_input n = - e_pair (e_list [e_int n; e_int (2*n)]) - (e_pair (e_int 3) (e_list [e_int 8])) in - let make_expected n = - e_pair (e_typed_list [] t_operation) - (e_pair (e_int (n+3)) (e_list [e_int (2*n)])) - in expect_eq_n program "main" make_input make_expected + let aux lst = e_list @@ List.map e_int lst in + let%bind () = expect_eq program "fold_op" (aux [ 1 ; 2 ; 3 ]) (e_int 16) in + let%bind () = + let make_input n = + e_pair (e_list [e_int n; e_int (2*n)]) + (e_pair (e_int 3) (e_list [e_int 8])) in + let make_expected n = + e_pair (e_typed_list [] t_operation) + (e_pair (e_int (n+3)) (e_list [e_int (2*n)])) + in + expect_eq_n program "main" make_input make_expected + in + let%bind () = expect_eq_evaluate program "x" (e_list []) in + let%bind () = expect_eq_evaluate program "y" (e_list @@ List.map e_int [3 ; 4 ; 5]) in + let%bind () = expect_eq_evaluate program "z" (e_list @@ List.map e_int [2 ; 3 ; 4 ; 5]) in + let%bind () = expect_eq program "map_op" (aux [2 ; 3 ; 4 ; 5]) (aux [3 ; 4 ; 5 ; 6]) in + let%bind () = expect_eq program "iter_op" (aux [2 ; 3 ; 4 ; 5]) (e_unit ()) in + ok () let lambda_mligo () : unit result = let%bind program = mtype_file "./contracts/lambda.mligo" in @@ -689,7 +795,10 @@ let main = test_suite "Integration (End to End)" [ test "unit" unit_expression ; test "string" string_expression ; test "option" option ; + test "option (mligo)" moption ; test "map" map ; + test "map (mligo)" mmap ; + test "big_map" big_map ; test "list" list ; test "loop" loop ; test "matching" matching ; @@ -706,9 +815,11 @@ let main = test_suite "Integration (End to End)" [ test "let-in (mligo)" let_in_mligo ; test "match variant (mligo)" match_variant ; test "match variant 2 (mligo)" match_matej ; - (* test "list matching (mligo)" mligo_list ; *) + test "list matching (mligo)" mligo_list ; (* test "guess the hash mligo" guess_the_hash_mligo ; WIP? *) - (* test "failwith mligo" failwith_mligo ; *) + test "failwith ligo" failwith_ligo ; + test "failwith mligo" failwith_mligo ; + test "assert mligo" assert_mligo ; (* test "guess string mligo" guess_string_mligo ; WIP? *) test "lambda mligo" lambda_mligo ; test "lambda ligo" lambda_ligo ; diff --git a/src/test/test_helpers.ml b/src/test/test_helpers.ml index f1a51a794..9eee8adc0 100644 --- a/src/test/test_helpers.ml +++ b/src/test/test_helpers.ml @@ -12,14 +12,14 @@ let wrap_test name f = match result with | Ok ((), annotations) -> ignore annotations; () | Error err -> - Format.printf "%a\n%!" Ligo.Display.error_pp (err ()) ; + Format.printf "%a\n%!" (Ligo.Display.error_pp ~dev:true) (err ()) ; raise Alcotest.Test_error let wrap_test_raw f = match f () with | Trace.Ok ((), annotations) -> ignore annotations; () | Error err -> - Format.printf "%a\n%!" Ligo.Display.error_pp (err ()) + Format.printf "%a\n%!" (Ligo.Display.error_pp ~dev:true) (err ()) let test name f = Test ( @@ -31,14 +31,14 @@ let test_suite name lst = Test_suite (name , lst) open Ast_simplified.Combinators -let expect ?options program entry_point input expecter = +let expect ?input_to_value ?options program entry_point input expecter = let%bind result = let run_error = let title () = "expect run" in let content () = Format.asprintf "Entry_point: %s" entry_point in error title content in trace run_error @@ - Ligo.Run.run_simplityped ~debug_michelson:true ?options program entry_point input in + Ligo.Run.Of_simplified.run_typed_program ?input_to_value ?options program entry_point input in expecter result let expect_fail ?options program entry_point input = @@ -49,10 +49,10 @@ let expect_fail ?options program entry_point input = in trace run_error @@ Assert.assert_fail - @@ Ligo.Run.run_simplityped ~debug_michelson:true ?options program entry_point input + @@ Ligo.Run.Of_simplified.run_typed_program ?options program entry_point input -let expect_eq ?options program entry_point input expected = +let expect_eq ?input_to_value ?options program entry_point input expected = let expecter = fun result -> let expect_error = let title () = "expect result" in @@ -62,7 +62,7 @@ let expect_eq ?options program entry_point input expected = error title content in trace expect_error @@ Ast_simplified.Misc.assert_value_eq (expected , result) in - expect ?options program entry_point input expecter + expect ?input_to_value ?options program entry_point input expecter let expect_evaluate program entry_point expecter = let error = @@ -70,7 +70,7 @@ let expect_evaluate program entry_point expecter = let content () = Format.asprintf "Entry_point: %s" entry_point in error title content in trace error @@ - let%bind result = Ligo.Run.evaluate_simplityped ~debug_mini_c:true ~debug_michelson:true program entry_point in + let%bind result = Ligo.Run.Of_simplified.evaluate_typed_program_entry program entry_point in expecter result let expect_eq_evaluate program entry_point expected = @@ -89,23 +89,23 @@ let expect_n_aux ?options lst program entry_point make_input make_expecter = let%bind _ = bind_map_list aux lst in ok () -let expect_eq_n_aux ?options lst program entry_point make_input make_expected = +let expect_eq_n_aux ?input_to_value ?options lst program entry_point make_input make_expected = let aux n = let input = make_input n in let expected = make_expected n in trace (simple_error ("expect_eq_n " ^ (string_of_int n))) @@ - let result = expect_eq ?options program entry_point input expected in + let result = expect_eq ?input_to_value ?options program entry_point input expected in result in let%bind _ = bind_map_list_seq aux lst in ok () -let expect_eq_n ?options = expect_eq_n_aux ?options [0 ; 1 ; 2 ; 42 ; 163 ; -1] -let expect_eq_n_pos ?options = expect_eq_n_aux ?options [0 ; 1 ; 2 ; 42 ; 163] -let expect_eq_n_strict_pos ?options = expect_eq_n_aux ?options [2 ; 42 ; 163] -let expect_eq_n_pos_small ?options = expect_eq_n_aux ?options [0 ; 1 ; 2 ; 10] -let expect_eq_n_strict_pos_small ?options = expect_eq_n_aux ?options [1 ; 2 ; 10] -let expect_eq_n_pos_mid = expect_eq_n_aux [0 ; 1 ; 2 ; 10 ; 33] +let expect_eq_n ?input_to_value ?options = expect_eq_n_aux ?input_to_value ?options [0 ; 1 ; 2 ; 42 ; 163 ; -1] +let expect_eq_n_pos ?input_to_value ?options = expect_eq_n_aux ?input_to_value ?options [0 ; 1 ; 2 ; 42 ; 163] +let expect_eq_n_strict_pos ?input_to_value ?options = expect_eq_n_aux ?input_to_value ?options [2 ; 42 ; 163] +let expect_eq_n_pos_small ?input_to_value ?options = expect_eq_n_aux ?input_to_value ?options [0 ; 1 ; 2 ; 10] +let expect_eq_n_strict_pos_small ?input_to_value ?options = expect_eq_n_aux ?input_to_value ?options [1 ; 2 ; 10] +let expect_eq_n_pos_mid ?input_to_value = expect_eq_n_aux ?input_to_value [0 ; 1 ; 2 ; 10 ; 33] let expect_n_pos_small ?options = expect_n_aux ?options [0 ; 2 ; 10] let expect_n_strict_pos_small ?options = expect_n_aux ?options [2 ; 10] diff --git a/src/test/typer_tests.ml b/src/test/typer_tests.ml index b61da4bd0..b22fb01db 100644 --- a/src/test/typer_tests.ml +++ b/src/test/typer_tests.ml @@ -1,10 +1,10 @@ open Trace -open Ligo.AST_Simplified +open Ast_simplified open Test_helpers -module Typed = Ligo.AST_Typed -module Typer = Ligo.Typer -module Simplified = Ligo.AST_Simplified +module Typed = Ast_typed +module Typer = Typer +module Simplified = Ast_simplified let int () : unit result = let open Combinators in diff --git a/src/test/vote_tests.ml b/src/test/vote_tests.ml index d4d1f9336..683169ee2 100644 --- a/src/test/vote_tests.ml +++ b/src/test/vote_tests.ml @@ -1,13 +1,14 @@ open Trace -open Ligo.Run open Test_helpers +let type_file = Ligo.Compile.Of_source.type_file (Syntax_name "cameligo") + let get_program = let s = ref None in fun () -> match !s with | Some s -> ok s | None -> ( - let%bind program = type_file `cameligo "./contracts/vote.mligo" in + let%bind program = type_file "./contracts/vote.mligo" in s := Some program ; ok program ) @@ -39,7 +40,7 @@ let vote str = let init_vote () = let%bind program = get_program () in - let%bind result = Ligo.Run.run_simplityped program "main" (e_pair (vote "Yes") (init_storage "basic")) in + let%bind result = Ligo.Run.Of_simplified.run_typed_program program "main" (e_pair (vote "Yes") (init_storage "basic")) in let%bind (_ , storage) = extract_pair result in let%bind storage' = extract_record storage in let votes = List.assoc "candidates" storage' in diff --git a/vendors/ligo-utils/simple-utils/trace.ml b/vendors/ligo-utils/simple-utils/trace.ml index 52637021e..329203a46 100644 --- a/vendors/ligo-utils/simple-utils/trace.ml +++ b/vendors/ligo-utils/simple-utils/trace.ml @@ -639,6 +639,8 @@ let bind_or (a, b) = match a with | Ok _ as o -> o | _ -> b +let bind_map_or (fa , fb) c = + bind_or (fa c , fb c) let bind_lr (type a b) ((a : a result), (b:b result)) : [`Left of a | `Right of b] result = match (a, b) with diff --git a/vendors/ligo-utils/simple-utils/x_list.ml b/vendors/ligo-utils/simple-utils/x_list.ml index 9037b0e9e..a7d36261b 100644 --- a/vendors/ligo-utils/simple-utils/x_list.ml +++ b/vendors/ligo-utils/simple-utils/x_list.ml @@ -5,7 +5,6 @@ let rec remove n = function | _ :: tl when n = 0 -> tl | hd :: tl -> hd :: remove (n - 1) tl - let map ?(acc = []) f lst = let rec aux acc f = function | [] -> acc @@ -23,7 +22,7 @@ let fold_map_right : type acc ele ret . (acc -> ele -> (acc * ret)) -> acc -> el in snd @@ aux (acc , []) f (List.rev lst) -let fold_map : type acc ele ret . (acc -> ele -> (acc * ret)) -> acc -> ele list -> ret list = +let fold_map_acc : type acc ele ret . (acc -> ele -> (acc * ret)) -> acc -> ele list -> acc * ret list = fun f acc lst -> let rec aux (acc , prev) f = function | [] -> (acc , prev) @@ -31,7 +30,12 @@ let fold_map : type acc ele ret . (acc -> ele -> (acc * ret)) -> acc -> ele list let (acc' , hd') = f acc hd in aux (acc' , hd' :: prev) f tl in - List.rev @@ snd @@ aux (acc , []) f lst + let (acc, lst) = aux (acc , []) f lst in + (acc, List.rev lst) + +let fold_map : type acc ele ret . (acc -> ele -> (acc * ret)) -> acc -> ele list -> ret list = + fun f acc lst -> + snd (fold_map_acc f acc lst) let fold_right' f init lst = List.fold_left f init (List.rev lst) diff --git a/vendors/ligo-utils/tezos-utils/x_michelson.ml b/vendors/ligo-utils/tezos-utils/x_michelson.ml index 6bb8e6203..5ac8d1282 100644 --- a/vendors/ligo-utils/tezos-utils/x_michelson.ml +++ b/vendors/ligo-utils/tezos-utils/x_michelson.ml @@ -15,7 +15,6 @@ let annotate annot = function let seq s : michelson = Seq (0, s) -let i_comment s : michelson = seq [ prim ~annot:["\"" ^ s ^ "\""] I_UNIT ; prim I_DROP ] let contract parameter storage code = seq [ @@ -45,6 +44,9 @@ let i_piar = seq [ i_swap ; i_pair ] let i_push ty code = prim ~children:[ty;code] I_PUSH let i_push_unit = i_push t_unit d_unit let i_push_string str = i_push t_string (string str) + +let i_comment s : michelson = seq [ i_push_string s ; prim I_DROP ] + let i_none ty = prim ~children:[ty] I_NONE let i_nil ty = prim ~children:[ty] I_NIL let i_empty_set ty = prim ~children:[ty] I_EMPTY_SET @@ -58,6 +60,7 @@ let i_exec = prim I_EXEC let i_if a b = prim ~children:[seq [a] ; seq[b]] I_IF let i_if_none a b = prim ~children:[seq [a] ; seq[b]] I_IF_NONE +let i_if_cons a b = prim ~children:[seq [a] ; seq[b]] I_IF_CONS let i_if_left a b = prim ~children:[seq [a] ; seq[b]] I_IF_LEFT let i_failwith = prim I_FAILWITH let i_assert_some = i_if_none (seq [i_push_string "ASSERT_SOME" ; i_failwith]) (seq []) @@ -84,6 +87,18 @@ let pp ppf (michelson:michelson) = let node = printable string_of_prim canonical in print_expr ppf node +let pp_json ppf (michelson : michelson) = + let open Micheline_printer in + let canonical = strip_locations michelson in + let node = printable string_of_prim canonical in + let json = Tezos_data_encoding.( + Json.construct + (Micheline.erased_encoding ~variant:"???" {comment = None} Data_encoding.string) + node + ) + in + Format.fprintf ppf "%a" Tezos_data_encoding.Json.pp json + let pp_stripped ppf (michelson:michelson) = let open Micheline_printer in let michelson' = strip_nops @@ strip_annots michelson in diff --git a/src/rope/rope.ml b/vendors/rope/rope.ml similarity index 100% rename from src/rope/rope.ml rename to vendors/rope/rope.ml diff --git a/src/rope/rope.mli b/vendors/rope/rope.mli similarity index 100% rename from src/rope/rope.mli rename to vendors/rope/rope.mli diff --git a/src/rope/rope_implementation.ml b/vendors/rope/rope_implementation.ml similarity index 100% rename from src/rope/rope_implementation.ml rename to vendors/rope/rope_implementation.ml diff --git a/src/rope/rope_implementation.mli b/vendors/rope/rope_implementation.mli similarity index 100% rename from src/rope/rope_implementation.mli rename to vendors/rope/rope_implementation.mli diff --git a/src/rope/rope_test.ml b/vendors/rope/rope_test.ml similarity index 100% rename from src/rope/rope_test.ml rename to vendors/rope/rope_test.ml diff --git a/src/rope/rope_top_level_open.ml b/vendors/rope/rope_top_level_open.ml similarity index 100% rename from src/rope/rope_top_level_open.ml rename to vendors/rope/rope_top_level_open.ml diff --git a/src/rope/rope_top_level_open.mli b/vendors/rope/rope_top_level_open.mli similarity index 100% rename from src/rope/rope_top_level_open.mli rename to vendors/rope/rope_top_level_open.mli