Merge branch 'rinderknecht@contracts' into 'dev'

First batch of rewritten contracts (PascaLIGO).

See merge request ligolang/ligo!405
This commit is contained in:
Suzanne Dupéron 2020-02-10 19:35:22 +00:00
commit f10cb1616e
56 changed files with 866 additions and 899 deletions

View File

@ -1079,7 +1079,7 @@ let%expect_test _ =
let%expect_test _ = let%expect_test _ =
run_ligo_bad [ "compile-contract" ; contract "bad_timestamp.ligo" ; "main" ] ; run_ligo_bad [ "compile-contract" ; contract "bad_timestamp.ligo" ; "main" ] ;
[%expect {| [%expect {|
ligo: in file "bad_timestamp.ligo", line 5, characters 29-43. Badly formatted timestamp "badtimestamp": {"location":"in file \"bad_timestamp.ligo\", line 5, characters 29-43"} ligo: in file "bad_timestamp.ligo", line 7, characters 30-44. Badly formatted timestamp "badtimestamp": {"location":"in file \"bad_timestamp.ligo\", line 7, characters 30-44"}
If you're not sure how to fix this error, you can If you're not sure how to fix this error, you can

View File

@ -1153,9 +1153,7 @@ module Compiler = struct
| C_BYTES_PACK -> ok @@ simple_unary @@ prim I_PACK | C_BYTES_PACK -> ok @@ simple_unary @@ prim I_PACK
| C_CONCAT -> ok @@ simple_binary @@ prim I_CONCAT | C_CONCAT -> ok @@ simple_binary @@ prim I_CONCAT
| C_CHAIN_ID -> ok @@ simple_constant @@ prim I_CHAIN_ID | C_CHAIN_ID -> ok @@ simple_constant @@ prim I_CHAIN_ID
| _ -> simple_fail @@ Format.asprintf "operator not implemented for %a" PP.constant c | _ -> simple_fail @@ Format.asprintf "operator not implemented for %a" Stage_common.PP.constant c
(* (*
Some complex operators will need to be added in compiler/compiler_program. Some complex operators will need to be added in compiler/compiler_program.

View File

@ -1,20 +1,12 @@
// Test different ways of calling functions in PascaLIGO // Test different ways of calling functions in PascaLIGO
type foo is record type foo is record [bar : int -> int]
bar : int -> int ;
end
function f (const i : int) : int is function f (const i : int) : int is i
begin
skip
end with i
function g (const i : unit) : int -> int is function g (const i : unit) : int -> int is f
begin skip end with f
const r : foo = record const r : foo = record [bar = f]
bar = f ;
end
const x : int = f (42) const x : int = f (42)
const y : int = r.bar (42) const y : int = r.bar (42)

View File

@ -1,22 +1,15 @@
// Test PascaLIGO arithmetic operators // Test PascaLIGO arithmetic operators
function mod_op (const n : int) : nat is function mod_op (const n : int) : nat is n mod 42
begin skip end with n mod 42
function plus_op (const n : int) : int is function plus_op (const n : int) : int is n + 42
begin skip end with n + 42
function minus_op (const n : int) : int is function minus_op (const n : int) : int is n - 42
begin skip end with n - 42
function times_op (const n : int) : int is function times_op (const n : int) : int is n * 42
begin skip end with n * 42
function div_op (const n : int) : int is function div_op (const n : int) : int is n / 2
begin skip end with n / 2
function int_op (const n : nat) : int is function int_op (const n : nat) : int is int (n)
block { skip } with int(n)
function neg_op (const n : int) : int is function neg_op (const n : int) : int is -n
begin skip end with -n

View File

@ -1,4 +1,4 @@
function main (const i : int) : int is function main (const i : int) : int is
begin block {
i := i + 1 ; i := i + 1
end with i } with i

View File

@ -1,19 +1,19 @@
const x : int = 1; attributes ["inline"] const x : int = 1; attributes ["inline"]
function foo (const a : int) : int is function foo (const a : int) : int is
begin block {
const test : int = 2 + a; const test : int = 2 + a;
attributes ["inline"]; attributes ["inline"];
end with test; } with test;
attributes ["inline"]; attributes ["inline"];
const y : int = 1; attributes ["inline"; "other"] const y : int = 1; attributes ["inline"; "other"]
function bar (const b : int) : int is function bar (const b : int) : int is
begin block {
function test (const z : int) : int is function test (const z : int) : int is
begin block {
const r : int = 2 + b + z const r : int = 2 + b + z
end with r; } with r;
attributes ["inline"; "foo"; "bar"] attributes ["inline"; "foo"; "bar"]
end with test(b) } with test (b)

View File

@ -1,7 +1,9 @@
type storage_ is timestamp type parameter is unit
type storage is timestamp
type return is list (operation) * storage
function main(const p : unit; const s : storage_) : list(operation) * storage_ is function main (const p : parameter; const s : storage) : return is
block { block {
var toto : timestamp := ("badtimestamp" : timestamp); var stamp : timestamp := ("badtimestamp" : timestamp)
} }
with ((nil: list(operation)), toto) with ((nil: list(operation)), stamp)

View File

@ -1,4 +1,9 @@
type t is (nat * nat) type parameter is unit
type s is map(t)
function main (const u : unit; const s : s) : (list(operation) * s) is ((nil : list(operation)), s) type binding is nat * nat
type storage is map (binding)
type return is list (operation) * storage
function main (const param : parameter; const store : storage) : return is
((nil : list (operation)), store)

View File

@ -1,11 +1,12 @@
(** (*
This test makes sure that the balance is accessible in PascaLIGO. This test makes sure that the balance is accessible in PascaLIGO.
It's there to detect a regression of: https://gitlab.com/ligolang/ligo/issues/68
It is meant to detect the regression detailled in the following issue: https://gitlab.com/ligolang/ligo/issues/68
*) *)
type parameter is unit
type storage is tez type storage is tez
type return is list (operation) * storage
function main (const p : unit; const s: tez) : list(operation) * storage is function main (const param : parameter; const store: storage) : return is
((nil : list (operation)), balance) ((nil : list (operation)), balance)

View File

@ -1,36 +1,35 @@
type storage_ is big_map(int, int) * unit type parameter is unit
type foo is big_map(int, int) type storage is big_map (int, int) * unit
type return is list (operation) * storage
function main(const p : unit; const s : storage_) : list(operation) * storage_ is function main (const p : parameter; const s : storage) : return is
block { block {
var toto : option (int) := Some (0); var toto : option (int) := Some (0);
toto := s.0[23]; toto := s.0[23];
s.0[2] := 444; s.0[2] := 444
} }
with ((nil: list(operation)), s) with ((nil: list(operation)), s)
type foo is big_map (int, int)
function set_ (var n : int; var m : foo) : foo is block { function set_ (var n : int; var m : foo) : foo is block {
m[23] := n ; m[23] := n
} with m } with m
function rm (var m : foo) : foo is block { function rm (var m : foo) : foo is block {
remove 42 from map m; remove 42 from map m
} with m } with m
function gf (const m : foo) : int is begin skip end with get_force(23, m) function gf (const m : foo) : int is get_force (23, m)
function get (const m : foo) : option(int) is begin skip end with m[42] function get (const m : foo) : option (int) is m[42]
const empty_big_map : big_map(int,int) = big_map end const empty_big_map : big_map (int,int) = big_map []
const big_map1 : big_map(int,int) = big_map const big_map1 : big_map (int,int) = big_map [23 -> 0; 42 -> 0]
23 -> 0 ;
42 -> 0 ;
end
function mutimaps (const m : foo ; const n : foo) : foo is block function mutimaps (const m : foo; const n : foo) : foo is block {
{
var bar : foo := m; var bar : foo := m;
bar[42] := 0; bar[42] := 0;
n[42] := get_force(42, bar) ; n[42] := get_force (42, bar)
} with n } with n

View File

@ -1,16 +1,11 @@
// Test PascaLIGO bitwise operators // Test PascaLIGO bitwise operators
function or_op (const n : nat) : nat is function or_op (const n : nat) : nat is bitwise_or (n, 4n)
bitwise_or(n , 4n)
function and_op (const n : nat) : nat is function and_op (const n : nat) : nat is bitwise_and (n, 7n)
bitwise_and(n , 7n)
function xor_op (const n : nat) : nat is function xor_op (const n : nat) : nat is bitwise_xor (n, 7n)
bitwise_xor(n , 7n)
function lsl_op (const n : nat) : nat is function lsl_op (const n : nat) : nat is bitwise_lsl (n, 7n)
bitwise_lsl(n , 7n)
function lsr_op (const n : nat) : nat is function lsr_op (const n : nat) : nat is bitwise_lsr (n, 7n)
bitwise_lsr(n , 7n)

View File

@ -1,2 +1 @@
function blockless (const n: int) : int is function blockless (const n : int) : int is n + 10
n + 10;

View File

@ -1,16 +1,11 @@
// Test PascaLIGO boolean operators // Test PascaLIGO boolean operators
function or_true (const b : bool) : bool is function or_true (const b : bool) : bool is b or True
begin skip end with b or True
function or_false (const b : bool) : bool is function or_false (const b : bool) : bool is b or False
begin skip end with b or False
function and_true (const b : bool) : bool is function and_true (const b : bool) : bool is b and True
begin skip end with b and True
function and_false (const b : bool) : bool is function and_false (const b : bool) : bool is b and False
begin skip end with b and False
function not_bool (const b: bool) : bool is function not_bool (const b : bool) : bool is not b
begin skip end with not b

View File

@ -1,8 +1,5 @@
function concat_op (const s : bytes) : bytes is function concat_op (const s : bytes) : bytes is bytes_concat (s, 0x7070)
begin skip end with bytes_concat(s , 0x7070)
function slice_op (const s : bytes) : bytes is function slice_op (const s : bytes) : bytes is bytes_slice (1n, 2n, s)
begin skip end with bytes_slice(1n , 2n , s)
function hasherman (const s : bytes) : bytes is function hasherman (const s : bytes) : bytes is sha_256 (s)
begin skip end with sha_256(s)

View File

@ -1,11 +1,11 @@
function id_string (const p : string) : option (string) is block { function id_string (const p : string) : option (string) is block {
const packed : bytes = bytes_pack(p) ; const packed : bytes = bytes_pack (p)
} with (bytes_unpack (packed) : option (string)) } with (bytes_unpack (packed) : option (string))
function id_int (const p : int) : option (int) is block { function id_int (const p : int) : option (int) is block {
const packed : bytes = bytes_pack(p) ; const packed : bytes = bytes_pack (p)
} with (bytes_unpack (packed) : option (int)) } with (bytes_unpack (packed) : option (int))
function id_address (const p : address) : option (address) is block { function id_address (const p : address) : option (address) is block {
const packed : bytes = bytes_pack(p) ; const packed : bytes = bytes_pack (p)
} with (bytes_unpack (packed) : option (address)) } with (bytes_unpack (packed) : option (address))

View File

@ -1,5 +1 @@
function chain_id (const tt : chain_id) : chain_id is get_chain_id
function chain_id (const tt : chain_id) : chain_id is
block {
var toto : chain_id := get_chain_id ;
} with ( toto )

View File

@ -1,2 +1,4 @@
function check_signature (const pk: key; const signed: signature; const msg: bytes) : bool is function check_signature (const pk : key;
crypto_check(pk, signed, msg) const signed : signature;
const msg: bytes) : bool
is crypto_check (pk, signed, msg)

View File

@ -1,5 +1,4 @@
function foo (const i : int) : int is function foo (const i : int) : int is
block { block {
function bar (const j : int) : int is function add (const j : int) : int is i+j
i + j ; } with add (i)
} with bar (i)

View File

@ -1,6 +1,5 @@
function foobar (const i : int) : int is function foobar (const i : int) : int is
block { block {
const j : int = 3; const j : int = 3;
function toto(const k : int) : int is function add (const k : int) : int is i+j+k
i + j + k ; } with add (42)
} with toto(42)

View File

@ -1,12 +1,10 @@
// This might seem like it's covered by induction with closure-2.ligo // This might seem like it is covered by induction with closure-2.ligo,
// But it exists to prevent a regression on the bug patched by: // but it exists to prevent a regression on the bug patched by:
// https://gitlab.com/ligolang/ligo/commit/faf3bbc06106de98189f1c1673bd57e78351dc7e // https://gitlab.com/ligolang/ligo/commit/faf3bbc06106de98189f1c1673bd57e78351dc7e
function foobar (const i : int) : int is function foobar (const i : int) : int is
block { block {
const j : int = 3; const j : int = 3;
const k : int = 4; const k : int = 4;
function toto(const l : int) : int is function add (const l : int) : int is i+j+k+l
i + j + k + l; } with add (42)
} with toto(42)

View File

@ -1,7 +1,5 @@
function toto (const i : int) : int is function toto (const i : int) : int is
block { block {
function tata (const j : int) : int is function tata (const j : int) : int is i+j;
i + j ; function titi (const j : int) : int is i+j
function titi (const j : int) : int is
i + j ;
} with tata (i) + titi (i) } with tata (i) + titi (i)

View File

@ -1,58 +1,71 @@
// Copyright Coase, Inc 2019 // Copyright Coase, Inc 2019
type card_pattern_id is nat type card_pattern_id is nat
type card_pattern is record [ type card_pattern is record [
coefficient : tez; coefficient : tez;
quantity : nat ; quantity : nat
] ]
type card_patterns is map (card_pattern_id, card_pattern) type card_patterns is map (card_pattern_id, card_pattern)
type card_id is nat type card_id is nat
type card is record [ type card is record [
card_owner : address; card_owner : address;
card_pattern : card_pattern_id ; card_pattern : card_pattern_id
] ]
type cards is map (card_id, card) type cards is map (card_id, card)
type storage_type is record [ type storage is record [
cards : cards; cards : cards;
card_patterns : card_patterns; card_patterns : card_patterns;
next_id : nat ; next_id : nat
] ]
type return is list (operation) * storage
type action_buy_single is record [ type action_buy_single is record [
card_to_buy : card_pattern_id ; card_to_buy : card_pattern_id
]
type action_sell_single is record [
card_to_sell : card_id ;
]
type action_transfer_single is record [
card_to_transfer : card_id ;
destination : address ;
] ]
type action is type action_sell_single is record [
| Buy_single of action_buy_single card_to_sell : card_id
]
type action_transfer_single is record [
card_to_transfer : card_id;
destination : address
]
type parameter is
Buy_single of action_buy_single
| Sell_single of action_sell_single | Sell_single of action_sell_single
| Transfer_single of action_transfer_single | Transfer_single of action_transfer_single
function transfer_single(const action : action_transfer_single ; const s : storage_type) : (list(operation) * storage_type) is function transfer_single (const action : action_transfer_single;
begin const s : storage) : return is block {
const cards : cards = s.cards; const cards : cards = s.cards;
const card : card = get_force (action.card_to_transfer, cards); const card : card = get_force (action.card_to_transfer, cards);
if (card.card_owner =/= source) then failwith ("This card doesn't belong to you") else skip ; if card.card_owner =/= source then
failwith ("This card doesn't belong to you")
else skip;
card.card_owner := action.destination; card.card_owner := action.destination;
cards[action.card_to_transfer] := card; cards[action.card_to_transfer] := card;
s.cards := cards; s.cards := cards;
const operations : list(operation) = nil ; const operations : list (operation) = nil
end with (operations , s) ; } with (operations, s)
function sell_single(const action : action_sell_single ; const s : storage_type) : (list(operation) * storage_type) is function sell_single (const action : action_sell_single;
begin const s : storage) : return is
block {
const card : card = get_force (action.card_to_sell, s.cards); const card : card = get_force (action.card_to_sell, s.cards);
if (card.card_owner =/= source) then failwith ("This card doesn't belong to you") else skip ; if card.card_owner =/= source
const card_pattern : card_pattern = get_force(card.card_pattern , s.card_patterns) ; then failwith ("This card doesn't belong to you")
else skip;
const card_pattern : card_pattern =
get_force (card.card_pattern, s.card_patterns);
card_pattern.quantity := abs (card_pattern.quantity - 1n); card_pattern.quantity := abs (card_pattern.quantity - 1n);
const card_patterns : card_patterns = s.card_patterns; const card_patterns : card_patterns = s.card_patterns;
card_patterns[card.card_pattern] := card_pattern; card_patterns[card.card_pattern] := card_pattern;
@ -63,15 +76,18 @@ function sell_single(const action : action_sell_single ; const s : storage_type)
const price : tez = card_pattern.coefficient * card_pattern.quantity; const price : tez = card_pattern.coefficient * card_pattern.quantity;
const receiver : contract (unit) = get_contract (source); const receiver : contract (unit) = get_contract (source);
const op : operation = transaction (unit, price, receiver); const op : operation = transaction (unit, price, receiver);
const operations : list(operation) = list op end ; const operations : list (operation) = list [op]
end with (operations , s) } with (operations, s)
function buy_single(const action : action_buy_single ; const s : storage_type) : (list(operation) * storage_type) is function buy_single (const action : action_buy_single;
begin const s : storage) : return is
block {
// Check funds // Check funds
const card_pattern : card_pattern = get_force(action.card_to_buy , s.card_patterns) ; const card_pattern : card_pattern =
const price : tez = card_pattern.coefficient * (card_pattern.quantity + 1n) ; get_force (action.card_to_buy, s.card_patterns);
if (price > amount) then failwith ("Not enough money") else skip ; const price : tez =
card_pattern.coefficient * (card_pattern.quantity + 1n);
if price > amount then failwith ("Not enough money") else skip;
// Administrative procedure // Administrative procedure
const operations : list(operation) = nil; const operations : list(operation) = nil;
// Increase quantity // Increase quantity
@ -81,18 +97,17 @@ function buy_single(const action : action_buy_single ; const s : storage_type) :
s.card_patterns := card_patterns; s.card_patterns := card_patterns;
// Add card // Add card
const cards : cards = s.cards; const cards : cards = s.cards;
cards[s.next_id] := record cards[s.next_id] := record [
card_owner = source; card_owner = source;
card_pattern = action.card_to_buy ; card_pattern = action.card_to_buy
end ; ];
s.cards := cards; s.cards := cards;
s.next_id := s.next_id + 1n ; s.next_id := s.next_id + 1n
end with (operations , s) } with (operations, s)
function main(const action : action ; const s : storage_type) : (list(operation) * storage_type) is function main (const action : parameter; const s : storage) : return is
block {skip} with
case action of case action of
| Buy_single (bs) -> buy_single (bs , s) Buy_single (bs) -> buy_single (bs, s)
| Sell_single (as) -> sell_single (as, s) | Sell_single (as) -> sell_single (as, s)
| Transfer_single (at) -> transfer_single (at, s) | Transfer_single (at) -> transfer_single (at, s)
end end

View File

@ -1,10 +1 @@
// Test if conditional with trivial conditions in PascaLIGO function main (const i : int) : int is if 1 = 1 then 42 else 0
function main (const i : int) : int is
begin
if 1 = 1 then
i := 42
else
i := 0
end with i

View File

@ -1,16 +1,10 @@
// Test if conditional in PascaLIGO
function main (const i : int) : int is function main (const i : int) : int is
begin block {
var result : int := 23; var result : int := 23;
if i = 2 then if i = 2 then result := 42 else result := 0
result := 42 } with result
else
result := 0
end with result
function foo (const b : bool) : int is function foo (const b : bool) : int is
begin block {
var x : int := 41 ; const x : int = 41
x := 1 + (if b then x else main(x)) ; } with 1 + (if b then x else main (x))
end with x

View File

@ -1,6 +1,7 @@
type some_type is int type t is int
function main (const p : int ; const s : some_type) : (list(operation) * int) is function main (const p : int ; const s : t) : list (operation) * int is
block { skip } // skip is a do nothing instruction, needed for empty blocks block {
skip
} // skip is a do nothing instruction, needed for empty blocks
with ((nil : list(operation)), p + s) with ((nil : list(operation)), p + s)

View File

@ -1,5 +1,5 @@
// Test PasaLIGO variable declarations inside of a block // Test PasaLIGO variable declarations inside of a block
function main (const i : int) : int is block { function main (const i : int) : int is block {
const j : int = 42 ; const j : int = 42
} with j } with j

View File

@ -1,8 +1,5 @@
// Test PascaLIGO top level declarations // Test PascaLIGO top-level declarations
const foo : int = 42 const foo : int = 42
function main (const i : int) : int is function main (const i : int) : int is i + foo
begin
skip
end with i + foo

View File

@ -1,31 +1,29 @@
//Test deep_access in PascalLigo // Test deep access
type pii is (int*int)
type ppi is record x:pii; y:pii end
type ppp is (ppi*ppi)
function main (const toto : unit) : int is block { type pii is int * int
var a : ppp := (
record type ppi is record [x : pii; y : pii]
x = (0,1);
y = (10,11); type ppp is ppi * ppi
end ,
record function main (const toto : unit) : int is
x = (100,101); block {
y = (110,111); var a : ppp :=
end (record [x = (0,1); y = (10,11)],
) ; record [x = (100,101); y = (110,111)]);
a.0.x.0 := 2; a.0.x.0 := 2;
const b:int = a.0.x.0; } with a.0.x.0
} with b
function asymetric_tuple_access(const foo : unit) : int is block { function asymetric_tuple_access (const foo : unit) : int is
var mytuple : int * (int * (int * int)) := (0,(1,(2,3))) ; block {
} with mytuple.0 + mytuple.1.0 + mytuple.1.1.0 + mytuple.1.1.1 var tuple : int * (int * (int * int)) := (0,(1,(2,3)))
} with tuple.0 + tuple.1.0 + tuple.1.1.0 + tuple.1.1.1
type nested_record_t is record type nested_record_t is
nesty : (record mymap : map(int,string) ; end) ; record [nesty : record [mymap : map (int,string)]]
end
function nested_record (var nee : nested_record_t) : string is block { function nested_record (var nee : nested_record_t) : string is
nee.nesty.mymap[1] := "one" ; block {
} with ( get_force(1, nee.nesty.mymap) ) nee.nesty.mymap[1] := "one"
} with get_force (1, nee.nesty.mymap)

View File

@ -1,16 +1,19 @@
type action is type parameter is
| Increment of int Increment of int
| Decrement of int | Decrement of int
function increment(const i : int ; const n : int) : int is type storage is int
block { skip } with (i + n)
function decrement(const i : int ; const n : int) : int is type return is list (operation) * storage
block { skip } with (i - n)
function main (const p : action ; const s : int) : (list(operation) * int) is function increment (const i : int; const n : int) : int is i+n
block {skip} with ((nil : list(operation)),
case p of function decrement (const i : int; const n : int) : int is i-n
| Increment (n) -> increment (s, n)
| Decrement (n) -> decrement (s, n) const nop : list (operation) = nil
end)
function main (const action : parameter; const store : storage) : return is
case action of
Increment (n) -> (nop, increment (store, n))
| Decrement (n) -> (nop, decrement (store, n))
end

View File

@ -1,8 +1,11 @@
function main(const p : unit; const s : int) : list(operation) * int is type parameter is unit
((list end : list(operation)), s + 1) type storage is int
type return is list (operation) * storage
function main(const p : unit; const s : int) : list(operation) * int is function main(const p : parameter; const s : storage) : return is
begin ((nil : list(operation)), s+1)
const ret : list(operation) * int = main(p, s)
end function main (const p : parameter; const s : storage) : return is
with (ret.0, ret.1 + 1) block {
const ret : return = main (p, s)
} with (ret.0, ret.1 + 1)

View File

@ -1,9 +1,9 @@
type foo is type t is
| Bar of int Bar of int
| Baz | Baz
function main (const f: foo) : int is function main (const x : t) : int is
(case f of case x of
| Bar (n) -> n Bar (n) -> n
| Baz -> -1 | Baz -> -1
end) end

View File

@ -1,16 +1,19 @@
function cb(const a : address; const s : unit) : list(operation) * unit is type storage is unit
type return is list (operation) * storage
function cb (const a : address; const s : storage) : return is
block { block {
const c : contract (unit) = get_entrypoint ("%cb", a) const c : contract (unit) = get_entrypoint ("%cb", a)
} }
with (list transaction(unit, 0mutez, c) end, s) with (list [transaction (unit, 0mutez, c)], s)
function cbo(const a : address; const s : unit) : list(operation) * unit is function cbo (const a : address; const s : storage) : return is
block { block {
const c : contract (unit) = const c : contract (unit) =
case (get_entrypoint_opt ("%cbo", a) : option (contract (unit))) of case (get_entrypoint_opt ("%cbo", a) : option (contract (unit))) of
| Some (c) -> c Some (c) -> c
| None -> (failwith ("entrypoint not found") : contract (unit)) | None -> (failwith ("entrypoint not found") : contract (unit))
end end
} } with (list [transaction(unit, 0mutez, c)], s)
with (list transaction(unit, 0mutez, c) end, s)

View File

@ -1,11 +1,5 @@
type myrec is record type t is record [foo : nat; bar : string]
foo : nat;
bar : string;
end;
const a : myrec = record const a : t = record [foo = 0n; bar = "bar"]
foo = 0n;
bar = "bar";
end;
const b : int = 2 ; const b : int = 2

View File

@ -1,11 +1,15 @@
type param is type parameter is
| Zero of nat Zero of nat
| Pos of nat | Pos of nat
function main (const p : param; const s : unit) : list(operation) * unit is type storage is unit
type return is list (operation) * storage
function main (const p : parameter; const s : storage) : return is
block { block {
case p of case p of
| Zero (n) -> if n > 0n then failwith("fail") else skip Zero (n) -> if n > 0n then failwith ("fail") else skip
| Pos (n) -> if n > 0n then skip else failwith ("fail") | Pos (n) -> if n > 0n then skip else failwith ("fail")
end end
} }
@ -13,25 +17,27 @@ function main (const p : param; const s : unit) : list(operation) * unit is
function foobar (const i : int) : int is function foobar (const i : int) : int is
block { block {
var p : param := Zero (42n) ; var p : parameter := Zero (42n);
if i > 0 then block { if i > 0 then {
i := i + 1; i := i + 1;
if i > 10 then block { if i > 10 then {
i := 20; i := 20;
failwith ("who knows"); failwith ("who knows");
i := 30 ; i := 30 // Should be no-op
} else skip }
} else block { else skip
}
else
case p of case p of
| Zero (n) -> failwith ("wooo") Zero (n) -> failwith ("wooo")
| Pos (n) -> skip | Pos (n) -> skip
end end
} } with
} with case p of case p of
| Zero (n) -> i Zero (n) -> i
| Pos (n) -> (failwith ("waaaa") : int) | Pos (n) -> (failwith ("waaaa") : int)
end end
function failer (const p : int) : int is block { function failer (const p : int) : int is block {
if p = 1 then failwith("some_string") else skip ; if p = 1 then failwith ("some_string") else skip
} with p } with p

View File

@ -1,11 +1,2 @@
// This was meant to test the for loop in PascaLIGO
// But for whatever reason, the LIGO compiler currently thinks this is a 'complex loop'
// even though it isn't.
// See this error:
// $ ligo dry-run for.ligo main 0 0
// bounded iterators: only simple for loops are supported yet
// {"loop_loc":"in file \"for.ligo\", line 4, characters 10-42"}
function main (const a: int) : int is function main (const a: int) : int is
block { for i := 0 to 100 block { skip } } with i; block { for i := 0 to 100 block { skip } } with i

View File

@ -1,9 +1,9 @@
// Test a PascaLIGO function with more complex logic than function.ligo // Test a PascaLIGO function with more complex logic than function.ligo
function main (const i : int) : int is function main (const i : int) : int is
begin block {
var j : int := 0; var j : int := 0;
var k : int := 1; var k : int := 1;
j := k + i; j := k + i;
k := i + j ; k := i + j
end with (k + j) } with k + j

View File

@ -1,10 +1,7 @@
// Test a PascaLIGO function which uses other functions as subroutines // Test a PascaLIGO function which uses other functions as subroutines
function inc ( const i : int ) : int is function inc (const i : int) : int is i+1
block { skip } with i + 1
function double_inc ( const i : int ) : int is function double_inc (const i : int) : int is inc (i+1)
block { skip } with inc(i + 1)
function foo ( const i : int ) : int is function foo (const i : int) : int is inc (i) + double_inc (i)
block { skip } with inc(i) + double_inc(i)

View File

@ -1,6 +1,3 @@
// Test a trivial PascaLIGO function // Test a trivial PascaLIGO function
function main (const i : int) : int is function main (const i : int) : int is i
begin
skip
end with i

View File

@ -1,16 +1,19 @@
function cb(const s : unit) : list(operation) * unit is type storage is unit
type return is list (operation) * storage
function cb (const s : storage) : return is
block { block {
const c : contract (unit) = get_contract (source) const c : contract (unit) = get_contract (source)
} }
with (list transaction(unit, 0mutez, c) end, s) with (list [transaction(unit, 0mutez, c)], s)
function cbo(const s : unit) : list(operation) * unit is function cbo (const s : unit) : return is
block { block {
const c : contract (unit) = const c : contract (unit) =
case (get_contract_opt (source) : option (contract (unit))) of case (get_contract_opt (source) : option (contract (unit))) of
| Some (c) -> c Some (c) -> c
| None -> (failwith ("contract not found") : contract (unit)) | None -> (failwith ("contract not found") : contract (unit))
end end
} }
with (list transaction(unit, 0mutez, c) end, s) with (list [transaction(unit, 0mutez, c)], s)

View File

@ -1,6 +1,6 @@
type heap_element is int * string type heap_elt is int * string
function heap_element_lt(const x : heap_element ; const y : heap_element) : bool is function heap_elt_lt (const x : heap_elt;
block { skip } with x.0 < y.0 const y : heap_elt) : bool is x.0 < y.0
#include "heap.ligo" #include "heap.ligo"

View File

@ -1,66 +1,66 @@
// Implementation of the heap data structure in PascaLIGO // Implementation of the heap data structure in PascaLIGO
// See: https://en.wikipedia.org/wiki/Heap_%28data_structure%29 // See: https://en.wikipedia.org/wiki/Heap_%28data_structure%29
type heap is map(nat, heap_element) ; type heap is map (nat, heap_elt)
function is_empty (const h : heap) : bool is function is_empty (const h : heap) : bool is size (h) = 0n
block {skip} with size(h) = 0n
function get_top (const h : heap) : heap_element is function get_top (const h : heap) : heap_elt is get_force (1n, h)
block {skip} with get_force(1n, h)
function pop_switch (const h : heap) : heap is function pop_switch (const h : heap) : heap is
block { block {
const result : heap_element = get_top (h) ; const result : heap_elt = get_top (h);
const s : nat = size (h); const s : nat = size (h);
const last : heap_element = get_force(s, h) ; const last : heap_elt = get_force (s, h);
remove 1n from map h; remove 1n from map h;
h[1n] := last ; h[1n] := last
} with h } with h
function pop_ (const h : heap) : nat is function pop_ (const h : heap) : nat is
begin block {
const result : heap_element = get_top (h) ; const result : heap_elt = get_top (h);
const s : nat = size (h); const s : nat = size (h);
var current : heap_element := get_force(s, h) ; var current : heap_elt := get_force (s, h);
const i : nat = 1n; const i : nat = 1n;
const left : nat = 2n * i; const left : nat = 2n * i;
const right : nat = left + 1n; const right : nat = left + 1n;
remove 1n from map h; remove 1n from map h;
h[1n] := current; h[1n] := current;
var largest : nat := i; var largest : nat := i;
if (left <= s and heap_element_lt(get_force(s , h) , get_force(left , h))) then const tmp : heap_elt = get_force (s, h);
largest := left if left <= s and heap_elt_lt (tmp, get_force (left,h))
else if (right <= s and heap_element_lt(get_force(s , h) , get_force(right , h))) then then largest := left
largest := right else
if right <= s and heap_elt_lt (tmp, get_force (right,h))
then largest := right
else skip else skip
end with largest } with largest
function insert (const h : heap ; const e : heap_element) : heap is function insert (const h : heap ; const e : heap_elt) : heap is
begin block {
var i : nat := size (h) + 1n; var i : nat := size (h) + 1n;
h[i] := e; h[i] := e;
var largest : nat := i; var largest : nat := i;
var parent : nat := 0n; var parent : nat := 0n;
while (largest =/= i) block { while largest =/= i block {
parent := i/2n; parent := i/2n;
largest := i; largest := i;
if (parent >= 1n) then block { if parent >= 1n then {
if (heap_element_lt(get_force(parent , h) , get_force(i , h))) then block { if heap_elt_lt (get_force (parent,h), get_force(i,h))) then {
largest := parent; largest := parent;
const tmp : heap_element = get_force(i , h) ; const tmp : heap_elt = get_force (i,h);
h[i] := get_force(parent, h); h[i] := get_force(parent, h);
h[parent] := tmp ; h[parent] := tmp
} else skip } else skip
} else skip } else skip
} }
end with h } with h
function pop (const h : heap) : (heap * heap_element * nat) is function pop (const h : heap) : heap * heap_elt * nat is
begin block {
const result : heap_element = get_top (h) ; const result : heap_elt = get_top (h);
var s : nat := size (h); var s : nat := size (h);
const last : heap_element = get_force(s, h) ; const last : heap_elt = get_force (s,h);
remove s from map h; remove s from map h;
h[1n] := last; h[1n] := last;
s := size (h); s := size (h);
@ -69,25 +69,27 @@ function pop (const h : heap) : (heap * heap_element * nat) is
var left : nat := 0n; var left : nat := 0n;
var right : nat := 0n; var right : nat := 0n;
var c : nat := 0n; var c : nat := 0n;
while (largest =/= i) block { while largest =/= i block {
c := c + 1n; c := c + 1n;
i := largest; i := largest;
left := 2n * i; left := 2n * i;
right := left + 1n; right := left + 1n;
if (left <= s) then begin if left <= s then {
if (heap_element_lt(get_force(left , h) , get_force(i , h))) then begin if heap_elt_lt (get_force (left,h), get_force(i,h)) then {
largest := left; largest := left;
const tmp : heap_element = get_force(i , h) ; const tmp : heap_elt = get_force(i,h);
h[i] := get_force (left, h); h[i] := get_force (left, h);
h[left] := tmp ; h[left] := tmp
end else skip ; } else skip
end else if (right <= s) then begin
if (heap_element_lt(get_force(right , h) , get_force(i , h))) then begin
largest := right ;
const tmp : heap_element = get_force(i , h) ;
h[i] := get_force(right , h) ;
h[left] := tmp ;
end else skip ;
end else skip ;
} }
end with (h , result , c) else
if right <= s then {
if heap_elt_lt (get_force (right, h), get_force (i,h)) then {
largest := right;
const tmp : heap_elt = get_force (i,h);
h[i] := get_force (right, h);
h[left] := tmp
} else skip
} else skip
}
} with (h, result, c)

View File

@ -1,27 +1,27 @@
// Test a PascaLIGO function which takes another PascaLIGO function as an argument (* Test a PascaLIGO function which takes another function as an
argument *)
function foobar (const i : int) : int is function foobar (const i : int) : int is
begin block {
function foo (const i : int) : int is i; function foo (const i : int) : int is i;
function bar (const f : int -> int) : int is f (i); function bar (const f : int -> int) : int is f (i);
end with bar (foo); } with bar (foo)
// higher order function with more than one argument // higher order function with more than one argument
function higher2(const i : int; const f : int -> int): int is
begin function higher2 (const i : int; const f : int -> int): int is f (i)
const ii: int = f (i)
end with ii
function foobar2 (const i : int) : int is function foobar2 (const i : int) : int is
begin block {
function foo2 (const i : int) : int is i function foo2 (const i : int) : int is i
end with higher2 (i,foo2) } with higher2 (i, foo2)
const a : int = 0; const a : int = 0
function foobar3 (const i : int) : int is function foobar3 (const i : int) : int is
begin block {
function foo2 (const i : int) : int is a+i function foo2 (const i : int) : int is a+i
end with higher2 (i,foo2) } with higher2 (i, foo2)
function f (const i : int) : int is i function f (const i : int) : int is i
@ -29,17 +29,15 @@ function g (const i : int) : int is f (i)
function foobar4 (const i : int) : int is g (g (i)) function foobar4 (const i : int) : int is g (g (i))
function higher3(const i : int; const f : int -> int; const g : int -> int) function higher3 (const i : int;
: int is const f : int -> int;
begin const g : int -> int) : int is f (g (i))
const ii : int = f(g(i))
end with ii
function foobar5 (const i : int) : int is function foobar5 (const i : int) : int is
begin block {
const a : int = 0; const a : int = 0;
function foo (const i : int) : int is a+i; function foo (const i : int) : int is a+i;
function goo (const i : int) : int is foo (i) function goo (const i : int) : int is foo (i)
end with higher3(i,foo,goo) } with higher3 (i, foo, goo)
function foobar6 (const i : int) : int -> int is f function foobar6 (const i : int) : int -> int is f

View File

@ -1,2 +1 @@
function main (const i: int) : option(nat) is function main (const i : int) : option (nat) is is_nat (i)
block {skip} with is_nat(i)

View File

@ -1,5 +1,7 @@
function check_hash_key (const kh1 : key_hash; const k2 : key) : bool*key_hash is block { function check_hash_key (const kh1 : key_hash;
const k2 : key) : bool * key_hash is
block {
var ret : bool := False; var ret : bool := False;
var kh2 : key_hash := crypto_hash_key (k2); var kh2 : key_hash := crypto_hash_key (k2);
if kh1 = kh2 then ret := True else skip; if kh1 = kh2 then ret := True else skip
} with (ret, kh2) } with (ret, kh2)

View File

@ -1,7 +1,3 @@
function f (const x : unit) : unit is function f (const x : unit) : unit is Unit
begin skip end with unit
function main (const p : unit ; const s : unit) : unit is function main (const p : unit ; const s : unit) : unit is f (Unit)
begin
var y : unit := f(unit) ;
end with y

View File

@ -2,48 +2,32 @@
type foobar is list (int) type foobar is list (int)
const fb : foobar = list const fb : foobar = list [23; 42]
23 ;
42 ;
end
const fb2 : foobar = 144 # fb const fb2 : foobar = 144 # fb
const fb3 : foobar = cons (688, fb2) const fb3 : foobar = cons (688, fb2)
function size_ (const m : foobar) : nat is function size_ (const m : foobar) : nat is size (m)
block {skip} with (size(m))
// function hdf (const m : foobar) : int is begin skip end with hd(m) // function hdf (const m : foobar) : int is hd (m)
const bl : foobar = list const bl : foobar = list [144; 51; 42; 120; 421]
144 ;
51 ;
42 ;
120 ;
421 ;
end
function fold_op (const s : list (int)) : int is function fold_op (const s : list (int)) : int is
begin block {
function aggregate (const prec: int; const cur: int) : int is function aggregate (const prec: int; const cur: int) : int is prec+cur
begin } with list_fold (aggregate, s, 10)
skip
end with prec + cur
end with list_fold(aggregate, s, 10)
function iter_op (const s : list (int)) : int is function iter_op (const s : list (int)) : int is
begin block {
var r : int := 0; var r : int := 0;
function aggregate (const i : int) : unit is function aggregate (const i : int) : unit is
begin block { r := r + i } with unit;
r := r + i ; list_iter (aggregate, s)
end with unit ; } with r
list_iter(aggregate, s) ;
end with r
function map_op (const s : list (int)) : list (int) is function map_op (const s : list (int)) : list (int) is
block { block {
function increment (const i : int) : int is block { skip } with i + 1 function increment (const i : int) : int is i+1
} with list_map (increment, s) } with list_map (increment, s)

View File

@ -1,193 +1,188 @@
// Test while loops in PascaLIGO // Test while loops in PascaLIGO
function counter (var n : nat) : nat is block { function counter (var n : nat) : nat is
block {
var i : nat := 0n; var i : nat := 0n;
while i < n block { while i < n block {
i := i + 1n; i := i + 1n
} }
} with i } with i
function while_sum (var n : nat) : nat is block { function while_sum (var n : nat) : nat is
block {
var i : nat := 0n; var i : nat := 0n;
var r : nat := 0n; var r : nat := 0n;
while i < n block { while i < n block {
i := i + 1n; i := i + 1n;
r := r + i; r := r + i
} }
} with r } with r
function for_sum (var n : nat) : int is block { function for_sum (var n : nat) : int is
block {
var acc : int := 0; var acc : int := 0;
for i := 1 to int (n) for i := 1 to int (n)
begin block {
acc := acc + i; acc := acc + i
end }
} with acc } with acc
function for_collection_list (var nee : unit) : (int * string) is block { function for_collection_list (var nee : unit) : (int * string) is
block {
var acc : int := 0; var acc : int := 0;
var st : string := "to"; var st : string := "to";
var mylist : list(int) := list 1; 1; 1 end; var mylist : list (int) := list [1; 1; 1];
for x in list mylist for x in list mylist
begin block {
acc := acc + x; acc := acc + x;
st := st ^ "to"; st := st ^ "to"
end }
} with (acc, st) } with (acc, st)
function for_collection_set (var nee : unit) : (int * string) is block { function for_collection_set (var nee : unit) : int * string is
block {
var acc : int := 0; var acc : int := 0;
var st : string := "to"; var st : string := "to";
var myset : set(int) := set 1; 2; 3 end; var myset : set (int) := set [1; 2; 3];
for x in set myset for x in set myset block {
begin
acc := acc + x; acc := acc + x;
st := st^"to" ; st := st ^ "to"
end }
} with (acc, st) } with (acc, st)
function for_collection_if_and_local_var (var nee : unit) : int is block { function for_collection_if_and_local_var (var nee : unit) : int is
block {
var acc : int := 0; var acc : int := 0;
const theone : int = 1; const theone : int = 1;
var myset : set(int) := set 1 ; 2 ; 3 end ; var myset : set (int) := set [1; 2; 3];
for x in set myset for x in set myset block {
begin
const thetwo : int = 2; const thetwo : int = 2;
if x=theone then if x = theone then acc := acc + x
acc := acc + x else if x = thetwo then acc := acc + thetwo
else if x=thetwo then else acc := acc + 10
acc := acc + thetwo; }
else
acc := acc + 10;
end
} with acc } with acc
function for_collection_rhs_capture (var nee : unit) : int is block { function for_collection_rhs_capture (var nee : unit) : int is
block {
var acc : int := 0; var acc : int := 0;
const mybigint : int = 1000; const mybigint : int = 1000;
var myset : set(int) := set 1 ; 2 ; 3 end ; var myset : set (int) := set [1; 2; 3];
for x in set myset for x in set myset block {
begin if x = 1 then acc := acc + mybigint
if x=1 then acc := acc + mybigint; else acc := acc + 10
else acc := acc + 10; }
end
} with acc } with acc
function for_collection_proc_call (var nee : unit) : int is block { function for_collection_proc_call (var nee : unit) : int is
block {
var acc : int := 0; var acc : int := 0;
var myset : set(int) := set 1 ; 2 ; 3 end ; var myset : set (int) := set [1; 2; 3];
for x in set myset for x in set myset block {
begin
if x = 1 then if x = 1 then
acc := acc + for_collection_rhs_capture(unit); acc := acc + for_collection_rhs_capture (unit)
else else acc := acc + 10
acc := acc + 10; }
end
} with acc } with acc
function for_collection_comp_with_acc (var nee : unit) : int is block { function for_collection_comp_with_acc (var nee : unit) : int is
block {
var myint : int := 0; var myint : int := 0;
var mylist : list(int) := list 1 ; 10 ; 15 end; var mylist : list (int) := list [1; 10; 15];
for x in list mylist for x in list mylist block {
begin
if x < myint then skip; if x < myint then skip;
else myint := myint + 10 else myint := myint + 10
end }
} with myint } with myint
function for_collection_with_patches (var nee : unit) : map(string,int) is block { function for_collection_with_patches (var nee : unit) : map (string,int) is
block {
var myint : int := 12; var myint : int := 12;
var mylist : list(string) := list "I"; "am"; "foo" end; var mylist : list (string) := list ["I"; "am"; "foo"];
var mymap : map(string,int) := map end; var mymap : map (string,int) := map [];
for x in list mylist for x in list mylist block {
begin patch mymap with map [x -> myint]
patch mymap with map [x -> myint]; }
end
} with mymap } with mymap
function for_collection_empty (var nee : unit) : int is block { function for_collection_empty (var nee : unit) : int is
block {
var acc : int := 0; var acc : int := 0;
var myset : set(int) := set 1; 2; 3 end; var myset : set(int) := set [1; 2; 3];
for x in set myset for x in set myset block {
begin
skip skip
end }
} with acc } with acc
function for_collection_map_kv (var nee : unit) : (int * string) is block { function for_collection_map_kv (var nee : unit) : int * string is
block {
var acc : int := 0; var acc : int := 0;
var st : string := ""; var st : string := "";
var mymap : map(string,int) := map "1" -> 1; "2" -> 2; "3" -> 3 end; var mymap : map (string, int) := map ["1" -> 1; "2" -> 2; "3" -> 3];
for k -> v in map mymap for k -> v in map mymap block {
begin
acc := acc + v; acc := acc + v;
st := st ^ k; st := st ^ k;
end }
} with (acc, st) } with (acc, st)
function for_collection_map_k (var nee : unit) : string is block { function for_collection_map_k (var nee : unit) : string is
block {
var st : string := ""; var st : string := "";
var mymap : map(string,int) := map "1" -> 1 ; "2" -> 2 ; "3" -> 3 end ; var mymap : map (string, int) := map ["1" -> 1; "2" -> 2; "3" -> 3];
for k in map mymap for k in map mymap block {
begin st := st ^ k
st := st ^ k; }
end
} with st } with st
function nested_for_collection (var nee : unit) : (int*string) is block { function nested_for_collection (var nee : unit) : int * string is
block {
var myint : int := 0; var myint : int := 0;
var mystoo : string := ""; var mystoo : string := "";
var mylist : list(int) := list 1 ; 2 ; 3 end ; var mylist : list(int) := list [1; 2; 3];
var mymap : map(string,string) := map " one" -> "," ; "two" -> " " end ; var mymap : map (string, string) := map [" one" -> ","; "two" -> " "];
for i in list mylist block {
for i in list mylist
begin
myint := myint + i; myint := myint + i;
var myset : set(string) := set "1" ; "2" ; "3" end ; var myset : set (string) := set ["1"; "2"; "3"];
for st in set myset for st in set myset block {
begin
myint := myint + i; myint := myint + i;
mystoo := mystoo ^ st; mystoo := mystoo ^ st;
for k -> v in map mymap for k -> v in map mymap block {
begin mystoo := mystoo ^ k ^ v
mystoo := mystoo ^ k ^ v ; }
end }
end }
end
} with (myint, mystoo) } with (myint, mystoo)
function nested_for_collection_local_var (var nee : unit) : (int*string) is block { function nested_for_collection_local_var (var nee : unit) : int*string is
block {
var myint : int := 0; var myint : int := 0;
var myst : string := ""; var myst : string := "";
var mylist : list(int) := list 1 ; 2 ; 3 end ; var mylist : list (int) := list [1; 2; 3];
for i in list mylist block {
for i in list mylist
begin
var myst_loc : string := ""; var myst_loc : string := "";
myint := myint + i; myint := myint + i;
var myset : set(string) := set "1" ; "2" ; "3" end ; var myset : set (string) := set ["1"; "2"; "3"];
for st in set myset for st in set myset block {
begin
myint := myint + i; myint := myint + i;
myst_loc := myst_loc ^ st; myst_loc := myst_loc ^ st;
end; };
myst := myst_loc ^ myst ; myst := myst_loc ^ myst
end }
} with (myint, myst) } with (myint, myst)
function dummy (const n : nat) : nat is block { function dummy (const n : nat) : nat is block {
while False block { skip } while False block { skip }
} with n } with n
function inner_capture_in_conditional_block (var nee : unit) : bool*int is block { function inner_capture_in_conditional_block (var nee : unit) : bool * int is
block {
var count : int := 1; var count : int := 1;
var ret : bool := False; var ret : bool := False;
var mylist : list(int) := list 1 ; 2 ; 3 end ; var mylist : list (int) := list [1; 2; 3];
for it1 in list mylist block { for it1 in list mylist block {
for it2 in list mylist block { for it2 in list mylist block {
if count = it2 then ret := not (ret) if count = it2 then ret := not (ret) else skip
else skip;
}; };
count := count + 1; count := count + 1
} }
} with (ret, count) } with (ret, count)

View File

@ -2,22 +2,19 @@
type foobar is map (int, int) type foobar is map (int, int)
const empty_map : foobar = map end const empty_map : foobar = map []
const map1 : foobar = map const map1 : foobar = map [
144 -> 23; 144 -> 23;
51 -> 23; 51 -> 23;
42 -> 23; 42 -> 23;
120 -> 23; 120 -> 23;
421 -> 23 ; 421 -> 23]
end
const map2 : foobar = map const map2 : foobar = map [23 -> 0; 42 -> 0]
23 -> 0 ;
42 -> 0 ;
end
function set_ (var n : int; var m : foobar) : foobar is block { function set_ (var n : int; var m : foobar) : foobar is block {
m[23] := n ; m[23] := n
} with m } with m
@ -30,45 +27,38 @@ function patch_ (var m: foobar) : foobar is block {
} with m } with m
function patch_deep (var m : foobar * nat) : foobar * nat is function patch_deep (var m : foobar * nat) : foobar * nat is
begin patch m.0 with map [1 -> 9]; end with m block { patch m.0 with map [1 -> 9] } with m
function size_ (const m : foobar) : nat is function size_ (const m : foobar) : nat is size (m)
block {skip} with (size(m))
function gf (const m : foobar) : int is begin skip end with get_force(23, m) function gf (const m : foobar) : int is get_force (23, m)
function get (const m : foobar) : option(int) is function get (const m : foobar) : option (int) is m[42]
begin
skip
end with m[42]
function get_ (const m : foobar) : option(int) is function get_ (const m : foobar) : option (int) is map_get (42, m)
begin
skip
end with map_get(42 , m)
function mem (const k: int; const m: foobar) : bool is map_mem (k, m) function mem (const k: int; const m: foobar) : bool is map_mem (k, m)
function iter_op (const m : foobar) : unit is function iter_op (const m : foobar) : unit is
block { block {
function aggregate (const i : int; const j : int) : unit is block function aggregate (const i : int; const j : int) : unit is block
{ if (i=j) then skip else failwith("fail") } with unit ; { if i=j then skip else failwith ("fail") } with unit
// map_iter(m , aggregate) ; } with map_iter (aggregate, m)
} with map_iter(aggregate, m) ;
function map_op (const m : foobar) : foobar is function map_op (const m : foobar) : foobar is
block { block {
function increment (const i : int ; const j : int) : int is block { skip } with j + 1 ; function increment (const i : int; const j : int) : int is j+1
} with map_map(increment, m) ; } with map_map (increment, m)
function fold_op (const m : foobar) : int is function fold_op (const m : foobar) : int is
block { block {
function aggregate (const i : int ; const j : (int * int)) : int is block { skip } with i + j.0 + j.1 ; function aggregate (const i : int; const j : int * int) : int is
i + j.0 + j.1
} with map_fold(aggregate, m, 10) } with map_fold(aggregate, m, 10)
function deep_op (var m : foobar) : foobar is function deep_op (var m : foobar) : foobar is
block { block {
var coco : (int*foobar) := (0, m); var coco : int * foobar := (0, m);
remove 42 from map coco.1; remove 42 from map coco.1;
coco.1[32] := 16 ; coco.1[32] := 16
} with coco.1 } with coco.1

View File

@ -1,37 +1,37 @@
// Test the pattern matching functionality of PascaLIGO // Test the pattern matching functionality of PascaLIGO
function match_bool (const i : int) : int is function match_bool (const i : int) : int is
begin block {
var result : int := 23; var result : int := 23;
case i = 2 of case i = 2 of
| True -> result := 42 True -> result := 42
| False -> result := 0 | False -> result := 0
end end
end with result } with result
function match_option (const o : option (int)) : int is function match_option (const o : option (int)) : int is
begin block {
var result : int := 23; var result : int := 23;
case o of case o of
| None -> skip None -> skip
| Some (s) -> result := s | Some (s) -> result := s
end end
end with result } with result
function match_expr_bool (const i : int) : int is function match_expr_bool (const i : int) : int is
case i = 2 of case i = 2 of
| True -> 42 True -> 42
| False -> 0 | False -> 0
end end
function match_expr_option (const o : option (int)) : int is function match_expr_option (const o : option (int)) : int is
case o of case o of
| None -> 42 None -> 42
| Some (s) -> s | Some (s) -> s
end end
function match_expr_list (const l : list (int)) : int is function match_expr_list (const l : list (int)) : int is
case l of case l of
| nil -> -1 nil -> -1
| hd # tl -> hd | hd # tl -> hd
end end

View File

@ -1,10 +1,14 @@
// Test functions with several parameters in PascaLIGO // Test functions with several parameters in PascaLIGO
function ab(const a : int; const b : int) : int is function ab (const a : int; const b : int) : int is a+b
begin skip end with (a + b)
function abcd(const a : int; const b : int; const c : int; const d : int) : int is function abcd (const a : int;
begin skip end with (a + b + c + d + 2) const b : int;
const c : int;
const d : int) : int is a+b+c+d+2
function abcde(const a : int; const b : int; const c : int; const d : int; const e : int) : int is function abcde (const a : int;
begin skip end with (c + e + 3) const b : int;
const c : int;
const d : int;
const e : int) : int is c+e+3

View File

@ -1,71 +1,95 @@
// storage type // storage type
type threshold_t is nat
type max_proposal_t is nat
type max_message_size_t is nat
type state_hash_t is bytes
type addr_set_t is set(address)
type message_store_t is map(bytes,addr_set_t)
type proposal_counters_t is map(address,nat)
type storage_t is record type threshold is nat
state_hash : state_hash_t ; type max_proposal is nat
threshold : threshold_t ; type max_message_size is nat
max_proposal : max_proposal_t ; type state_hash is bytes
max_message_size : max_message_size_t ; type addr_set is set (address)
authorized_addresses : addr_set_t ; type message_store is map (bytes, addr_set)
message_store : message_store_t ; type proposal_counters is map (address, nat)
proposal_counters : proposal_counters_t ;
end type storage is
record [
state_hash : state_hash;
threshold : threshold;
max_proposal : max_proposal;
max_message_size : max_message_size;
authorized_addresses : addr_set;
message_store : message_store;
proposal_counters : proposal_counters
]
// I/O types // I/O types
type message_t is (bytes -> list(operation))
type send_pt is message_t type message is bytes -> list (operation)
type withdraw_pt is message_t type send_pt is message
type withdraw_pt is message
type default_pt is unit type default_pt is unit
type contract_return_t is (list(operation) * storage_t) type return is list (operation) * storage
type entry_point_t is type parameter is
| Send of send_pt Send of send_pt
| Withdraw of withdraw_pt | Withdraw of withdraw_pt
| Default of default_pt | Default of default_pt
function send (const param : send_pt; const s : storage) : return is
function send (const param : send_pt; const s : storage_t) : contract_return_t is block { block {
// check sender against the authorized addresses // check sender against the authorized addresses
if not set_mem(sender,s.authorized_addresses) then failwith("Unauthorized address") else skip ;
// check message size against the stored limit if not set_mem (sender, s.authorized_addresses)
var message : message_t := param ; then failwith("Unauthorized address")
const packed_msg : bytes = bytes_pack(message) ;
if size(packed_msg) > s.max_message_size then failwith("Message size exceed maximum limit")
else skip; else skip;
// compute the new set of addresses associated with the message and update counters // check message size against the stored limit
var new_store : addr_set_t := set_empty ;
var message : message := param;
const packed_msg : bytes = bytes_pack (message);
if size (packed_msg) > s.max_message_size
then failwith ("Message size exceed maximum limit")
else skip;
(* compute the new set of addresses associated with the message and
update counters *)
var new_store : addr_set := set_empty;
case map_get (packed_msg, s.message_store) of case map_get (packed_msg, s.message_store) of
| Some(voters) -> block { // the message is already stored Some (voters) ->
// increment the counter only if the sender isn't already associated with the message block {
if set_mem(sender,voters) then skip (* The message is already stored.
else s.proposal_counters[sender] := get_force(sender,s.proposal_counters) + 1n ; Increment the counter only if the sender is not already
associated with the message. *)
if set_mem (sender, voters)
then skip
else s.proposal_counters[sender] :=
get_force (sender, s.proposal_counters) + 1n;
new_store := set_add(sender,voters) new_store := set_add(sender,voters)
} }
| None -> block { // the message has never been received before | None ->
s.proposal_counters[sender] := get_force(sender,s.proposal_counters) + 1n ; block {
new_store := set [sender]; // the message has never been received before
s.proposal_counters[sender] :=
get_force (sender, s.proposal_counters) + 1n;
new_store := set [sender]
} }
end; end;
// check sender counters against the maximum number of proposal // check sender counters against the maximum number of proposal
var sender_proposal_counter : nat := get_force(sender,s.proposal_counters) ;
if sender_proposal_counter > s.max_proposal then failwith("Maximum number of proposal reached") var sender_proposal_counter : nat :=
get_force (sender, s.proposal_counters);
if sender_proposal_counter > s.max_proposal
then failwith ("Maximum number of proposal reached")
else skip; else skip;
// check the threshold // check the threshold
var ret_ops : list(operation) := (nil : list(operation)) ;
if size(new_store) >= s.threshold then block { var ret_ops : list (operation) := nil;
if size (new_store) >= s.threshold then {
remove packed_msg from map s.message_store; remove packed_msg from map s.message_store;
ret_ops := message (s.state_hash); ret_ops := message (s.state_hash);
// update the state hash // update the state hash
@ -74,45 +98,53 @@ function send (const param : send_pt; const s : storage_t) : contract_return_t i
for addr -> ctr in map s.proposal_counters block { for addr -> ctr in map s.proposal_counters block {
if set_mem(addr,new_store) then if set_mem(addr,new_store) then
s.proposal_counters[addr] := abs (ctr - 1n) s.proposal_counters[addr] := abs (ctr - 1n)
else skip ; else skip
} }
} else } else s.message_store[packed_msg] := new_store
s.message_store[packed_msg] := new_store
} with (ret_ops, s) } with (ret_ops, s)
function withdraw (const param : withdraw_pt; const s : storage_t) : contract_return_t is block { function withdraw (const param : withdraw_pt; const s : storage) : return is
block {
var message : message_t := param ; var message : message := param;
const packed_msg : bytes = bytes_pack (message); const packed_msg : bytes = bytes_pack (message);
case map_get(packed_msg, s.message_store) of case map_get(packed_msg, s.message_store) of
| Some(voters) -> block { // the message is stored Some (voters) ->
const new_set : addr_set_t = set_remove(sender,voters) ; block {
// The message is stored
const new_set : addr_set = set_remove (sender, voters);
// decrement the counter only if the sender was already associated with the message (* Decrement the counter only if the sender was already
if size(voters) =/= size(new_set) then associated with the message *)
s.proposal_counters[sender] := abs (get_force(sender,s.proposal_counters) - 1n)
if size (voters) =/= size (new_set)
then s.proposal_counters[sender] :=
abs (get_force (sender, s.proposal_counters) - 1n)
else skip ; else skip ;
// if the message is left without any associated addresses, remove the corresponding message_store field (* If the message is left without any associated addresses,
if size(new_set) = 0n then remove packed_msg from map s.message_store remove the corresponding message_store field *)
if size (new_set) = 0n
then remove packed_msg from map s.message_store
else s.message_store[packed_msg] := new_set else s.message_store[packed_msg] := new_set
} }
| None -> skip end // the message isn't stored, ignore | None -> skip
end // The message is not stored, ignore.
} with ((nil : list (operation)), s) } with ((nil : list (operation)), s)
function default (const p : default_pt; const s : storage_t) : contract_return_t is function default (const p : default_pt; const s : storage) : return is
((nil : list (operation)), s) ((nil : list (operation)), s)
function main(const param : entry_point_t; const s : storage_t) : contract_return_t is function main (const param : parameter; const s : storage) : return is
case param of case param of
// propagate message p if the number authorized addresses having (* Propagate message p if the number of authorized addresses having
// voted for the same message p equals the threshold voted for the same message p equals the threshold. *)
| Send (p) -> send (p, s) | Send (p) -> send (p, s)
// withraw vote for message p
(* Withraw vote for message p *)
| Withdraw (p) -> withdraw (p, s) | Withdraw (p) -> withdraw (p, s)
// use this entry-point to transfer tez to the contract
(* Use this action to transfer tez to the contract *)
| Default (p) -> default (p, s) | Default (p) -> default (p, s)
end end

View File

@ -1,62 +1,66 @@
// storage type // storage type
type counter_t is nat
type threshold_t is nat
type authorized_keys_t is list(key)
type id_t is string
type storage_t is record type counter is nat
id : id_t ; type threshold is nat
counter : counter_t ; type authorized_keys is list (key)
threshold : threshold_t ; type id is string
auth : authorized_keys_t ;
end type storage is
record [
id : id;
counter : counter;
threshold : threshold;
auth : authorized_keys
]
// I/O types // I/O types
type message_t is (unit -> list(operation))
type signatures_t is list(key_hash * signature)
type check_message_pt is record
counter : counter_t ;
message : message_t ;
signatures : signatures_t ;
end
type contract_return_t is (list(operation) * storage_t) type message is unit -> list (operation)
type entry_point_t is type signatures is list (key_hash * signature)
| CheckMessage of check_message_pt
type check_message_pt is
record [
counter : counter;
message : message;
signatures : signatures
]
type return is list (operation) * storage
type parameter is CheckMessage of check_message_pt
function check_message (const param : check_message_pt; function check_message (const param : check_message_pt;
const s : storage_t) : contract_return_t is block { const s : storage) : return is block {
var message : message_t := param.message ; var message : message := param.message;
if param.counter =/= s.counter then if param.counter =/= s.counter then
failwith ("Counters does not match") failwith ("Counters does not match")
else block { else {
const packed_payload : bytes = const packed_payload : bytes =
bytes_pack ((message, param.counter, s.id, get_chain_id)); bytes_pack ((message, param.counter, s.id, get_chain_id));
var valid : nat := 0n; var valid : nat := 0n;
var keys : authorized_keys_t := s.auth ; var keys : authorized_keys := s.auth;
for pkh_sig in list param.signatures block { for pkh_sig in list param.signatures block {
case keys of case keys of
| nil -> skip nil -> skip
| key # tl -> block { | key # tl -> block {
keys := tl; keys := tl;
if pkh_sig.0 = crypto_hash_key (key) then if pkh_sig.0 = crypto_hash_key (key) then
if crypto_check(key,pkh_sig.1,packed_payload) then valid := valid + 1n ; if crypto_check (key, pkh_sig.1, packed_payload)
then valid := valid + 1n
else failwith ("Invalid signature") else failwith ("Invalid signature")
else skip; else skip
} }
end end
}; };
if valid < s.threshold then if valid < s.threshold then
failwith ("Not enough signatures passed the check") failwith ("Not enough signatures passed the check")
else s.counter := s.counter + 1n ; else s.counter := s.counter + 1n
} }
} with (message (unit), s) } with (message (unit), s)
function main(const param : entry_point_t; const s : storage_t) : contract_return_t is function main (const param : parameter; const s : storage) : return is
case param of case param of CheckMessage (p) -> check_message (p,s) end
| CheckMessage (p) -> check_message(p,s)
end