Support for empty sets and maps. Alternate syntax for maps and lists:

sets, maps and lists are now homogeneous.

Lists by extension now require the "list" keyword, like sets and
maps. Semicolons needed, instead of commas.

New syntax for lists: `list [e_1; e_2; ...; e_n]`.

The empty list can now be denoted either by `list []` or `list end` or
`nil'.

Both `list` and `nil` are new keywords. Lists can also be denoted
without brackets, as sets and maps: `list e_1; e_2; ...; e_n end`.

The extension for maps follows the extension for sets: `map [b_1; b_2;
...; b_n]` or `maps b_1; ...; b_n end`.
This commit is contained in:
Christian Rinderknecht 2019-03-26 10:31:55 +01:00
parent 98f9d3e417
commit fef4337e83
No known key found for this signature in database
GPG Key ID: 9446816CFD267040
7 changed files with 288 additions and 135 deletions

103
AST.ml
View File

@ -39,6 +39,7 @@ let sepseq_to_region to_region = function
(* Keywords of LIGO *)
type keyword = Region.t
type kwd_and = Region.t
type kwd_begin = Region.t
type kwd_block = Region.t
@ -56,8 +57,10 @@ type kwd_function = Region.t
type kwd_if = Region.t
type kwd_in = Region.t
type kwd_is = Region.t
type kwd_list = Region.t
type kwd_map = Region.t
type kwd_mod = Region.t
type kwd_nil = Region.t
type kwd_not = Region.t
type kwd_of = Region.t
type kwd_or = Region.t
@ -378,10 +381,10 @@ and map_patch = {
}
and map_injection = {
opening : kwd_map;
bindings : (binding reg, semi) nsepseq;
opening : opening;
bindings : (binding reg, semi) sepseq;
terminator : semi option;
closing : kwd_end
closing : closing
}
and binding = {
@ -518,12 +521,20 @@ and set_expr =
SetInj of set_injection reg
and set_injection = {
opening : kwd_set;
elements : (expr, semi) nsepseq;
opening : opening;
elements : (expr, semi) sepseq;
terminator : semi option;
closing : kwd_end
closing : closing
}
and opening =
Kwd of keyword
| KwdBracket of keyword * lbracket
and closing =
End of kwd_end
| RBracket of rbracket
and map_expr =
MapLookUp of map_lookup reg
| MapInj of map_injection reg
@ -581,9 +592,22 @@ and string_expr =
| String of Lexer.lexeme reg
and list_expr =
Cons of cons bin_op reg
| List of (expr, comma) nsepseq brackets reg
| EmptyList of empty_list reg
Cons of cons bin_op reg
| List of list_injection reg
| Nil of nil par reg
and list_injection = {
opening : opening;
elements : (expr, semi) sepseq;
terminator : semi option;
closing : closing
}
and nil = {
nil : kwd_nil;
colon : colon;
list_type : type_expr
}
and constr_expr =
SomeApp of (c_Some * arguments) reg
@ -615,15 +639,6 @@ and record_projection = {
and tuple = (expr, comma) nsepseq par reg
and empty_list = typed_empty_list par
and typed_empty_list = {
lbracket : lbracket;
rbracket : rbracket;
colon : colon;
list_type : type_expr
}
and none_expr = typed_none_expr par
and typed_none_expr = {
@ -725,9 +740,9 @@ and string_expr_to_region = function
| String {region; _} -> region
and list_expr_to_region = function
Cons {region; _}
| List {region; _}
| EmptyList {region; _} -> region
Cons {region; _}
| List {region; _}
| Nil {region; _} -> region
and constr_expr_to_region = function
NoneExpr {region; _}
@ -1283,8 +1298,8 @@ and print_string_expr = function
and print_list_expr = function
Cons {value = {arg1; op; arg2}; _} ->
print_expr arg1; print_token op "#"; print_expr arg2
| List e -> print_list e
| EmptyList e -> print_empty_list e
| List e -> print_list_injection e
| Nil e -> print_nil e
and print_constr_expr = function
SomeApp e -> print_some_app e
@ -1356,17 +1371,27 @@ and print_set_remove node =
and print_map_injection {value; _} =
let {opening; bindings; terminator; closing} = value in
print_token opening "map";
print_nsepseq ";" print_binding bindings;
print_opening "map" opening;
print_sepseq ";" print_binding bindings;
print_terminator terminator;
print_token closing "end"
print_closing closing
and print_set_injection {value; _} =
let {opening; elements; terminator; closing} = value in
print_token opening "set";
print_nsepseq ";" print_expr elements;
let {opening; elements; terminator; closing} : set_injection = value in
print_opening "set" opening;
print_sepseq ";" print_expr elements;
print_terminator terminator;
print_token closing "end"
print_closing closing
and print_opening lexeme = function
Kwd kwd -> print_token kwd lexeme
| KwdBracket (kwd, lbracket) ->
print_token kwd lexeme;
print_token lbracket "{"
and print_closing = function
RBracket rbracket -> print_token rbracket "}"
| End kwd_end -> print_token kwd_end "end"
and print_binding {value; _} =
let {source; arrow; image} = value in
@ -1380,18 +1405,18 @@ and print_tuple {value; _} =
print_nsepseq "," print_expr inside;
print_token rpar ")"
and print_list {value; _} =
let {lbracket; inside; rbracket} = value in
print_token lbracket "[";
print_nsepseq "," print_expr inside;
print_token rbracket "]"
and print_list_injection {value; _} =
let {opening; elements; terminator; closing} : list_injection = value in
print_opening "list" opening;
print_sepseq ";" print_expr elements;
print_terminator terminator;
print_closing closing
and print_empty_list {value; _} =
and print_nil {value; _} =
let {lpar; inside; rpar} = value in
let {lbracket; rbracket; colon; list_type} = inside in
let {nil; colon; list_type} = inside in
print_token lpar "(";
print_token lbracket "[";
print_token rbracket "]";
print_token nil "nil";
print_token colon ":";
print_type_expr list_type;
print_token rpar ")"

51
AST.mli
View File

@ -23,6 +23,7 @@ val sepseq_to_region : ('a -> Region.t) -> ('a,'sep) sepseq -> Region.t
(* Keywords of LIGO *)
type keyword = Region.t
type kwd_and = Region.t
type kwd_begin = Region.t
type kwd_block = Region.t
@ -40,8 +41,10 @@ type kwd_function = Region.t
type kwd_if = Region.t
type kwd_in = Region.t
type kwd_is = Region.t
type kwd_list = Region.t
type kwd_map = Region.t
type kwd_mod = Region.t
type kwd_nil = Region.t
type kwd_not = Region.t
type kwd_of = Region.t
type kwd_or = Region.t
@ -362,10 +365,10 @@ and map_patch = {
}
and map_injection = {
opening : kwd_map;
bindings : (binding reg, semi) nsepseq;
opening : opening;
bindings : (binding reg, semi) sepseq;
terminator : semi option;
closing : kwd_end
closing : closing
}
and binding = {
@ -502,12 +505,20 @@ and set_expr =
SetInj of set_injection reg
and set_injection = {
opening : kwd_set;
elements : (expr, semi) nsepseq;
opening : opening;
elements : (expr, semi) sepseq;
terminator : semi option;
closing : kwd_end
closing : closing
}
and opening =
Kwd of keyword
| KwdBracket of keyword * lbracket
and closing =
End of kwd_end
| RBracket of rbracket
and map_expr =
MapLookUp of map_lookup reg
| MapInj of map_injection reg
@ -565,9 +576,22 @@ and string_expr =
| String of Lexer.lexeme reg
and list_expr =
Cons of cons bin_op reg
| List of (expr, comma) nsepseq brackets reg
| EmptyList of empty_list reg
Cons of cons bin_op reg
| List of list_injection reg
| Nil of nil par reg
and list_injection = {
opening : opening;
elements : (expr, semi) sepseq;
terminator : semi option;
closing : closing
}
and nil = {
nil : kwd_nil;
colon : colon;
list_type : type_expr
}
and constr_expr =
SomeApp of (c_Some * arguments) reg
@ -599,15 +623,6 @@ and record_projection = {
and tuple = (expr, comma) nsepseq par reg
and empty_list = typed_empty_list par
and typed_empty_list = {
lbracket : lbracket;
rbracket : rbracket;
colon : colon;
list_type : type_expr
}
and none_expr = typed_none_expr par
and typed_none_expr = {

View File

@ -82,8 +82,10 @@ type t =
| If of Region.t (* "if" *)
| In of Region.t (* "in" *)
| Is of Region.t (* "is" *)
| List of Region.t (* "list" *)
| Map of Region.t (* "map" *)
| Mod of Region.t (* "mod" *)
| Nil of Region.t (* "nil" *)
| Not of Region.t (* "not" *)
| Of of Region.t (* "of" *)
| Or of Region.t (* "or" *)

View File

@ -81,8 +81,10 @@ type t =
| If of Region.t (* "if" *)
| In of Region.t (* "in" *)
| Is of Region.t (* "is" *)
| List of Region.t (* "list" *)
| Map of Region.t (* "map" *)
| Mod of Region.t (* "mod" *)
| Nil of Region.t (* "nil" *)
| Not of Region.t (* "not" *)
| Of of Region.t (* "of" *)
| Or of Region.t (* "or" *)
@ -206,8 +208,10 @@ let proj_token = function
| If region -> region, "If"
| In region -> region, "In"
| Is region -> region, "Is"
| List region -> region, "List"
| Map region -> region, "Map"
| Mod region -> region, "Mod"
| Nil region -> region, "Nil"
| Not region -> region, "Not"
| Of region -> region, "Of"
| Or region -> region, "Or"
@ -286,22 +290,23 @@ let to_lexeme = function
| Const _ -> "const"
| Contains _ -> "contains"
| Down _ -> "down"
| Fail _ -> "fail"
| If _ -> "if"
| In _ -> "in"
| Is _ -> "is"
| Else _ -> "else"
| End _ -> "end"
| Entrypoint _ -> "entrypoint"
| Fail _ -> "fail"
| For _ -> "for"
| From _ -> "from"
| Function _ -> "function"
| Type _ -> "type"
| If _ -> "if"
| In _ -> "in"
| Is _ -> "is"
| List _ -> "list"
| Map _ -> "map"
| Mod _ -> "mod"
| Nil _ -> "nil"
| Not _ -> "not"
| Of _ -> "of"
| Or _ -> "or"
| Var _ -> "var"
| End _ -> "end"
| Then _ -> "then"
| Else _ -> "else"
| Map _ -> "map"
| Patch _ -> "patch"
| Procedure _ -> "procedure"
| Record _ -> "record"
@ -310,9 +315,10 @@ let to_lexeme = function
| Skip _ -> "skip"
| Step _ -> "step"
| Storage _ -> "storage"
| Then _ -> "then"
| To _ -> "to"
| Mod _ -> "mod"
| Not _ -> "not"
| Type _ -> "type"
| Var _ -> "var"
| While _ -> "while"
| With _ -> "with"
@ -346,22 +352,23 @@ let keywords = [
(fun reg -> Const reg);
(fun reg -> Contains reg);
(fun reg -> Down reg);
(fun reg -> Fail reg);
(fun reg -> If reg);
(fun reg -> In reg);
(fun reg -> Is reg);
(fun reg -> Else reg);
(fun reg -> End reg);
(fun reg -> Entrypoint reg);
(fun reg -> For reg);
(fun reg -> From reg);
(fun reg -> Function reg);
(fun reg -> Type reg);
(fun reg -> Fail reg);
(fun reg -> If reg);
(fun reg -> In reg);
(fun reg -> Is reg);
(fun reg -> List reg);
(fun reg -> Map reg);
(fun reg -> Mod reg);
(fun reg -> Nil reg);
(fun reg -> Not reg);
(fun reg -> Of reg);
(fun reg -> Or reg);
(fun reg -> Var reg);
(fun reg -> End reg);
(fun reg -> Then reg);
(fun reg -> Else reg);
(fun reg -> Map reg);
(fun reg -> Patch reg);
(fun reg -> Procedure reg);
(fun reg -> Record reg);
@ -370,9 +377,10 @@ let keywords = [
(fun reg -> Skip reg);
(fun reg -> Step reg);
(fun reg -> Storage reg);
(fun reg -> Then reg);
(fun reg -> To reg);
(fun reg -> Mod reg);
(fun reg -> Not reg);
(fun reg -> Type reg);
(fun reg -> Var reg);
(fun reg -> While reg);
(fun reg -> With reg)
]
@ -574,22 +582,23 @@ let is_kwd = function
| Const _
| Contains _
| Down _
| Fail _
| If _
| In _
| Is _
| Else _
| End _
| Entrypoint _
| Fail _
| For _
| From _
| Function _
| Type _
| If _
| In _
| Is _
| List _
| Map _
| Mod _
| Nil _
| Not _
| Of _
| Or _
| Var _
| End _
| Then _
| Else _
| Map _
| Patch _
| Procedure _
| Record _
@ -598,9 +607,10 @@ let is_kwd = function
| Skip _
| Step _
| Storage _
| Then _
| To _
| Mod _
| Not _
| Type _
| Var _
| While _
| With _ -> true
| _ -> false

View File

@ -49,22 +49,23 @@
%token <Region.t> Const (* "const" *)
%token <Region.t> Contains (* "contains" *)
%token <Region.t> Down (* "down" *)
%token <Region.t> Else (* "else" *)
%token <Region.t> End (* "end" *)
%token <Region.t> Entrypoint (* "entrypoint" *)
%token <Region.t> Fail (* "fail" *)
%token <Region.t> For (* "for" *)
%token <Region.t> Function (* "function" *)
%token <Region.t> From (* "from" *)
%token <Region.t> If (* "if" *)
%token <Region.t> In (* "in" *)
%token <Region.t> Is (* "is" *)
%token <Region.t> Entrypoint (* "entrypoint" *)
%token <Region.t> For (* "for" *)
%token <Region.t> Function (* "function" *)
%token <Region.t> Type (* "type" *)
%token <Region.t> List (* "list" *)
%token <Region.t> Map (* "map" *)
%token <Region.t> Mod (* "mod" *)
%token <Region.t> Nil (* "nil" *)
%token <Region.t> Not (* "not" *)
%token <Region.t> Of (* "of" *)
%token <Region.t> Or (* "or" *)
%token <Region.t> Var (* "var" *)
%token <Region.t> End (* "end" *)
%token <Region.t> Then (* "then" *)
%token <Region.t> Else (* "else" *)
%token <Region.t> Map (* "map" *)
%token <Region.t> Patch (* "patch" *)
%token <Region.t> Procedure (* "procedure" *)
%token <Region.t> Record (* "record" *)
@ -73,9 +74,10 @@
%token <Region.t> Skip (* "skip" *)
%token <Region.t> Step (* "step" *)
%token <Region.t> Storage (* "storage" *)
%token <Region.t> Then (* "then" *)
%token <Region.t> To (* "to" *)
%token <Region.t> Mod (* "mod" *)
%token <Region.t> Not (* "not" *)
%token <Region.t> Type (* "type" *)
%token <Region.t> Var (* "var" *)
%token <Region.t> While (* "while" *)
%token <Region.t> With (* "with" *)

View File

@ -177,6 +177,13 @@ core_type:
let tuple = {region; value={lpar; inside=inside,[]; rpar}}
in TApp {region=total; value = type_constr, tuple}
}
| List par(type_expr) {
let total = cover $1 $2.region in
let type_constr = {value="list"; region=$1} in
let {region; value = {lpar; inside; rpar}} = $2 in
let tuple = {region; value={lpar; inside=inside,[]; rpar}}
in TApp {region=total; value = type_constr, tuple}
}
| par(type_expr) {
TPar $1
}
@ -390,18 +397,17 @@ unqualified_decl(OP):
let init =
match $5.value with
`Expr e -> e
| `EList (lbracket, rbracket) ->
| `EList kwd_nil ->
let region = $5.region
and value = {
lbracket;
rbracket;
nil = kwd_nil;
colon = Region.ghost;
list_type = $3} in
let value = {
lpar = Region.ghost;
inside = value;
rpar = Region.ghost} in
EList (EmptyList {region; value})
EList (Nil {region; value})
| `ENone region ->
let value = {
lpar = Region.ghost;
@ -451,13 +457,12 @@ var_decl:
}
extended_expr:
expr { {region = expr_to_region $1;
value = `Expr $1} }
| LBRACKET RBRACKET { {region = cover $1 $2;
value = `EList ($1,$2)} }
| C_None { {region = $1; value = `ENone $1} }
| map_injection { {region = $1.region; value = `EMap $1} }
| set_injection { {region = $1.region; value = `ESet $1} }
expr { {region = expr_to_region $1;
value = `Expr $1} }
| Nil { {region = $1; value = `EList $1} }
| C_None { {region = $1; value = `ENone $1} }
| map_injection { {region = $1.region; value = `EMap $1} }
| set_injection { {region = $1.region; value = `ESet $1} }
instruction:
single_instr { Single $1 }
@ -527,11 +532,39 @@ set_injection:
Set series(expr,End) {
let first, (others, terminator, closing) = $2 in
let region = cover $1 closing
and value = {
opening = $1;
elements = first, others;
and value : set_injection = {
opening = Kwd $1;
elements = Some (first, others);
terminator;
closing}
closing = End closing}
in {region; value}
}
| Set End {
let region = cover $1 $2
and value : set_injection = {
opening = Kwd $1;
elements = None;
terminator = None;
closing = End $2}
in {region; value}
}
| Set LBRACKET series(expr,RBRACKET) {
let first, (others, terminator, closing) = $3 in
let region = cover $1 closing
and value : set_injection = {
opening = KwdBracket ($1,$2);
elements = Some (first, others);
terminator;
closing = RBracket closing}
in {region; value}
}
| Set LBRACKET RBRACKET {
let region = cover $1 $3
and value : set_injection = {
opening = KwdBracket ($1,$2);
elements = None;
terminator = None;
closing = RBracket $3}
in {region; value}
}
@ -540,10 +573,38 @@ map_injection:
let first, (others, terminator, closing) = $2 in
let region = cover $1 closing
and value = {
opening = $1;
bindings = first, others;
opening = Kwd $1;
bindings = Some (first, others);
terminator;
closing}
closing = End closing}
in {region; value}
}
| Map End {
let region = cover $1 $2
and value = {
opening = Kwd $1;
bindings = None;
terminator = None;
closing = End $2}
in {region; value}
}
| Map LBRACKET series(binding,RBRACKET) {
let first, (others, terminator, closing) = $3 in
let region = cover $1 closing
and value = {
opening = KwdBracket ($1,$2);
bindings = Some (first, others);
terminator;
closing = RBracket closing}
in {region; value}
}
| Map LBRACKET RBRACKET {
let region = cover $1 $3
and value = {
opening = KwdBracket ($1,$2);
bindings = None;
terminator = None;
closing = RBracket $3}
in {region; value}
}
@ -873,7 +934,7 @@ core_expr:
| C_Unit { EUnit $1 }
| tuple { ETuple $1 }
| list_expr { EList (List $1) }
| empty_list { EList (EmptyList $1) }
| nil { EList (Nil $1) }
| none_expr { EConstr (NoneExpr $1) }
| fun_call { ECall $1 }
| map_expr { EMap $1 }
@ -953,17 +1014,53 @@ arguments:
tuple { $1 }
list_expr:
brackets(nsepseq(expr,COMMA)) { $1 }
List series(expr,End) {
let first, (others, terminator, closing) = $2 in
let region = cover $1 closing
and value : list_injection = {
opening = Kwd $1;
elements = Some (first, others);
terminator;
closing = End closing}
in {region; value}
}
| List End {
let region = cover $1 $2
and value : list_injection = {
opening = Kwd $1;
elements = None;
terminator = None;
closing = End $2}
in {region; value}
}
| List LBRACKET series(expr,RBRACKET) {
let first, (others, terminator, closing) = $3 in
let region = cover $1 closing
and value : list_injection = {
opening = KwdBracket ($1,$2);
elements = Some (first, others);
terminator;
closing = RBracket closing}
in {region; value}
}
| List LBRACKET RBRACKET {
let region = cover $1 $3
and value : list_injection = {
opening = KwdBracket ($1,$2);
elements = None;
terminator = None;
closing = RBracket $3}
in {region; value}
}
empty_list:
nil:
par(typed_empty_list) { $1 }
typed_empty_list:
LBRACKET RBRACKET COLON type_expr {
{lbracket = $1;
rbracket = $2;
colon = $3;
list_type = $4}
Nil COLON type_expr {
{nil = $1;
colon = $2;
list_type = $3}
}
none_expr:

View File

@ -10,7 +10,9 @@ entrypoint contribute (storage store : store;
const sender : address;
const amount : mutez)
: store * list (operation) is
var operations : list (operation) := []
var operations : list (operation) := nil
const s : list (int) = list [1; 2; 3]
const t : set (int) = set []
block {
if now > store.deadline then
fail "Deadline passed";
@ -24,14 +26,14 @@ entrypoint contribute (storage store : store;
entrypoint withdraw (storage store : store; const sender : address)
: store * list (operation) is
var operations : list (operation) := []
var operations : list (operation) := list end
begin
if sender = owner then
if now (Unit) >= store.deadline then
if balance >= store.goal then {
store.funded := True;
// patch store with record funded = True end;
operations := [Transfer (owner, balance)];
operations := list [Transfer (owner, balance)];
};
else fail "Below target"
else { fail "Too soon"; }
@ -40,7 +42,7 @@ entrypoint withdraw (storage store : store; const sender : address)
entrypoint claim (storage store : store; const sender : address)
: store * list (operation) is
var operations : list (operation) := []
var operations : list (operation) := list []
var amount : mutez := 0
begin
if now <= store.deadline then
@ -54,7 +56,7 @@ entrypoint claim (storage store : store; const sender : address)
fail "Cannot refund"
else
begin
operations := [Transfer (sender, amount)];
operations := list [Transfer (sender, amount)];
remove sender from map store.backers
end
end