Improve the interface to the compiler
It is now more consistent though we can still discuss how we want the interface to look.
This commit is contained in:
parent
922107e438
commit
fe1a2758c3
@ -21,8 +21,8 @@
|
|||||||
-include("aeso_icode.hrl").
|
-include("aeso_icode.hrl").
|
||||||
|
|
||||||
|
|
||||||
-type option() :: pp_sophia_code | pp_ast | pp_icode | pp_assembler |
|
-type option() :: pp_sophia_code | pp_ast | pp_types | pp_typed_ast |
|
||||||
pp_bytecode.
|
pp_icode| pp_assembler | pp_bytecode.
|
||||||
-type options() :: [option()].
|
-type options() :: [option()].
|
||||||
|
|
||||||
-export_type([ option/0
|
-export_type([ option/0
|
||||||
@ -43,29 +43,51 @@ file(Filename) ->
|
|||||||
file(Filename, []).
|
file(Filename, []).
|
||||||
|
|
||||||
-spec file(string(), options()) -> map().
|
-spec file(string(), options()) -> map().
|
||||||
file(Filename, Options) ->
|
file(File, Options) ->
|
||||||
C = read_contract(Filename),
|
case read_contract(File, Options) of
|
||||||
from_string(C, Options).
|
{ok,Bin} -> from_string(Bin, Options);
|
||||||
|
{error,Error} -> {error,{File,Error}}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec from_string(string(), options()) -> map().
|
-spec from_string(binary() | string(), options()) -> map().
|
||||||
|
from_string(ContractBin, Options) when is_binary(ContractBin) ->
|
||||||
|
from_string(binary_to_list(ContractBin), Options);
|
||||||
from_string(ContractString, Options) ->
|
from_string(ContractString, Options) ->
|
||||||
Ast = parse(ContractString, Options),
|
try
|
||||||
ok = pp_sophia_code(Ast, Options),
|
Ast = parse(ContractString, Options),
|
||||||
ok = pp_ast(Ast, Options),
|
ok = pp_sophia_code(Ast, Options),
|
||||||
TypedAst = aeso_ast_infer_types:infer(Ast, Options),
|
ok = pp_ast(Ast, Options),
|
||||||
%% pp_types is handled inside aeso_ast_infer_types.
|
TypedAst = aeso_ast_infer_types:infer(Ast, Options),
|
||||||
ok = pp_typed_ast(TypedAst, Options),
|
%% pp_types is handled inside aeso_ast_infer_types.
|
||||||
ICode = to_icode(TypedAst, Options),
|
ok = pp_typed_ast(TypedAst, Options),
|
||||||
TypeInfo = extract_type_info(ICode),
|
ICode = to_icode(TypedAst, Options),
|
||||||
ok = pp_icode(ICode, Options),
|
TypeInfo = extract_type_info(ICode),
|
||||||
Assembler = assemble(ICode, Options),
|
ok = pp_icode(ICode, Options),
|
||||||
ok = pp_assembler(Assembler, Options),
|
Assembler = assemble(ICode, Options),
|
||||||
ByteCodeList = to_bytecode(Assembler, Options),
|
ok = pp_assembler(Assembler, Options),
|
||||||
ByteCode = << << B:8 >> || B <- ByteCodeList >>,
|
ByteCodeList = to_bytecode(Assembler, Options),
|
||||||
ok = pp_bytecode(ByteCode, Options),
|
ByteCode = << << B:8 >> || B <- ByteCodeList >>,
|
||||||
#{byte_code => ByteCode, type_info => TypeInfo,
|
ok = pp_bytecode(ByteCode, Options),
|
||||||
contract_source => ContractString,
|
{ok,#{byte_code => ByteCode,
|
||||||
compiler_version => version()}.
|
compiler_version => version(),
|
||||||
|
contract_source => ContractString,
|
||||||
|
type_info => TypeInfo
|
||||||
|
}}
|
||||||
|
catch
|
||||||
|
%% The compiler errors.
|
||||||
|
error:{parse_errors,Errors} ->
|
||||||
|
{error,join_errors("Parse errors", Errors, fun(E) -> E end)};
|
||||||
|
error:{type_errors,Errors} ->
|
||||||
|
{error,join_errors("Type errors", Errors, fun(E) -> E end)};
|
||||||
|
error:{code_errors,Errors} ->
|
||||||
|
{error,join_errors("Code errors", Errors,
|
||||||
|
fun (E) -> io_lib:format("~p", [E]) end)}
|
||||||
|
%% General programming errors in the compiler just signal error.
|
||||||
|
end.
|
||||||
|
|
||||||
|
join_errors(Prefix, Errors, Pfun) ->
|
||||||
|
Ess = [ Pfun(E) || E <- Errors ],
|
||||||
|
list_to_binary(string:join([Prefix|Ess], "\n")).
|
||||||
|
|
||||||
-define(CALL_NAME, "__call").
|
-define(CALL_NAME, "__call").
|
||||||
|
|
||||||
@ -76,26 +98,36 @@ from_string(ContractString, Options) ->
|
|||||||
-spec check_call(string(), options()) -> {ok, string(), {[Type], Type | any}, [term()]} | {error, term()}
|
-spec check_call(string(), options()) -> {ok, string(), {[Type], Type | any}, [term()]} | {error, term()}
|
||||||
when Type :: term().
|
when Type :: term().
|
||||||
check_call(ContractString, Options) ->
|
check_call(ContractString, Options) ->
|
||||||
Ast = parse(ContractString, Options),
|
try
|
||||||
ok = pp_sophia_code(Ast, Options),
|
Ast = parse(ContractString, Options),
|
||||||
ok = pp_ast(Ast, Options),
|
ok = pp_sophia_code(Ast, Options),
|
||||||
TypedAst = aeso_ast_infer_types:infer(Ast, [permissive_address_literals]),
|
ok = pp_ast(Ast, Options),
|
||||||
{ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst),
|
TypedAst = aeso_ast_infer_types:infer(Ast, [permissive_address_literals]),
|
||||||
ok = pp_typed_ast(TypedAst, Options),
|
{ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst),
|
||||||
Icode = to_icode(TypedAst, Options),
|
ok = pp_typed_ast(TypedAst, Options),
|
||||||
ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ],
|
Icode = to_icode(TypedAst, Options),
|
||||||
RetVMType = case RetType of
|
ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ],
|
||||||
{id, _, "_"} -> any;
|
RetVMType = case RetType of
|
||||||
_ -> aeso_ast_to_icode:ast_typerep(RetType, Icode)
|
{id, _, "_"} -> any;
|
||||||
end,
|
_ -> aeso_ast_to_icode:ast_typerep(RetType, Icode)
|
||||||
ok = pp_icode(Icode, Options),
|
end,
|
||||||
#{ functions := Funs } = Icode,
|
ok = pp_icode(Icode, Options),
|
||||||
ArgIcode = get_arg_icode(Funs),
|
#{ functions := Funs } = Icode,
|
||||||
try [ icode_to_term(T, Arg) || {T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ] of
|
ArgIcode = get_arg_icode(Funs),
|
||||||
ArgTerms ->
|
ArgTerms = [ icode_to_term(T, Arg) ||
|
||||||
{ok, FunName, {ArgVMTypes, RetVMType}, ArgTerms}
|
{T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ],
|
||||||
catch throw:Err ->
|
{ok, FunName, {ArgVMTypes, RetVMType}, ArgTerms}
|
||||||
{error, Err}
|
catch
|
||||||
|
error:{parse_errors, Errors} ->
|
||||||
|
{error,join_errors("Parse errors", Errors, fun (E) -> E end)};
|
||||||
|
error:{type_errors, Errors} ->
|
||||||
|
{error,join_errors("Type errors", Errors, fun (E) -> E end)};
|
||||||
|
error:{badmatch,{error,missing_call_function}} ->
|
||||||
|
{error,join_errors("Type errors", ["missing __call function"],
|
||||||
|
fun (E) -> E end)};
|
||||||
|
throw:Error -> %Don't ask
|
||||||
|
{error,join_errors("Code errors", [Error],
|
||||||
|
fun (E) -> io_lib:format("~p", [E]) end)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec create_calldata(map(), string(), string()) ->
|
-spec create_calldata(map(), string(), string()) ->
|
||||||
@ -113,7 +145,7 @@ create_calldata(Contract, Function, Argument) when is_map(Contract) ->
|
|||||||
%% Function should be "foo : type", and
|
%% Function should be "foo : type", and
|
||||||
%% Argument should be "Arg1, Arg2, .., ArgN" (no parens)
|
%% Argument should be "Arg1, Arg2, .., ArgN" (no parens)
|
||||||
case string:lexemes(Function, ": ") of
|
case string:lexemes(Function, ": ") of
|
||||||
%% If function is a single word fallback to old calldata generation
|
%% If function is a single word fallback to old calldata generation
|
||||||
[FunName] -> aeso_abi:old_create_calldata(Contract, FunName, Argument);
|
[FunName] -> aeso_abi:old_create_calldata(Contract, FunName, Argument);
|
||||||
[FunName | _] ->
|
[FunName | _] ->
|
||||||
Args = lists:map(fun($\n) -> 32; (X) -> X end, Argument), %% newline to space
|
Args = lists:map(fun($\n) -> 32; (X) -> X end, Argument), %% newline to space
|
||||||
@ -251,9 +283,13 @@ parse_error({Line,Pos}, ErrorString) ->
|
|||||||
Error = io_lib:format("line ~p, column ~p: ~s", [Line,Pos,ErrorString]),
|
Error = io_lib:format("line ~p, column ~p: ~s", [Line,Pos,ErrorString]),
|
||||||
error({parse_errors,[Error]}).
|
error({parse_errors,[Error]}).
|
||||||
|
|
||||||
read_contract(Name) ->
|
read_contract(Name, Opts) ->
|
||||||
{ok, Bin} = file:read_file(filename:join(contract_path(), lists:concat([Name, ".aes"]))),
|
FileName = filename(Name, ".aes", Opts),
|
||||||
binary_to_list(Bin).
|
file:read_file(FileName).
|
||||||
|
|
||||||
contract_path() ->
|
filename(File, Suffix, _Opts) ->
|
||||||
"apps/aesophia/test/contracts".
|
Base = filename:basename(File, Suffix),
|
||||||
|
Sdir = filename:dirname(File),
|
||||||
|
if Sdir == "." -> Base ++ Suffix;
|
||||||
|
true -> filename:join(Sdir, Base ++ Suffix)
|
||||||
|
end.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user