diff --git a/src/aeso_aci.erl b/src/aeso_aci.erl index 24c6f49..5a1a509 100644 --- a/src/aeso_aci.erl +++ b/src/aeso_aci.erl @@ -21,6 +21,8 @@ , json_encode_expr/1 , json_encode_type/1]). +-include("aeso_utils.hrl"). + -type aci_type() :: json | string. -type json() :: jsx:json_term(). -type json_text() :: binary(). @@ -68,9 +70,7 @@ do_contract_interface(Type, Contract, Options) when is_binary(Contract) -> do_contract_interface(Type, ContractString, Options) -> try Ast = aeso_compiler:parse(ContractString, Options), - %% io:format("~p\n", [Ast]), {TypedAst, _} = aeso_ast_infer_types:infer(Ast, [dont_unfold | Options]), - %% io:format("~p\n", [TypedAst]), from_typed_ast(Type, TypedAst) catch throw:{error, Errors} -> {error, Errors} @@ -83,7 +83,7 @@ from_typed_ast(Type, TypedAst) -> string -> do_render_aci_json(JArray) end. -encode_contract(Contract = {contract, _, {con, _, Name}, _}) -> +encode_contract(Contract = {Head, _, {con, _, Name}, _}) when ?IS_CONTRACT_HEAD(Head) -> C0 = #{name => encode_name(Name)}, Tdefs0 = [ encode_typedef(T) || T <- sort_decls(contract_types(Contract)) ], @@ -107,7 +107,7 @@ encode_contract(Contract = {contract, _, {con, _, Name}, _}) -> || F <- sort_decls(contract_funcs(Contract)), is_entrypoint(F) ], - #{contract => C3#{functions => Fdefs, payable => is_payable(Contract)}}; + #{contract => C3#{kind => Head, functions => Fdefs, payable => is_payable(Contract)}}; encode_contract(Namespace = {namespace, _, {con, _, Name}, _}) -> Tdefs = [ encode_typedef(T) || T <- sort_decls(contract_types(Namespace)) ], #{namespace => #{name => encode_name(Name), @@ -232,13 +232,19 @@ do_render_aci_json(Json) -> {ok, list_to_binary(string:join(DecodedContracts, "\n"))}. decode_contract(#{contract := #{name := Name, + kind := Kind, payable := Payable, type_defs := Ts0, functions := Fs} = C}) -> MkTDef = fun(N, T) -> #{name => N, vars => [], typedef => T} end, Ts = [ MkTDef(<<"state">>, maps:get(state, C)) || maps:is_key(state, C) ] ++ [ MkTDef(<<"event">>, maps:get(event, C)) || maps:is_key(event, C) ] ++ Ts0, - [payable(Payable), "contract ", io_lib:format("~s", [Name])," =\n", + [payable(Payable), case Kind of + contract_main -> "main contract "; + contract_child -> "contract "; + contract_interface -> "contract interface " + end, + io_lib:format("~s", [Name])," =\n", decode_tdefs(Ts), decode_funcs(Fs)]; decode_contract(#{namespace := #{name := Name, type_defs := Ts}}) when Ts /= [] -> ["namespace ", io_lib:format("~s", [Name])," =\n", @@ -332,10 +338,10 @@ payable(false) -> "". %% #contract{Ann, Con, [Declarations]}. -contract_funcs({C, _, _, Decls}) when C == contract; C == namespace -> +contract_funcs({C, _, _, Decls}) when ?IS_CONTRACT_HEAD(C); C == namespace -> [ D || D <- Decls, is_fun(D)]. -contract_types({C, _, _, Decls}) when C == contract; C == namespace -> +contract_types({C, _, _, Decls}) when ?IS_CONTRACT_HEAD(C); C == namespace -> [ D || D <- Decls, is_type(D) ]. is_fun({letfun, _, _, _, _, _}) -> true; diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 8755cb1..3f8c3ce 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -18,6 +18,8 @@ , pp_type/2 ]). +-include("aeso_utils.hrl"). + -type utype() :: {fun_t, aeso_syntax:ann(), named_args_t(), [utype()], utype()} | {app_t, aeso_syntax:ann(), utype(), [utype()]} | {tuple_t, aeso_syntax:ann(), [utype()]} @@ -123,7 +125,7 @@ , in_pattern = false :: boolean() , stateful = false :: boolean() , current_function = none :: none | aeso_syntax:id() - , what = top :: top | namespace | contract | main_contract + , what = top :: top | namespace | contract | contract_interface }). -type env() :: #env{}. @@ -191,9 +193,9 @@ bind_fun(X, Type, Env) -> force_bind_fun(X, Type, Env = #env{ what = What }) -> Ann = aeso_syntax:get_ann(Type), NoCode = get_option(no_code, false), - Entry = if X == "init", What == main_contract, not NoCode -> + Entry = if X == "init", What == contract, not NoCode -> {reserved_init, Ann, Type}; - What == contract -> {contract_fun, Ann, Type}; + What == contract_interface -> {contract_fun, Ann, Type}; true -> {Ann, Type} end, on_current_scope(Env, fun(Scope = #scope{ funs = Funs }) -> @@ -261,13 +263,21 @@ contract_call_type({fun_t, Ann, [], Args, Ret}) -> Args, {if_t, Ann, Id("protected"), {app_t, Ann, {id, Ann, "option"}, [Ret]}, Ret}}. -spec bind_contract(aeso_syntax:decl(), env()) -> env(). -bind_contract({contract, Ann, Id, Contents}, Env) -> +bind_contract({Contract, Ann, Id, Contents}, Env) + when ?IS_CONTRACT_HEAD(Contract) -> Key = name(Id), Sys = [{origin, system}], - Fields = [ {field_t, AnnF, Entrypoint, contract_call_type(Type)} - || {fun_decl, AnnF, Entrypoint, Type} <- Contents ] ++ - %% Predefined fields - [ {field_t, Sys, {id, Sys, "address"}, {id, Sys, "address"}} ], + Fields = + [ {field_t, AnnF, Entrypoint, contract_call_type(Type)} + || {fun_decl, AnnF, Entrypoint, Type} <- Contents ] ++ + [ {field_t, AnnF, Entrypoint, + contract_call_type( + {fun_t, AnnF, [], [ArgT || ArgT <- if is_list(Args) -> Args; true -> [Args] end], RetT}) + } + || {letfun, AnnF, Entrypoint, _Named, Args, {typed, _, _, RetT}} <- Contents + ] ++ + %% Predefined fields + [ {field_t, Sys, {id, Sys, "address"}, {id, Sys, "address"}} ], FieldInfo = [ {Entrypoint, #field_info{ ann = FieldAnn, kind = contract, field_t = Type, @@ -463,6 +473,7 @@ global_env() -> {"block_height", Int}, {"difficulty", Int}, {"gas_limit", Int}, + {"bytecode_hash", Fun1(Address, Option(Hash))}, %% Tx constructors {"GAMetaTx", Fun([Address, Int], GAMetaTx)}, {"PayingForTx", Fun([Address, Int], PayForTx)}, @@ -701,7 +712,10 @@ infer(Contracts, Options) -> create_options(Options), ets_new(type_vars, [set]), check_modifiers(Env, Contracts), - {Env1, Decls} = infer1(Env, Contracts, [], Options), + create_type_errors(), + Contracts1 = identify_main_contract(Contracts), + destroy_and_report_type_errors(Env), + {Env1, Decls} = infer1(Env, Contracts1, [], Options), {Env2, DeclsFolded, DeclsUnfolded} = case proplists:get_value(dont_unfold, Options, false) of true -> {Env1, Decls, Decls}; @@ -719,12 +733,16 @@ infer(Contracts, Options) -> -spec infer1(env(), [aeso_syntax:decl()], [aeso_syntax:decl()], list(option())) -> {env(), [aeso_syntax:decl()]}. infer1(Env, [], Acc, _Options) -> {Env, lists:reverse(Acc)}; -infer1(Env, [{contract, Ann, ConName, Code} | Rest], Acc, Options) -> +infer1(Env, [{Contract, Ann, ConName, Code} | Rest], Acc, Options) + when ?IS_CONTRACT_HEAD(Contract) -> %% do type inference on each contract independently. check_scope_name_clash(Env, contract, ConName), - What = if Rest == [] -> main_contract; true -> contract end, + What = case aeso_syntax:get_ann(interface, Ann, false) of + true -> contract_interface; + false -> contract + end, {Env1, Code1} = infer_contract_top(push_scope(contract, ConName, Env), What, Code, Options), - Contract1 = {contract, Ann, ConName, Code1}, + Contract1 = {Contract, Ann, ConName, Code1}, Env2 = pop_scope(Env1), Env3 = bind_contract(Contract1, Env2), infer1(Env3, Rest, [Contract1 | Acc], Options); @@ -737,6 +755,26 @@ infer1(Env, [{pragma, _, _} | Rest], Acc, Options) -> %% Pragmas are checked in check_modifiers infer1(Env, Rest, Acc, Options). +%% Checks if the main contract is somehow defined. +%% Performs some basic sorting to make the dependencies more happy. +identify_main_contract(Contracts) -> + Childs = [C || C = {contract_child, _, _, _} <- Contracts], + Mains = [C || C = {contract_main, _, _, _} <- Contracts], + Interfaces = [C || C = {contract_interface, _, _, _} <- Contracts], + Namespaces = [N || N = {namespace, _, _, _} <- Contracts], + case Mains of + [] -> case Childs of + [] -> type_error({main_contract_undefined}); + [{contract_child, Ann, Con, Body}] -> + Interfaces ++ Namespaces ++ + [C || C = {_, _, Con1, _} <- Childs, Con1 /= Con] ++ + [{contract_main, Ann, Con, Body}]; + _ -> type_error({ambiguous_main_contract}) + end; + [_] -> Interfaces ++ Namespaces ++ Childs ++ Mains; + _ -> type_error({multiple_main_contracts}) + end. + check_scope_name_clash(Env, Kind, Name) -> case get_scope(Env, qname(Name)) of false -> ok; @@ -746,7 +784,7 @@ check_scope_name_clash(Env, Kind, Name) -> destroy_and_report_type_errors(Env) end. --spec infer_contract_top(env(), main_contract | contract | namespace, [aeso_syntax:decl()], list(option())) -> +-spec infer_contract_top(env(), contract_interface | contract | namespace, [aeso_syntax:decl()], list(option())) -> {env(), [aeso_syntax:decl()]}. infer_contract_top(Env, Kind, Defs0, Options) -> create_type_errors(), @@ -756,7 +794,7 @@ infer_contract_top(Env, Kind, Defs0, Options) -> %% infer_contract takes a proplist mapping global names to types, and %% a list of definitions. --spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()], list(option())) -> {env(), [aeso_syntax:decl()]}. +-spec infer_contract(env(), contract_interface | contract | namespace, [aeso_syntax:decl()], list(option())) -> {env(), [aeso_syntax:decl()]}. infer_contract(Env0, What, Defs0, Options) -> create_type_errors(), Defs01 = process_blocks(Defs0), @@ -772,19 +810,19 @@ infer_contract(Env0, What, Defs0, Options) -> ({fun_decl, _, _, _}) -> prototype; (_) -> unexpected end, - Get = fun(K) -> [ Def || Def <- Defs, Kind(Def) == K ] end, - {Env1, TypeDefs} = check_typedefs(Env, Get(type)), + Get = fun(K, In) -> [ Def || Def <- In, Kind(Def) == K ] end, + {Env1, TypeDefs} = check_typedefs(Env, Get(type, Defs)), create_type_errors(), - check_unexpected(Get(unexpected)), + check_unexpected(Get(unexpected, Defs)), Env2 = case What of - namespace -> Env1; - contract -> Env1; - main_contract -> bind_state(Env1) %% bind state and put + namespace -> Env1; + contract_interface -> Env1; + contract -> bind_state(Env1) %% bind state and put end, - {ProtoSigs, Decls} = lists:unzip([ check_fundecl(Env1, Decl) || Decl <- Get(prototype) ]), + {ProtoSigs, Decls} = lists:unzip([ check_fundecl(Env1, Decl) || Decl <- Get(prototype, Defs) ]), Env3 = bind_funs(ProtoSigs, Env2), - Functions = Get(function), + Functions = Get(function, Defs), %% Check for duplicates in Functions (we turn it into a map below) FunBind = fun({letfun, Ann, {id, _, Fun}, _, _, _}) -> {Fun, {tuple_t, Ann, []}}; ({fun_clauses, Ann, {id, _, Fun}, _, _}) -> {Fun, {tuple_t, Ann, []}} end, @@ -794,11 +832,11 @@ infer_contract(Env0, What, Defs0, Options) -> check_reserved_entrypoints(FunMap), DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Def) end, FunMap), SCCs = aeso_utils:scc(DepGraph), - %% io:format("Dependency sorted functions:\n ~p\n", [SCCs]), {Env4, Defs1} = check_sccs(Env3, FunMap, SCCs, []), %% Check that `init` doesn't read or write the state check_state_dependencies(Env4, Defs1), destroy_and_report_type_errors(Env4), + %% Add inferred types of definitions {Env4, TypeDefs ++ Decls ++ Defs1}. %% Restructure blocks into multi-clause fundefs (`fun_clauses`). @@ -830,9 +868,9 @@ expose_internals(Defs, What) -> [ begin Ann = element(2, Def), NewAnn = case What of - namespace -> [A ||A <- Ann, A /= {private, true}, A /= private]; - main_contract -> [{entrypoint, true}|Ann]; % minor duplication - contract -> Ann + namespace -> [A ||A <- Ann, A /= {private, true}, A /= private]; + contract -> [{entrypoint, true}|Ann]; % minor duplication + contract_interface -> Ann end, Def1 = setelement(2, Def, NewAnn), case Def1 of % fix inner clauses @@ -907,15 +945,16 @@ check_modifiers(Env, Contracts) -> check_modifiers_(Env, Contracts), destroy_and_report_type_errors(Env). -check_modifiers_(Env, [{contract, _, Con, Decls} | Rest]) -> - IsMain = Rest == [], +check_modifiers_(Env, [{Contract, _, Con, Decls} | Rest]) + when ?IS_CONTRACT_HEAD(Contract) -> + IsInterface = Contract =:= contract_interface, check_modifiers1(contract, Decls), case {lists:keymember(letfun, 1, Decls), [ D || D <- Decls, aeso_syntax:get_ann(entrypoint, D, false) ]} of {true, []} -> type_error({contract_has_no_entrypoints, Con}); - _ when not IsMain -> - case [ {Ann, Id} || {letfun, Ann, Id, _, _, _} <- Decls ] of - [{Ann, Id} | _] -> type_error({definition_in_non_main_contract, Ann, Id}); + _ when IsInterface -> + case [ {AnnF, Id} || {letfun, AnnF, Id, _, _, _} <- Decls ] of + [{AnnF, Id} | _] -> type_error({definition_in_contract_interface, AnnF, Id}); [] -> ok end; _ -> ok @@ -2653,7 +2692,7 @@ mk_error({namespace, _Pos, {con, Pos, Name}, _Def}) -> 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}) -> +mk_error({Contract, _Pos, {con, Pos, Name}, _Def}) when ?IS_CONTRACT_HEAD(Contract) -> 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); @@ -2728,8 +2767,8 @@ mk_error({contract_has_no_entrypoints, Con}) -> "contract functions must be declared with the 'entrypoint' keyword instead of\n" "'function'.\n", [pp_expr("", Con), pp_loc(Con)]), mk_t_err(pos(Con), Msg); -mk_error({definition_in_non_main_contract, Ann, {id, _, Id}}) -> - Msg = "Only the main contract can contain defined functions or entrypoints.\n", +mk_error({definition_in_contract_interface, Ann, {id, _, Id}}) -> + Msg = "Contract interfaces cannot contain defined functions or entrypoints.\n", Cxt = io_lib:format("Fix: replace the definition of '~s' by a type signature.\n", [Id]), mk_t_err(pos(Ann), Msg, Cxt); mk_error({unbound_type, Type}) -> @@ -2798,6 +2837,15 @@ mk_error({named_argument_must_be_literal_bool, Name, Arg}) -> mk_error({conflicting_updates_for_field, Upd, Key}) -> Msg = io_lib:format("Conflicting updates for field '~s'\n", [Key]), mk_t_err(pos(Upd), Msg); +mk_error({ambiguous_main_contract}) -> + Msg = "Could not deduce the main contract. You can point it manually with `main` keyword.", + mk_t_err(pos(0, 0), Msg); +mk_error({main_contract_undefined}) -> + Msg = "No contract defined.", + mk_t_err(pos(0, 0), Msg); +mk_error({multiple_main_contracts}) -> + Msg = "Up to one main contract can be defined.", + mk_t_err(pos(0, 0), Msg); mk_error(Err) -> Msg = io_lib:format("Unknown error: ~p\n", [Err]), mk_t_err(pos(0, 0), Msg). diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 07f4e01..27de5b3 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -12,6 +12,8 @@ -export([ast_to_fcode/2, format_fexpr/1]). -export_type([fcode/0, fexpr/0, fun_def/0]). +-include("aeso_utils.hrl"). + %% -- Type definitions ------------------------------------------------------- -type option() :: term(). @@ -136,6 +138,7 @@ -type type_env() :: #{ sophia_name() => type_def() }. -type fun_env() :: #{ sophia_name() => {fun_name(), non_neg_integer()} }. -type con_env() :: #{ sophia_name() => con_tag() }. +-type child_con_env() :: #{sophia_name() => fcode()}. -type builtins() :: #{ sophia_name() => {builtin(), non_neg_integer() | none} }. -type context() :: {main_contract, string()} @@ -144,16 +147,17 @@ -type state_layout() :: {tuple, [state_layout()]} | {reg, state_reg()}. --type env() :: #{ type_env := type_env(), - fun_env := fun_env(), - con_env := con_env(), - event_type => aeso_syntax:typedef(), - builtins := builtins(), - options := [option()], - state_layout => state_layout(), - context => context(), - vars => [var_name()], - functions := #{ fun_name() => fun_def() } }. +-type env() :: #{ type_env := type_env(), + fun_env := fun_env(), + con_env := con_env(), + child_con_env := child_con_env(), + event_type => aeso_syntax:typedef(), + builtins := builtins(), + options := [option()], + state_layout => state_layout(), + context => context(), + vars => [var_name()], + functions := #{ fun_name() => fun_def() } }. -define(HASH_BYTES, 32). @@ -182,6 +186,7 @@ init_env(Options) -> #{ type_env => init_type_env(), fun_env => #{}, builtins => builtins(), + child_con_env => #{}, con_env => #{["None"] => #con_tag{ tag = 0, arities = [0, 1] }, ["Some"] => #con_tag{ tag = 1, arities = [0, 1] }, ["RelativeTTL"] => #con_tag{ tag = 0, arities = [1, 1] }, @@ -308,30 +313,41 @@ get_option(Opt, Env, Default) -> %% -- Compilation ------------------------------------------------------------ -spec to_fcode(env(), aeso_syntax:ast()) -> fcode(). -to_fcode(Env, [{contract, Attrs, MainCon = {con, _, Main}, Decls}]) -> - #{ builtins := Builtins } = Env, - MainEnv = Env#{ context => {main_contract, Main}, - builtins => Builtins#{[Main, "state"] => {get_state, none}, - [Main, "put"] => {set_state, 1}, - [Main, "Chain", "event"] => {chain_event, 1}} }, - #{ functions := Funs } = Env1 = - decls_to_fcode(MainEnv, Decls), - StateType = lookup_type(Env1, [Main, "state"], [], {tuple, []}), - EventType = lookup_type(Env1, [Main, "event"], [], none), - StateLayout = state_layout(Env1), - Payable = proplists:get_value(payable, Attrs, false), - #{ contract_name => Main, - state_type => StateType, - state_layout => StateLayout, - event_type => EventType, - payable => Payable, - functions => add_init_function(Env1, MainCon, StateType, - add_event_function(Env1, EventType, Funs)) }; -to_fcode(_Env, [NotContract]) -> - fcode_error({last_declaration_must_be_contract, NotContract}); -to_fcode(Env, [{contract, _, {con, _, Con}, Decls} | Code]) -> - Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls), - to_fcode(Env1, Code); +to_fcode(Env, [{Contract, Attrs, Con = {con, _, Name}, Decls}|Rest]) + when ?IS_CONTRACT_HEAD(Contract) -> + case Contract =:= contract_interface of + false -> + + #{ builtins := Builtins } = Env, + ConEnv = Env#{ context => {main_contract, Name}, + builtins => Builtins#{[Name, "state"] => {get_state, none}, + [Name, "put"] => {set_state, 1}, + [Name, "Chain", "event"] => {chain_event, 1}} }, + #{ functions := Funs } = Env1 = + decls_to_fcode(ConEnv, Decls), + StateType = lookup_type(Env1, [Name, "state"], [], {tuple, []}), + EventType = lookup_type(Env1, [Name, "event"], [], none), + StateLayout = state_layout(Env1), + Payable = proplists:get_value(payable, Attrs, false), + ConFcode = #{ contract_name => Name, + state_type => StateType, + state_layout => StateLayout, + event_type => EventType, + payable => Payable, + functions => add_init_function(Env1, Con, StateType, + add_event_function(Env1, EventType, Funs)) }, + case Contract of + contract_main -> Rest = [], ConFcode; + contract_child -> + Env2 = add_child_con(Env1, Name, ConFcode), + to_fcode(Env2, Rest) + end; + true -> + Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls), + to_fcode(Env1, Rest) + end; +to_fcode(_Env, [NotMain = {NotMainHead, _ ,_ , _}]) when NotMainHead =/= main_contract -> + fcode_error({last_declaration_must_be_main_contract, NotMain}); to_fcode(Env, [{namespace, _, {con, _, Con}, Decls} | Code]) -> Env1 = decls_to_fcode(Env#{ context => {namespace, Con} }, Decls), to_fcode(Env1, Code). @@ -341,9 +357,7 @@ decls_to_fcode(Env, Decls) -> %% First compute mapping from Sophia names to fun_names and add it to the %% environment. Env1 = add_fun_env(Env, Decls), - lists:foldl(fun(D, E) -> - R = decl_to_fcode(E, D), - R + lists:foldl(fun(D, E) -> decl_to_fcode(E, D) end, Env1, Decls). -spec decl_to_fcode(env(), aeso_syntax:decl()) -> env(). @@ -1614,6 +1628,10 @@ bind_constructors(Env = #{ con_env := ConEnv }, NewCons) -> %% -- Names -- +-spec add_child_con(env(), sophia_name(), fcode()) -> env(). +add_child_con(Env = #{child_con_env := CEnv}, Name, Fcode) -> + Env#{ child_con_env := CEnv#{Name => Fcode} }. + -spec add_fun_env(env(), [aeso_syntax:decl()]) -> env(). add_fun_env(Env = #{ context := {abstract_contract, _} }, _) -> Env; %% no functions from abstract contracts add_fun_env(Env = #{ fun_env := FunEnv }, Decls) -> diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index b1a1874..8cace86 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -14,12 +14,13 @@ -include_lib("aebytecode/include/aeb_opcodes.hrl"). -include("aeso_icode.hrl"). +-include("aeso_utils.hrl"). -spec convert_typed(aeso_syntax:ast(), list()) -> aeso_icode:icode(). convert_typed(TypedTree, Options) -> {Payable, Name} = case lists:last(TypedTree) of - {contract, Attrs, {con, _, Con}, _} -> + {Contr, Attrs, {con, _, Con}, _} when ?IS_CONTRACT_HEAD(Contr) -> {proplists:get_value(payable, Attrs, false), Con}; Decl -> gen_error({last_declaration_must_be_contract, Decl}) @@ -29,7 +30,8 @@ convert_typed(TypedTree, Options) -> Icode = code(TypedTree, NewIcode, Options), deadcode_elimination(Icode). -code([{contract, _Attribs, Con, Code}|Rest], Icode, Options) -> +code([{Contract, _Attribs, Con, Code}|Rest], Icode, Options) + when ?IS_CONTRACT_HEAD(Contract) -> NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Con, Icode)), code(Rest, NewIcode, Options); code([{namespace, _Ann, Name, Code}|Rest], Icode, Options) -> diff --git a/src/aeso_code_errors.erl b/src/aeso_code_errors.erl index 05bc135..bb2568d 100644 --- a/src/aeso_code_errors.erl +++ b/src/aeso_code_errors.erl @@ -10,9 +10,9 @@ -export([format/1, pos/1]). -format({last_declaration_must_be_contract, Decl = {namespace, _, {con, _, C}, _}}) -> - Msg = io_lib:format("Expected a contract as the last declaration instead of the namespace '~s'\n", - [C]), +format({last_declaration_must_be_contract, Decl = {Kind, _, {con, _, C}, _}}) -> + Msg = io_lib:format("Expected a contract as the last declaration instead of the ~p '~s'\n", + [Kind, C]), mk_err(pos(Decl), Msg); format({missing_init_function, Con}) -> Msg = io_lib:format("Missing init function for the contract '~s'.\n", [pp_expr(Con)]), diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 25cb1b9..930c70c 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -28,6 +28,7 @@ -include_lib("aebytecode/include/aeb_opcodes.hrl"). -include("aeso_icode.hrl"). +-include("aeso_utils.hrl"). -type option() :: pp_sophia_code @@ -468,7 +469,7 @@ error_missing_call_function() -> Msg = "Internal error: missing '__call'-function", aeso_errors:throw(aeso_errors:new(internal_error, Msg)). -get_call_type([{contract, _, _, Defs}]) -> +get_call_type([{Contract, _, _, Defs}]) when ?IS_CONTRACT_HEAD(Contract) -> case [ {lists:last(QFunName), FunType} || {letfun, _, {id, _, ?CALL_NAME}, [], _Ret, {typed, _, @@ -482,7 +483,7 @@ get_call_type([_ | Contracts]) -> get_call_type(Contracts). -dialyzer({nowarn_function, get_decode_type/2}). -get_decode_type(FunName, [{contract, Ann, _, Defs}]) -> +get_decode_type(FunName, [{Contract, Ann, _, Defs}]) when ?IS_CONTRACT_HEAD(Contract) -> GetType = fun({letfun, _, {id, _, Name}, Args, Ret, _}) when Name == FunName -> [{Args, Ret}]; ({fun_decl, _, {id, _, Name}, {fun_t, _, _, Args, Ret}}) when Name == FunName -> [{Args, Ret}]; (_) -> [] end, diff --git a/src/aeso_parser.erl b/src/aeso_parser.erl index acb09c6..c29403d 100644 --- a/src/aeso_parser.erl +++ b/src/aeso_parser.erl @@ -93,8 +93,20 @@ decl() -> ?LAZY_P( choice( %% Contract declaration - [ ?RULE(keyword(contract), con(), tok('='), maybe_block(decl()), {contract, _1, _2, _4}) - , ?RULE(token(payable), keyword(contract), con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract, _2, _3, _5})) + [ ?RULE(token(main), keyword(contract), + con(), tok('='), maybe_block(decl()), {contract_main, _2, _3, _5}) + , ?RULE(keyword(contract), + con(), tok('='), maybe_block(decl()), {contract_child, _1, _2, _4}) + , ?RULE(keyword(contract), token(interface), + con(), tok('='), maybe_block(decl()), {contract_interface, _1, _3, _5}) + , ?RULE(token(payable), token(main), keyword(contract), + con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_main, _3, _4, _6})) + , ?RULE(token(payable), keyword(contract), + con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_child, _2, _3, _5})) + , ?RULE(token(payable), keyword(contract), token(interface), + con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_interface, _2, _4, _6})) + + , ?RULE(keyword(namespace), con(), tok('='), maybe_block(decl()), {namespace, _1, _2, _4}) , ?RULE(keyword(include), str(), {include, get_ann(_1), _2}) , pragma() diff --git a/src/aeso_pretty.erl b/src/aeso_pretty.erl index dfbd577..6b43b4c 100644 --- a/src/aeso_pretty.erl +++ b/src/aeso_pretty.erl @@ -13,6 +13,8 @@ -export_type([options/0]). +-include("aeso_utils.hrl"). + -type doc() :: prettypr:document(). -type options() :: [{indent, non_neg_integer()} | show_generated]. @@ -131,6 +133,10 @@ typed(A, Type) -> false -> follow(hsep(A, text(":")), type(Type)) end. +contract_head(contract_main) -> text("main contract"); +contract_head(contract_child) -> text("contract"); +contract_head(contract_interface) -> text("contract interface"). + %% -- Exports ---------------------------------------------------------------- -spec decls([aeso_syntax:decl()], options()) -> doc(). @@ -145,11 +151,11 @@ decl(D, Options) -> with_options(Options, fun() -> decl(D) end). -spec decl(aeso_syntax:decl()) -> doc(). -decl({contract, Attrs, C, Ds}) -> +decl({Con, Attrs, C, Ds}) when ?IS_CONTRACT_HEAD(Con) -> Mod = fun({Mod, true}) when Mod == payable -> text(atom_to_list(Mod)); (_) -> empty() end, - block(follow( hsep(lists:map(Mod, Attrs) ++ [text("contract")]) + block(follow( hsep(lists:map(Mod, Attrs) ++ [contract_head(Con)]) , hsep(name(C), text("="))), decls(Ds)); decl({namespace, _, C, Ds}) -> block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds)); diff --git a/src/aeso_scan.erl b/src/aeso_scan.erl index e81757f..2c5d301 100644 --- a/src/aeso_scan.erl +++ b/src/aeso_scan.erl @@ -44,7 +44,9 @@ lexer() -> , {"[^/*]+|[/*]", skip()} ], Keywords = ["contract", "include", "let", "switch", "type", "record", "datatype", "if", "elif", "else", "function", - "stateful", "payable", "true", "false", "mod", "public", "entrypoint", "private", "indexed", "namespace"], + "stateful", "payable", "true", "false", "mod", "public", "entrypoint", "private", "indexed", "namespace", + "interface", "main" + ], KW = string:join(Keywords, "|"), Rules = diff --git a/src/aeso_syntax.erl b/src/aeso_syntax.erl index 1d01ef0..b48e4ff 100644 --- a/src/aeso_syntax.erl +++ b/src/aeso_syntax.erl @@ -25,7 +25,8 @@ -type ann_origin() :: system | user. -type ann_format() :: '?:' | hex | infix | prefix | elif. --type ann() :: [{line, ann_line()} | {col, ann_col()} | {format, ann_format()} | {origin, ann_origin()} | stateful | private]. +-type ann() :: [ {line, ann_line()} | {col, ann_col()} | {format, ann_format()} | {origin, ann_origin()} + | stateful | private] | payable | main | interface. -type name() :: string(). -type id() :: {id, ann(), name()}. @@ -34,7 +35,9 @@ -type qcon() :: {qcon, ann(), [name()]}. -type tvar() :: {tvar, ann(), name()}. --type decl() :: {contract, ann(), con(), [decl()]} +-type decl() :: {contract_main, ann(), con(), [decl()]} + | {contract_child, ann(), con(), [decl()]} + | {contract_interface, ann(), con(), [decl()]} | {namespace, ann(), con(), [decl()]} | {pragma, ann(), pragma()} | {type_decl, ann(), id(), [tvar()]} % Only for error msgs diff --git a/test/aeso_abi_tests.erl b/test/aeso_abi_tests.erl index 6f1fb02..9306657 100644 --- a/test/aeso_abi_tests.erl +++ b/test/aeso_abi_tests.erl @@ -190,7 +190,7 @@ parameterized_contract(ExtraCode, FunName, Types) -> lists:flatten( ["contract Remote =\n" " entrypoint bla : () => unit\n\n" - "contract Dummy =\n", + "main contract Dummy =\n", ExtraCode, "\n", " type an_alias('a) = string * 'a\n" " record r = {x : an_alias(int), y : variant}\n" diff --git a/test/aeso_calldata_tests.erl b/test/aeso_calldata_tests.erl index c939893..58d66e3 100644 --- a/test/aeso_calldata_tests.erl +++ b/test/aeso_calldata_tests.erl @@ -59,8 +59,8 @@ calldata_aci_test_() -> end} || {ContractName, Fun, Args} <- compilable_contracts()]. parse_args(Fun, Args) -> - [{contract, _, _, [{letfun, _, _, _, _, {app, _, _, AST}}]}] = - aeso_parser:string("contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"), + [{contract_main, _, _, [{letfun, _, _, _, _, {app, _, _, AST}}]}] = + aeso_parser:string("main contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"), strip_ann(AST). strip_ann(T) when is_tuple(T) -> diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index 36e70b4..3e3cfa5 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -179,17 +179,12 @@ compilable_contracts() -> "lhs_matching", "more_strings", "protected_call", - "hermetization_turnoff" + "hermetization_turnoff", + "multiple_contracts" ]. not_compilable_on(fate) -> []; -not_compilable_on(aevm) -> - [ "stdlib_include", "manual_stdlib_include", "pairing_crypto" - , "aens_update", "basic_auth_tx", "more_strings" - , "unapplied_builtins", "bytes_to_x", "state_handling", "protected_call" - , "hermetization_turnoff" - - ]. +not_compilable_on(aevm) -> compilable_contracts(). debug_mode_contracts() -> ["hermetization_turnoff"]. @@ -635,9 +630,9 @@ failing_contracts() -> <>]) - , ?TYPE_ERROR(multiple_contracts, + , ?TYPE_ERROR(interface_with_defs, [<>]) , ?TYPE_ERROR(contract_as_namespace, [< {fate, ?Msg(File, Line, Col, ErrFATE)}]}). failing_code_gen_contracts() -> - [ ?SAME(last_declaration_must_be_contract, 1, 1, - "Expected a contract as the last declaration instead of the namespace 'LastDeclarationIsNotAContract'") - , ?SAME(missing_definition, 2, 14, + [ ?SAME(missing_definition, 2, 14, "Missing definition of function 'foo'.") , ?AEVM(polymorphic_entrypoint, 2, 17, "The argument\n" diff --git a/test/aeso_parser_tests.erl b/test/aeso_parser_tests.erl index c978b0a..f8e2eee 100644 --- a/test/aeso_parser_tests.erl +++ b/test/aeso_parser_tests.erl @@ -12,10 +12,10 @@ simple_contracts_test_() -> fun(_) -> ok end, [{"Parse a contract with an identity function.", fun() -> - Text = "contract Identity =\n" + Text = "main contract Identity =\n" " function id(x) = x\n", ?assertMatch( - [{contract, _, {con, _, "Identity"}, + [{contract_main, _, {con, _, "Identity"}, [{letfun, _, {id, _, "id"}, [{id, _, "x"}], {id, _, "_"}, {id, _, "x"}}]}], parse_string(Text)), ok diff --git a/test/contracts/__call.aes b/test/contracts/__call.aes index 1e19b5b..1f90e04 100644 --- a/test/contracts/__call.aes +++ b/test/contracts/__call.aes @@ -1,5 +1,5 @@ contract Identity = - function main (x:int) = x + function main_fun (x:int) = x function __call() = 12 diff --git a/test/contracts/address_chain.aes b/test/contracts/address_chain.aes index 4c55a45..da5a111 100644 --- a/test/contracts/address_chain.aes +++ b/test/contracts/address_chain.aes @@ -1,5 +1,5 @@ -contract Remote = - entrypoint main : (int) => unit +contract interface Remote = + entrypoint main_fun : (int) => unit contract AddrChain = type o_type = oracle(string, map(string, int)) diff --git a/test/contracts/address_literals.aes b/test/contracts/address_literals.aes index 15007cf..94e7e0c 100644 --- a/test/contracts/address_literals.aes +++ b/test/contracts/address_literals.aes @@ -1,5 +1,5 @@ -contract Remote = +contract interface Remote = entrypoint foo : () => unit contract AddressLiterals = diff --git a/test/contracts/bad_address_literals.aes b/test/contracts/bad_address_literals.aes index 1750846..30eebac 100644 --- a/test/contracts/bad_address_literals.aes +++ b/test/contracts/bad_address_literals.aes @@ -1,5 +1,5 @@ -contract Remote = +contract interface Remote = entrypoint foo : () => unit contract AddressLiterals = diff --git a/test/contracts/bad_protected_call.aes b/test/contracts/bad_protected_call.aes index ba1f59c..9b7cf9d 100644 --- a/test/contracts/bad_protected_call.aes +++ b/test/contracts/bad_protected_call.aes @@ -1,4 +1,4 @@ -contract Remote = +contract interface Remote = entrypoint id : int => int contract ProtectedCall = diff --git a/test/contracts/bad_top_level_decl.aes b/test/contracts/bad_top_level_decl.aes index 5475fb6..e9053aa 100644 --- a/test/contracts/bad_top_level_decl.aes +++ b/test/contracts/bad_top_level_decl.aes @@ -1,3 +1,3 @@ function square(x) = x ^ 2 contract Main = - entrypoint main() = square(10) + entrypoint main_fun() = square(10) diff --git a/test/contracts/code_errors/bad_aens_resolve.aes b/test/contracts/code_errors/bad_aens_resolve.aes index 38d932b..8700dfb 100644 --- a/test/contracts/code_errors/bad_aens_resolve.aes +++ b/test/contracts/code_errors/bad_aens_resolve.aes @@ -5,5 +5,5 @@ contract BadAENSresolve = function fail() : t(int) = AENS.resolve("foo.aet", "whatever") - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/higher_order_map_keys.aes b/test/contracts/code_errors/higher_order_map_keys.aes index a5fa742..98327e2 100644 --- a/test/contracts/code_errors/higher_order_map_keys.aes +++ b/test/contracts/code_errors/higher_order_map_keys.aes @@ -3,4 +3,4 @@ contract MapAsMapKey = function foo(m) : t(int => int) = {[m] = 0} - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/higher_order_query_type.aes b/test/contracts/code_errors/higher_order_query_type.aes index 39d533f..1f4a4e6 100644 --- a/test/contracts/code_errors/higher_order_query_type.aes +++ b/test/contracts/code_errors/higher_order_query_type.aes @@ -2,4 +2,4 @@ contract HigherOrderQueryType = stateful function foo(o) : oracle_query(_, string ) = Oracle.query(o, (x) => x + 1, 100, RelativeTTL(100), RelativeTTL(100)) - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/higher_order_response_type.aes b/test/contracts/code_errors/higher_order_response_type.aes index ae4ec93..87da03c 100644 --- a/test/contracts/code_errors/higher_order_response_type.aes +++ b/test/contracts/code_errors/higher_order_response_type.aes @@ -2,4 +2,4 @@ contract HigherOrderResponseType = stateful function foo(o, q : oracle_query(string, _)) = Oracle.respond(o, q, (x) => x + 1) - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/last_declaration_must_be_contract.aes b/test/contracts/code_errors/last_declaration_must_be_contract.aes deleted file mode 100644 index 1c72d81..0000000 --- a/test/contracts/code_errors/last_declaration_must_be_contract.aes +++ /dev/null @@ -1,2 +0,0 @@ -namespace LastDeclarationIsNotAContract = - function add(x, y) = x + y diff --git a/test/contracts/code_errors/missing_definition.aes b/test/contracts/code_errors/missing_definition.aes index 6f7b919..5e354ec 100644 --- a/test/contracts/code_errors/missing_definition.aes +++ b/test/contracts/code_errors/missing_definition.aes @@ -1,3 +1,3 @@ contract MissingDefinition = entrypoint foo : int => int - entrypoint main() = foo(0) + entrypoint main_fun() = foo(0) diff --git a/test/contracts/code_errors/polymorphic_aens_resolve.aes b/test/contracts/code_errors/polymorphic_aens_resolve.aes index 6301743..0bd9cc8 100644 --- a/test/contracts/code_errors/polymorphic_aens_resolve.aes +++ b/test/contracts/code_errors/polymorphic_aens_resolve.aes @@ -3,5 +3,5 @@ contract PolymorphicAENSresolve = function fail() : option('a) = AENS.resolve("foo.aet", "whatever") - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/polymorphic_map_keys.aes b/test/contracts/code_errors/polymorphic_map_keys.aes index eb64237..9821780 100644 --- a/test/contracts/code_errors/polymorphic_map_keys.aes +++ b/test/contracts/code_errors/polymorphic_map_keys.aes @@ -3,4 +3,4 @@ contract MapAsMapKey = function foo(m) : t('a) = {[m] = 0} - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/polymorphic_query_type.aes b/test/contracts/code_errors/polymorphic_query_type.aes index 4fba99b..0f5d6ab 100644 --- a/test/contracts/code_errors/polymorphic_query_type.aes +++ b/test/contracts/code_errors/polymorphic_query_type.aes @@ -2,4 +2,4 @@ contract PolymorphicQueryType = stateful function is_oracle(o) = Oracle.check(o) - entrypoint main() = () + entrypoint main_fun() = () diff --git a/test/contracts/code_errors/polymorphic_response_type.aes b/test/contracts/code_errors/polymorphic_response_type.aes index 9b33971..3c26af5 100644 --- a/test/contracts/code_errors/polymorphic_response_type.aes +++ b/test/contracts/code_errors/polymorphic_response_type.aes @@ -2,4 +2,4 @@ contract PolymorphicResponseType = function is_oracle(o : oracle(string, 'r)) = Oracle.check(o) - entrypoint main(o : oracle(string, int)) = is_oracle(o) + entrypoint main_fun(o : oracle(string, int)) = is_oracle(o) diff --git a/test/contracts/code_errors/unapplied_contract_call.aes b/test/contracts/code_errors/unapplied_contract_call.aes index 0ef0248..78f5a12 100644 --- a/test/contracts/code_errors/unapplied_contract_call.aes +++ b/test/contracts/code_errors/unapplied_contract_call.aes @@ -1,4 +1,4 @@ -contract Remote = +contract interface Remote = entrypoint foo : int => int contract UnappliedContractCall = diff --git a/test/contracts/code_errors/unapplied_named_arg_builtin.aes b/test/contracts/code_errors/unapplied_named_arg_builtin.aes index 9b0a5ce..ebd2d1a 100644 --- a/test/contracts/code_errors/unapplied_named_arg_builtin.aes +++ b/test/contracts/code_errors/unapplied_named_arg_builtin.aes @@ -1,5 +1,5 @@ contract UnappliedNamedArgBuiltin = // Allowed in FATE, but not AEVM - stateful entrypoint main(s) = + stateful entrypoint main_fun(s) = let reg = Oracle.register reg(signature = s, Contract.address, 100, RelativeTTL(100)) : oracle(int, int) diff --git a/test/contracts/complex_types.aes b/test/contracts/complex_types.aes index 57e19d7..83b9b69 100644 --- a/test/contracts/complex_types.aes +++ b/test/contracts/complex_types.aes @@ -1,5 +1,5 @@ -contract Remote = +contract interface Remote = entrypoint up_to : (int) => list(int) entrypoint sum : (list(int)) => int entrypoint some_string : () => string diff --git a/test/contracts/contract_as_namespace.aes b/test/contracts/contract_as_namespace.aes index 489dfda..ac4de29 100644 --- a/test/contracts/contract_as_namespace.aes +++ b/test/contracts/contract_as_namespace.aes @@ -1,4 +1,4 @@ -contract Foo = +contract interface Foo = entrypoint foo : () => int contract Fail = diff --git a/test/contracts/environment.aes b/test/contracts/environment.aes index d02eec5..a05f5bf 100644 --- a/test/contracts/environment.aes +++ b/test/contracts/environment.aes @@ -1,6 +1,6 @@ // Testing primitives for accessing the block chain environment -contract Interface = +contract interface Interface = entrypoint contract_address : () => address entrypoint call_origin : () => address entrypoint call_caller : () => address diff --git a/test/contracts/events.aes b/test/contracts/events.aes index 74a3393..b63397c 100644 --- a/test/contracts/events.aes +++ b/test/contracts/events.aes @@ -1,4 +1,4 @@ -contract Remote = +contract interface Remote = entrypoint dummy : () => unit contract Events = diff --git a/test/contracts/factorial.aes b/test/contracts/factorial.aes index 88a8869..800ef07 100644 --- a/test/contracts/factorial.aes +++ b/test/contracts/factorial.aes @@ -1,6 +1,6 @@ // An implementation of the factorial function where each recursive // call is to another contract. Not the cheapest way to compute factorial. -contract FactorialServer = +contract interface FactorialServer = entrypoint fac : (int) => int contract Factorial = diff --git a/test/contracts/identity.aes b/test/contracts/identity.aes index cc5eeaf..2a639f6 100644 --- a/test/contracts/identity.aes +++ b/test/contracts/identity.aes @@ -1,3 +1,2 @@ - -contract Identity = - entrypoint main (x:int) = x +main contract Identity = + entrypoint main_fun (x:int) = x diff --git a/test/contracts/lhs_matching.aes b/test/contracts/lhs_matching.aes index 2cafa9d..98dddbb 100644 --- a/test/contracts/lhs_matching.aes +++ b/test/contracts/lhs_matching.aes @@ -16,7 +16,7 @@ contract LHSMatching = let null(_ :: _) = false !null(xs) - entrypoint main() = + entrypoint main_fun() = from_some(Some([0])) ++ append([length([true]), 2, 3], [4, 5, 6]) ++ [7 | if (local_match([false]))] diff --git a/test/contracts/missing_event_type.aes b/test/contracts/missing_event_type.aes index 8931c5e..745fcf4 100644 --- a/test/contracts/missing_event_type.aes +++ b/test/contracts/missing_event_type.aes @@ -1,3 +1,3 @@ contract MissingEventType = - entrypoint main() = + entrypoint main_fun() = Chain.event("MAIN") diff --git a/test/contracts/multiple_contracts.aes b/test/contracts/multiple_contracts.aes index 41df9b4..5d71b36 100644 --- a/test/contracts/multiple_contracts.aes +++ b/test/contracts/multiple_contracts.aes @@ -1,5 +1,7 @@ -contract ContractOne = - entrypoint foo() = "foo" +contract Child = + entrypoint + add2 : int => int + add2(x) = x + 2 -contract ContractTwo = - entrypoint bar() = "bar" +main contract Main = + entrypoint add4(x, c : Child) = c.add2(x) + 2 \ No newline at end of file diff --git a/test/contracts/non_functional_entrypoint.aes b/test/contracts/non_functional_entrypoint.aes index 4162e38..0b23b5a 100644 --- a/test/contracts/non_functional_entrypoint.aes +++ b/test/contracts/non_functional_entrypoint.aes @@ -1,4 +1,4 @@ -contract C1 = +contract interface C1 = entrypoint f : int contract C = diff --git a/test/contracts/protected_call.aes b/test/contracts/protected_call.aes index d377399..6bf09b2 100644 --- a/test/contracts/protected_call.aes +++ b/test/contracts/protected_call.aes @@ -1,4 +1,4 @@ -contract Remote = +contract interface Remote = entrypoint id : int => int contract ProtectedCall = diff --git a/test/contracts/remote_call.aes b/test/contracts/remote_call.aes index e644a0f..c5b0547 100644 --- a/test/contracts/remote_call.aes +++ b/test/contracts/remote_call.aes @@ -1,18 +1,18 @@ -contract Remote1 = - entrypoint main : (int) => int +contract interface Remote1 = + entrypoint main_fun : (int) => int -contract Remote2 = +contract interface Remote2 = entrypoint call : (Remote1, int) => int -contract Remote3 = +contract interface Remote3 = entrypoint get : () => int entrypoint tick : () => unit contract RemoteCall = stateful entrypoint call(r : Remote1, x : int) : int = - r.main(gas = 10000, value = 10, x) + r.main_fun(gas = 10000, value = 10, x) entrypoint staged_call(r1 : Remote1, r2 : Remote2, x : int) = r2.call(r1, x) diff --git a/test/contracts/spend_test.aes b/test/contracts/spend_test.aes index 7213959..0eb1666 100644 --- a/test/contracts/spend_test.aes +++ b/test/contracts/spend_test.aes @@ -1,5 +1,5 @@ -contract SpendContract = +contract interface SpendContract = entrypoint withdraw : (int) => int contract SpendTest = diff --git a/test/contracts/state_handling.aes b/test/contracts/state_handling.aes index 00c2fcb..67722ba 100644 --- a/test/contracts/state_handling.aes +++ b/test/contracts/state_handling.aes @@ -1,5 +1,5 @@ include "String.aes" -contract Remote = +contract interface Remote = record rstate = { i : int, s : string, m : map(int, int) } entrypoint look_at : (rstate) => unit diff --git a/test/contracts/stateful.aes b/test/contracts/stateful.aes index e6ea8be..7237b6e 100644 --- a/test/contracts/stateful.aes +++ b/test/contracts/stateful.aes @@ -1,5 +1,5 @@ -contract Remote = +contract interface Remote = stateful entrypoint remote_spend : (address, int) => unit entrypoint remote_pure : int => int diff --git a/test/contracts/test.aes b/test/contracts/test.aes index bd1a130..c20002f 100644 --- a/test/contracts/test.aes +++ b/test/contracts/test.aes @@ -95,7 +95,7 @@ contract Identity = function s(n) = (f,x)=>f(n(f,x)) function add(m,n) = (f,x)=>m(f,n(f,x)) - entrypoint main() = + entrypoint main_fun() = let three=s(s(s(z))) add(three,three) (((i)=>i+1),0) diff --git a/test/contracts/type_clash.aes b/test/contracts/type_clash.aes index dd20607..fb95e4c 100644 --- a/test/contracts/type_clash.aes +++ b/test/contracts/type_clash.aes @@ -1,5 +1,5 @@ -contract Remote = +contract interface Remote = type themap = map(int, string) entrypoint foo : () => themap diff --git a/test/contracts/unapplied_builtins.aes b/test/contracts/unapplied_builtins.aes index 678b085..1f2e9ae 100644 --- a/test/contracts/unapplied_builtins.aes +++ b/test/contracts/unapplied_builtins.aes @@ -9,7 +9,7 @@ // Oracle.extend include "String.aes" contract UnappliedBuiltins = - entrypoint main() = () + entrypoint main_fun() = () type o = oracle(int, int) type t = list(int * string) type m = map(int, int)