From 4f554acee6109a12b3d38e298f3396866ff522d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Rowicki?= <35342116+radrow@users.noreply.github.com> Date: Mon, 30 Mar 2020 14:52:16 +0200 Subject: [PATCH] Fix error messages for some illegal constructions, fix absolute path includes (#251) * Updated tests, banned type decls and toplevel letvals * Properly ban nested contracts * Fix including by path * Fix error message test * Fix prettpr attr display. Make dialyzer happy * More tests * Fixed type printing * Updated docs --- docs/sophia.md | 18 +++- src/aeso_ast_infer_types.erl | 44 ++++++--- src/aeso_ast_to_fcode.erl | 1 - src/aeso_compiler.erl | 4 +- src/aeso_parser.erl | 10 +- src/aeso_pretty.erl | 21 +++-- src/aeso_syntax.erl | 12 ++- src/aeso_syntax_utils.erl | 1 - test/aeso_compiler_tests.erl | 52 ++++++++++- test/contracts/05_greeter.aes | 3 +- test/contracts/all_syntax.aes | 92 +++++++++++++------ test/contracts/bad_arity.aes | 4 + .../bad_unnamed_map_update_default.aes | 5 + test/contracts/empty_typedecl.aes | 3 + test/contracts/higher_kinded_type.aes | 3 + test/contracts/multi_sig.aes | 4 +- test/contracts/non_functional_entrypoint.aes | 5 + test/contracts/not_toplevel_contract.aes | 6 ++ test/contracts/not_toplevel_include.aes | 5 + ..._and_ns.aes => not_toplevel_namespace.aes} | 3 +- test/contracts/toplevel_let.aes | 3 + test/contracts/voting.aes | 13 --- 22 files changed, 224 insertions(+), 88 deletions(-) create mode 100644 test/contracts/bad_arity.aes create mode 100644 test/contracts/bad_unnamed_map_update_default.aes create mode 100644 test/contracts/empty_typedecl.aes create mode 100644 test/contracts/higher_kinded_type.aes create mode 100644 test/contracts/non_functional_entrypoint.aes create mode 100644 test/contracts/not_toplevel_contract.aes create mode 100644 test/contracts/not_toplevel_include.aes rename test/contracts/{bad_include_and_ns.aes => not_toplevel_namespace.aes} (62%) create mode 100644 test/contracts/toplevel_let.aes diff --git a/docs/sophia.md b/docs/sophia.md index 3195870..8640b4e 100644 --- a/docs/sophia.md +++ b/docs/sophia.md @@ -446,6 +446,13 @@ Example syntax: // yields [12,13,14,20,21,22,30,31,32] ``` +Lists can be constructed using the range syntax using special `..` operator: +``` +[1..4] == [1,2,3,4] +``` +The ranges are always ascending and have step equal to 1. + + Please refer to the [standard library](sophia_stdlib.md#List) for the predefined functionalities. ### Maps and records @@ -825,15 +832,17 @@ In describing the syntax below, we use the following conventions: A Sophia file consists of a sequence of *declarations* in a layout block. ```c -File ::= Block(Decl) -Decl ::= ['payable'] 'contract' Con '=' Block(Decl) +File ::= Block(TopDecl) + +TopDecl ::= ['payable'] 'contract' Con '=' Block(Decl) | 'namespace' Con '=' Block(Decl) | '@compiler' PragmaOp Version | 'include' String - | 'type' Id ['(' TVar* ')'] ['=' TypeAlias] + +Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias | 'record' Id ['(' TVar* ')'] '=' RecordType | 'datatype' Id ['(' TVar* ')'] '=' DataType - | EModifier* ('entrypoint' | 'function') Block(FunDecl) + | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl) FunDecl ::= Id ':' Type // Type signature | Id Args [':' Type] '=' Block(Stmt) // Definition @@ -945,6 +954,7 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x + | '[' Sep(Expr, ',') ']' // List [1, 2, 3] | '[' Expr '|' Sep(Generator, ',') ']' // List comprehension [k | x <- [1], if (f(x)), let k = x+1] + | '[' Expr '..' Expr ']' // List range [1..n] | '{' Sep(FieldUpdate, ',') '}' // Record or map value {x = 0, y = 1}, {[key] = val} | '(' Expr ')' // Parens (1 + 2) * 3 | Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 868329c..950131c 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -2262,6 +2262,24 @@ 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 a higher kinded type variable\n" + "(takes another type as an 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("~s at ~s was declared with an invalid type ~s.\n" + "Entrypoints and functions must have functional types" + , [pp(Id), pp_loc(Id), pp(instantiate(Type))]), + 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 +2362,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)]), @@ -2395,13 +2405,21 @@ mk_error({include, _, {string, Pos, Name}}) -> [binary_to_list(Name), pp_loc(Pos)]), mk_t_err(pos(Pos), Msg); 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", + Msg = io_lib:format("Nested namespaces are not allowed\nNamespace '~s' at ~s not defined at top level.\n", + [Name, pp_loc(Pos)]), + mk_t_err(pos(Pos), Msg); +mk_error({contract, _Pos, {con, Pos, Name}, _Def}) -> + Msg = io_lib:format("Nested contracts are not allowed\nContract '~s' at ~s not defined at top level.\n", + [Name, pp_loc(Pos)]), + mk_t_err(pos(Pos), 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({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({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_compiler.erl b/src/aeso_compiler.erl index c677119..ae25a65 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -336,12 +336,12 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) -> try {ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))} catch throw:cannot_translate_to_sophia -> - Type1 = prettypr:format(aeso_pretty:type(Type)), + Type1 = prettypr:format(aeso_pretty:type(Type0)), Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s\n", [aeb_fate_encoding:deserialize(Data), Type1]), {error, [aeso_errors:new(data_error, Msg)]}; _:_ -> - Type1 = prettypr:format(aeso_pretty:type(Type)), + Type1 = prettypr:format(aeso_pretty:type(Type0)), Msg = io_lib:format("Failed to decode binary as type ~s\n", [Type1]), {error, [aeso_errors:new(data_error, Msg)]} end diff --git a/src/aeso_parser.erl b/src/aeso_parser.erl index 74a329c..16212ce 100644 --- a/src/aeso_parser.erl +++ b/src/aeso_parser.erl @@ -656,8 +656,14 @@ stdlib_options() -> get_include_code(File, Ann, Opts) -> case {read_file(File, Opts), read_file(File, stdlib_options())} of - {{ok, _}, {ok,_ }} -> - fail(ann_pos(Ann), "Illegal redefinition of standard library " ++ File); + {{ok, Bin}, {ok, _}} -> + case filename:basename(File) == File of + true -> { error + , fail( ann_pos(Ann) + , "Illegal redefinition of standard library " ++ binary_to_list(File))}; + %% If a path is provided then the stdlib takes lower priority + false -> {ok, binary_to_list(Bin)} + end; {_, {ok, Bin}} -> {ok, binary_to_list(Bin)}; {{ok, Bin}, _} -> diff --git a/src/aeso_pretty.erl b/src/aeso_pretty.erl index bf00107..ac80edb 100644 --- a/src/aeso_pretty.erl +++ b/src/aeso_pretty.erl @@ -145,8 +145,12 @@ decl(D, Options) -> with_options(Options, fun() -> decl(D) end). -spec decl(aeso_syntax:decl()) -> doc(). -decl({contract, _, C, Ds}) -> - block(follow(text("contract"), hsep(name(C), text("="))), decls(Ds)); +decl({contract, Attrs, C, Ds}) -> + Mod = fun({Mod, true}) when Mod == payable -> + text(atom_to_list(Mod)); + (_) -> empty() end, + block(follow( hsep(lists:map(Mod, Attrs) ++ [text("contract")]) + , hsep(name(C), text("="))), decls(Ds)); decl({namespace, _, C, Ds}) -> block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds)); decl({pragma, _, Pragma}) -> pragma(Pragma); @@ -155,13 +159,16 @@ decl({type_def, _, T, Vars, Def}) -> Kind = element(1, Def), equals(typedecl(Kind, T, Vars), typedef(Def)); decl({fun_decl, Ann, F, T}) -> + Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable -> + text(atom_to_list(Mod)); + (_) -> empty() end, Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of true -> text("entrypoint"); false -> text("function") end, - hsep(Fun, typed(name(F), T)); + hsep(lists:map(Mod, Ann) ++ [Fun, typed(name(F), T)]); decl(D = {letfun, Attrs, _, _, _, _}) -> - Mod = fun({Mod, true}) when Mod == private; Mod == stateful -> + Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable -> text(atom_to_list(Mod)); (_) -> empty() end, Fun = case aeso_syntax:get_ann(entrypoint, Attrs, false) of @@ -364,7 +371,8 @@ expr_p(_, {Type, _, Bin}) Type == oracle_query_id -> text(binary_to_list(aeser_api_encoder:encode(Type, Bin))); expr_p(_, {string, _, <<>>}) -> text("\"\""); -expr_p(_, {string, _, S}) -> term(binary_to_list(S)); +expr_p(_, {string, _, S}) -> + text(io_lib:format("\"~s\"", [binary_to_list(S)])); expr_p(_, {char, _, C}) -> case C of $' -> text("'\\''"); @@ -486,6 +494,3 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) -> end; get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}. -fmt(Fmt, Args) -> text(lists:flatten(io_lib:format(Fmt, Args))). -term(X) -> fmt("~p", [X]). - 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/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index ec75032..c6f5b9f 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -375,11 +375,15 @@ failing_contracts() -> " r.foo : (gas : int, value : int) => Remote.themap\n" "against the expected type\n" " (gas : int, value : int) => map(string, int)">>]) - , ?TYPE_ERROR(bad_include_and_ns, - [<>, - <>]) + , ?TYPE_ERROR(not_toplevel_include, + [<>]) + , ?TYPE_ERROR(not_toplevel_namespace, + [<>]) + , ?TYPE_ERROR(not_toplevel_contract, + [<>]) , ?TYPE_ERROR(bad_address_literals, [< [<>]) + , ?TYPE_ERROR(toplevel_let, + [<>]) + , ?TYPE_ERROR(empty_typedecl, + [<>]) + , ?TYPE_ERROR(higher_kinded_type, + [<>]) + , ?TYPE_ERROR(bad_arity, + [<>, + <>, + <>, + <>]) + , ?TYPE_ERROR(bad_unnamed_map_update_default, + [<>]) + , ?TYPE_ERROR(non_functional_entrypoint, + [<>]) , ?TYPE_ERROR(bad_records, [< + function setGreeting(greeting: string) = state{ greeting = greeting } diff --git a/test/contracts/all_syntax.aes b/test/contracts/all_syntax.aes index a88bae8..6a40f27 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) +namespace Ns = + datatype d('a) = D | S(int) | M('a, list('a), int) + private function fff() = 123 + + stateful entrypoint + f (1, x) = (_) => x + +payable contract AllSyntaxType = /** Multi- * line * comment */ - function foo : _ + stateful function foo : _ + entrypoint bar : int => (int * 'a) + 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 kp = "nietzsche" + 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 diff --git a/test/contracts/bad_arity.aes b/test/contracts/bad_arity.aes new file mode 100644 index 0000000..0f02b14 --- /dev/null +++ b/test/contracts/bad_arity.aes @@ -0,0 +1,4 @@ +contract C = + type id('a) = 'a + entrypoint f() : id = 123 + entrypoint g() : id(int, int) = 123 \ No newline at end of file diff --git a/test/contracts/bad_unnamed_map_update_default.aes b/test/contracts/bad_unnamed_map_update_default.aes new file mode 100644 index 0000000..7eb39c1 --- /dev/null +++ b/test/contracts/bad_unnamed_map_update_default.aes @@ -0,0 +1,5 @@ +contract C = + entrypoint f() = + let z = 123 + {}{ [1 = 0] = z + 1 } + 2 \ No newline at end of file diff --git a/test/contracts/empty_typedecl.aes b/test/contracts/empty_typedecl.aes new file mode 100644 index 0000000..51b0286 --- /dev/null +++ b/test/contracts/empty_typedecl.aes @@ -0,0 +1,3 @@ +contract C = + type t + entrypoint f() = 123 \ No newline at end of file diff --git a/test/contracts/higher_kinded_type.aes b/test/contracts/higher_kinded_type.aes new file mode 100644 index 0000000..2f71537 --- /dev/null +++ b/test/contracts/higher_kinded_type.aes @@ -0,0 +1,3 @@ +contract IWantToBelieve = + type stateT('s, 'm, 'a) = 's => 'm('a * 's) + entrypoint s() = 123 \ 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/non_functional_entrypoint.aes b/test/contracts/non_functional_entrypoint.aes new file mode 100644 index 0000000..4162e38 --- /dev/null +++ b/test/contracts/non_functional_entrypoint.aes @@ -0,0 +1,5 @@ +contract C1 = + entrypoint f : int + +contract C = + entrypoint f() = 123 \ No newline at end of file diff --git a/test/contracts/not_toplevel_contract.aes b/test/contracts/not_toplevel_contract.aes new file mode 100644 index 0000000..4d2c579 --- /dev/null +++ b/test/contracts/not_toplevel_contract.aes @@ -0,0 +1,6 @@ +namespace BadNs = + contract Con = + entrypoint e : () => int + +contract Con = + entrypoint foo() = 43 diff --git a/test/contracts/not_toplevel_include.aes b/test/contracts/not_toplevel_include.aes new file mode 100644 index 0000000..0b08c88 --- /dev/null +++ b/test/contracts/not_toplevel_include.aes @@ -0,0 +1,5 @@ +namespace BadNs = + include "included.aes" + +contract Con = + entrypoint foo() = 43 diff --git a/test/contracts/bad_include_and_ns.aes b/test/contracts/not_toplevel_namespace.aes similarity index 62% rename from test/contracts/bad_include_and_ns.aes rename to test/contracts/not_toplevel_namespace.aes index 42ebe67..df27823 100644 --- a/test/contracts/bad_include_and_ns.aes +++ b/test/contracts/not_toplevel_namespace.aes @@ -1,5 +1,4 @@ -contract Bad = - include "included.aes" +contract BadCon = namespace Foo = function foo() = 42 diff --git a/test/contracts/toplevel_let.aes b/test/contracts/toplevel_let.aes new file mode 100644 index 0000000..adca04c --- /dev/null +++ b/test/contracts/toplevel_let.aes @@ -0,0 +1,3 @@ +contract C = + let this_is_illegal = 2/0 + entrypoint this_is_legal() = 2/0 \ No newline at end of file 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