Merge branch '129-allow-passing-timestamp-literals' into 'dev'

Resolve "Allow passing timestamp literals"

Closes #129

See merge request ligolang/ligo!298
This commit is contained in:
John David Pressman 2020-01-03 21:46:46 +00:00
commit d3fa06d62a
7 changed files with 86 additions and 14 deletions

View File

@ -19,6 +19,8 @@ const today: timestamp = now;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
> When running code with ligo CLI, the option `--predecessor-timestamp` allows you to control what `now` returns.
### Timestamp arithmetic ### Timestamp arithmetic
In LIGO, timestamps can be added with `int`(s), this enables you to set e.g. time constraints for your smart contracts like this: In LIGO, timestamps can be added with `int`(s), this enables you to set e.g. time constraints for your smart contracts like this:
@ -30,6 +32,8 @@ In LIGO, timestamps can be added with `int`(s), this enables you to set e.g. tim
const today: timestamp = now; const today: timestamp = now;
const one_day: int = 86400; const one_day: int = 86400;
const in_24_hrs: timestamp = today + one_day; const in_24_hrs: timestamp = today + one_day;
const some_date: timestamp = ("2000-01-01T10:10:10Z" : timestamp);
const one_day_later: timestamp = some_date + one_day;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -90,7 +90,7 @@ let predecessor_timestamp =
let open Arg in let open Arg in
let info = let info =
let docv = "PREDECESSOR_TIMESTAMP" in let docv = "PREDECESSOR_TIMESTAMP" in
let doc = "$(docv) is the pedecessor_timestamp the michelson interpreter transaction will use (e.g. '2000-01-01T10:10:10Z')" in let doc = "$(docv) is the pedecessor_timestamp (now value) the michelson interpreter will use (e.g. '2000-01-01T10:10:10Z')" in
info ~docv ~doc ["predecessor-timestamp"] in info ~docv ~doc ["predecessor-timestamp"] in
value @@ opt (some string) None info value @@ opt (some string) None info
@ -156,7 +156,7 @@ let measure_contract =
(Term.ret term , Term.info ~doc cmdname) (Term.ret term , Term.info ~doc cmdname)
let compile_parameter = let compile_parameter =
let f source_file entry_point expression syntax display_format michelson_format = let f source_file entry_point expression syntax amount sender source predecessor_timestamp display_format michelson_format =
toplevel ~display_format @@ toplevel ~display_format @@
let%bind simplified = Compile.Of_source.compile source_file (Syntax_name syntax) in let%bind simplified = Compile.Of_source.compile source_file (Syntax_name syntax) in
let%bind typed_prg,state = Compile.Of_simplified.compile simplified in let%bind typed_prg,state = Compile.Of_simplified.compile simplified in
@ -174,11 +174,12 @@ let compile_parameter =
let%bind compiled_param = Compile.Of_mini_c.aggregate_and_compile_expression mini_c_prg mini_c_param in let%bind compiled_param = Compile.Of_mini_c.aggregate_and_compile_expression mini_c_prg mini_c_param in
let%bind () = Compile.Of_typed.assert_equal_contract_type Check_parameter entry_point typed_prg typed_param in let%bind () = Compile.Of_typed.assert_equal_contract_type Check_parameter entry_point typed_prg typed_param in
let%bind () = Compile.Of_michelson.assert_equal_contract_type Check_parameter michelson_prg compiled_param in let%bind () = Compile.Of_michelson.assert_equal_contract_type Check_parameter michelson_prg compiled_param in
let%bind value = Run.evaluate_expression compiled_param.expr compiled_param.expr_ty in let%bind options = Run.make_dry_run_options {predecessor_timestamp ; amount ; sender ; source } in
let%bind value = Run.evaluate_expression ~options compiled_param.expr compiled_param.expr_ty in
ok @@ Format.asprintf "%a\n" (Main.Display.michelson_pp michelson_format) value ok @@ Format.asprintf "%a\n" (Main.Display.michelson_pp michelson_format) value
in in
let term = let term =
Term.(const f $ source_file 0 $ entry_point 1 $ expression "PARAMETER" 2 $ syntax $ display_format $ michelson_code_format) in Term.(const f $ source_file 0 $ entry_point 1 $ expression "PARAMETER" 2 $ syntax $ amount $ sender $ source $ predecessor_timestamp $ display_format $ michelson_code_format) in
let cmdname = "compile-parameter" in let cmdname = "compile-parameter" in
let doc = "Subcommand: compile parameters to a michelson expression. The resulting michelson expression can be passed as an argument in a transaction which calls a contract." in let doc = "Subcommand: compile parameters to a michelson expression. The resulting michelson expression can be passed as an argument in a transaction which calls a contract." in
(Term.ret term , Term.info ~doc cmdname) (Term.ret term , Term.info ~doc cmdname)
@ -213,7 +214,7 @@ let interpret =
let compile_storage = let compile_storage =
let f source_file entry_point expression syntax display_format michelson_format = let f source_file entry_point expression syntax amount sender source predecessor_timestamp display_format michelson_format =
toplevel ~display_format @@ toplevel ~display_format @@
let%bind simplified = Compile.Of_source.compile source_file (Syntax_name syntax) in let%bind simplified = Compile.Of_source.compile source_file (Syntax_name syntax) in
let%bind typed_prg,state = Compile.Of_simplified.compile simplified in let%bind typed_prg,state = Compile.Of_simplified.compile simplified in
@ -231,11 +232,12 @@ let compile_storage =
let%bind compiled_param = Compile.Of_mini_c.compile_expression mini_c_param in let%bind compiled_param = Compile.Of_mini_c.compile_expression mini_c_param in
let%bind () = Compile.Of_typed.assert_equal_contract_type Check_storage entry_point typed_prg typed_param in let%bind () = Compile.Of_typed.assert_equal_contract_type Check_storage entry_point typed_prg typed_param in
let%bind () = Compile.Of_michelson.assert_equal_contract_type Check_storage michelson_prg compiled_param in let%bind () = Compile.Of_michelson.assert_equal_contract_type Check_storage michelson_prg compiled_param in
let%bind value = Run.evaluate_expression compiled_param.expr compiled_param.expr_ty in let%bind options = Run.make_dry_run_options {predecessor_timestamp ; amount ; sender ; source } in
let%bind value = Run.evaluate_expression ~options compiled_param.expr compiled_param.expr_ty in
ok @@ Format.asprintf "%a\n" (Main.Display.michelson_pp michelson_format) value ok @@ Format.asprintf "%a\n" (Main.Display.michelson_pp michelson_format) value
in in
let term = let term =
Term.(const f $ source_file 0 $ entry_point 1 $ expression "STORAGE" 2 $ syntax $ display_format $ michelson_code_format) in Term.(const f $ source_file 0 $ entry_point 1 $ expression "STORAGE" 2 $ syntax $ amount $ sender $ source $ predecessor_timestamp $ display_format $ michelson_code_format) in
let cmdname = "compile-storage" in let cmdname = "compile-storage" in
let doc = "Subcommand: compile an initial storage in ligo syntax to a michelson expression. The resulting michelson expression can be passed as an argument in a transaction which originates a contract." in let doc = "Subcommand: compile an initial storage in ligo syntax to a michelson expression. The resulting michelson expression can be passed as an argument in a transaction which originates a contract." in
(Term.ret term , Term.info ~doc cmdname) (Term.ret term , Term.info ~doc cmdname)

View File

@ -30,6 +30,10 @@ let%expect_test _ =
() ()
let%expect_test _ =
run_ligo_good [ "compile-storage" ; contract "timestamp.ligo" ; "main" ; "now" ; "--predecessor-timestamp" ; "2042-01-01T00:00:00Z" ] ;
[%expect {| "2042-01-01T00:00:01Z" |}]
let%expect_test _ = let%expect_test _ =
run_ligo_good [ "compile-contract" ; contract "coase.ligo" ; "main" ] ; run_ligo_good [ "compile-contract" ; contract "coase.ligo" ; "main" ] ;
[%expect {| [%expect {|
@ -936,3 +940,7 @@ let%expect_test _ =
let%expect_test _ = let%expect_test _ =
run_ligo_bad [ "compile-contract" ; contract "bad_address_format.religo" ; "main" ] ; run_ligo_bad [ "compile-contract" ; contract "bad_address_format.religo" ; "main" ] ;
[%expect {| ligo: in file "bad_address_format.religo", line 2, characters 25-47. Badly formatted address "KT1badaddr": {"location":"in file \"bad_address_format.religo\", line 2, characters 25-47"} |}] [%expect {| ligo: in file "bad_address_format.religo", line 2, characters 25-47. Badly formatted address "KT1badaddr": {"location":"in file \"bad_address_format.religo\", line 2, characters 25-47"} |}]
let%expect_test _ =
run_ligo_bad [ "compile-contract" ; contract "bad_timestamp.ligo" ; "main" ] ;
[%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"} |}]

View File

@ -176,6 +176,9 @@ let%expect_test _ =
contract. contract.
OPTIONS OPTIONS
--amount=AMOUNT (absent=0)
AMOUNT is the amount the michelson interpreter will use.
--format=DISPLAY_FORMAT, --display-format=DISPLAY_FORMAT --format=DISPLAY_FORMAT, --display-format=DISPLAY_FORMAT
(absent=human-readable) (absent=human-readable)
DISPLAY_FORMAT is the format that will be used by the CLI. DISPLAY_FORMAT is the format that will be used by the CLI.
@ -194,11 +197,23 @@ let%expect_test _ =
compile-contract for the resulting Michelson. Available formats compile-contract for the resulting Michelson. Available formats
are 'text' (default), 'json' and 'hex'. are 'text' (default), 'json' and 'hex'.
--predecessor-timestamp=PREDECESSOR_TIMESTAMP
PREDECESSOR_TIMESTAMP is the pedecessor_timestamp (now value) the
michelson interpreter will use (e.g. '2000-01-01T10:10:10Z')
-s SYNTAX, --syntax=SYNTAX (absent=auto) -s SYNTAX, --syntax=SYNTAX (absent=auto)
SYNTAX is the syntax that will be used. Currently supported SYNTAX is the syntax that will be used. Currently supported
syntaxes are "pascaligo" and "cameligo". By default, the syntax is syntaxes are "pascaligo" and "cameligo". By default, the syntax is
guessed from the extension (.ligo and .mligo, respectively). guessed from the extension (.ligo and .mligo, respectively).
--sender=SENDER
SENDER is the sender the michelson interpreter transaction will
use.
--source=SOURCE
SOURCE is the source the michelson interpreter transaction will
use.
--version --version
Show version information. |} ] ; Show version information. |} ] ;
@ -226,6 +241,9 @@ let%expect_test _ =
STORAGE_EXPRESSION is the expression that will be compiled. STORAGE_EXPRESSION is the expression that will be compiled.
OPTIONS OPTIONS
--amount=AMOUNT (absent=0)
AMOUNT is the amount the michelson interpreter will use.
--format=DISPLAY_FORMAT, --display-format=DISPLAY_FORMAT --format=DISPLAY_FORMAT, --display-format=DISPLAY_FORMAT
(absent=human-readable) (absent=human-readable)
DISPLAY_FORMAT is the format that will be used by the CLI. DISPLAY_FORMAT is the format that will be used by the CLI.
@ -244,11 +262,23 @@ let%expect_test _ =
compile-contract for the resulting Michelson. Available formats compile-contract for the resulting Michelson. Available formats
are 'text' (default), 'json' and 'hex'. are 'text' (default), 'json' and 'hex'.
--predecessor-timestamp=PREDECESSOR_TIMESTAMP
PREDECESSOR_TIMESTAMP is the pedecessor_timestamp (now value) the
michelson interpreter will use (e.g. '2000-01-01T10:10:10Z')
-s SYNTAX, --syntax=SYNTAX (absent=auto) -s SYNTAX, --syntax=SYNTAX (absent=auto)
SYNTAX is the syntax that will be used. Currently supported SYNTAX is the syntax that will be used. Currently supported
syntaxes are "pascaligo" and "cameligo". By default, the syntax is syntaxes are "pascaligo" and "cameligo". By default, the syntax is
guessed from the extension (.ligo and .mligo, respectively). guessed from the extension (.ligo and .mligo, respectively).
--sender=SENDER
SENDER is the sender the michelson interpreter transaction will
use.
--source=SOURCE
SOURCE is the source the michelson interpreter transaction will
use.
--version --version
Show version information. |} ] ; Show version information. |} ] ;
@ -294,8 +324,8 @@ let%expect_test _ =
`plain' whenever the TERM env var is `dumb' or undefined. `plain' whenever the TERM env var is `dumb' or undefined.
--predecessor-timestamp=PREDECESSOR_TIMESTAMP --predecessor-timestamp=PREDECESSOR_TIMESTAMP
PREDECESSOR_TIMESTAMP is the pedecessor_timestamp the michelson PREDECESSOR_TIMESTAMP is the pedecessor_timestamp (now value) the
interpreter transaction will use (e.g. '2000-01-01T10:10:10Z') michelson interpreter will use (e.g. '2000-01-01T10:10:10Z')
-s SYNTAX, --syntax=SYNTAX (absent=auto) -s SYNTAX, --syntax=SYNTAX (absent=auto)
SYNTAX is the syntax that will be used. Currently supported SYNTAX is the syntax that will be used. Currently supported
@ -352,8 +382,8 @@ let%expect_test _ =
`plain' whenever the TERM env var is `dumb' or undefined. `plain' whenever the TERM env var is `dumb' or undefined.
--predecessor-timestamp=PREDECESSOR_TIMESTAMP --predecessor-timestamp=PREDECESSOR_TIMESTAMP
PREDECESSOR_TIMESTAMP is the pedecessor_timestamp the michelson PREDECESSOR_TIMESTAMP is the pedecessor_timestamp (now value) the
interpreter transaction will use (e.g. '2000-01-01T10:10:10Z') michelson interpreter will use (e.g. '2000-01-01T10:10:10Z')
-s SYNTAX, --syntax=SYNTAX (absent=auto) -s SYNTAX, --syntax=SYNTAX (absent=auto)
SYNTAX is the syntax that will be used. Currently supported SYNTAX is the syntax that will be used. Currently supported
@ -405,8 +435,8 @@ let%expect_test _ =
`plain' whenever the TERM env var is `dumb' or undefined. `plain' whenever the TERM env var is `dumb' or undefined.
--predecessor-timestamp=PREDECESSOR_TIMESTAMP --predecessor-timestamp=PREDECESSOR_TIMESTAMP
PREDECESSOR_TIMESTAMP is the pedecessor_timestamp the michelson PREDECESSOR_TIMESTAMP is the pedecessor_timestamp (now value) the
interpreter transaction will use (e.g. '2000-01-01T10:10:10Z') michelson interpreter will use (e.g. '2000-01-01T10:10:10Z')
-s SYNTAX, --syntax=SYNTAX (absent=auto) -s SYNTAX, --syntax=SYNTAX (absent=auto)
SYNTAX is the syntax that will be used. Currently supported SYNTAX is the syntax that will be used. Currently supported

View File

@ -1,11 +1,29 @@
open Ast_simplified open Ast_simplified
open Trace open Trace
module Errors = struct
let bad_string_timestamp ts loc () =
let title = (thunk ("Badly formatted timestamp \""^ts^"\"")) in
let message () = "" in
let data = [
("location" , fun () -> Format.asprintf "%a" Location.pp loc)
] in
error ~data title message ()
end
open Errors
let peephole_expression : expression -> expression result = fun e -> let peephole_expression : expression -> expression result = fun e ->
let return expression = ok { e with expression } in let return expression = ok { e with expression } in
match e.expression with match e.expression with
| E_ascription (e' , t) as e -> ( | E_ascription (e' , t) as e -> (
match (e'.expression , t.type_expression') with match (e'.expression , t.type_expression') with
| (E_literal (Literal_int i) , T_constant (TC_timestamp)) -> return @@ E_literal (Literal_timestamp i)
| (E_literal (Literal_string str) , T_constant (TC_timestamp)) ->
let%bind time =
trace_option (bad_string_timestamp str e'.location)
@@ Memory_proto_alpha.Protocol.Alpha_context.Timestamp.of_notation str in
let itime = Int64.to_int @@ Tezos_utils.Time.Protocol.to_seconds time in
return @@ E_literal (Literal_timestamp itime)
| (E_literal (Literal_string str) , T_constant (TC_address)) -> return @@ E_literal (Literal_address str) | (E_literal (Literal_string str) , T_constant (TC_address)) -> return @@ E_literal (Literal_address str)
| (E_literal (Literal_string str) , T_constant (TC_bytes)) -> ( | (E_literal (Literal_string str) , T_constant (TC_bytes)) -> (
let%bind e' = e'_bytes str in let%bind e' = e'_bytes str in
@ -13,4 +31,4 @@ let peephole_expression : expression -> expression result = fun e ->
) )
| _ -> return e | _ -> return e
) )
| e -> return e | e -> return e

View File

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

View File

@ -0,0 +1,3 @@
type storage_ is timestamp
function main(const p : unit; const s : storage_) : list(operation) * storage_ is ((nil: list(operation)), now)