diff --git a/.gitignore b/.gitignore index 20157262c..d2d2464e1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ Version.ml **/.DS_Store .vscode/ /ligo.install +*.coverage /_coverage/ -/_coverage_all/ -/_coverage_ligo/ -/_coverage_cli/ +/_coverage_*/ diff --git a/Makefile b/Makefile index 7932e1d84..f69d64ba3 100644 --- a/Makefile +++ b/Makefile @@ -45,9 +45,12 @@ coverage-ligo: clean bisect-ppx-report html -o ./_coverage_ligo --title="LIGO test coverage" bisect-ppx-report summary --per-file +coverage-doc: clean + BISECT_ENABLE=yes dune build @doc-test --force + bisect-ppx-report html -o ./_coverage_doc --title="LIGO doc coverage" + bisect-ppx-report summary --per-file + coverage-cli: clean BISECT_ENABLE=yes dune runtest src/bin/expect_tests bisect-ppx-report html -o ./_coverage_cli --title="CLI test coverage" - bisect-ppx-report summary --per-file - # PRE="CLI coverage: " - # bisect-ppx-report summary --per-file | grep 'src/bin/cli.ml\|src/bin/cli_helpers.ml' | awk -v ORS=" " '{print $1}' | awk -v PRE=${PRE} -v POST="%" '{print PRE ($1 + $2 / NF) POST}' \ No newline at end of file + bisect-ppx-report summary --per-file \ No newline at end of file diff --git a/gitlab-pages/docs/language-basics/sets-lists-touples.md b/gitlab-pages/docs/language-basics/sets-lists-touples.md index c11fa1363..88b57518a 100644 --- a/gitlab-pages/docs/language-basics/sets-lists-touples.md +++ b/gitlab-pages/docs/language-basics/sets-lists-touples.md @@ -15,7 +15,7 @@ Sets are similar to lists. The main difference is that elements of a `set` must -```pascaligo +```pascaligo group=a type int_set is set(int); const my_set: int_set = set 1; @@ -25,14 +25,14 @@ end ``` -```cameligo +```cameligo group=a type int_set = int set let my_set: int_set = Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set))) ``` -```reasonligo +```reasonligo group=a type int_set = set(int); let my_set: int_set = Set.add(3, Set.add(2, Set.add(1, Set.empty: set(int)))); @@ -44,16 +44,16 @@ let my_set: int_set = -```pascaligo +```pascaligo group=a const my_set: int_set = set end; const my_set_2: int_set = set_empty; ``` -```cameligo +```cameligo group=a let my_set: int_set = (Set.empty: int set) ``` -```reasonligo +```reasonligo group=a let my_set: int_set = (Set.empty: set(int)); ``` @@ -62,18 +62,18 @@ let my_set: int_set = (Set.empty: set(int)); -```pascaligo +```pascaligo group=a const contains_three: bool = my_set contains 3; // or alternatively const contains_three_fn: bool = set_mem(3, my_set); ``` -```cameligo +```cameligo group=a let contains_three: bool = Set.mem 3 my_set ``` -```reasonligo +```reasonligo group=a let contains_three: bool = Set.mem(3, my_set); ``` @@ -83,17 +83,17 @@ let contains_three: bool = Set.mem(3, my_set); ### Obtaining the size of a set -```pascaligo +```pascaligo group=a const set_size: nat = size(my_set); ``` -```cameligo +```cameligo group=a let set_size: nat = Set.size my_set ``` -```reasonligo +```reasonligo group=a let set_size: nat = Set.size(my_set); ``` @@ -103,21 +103,21 @@ let set_size: nat = Set.size(my_set); ### Modifying a set -```pascaligo +```pascaligo group=a const larger_set: int_set = set_add(4, my_set); const smaller_set: int_set = set_remove(3, my_set); ``` -```cameligo +```cameligo group=a let larger_set: int_set = Set.add 4 my_set let smaller_set: int_set = Set.remove 3 my_set ``` -```reasonligo +```reasonligo group=a let larger_set: int_set = Set.add(4, my_set); let smaller_set: int_set = Set.remove(3, my_set); ``` @@ -128,20 +128,20 @@ let smaller_set: int_set = Set.remove(3, my_set); ### Folding a set -```pascaligo +```pascaligo group=a function sum(const result: int; const i: int): int is result + i; // Outputs 6 const sum_of_a_set: int = set_fold(sum, my_set, 0); ``` -```cameligo +```cameligo group=a let sum (result: int) (i: int) : int = result + i let sum_of_a_set: int = Set.fold sum my_set 0 ``` -```reasonligo +```reasonligo group=a let sum = (result: int, i: int): int => result + i; let sum_of_a_set: int = Set.fold(sum, my_set, 0); ``` @@ -157,7 +157,7 @@ Lists are similar to sets, but their elements don't need to be unique and they d -```pascaligo +```pascaligo group=b type int_list is list(int); const my_list: int_list = list 1; @@ -167,13 +167,13 @@ end ``` -```cameligo +```cameligo group=b type int_list = int list let my_list: int_list = [1; 2; 3] ``` -```reasonligo +```reasonligo group=b type int_list = list(int); let my_list: int_list = [1, 2, 3]; ``` @@ -185,21 +185,21 @@ let my_list: int_list = [1, 2, 3]; -```pascaligo +```pascaligo group=b const larger_list: int_list = cons(4, my_list); const even_larger_list: int_list = 5 # larger_list; ``` -```cameligo +```cameligo group=b let larger_list: int_list = 4 :: my_list (* CameLIGO doesn't have a List.cons *) ``` -```reasonligo +```reasonligo group=b let larger_list: int_list = [4, ...my_list]; -/* ReasonLIGO doesn't have a List.cons */ +(* ReasonLIGO doesn't have a List.cons *) ``` @@ -211,7 +211,7 @@ let larger_list: int_list = [4, ...my_list]; -```pascaligo +```pascaligo group=b function increment(const i: int): int is block { skip } with i + 1; // Creates a new list with elements incremented by 1 const incremented_list: int_list = list_map(increment, even_larger_list); @@ -219,7 +219,7 @@ const incremented_list: int_list = list_map(increment, even_larger_list); -```cameligo +```cameligo group=b let increment (i: int) : int = i + 1 (* Creates a new list with elements incremented by 1 *) let incremented_list: int_list = List.map increment larger_list @@ -228,9 +228,9 @@ let incremented_list: int_list = List.map increment larger_list -```reasonligo +```reasonligo group=b let increment = (i: int): int => i + 1; -/* Creates a new list with elements incremented by 1 */ +(* Creates a new list with elements incremented by 1 *) let incremented_list: int_list = List.map(increment, larger_list); ``` @@ -240,7 +240,7 @@ let incremented_list: int_list = List.map(increment, larger_list); ### Folding of a list: -```pascaligo +```pascaligo group=b function sum(const result: int; const i: int): int is block { skip } with result + i; // Outputs 6 const sum_of_a_list: int = list_fold(sum, my_list, 0); @@ -248,7 +248,7 @@ const sum_of_a_list: int = list_fold(sum, my_list, 0); -```cameligo +```cameligo group=b let sum (result: int) (i: int) : int = result + i // Outputs 6 let sum_of_a_list: int = List.fold sum my_list 0 @@ -256,9 +256,9 @@ let sum_of_a_list: int = List.fold sum my_list 0 -```reasonligo +```reasonligo group=b let sum = (result: int, i: int): int => result + i; -/* Outputs 6 */ +(* Outputs 6 *) let sum_of_a_list: int = List.fold(sum, my_list, 0); ``` @@ -287,22 +287,22 @@ sake of illustration. -```pascaligo +```pascaligo group=c type full_name is string * string; const full_name: full_name = ("Alice", "Johnson"); ``` -```cameligo +```cameligo group=c type full_name = string * string (* The parenthesis here are optional *) let full_name: full_name = ("Alice", "Johnson") ``` -```reasonligo +```reasonligo group=c type full_name = (string, string); -/* The parenthesis here are optional */ +(* The parenthesis here are optional *) let full_name: full_name = ("Alice", "Johnson"); ``` @@ -320,17 +320,17 @@ Tuple elements are one-indexed and accessed like so: -```pascaligo +```pascaligo group=c const first_name: string = full_name.1; ``` -```cameligo +```cameligo group=c let first_name: string = full_name.1 ``` -```reasonligo +```reasonligo group=c let first_name: string = full_name[1]; ``` diff --git a/src/main/compile/helpers.ml b/src/main/compile/helpers.ml index f9706d11c..479b4cd33 100644 --- a/src/main/compile/helpers.ml +++ b/src/main/compile/helpers.ml @@ -68,15 +68,6 @@ let parsify_reasonligo = fun source -> Simplify.Cameligo.simpl_program raw in ok simplified -let parsify_string_reasonligo = fun source -> - let%bind raw = - trace (simple_error "parsing") @@ - Parser.Reasonligo.parse_string source in - let%bind simplified = - trace (simple_error "simplifying") @@ - Simplify.Cameligo.simpl_program raw in - ok simplified - let parsify_expression_reasonligo = fun source -> let%bind raw = trace (simple_error "parsing expression") @@ @@ -105,3 +96,40 @@ let parsify_expression = fun syntax source -> let%bind parsified = parsify source in let%bind applied = Self_ast_simplified.all_expression parsified in ok applied + +let parsify_string_reasonligo = fun source -> + let%bind raw = + trace (simple_error "parsing") @@ + Parser.Reasonligo.parse_string source in + let%bind simplified = + trace (simple_error "simplifying") @@ + Simplify.Cameligo.simpl_program raw in + ok simplified + +let parsify_string_pascaligo = fun source -> + let%bind raw = + trace (simple_error "parsing") @@ + Parser.Pascaligo.parse_string source in + let%bind simplified = + trace (simple_error "simplifying") @@ + Simplify.Pascaligo.simpl_program raw in + ok simplified + +let parsify_string_cameligo = fun source -> + let%bind raw = + trace (simple_error "parsing") @@ + Parser.Cameligo.parse_string source in + let%bind simplified = + trace (simple_error "simplifying") @@ + Simplify.Cameligo.simpl_program raw in + ok simplified + +let parsify_string = fun (syntax : v_syntax) source_filename -> + let%bind parsify = match syntax with + | Pascaligo -> ok parsify_string_pascaligo + | Cameligo -> ok parsify_string_cameligo + | ReasonLIGO -> ok parsify_string_reasonligo + in + let%bind parsified = parsify source_filename in + let%bind applied = Self_ast_simplified.all_program parsified in + ok applied diff --git a/src/main/compile/of_source.ml b/src/main/compile/of_source.ml index 2a08a229b..0c43d7d45 100644 --- a/src/main/compile/of_source.ml +++ b/src/main/compile/of_source.ml @@ -6,6 +6,10 @@ let compile (source_filename:string) syntax : Ast_simplified.program result = let%bind simplified = parsify syntax source_filename in ok simplified +let compile_string (source:string) syntax : Ast_simplified.program result = + let%bind simplified = parsify_string syntax source in + ok simplified + let compile_expression : v_syntax -> string -> Ast_simplified.expression result = fun syntax exp -> parsify_expression syntax exp diff --git a/src/test/doc_test.ml b/src/test/doc_test.ml new file mode 100644 index 000000000..7290c8156 --- /dev/null +++ b/src/test/doc_test.ml @@ -0,0 +1,8 @@ +open Test_helpers + +let () = + Printexc.record_backtrace true ; + run_test @@ test_suite "LIGO" [ + Md_file_tests.main ; + ] ; + () diff --git a/src/test/dune b/src/test/dune index 24a44109f..9c018595d 100644 --- a/src/test/dune +++ b/src/test/dune @@ -1,5 +1,7 @@ +(ocamllex md) + (executables - (names test manual_test) + (names test manual_test doc_test) (libraries simple-utils ligo @@ -12,6 +14,12 @@ (flags (:standard -w +1..62-4-9-44-40-42-48@39@33 -open Simple_utils )) ) +(alias + (name doc-test) + (action (run ./doc_test.exe)) + (deps (source_tree ../../gitlab-pages/docs/language-basics)) +) + (alias (name ligo-test) (action (run ./test.exe)) diff --git a/src/test/md.mll b/src/test/md.mll new file mode 100644 index 000000000..08228de9e --- /dev/null +++ b/src/test/md.mll @@ -0,0 +1,62 @@ +{ +(* initial version taken from https://github.com/realworldocaml/mdx *) +type arg = + | Field of string + | NameValue of string * string + +type block = { + line : int; + file : string; + arguments: arg list; + header : string option; + contents: string list; +} + +exception Err of string + +let line_ref = ref 1 + +let newline lexbuf = + Lexing.new_line lexbuf; + incr line_ref +} + +let eol = '\n' | eof +let ws = ' ' | '\t' + +rule text = parse + | eof { [] } + | "```" ([^' ' '\n']* as h) ws* ([^'\n']* as l) eol + { + let header = if h = "" then None else Some h in + let contents = block lexbuf in + let arguments = String.split_on_char ' ' l in + let arguments = List.map (fun a -> + if (String.contains a '=') then + ( let a = String.split_on_char '=' a in + NameValue (List.nth a 0, List.nth a 1)) + else + Field a + ) arguments in + let file = lexbuf.Lexing.lex_start_p.Lexing.pos_fname in + newline lexbuf; + let line = !line_ref in + List.iter (fun _ -> newline lexbuf) contents; + newline lexbuf; + { file; line; header; arguments; contents; } + :: text lexbuf } + | [^'\n']* eol + { newline lexbuf; + text lexbuf } + +and block = parse + | eof | "```" ws* eol { [] } + | ([^'\n'] * as str) eol { str :: block lexbuf } + +{ +let token lexbuf = + try + text lexbuf + with Failure _ -> + raise (Err "incomplete code block") +} diff --git a/src/test/md_file_tests.ml b/src/test/md_file_tests.ml new file mode 100644 index 000000000..347acbbcf --- /dev/null +++ b/src/test/md_file_tests.ml @@ -0,0 +1,74 @@ +open Trace +open Test_helpers + +module SnippetsGroup = Map.Make(struct type t = (string * string) let compare a b = compare a b end) + +let failed_to_compile_md_file md_file (s,group,prg) = + let title () = "Failed to compile "^s^" group '"^group^"' in file '"^md_file^"'" in + let content () = "unable to compile the program down to michelson" in + let data = [ + ("source" , fun () -> Format.asprintf "%s" prg) ; + ] in + error ~data title content + +(** + binds the snippets by (syntax, group_name) + e.g. :(pascaligo, a) -> "let .. in let .. in" + (cameligo, a) -> "let .. in let .. in" + syntax and group_name being retrieved from the .md file header & arguments + e.g. : ```syntax group=group_name ...some code ... ``` +**) +let get_groups md_file = + let channel = open_in md_file in + let lexbuf = Lexing.from_channel channel in + let code_blocks = Md.token lexbuf in + List.fold_left + (fun (grp_map: _ SnippetsGroup.t) (el:Md.block) -> + match el.header with + | Some s -> + List.fold_left + (fun grp_map arg -> match arg with + | Md.NameValue ("group", name) -> + SnippetsGroup.update (s,name) + (fun arg_content -> + match arg_content with + | Some ct -> Some (String.concat "\n" (ct::el.contents)) + | None -> Some (String.concat "\n" el.contents) + ) + grp_map + | _ -> grp_map + ) + grp_map el.arguments + | None -> grp_map + ) + SnippetsGroup.empty code_blocks + +(** + evaluate each expression in each programs from the snippets group map +**) +let compile_groups _filename (grp_map: _ SnippetsGroup.t) = + let grp_list = SnippetsGroup.bindings grp_map in + let%bind _michelsons = bind_map_list + (fun ((s,_grp),contents) -> + (*TODO: hierarchical error ?*) + trace_strong (failed_to_compile_md_file _filename (s,_grp,contents)) @@ + let%bind v_syntax = Compile.Helpers.syntax_to_variant (Syntax_name s) None in + let%bind simplified = Compile.Of_source.compile_string contents v_syntax in + let%bind typed,_ = Compile.Of_simplified.compile simplified in + let%bind mini_c = Compile.Of_typed.compile typed in + bind_map_list + (fun ((_,exp),_) -> Compile.Of_mini_c.aggregate_and_compile_expression mini_c exp) + mini_c + ) + grp_list in + ok () + +let compile filename () = + let groups = get_groups filename in + let%bind () = compile_groups filename groups in + ok () + +let md_root = "../../gitlab-pages/docs/language-basics/" +let main = test_suite "Markdown files" [ + test "sets_lists_touples" (compile (md_root^"sets-lists-touples.md")) ; + ]