diff --git a/src/aeso_aci.erl b/src/aeso_aci.erl index 233cbec..24c6f49 100644 --- a/src/aeso_aci.erl +++ b/src/aeso_aci.erl @@ -69,7 +69,7 @@ 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]), + {TypedAst, _} = aeso_ast_infer_types:infer(Ast, [dont_unfold | Options]), %% io:format("~p\n", [TypedAst]), from_typed_ast(Type, TypedAst) catch diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index bb09980..f420f02 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -557,7 +557,7 @@ map_t(As, K, V) -> {app_t, As, {id, As, "map"}, [K, V]}. infer(Contracts) -> infer(Contracts, []). --type option() :: return_env | dont_unfold | no_code | term(). +-type option() :: return_env | dont_unfold | no_code | debug_mode | term(). -spec init_env(list(option())) -> env(). init_env(_Options) -> global_env(). @@ -622,16 +622,20 @@ check_scope_name_clash(Env, Kind, Name) -> -spec infer_contract_top(env(), main_contract | contract | namespace, [aeso_syntax:decl()], list(option())) -> {env(), [aeso_syntax:decl()]}. -infer_contract_top(Env, Kind, Defs0, _Options) -> +infer_contract_top(Env, Kind, Defs0, Options) -> Defs = desugar(Defs0), - infer_contract(Env, Kind, Defs). + infer_contract(Env, Kind, Defs, 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()]) -> {env(), [aeso_syntax:decl()]}. -infer_contract(Env0, What, Defs0) -> +-spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()], list(option())) -> {env(), [aeso_syntax:decl()]}. +infer_contract(Env0, What, Defs0, Options) -> create_type_errors(), - Defs = process_blocks(Defs0), + Defs01 = process_blocks(Defs0), + Defs = case lists:member(debug_mode, Options) of + true -> expose_internals(Defs01, What); + false -> Defs01 + end, destroy_and_report_type_errors(Env0), Env = Env0#env{ what = What }, Kind = fun({type_def, _, _, _, _}) -> type; @@ -679,7 +683,7 @@ process_blocks(Decls) -> -spec process_block(aeso_syntax:ann(), [aeso_syntax:decl()]) -> [aeso_syntax:decl()]. process_block(_, []) -> []; process_block(_, [Decl]) -> [Decl]; -process_block(Ann, [Decl | Decls]) -> +process_block(_Ann, [Decl | Decls]) -> IsThis = fun(Name) -> fun({letfun, _, {id, _, Name1}, _, _, _}) -> Name == Name1; (_) -> false end end, case Decl of @@ -693,6 +697,20 @@ process_block(Ann, [Decl | Decls]) -> [{fun_clauses, Ann1, Id, {id, [{origin, system} | Ann1], "_"}, Clauses}] end. +%% Turns private stuff into public stuff +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 + end, + setelement(2, Def, NewAnn) + end + || Def <- Defs + ]. + -spec check_typedefs(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}. check_typedefs(Env = #env{ namespace = Ns }, Defs) -> create_type_errors(), diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 5f3a2cb..25cb1b9 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -38,7 +38,8 @@ | pp_assembler | pp_bytecode | no_code - | keep_included + | keep_included + | debug_mode | {backend, aevm | fate} | {include, {file_system, [string()]} | {explicit_files, #{string() => binary()}}} diff --git a/test/aeso_aci_tests.erl b/test/aeso_aci_tests.erl index c851afb..d570390 100644 --- a/test/aeso_aci_tests.erl +++ b/test/aeso_aci_tests.erl @@ -83,8 +83,8 @@ test_cases(3) -> DecACI = <<"contract C =\n" " type state = unit\n" " datatype event = SingleEventDefined\n" - " datatype bert('a) = Bin('a)\n" - " entrypoint a : (C.bert(string)) => int\n">>, + " datatype bert('a) = Bin('a)\n" + " entrypoint a : (C.bert(string)) => int\n">>, {Contract,MapACI,DecACI}. %% Roundtrip @@ -97,7 +97,10 @@ all_contracts() -> aeso_compiler_tests:compilable_contracts(). aci_test_contract(Name) -> String = aeso_test_utils:read_contract(Name), - Opts = [{include, {file_system, [aeso_test_utils:contract_path()]}}], + Opts = case lists:member(Name, aeso_compiler_tests:debug_mode_contracts()) of + true -> [debug_mode]; + false -> [] + end ++ [{include, {file_system, [aeso_test_utils:contract_path()]}}], {ok, JSON} = aeso_aci:contract_interface(json, String, Opts), {ok, #{aci := JSON1}} = aeso_compiler:from_string(String, [{aci, json}, {backend, fate} | Opts]), ?assertEqual(JSON, JSON1), diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index 208839d..a6c76a6 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -110,7 +110,15 @@ compile(Backend, Name) -> compile(Backend, Name, Options) -> String = aeso_test_utils:read_contract(Name), - case aeso_compiler:from_string(String, [{src_file, Name ++ ".aes"}, {backend, Backend} | Options]) of + Options1 = + case lists:member(Name, debug_mode_contracts()) of + true -> [debug_mode]; + false -> [] + end ++ + [ {src_file, Name ++ ".aes"}, {backend, Backend} + , {include, {file_system, [aeso_test_utils:contract_path()]}} + ] ++ Options, + case aeso_compiler:from_string(String, Options1) of {ok, Map} -> Map; {error, ErrorString} when is_binary(ErrorString) -> ErrorString; {error, Errors} -> Errors @@ -165,15 +173,20 @@ compilable_contracts() -> "underscore_number_literals", "qualified_constructor", "let_patterns", - "lhs_matching" + "lhs_matching", + "hermetization_turnoff" ]. not_compilable_on(fate) -> []; not_compilable_on(aevm) -> ["stdlib_include", - "manual_stdlib_include" + "manual_stdlib_include", + "hermetization_turnoff" ]. +debug_mode_contracts() -> + ["hermetization_turnoff"]. + %% Contracts that should produce type errors -define(Pos(Kind, File, Line, Col), (list_to_binary(Kind))/binary, " error in '", @@ -853,6 +866,11 @@ validate(Contract1, Contract2) -> ByteCode = #{ fate_code := FCode } = compile(fate, Contract1), FCode1 = aeb_fate_code:serialize(aeb_fate_code:strip_init_function(FCode)), Source = aeso_test_utils:read_contract(Contract2), - aeso_compiler:validate_byte_code(ByteCode#{ byte_code := FCode1 }, Source, - [{backend, fate}, {include, {file_system, [aeso_test_utils:contract_path()]}}]). + aeso_compiler:validate_byte_code( + ByteCode#{ byte_code := FCode1 }, Source, + case lists:member(Contract2, debug_mode_contracts()) of + true -> [debug_mode]; + false -> [] + end ++ + [{backend, fate}, {include, {file_system, [aeso_test_utils:contract_path()]}}]). diff --git a/test/contracts/hermetization_turnoff.aes b/test/contracts/hermetization_turnoff.aes new file mode 100644 index 0000000..e9884f8 --- /dev/null +++ b/test/contracts/hermetization_turnoff.aes @@ -0,0 +1,11 @@ +namespace M = + function mf() = mg() + function mg() = mf() + +namespace N = + function nf() = ng() + M.mf() + M.mg() + private function ng() = nf() + M.mf() + M.mg() + +contract C = + entrypoint f() = N.ng() + N.nf() + g() + function g() = N.ng() + N.nf() + f()