diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 868329c..b588dd8 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -2262,6 +2262,22 @@ mk_t_err(Pos, Msg) -> mk_t_err(Pos, Msg, Ctxt) -> aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)). +mk_error({higher_kinded_typevar, T}) -> + Msg = io_lib:format("Type ~s is higher kinded (takes a type argument that takes\n" + "a type argument)\n", [pp(instantiate(T))] + ), + mk_t_err(pos(T), Msg); +mk_error({wrong_type_arguments, X, ArityGiven, ArityReal}) -> + Msg = io_lib:format("Arity for ~s doesn't match. Expected ~p, got ~p\n" + , [pp(instantiate(X)), ArityReal, ArityGiven] + ), + mk_t_err(pos(X), Msg); +mk_error({unnamed_map_update_with_default, Upd}) -> + Msg = "Invalid map update with default\n", + mk_t_err(pos(Upd), Msg); +mk_error({fundecl_must_have_funtype, _Ann, Id, _Type}) -> + Msg = io_lib:format("Function/entrypoint declaration must have a function type\n"), + mk_t_err(pos(Id), Msg); mk_error({cannot_unify, A, B, When}) -> Msg = io_lib:format("Cannot unify ~s\n and ~s\n", [pp(instantiate(A)), pp(instantiate(B))]), @@ -2344,14 +2360,6 @@ mk_error({indexed_type_must_be_word, Type, Type1}) -> Msg = io_lib:format("The indexed type ~s (at ~s) equals ~s which is not a word type\n", [pp_type("", Type), pp_loc(Type), pp_type("", Type1)]), mk_t_err(pos(Type), Msg); -mk_error({payload_type_must_be_string, Type, Type}) -> - Msg = io_lib:format("The payload type ~s (at ~s) should be string\n", - [pp_type("", Type), pp_loc(Type)]), - mk_t_err(pos(Type), Msg); -mk_error({payload_type_must_be_string, Type, Type1}) -> - Msg = io_lib:format("The payload type ~s (at ~s) equals ~s but it should be string\n", - [pp_type("", Type), pp_loc(Type), pp_type("", Type1)]), - mk_t_err(pos(Type), Msg); mk_error({event_0_to_3_indexed_values, Constr}) -> Msg = io_lib:format("The event constructor ~s (at ~s) has too many indexed values (max 3)\n", [name(Constr), pp_loc(Constr)]), @@ -2398,10 +2406,14 @@ mk_error({namespace, _Pos, {con, Pos, Name}, _Def}) -> Msg = io_lib:format("Nested namespace not allowed\nNamespace '~s' at ~s not defined at top level.\n", [Name, pp_loc(Pos)]), mk_t_err(pos(Pos), Msg); -mk_error({repeated_arg, Fun, Arg}) -> - Msg = io_lib:format("Repeated argument ~s to function ~s (at ~s).\n", - [Arg, pp(Fun), pp_loc(Fun)]), - mk_t_err(pos(Fun), Msg); +mk_error({type_decl, _, {id, Pos, Name}, _}) -> + Msg = io_lib:format("Empty type declarations are not supported\nType ~s at ~s lacks a definition\n", + [Name, pp_loc(Pos)]), + mk_t_err(pos(Pos), Msg); +mk_error({letval, _Pos, {id, Pos, Name}, _Def}) -> + Msg = io_lib:format("Toplevel \"let\" definitions are not supported\nValue ~s at ~s could be replaced by 0-argument function\n", + [Name, pp_loc(Pos)]), + mk_t_err(pos(Pos), Msg); mk_error({stateful_not_allowed, Id, Fun}) -> Msg = io_lib:format("Cannot reference stateful function ~s (at ~s)\nin the definition of non-stateful function ~s.\n", [pp(Id), pp_loc(Id), pp(Fun)]), diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index eb27e16..50ea216 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -291,7 +291,6 @@ decls_to_fcode(Env, Decls) -> end, Env1, Decls). -spec decl_to_fcode(env(), aeso_syntax:decl()) -> env(). -decl_to_fcode(Env, {type_decl, _, _, _}) -> Env; decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, _, Id, _}) -> case is_no_code(Env) of false -> fcode_error({missing_definition, Id}); diff --git a/src/aeso_syntax.erl b/src/aeso_syntax.erl index 61011da..30d4d67 100644 --- a/src/aeso_syntax.erl +++ b/src/aeso_syntax.erl @@ -37,20 +37,24 @@ -type decl() :: {contract, ann(), con(), [decl()]} | {namespace, ann(), con(), [decl()]} | {pragma, ann(), pragma()} - | {type_decl, ann(), id(), [tvar()]} + | {type_decl, ann(), id(), [tvar()]} % Only for error msgs | {type_def, ann(), id(), [tvar()], typedef()} | {fun_decl, ann(), id(), type()} | {fun_clauses, ann(), id(), type(), [letbind()]} | {block, ann(), [decl()]} - | letbind(). + | letfun() + | letval(). % Only for error msgs -type compiler_version() :: [non_neg_integer()]. -type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}. + +-type letval() :: {letval, ann(), pat(), expr()}. +-type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}. -type letbind() - :: {letval, ann(), pat(), expr()} - | {letfun, ann(), id(), [pat()], type(), expr()}. + :: letfun() + | letval(). -type arg() :: {arg, ann(), id(), type()}. diff --git a/src/aeso_syntax_utils.erl b/src/aeso_syntax_utils.erl index 71c7c90..deef257 100644 --- a/src/aeso_syntax_utils.erl +++ b/src/aeso_syntax_utils.erl @@ -45,7 +45,6 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) -> %% decl() {contract, _, _, Ds} -> Decl(Ds); {namespace, _, _, Ds} -> Decl(Ds); - {type_decl, _, I, _} -> BindType(I); {type_def, _, I, _, D} -> Plus(BindType(I), Decl(D)); {fun_decl, _, _, T} -> Type(T); {letval, _, P, E} -> Scoped(BindExpr(P), Expr(E)); diff --git a/test/contracts/05_greeter.aes b/test/contracts/05_greeter.aes index 04ee5fd..1b83716 100644 --- a/test/contracts/05_greeter.aes +++ b/test/contracts/05_greeter.aes @@ -58,8 +58,7 @@ contract Greeter = let state = { greeting = "Hello" } - let setGreeting = - (greeting: string) => + function setGreeting(greeting: string) = state{ greeting = greeting } diff --git a/test/contracts/all_syntax.aes b/test/contracts/all_syntax.aes index a88bae8..26e3ab3 100644 --- a/test/contracts/all_syntax.aes +++ b/test/contracts/all_syntax.aes @@ -1,44 +1,78 @@ // Try to cover all syntactic constructs. +@compiler > 0 +@compiler =< 10.1.1.1.1.1.2.3.4 contract AllSyntaxType = - type typeDecl /* bla */ - type paramTypeDecl('a, 'b) - /** Multi- * line * comment */ function foo : _ + entrypoint bar : int => (int * 'a) +/* +namespace Ns = + datatype d('a) = D | S(int) | M('a, list('a), int) + private function f() = 123 + entrypoint + f : (int, 'a) => ('a * 'b) => 'a + f (1, x) = (_) => x + f (_, _) = (t : 'a * 'b) => switch(t) + (l, r) => l + _ => abort("tuple exploit") contract AllSyntax = - type typeDecl = int - type paramTypeDecl('a, 'b) = (('a, 'b) => 'b) => list('a) => 'b => 'b + datatype mickiewicz = Adam | Mickiewicz + record goethe('a, 'b) = { + johann : int, + wolfgang : 'a, + von : 'a * 'b * int, + goethe : unit + } + type dante = Ns.d(int) + type shakespeare('a) = goethe('a, 'a) - record nestedRecord = { x : int } - record recordType = { z : nestedRecord, y : int } - datatype variantType('a) = None | Some('a) + type state = shakespeare(int) - let valWithType : map(int, int) => option(int) = (m) => Map.get(m, 42) - let valNoType = - if(valWithType(Map.empty) == None) - print(42 mod 10 * 5 / 3) + entrypoint init() = { + johann = 1000, + wolfgang = -10, + von = (2 + 2, 0, List.sum([x | k <- [1,2,3] + , let l = k + 1 + , if(l < 10) + , let f(x) = x + 100 + , Adam <- [Adam, Mickiewicz] + , let x = f(l) + ])), + goethe = () } - function funWithType(x : int, y) : int * list(int) = (x, 0 :: [y] ++ []) - function funNoType() = - let foo = (x, y : bool) => - if (! (y && x =< 0x0b || true)) [x] - else [11..20] - let setY(r : recordType) : unit = r{ y = 5 } - let setX(r : recordType, x : int) : recordType = r { z.x = x } // nested record update - let getY(r) = switch(r) {y = y} => y - switch (funWithType(1, -2)) - (x, [y, z]) => bar({x = z, y = -y + - -z * (-1)}) - (x, y :: _) => () + function f() = + let p = "Пушкин" + let k(x : bytes(8)) : bytes(8) = Bytes.to_int(#fedcba9876543210) - let hash : address = #01ab0fff11 - let b = false - let qcon = Mod.Con - let str = "blabla\nfoo" - let chr = '"' + let f : () => address = () => ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt + if(Bits.test(Bits.all, 10)) + abort("ohno") + if(true && false) + require(true, "ohyes") + elif(false || 2 == 2) + () + else + () + if(true) f(1,2)((1,2)) + else switch(1::[1,2,3]) + [] => 1 + a::b => 123 + 1::2::3 => 123123 + [2,3,4] => 1 + _ => 13 + 1::[2] => 2138 + put(state{johann = 1}) + let m = {["foo"] = 19, /*hey wanna talk about inlined comments?*/ ["bar"] = 42} + let n = {} + m{ ["x" = 0] @ z = z + state.johann } + let sh : shakespeare(shakespeare(int)) = + {wolfgang = state} + sh{wolfgang.wolfgang = sh.wolfgang} // comment +/* \ No newline at end of file diff --git a/test/contracts/multi_sig.aes b/test/contracts/multi_sig.aes index cb1363f..f6ae20b 100644 --- a/test/contracts/multi_sig.aes +++ b/test/contracts/multi_sig.aes @@ -15,7 +15,7 @@ contract MultiSig = | OwnerRemoved (address) // of { .removedOwner : Address } | ReqChanged (int) // of { .newReq : int } - let maxOwners : int = 250 + function maxOwners() : int = 250 record state = { nRequired : int , nOwners : int @@ -68,7 +68,7 @@ contract MultiSig = switch(check_pending(callhash())) CheckFail(state') => { state = state' } CheckOk(state') => - if(state.nOwners >= maxOwners) () /* TODO */ + if(state.nOwners >= maxOwners()) () /* TODO */ else let nOwners' = state'.nOwners + 1 { state = state' { owners = Map.insert(nOwners', newOwner, state'.owners) diff --git a/test/contracts/voting.aes b/test/contracts/voting.aes index d786f6d..2a5ec05 100644 --- a/test/contracts/voting.aes +++ b/test/contracts/voting.aes @@ -1,16 +1,3 @@ - -/* Contract type */ -contract VotingType = - type state - function init : list(string) => state - - function giveRightToVote : address => unit - function delegate : address => unit - function vote : int => unit - function winnerName : unit => string - function currentTally : unit => list(string * int) - -/* Contract implementation */ contract Voting = // Types