From 04daf776d3f84105cbc0c23bf5cb04736edc0e9d Mon Sep 17 00:00:00 2001 From: John David Pressman Date: Tue, 4 Feb 2020 23:08:47 -0800 Subject: [PATCH 1/9] Add rough draft of big map reference page to docs --- gitlab-pages/docs/reference/big_map.md | 184 +++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 gitlab-pages/docs/reference/big_map.md diff --git a/gitlab-pages/docs/reference/big_map.md b/gitlab-pages/docs/reference/big_map.md new file mode 100644 index 000000000..861429c34 --- /dev/null +++ b/gitlab-pages/docs/reference/big_map.md @@ -0,0 +1,184 @@ +--- +id: big-map-reference +title: Big Map +--- + +## Big_map.find_opt(k: a', m: (a',b') big_map) : b' option + +Retrieve the value associated with a particular key. This version returns an option +which can either shift logic in response to a missing value or throw an error. + + + +```pascaligo +const my_balance : option(move) = + moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] +``` + + + +```cameligo +let my_balance : move option = + Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves +``` + + + +```reasonligo +let my_balance : option(move) = + Big_map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves); +``` + + +## Big_map.find(k: a', m: (a', b') big_map) : b' + +Forcefully retrieve the value associated with a particular key. If that value +doesn't exist, this function throws an error. + + + +```pascaligo +const my_balance : move = + get_force (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves); +``` + + + +```cameligo +let my_balance : move = + Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves +``` + + + +```reasonligo +let my_balance : move = + Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves); +``` + + + +## Big_map.update(k: a', v: b', m: (a', b') big_map) : (a', b') big_map + +Change the value associated with a particular key, if that value doesn't already +exist add it. + + + + + +The values of a PascaLIGO big map can be updated using the ordinary +assignment syntax: + +```pascaligo + +function set_ (var m : moveset) : moveset is + block { + m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9); + } with m +``` + + + +```cameligo +let updated_map : moveset = + Big_map.update ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) (Some (4,9)) moves +``` + + + +```reasonligo +let updated_map : moveset = + Big_map.update(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves); +``` + + + +## Big_map.add(k: a', v: b', m: (a', b') big_map) : (a', b') big_map + +## Big_map.remove(k: a', m: (a', b') big_map) : (a', b') big_map + +Remove a key and its associated value from the big map. + + + + +```pascaligo +function rm (var m : foo) : foo is block { + remove 42 from map m; +} with m +``` + + +```cameligo +let rm (m : foo) : foo = Big_map.remove 42 m +``` + + +```reasonligo +let rm = (m: foo): foo => Big_map.remove(42, m); +``` + + + +## Big_map.literal(key_value_pair_list: (a', b') list) : (a', b') big_map + +Constructs a big map from a list of key-value pair tuples. + + + + +```pascaligo +const moves: moveset = + big_map + ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2); + ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3); + end +``` + + + +```cameligo +let moves: moveset = + Big_map.literal [ + (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2)); + (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3)); + ] +``` + + + +```reasonligo +let moves: moveset = + Big_map.literal ([ + ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)), + ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)), + ]); +``` + + + + +## Big_map.empty() : (a', b') big_map + +Create an empty big map. + + + + +```pascaligo +const empty_big_map : big_map(int,int) = big_map end +``` + + +```cameligo +let empty_map : foo = Big_map.empty +``` + + +```reasonligo +let empty_map: foo = Big_map.empty; +``` + + + From f79839276004ad80e4a605b699fa4a27b76570b9 Mon Sep 17 00:00:00 2001 From: Lesenechal Remi Date: Mon, 10 Feb 2020 19:54:23 +0100 Subject: [PATCH 2/9] constant typer: * Removed unused LIST_CONS * support for misc constants (untestetable for now) --- src/passes/operators/operators.ml | 89 +++++++++++++++++------------ src/stages/common/PP.ml | 1 - src/stages/common/types.ml | 1 - src/stages/mini_c/PP.ml | 1 - src/stages/typesystem/shorthands.ml | 5 ++ 5 files changed, 59 insertions(+), 38 deletions(-) diff --git a/src/passes/operators/operators.ml b/src/passes/operators/operators.ml index ed77a7f64..842e32520 100644 --- a/src/passes/operators/operators.ml +++ b/src/passes/operators/operators.ml @@ -327,6 +327,9 @@ module Typer = struct let tc_divargs a b c = tc [a;b;c] [ (*TODO…*) ] let tc_modargs a b c = tc [a;b;c] [ (*TODO…*) ] let tc_addargs a b c = tc [a;b;c] [ (*TODO…*) ] + let tc_comparable a = tc [a] [ [nat] ; [int] ; [mutez] ; [timestamp] ] + let tc_concatable a = tc [a] [ [string] ; [bytes] ] + let tc_storable a = tc [a] [ [string] ; [bytes] ; (*Humm .. TODO ?*) ] let t_none = forall "a" @@ fun a -> option a @@ -355,18 +358,20 @@ module Typer = struct let t_hash512 = tuple1 bytes --> bytes let t_blake2b = tuple1 bytes --> bytes let t_hash_key = tuple1 key --> key_hash + let t_is_nat = tuple1 int --> bool let t_check_signature = tuple3 key signature bytes --> bool let t_chain_id = tuple0 --> chain_id let t_sender = tuple0 --> address let t_source = tuple0 --> address let t_unit = tuple0 --> unit let t_amount = tuple0 --> mutez + let t_balance = tuple0 --> mutez let t_address = tuple0 --> address let t_now = tuple0 --> timestamp let t_transaction = forall "a" @@ fun a -> tuple3 a mutez (contract a) --> operation let t_get_contract = forall "a" @@ fun a -> tuple0 --> contract a let t_abs = tuple1 int --> nat - let t_cons = forall "a" @@ fun a -> a --> tuple1 (list a) --> list a + let t_cons = forall "a" @@ fun a -> tuple2 a (list a) --> list a let t_assertion = tuple1 bool --> unit let t_times = forall3_tc "a" "b" "c" @@ fun a b c -> [tc_timargs a b c] => tuple2 a b --> c (* TYPECLASS *) let t_div = forall3_tc "a" "b" "c" @@ fun a b c -> [tc_divargs a b c] => tuple2 a b --> c (* TYPECLASS *) @@ -377,21 +382,41 @@ module Typer = struct let t_set_remove = forall "a" @@ fun a -> tuple2 a (set a) --> set a let t_not = tuple1 bool --> bool + let t_continuation = forall "a" @@ fun a -> tuple2 bool a + let t_fold_while = forall "a" @@ fun a -> tuple2 (a --> tuple2 bool a) a --> a + let t_neg = tuple1 int --> int + let t_and = tuple2 bool bool --> bool + let t_or = tuple2 bool bool --> bool + let t_xor = tuple2 bool bool --> bool + let t_lsl = tuple2 nat nat --> nat + let t_lsr = tuple2 nat nat --> nat + let t_comp = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple2 a a --> bool + let t_concat = forall_tc "a" @@ fun a -> [tc_concatable a] => tuple2 a a --> a + let t_set_empty = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple0 --> set a + let t_set_iter = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple2 (a --> unit) (set a) --> unit + let t_set_fold = forall2_tc "a" "b" @@ fun a b -> [tc_comparable b] => tuple3 (tuple2 a b --> a) (set b) b --> b + let t_list_iter = forall "a" @@ fun a -> tuple2 (a --> unit) (list a) --> unit + let t_list_map = forall "a" @@ fun a -> tuple2 (a --> a) (list a) --> (list a) + let t_list_fold = forall2 "a" "b" @@ fun a b -> tuple3 (tuple2 a b --> a) (list b) a --> a + let t_self_address = tuple0 --> address + let t_implicit_account = forall_tc "a" @@ fun a -> [tc_storable a] => tuple1 key_hash --> contract a + let t_set_delegate = tuple1 (option key_hash) --> operation + let constant_type : constant' -> Typesystem.Core.type_value result = function | C_INT -> ok @@ t_int ; | C_UNIT -> ok @@ t_unit ; | C_NOW -> ok @@ t_now ; - | C_IS_NAT -> ok @@ failwith "t_is_nat" ; + | C_IS_NAT -> ok @@ t_is_nat ; | C_SOME -> ok @@ t_some ; | C_NONE -> ok @@ t_none ; | C_ASSERTION -> ok @@ t_assertion ; | C_FAILWITH -> ok @@ t_failwith ; (* LOOPS *) - | C_FOLD_WHILE -> ok @@ failwith "t_fold_while" ; - | C_CONTINUE -> ok @@ failwith "t_continue" ; - | C_STOP -> ok @@ failwith "t_stop" ; + | C_FOLD_WHILE -> ok @@ t_fold_while ; + | C_CONTINUE -> ok @@ t_continuation ; + | C_STOP -> ok @@ t_continuation ; (* MATH *) - | C_NEG -> ok @@ failwith "t_neg" ; + | C_NEG -> ok @@ t_neg ; | C_ABS -> ok @@ t_abs ; | C_ADD -> ok @@ t_add ; | C_SUB -> ok @@ t_sub ; @@ -400,38 +425,38 @@ module Typer = struct | C_MOD -> ok @@ t_mod ; (* LOGIC *) | C_NOT -> ok @@ t_not ; - | C_AND -> ok @@ failwith "t_and" ; - | C_OR -> ok @@ failwith "t_or" ; - | C_XOR -> ok @@ failwith "t_xor" ; - | C_LSL -> ok @@ failwith "t_lsl" ; - | C_LSR -> ok @@ failwith "t_lsr" ; + | C_AND -> ok @@ t_and ; + | C_OR -> ok @@ t_or ; + | C_XOR -> ok @@ t_xor ; + | C_LSL -> ok @@ t_lsl ; + | C_LSR -> ok @@ t_lsr ; (* COMPARATOR *) - | C_EQ -> ok @@ failwith "t_comparator EQ" ; - | C_NEQ -> ok @@ failwith "t_comparator NEQ" ; - | C_LT -> ok @@ failwith "t_comparator LT" ; - | C_GT -> ok @@ failwith "t_comparator GT" ; - | C_LE -> ok @@ failwith "t_comparator LE" ; - | C_GE -> ok @@ failwith "t_comparator GE" ; + | C_EQ -> ok @@ t_comp ; + | C_NEQ -> ok @@ t_comp ; + | C_LT -> ok @@ t_comp ; + | C_GT -> ok @@ t_comp ; + | C_LE -> ok @@ t_comp ; + | C_GE -> ok @@ t_comp ; (* BYTES / STRING *) | C_SIZE -> ok @@ t_size ; - | C_CONCAT -> ok @@ failwith "t_concat" ; + | C_CONCAT -> ok @@ t_concat ; | C_SLICE -> ok @@ t_slice ; | C_BYTES_PACK -> ok @@ t_bytes_pack ; | C_BYTES_UNPACK -> ok @@ t_bytes_unpack ; | C_CONS -> ok @@ t_cons ; (* SET *) - | C_SET_EMPTY -> ok @@ failwith "t_set_empty" ; + | C_SET_EMPTY -> ok @@ t_set_empty ; | C_SET_ADD -> ok @@ t_set_add ; | C_SET_REMOVE -> ok @@ t_set_remove ; - | C_SET_ITER -> ok @@ failwith "t_set_iter" ; - | C_SET_FOLD -> ok @@ failwith "t_set_fold" ; + | C_SET_ITER -> ok @@ t_set_iter ; + | C_SET_FOLD -> ok @@ t_set_fold ; | C_SET_MEM -> ok @@ t_set_mem ; (* LIST *) - | C_LIST_ITER -> ok @@ failwith "t_list_iter" ; - | C_LIST_MAP -> ok @@ failwith "t_list_map" ; - | C_LIST_FOLD -> ok @@ failwith "t_list_fold" ; - | C_LIST_CONS -> ok @@ failwith "t_list_cons" ; + | C_LIST_ITER -> ok @@ t_list_iter ; + | C_LIST_MAP -> ok @@ t_list_map ; + | C_LIST_FOLD -> ok @@ t_list_fold ; + (* MAP *) | C_MAP_ADD -> ok @@ t_map_add ; | C_MAP_REMOVE -> ok @@ t_map_remove ; @@ -454,14 +479,14 @@ module Typer = struct | C_CONTRACT -> ok @@ t_get_contract ; | C_CONTRACT_ENTRYPOINT -> ok @@ failwith "t_get_entrypoint" ; | C_AMOUNT -> ok @@ t_amount ; - | C_BALANCE -> ok @@ failwith "t_balance" ; + | C_BALANCE -> ok @@ t_balance ; | C_CALL -> ok @@ t_transaction ; | C_SENDER -> ok @@ t_sender ; | C_SOURCE -> ok @@ t_source ; | C_ADDRESS -> ok @@ t_address ; - | C_SELF_ADDRESS -> ok @@ failwith "t_self_address"; - | C_IMPLICIT_ACCOUNT -> ok @@ failwith "t_implicit_account"; - | C_SET_DELEGATE -> ok @@ failwith "t_set_delegate" ; + | C_SELF_ADDRESS -> ok @@ t_self_address; + | C_IMPLICIT_ACCOUNT -> ok @@ t_implicit_account; + | C_SET_DELEGATE -> ok @@ t_set_delegate ; | c -> simple_fail @@ Format.asprintf "Typer not implemented for consant %a" Stage_common.PP.constant c end @@ -489,11 +514,6 @@ module Typer = struct let some = typer_1 "SOME" @@ fun a -> ok @@ t_option a () - let list_cons : typer = typer_2 "CONS" @@ fun hd tl -> - let%bind tl' = get_t_list tl in - let%bind () = assert_type_expression_eq (hd , tl') in - ok tl - let map_remove : typer = typer_2 "MAP_REMOVE" @@ fun k m -> let%bind (src , _) = bind_map_or (get_t_map , get_t_big_map) m in let%bind () = assert_type_expression_eq (src , k) in @@ -1031,7 +1051,6 @@ module Typer = struct | C_LIST_ITER -> ok @@ list_iter ; | C_LIST_MAP -> ok @@ list_map ; | C_LIST_FOLD -> ok @@ list_fold ; - | C_LIST_CONS -> ok @@ list_cons ; (* MAP *) | C_MAP_ADD -> ok @@ map_add ; | C_MAP_REMOVE -> ok @@ map_remove ; diff --git a/src/stages/common/PP.ml b/src/stages/common/PP.ml index d14ada03f..7235c9472 100644 --- a/src/stages/common/PP.ml +++ b/src/stages/common/PP.ml @@ -105,7 +105,6 @@ let constant ppf : constant' -> unit = function | C_LIST_ITER -> fprintf ppf "LIST_ITER" | C_LIST_MAP -> fprintf ppf "LIST_MAP" | C_LIST_FOLD -> fprintf ppf "LIST_FOLD" - | C_LIST_CONS -> fprintf ppf "LIST_CONS" (* Maps *) | C_MAP -> fprintf ppf "MAP" | C_MAP_EMPTY -> fprintf ppf "MAP_EMPTY" diff --git a/src/stages/common/types.ml b/src/stages/common/types.ml index 9cc8f2998..d390d1d46 100644 --- a/src/stages/common/types.ml +++ b/src/stages/common/types.ml @@ -247,7 +247,6 @@ and constant' = | C_LIST_ITER | C_LIST_MAP | C_LIST_FOLD - | C_LIST_CONS (* Maps *) | C_MAP | C_MAP_EMPTY diff --git a/src/stages/mini_c/PP.ml b/src/stages/mini_c/PP.ml index c9655dc24..fb607db79 100644 --- a/src/stages/mini_c/PP.ml +++ b/src/stages/mini_c/PP.ml @@ -201,7 +201,6 @@ and constant ppf : constant' -> unit = function | C_LIST_ITER -> fprintf ppf "LIST_ITER" | C_LIST_MAP -> fprintf ppf "LIST_MAP" | C_LIST_FOLD -> fprintf ppf "LIST_FOLD" - | C_LIST_CONS -> fprintf ppf "LIST_CONS" (* Maps *) | C_MAP -> fprintf ppf "MAP" | C_MAP_EMPTY -> fprintf ppf "MAP_EMPTY" diff --git a/src/stages/typesystem/shorthands.ml b/src/stages/typesystem/shorthands.ml index 15e1bdca0..81a341b32 100644 --- a/src/stages/typesystem/shorthands.ml +++ b/src/stages/typesystem/shorthands.ml @@ -39,6 +39,11 @@ let forall3_tc a b c f = forall_tc c @@ fun c' -> f a' b' c' +let forall2_tc a b f = + forall a @@ fun a' -> + forall_tc b @@ fun b' -> + f a' b' + let (=>) tc ty = (tc , ty) let (-->) arg ret = P_constant (C_arrow , [arg; ret]) let option t = P_constant (C_option , [t]) From 87a890164556fe5f2b9543316e2b7f2ded973ecb Mon Sep 17 00:00:00 2001 From: Lesenechal Remi Date: Mon, 10 Feb 2020 20:02:43 +0100 Subject: [PATCH 3/9] review fixes --- src/passes/operators/operators.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/passes/operators/operators.ml b/src/passes/operators/operators.ml index 842e32520..d9a5d4a9e 100644 --- a/src/passes/operators/operators.ml +++ b/src/passes/operators/operators.ml @@ -382,8 +382,8 @@ module Typer = struct let t_set_remove = forall "a" @@ fun a -> tuple2 a (set a) --> set a let t_not = tuple1 bool --> bool - let t_continuation = forall "a" @@ fun a -> tuple2 bool a - let t_fold_while = forall "a" @@ fun a -> tuple2 (a --> tuple2 bool a) a --> a + let t_continuation = forall "a" @@ fun a -> pair bool a + let t_fold_while = forall "a" @@ fun a -> tuple2 (a --> pair bool a) a --> a let t_neg = tuple1 int --> int let t_and = tuple2 bool bool --> bool let t_or = tuple2 bool bool --> bool @@ -394,10 +394,10 @@ module Typer = struct let t_concat = forall_tc "a" @@ fun a -> [tc_concatable a] => tuple2 a a --> a let t_set_empty = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple0 --> set a let t_set_iter = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple2 (a --> unit) (set a) --> unit - let t_set_fold = forall2_tc "a" "b" @@ fun a b -> [tc_comparable b] => tuple3 (tuple2 a b --> a) (set b) b --> b + let t_set_fold = forall2_tc "a" "b" @@ fun a b -> [tc_comparable b] => tuple3 (pair a b --> a) (set b) a --> a let t_list_iter = forall "a" @@ fun a -> tuple2 (a --> unit) (list a) --> unit let t_list_map = forall "a" @@ fun a -> tuple2 (a --> a) (list a) --> (list a) - let t_list_fold = forall2 "a" "b" @@ fun a b -> tuple3 (tuple2 a b --> a) (list b) a --> a + let t_list_fold = forall2 "a" "b" @@ fun a b -> tuple3 (pair a b --> a) (list b) a --> a let t_self_address = tuple0 --> address let t_implicit_account = forall_tc "a" @@ fun a -> [tc_storable a] => tuple1 key_hash --> contract a let t_set_delegate = tuple1 (option key_hash) --> operation From c71b413bae97ba19b6d2a20b24aaaec77291af95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Suzanne=20Dup=C3=A9ron?= Date: Mon, 10 Feb 2020 13:45:45 +0100 Subject: [PATCH 4/9] Changelog for mutation & list_iter --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1977c3295..b40924f28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +## [9164206ef1fcf3e577820442b5afbad92d03ffa4] - 2020-02-09 +### Changed +- Mutation of variables inside lambdas passed to list_iter do not have effect anymore. Side-effects used to survive iterations of list_iter via a quirk in the Michelson list_iter. Now, either use a list_fold and explicitly pass through the updated variables (e.g. storage) to the next iteration, or use a `for` loop which automatically detects mutations within the loop body and lifts the affected variables to a record that is passed from iteration to iteration. + ## [Add crypto reference page to docs](https://gitlab.com/ligolang/ligo/-/merge_requests/370) ### Changed - Corrected typo in CameLIGO/ReasonLIGO front end where Crypto.blake2b was 'Crypto.black2b' From 39c0f019988cb660af2c71dc9c29a85c5dbf16fb Mon Sep 17 00:00:00 2001 From: John David Pressman Date: Tue, 11 Feb 2020 01:03:46 -0800 Subject: [PATCH 5/9] Add big_map reference page to doc tests and add big_map `add` to test suite --- gitlab-pages/docs/reference/big_map.md | 84 ++++++++++++++++++++++++++ src/test/contracts/big_map.ligo | 2 + src/test/contracts/big_map.mligo | 4 +- src/test/contracts/big_map.religo | 2 + src/test/integration_tests.ml | 5 ++ src/test/md_file_tests.ml | 1 + 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/gitlab-pages/docs/reference/big_map.md b/gitlab-pages/docs/reference/big_map.md index 861429c34..4dd6ba3af 100644 --- a/gitlab-pages/docs/reference/big_map.md +++ b/gitlab-pages/docs/reference/big_map.md @@ -3,6 +3,67 @@ id: big-map-reference title: Big Map --- +## Defining A Big Map Type + + + +```pascaligo +type move is (int * int) +type moveset is big_map (address, move) +type foo is big_map (int, int) +``` + + +```cameligo +type move = int * int +type moveset = (address, move) big_map +type foo = (int, int) big_map +``` + + +```reasonligo +type move = (int, int); +type moveset = big_map(address, move); +type foo = big_map(int, int); +``` + + + +## Creating A Map + + + + +```pascaligo +const moves: moveset = + big_map + ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2); + ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3); + end +``` + + + +```cameligo +let moves: moveset = + Big_map.literal [ + (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2)); + (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3)); + ] +``` + + + +```reasonligo +let moves: moveset = + Big_map.literal ([ + ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)), + ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)), + ]); +``` + + + ## Big_map.find_opt(k: a', m: (a',b') big_map) : b' option Retrieve the value associated with a particular key. This version returns an option @@ -96,6 +157,29 @@ let updated_map : moveset = ## Big_map.add(k: a', v: b', m: (a', b') big_map) : (a', b') big_map +Add a key and its associated value to the big map. + + + + +```pascaligo +function set_ (var n : int ; var m : foo) : foo is block { + m[23] := n ; +} with m +``` + + +```cameligo +let add (n,m : int * foo) : foo = Big_map.add 23 n m +``` + + +```reasonligo +let add = ((n,m): (int, foo)): foo => Big_map.add(23, n, m); +``` + + + ## Big_map.remove(k: a', m: (a', b') big_map) : (a', b') big_map Remove a key and its associated value from the big map. diff --git a/src/test/contracts/big_map.ligo b/src/test/contracts/big_map.ligo index e6ab78c58..a24e09e97 100644 --- a/src/test/contracts/big_map.ligo +++ b/src/test/contracts/big_map.ligo @@ -13,6 +13,8 @@ function set_ (var n : int ; var m : foo) : foo is block { m[23] := n ; } with m +function add (var n : int ; var m : foo) : foo is set_(n,m) + function rm (var m : foo) : foo is block { remove 42 from map m; } with m diff --git a/src/test/contracts/big_map.mligo b/src/test/contracts/big_map.mligo index eb06bd5f4..35a173f82 100644 --- a/src/test/contracts/big_map.mligo +++ b/src/test/contracts/big_map.mligo @@ -1,8 +1,8 @@ type foo = (int, int) big_map -let set_2 (n : int) (m : foo) : foo = Big_map.update 23 (Some n) m +let set_ (n, m: int * foo) : foo = Big_map.update 23 (Some n) m -let set_ (t: int * foo) : foo = set_2 t.0 t.1 +let add (n,m : int * foo) : foo = Big_map.add 23 n m let rm (m : foo) : foo = Big_map.remove 42 m diff --git a/src/test/contracts/big_map.religo b/src/test/contracts/big_map.religo index 03b13b404..92f5431c8 100644 --- a/src/test/contracts/big_map.religo +++ b/src/test/contracts/big_map.religo @@ -4,6 +4,8 @@ let set2 = (n: int, m: foo): foo => Big_map.update(23, Some(n), m); let set_ = (x: (int, foo)): foo => set2(x[0], x[1]); +let add = ((n,m): (int, foo)): foo => Big_map.add(23, n, m); + let rm = (m: foo): foo => Big_map.remove(42, m); let gf = (m: foo): int => Big_map.find(23, m); diff --git a/src/test/integration_tests.ml b/src/test/integration_tests.ml index 204d2fc55..4128a301f 100644 --- a/src/test/integration_tests.ml +++ b/src/test/integration_tests.ml @@ -1073,6 +1073,11 @@ let big_map_ type_f path : unit result = let make_expected = fun n -> ez [(23 , n) ; (42 , 0)] in expect_eq_n_pos_small program "set_" make_input make_expected in + let%bind () = + let input = (e_pair (e_int 23) (ez [(42, 42)])) in + let expected = ez [(23, 23) ; (42, 42)] in + expect_eq program "add" input 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 diff --git a/src/test/md_file_tests.ml b/src/test/md_file_tests.ml index 86aefeb89..9d1d3cf0a 100644 --- a/src/test/md_file_tests.ml +++ b/src/test/md_file_tests.ml @@ -122,6 +122,7 @@ let md_files = [ "/gitlab-pages/docs/advanced/timestamps-addresses.md"; "/gitlab-pages/docs/api/cli-commands.md"; "/gitlab-pages/docs/api/cheat-sheet.md"; + "/gitlab-pages/docs/reference/big_map.md"; ] let md_root = "../../gitlab-pages/docs/language-basics/" From 702416a0a7bddeb01e9ff1246c5660518a10efd9 Mon Sep 17 00:00:00 2001 From: Lesenechal Remi Date: Tue, 11 Feb 2020 11:05:43 +0100 Subject: [PATCH 6/9] fix continuation and add some comments --- src/passes/operators/operators.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/passes/operators/operators.ml b/src/passes/operators/operators.ml index d9a5d4a9e..6c75f1f01 100644 --- a/src/passes/operators/operators.ml +++ b/src/passes/operators/operators.ml @@ -382,7 +382,7 @@ module Typer = struct let t_set_remove = forall "a" @@ fun a -> tuple2 a (set a) --> set a let t_not = tuple1 bool --> bool - let t_continuation = forall "a" @@ fun a -> pair bool a + let t_continuation = forall "a" @@ fun a -> tuple2 bool a --> pair bool a let t_fold_while = forall "a" @@ fun a -> tuple2 (a --> pair bool a) a --> a let t_neg = tuple1 int --> int let t_and = tuple2 bool bool --> bool @@ -394,9 +394,11 @@ module Typer = struct let t_concat = forall_tc "a" @@ fun a -> [tc_concatable a] => tuple2 a a --> a let t_set_empty = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple0 --> set a let t_set_iter = forall_tc "a" @@ fun a -> [tc_comparable a] => tuple2 (a --> unit) (set a) --> unit + (* TODO: check that the implementation has this type *) let t_set_fold = forall2_tc "a" "b" @@ fun a b -> [tc_comparable b] => tuple3 (pair a b --> a) (set b) a --> a let t_list_iter = forall "a" @@ fun a -> tuple2 (a --> unit) (list a) --> unit let t_list_map = forall "a" @@ fun a -> tuple2 (a --> a) (list a) --> (list a) + (* TODO: check that the implementation has this type *) let t_list_fold = forall2 "a" "b" @@ fun a b -> tuple3 (pair a b --> a) (list b) a --> a let t_self_address = tuple0 --> address let t_implicit_account = forall_tc "a" @@ fun a -> [tc_storable a] => tuple1 key_hash --> contract a From 8b83e375bd189b3c32629a34e1ab2db787478656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lesenechal?= Date: Tue, 11 Feb 2020 10:45:08 +0000 Subject: [PATCH 7/9] Revert "Merge branch 'feature/adt-generator-poly-3' into 'dev'" This reverts merge request !403 --- docker/distribution/generic/build.Dockerfile | 2 +- scripts/build_docker_image.sh | 3 +- scripts/build_ligo_local.sh | 1 - scripts/distribution/generic/build.sh | 2 - scripts/distribution/generic/package.sh | 2 - scripts/distribution/generic/parameters.sh | 12 +- scripts/install_build_environment.sh | 3 - scripts/install_native_dependencies.sh | 3 - scripts/install_vendors_deps.sh | 1 - src/passes/4-typer-old/typer.ml | 1 + src/stages/adt_generator/.gitignore | 2 - src/stages/adt_generator/README | 4 +- src/stages/adt_generator/a.ml | 21 +-- src/stages/adt_generator/dune | 12 +- src/stages/adt_generator/fold.ml | 185 ++++++++++++++++++- src/stages/adt_generator/generator.py | 58 ++---- src/stages/adt_generator/use_a_fold.ml | 6 +- src/stages/ast_typed/types.ml | 1 + tools/webide/Dockerfile | 2 +- vendors/UnionFind/UnionFind.install | 36 ++++ 20 files changed, 254 insertions(+), 103 deletions(-) delete mode 100644 src/stages/adt_generator/.gitignore create mode 100644 vendors/UnionFind/UnionFind.install diff --git a/docker/distribution/generic/build.Dockerfile b/docker/distribution/generic/build.Dockerfile index ba01c043c..f6c9358e9 100644 --- a/docker/distribution/generic/build.Dockerfile +++ b/docker/distribution/generic/build.Dockerfile @@ -29,7 +29,7 @@ RUN opam update # Install ligo RUN sh scripts/install_vendors_deps.sh -RUN opam install -y . || (tail -n +1 ~/.opam/log/* ; false) +RUN opam install -y . # Use the ligo binary as a default command ENTRYPOINT [ "/home/opam/.opam/4.07/bin/ligo" ] diff --git a/scripts/build_docker_image.sh b/scripts/build_docker_image.sh index f342b424f..260a530c7 100755 --- a/scripts/build_docker_image.sh +++ b/scripts/build_docker_image.sh @@ -1,4 +1,3 @@ #!/bin/sh set -e -set -x -docker build -t "${LIGO_REGISTRY_IMAGE_BUILD:-ligolang/ligo}:next" -f ./docker/distribution/debian/distribute.Dockerfile . +docker build -t "${LIGO_REGISTRY_IMAGE_BUILD:-ligolang/ligo}:next" -f ./docker/distribution/debian/distribute.Dockerfile . \ No newline at end of file diff --git a/scripts/build_ligo_local.sh b/scripts/build_ligo_local.sh index fb556805a..b78e4ffd6 100755 --- a/scripts/build_ligo_local.sh +++ b/scripts/build_ligo_local.sh @@ -1,6 +1,5 @@ #!/bin/sh set -e -set -x eval $(opam config env) dune build -p ligo diff --git a/scripts/distribution/generic/build.sh b/scripts/distribution/generic/build.sh index 968f55a21..49aba15e1 100755 --- a/scripts/distribution/generic/build.sh +++ b/scripts/distribution/generic/build.sh @@ -1,6 +1,4 @@ #!/bin/sh -set -e -set -x dockerfile_name="build" # Generic dockerfile diff --git a/scripts/distribution/generic/package.sh b/scripts/distribution/generic/package.sh index d9d047e6d..79be37d41 100755 --- a/scripts/distribution/generic/package.sh +++ b/scripts/distribution/generic/package.sh @@ -1,6 +1,4 @@ #!/bin/sh -set -e -set -x dockerfile_name="package" dockerfile="" diff --git a/scripts/distribution/generic/parameters.sh b/scripts/distribution/generic/parameters.sh index 2241b9fb0..3899711d8 100644 --- a/scripts/distribution/generic/parameters.sh +++ b/scripts/distribution/generic/parameters.sh @@ -1,15 +1,11 @@ -#!/bin/sh -set -e -set -x - # This script accepts three arguments, os family, os and its version, # which are subsequently used to fetch the respective docker # image from the ocaml/infrastructure project. # # https://github.com/ocaml/infrastructure/wiki/Containers#selecting-linux-distributions -target_os_family="$1" -target_os="$2" -target_os_version="$3" +target_os_family=$1 +target_os=$2 +target_os_version=$3 # Variables configured at the CI level dist="$LIGO_DIST_DIR" @@ -33,4 +29,4 @@ fi target_os_specific_dockerfile="./docker/distribution/$target_os_family/$target_os/$dockerfile_name.Dockerfile" if test -f "$target_os_specific_dockerfile"; then dockerfile="$target_os_specific_dockerfile" -fi +fi \ No newline at end of file diff --git a/scripts/install_build_environment.sh b/scripts/install_build_environment.sh index 628235e70..0dd33f068 100755 --- a/scripts/install_build_environment.sh +++ b/scripts/install_build_environment.sh @@ -22,7 +22,6 @@ echo "Installing dependencies.." if [ -n "`uname -a | grep -i arch`" ] then sudo pacman -Sy --noconfirm \ - python \ make \ m4 \ gcc \ @@ -35,8 +34,6 @@ fi if [ -n "`uname -a | grep -i ubuntu`" ] then sudo apt-get install -y make \ - python3 \ - make \ m4 \ gcc \ patch \ diff --git a/scripts/install_native_dependencies.sh b/scripts/install_native_dependencies.sh index f12e76cb2..2a0e56903 100755 --- a/scripts/install_native_dependencies.sh +++ b/scripts/install_native_dependencies.sh @@ -1,13 +1,11 @@ #!/bin/sh set -e -set -x . /etc/os-release if [ $ID = arch ] then pacman -Sy sudo pacman -S --noconfirm \ - python \ libevdev \ perl \ pkg-config \ @@ -22,7 +20,6 @@ then else apt-get update -qq apt-get -y -qq install \ - python3 \ libev-dev \ perl \ pkg-config \ diff --git a/scripts/install_vendors_deps.sh b/scripts/install_vendors_deps.sh index 5c870ffdc..15f9b47d4 100755 --- a/scripts/install_vendors_deps.sh +++ b/scripts/install_vendors_deps.sh @@ -1,6 +1,5 @@ #!/bin/sh set -e -set -x # Install local dependencies opam install -y --deps-only --with-test ./ligo.opam $(find vendors -name \*.opam) diff --git a/src/passes/4-typer-old/typer.ml b/src/passes/4-typer-old/typer.ml index 7c1cd41a4..87f4b2477 100644 --- a/src/passes/4-typer-old/typer.ml +++ b/src/passes/4-typer-old/typer.ml @@ -649,6 +649,7 @@ and type_expression' : environment -> ?tv_opt:O.type_expression -> I.expression let wtype = Format.asprintf "Loops over collections expect lists, sets or maps, got type %a" O.PP.type_expression tv_col in fail @@ simple_error wtype in + let lname = lname in let e' = Environment.add_ez_binder lname input_type e in let%bind body = type_expression' ?tv_opt:(Some tv_out) e' result in let output_type = body.type_expression in diff --git a/src/stages/adt_generator/.gitignore b/src/stages/adt_generator/.gitignore deleted file mode 100644 index 9ec2ad34e..000000000 --- a/src/stages/adt_generator/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# This is an auto-generated test file -/generated_fold.ml diff --git a/src/stages/adt_generator/README b/src/stages/adt_generator/README index 2d1b53c3d..20ecdfd43 100644 --- a/src/stages/adt_generator/README +++ b/src/stages/adt_generator/README @@ -1,6 +1,6 @@ -Build & test with: +Build with: - dune build adt_generator.exe && ../../../_build/default/src/stages/adt_generator/adt_generator.exe + dune build adt_generator.a Run with diff --git a/src/stages/adt_generator/a.ml b/src/stages/adt_generator/a.ml index 34b611dc1..f1d8b2fb1 100644 --- a/src/stages/adt_generator/a.ml +++ b/src/stages/adt_generator/a.ml @@ -1,6 +1,6 @@ type root = -| A of rootA -| B of rootB +| A of a +| B of int | C of string and a = { @@ -15,20 +15,3 @@ and ta1 = and ta2 = | Z of ta2 | W of unit - -and rootA = - a list - -and rootB = - int list - -let fold_list v state continue = - let aux = fun (lst', state) elt -> - let (elt', state) = continue elt state in - (elt' :: lst' , state) in - List.fold_left aux ([], state) v - -let fold_option v state continue = - match v with - Some x -> continue x state - | None -> None diff --git a/src/stages/adt_generator/dune b/src/stages/adt_generator/dune index d70d8647e..4a52c6088 100644 --- a/src/stages/adt_generator/dune +++ b/src/stages/adt_generator/dune @@ -1,9 +1,8 @@ (rule - (target generated_fold.ml) + (target fold.ml) (deps generator.py) - (action (with-stdout-to generated_fold.ml (run python3 ./generator.py))) -; (mode (promote (until-clean))) ; If this is uncommented, then "dune build -p ligo" can't find the file (but "dune build" can) -) + (action (with-stdout-to fold.ml (run python3 ./generator.py))) + (mode (promote (until-clean)))) ; (library ; (name adt_generator) ; (public_name ligo.adt_generator) @@ -17,8 +16,3 @@ (libraries ) ) - -(alias - (name runtest) - (action (run ./adt_generator.exe)) -) diff --git a/src/stages/adt_generator/fold.ml b/src/stages/adt_generator/fold.ml index 271974820..4e4c41357 100644 --- a/src/stages/adt_generator/fold.ml +++ b/src/stages/adt_generator/fold.ml @@ -1 +1,184 @@ -include Generated_fold +open A + +type root' = + | A' of a' + | B' of int + | C' of string +and a' = + { + a1' : ta1' ; + a2' : ta2' ; + } +and ta1' = + | X' of root' + | Y' of ta2' +and ta2' = + | Z' of ta2' + | W' of unit + +type 'state continue_fold = + { + root : root -> 'state -> (root' * 'state) ; + root_A : a -> 'state -> (a' * 'state) ; + root_B : int -> 'state -> (int * 'state) ; + root_C : string -> 'state -> (string * 'state) ; + a : a -> 'state -> (a' * 'state) ; + a_a1 : ta1 -> 'state -> (ta1' * 'state) ; + a_a2 : ta2 -> 'state -> (ta2' * 'state) ; + ta1 : ta1 -> 'state -> (ta1' * 'state) ; + ta1_X : root -> 'state -> (root' * 'state) ; + ta1_Y : ta2 -> 'state -> (ta2' * 'state) ; + ta2 : ta2 -> 'state -> (ta2' * 'state) ; + ta2_Z : ta2 -> 'state -> (ta2' * 'state) ; + ta2_W : unit -> 'state -> (unit * 'state) ; + } + +type 'state fold_config = + { + root : root -> 'state -> ('state continue_fold) -> (root' * 'state) ; + root_pre_state : root -> 'state -> 'state ; + root_post_state : root -> root' -> 'state -> 'state ; + root_A : a -> 'state -> ('state continue_fold) -> (a' * 'state) ; + root_B : int -> 'state -> ('state continue_fold) -> (int * 'state) ; + root_C : string -> 'state -> ('state continue_fold) -> (string * 'state) ; + a : a -> 'state -> ('state continue_fold) -> (a' * 'state) ; + a_pre_state : a -> 'state -> 'state ; + a_post_state : a -> a' -> 'state -> 'state ; + a_a1 : ta1 -> 'state -> ('state continue_fold) -> (ta1' * 'state) ; + a_a2 : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ; + ta1 : ta1 -> 'state -> ('state continue_fold) -> (ta1' * 'state) ; + ta1_pre_state : ta1 -> 'state -> 'state ; + ta1_post_state : ta1 -> ta1' -> 'state -> 'state ; + ta1_X : root -> 'state -> ('state continue_fold) -> (root' * 'state) ; + ta1_Y : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ; + ta2 : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ; + ta2_pre_state : ta2 -> 'state -> 'state ; + ta2_post_state : ta2 -> ta2' -> 'state -> 'state ; + ta2_Z : ta2 -> 'state -> ('state continue_fold) -> (ta2' * 'state) ; + ta2_W : unit -> 'state -> ('state continue_fold) -> (unit * 'state) ; + } + +(* Curries the "visitor" argument to the folds (non-customizable traversal functions). *) +let rec mk_continue_fold : type state . state fold_config -> state continue_fold = fun visitor -> + { + root = fold_root visitor ; + root_A = fold_root_A visitor ; + root_B = fold_root_B visitor ; + root_C = fold_root_C visitor ; + a = fold_a visitor ; + a_a1 = fold_a_a1 visitor ; + a_a2 = fold_a_a2 visitor ; + ta1 = fold_ta1 visitor ; + ta1_X = fold_ta1_X visitor ; + ta1_Y = fold_ta1_Y visitor ; + ta2 = fold_ta2 visitor ; + ta2_Z = fold_ta2_Z visitor ; + ta2_W = fold_ta2_W visitor ; +} + +and fold_root : type state . state fold_config -> root -> state -> (root' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + let state = visitor.root_pre_state x state in + let (new_x, state) = visitor.root x state continue_fold in + let state = visitor.root_post_state x new_x state in + (new_x, state) + +and fold_root_A : type state . state fold_config -> a -> state -> (a' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.root_A x state continue_fold + +and fold_root_B : type state . state fold_config -> int -> state -> (int * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.root_B x state continue_fold + +and fold_root_C : type state . state fold_config -> string -> state -> (string * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.root_C x state continue_fold + +and fold_a : type state . state fold_config -> a -> state -> (a' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + let state = visitor.a_pre_state x state in + let (new_x, state) = visitor.a x state continue_fold in + let state = visitor.a_post_state x new_x state in + (new_x, state) + +and fold_a_a1 : type state . state fold_config -> ta1 -> state -> (ta1' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.a_a1 x state continue_fold + +and fold_a_a2 : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.a_a2 x state continue_fold + +and fold_ta1 : type state . state fold_config -> ta1 -> state -> (ta1' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + let state = visitor.ta1_pre_state x state in + let (new_x, state) = visitor.ta1 x state continue_fold in + let state = visitor.ta1_post_state x new_x state in + (new_x, state) + +and fold_ta1_X : type state . state fold_config -> root -> state -> (root' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.ta1_X x state continue_fold + +and fold_ta1_Y : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.ta1_Y x state continue_fold + +and fold_ta2 : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + let state = visitor.ta2_pre_state x state in + let (new_x, state) = visitor.ta2 x state continue_fold in + let state = visitor.ta2_post_state x new_x state in + (new_x, state) + +and fold_ta2_Z : type state . state fold_config -> ta2 -> state -> (ta2' * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.ta2_Z x state continue_fold + +and fold_ta2_W : type state . state fold_config -> unit -> state -> (unit * state) = fun visitor x state -> + let continue_fold : state continue_fold = mk_continue_fold visitor in + visitor.ta2_W x state continue_fold + +let no_op : 'a fold_config = { + root = (fun v state continue -> + match v with + | A v -> let (v, state) = continue.root_A v state in (A' v, state) + | B v -> let (v, state) = continue.root_B v state in (B' v, state) + | C v -> let (v, state) = continue.root_C v state in (C' v, state) + ); + root_pre_state = (fun v state -> ignore v; state) ; + root_post_state = (fun v new_v state -> ignore (v, new_v); state) ; + root_A = (fun v state continue -> continue.a v state ) ; + root_B = (fun v state continue -> ignore continue; (v, state) ) ; + root_C = (fun v state continue -> ignore continue; (v, state) ) ; + a = (fun v state continue -> + match v with + { a1; a2; } -> + let (a1', state) = continue.a_a1 a1 state in + let (a2', state) = continue.a_a2 a2 state in + ({ a1'; a2'; }, state) + ); + a_pre_state = (fun v state -> ignore v; state) ; + a_post_state = (fun v new_v state -> ignore (v, new_v); state) ; + a_a1 = (fun v state continue -> continue.ta1 v state ) ; + a_a2 = (fun v state continue -> continue.ta2 v state ) ; + ta1 = (fun v state continue -> + match v with + | X v -> let (v, state) = continue.ta1_X v state in (X' v, state) + | Y v -> let (v, state) = continue.ta1_Y v state in (Y' v, state) + ); + ta1_pre_state = (fun v state -> ignore v; state) ; + ta1_post_state = (fun v new_v state -> ignore (v, new_v); state) ; + ta1_X = (fun v state continue -> continue.root v state ) ; + ta1_Y = (fun v state continue -> continue.ta2 v state ) ; + ta2 = (fun v state continue -> + match v with + | Z v -> let (v, state) = continue.ta2_Z v state in (Z' v, state) + | W v -> let (v, state) = continue.ta2_W v state in (W' v, state) + ); + ta2_pre_state = (fun v state -> ignore v; state) ; + ta2_post_state = (fun v new_v state -> ignore (v, new_v); state) ; + ta2_Z = (fun v state continue -> continue.ta2 v state ) ; + ta2_W = (fun v state continue -> ignore continue; (v, state) ) ; +} diff --git a/src/stages/adt_generator/generator.py b/src/stages/adt_generator/generator.py index 48b8c5fd4..65fe21878 100644 --- a/src/stages/adt_generator/generator.py +++ b/src/stages/adt_generator/generator.py @@ -1,49 +1,34 @@ moduleName = "A" -variant="_ _variant" -record="_ _record" -def poly(x): return x adts = [ - # typename, kind, fields_or_ctors - ("root", variant, [ - # ctor, builtin?, type - ("A", False, "rootA"), - ("B", False, "rootB"), + # typename, variant?, fields_or_ctors + ("root", True, [ + # ctor, builtin, type + ("A", False, "a"), + ("B", True, "int"), ("C", True, "string"), ]), - ("a", record, [ - # field, builtin?, type + ("a", False, [ ("a1", False, "ta1"), ("a2", False, "ta2"), ]), - ("ta1", variant, [ + ("ta1", True, [ ("X", False, "root"), ("Y", False, "ta2"), ]), - ("ta2", variant, [ + ("ta2", True, [ ("Z", False, "ta2"), ("W", True, "unit"), ]), - # polymorphic type - ("rootA", poly("list"), - [ - # Position (0..n-1), builtin?, type argument - (0, False, "a") - ]), - ("rootB", poly("list"), - [ - # Position (0..n-1), builtin?, type argument - (0, True, "int") - ]), ] from collections import namedtuple -adt = namedtuple('adt', ['name', 'newName', 'kind', 'ctorsOrFields']) +adt = namedtuple('adt', ['name', 'newName', 'isVariant', 'ctorsOrFields']) ctorOrField = namedtuple('ctorOrField', ['name', 'newName', 'isBuiltin', 'type_', 'newType']) adts = [ adt( name = name, newName = f"{name}'", - kind = kind, + isVariant = isVariant, ctorsOrFields = [ ctorOrField( name = cf, @@ -55,32 +40,23 @@ adts = [ for (cf, isBuiltin, type_) in ctors ], ) - for (name, kind, ctors) in adts + for (name, isVariant, ctors) in adts ] -print("(* This is an auto-generated file. Do not edit. *)") - -print("") print("open %s" % moduleName) print("") for (index, t) in enumerate(adts): typeOrAnd = "type" if index == 0 else "and" print(f"{typeOrAnd} {t.newName} =") - if t.kind == variant: + if t.isVariant: for c in t.ctorsOrFields: print(f" | {c.newName} of {c.newType}") - elif t.kind == record: + else: print(" {") for f in t.ctorsOrFields: print(f" {f.newName} : {f.newType} ;") print(" }") - else: - print(" ", end='') - for a in t.ctorsOrFields: - print(f"{a.newType}", end=' ') - print(t.kind, end='') - print("") print("") print(f"type 'state continue_fold =") @@ -131,10 +107,10 @@ print("let no_op : 'a fold_config = {") for t in adts: print(f" {t.name} = (fun v state continue ->") print(" match v with") - if t.kind == variant: + if t.isVariant: for c in t.ctorsOrFields: print(f" | {c.name} v -> let (v, state) = continue.{t.name}_{c.name} v state in ({c.newName} v, state)") - elif t.kind == record: + else: print(" {", end=' ') for f in t.ctorsOrFields: print(f"{f.name};", end=' ') @@ -145,10 +121,6 @@ for t in adts: for f in t.ctorsOrFields: print(f"{f.newName};", end=' ') print("}, state)") - else: - print(f" v -> fold_{t.kind} v state (", end=' ') - print(", ".join([f"continue.{t.name}_{f.name}" for f in t.ctorsOrFields]), end='') - print(" )") print(" );") print(f" {t.name}_pre_state = (fun v state -> ignore v; state) ;") print(f" {t.name}_post_state = (fun v new_v state -> ignore (v, new_v); state) ;") diff --git a/src/stages/adt_generator/use_a_fold.ml b/src/stages/adt_generator/use_a_fold.ml index 0fe476d42..6a73f4782 100644 --- a/src/stages/adt_generator/use_a_fold.ml +++ b/src/stages/adt_generator/use_a_fold.ml @@ -4,7 +4,7 @@ open Fold (* TODO: how should we plug these into our test framework? *) let () = - let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in + let some_root : root = A { a1 = X (A { a1 = X (B 1) ; a2 = W () ; }) ; a2 = Z (W ()) ; } in let op = { no_op with a = fun the_a state continue_fold -> @@ -23,7 +23,7 @@ let () = () let () = - let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in + let some_root : root = A { a1 = X (A { a1 = X (B 1) ; a2 = W () ; }) ; a2 = Z (W ()) ; } in let op = { no_op with a_pre_state = fun _the_a state -> state + 1 } in let state = 0 in let (_, state) = fold_root op some_root state in @@ -33,7 +33,7 @@ let () = () let () = - let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in + let some_root : root = A { a1 = X (A { a1 = X (B 1) ; a2 = W () ; }) ; a2 = Z (W ()) ; } in let op = { no_op with a_post_state = fun _the_a _new_a state -> state + 1 } in let state = 0 in let (_, state) = fold_root op some_root state in diff --git a/src/stages/ast_typed/types.ml b/src/stages/ast_typed/types.ml index 8804e49e7..5aa323c9b 100644 --- a/src/stages/ast_typed/types.ml +++ b/src/stages/ast_typed/types.ml @@ -95,6 +95,7 @@ and matching = and ascription = {anno_expr: expression; type_annotation: type_expression} + and environment_element_definition = | ED_binder | ED_declaration of (expression * free_variables) diff --git a/tools/webide/Dockerfile b/tools/webide/Dockerfile index 212b12130..4dfa9963a 100644 --- a/tools/webide/Dockerfile +++ b/tools/webide/Dockerfile @@ -17,7 +17,7 @@ FROM node:12-buster WORKDIR /app -RUN apt-get update && apt-get -y install python3 libev-dev perl pkg-config libgmp-dev libhidapi-dev m4 libcap-dev bubblewrap rsync +RUN apt-get update && apt-get -y install libev-dev perl pkg-config libgmp-dev libhidapi-dev m4 libcap-dev bubblewrap rsync COPY ligo_deb10.deb /tmp/ligo_deb10.deb RUN dpkg -i /tmp/ligo_deb10.deb && rm /tmp/ligo_deb10.deb diff --git a/vendors/UnionFind/UnionFind.install b/vendors/UnionFind/UnionFind.install new file mode 100644 index 000000000..692984e20 --- /dev/null +++ b/vendors/UnionFind/UnionFind.install @@ -0,0 +1,36 @@ +lib: [ + "_build/install/default/lib/UnionFind/META" + "_build/install/default/lib/UnionFind/Partition.cmi" + "_build/install/default/lib/UnionFind/Partition.cmti" + "_build/install/default/lib/UnionFind/Partition.mli" + "_build/install/default/lib/UnionFind/Partition0.cmi" + "_build/install/default/lib/UnionFind/Partition0.cmt" + "_build/install/default/lib/UnionFind/Partition0.cmx" + "_build/install/default/lib/UnionFind/Partition0.ml" + "_build/install/default/lib/UnionFind/Partition1.cmi" + "_build/install/default/lib/UnionFind/Partition1.cmt" + "_build/install/default/lib/UnionFind/Partition1.cmx" + "_build/install/default/lib/UnionFind/Partition1.ml" + "_build/install/default/lib/UnionFind/Partition2.cmi" + "_build/install/default/lib/UnionFind/Partition2.cmt" + "_build/install/default/lib/UnionFind/Partition2.cmx" + "_build/install/default/lib/UnionFind/Partition2.ml" + "_build/install/default/lib/UnionFind/Partition3.cmi" + "_build/install/default/lib/UnionFind/Partition3.cmt" + "_build/install/default/lib/UnionFind/Partition3.cmx" + "_build/install/default/lib/UnionFind/Partition3.ml" + "_build/install/default/lib/UnionFind/UnionFind.a" + "_build/install/default/lib/UnionFind/UnionFind.cma" + "_build/install/default/lib/UnionFind/UnionFind.cmxa" + "_build/install/default/lib/UnionFind/UnionFind.cmxs" + "_build/install/default/lib/UnionFind/dune-package" + "_build/install/default/lib/UnionFind/opam" + "_build/install/default/lib/UnionFind/unionFind.cmi" + "_build/install/default/lib/UnionFind/unionFind.cmt" + "_build/install/default/lib/UnionFind/unionFind.cmx" + "_build/install/default/lib/UnionFind/unionFind.ml" +] +doc: [ + "_build/install/default/doc/UnionFind/LICENSE" + "_build/install/default/doc/UnionFind/README.md" +] From 8c0a25bdb5951c27e6ee41008f99d9bd18dbd9df Mon Sep 17 00:00:00 2001 From: Christian Rinderknecht Date: Tue, 11 Feb 2020 22:29:12 +0100 Subject: [PATCH 8/9] Fixes after writing the slides. --- .../docs/advanced/entrypoints-contracts.md | 120 +++++++++--------- gitlab-pages/docs/advanced/include.md | 16 +-- .../docs/advanced/timestamps-addresses.md | 8 +- gitlab-pages/docs/intro/what-and-why.md | 2 +- .../docs/language-basics/boolean-if-else.md | 23 ++++ .../docs/language-basics/functions.md | 35 +++-- gitlab-pages/docs/language-basics/loops.md | 61 +++++---- .../docs/language-basics/maps-records.md | 67 +++++----- .../docs/language-basics/math-numbers-tez.md | 17 ++- .../docs/language-basics/sets-lists-tuples.md | 120 ++++++++++-------- gitlab-pages/docs/language-basics/strings.md | 18 +-- .../docs/language-basics/tezos-specific.md | 22 ++-- gitlab-pages/docs/language-basics/types.md | 3 +- .../variables-and-constants.md | 3 +- .../version-next/contributors/origin.md | 10 +- .../version-next/contributors/philosophy.md | 75 +++-------- 16 files changed, 309 insertions(+), 291 deletions(-) diff --git a/gitlab-pages/docs/advanced/entrypoints-contracts.md b/gitlab-pages/docs/advanced/entrypoints-contracts.md index 07bb7ee0c..15fa7cb75 100644 --- a/gitlab-pages/docs/advanced/entrypoints-contracts.md +++ b/gitlab-pages/docs/advanced/entrypoints-contracts.md @@ -18,9 +18,9 @@ is provided, but the type of an access function contains both. The type of the contract parameter and the storage are up to the contract designer, but the type for list operations is not. The return -type of an entrypoint is as follows, assuming that the type `storage` -has been defined elsewhere. (Note that you can use any type with any -name for the storage.) +type of an access function is as follows, assuming that the type +`storage` has been defined elsewhere. (Note that you can use any type +with any name for the storage.) @@ -45,9 +45,10 @@ type return = (list (operation), storage); The contract storage can only be modified by activating an access function. It is important to understand what that means. What it does *not* mean is that some global variable holding the storage is -modified by the entrypoint. Instead, what it *does* mean is that, -given the state of the storage *on-chain*, an entrypoint specifies how -to create another state for it, depending on a parameter. +modified by the access function. Instead, what it *does* mean is that, +given the state of the storage *on-chain*, an access function +specifies how to create another state for it, depending on a +parameter. Here is an example where the storage is a single natural number that is updated by the parameter. @@ -57,28 +58,32 @@ is updated by the parameter. ```pascaligo group=a +type parameter is nat type storage is nat type return is list (operation) * storage -function save (const parameter : nat; const store : storage) : return is - ((nil : list (operation)), parameter) +function save (const action : parameter; const store : storage) : return is + ((nil : list (operation)), store) ``` ```cameligo group=a +type parameter = nat type storage = nat +type return = operation list * storage -let save (parameter, store: nat * storage) : return = - (([] : operation list), parameter) +let save (action, store: parameter * storage) : return = + (([] : operation list), store) ``` ```reasonligo group=a +type parameter = nat; type storage = nat; +type return = (list (operation), storage); -let main = ((parameter, store): (nat, storage)) : return => { - (([] : list (operation)), parameter); -}; +let main = ((action, store): (parameter, storage)) : return => + (([] : list (operation)), store); ``` @@ -107,8 +112,8 @@ contract, either the counter or the name is updated. ```pascaligo group=b type parameter is - Entrypoint_A of nat -| Entrypoint_B of string + Action_A of nat +| Action_B of string type storage is record [ counter : nat; @@ -117,24 +122,24 @@ type storage is record [ type return is list (operation) * storage -function handle_A (const n : nat; const store : storage) : return is +function entry_A (const n : nat; const store : storage) : return is ((nil : list (operation)), store with record [counter = n]) -function handle_B (const s : string; const store : storage) : return is +function entry_B (const s : string; const store : storage) : return is ((nil : list (operation)), store with record [name = s]) -function main (const param : parameter; const store : storage): return is - case param of - Entrypoint_A (n) -> handle_A (n, store) - | Entrypoint_B (s) -> handle_B (s, store) +function access (const action : parameter; const store : storage): return is + case action of + Action_A (n) -> entry_A (n, store) + | Action_B (s) -> entry_B (s, store) end ``` ```cameligo group=b type parameter = - Entrypoint_A of nat -| Entrypoint_B of string + Action_A of nat +| Action_B of string type storage = { counter : nat; @@ -143,23 +148,23 @@ type storage = { type return = operation list * storage -let handle_A (n, store : nat * storage) : return = +let entry_A (n, store : nat * storage) : return = ([] : operation list), {store with counter = n} -let handle_B (s, store : string * storage) : return = +let entry_B (s, store : string * storage) : return = ([] : operation list), {store with name = s} -let main (param, store: parameter * storage) : return = - match param with - Entrypoint_A n -> handle_A (n, store) - | Entrypoint_B s -> handle_B (s, store) +let access (action, store: parameter * storage) : return = + match action with + Action_A n -> entry_A (n, store) + | Action_B s -> entry_B (s, store) ``` ```reasonligo group=b type parameter = -| Entrypoint_A (nat) -| Entrypoint_B (string); +| Action_A (nat) +| Action_B (string); type storage = { counter : nat, @@ -168,18 +173,17 @@ type storage = { type return = (list (operation), storage); -let handle_A = ((n, store): (nat, storage)) : return => { - (([] : list (operation)), {...store, counter : n}); }; +let entry_A = ((n, store): (nat, storage)) : return => + (([] : list (operation)), {...store, counter : n}); -let handle_B = ((s, store): (string, storage)) : return => { - (([] : list (operation)), {...store, name : s}); }; +let entry_B = ((s, store): (string, storage)) : return => + (([] : list (operation)), {...store, name : s}); -let main = ((param, store): (parameter, storage)) : return => { - switch (param) { - | Entrypoint_A (n) => handle_A ((n, store)) - | Entrypoint_B (s) => handle_B ((s, store)) - } -}; +let access = ((action, store): (parameter, storage)) : return => + switch (action) { + | Action_A (n) => entry_A ((n, store)) + | Action_B (s) => entry_B ((s, store)) + }; ``` @@ -203,7 +207,7 @@ type parameter is unit type storage is unit type return is list (operation) * storage -function deny (const param : parameter; const store : storage) : return is +function deny (const action : parameter; const store : storage) : return is if amount > 0mutez then (failwith ("This contract does not accept tokens.") : return) else ((nil : list (operation)), store) @@ -215,7 +219,7 @@ type parameter = unit type storage = unit type return = operation list * storage -let deny (param, store : parameter * storage) : return = +let deny (action, store : parameter * storage) : return = if amount > 0mutez then (failwith "This contract does not accept tokens.": return) else (([] : operation list), store) @@ -227,7 +231,7 @@ type parameter = unit; type storage = unit; type return = (list (operation), storage); -let deny = ((param, store): (parameter, storage)) : return => { +let deny = ((action, store): (parameter, storage)) : return => { if (amount > 0mutez) { (failwith("This contract does not accept tokens."): return); } else { (([] : list (operation)), store); }; @@ -245,7 +249,7 @@ This example shows how `sender` or `source` can be used to deny access to an ent ```pascaligo group=c const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address); -function filter (const param : parameter; const store : storage) : return is +function filter (const action : parameter; const store : storage) : return is if source =/= owner then (failwith ("Access denied.") : return) else ((nil : list(operation)), store) ``` @@ -254,7 +258,7 @@ function filter (const param : parameter; const store : storage) : return is ```cameligo group=c let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -let filter (param, store: parameter * storage) : return = +let filter (action, store: parameter * storage) : return = if source <> owner then (failwith "Access denied." : return) else (([] : operation list), store) ``` @@ -263,7 +267,7 @@ let filter (param, store: parameter * storage) : return = ```reasonligo group=c let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address); -let main = ((param, store): (parameter, storage)) : storage => { +let access = ((action, store): (parameter, storage)) : storage => { if (source != owner) { (failwith ("Access denied.") : return); } else { (([] : list (operation)), store); }; }; @@ -289,10 +293,10 @@ emiting a transaction operation at the end of an entrypoint. > account (tz1, ...): all you have to do is use a unit value as the > parameter of the smart contract. -In our case, we have a `counter.ligo` contract that accepts a -parameter of type `action`, and we have a `proxy.ligo` contract that -accepts the same parameter type, and forwards the call to the deployed -counter contract. +In our case, we have a `counter.ligo` contract that accepts an action +of type `parameter`, and we have a `proxy.ligo` contract that accepts +the same parameter type, and forwards the call to the deployed counter +contract. @@ -323,13 +327,13 @@ type return is list (operation) * storage const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) -function proxy (const param : parameter; const store : storage): return is +function proxy (const action : parameter; const store : storage): return is block { const counter : contract (parameter) = get_contract (dest); (* Reuse the parameter in the subsequent transaction or use another one, `mock_param`. *) const mock_param : parameter = Increment (5n); - const op : operation = transaction (param, 0mutez, counter); + const op : operation = transaction (action, 0mutez, counter); const ops : list (operation) = list [op] } with (ops, store) ``` @@ -338,7 +342,7 @@ function proxy (const param : parameter; const store : storage): return is ```cameligo skip // counter.mligo -type paramater = +type parameter = Increment of nat | Decrement of nat | Reset @@ -360,12 +364,12 @@ type return = operation list * storage let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) -let proxy (param, store : parameter * storage) : return = +let proxy (action, store : parameter * storage) : return = let counter : parameter contract = Operation.get_contract dest in (* Reuse the parameter in the subsequent transaction or use another one, `mock_param`. *) let mock_param : parameter = Increment (5n) in - let op : operation = Operation.transaction param 0mutez counter + let op : operation = Operation.transaction action 0mutez counter in [op], store ``` @@ -395,12 +399,12 @@ type return = (list (operation), storage); let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address); -let proxy = ((param, store): (parameter, storage)) : return => { +let proxy = ((action, store): (parameter, storage)) : return => { let counter : contract (parameter) = Operation.get_contract (dest); (* Reuse the parameter in the subsequent transaction or use another one, `mock_param`. *) let mock_param : parameter = Increment (5n); - let op : operation = Operation.transaction (param, 0mutez, counter); + let op : operation = Operation.transaction (action, 0mutez, counter); ([op], store) }; ``` diff --git a/gitlab-pages/docs/advanced/include.md b/gitlab-pages/docs/advanced/include.md index 956d4a80e..21094102e 100644 --- a/gitlab-pages/docs/advanced/include.md +++ b/gitlab-pages/docs/advanced/include.md @@ -3,13 +3,12 @@ id: include title: Including Other Contracts --- -Lets say we have a contract that's getting a bit too big. If it has a modular -structure, you might find it useful to use the `#include` statement to split the -contract up over multiple files. +Let us say that we have a contract that is getting a too large. If it +has a modular structure, you might find it useful to use the +`#include` statement to split the contract up over multiple files. - -You take the code that you want to include and put it in a separate file, for -example `included.ligo`: +You take the code that you want to include and put it in a separate +file, for example `included.ligo`: @@ -23,7 +22,6 @@ const foo : int = 144 ```cameligo - // Demonstrate CameLIGO inclusion statements, see includer.mligo let foo : int = 144 @@ -31,7 +29,6 @@ let foo : int = 144 ```reasonligo - // Demonstrate ReasonLIGO inclusion statements, see includer.religo let foo : int = 144; @@ -46,7 +43,6 @@ And then you can include this code using the `#include` statement like so: ```pascaligo - #include "included.ligo" const bar : int = foo @@ -54,7 +50,6 @@ const bar : int = foo ```cameligo - #include "included.mligo" let bar : int = foo @@ -62,7 +57,6 @@ let bar : int = foo ```reasonligo - #include "included.religo" let bar : int = foo; diff --git a/gitlab-pages/docs/advanced/timestamps-addresses.md b/gitlab-pages/docs/advanced/timestamps-addresses.md index 5174e1cc8..fb2154bc8 100644 --- a/gitlab-pages/docs/advanced/timestamps-addresses.md +++ b/gitlab-pages/docs/advanced/timestamps-addresses.md @@ -33,10 +33,10 @@ let today : timestamp = Current.time; -> When running code with ligo CLI, the option +> When running code, the LIGO CLI option > `--predecessor-timestamp` allows you to control what `now` returns. -### Timestamp Arithmetic +### Timestamp Arithmetics In LIGO, timestamps can be added to integers, allowing you to set time constraints on your smart contracts. Consider the following scenarios. @@ -124,9 +124,9 @@ let not_tomorrow : bool = (Current.time == in_24_hrs); ## Addresses -The type `address` in LIGO denotes Tezos addresses (tz1, tz2, tz3, +The `address` type in LIGO denotes Tezos addresses (tz1, tz2, tz3, KT1, ...). Currently, addresses are created by casting a string to the -type `address`. Beware of failures if the address is invalid. Consider +`address` type. Beware of failures if the address is invalid. Consider the following examples. diff --git a/gitlab-pages/docs/intro/what-and-why.md b/gitlab-pages/docs/intro/what-and-why.md index 2cf50e98c..f195b97a7 100644 --- a/gitlab-pages/docs/intro/what-and-why.md +++ b/gitlab-pages/docs/intro/what-and-why.md @@ -162,7 +162,7 @@ not worry if it is a little confusing at first; we will explain all the syntax in the upcoming sections of the documentation. - + ```pascaligo group=a type storage is int diff --git a/gitlab-pages/docs/language-basics/boolean-if-else.md b/gitlab-pages/docs/language-basics/boolean-if-else.md index 56d565cec..8a872d777 100644 --- a/gitlab-pages/docs/language-basics/boolean-if-else.md +++ b/gitlab-pages/docs/language-basics/boolean-if-else.md @@ -148,6 +148,29 @@ gitlab-pages/docs/language-basics/boolean-if-else/cond.ligo compare 21n' # Outputs: Large (Unit) ``` +When the branches of the conditional are not a single expression, as +above, we need a block: + +```pascaligo skip +if x < y then + block { + const z : nat = x; + x := y; y := z + } +else skip; +``` + +As an exception to the rule, the blocks in a conditional branch do not +need to be introduced by the keywor `block`, so, we could have written +instead: +```pascaligo skip +if x < y then { + const z : nat = x; + x := y; y := z +} +else skip; +``` + ```cameligo group=e type magnitude = Small | Large // See variant types. diff --git a/gitlab-pages/docs/language-basics/functions.md b/gitlab-pages/docs/language-basics/functions.md index 9fe1ff4f2..d0344a754 100644 --- a/gitlab-pages/docs/language-basics/functions.md +++ b/gitlab-pages/docs/language-basics/functions.md @@ -3,8 +3,8 @@ id: functions title: Functions --- -LIGO features functions are the basic building block of contracts. For -example, entrypoints are functions. +LIGO functions are the basic building block of contracts. For example, +entrypoints are functions. ## Declaring Functions @@ -119,8 +119,8 @@ parameter, we should gather the arguments in a [tuple](language-basics/sets-lists-tuples.md) and pass the tuple in as a single parameter. -Here is how you define a basic function that accepts two `ints` and -returns an `int` as well: +Here is how you define a basic function that accepts two integers and +returns an integer as well: ```cameligo group=b let add (a, b : int * int) : int = a + b // Uncurried @@ -137,10 +137,11 @@ ligo run-function gitlab-pages/docs/language-basics/src/functions/curry.mligo in The function body is a single expression, whose value is returned. - Functions in ReasonLIGO are defined using the `let` -keyword, like other values. The difference is that a tuple of -parameters is provided after the value name, with its type, then -followed by the return type. + + +Functions in ReasonLIGO are defined using the `let` keyword, like +other values. The difference is that a tuple of parameters is provided +after the value name, with its type, then followed by the return type. Here is how you define a basic function that sums two integers: ```reasonligo group=b @@ -154,7 +155,19 @@ ligo run-function gitlab-pages/docs/language-basics/src/functions/blockless.reli # Outputs: 3 ``` -The function body is a single expression, whose value is returned. +As in CameLIGO and with blockless functions in PascaLIGO, the function +body is a single expression, whose value is returned. + +If the body contains more than a single expression, you use block +between braces: +```reasonligo group=b +let myFun = ((x, y) : (int, int)) : int => { + let doubleX = x + x; + let doubleY = y + y; + doubleX + doubleY +}; +``` + ## Anonymous functions (a.k.a. lambdas) @@ -170,7 +183,6 @@ Here is how to define an anonymous function: ```pascaligo group=c function increment (const b : int) : int is (function (const a : int) : int is a + 1) (b) - const a : int = increment (1); // a = 2 ``` @@ -196,7 +208,7 @@ ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.mligo a ```reasonligo group=c -let increment = (b : int) : int => ((a : int) : int => a + 1)(b); +let increment = (b : int) : int => ((a : int) : int => a + 1) (b); let a : int = increment (1); // a == 2 ``` @@ -257,5 +269,4 @@ gitlab-pages/docs/language-basics/src/functions/incr_map.religo incr_map # Outputs: [ 2 ; 3 ; 4 ] ``` - diff --git a/gitlab-pages/docs/language-basics/loops.md b/gitlab-pages/docs/language-basics/loops.md index ce656ec86..bb31e124f 100644 --- a/gitlab-pages/docs/language-basics/loops.md +++ b/gitlab-pages/docs/language-basics/loops.md @@ -20,16 +20,15 @@ loops fails to become true, the execution will run out of gas and stop with a failure anyway. Here is how to compute the greatest common divisors of two natural -number by means of Euclid's algorithm: +numbers by means of Euclid's algorithm: ```pascaligo group=a function gcd (var x : nat; var y : nat) : nat is block { - if x < y then - block { - const z : nat = x; - x := y; y := z - } + if x < y then { + const z : nat = x; + x := y; y := z + } else skip; var r : nat := 0n; while y =/= 0n block { @@ -55,18 +54,19 @@ constant, therefore it makes no sense in CameLIGO to feature loops, which we understand as syntactic constructs where the state of a stopping condition is mutated, as with "while" loops in PascaLIGO. -Instead, CameLIGO features a *fold operation* as a predefined function -named `Loop.fold_while`. It takes an initial value of a certain type, -called an *accumulator*, and repeatedly calls a given function, called -*iterated function*, that takes that accumulator and returns the next -value of the accumulator, until a condition is met and the fold stops -with the final value of the accumulator. The iterated function needs -to have a special type: if the type of the accumulator is `t`, then it -must have the type `bool * t` (not simply `t`). It is the boolean -value that denotes whether the stopping condition has been reached. +Instead, CameLIGO implements a *folded operation* by means of a +predefined function named `Loop.fold_while`. It takes an initial value +of a certain type, called an *accumulator*, and repeatedly calls a +given function, called *folded function*, that takes that +accumulator and returns the next value of the accumulator, until a +condition is met and the fold stops with the final value of the +accumulator. The iterated function needs to have a special type: if +the type of the accumulator is `t`, then it must have the type `bool * +t` (not simply `t`). It is the boolean value that denotes whether the +stopping condition has been reached. Here is how to compute the greatest common divisors of two natural -number by means of Euclid's algorithm: +numbers by means of Euclid's algorithm: ```cameligo group=a let iter (x,y : nat * nat) : bool * (nat * nat) = @@ -117,7 +117,7 @@ accumulator is `t`, then it must have the type `bool * t` (not simply condition has been reached. Here is how to compute the greatest common divisors of two natural -number by means of Euclid's algorithm: +numbers by means of Euclid's algorithm: ```reasonligo group=a let iter = ((x,y) : (nat, nat)) : (bool, (nat, nat)) => @@ -149,11 +149,10 @@ let gcd = ((x,y) : (nat, nat)) : nat => { In addition to general loops, PascaLIGO features a specialised kind of *loop to iterate over bounded intervals*. These loops are familiarly -known as "for loops" and they have the form `for to - `, which is familiar for programmers of -imperative languages. +known as "for loops" and they have the form `for +to `, as found in imperative languages. -Consider how to sum integers from `0` to `n`: +Consider how to sum the natural numbers up to `n`: ```pascaligo group=c function sum (var n : nat) : int is block { @@ -177,7 +176,7 @@ gitlab-pages/docs/language-basics/src/loops/sum.ligo sum 7n PascaLIGO "for" loops can also iterate through the contents of a collection, that is, a list, a set or a map. This is done with a loop of the form `for in -`, where ``, where `` is any of the following keywords: `list`, `set` or `map`. Here is an example where the integers in a list are summed up. @@ -202,7 +201,7 @@ gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_list Here is an example where the integers in a set are summed up. -```pascaligo=e +```pascaligo group=d function sum_set (var s : set (int)) : int is block { var total : int := 0; for i in set s block { @@ -222,9 +221,23 @@ gitlab-pages/docs/language-basics/src/loops/collection.ligo sum_set Loops over maps are actually loops over the bindings of the map, that is, a pair key-value noted `key -> value` (or any other -variables). Give a map from strings to integers, here is how to sum +variables). Given a map from strings to integers, here is how to sum all the integers and concatenate all the strings. +Here is an example where the keys are concatenated and the values are +summed up. + +```pascaligo group=d +function sum_map (var m : map (string, int)) : string * int is block { + var string_total : string := ""; + var int_total : int := 0; + for key -> value in map m block { + string_total := string_total ^ key; + int_total := int_total + value + } +} with (string_total, int_total) +``` + You can call the function `sum_map` defined above using the LIGO compiler like so: ```shell diff --git a/gitlab-pages/docs/language-basics/maps-records.md b/gitlab-pages/docs/language-basics/maps-records.md index 59226b4e3..d691d588e 100644 --- a/gitlab-pages/docs/language-basics/maps-records.md +++ b/gitlab-pages/docs/language-basics/maps-records.md @@ -97,7 +97,7 @@ let alice_admin : bool = alice.is_admin ```reasonligo group=a -let alice_admin: bool = alice.is_admin; +let alice_admin : bool = alice.is_admin; ``` @@ -110,9 +110,7 @@ modified. One way to understand the update of record values is the *functional update*. The idea is to have an *expression* whose value is the -updated record. The shape of that expression is ` -with `. The record variable is the record to update and -the record value is the update itself. +updated record. Let us consider defining a function that translates three-dimensional points on a plane. @@ -120,6 +118,11 @@ points on a plane. + +In PascaLIGO, the shape of that expression is ` with +`. The record variable is the record to update and the +record value is the update itself. + ```pascaligo group=b type point is record [x : int; y : int; z : int] type vector is record [dx : int; dy : int] @@ -174,7 +177,7 @@ xy_translate "({x=2;y=3;z=1}, {dx=3;dy=4})" The syntax for the functional updates of record in ReasonLIGO follows -that of OCaml: +that of ReasonML: ```reasonligo group=b type point = {x : int, y : int, z : int}; @@ -199,7 +202,7 @@ xy_translate "({x:2,y:3,z:1}, {dx:3,dy:4})" You have to understand that `p` has not been changed by the functional update: a nameless new version of it has been created and returned. -### Imperative Updates +### Record Patches Another way to understand what it means to update a record value is to make sure that any further reference to the value afterwards will @@ -365,12 +368,13 @@ let moves : register = ### Accessing Map Bindings -We can use the postfix `[]` operator to read the `move` value -associated to a given key (`address` here) in the register. Here is an -example: - + +In PascaLIGO, we can use the postfix `[]` operator to read the `move` +value associated to a given key (`address` here) in the register. Here +is an example: + ```pascaligo group=f const my_balance : option (move) = moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)] @@ -480,10 +484,9 @@ We can update a binding in a map in ReasonLIGO by means of the `Map.update` built-in function: ```reasonligo group=f -let assign = (m : register) : register => { +let assign = (m : register) : register => Map.update - (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m) -}; + (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m); ``` > Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had @@ -521,9 +524,8 @@ let delete (key, moves : address * register) : register = In ReasonLIGO, we use the predefined function `Map.remove` as follows: ```reasonligo group=f -let delete = ((key, moves) : (address, register)) : register => { +let delete = ((key, moves) : (address, register)) : register => Map.remove (key, moves); -}; ``` @@ -540,7 +542,7 @@ There are three kinds of functional iterations over LIGO maps: the *iterated operation*, the *map operation* (not to be confused with the *map data structure*) and the *fold operation*. -#### Iterated Operation +#### Iterated Operation over Maps The first, the *iterated operation*, is an iteration over the map with no return value: its only use is to produce side-effects. This can be @@ -595,7 +597,7 @@ let iter_op = (m : register) : unit => { ``` -#### Map Operation +#### Map Operations over Maps We may want to change all the bindings of a map by applying to them a function. This is called a *map operation*, not to be confused with @@ -606,7 +608,7 @@ the map data structure. In PascaLIGO, the predefined functional iterator implementing the map -operation over maps is called `map_map`and is used as follows: +operation over maps is called `map_map` and is used as follows: ```pascaligo group=f function map_op (const m : register) : register is @@ -643,9 +645,9 @@ let map_op = (m : register) : register => { ``` -#### Fold Operation +#### Folded Operations over Maps -A *fold operation* is the most general of iterations. The folded +A *folded operation* is the most general of iterations. The folded function takes two arguments: an *accumulator* and the structure *element* at hand, with which it then produces a new accumulator. This enables having a partial result that becomes complete when the @@ -655,14 +657,15 @@ traversal of the data structure is over. -In PascaLIGO, the predefined functional iterator implementing the fold -operation over maps is called `map_fold` and is used as follows: +In PascaLIGO, the predefined functional iterator implementing the +folded operation over maps is called `map_fold` and is used as +follows: ```pascaligo group=f function fold_op (const m : register) : int is block { - function iterated (const j : int; const cur : address * move) : int is + function folded (const j : int; const cur : address * move) : int is j + cur.1.1 - } with map_fold (iterated, m, 5) + } with map_fold (folded, m, 5) ``` > The folded function must be pure, that is, it cannot mutate @@ -670,24 +673,26 @@ function fold_op (const m : register) : int is block { -In CameLIGO, the predefined functional iterator implementing the fold -operation over maps is called `Map.fold` and is used as follows: +In CameLIGO, the predefined functional iterator implementing the +folded operation over maps is called `Map.fold` and is used as +follows: ```cameligo group=f let fold_op (m : register) : register = - let iterated = fun (i,j : int * (address * move)) -> i + j.1.1 - in Map.fold iterated m 5 + let folded = fun (i,j : int * (address * move)) -> i + j.1.1 + in Map.fold folded m 5 ``` In ReasonLIGO, the predefined functional iterator implementing the -fold operation over maps is called `Map.fold` and is used as follows: +folded operation over maps is called `Map.fold` and is used as +follows: ```reasonligo group=f let fold_op = (m : register) : register => { - let iterated = ((i,j): (int, (address, move))) => i + j[1][1]; - Map.fold (iterated, m, 5); + let folded = ((i,j): (int, (address, move))) => i + j[1][1]; + Map.fold (folded, m, 5); }; ``` diff --git a/gitlab-pages/docs/language-basics/math-numbers-tez.md b/gitlab-pages/docs/language-basics/math-numbers-tez.md index 11a589c12..41d05ed5d 100644 --- a/gitlab-pages/docs/language-basics/math-numbers-tez.md +++ b/gitlab-pages/docs/language-basics/math-numbers-tez.md @@ -60,13 +60,13 @@ let b : int = 5n + 10 let c : tez = 5mutez + 10mutez // tez + int or tez + nat is invalid -// const d : tez = 5mutez + 10n +// let d : tez = 5mutez + 10n // two nats yield a nat let e : nat = 5n + 10n // nat + int yields an int: invalid -// const f : nat = 5n + 10 +// let f : nat = 5n + 10 let g : int = 1_000_000 ``` @@ -136,7 +136,7 @@ let a : int = 5 - 10 let b : int = 5n - 2n // Therefore the following is invalid -// const c : nat = 5n - 2n +// let c : nat = 5n - 2n let d : tez = 5mutez - 1mutez ``` @@ -167,15 +167,17 @@ You can multiply values of the same type, such as: ```pascaligo group=c const a : int = 5 * 5 const b : nat = 5n * 5n -// You can also multiply `nat` and `tez` in any order -const c : tez = 5n * 5mutez; + +// You can also multiply `nat` and `tez` +const c : tez = 5n * 5mutez ``` ```cameligo group=c let a : int = 5 * 5 let b : nat = 5n * 5n -// You can also multiply `nat` and `tez` in any order + +// You can also multiply `nat` and `tez` let c : tez = 5n * 5mutez ``` @@ -183,7 +185,8 @@ let c : tez = 5n * 5mutez ```reasonligo group=c let a : int = 5 * 5; let b : nat = 5n * 5n; -// You can also multiply `nat` and `tez` in any order + +// You can also multiply `nat` and `tez` let c : tez = 5n * 5mutez; ``` diff --git a/gitlab-pages/docs/language-basics/sets-lists-tuples.md b/gitlab-pages/docs/language-basics/sets-lists-tuples.md index 02c915928..a3db92b6d 100644 --- a/gitlab-pages/docs/language-basics/sets-lists-tuples.md +++ b/gitlab-pages/docs/language-basics/sets-lists-tuples.md @@ -13,10 +13,10 @@ values, called *components*, can be retrieved by their index (position). Probably the most common tuple is the *pair*. For example, if we were storing coordinates on a two dimensional grid we might use a pair `(x,y)` to store the coordinates `x` and `y`. There -is a *specific order*, so `(y,x)` is not equal to `(x,y)`. The number -of components is part of the type of a tuple, so, for example, we -cannot add an extra component to a pair and obtain a triple of the -same type, so, for instance, `(x,y)` has always a different type from +is a *specific order*, so `(y,x)` is not equal to `(x,y)` in +general. The number of components is part of the type of a tuple, so, +for example, we cannot add an extra component to a pair and obtain a +triple of the same type: `(x,y)` has always a different type from `(x,y,z)`, whereas `(y,x)` might have the same type as `(x,y)`. Like records, tuple components can be of arbitrary types. @@ -68,10 +68,10 @@ position in their tuple, which cannot be done in OCaml. -Tuple components are one-indexed like so: +Tuple components are one-indexed and accessed like so: ```pascaligo group=tuple -const first_name : string = full_name.1; +const first_name : string = full_name.1 ``` @@ -84,7 +84,7 @@ let first_name : string = full_name.0 -Tuple components are one-indexed like so: +Tuple components are one-indexed and accessed like so: ```reasonligo group=tuple let first_name : string = full_name[1]; @@ -102,24 +102,27 @@ called the *head*, and the sub-list after the head is called the *tail*. For those familiar with algorithmic data structure, you can think of a list a *stack*, where the top is written on the left. -> 💡 Lists are useful when returning operations from a smart -> contract's entrypoint. +> 💡 Lists are needed when returning operations from a smart +> contract's access function. ### Defining Lists ```pascaligo group=lists +const empty_list : list (int) = nil // Or list [] const my_list : list (int) = list [1; 2; 2] // The head is 1 ``` ```cameligo group=lists +let empty_list : int list = [] let my_list : int list = [1; 2; 2] // The head is 1 ``` ```reasonligo group=lists +let empty_list : list (int) = []; let my_list : list (int) = [1, 2, 2]; // The head is 1 ``` @@ -128,7 +131,6 @@ let my_list : list (int) = [1, 2, 2]; // The head is 1 ### Adding to Lists - Lists can be augmented by adding an element before the head (or, in terms of stack, by *pushing an element on top*). This operation is usually called *consing* in functional languages. @@ -167,12 +169,6 @@ let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2] ``` -> 💡 Lists can be iterated, folded or mapped to different values. You -> can find additional examples -> [here](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts) -> and other built-in operators -> [here](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/operators/operators.ml#L59) - ### Functional Iteration over Lists A *functional iterator* is a function that traverses a data structure @@ -180,16 +176,23 @@ and calls in turn a given function over the elements of that structure to compute some value. Another approach is possible in PascaLIGO: *loops* (see the relevant section). -There are three kinds of functional iterations over LIGO maps: the +There are three kinds of functional iterations over LIGO lists: the *iterated operation*, the *map operation* (not to be confused with the *map data structure*) and the *fold operation*. -#### Iterated Operation +> 💡 Lists can be iterated, folded or mapped to different values. You +> can find additional examples +> [here](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts) +> and other built-in operators +> [here](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/operators/operators.ml#L59) -The first, the *iterated operation*, is an iteration over the map with -no return value: its only use is to produce side-effects. This can be -useful if for example you would like to check that each value inside -of a map is within a certain range, and fail with an error otherwise. +#### Iterated Operation over Lists + +The first, the *iterated operation*, is an iteration over the list +with a unit return value. It is useful to enforce certain invariants +on the element of a list, or fail. For example you might want to check +that each value inside of a list is within a certain range, and fail +otherwise. @@ -244,7 +247,7 @@ let iter_op = (l : list (int)) : unit => { -#### Map Operation +#### Mapped Operation over Lists We may want to change all the elements of a given list by applying to them a function. This is called a *map operation*, not to be confused @@ -254,8 +257,9 @@ with the map data structure. -In PascaLIGO, the predefined functional iterator implementing the map -operation over lists is called `list_map` and is used as follows: +In PascaLIGO, the predefined functional iterator implementing the +mapped operation over lists is called `list_map` and is used as +follows: ```pascaligo group=lists function increment (const i : int): int is i + 1 @@ -264,10 +268,14 @@ function increment (const i : int): int is i + 1 const plus_one : list (int) = list_map (increment, larger_list) ``` +> The mapped function must be pure, that is, it cannot mutate +> variables. + -In CameLIGO, the predefined functional iterator implementing the map -operation over lists is called `List.map` and is used as follows: +In CameLIGO, the predefined functional iterator implementing the +mapped operation over lists is called `List.map` and is used as +follows: ```cameligo group=lists let increment (i : int) : int = i + 1 @@ -278,8 +286,9 @@ let plus_one : int list = List.map increment larger_list -In ReasonLIGO, the predefined functional iterator implementing the map -operation over lists is called `List.map` and is used as follows: +In ReasonLIGO, the predefined functional iterator implementing the +mapped operation over lists is called `List.map` and is used as +follows: ```reasonligo group=lists let increment = (i : int) : int => i + 1; @@ -290,9 +299,9 @@ let plus_one : list (int) = List.map (increment, larger_list); -#### Fold Operation +#### Folded Operation over Lists -A *fold operation* is the most general of iterations. The folded +A *folded operation* is the most general of iterations. The folded function takes two arguments: an *accumulator* and the structure *element* at hand, with which it then produces a new accumulator. This enables having a partial result that becomes complete when the @@ -302,12 +311,12 @@ traversal of the data structure is over. -In PascaLIGO, the predefined functional iterator implementing the fold -operation over lists is called `list_fold` and is used as follows: +In PascaLIGO, the predefined functional iterator implementing the +folded operation over lists is called `list_fold` and is used as +follows: ```pascaligo group=lists function sum (const acc : int; const i : int): int is acc + i - const sum_of_elements : int = list_fold (sum, my_list, 0) ``` @@ -316,7 +325,7 @@ const sum_of_elements : int = list_fold (sum, my_list, 0) -In CameLIGO, the predefined functional iterator implementing the fold +In CameLIGO, the predefined functional iterator implementing the folded operation over lists is called `List.fold` and is used as follows: ```cameligo group=lists @@ -327,7 +336,8 @@ let sum_of_elements : int = List.fold sum my_list 0 In ReasonLIGO, the predefined functional iterator implementing the -fold operation over lists is called `List.fold` and is used as follows: +folded operation over lists is called `List.fold` and is used as +follows: ```reasonligo group=lists let sum = ((result, i): (int, int)): int => result + i; @@ -365,7 +375,7 @@ let my_set : int set = Set.empty -In CameLIGO, the empty set is denoted by the predefined value +In ReasonLIGO, the empty set is denoted by the predefined value `Set.empty`. ```reasonligo group=sets @@ -469,7 +479,7 @@ let contains_3 : bool = Set.mem (3, my_set); -### Cardinal +### Cardinal of Sets @@ -509,7 +519,7 @@ let set_size : nat = Set.size (my_set); In PascaLIGO, there are two ways to update a set, that is to add or remove from it. Either we create a new set from the given one, or we -modify it in-place. First, let us consider the former way +modify it in-place. First, let us consider the former way: ```pascaligo group=sets const larger_set : set (int) = set_add (4, my_set) @@ -568,8 +578,8 @@ to compute some value. Another approach is possible in PascaLIGO: *loops* (see the relevant section). There are three kinds of functional iterations over LIGO maps: the -*iterated operation*, the *map operation* (not to be confused with the -*map data structure*) and the *fold operation*. +*iterated operation*, the *mapped operation* (not to be confused with +the *map data structure*) and the *folded operation*. #### Iterated Operation @@ -631,18 +641,18 @@ let iter_op = (s : set (int)) : unit => { -#### Map Operation +#### Mapped Operation (NOT IMPLEMENTED YET) We may want to change all the elements of a given set by applying to -them a function. This is called a *map operation*, not to be confused -with the map data structure. +them a function. This is called a *mapped operation*, not to be +confused with the map data structure. -In PascaLIGO, the predefined functional iterator implementing the map -operation over sets is called `set_map` and is used as follows: +In PascaLIGO, the predefined functional iterator implementing the +mapped operation over sets is called `set_map` and is used as follows: ```pascaligo skip function increment (const i : int): int is i + 1 @@ -653,8 +663,8 @@ const plus_one : set (int) = set_map (increment, larger_set) -In CameLIGO, the predefined functional iterator implementing the map -operation over sets is called `Set.map` and is used as follows: +In CameLIGO, the predefined functional iterator implementing the +mapped operation over sets is called `Set.map` and is used as follows: ```cameligo skip let increment (i : int) : int = i + 1 @@ -663,11 +673,10 @@ let increment (i : int) : int = i + 1 let plus_one : int set = Set.map increment larger_set ``` - -In ReasonLIGO, the predefined functional iterator implementing the map -operation over sets is called `Set.map` and is used as follows: +In ReasonLIGO, the predefined functional iterator implementing the +mapped operation over sets is called `Set.map` and is used as follows: ```reasonligo skip let increment = (i : int) : int => i + 1; @@ -678,9 +687,9 @@ let plus_one : set (int) = Set.map (increment, larger_set); -#### Fold Operation +#### Folded Operation -A *fold operation* is the most general of iterations. The folded +A *folded operation* is the most general of iterations. The folded function takes two arguments: an *accumulator* and the structure *element* at hand, with which it then produces a new accumulator. This enables having a partial result that becomes complete when the @@ -690,8 +699,9 @@ traversal of the data structure is over. -In PascaLIGO, the predefined functional iterator implementing the fold -operation over sets is called `set_fold` and is used as follows: +In PascaLIGO, the predefined functional iterator implementing the +folded operation over sets is called `set_fold` and is used as +follows: ```pascaligo group=sets function sum (const acc : int; const i : int): int is acc + i diff --git a/gitlab-pages/docs/language-basics/strings.md b/gitlab-pages/docs/language-basics/strings.md index 3ad0d568d..461d0e38d 100644 --- a/gitlab-pages/docs/language-basics/strings.md +++ b/gitlab-pages/docs/language-basics/strings.md @@ -27,7 +27,7 @@ let a : string = "Hello Alice"; Strings can be concatenated using the `^` operator. -```pascaligo +```pascaligo group=a const name : string = "Alice" const greeting : string = "Hello" const full_greeting : string = greeting ^ " " ^ name @@ -35,7 +35,7 @@ const full_greeting : string = greeting ^ " " ^ name Strings can be concatenated using the `^` operator. -```cameligo +```cameligo group=a let name : string = "Alice" let greeting : string = "Hello" let full_greeting : string = greeting ^ " " ^ name @@ -43,7 +43,7 @@ let full_greeting : string = greeting ^ " " ^ name Strings can be concatenated using the `++` operator. -```reasonligo +```reasonligo group=a let name : string = "Alice"; let greeting : string = "Hello"; let full_greeting : string = greeting ++ " " ++ name; @@ -57,17 +57,17 @@ Strings can be sliced using a built-in function: -```pascaligo +```pascaligo group=b const name : string = "Alice" const slice : string = string_slice (0n, 1n, name) ``` -```cameligo +```cameligo group=b let name : string = "Alice" let slice : string = String.slice 0n 1n name ``` -```reasonligo +```reasonligo group=b let name : string = "Alice"; let slice : string = String.slice (0n, 1n, name); ``` @@ -81,18 +81,18 @@ The length of a string can be found using a built-in function: -```pascaligo +```pascaligo group=c const name : string = "Alice" const length : nat = size (name) // length = 5 ``` -```cameligo +```cameligo group=c let name : string = "Alice" let length : nat = String.size name // length = 5 ``` -```reasonligo +```reasonligo group=c let name : string = "Alice"; let length : nat = String.size (name); // length == 5 ``` diff --git a/gitlab-pages/docs/language-basics/tezos-specific.md b/gitlab-pages/docs/language-basics/tezos-specific.md index 2072b499e..e63764b66 100644 --- a/gitlab-pages/docs/language-basics/tezos-specific.md +++ b/gitlab-pages/docs/language-basics/tezos-specific.md @@ -10,16 +10,15 @@ functions. This page will tell you about them. ## Pack and Unpack Michelson provides the `PACK` and `UNPACK` instructions for data -serialization. The instruction `PACK` converts Michelson data -structures into a binary format, and `UNPACK` reverses that -transformation. This functionality can be accessed from within LIGO. +serialization. The former converts Michelson data structures into a +binary format, and the latter reverses that transformation. This +functionality can be accessed from within LIGO. > ⚠️ `PACK` and `UNPACK` are Michelson instructions that are intended > to be used by people that really know what they are doing. There are > several risks and failure cases, such as unpacking a lambda from an -> untrusted source, and most of which are beyond the scope of this -> document. Do not use these functions without doing your homework -> first. +> untrusted source or casting the result to the wrong type. Do not use +> the corresponding LIGO functions without doing your homework first. @@ -27,7 +26,7 @@ transformation. This functionality can be accessed from within LIGO. ```pascaligo group=a function id_string (const p : string) : option (string) is block { const packed : bytes = bytes_pack (p) -} with (bytes_unpack (packed): option (string)) +} with (bytes_unpack (packed) : option (string)) ``` @@ -77,7 +76,7 @@ let check_hash_key (kh1, k2 : key_hash * key) : bool * key_hash = ```reasonligo group=b let check_hash_key = ((kh1, k2) : (key_hash, key)) : (bool, key_hash) => { - let kh2 : key_hash = Crypto.hash_key(k2); + let kh2 : key_hash = Crypto.hash_key (k2); if (kh1 == kh2) { (true, kh2); } else { (false, kh2); } }; ``` @@ -116,9 +115,8 @@ let check_signature (pk, signed, msg : key * signature * bytes) : bool = ```reasonligo group=c let check_signature = - ((pk, signed, msg) : (key, signature, bytes)) : bool => { + ((pk, signed, msg) : (key, signature, bytes)) : bool => Crypto.check (pk, signed, msg); -}; ``` @@ -129,8 +127,8 @@ Often you want to get the address of the contract being executed. You can do it with `self_address`. > ⚠️ Due to limitations in Michelson, `self_address` in a contract is -> only allowed at the entrypoint level, that is, at the -> top-level. Using it in an embedded function will cause an error. +> only allowed at the top-level. Using it in an embedded function will +> cause an error. diff --git a/gitlab-pages/docs/language-basics/types.md b/gitlab-pages/docs/language-basics/types.md index ace3e8794..1ea5eeba0 100644 --- a/gitlab-pages/docs/language-basics/types.md +++ b/gitlab-pages/docs/language-basics/types.md @@ -53,13 +53,12 @@ let dog_breed : breed = "Saluki"; ```pascaligo group=b -// The type accountBalances denotes maps from addresses to tez +// The type account_balances denotes maps from addresses to tez type account_balances is map (address, tez) const ledger : account_balances = map [("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> 10mutez] - ``` diff --git a/gitlab-pages/docs/language-basics/variables-and-constants.md b/gitlab-pages/docs/language-basics/variables-and-constants.md index 5c3c4ede2..3fe31ff18 100644 --- a/gitlab-pages/docs/language-basics/variables-and-constants.md +++ b/gitlab-pages/docs/language-basics/variables-and-constants.md @@ -69,7 +69,8 @@ or as function parameters. function add (const a : int; const b : int) : int is block { - var c : int := a + b + var c : int := a + 2*b; + c := c - b } with c ``` diff --git a/gitlab-pages/website/versioned_docs/version-next/contributors/origin.md b/gitlab-pages/website/versioned_docs/version-next/contributors/origin.md index 089c6ce08..72b6002ac 100644 --- a/gitlab-pages/website/versioned_docs/version-next/contributors/origin.md +++ b/gitlab-pages/website/versioned_docs/version-next/contributors/origin.md @@ -4,14 +4,8 @@ title: Origin original_id: origin --- -LIGO is a programming language that aims to provide developers with an -uncomplicated and safe way to implement smart contracts. Since it is -being implemented for the Tezos blockchain LIGO compiles to Michelson, -the native smart contract language of Tezos. +LIGO is a programming language that aims to provide developers with an uncomplicated and safe way to implement smart contracts. Since it is being implemented for the Tezos blockchain LIGO compiles to Michelson—the native smart contract language of Tezos. > Smart contracts are programs that run within a blockchain network. -LIGO was meant to be a language for developing Marigold on top of a -hacky framework called Meta-Michelson. However, due to the attention -received by the Tezos community, LIGO is now a standalone language -being developed to support Tezos directly. +LIGO was meant to be a language for developing Marigold on top of a hacky framework called Meta-Michelson. However, due to the attention received by the Tezos community, LIGO is now a standalone language being developed to support Tezos directly. \ No newline at end of file diff --git a/gitlab-pages/website/versioned_docs/version-next/contributors/philosophy.md b/gitlab-pages/website/versioned_docs/version-next/contributors/philosophy.md index db959a833..99c4d7c00 100644 --- a/gitlab-pages/website/versioned_docs/version-next/contributors/philosophy.md +++ b/gitlab-pages/website/versioned_docs/version-next/contributors/philosophy.md @@ -4,79 +4,42 @@ title: Philosophy original_id: philosophy --- -To understand LIGO’s design choices it is important to understand its -philosophy. We have two main concerns in mind while building LIGO. +To understand LIGO’s design choices it’s important to understand its philosophy. We have two main concerns in mind while building LIGO. ## Safety - -Once a smart contract is deployed, it will likely be impossible to -change it. You must get it right on the first try, and LIGO should -help as much as possible. There are multiple ways to make LIGO a safer -language for smart contracts. +Once a smart contract is deployed, it will likely be impossible to change it. You must get it right on the first try, and LIGO should help as much as possible. There are multiple ways to make LIGO a safer language for smart contracts. ### Automated Testing +Automated Testing is the process through which a program runs another program, and checks that this other program behaves correctly. -Automated Testing is the process through which a program runs another -program, and checks that this other program behaves correctly. - -There already is a testing library for LIGO programs written in OCaml -that is used to test LIGO itself. Making it accessible to users will -greatly improve safety. A way to do so would be to make it accessible -from within LIGO. +There already is a testing library for LIGO programs written in OCaml that is used to test LIGO itself. Making it accessible to users will greatly improve safety. A way to do so would be to make it accessible from within LIGO. ### Static Analysis - -Static analysis is the process of having a program analyze another -one. For instance, type systems are a kind of static analysis through -which it is possible to find lots of bugs. LIGO already has a simple -type system, and we plan to make it much stronger. +Static analysis is the process of having a program analyze another one. +For instance, type systems are a kind of static analysis through which it is possible to find lots of bugs. LIGO already has a simple type system, and we plan to make it much stronger. ### Conciseness - -Writing less code gives you less room to introduce errors. That is why -LIGO encourages writing lean rather than chunky smart contracts. +Writing less code gives you less room to introduce errors. That's why LIGO encourages writing lean rather than chunky smart contracts. --- ## Ergonomics - -Having an ergonomic product is crucial on multiple levels: Making -features easily accessible ensures they will actually get used. Not -wasting users time on idiosyncrasies frees more time for making -contracts safer or building apps. Keeping users in a Flow state makes -it possible to introduce more complex features in the language. There -are multiple ways to improve ergonomics. +Having an ergonomic product is crucial on multiple levels: +Making features easily accessible ensures they’ll actually get used. +Not wasting users time on idiosyncrasies frees more time for making contracts safer or building apps. +Keeping users in a Flow state makes it possible to introduce more complex features in the language. +There are multiple ways to improve ergonomics. ### The Language +LIGO should contain as few surprises as possible. This is usually known as the principle of least surprise. -LIGO should contain as few surprises as possible. This is usually -known as the principle of least surprise. +Most programmers who will use LIGO have already spent a lot of time learning to develop in an existing language, with its own set of conventions and expectations. These expectations are often the most important to accommodate. This is why C-style syntaxes are especially popular (e.g. JavaScript), C-style is well known and new languages want to take advantage of that familiarity. Therefore as an extension of the principle of least surprise, LIGO supports more than one syntax. The least surprising language for a new developer is the one that they have already learned how to use. It’s probably not practical to replicate the syntax of every programming language, so LIGO takes the approach of replicating the structure used by languages from a particular paradigm. -Most programmers who will use LIGO have already spent a lot of time -learning to develop in an existing language, with its own set of -conventions and expectations. These expectations are often the most -important to accommodate. This is why C-style syntaxes are especially -popular (e.g. JavaScript), C-style is well known and new languages -want to take advantage of that familiarity. Therefore as an extension -of the principle of least surprise, LIGO supports more than one -syntax. The least surprising language for a new developer is the one -that they have already learned how to use. It’s probably not practical -to replicate the syntax of every programming language, so LIGO takes -the approach of replicating the structure used by languages from a -particular paradigm. - -It is packaged in a Docker container, so that no particular -installation instructions are required. +It is packaged in a Docker container, so that no particular installation instructions are required. ### Editor Support +Without editor support, a lot of manipulations are very cumbersome. Checking for errors, testing, examining code, refactoring code, etc. This is why there is ongoing work on editor support, starting with highlighting and code-folding. -Without editor support, a lot of manipulations are very -cumbersome. Checking for errors, testing, examining code, refactoring -code, etc. This is why there is ongoing work on editor support, -starting with highlighting and code-folding. - -### Documentation - -Documentation includes a reference of the languages, tutorials, as -well as examples and design patterns. We are a long way from -there. But having an extensive documentation is part of our goals. +### Docs +Docs include documentation of the languages, tutorials, as well as examples and design patterns. +We’re a long way from there. But having extensive docs is part of our goals. \ No newline at end of file From e8da2626e44db2532124532721841d7f8ba90331 Mon Sep 17 00:00:00 2001 From: John David Pressman Date: Wed, 12 Feb 2020 01:39:41 +0000 Subject: [PATCH 9/9] Add set reference page to the docs Add Set.literal to the test suite --- gitlab-pages/docs/reference/set.md | 201 +++++++++++++++++++++++ src/test/contracts/set_arithmetic.mligo | 3 + src/test/contracts/set_arithmetic.religo | 2 + src/test/integration_tests.ml | 10 ++ src/test/md_file_tests.ml | 1 + 5 files changed, 217 insertions(+) create mode 100644 gitlab-pages/docs/reference/set.md diff --git a/gitlab-pages/docs/reference/set.md b/gitlab-pages/docs/reference/set.md new file mode 100644 index 000000000..a1de140b6 --- /dev/null +++ b/gitlab-pages/docs/reference/set.md @@ -0,0 +1,201 @@ +--- +id: set-reference +title: Set +--- + +## Defining a set + + + +```pascaligo group=a +type int_set is set (int); +const my_set : int_set = set 1; 2; 3 end +``` + + +```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 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)))); +``` + + + + +## Set.mem(is_member: a', s: a' set) : bool + +Check if a set `s` contains the element `is_member`. + + + +```pascaligo group=a +const contains_three : bool = my_set contains 3 +// or alternatively +const contains_three_fn: bool = set_mem (3, my_set); +``` + + +```cameligo group=a +let contains_three: bool = Set.mem 3 my_set +``` + +```reasonligo group=a +let contains_three: bool = Set.mem(3, my_set); +``` + + + + +## Set.empty() : a' set + +Create a new empty set. Needs to be annotated with the set type. + + + +```pascaligo group=a +const my_set: int_set = set end +const my_set_2: int_set = set_empty +``` + +```cameligo group=a +let my_set: int_set = (Set.empty: int set) +``` + +```reasonligo group=a +let my_set: int_set = (Set.empty: set (int)); +``` + + +## Set.literal(element_list_literal: 'a list) : 'a set + +Create a set from the elements of a list. Note that **you must pass a list literal** +to this function, a variable will not work. + + + + +```pascaligo +const s_fb : set(string) = set [ + "foo" ; + "bar" ; +] +``` + + +```cameligo +let literal_op (p: unit) : string set = + Set.literal ["foo"; "bar"; "foobar"] +``` + + +```reasonligo +let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]); +``` + + + +## Set.add(addition: a', s: a' set) : a' set + +Add the element `addition` to a set `s`. + + + +```pascaligo group=a +function add_op (const s : set(string)) : set(string) is + begin skip end with set_add("foobar" , s) +``` + + +```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 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)))); +``` + + + +## Set.remove(removal: a', s: a' set) : a' set + +Remove the element `removal` from a set `s`. + + + +```pascaligo group=a +const smaller_set: int_set = set_remove(3, my_set); +``` + + + +```cameligo group=a +let smaller_set: int_set = Set.remove 3 my_set +``` + + + +```reasonligo group=a +let smaller_set: int_set = Set.remove(3, my_set); +``` + + + + +## Set.fold(folding_function: a' -> a' -> a', s: a' set, initial: a') : a' + +Combine the elements of a set into a single value using a folding function. + + + +```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 group=a +let sum (result, i: int * int) : int = result + i +let sum_of_a_set: int = Set.fold sum my_set 0 +``` + + +```reasonligo group=a +let sum = (result_i: (int, int)): int => result_i[0] + result_i[1]; +let sum_of_a_set: int = Set.fold(sum, my_set, 0); +``` + + +## Set.size(s: a' set) : nat + +Get the number of elements in a set. + + + +```pascaligo group=a +const set_size: nat = size (my_set) +``` + + +```cameligo group=a +let set_size: nat = Set.size my_set +``` + + +```reasonligo group=a +let set_size: nat = Set.size (my_set); +``` + + diff --git a/src/test/contracts/set_arithmetic.mligo b/src/test/contracts/set_arithmetic.mligo index 74fdc170f..2713905b3 100644 --- a/src/test/contracts/set_arithmetic.mligo +++ b/src/test/contracts/set_arithmetic.mligo @@ -1,5 +1,8 @@ (* Test set operations in CameLIGO *) +let literal_op (p: unit) : string set = + Set.literal ["foo"; "bar"; "foobar"] + let add_op (s : string set) : string set = Set.add "foobar" s diff --git a/src/test/contracts/set_arithmetic.religo b/src/test/contracts/set_arithmetic.religo index 4e613500d..5aa634333 100644 --- a/src/test/contracts/set_arithmetic.religo +++ b/src/test/contracts/set_arithmetic.religo @@ -1,5 +1,7 @@ /* Test set operations in ReasonLIGO */ +let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]); + let add_op = (s: set(string)): set(string) => Set.add("foobar", s); let remove_op = (s: set(string)): set(string) => Set.remove("foobar", s); diff --git a/src/test/integration_tests.ml b/src/test/integration_tests.ml index f384db470..415bb354b 100644 --- a/src/test/integration_tests.ml +++ b/src/test/integration_tests.ml @@ -582,6 +582,11 @@ let set_arithmetic () : unit result = let set_arithmetic_mligo () : unit result = let%bind program = mtype_file "./contracts/set_arithmetic.mligo" in let%bind program_1 = type_file "./contracts/set_arithmetic-1.ligo" in + let%bind () = + expect_eq program "literal_op" + (e_unit ()) + (e_set [e_string "foo"; e_string "bar"; e_string "foobar"]) + in let%bind () = expect_eq program "size_op" (e_set [e_string "foo"; e_string "bar"; e_string "foobar"]) @@ -612,6 +617,11 @@ let set_arithmetic_mligo () : unit result = let set_arithmetic_religo () : unit result = let%bind program = retype_file "./contracts/set_arithmetic.religo" in let%bind program_1 = type_file "./contracts/set_arithmetic-1.ligo" in + let%bind () = + expect_eq program "literal_op" + (e_unit ()) + (e_set [e_string "foo"; e_string "bar"; e_string "foobar"]) + in let%bind () = expect_eq program "size_op" (e_set [e_string "foo"; e_string "bar"; e_string "foobar"]) diff --git a/src/test/md_file_tests.ml b/src/test/md_file_tests.ml index 247f396f1..908f6ccd0 100644 --- a/src/test/md_file_tests.ml +++ b/src/test/md_file_tests.ml @@ -122,6 +122,7 @@ let md_files = [ "/gitlab-pages/docs/advanced/timestamps-addresses.md"; "/gitlab-pages/docs/api/cli-commands.md"; "/gitlab-pages/docs/api/cheat-sheet.md"; + "/gitlab-pages/docs/reference/set.md"; "/gitlab-pages/docs/reference/big_map.md"; "/gitlab-pages/docs/reference/string.md"; ]