diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 0280edd..1703d40 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -36,6 +36,7 @@ | pp_assembler | pp_bytecode | no_code + | no_implicit_stdlib | {backend, aevm | fate} | {include, {file_system, [string()]} | {explicit_files, #{string() => binary()}}} diff --git a/src/aeso_parser.erl b/src/aeso_parser.erl index de71794..4cce718 100644 --- a/src/aeso_parser.erl +++ b/src/aeso_parser.erl @@ -6,6 +6,7 @@ -export([string/1, string/2, + string/3, type/1]). -include("aeso_parse_lib.hrl"). @@ -16,13 +17,25 @@ -spec string(string()) -> parse_result(). string(String) -> - string(String, []). + string(String, sets:new(), []). --spec string(string(), aeso_compiler:options()) -> parse_result(). + +-spec string(string(), compiler:options()) -> parse_result(). string(String, Opts) -> + string(String, sets:new(), Opts). + +-spec string(string(), sets:set(string()), aeso_compiler:options()) -> parse_result(). +string(String, Included, Opts) -> case parse_and_scan(file(), String, Opts) of {ok, AST} -> - expand_includes(AST, Opts); + STD = case lists:member(no_implicit_stdlib, Opts) of + false -> [{ include, [{src_file, File}, {origin, system}] + , {string, [{src_file, File}, {origin, system}], File}} + || {File, _} <- aeso_stdlib:stdlib_list() + ]; + true -> [] + end, + expand_includes(STD ++ AST, Included, Opts); Err = {error, _} -> Err end. @@ -230,7 +243,7 @@ exprAtom() -> , {bool, keyword(false), false} , ?LET_P(Fs, brace_list(?LAZY_P(field_assignment())), record(Fs)) , {list, [], bracket_list(Expr)} - , ?RULE(keyword('['), Expr, tok('|'), comma_sep(?LAZY_P(comprehension_bind())), tok(']'), list_comp_e(_1, _2, _4)) + , ?RULE(keyword('['), Expr, token('|'), comma_sep(?LAZY_P(comprehension_bind())), tok(']'), list_comp_e(_1, _2, _4)) , ?RULE(tok('['), Expr, binop('..'), Expr, tok(']'), _3(_2, _4)) , ?RULE(keyword('('), comma_sep(Expr), tok(')'), tuple_e(_1, _2)) ]) @@ -527,35 +540,40 @@ bad_expr_err(Reason, E) -> prettypr:nest(2, aeso_pretty:expr(E))])). %% -- Helper functions ------------------------------------------------------- -expand_includes(AST, Opts) -> - expand_includes(AST, [], Opts). +expand_includes(AST, Included, Opts) -> + expand_includes(AST, Included, [], Opts). -expand_includes([], Acc, _Opts) -> +expand_includes([], _Included, Acc, _Opts) -> {ok, lists:reverse(Acc)}; -expand_includes([{include, Ann, S = {string, _, File}} | AST], Acc, Opts) -> - case {read_file(File, Opts), maps:find(File, aeso_stdlib:stdlib())} of - {{ok, _}, {ok,_ }} -> - return_error(ann_pos(Ann), "Illegal redefinition of standard library " ++ File); - {_, {ok, Lib}} -> - case string(Lib) of - {ok, AST1} -> - expand_includes(AST1 ++ AST, Acc, Opts); - Err = {error, _} -> - Err - end; - {{ok, Bin}, _} -> +expand_includes([{include, Ann, S = {string, _, File}} | AST], Included, Acc, Opts) -> + case sets:is_element(File, Included) of + false -> Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}), - case string(binary_to_list(Bin), Opts1) of - {ok, AST1} -> - expand_includes(AST1 ++ AST, Acc, Opts); - Err = {error, _} -> - Err + Included1 = sets:add_element(File, Included), + case {read_file(File, Opts), maps:find(File, aeso_stdlib:stdlib())} of + {{ok, _}, {ok,_ }} -> + return_error(ann_pos(Ann), "Illegal redefinition of standard library " ++ File); + {_, {ok, Lib}} -> + case string(Lib, Included1, Opts1) of + {ok, AST1} -> + expand_includes(AST1 ++ AST, Included1, Acc, Opts); + Err = {error, _} -> + Err + end; + {{ok, Bin}, _} -> + case string(binary_to_list(Bin), Included1, Opts1) of + {ok, AST1} -> + expand_includes(AST1 ++ AST, Included1, Acc, Opts); + Err = {error, _} -> + Err + end; + {_, _} -> + {error, {get_pos(S), include_error, File}} end; - {{error, _}, _} -> - {error, {get_pos(S), include_error, File}} + true -> expand_includes(AST, Included, Acc, Opts) end; -expand_includes([E | AST], Acc, Opts) -> - expand_includes(AST, [E | Acc], Opts). +expand_includes([E | AST], Included, Acc, Opts) -> + expand_includes(AST, Included, [E | Acc], Opts). read_file(File, Opts) -> case proplists:get_value(include, Opts, {explicit_files, #{}}) of diff --git a/src/aeso_stdlib.erl b/src/aeso_stdlib.erl index e726840..4988b54 100644 --- a/src/aeso_stdlib.erl +++ b/src/aeso_stdlib.erl @@ -10,14 +10,15 @@ -module(aeso_stdlib). --export([stdlib/0]). +-export([stdlib/0, stdlib_list/0]). stdlib() -> - maps:from_list( - [ {<<"List.aes">>, std_list()} - %% , {<<"Func.aes">>, std_function()} - ] - ). + maps:from_list(stdlib_list()). + +stdlib_list() -> + [ {<<"List.aes">>, std_list()} + %% , {<<"Func.aes">>, std_function()} + ]. std_function() -> " @@ -51,7 +52,8 @@ namespace Func = ". std_list() -> -" +"namespace List =\n function flat_map() = 3\n". +x() ->" namespace List = function empty(l) = switch(l) diff --git a/test/aeso_aci_tests.erl b/test/aeso_aci_tests.erl index ee719be..0faef0e 100644 --- a/test/aeso_aci_tests.erl +++ b/test/aeso_aci_tests.erl @@ -9,7 +9,7 @@ simple_aci_test_() -> test_contract(N) -> {Contract,MapACI,DecACI} = test_cases(N), - {ok,JSON} = aeso_aci:contract_interface(json, Contract), + {ok,JSON} = aeso_aci:contract_interface(json, Contract, [no_implicit_stdlib]), ?assertEqual([MapACI], JSON), ?assertEqual({ok, DecACI}, aeso_aci:render_aci_json(JSON)). @@ -98,7 +98,7 @@ aci_test_contract(Name) -> {ok, ContractStub} = aeso_aci:render_aci_json(JSON), io:format("STUB:\n~s\n", [ContractStub]), - check_stub(ContractStub, [{src_file, Name}]), + check_stub(ContractStub, [{src_file, Name}, no_implicit_stdlib]), ok. diff --git a/test/aeso_parser_tests.erl b/test/aeso_parser_tests.erl index dcbbcd0..9b54d94 100644 --- a/test/aeso_parser_tests.erl +++ b/test/aeso_parser_tests.erl @@ -15,7 +15,7 @@ simple_contracts_test_() -> ?assertMatch( [{contract, _, {con, _, "Identity"}, [{letfun, _, {id, _, "id"}, [{arg, _, {id, _, "x"}, {id, _, "_"}}], {id, _, "_"}, - {id, _, "x"}}]}], parse_string(Text)), + {id, _, "x"}}]}], parse_string(Text, [no_implicit_stdlib])), ok end}, {"Operator precedence test.", @@ -71,21 +71,23 @@ parse_contract(Name) -> roundtrip_contract(Name) -> round_trip(aeso_test_utils:read_contract(Name)). -parse_string(Text) -> - case aeso_parser:string(Text) of +parse_string(Text) -> parse_string(Text, []). + +parse_string(Text, Opts) -> + case aeso_parser:string(Text, Opts) of {ok, Contract} -> Contract; Err -> error(Err) end. parse_expr(Text) -> [{letval, _, _, _, Expr}] = - parse_string("let _ = " ++ Text), + parse_string("let _ = " ++ Text, [no_implicit_stdlib]), Expr. round_trip(Text) -> - Contract = parse_string(Text), + Contract = parse_string(Text, [no_implicit_stdlib]), Text1 = prettypr:format(aeso_pretty:decls(Contract)), - Contract1 = parse_string(Text1), + Contract1 = parse_string(Text1, [no_implicit_stdlib]), NoSrcLoc = remove_line_numbers(Contract), NoSrcLoc1 = remove_line_numbers(Contract1), ?assertMatch(NoSrcLoc, diff(NoSrcLoc, NoSrcLoc1)).