%%%------------------------------------------------------------------- %%% @author Happi (Erik Stenman) %%% @copyright (C) 2017, Aeternity Anstalt %%% @doc %%% Intermediate Code for Aeterinty Sophia language. %%% @end %%% Created : 21 Dec 2017 %%% %%%------------------------------------------------------------------- -module(aeso_icode). -export([new/1, pp/1, set_name/2, set_namespace/2, set_payable/2, enter_namespace/2, get_namespace/1, in_main_contract/1, qualify/2, set_functions/2, map_typerep/2, option_typerep/1, get_constructor_tag/2]). -export_type([icode/0]). -include("aeso_icode.hrl"). -type type_def() :: fun(([aeb_aevm_data:type()]) -> aeb_aevm_data:type()). -type bindings() :: any(). -type fun_dec() :: { string() , [modifier()] , arg_list() , expr() , aeb_aevm_data:type()}. -type modifier() :: private | stateful. -type type_name() :: string() | [string()]. -type icode() :: #{ contract_name => string() , functions => [fun_dec()] , namespace => aeso_syntax:con() | aeso_syntax:qcon() , env => [bindings()] , state_type => aeb_aevm_data:type() , event_type => aeb_aevm_data:type() , types => #{ type_name() => type_def() } , type_vars => #{ string() => aeb_aevm_data:type() } , constructors => #{ [string()] => integer() } %% name to tag , options => [any()] , payable => boolean() }. pp(Icode) -> %% TODO: Actually do *Pretty* printing. io:format("~p~n", [Icode]). -spec new([any()]) -> icode(). new(Options) -> #{ contract_name => "" , functions => [] , env => new_env() %% Default to unit type for state and event , state_type => {tuple, []} , event_type => {tuple, []} , types => builtin_types() , type_vars => #{} , constructors => builtin_constructors() , options => Options , payable => false }. builtin_types() -> Word = fun([]) -> word end, #{ "bool" => Word , "int" => Word , "char" => Word , "bits" => Word , "string" => fun([]) -> string end , "address" => Word , "hash" => Word , "unit" => fun([]) -> {tuple, []} end , "signature" => fun([]) -> {tuple, [word, word]} end , "oracle" => fun([_, _]) -> word end , "oracle_query" => fun([_, _]) -> word end , "list" => fun([A]) -> {list, A} end , "option" => fun([A]) -> {variant, [[], [A]]} end , "map" => fun([K, V]) -> map_typerep(K, V) end , ["Chain", "ttl"] => fun([]) -> {variant, [[word], [word]]} end , ["AENS", "pointee"] => fun([]) -> {variant, [[word], [word], [word]]} end }. builtin_constructors() -> #{ ["RelativeTTL"] => 0 , ["FixedTTL"] => 1 , ["None"] => 0 , ["Some"] => 1 , ["AccountPointee"] => 0 , ["OraclePointee"] => 1 , ["ContractPointee"] => 2 }. map_typerep(K, V) -> {map, K, V}. option_typerep(A) -> {variant, [[], [A]]}. new_env() -> []. -spec set_name(string(), icode()) -> icode(). set_name(Name, Icode) -> maps:put(contract_name, Name, Icode). -spec set_payable(boolean(), icode()) -> icode(). set_payable(Payable, Icode) -> maps:put(payable, Payable, Icode). -spec set_namespace(aeso_syntax:con() | aeso_syntax:qcon(), icode()) -> icode(). set_namespace(NS, Icode) -> Icode#{ namespace => NS }. -spec enter_namespace(aeso_syntax:con(), icode()) -> icode(). enter_namespace(NS, Icode = #{ namespace := NS1 }) -> Icode#{ namespace => aeso_syntax:qualify(NS1, NS) }; enter_namespace(NS, Icode) -> Icode#{ namespace => NS }. -spec in_main_contract(icode()) -> boolean(). in_main_contract(#{ namespace := {con, _, Main}, contract_name := Main }) -> true; in_main_contract(_Icode) -> false. -spec get_namespace(icode()) -> false | aeso_syntax:con() | aeso_syntax:qcon(). get_namespace(Icode) -> maps:get(namespace, Icode, false). -spec qualify(aeso_syntax:id() | aeso_syntax:con(), icode()) -> aeso_syntax:id() | aeso_syntax:qid() | aeso_syntax:con() | aeso_syntax:qcon(). qualify(X, Icode) -> case get_namespace(Icode) of false -> X; NS -> aeso_syntax:qualify(NS, X) end. -spec set_functions([fun_dec()], icode()) -> icode(). set_functions(NewFuns, Icode) -> maps:put(functions, NewFuns, Icode). -spec get_constructor_tag([string()], icode()) -> integer(). get_constructor_tag(Name, #{constructors := Constructors}) -> case maps:get(Name, Constructors, undefined) of undefined -> error({undefined_constructor, Name}); Tag -> Tag end.