From 3137bc4d4a4f96ff7b257eda9f8474e03f754af1 Mon Sep 17 00:00:00 2001 From: Robert Virding Date: Fri, 11 Jan 2019 17:36:31 +0100 Subject: [PATCH 1/4] Improve the interface to the compiler It is now more consistent though we can still discuss how we want the interface to look. --- src/aeso_compiler.erl | 123 ++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 46 deletions(-) diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 92d9afe..7d34ad5 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -21,8 +21,8 @@ -include("aeso_icode.hrl"). --type option() :: pp_sophia_code | pp_ast | pp_icode | pp_assembler | - pp_bytecode. +-type option() :: pp_sophia_code | pp_ast | pp_types | pp_typed_ast | + pp_icode| pp_assembler | pp_bytecode. -type options() :: [option()]. -export_type([ option/0 @@ -43,29 +43,51 @@ file(Filename) -> file(Filename, []). -spec file(string(), options()) -> map(). -file(Filename, Options) -> - C = read_contract(Filename), - from_string(C, Options). +file(File, Options) -> + case read_contract(File) of + {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) -> - Ast = parse(ContractString, Options), - ok = pp_sophia_code(Ast, Options), - ok = pp_ast(Ast, Options), - TypedAst = aeso_ast_infer_types:infer(Ast, Options), - %% pp_types is handled inside aeso_ast_infer_types. - ok = pp_typed_ast(TypedAst, Options), - ICode = to_icode(TypedAst, Options), - TypeInfo = extract_type_info(ICode), - ok = pp_icode(ICode, Options), - Assembler = assemble(ICode, Options), - ok = pp_assembler(Assembler, Options), - ByteCodeList = to_bytecode(Assembler, Options), - ByteCode = << << B:8 >> || B <- ByteCodeList >>, - ok = pp_bytecode(ByteCode, Options), - #{byte_code => ByteCode, type_info => TypeInfo, - contract_source => ContractString, - compiler_version => version()}. + try + Ast = parse(ContractString, Options), + ok = pp_sophia_code(Ast, Options), + ok = pp_ast(Ast, Options), + TypedAst = aeso_ast_infer_types:infer(Ast, Options), + %% pp_types is handled inside aeso_ast_infer_types. + ok = pp_typed_ast(TypedAst, Options), + ICode = to_icode(TypedAst, Options), + TypeInfo = extract_type_info(ICode), + ok = pp_icode(ICode, Options), + Assembler = assemble(ICode, Options), + ok = pp_assembler(Assembler, Options), + ByteCodeList = to_bytecode(Assembler, Options), + ByteCode = << << B:8 >> || B <- ByteCodeList >>, + ok = pp_bytecode(ByteCode, Options), + {ok,#{byte_code => ByteCode, + 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"). @@ -76,26 +98,36 @@ from_string(ContractString, Options) -> -spec check_call(string(), options()) -> {ok, string(), {[Type], Type | any}, [term()]} | {error, term()} when Type :: term(). check_call(ContractString, Options) -> - Ast = parse(ContractString, Options), - ok = pp_sophia_code(Ast, Options), - ok = pp_ast(Ast, Options), - TypedAst = aeso_ast_infer_types:infer(Ast, [permissive_address_literals]), - {ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst), - ok = pp_typed_ast(TypedAst, Options), - Icode = to_icode(TypedAst, Options), - ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ], - RetVMType = case RetType of - {id, _, "_"} -> any; - _ -> aeso_ast_to_icode:ast_typerep(RetType, Icode) - end, - ok = pp_icode(Icode, Options), - #{ functions := Funs } = Icode, - ArgIcode = get_arg_icode(Funs), - try [ icode_to_term(T, Arg) || {T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ] of - ArgTerms -> - {ok, FunName, {ArgVMTypes, RetVMType}, ArgTerms} - catch throw:Err -> - {error, Err} + try + Ast = parse(ContractString, Options), + ok = pp_sophia_code(Ast, Options), + ok = pp_ast(Ast, Options), + TypedAst = aeso_ast_infer_types:infer(Ast, [permissive_address_literals]), + {ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst), + ok = pp_typed_ast(TypedAst, Options), + Icode = to_icode(TypedAst, Options), + ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ], + RetVMType = case RetType of + {id, _, "_"} -> any; + _ -> aeso_ast_to_icode:ast_typerep(RetType, Icode) + end, + ok = pp_icode(Icode, Options), + #{ functions := Funs } = Icode, + ArgIcode = get_arg_icode(Funs), + ArgTerms = [ icode_to_term(T, Arg) || + {T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ], + {ok, FunName, {ArgVMTypes, RetVMType}, ArgTerms} + 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. -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 %% Argument should be "Arg1, Arg2, .., ArgN" (no parens) 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 | _] -> Args = lists:map(fun($\n) -> 32; (X) -> X end, Argument), %% newline to space @@ -252,6 +284,5 @@ parse_error({Line,Pos}, ErrorString) -> error({parse_errors,[Error]}). read_contract(Name) -> - {ok, Bin} = file:read_file(Name), - binary_to_list(Bin). + file:read_file(Name). From cef2383726c8dd23db5b5174e547e8459ad8bbce Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Mon, 28 Jan 2019 10:47:12 +0100 Subject: [PATCH 2/4] Cleanup whitespace, bad typespec, and remaining enacl reference --- src/aeso_compiler.erl | 122 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 7d34ad5..3080e53 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -22,7 +22,7 @@ -type option() :: pp_sophia_code | pp_ast | pp_types | pp_typed_ast | - pp_icode| pp_assembler | pp_bytecode. + pp_icode| pp_assembler | pp_bytecode. -type options() :: [option()]. -export_type([ option/0 @@ -38,50 +38,50 @@ version() -> ?COMPILER_VERSION. --spec file(string()) -> map(). +-spec file(string()) -> {ok, map()} | {error, binary()}. file(Filename) -> file(Filename, []). --spec file(string(), options()) -> map(). +-spec file(string(), options()) -> {ok, map()} | {error, binary()}. file(File, Options) -> case read_contract(File) of {ok, Bin} -> from_string(Bin, Options); {error, Error} -> {error, {File, Error}} end. --spec from_string(binary() | string(), options()) -> map(). +-spec from_string(binary() | string(), options()) -> {ok, map()} | {error, binary()}. from_string(ContractBin, Options) when is_binary(ContractBin) -> from_string(binary_to_list(ContractBin), Options); from_string(ContractString, Options) -> try - Ast = parse(ContractString, Options), - ok = pp_sophia_code(Ast, Options), - ok = pp_ast(Ast, Options), - TypedAst = aeso_ast_infer_types:infer(Ast, Options), - %% pp_types is handled inside aeso_ast_infer_types. - ok = pp_typed_ast(TypedAst, Options), - ICode = to_icode(TypedAst, Options), - TypeInfo = extract_type_info(ICode), - ok = pp_icode(ICode, Options), - Assembler = assemble(ICode, Options), - ok = pp_assembler(Assembler, Options), - ByteCodeList = to_bytecode(Assembler, Options), - ByteCode = << << B:8 >> || B <- ByteCodeList >>, - ok = pp_bytecode(ByteCode, Options), - {ok,#{byte_code => ByteCode, - compiler_version => version(), - contract_source => ContractString, - type_info => TypeInfo - }} + Ast = parse(ContractString, Options), + ok = pp_sophia_code(Ast, Options), + ok = pp_ast(Ast, Options), + TypedAst = aeso_ast_infer_types:infer(Ast, Options), + %% pp_types is handled inside aeso_ast_infer_types. + ok = pp_typed_ast(TypedAst, Options), + ICode = to_icode(TypedAst, Options), + TypeInfo = extract_type_info(ICode), + ok = pp_icode(ICode, Options), + Assembler = assemble(ICode, Options), + ok = pp_assembler(Assembler, Options), + ByteCodeList = to_bytecode(Assembler, Options), + ByteCode = << << B:8 >> || B <- ByteCodeList >>, + ok = pp_bytecode(ByteCode, Options), + {ok, #{byte_code => ByteCode, + 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)} + 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. @@ -99,35 +99,35 @@ join_errors(Prefix, Errors, Pfun) -> when Type :: term(). check_call(ContractString, Options) -> try - Ast = parse(ContractString, Options), - ok = pp_sophia_code(Ast, Options), - ok = pp_ast(Ast, Options), - TypedAst = aeso_ast_infer_types:infer(Ast, [permissive_address_literals]), - {ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst), - ok = pp_typed_ast(TypedAst, Options), - Icode = to_icode(TypedAst, Options), - ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ], - RetVMType = case RetType of - {id, _, "_"} -> any; - _ -> aeso_ast_to_icode:ast_typerep(RetType, Icode) - end, - ok = pp_icode(Icode, Options), - #{ functions := Funs } = Icode, - ArgIcode = get_arg_icode(Funs), - ArgTerms = [ icode_to_term(T, Arg) || - {T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ], - {ok, FunName, {ArgVMTypes, RetVMType}, ArgTerms} + Ast = parse(ContractString, Options), + ok = pp_sophia_code(Ast, Options), + ok = pp_ast(Ast, Options), + TypedAst = aeso_ast_infer_types:infer(Ast, [permissive_address_literals]), + {ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst), + ok = pp_typed_ast(TypedAst, Options), + Icode = to_icode(TypedAst, Options), + ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ], + RetVMType = case RetType of + {id, _, "_"} -> any; + _ -> aeso_ast_to_icode:ast_typerep(RetType, Icode) + end, + ok = pp_icode(Icode, Options), + #{ functions := Funs } = Icode, + ArgIcode = get_arg_icode(Funs), + ArgTerms = [ icode_to_term(T, Arg) || + {T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ], + {ok, FunName, {ArgVMTypes, RetVMType}, ArgTerms} 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)} + 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. -spec create_calldata(map(), string(), string()) -> @@ -279,9 +279,9 @@ parse_string(Text) -> parse_error(Pos, ErrorString) end. -parse_error({Line,Pos}, ErrorString) -> - Error = io_lib:format("line ~p, column ~p: ~s", [Line,Pos,ErrorString]), - error({parse_errors,[Error]}). +parse_error({Line, Pos}, ErrorString) -> + Error = io_lib:format("line ~p, column ~p: ~s", [Line, Pos, ErrorString]), + error({parse_errors, [Error]}). read_contract(Name) -> file:read_file(Name). From f41b0a0ba7e10fa2bd8f3bac6f0cbbdbcb5abd4a Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Mon, 11 Feb 2019 21:43:22 +0100 Subject: [PATCH 3/4] Add create calldata to standalone compiler --- src/aesophia.erl | 116 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 26 deletions(-) diff --git a/src/aesophia.erl b/src/aesophia.erl index c7c57d9..72ad986 100644 --- a/src/aesophia.erl +++ b/src/aesophia.erl @@ -6,7 +6,13 @@ [ {src_file, undefined, undefined, string, "Sophia source code file"} , {verbose, $v, "verbose", undefined, "Verbose output"} , {help, $h, "help", undefined, "Show this message"} - , {outfile, $o, "out", string, "Output file (experimental)"} ]). + , {create_calldata, $c, "create_calldata", string, + "Create calldata with respect to (compiled) contract in this file"} + , {create_calldata_fun, undefined, "calldata_fun", string, + "Deprecated calldata creation - using function + arguments - function"} + , {create_calldata_args, undefined, "calldata_args", string, + "Deprecated calldata creation - using function + arguments - arguments"} + , {outfile, $o, "out", string, "Output the result to file (experimental)"} ]). usage() -> getopt:usage(?OPT_SPEC, "aesophia"). @@ -14,11 +20,14 @@ usage() -> main(Args) -> case getopt:parse(?OPT_SPEC, Args) of {ok, {Opts, []}} -> - case proplists:get_value(help, Opts, false) of - false -> - compile(Opts); + IsHelp = proplists:get_value(help, Opts, false), + CreateCallData = proplists:get_value(create_calldata, Opts, undefined), + if IsHelp -> + usage(); + CreateCallData /= undefined -> + create_calldata(CreateCallData, Opts); true -> - usage() + compile(Opts) end; {ok, {_, NonOpts}} -> @@ -44,28 +53,83 @@ compile(File, Opts) -> Verbose = proplists:get_value(verbose, Opts, false), OutFile = proplists:get_value(outfile, Opts, undefined), - try - Res = aeso_compiler:file(File, [pp_ast || Verbose]), - write_outfile(OutFile, Res), - io:format("\nCompiled successfully!\n") - catch - %% The compiler errors. - error:{type_errors, Errors} -> - io:format("\n~s\n", [string:join(["** Type errors\n" | Errors], "\n")]); - error:{parse_errors, Errors} -> - io:format("\n~s\n", [string:join(["** Parse errors\n" | Errors], "\n")]); - error:{code_errors, Errors} -> - ErrorStrings = [ io_lib:format("~p", [E]) || E <- Errors ], - io:format("\n~s\n", [string:join(["** Code errors\n" | ErrorStrings], "\n")]); - %% General programming errors in the compiler. - error:Error -> - Where = hd(erlang:get_stacktrace()), - ErrorString = io_lib:format("Error: ~p in\n ~p", [Error,Where]), - io:format("\n~s\n", [ErrorString]) + Res = + try aeso_compiler:file(File, [pp_ast || Verbose]) of + {ok, Map} -> + io:format("\nCompiled successfully!\n"), + {ok, Map}; + {error, Reason} -> + io:format("\nError: ~p\n\n", [Reason]), + {error, Reason} + catch + error:Error -> + Where = hd(erlang:get_stacktrace()), + ErrorString = io_lib:format("Error: ~p in\n ~p", [Error, Where]), + io:format("~s\n", [ErrorString]), + {error, list_to_binary(lists:flatten(ErrorString))} + end, + write_outfile(OutFile, Res). + + +create_calldata(ContractFile, Opts) -> + case file:read_file(ContractFile) of + {ok, Bin} -> + try + Contract = binary_to_term(Bin), + create_calldata_(Contract, Opts) + catch _:_ -> + io:format("Error: Bad contract file ~s\n\n", [ContractFile]), usage() + end; + {error, _} -> + io:format("Error: Could not find file ~s\n\n", [ContractFile]), usage() end. + +create_calldata_(Contract, Opts) -> + case proplists:get_value(src_file, Opts, undefined) of + undefined -> %% Check if old deprecated style is used + case {proplists:get_value(create_calldata_fun, Opts, undefined), + proplists:get_value(create_calldata_args, Opts, undefined)} of + {undefined, _} -> + io:format("Error: not enough create call data input\n\n"), usage(); + {_, undefined} -> + io:format("Error: not enough create call data input\n\n"), usage(); + {Fun, Args} -> + create_calldata(Contract, Fun, Args, Opts) + end; + CallFile -> + case file:read_file(CallFile) of + {ok, Bin} -> + create_calldata(Contract, "", binary_to_list(Bin), Opts); + {error, _} -> + io:format("Error: Could not find file ~s\n\n", [CallFile]), usage() + end + end. + +create_calldata(Contract, CallFun, CallArgs, Opts) -> + OutFile = proplists:get_value(outfile, Opts, undefined), + + Res = try + case aeso_compiler:create_calldata(Contract, CallFun, CallArgs) of + {ok, CallData, _CallDataType, _OutputType} -> + io:format("Call data created successfully!\n"), + {ok, CallData}; + Err = {error, Reason} -> + io:format("Error: Create calldata failed: ~p\n\n", [Reason]), + Err + end + catch + error:Error -> + Where = hd(erlang:get_stacktrace()), + ErrorString = io_lib:format("Error: ~p in\n ~p", [Error, Where]), + io:format("~s\n", [ErrorString]), + {error, list_to_binary(lists:flatten(ErrorString))} + end, + write_outfile(OutFile, Res). + + write_outfile(undefined, _) -> ok; -write_outfile(Out, ResMap) -> +write_outfile(Out, Res) -> %% Lazy approach - file:write_file(Out, term_to_binary(ResMap)), - io:format("Output written to: ~s\n", [Out]). + file:write_file(Out, term_to_binary(Res)), + io:format("Output written to: ~s\n\n", [Out]). From d14c56d4b50ece098b462f14a3419f4991f58355 Mon Sep 17 00:00:00 2001 From: Robert Virding Date: Fri, 25 Jan 2019 15:57:02 +0100 Subject: [PATCH 4/4] Fix testing to use new error message format --- test/aeso_compiler_tests.erl | 176 +++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 81 deletions(-) diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index 3c462ab..fced305 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -28,13 +28,15 @@ simple_compile_test_() -> end} || ContractName <- compilable_contracts() ] ++ [ {"Testing error messages of " ++ ContractName, fun() -> - {type_errors, Errors} = compile(ContractName), - check_errors(lists:sort(ExpectedErrors), lists:sort(Errors)) + <<"Type errors\n",ErrorString/binary>> = compile(ContractName), + check_errors(lists:sort(ExpectedErrors), ErrorString) end} || {ContractName, ExpectedErrors} <- failing_contracts() ] }. -check_errors(Expect, Actual) -> +check_errors(Expect, ErrorString) -> + %% This removes the final single \n as well. + Actual = binary:split(<>, <<"\n\n">>, [global,trim]), case {Expect -- Actual, Actual -- Expect} of {[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra}); {Missing, []} -> ?assertMatch({missing, []}, {missing, Missing}); @@ -42,10 +44,10 @@ check_errors(Expect, Actual) -> end. compile(Name) -> - try - aeso_compiler:from_string(aeso_test_utils:read_contract(Name), []) - catch _:{type_errors, _} = E -> - E + String = aeso_test_utils:read_contract(Name), + case aeso_compiler:from_string(String, []) of + {ok,Map} -> Map; + {error,ErrorString} -> ErrorString end. %% compilable_contracts() -> [ContractName]. @@ -75,82 +77,94 @@ compilable_contracts() -> failing_contracts() -> [ {"name_clash", - ["Duplicate definitions of abort at\n - (builtin location)\n - line 14, column 3\n", - "Duplicate definitions of double_def at\n - line 10, column 3\n - line 11, column 3\n", - "Duplicate definitions of double_proto at\n - line 4, column 3\n - line 5, column 3\n", - "Duplicate definitions of proto_and_def at\n - line 7, column 3\n - line 8, column 3\n", - "Duplicate definitions of put at\n - (builtin location)\n - line 15, column 3\n", - "Duplicate definitions of state at\n - (builtin location)\n - line 16, column 3\n"]} + [<<"Duplicate definitions of abort at\n" + " - (builtin location)\n" + " - line 14, column 3">>, + <<"Duplicate definitions of double_def at\n" + " - line 10, column 3\n" + " - line 11, column 3">>, + <<"Duplicate definitions of double_proto at\n" + " - line 4, column 3\n" + " - line 5, column 3">>, + <<"Duplicate definitions of proto_and_def at\n" + " - line 7, column 3\n" + " - line 8, column 3">>, + <<"Duplicate definitions of put at\n" + " - (builtin location)\n" + " - line 15, column 3">>, + <<"Duplicate definitions of state at\n" + " - (builtin location)\n" + " - line 16, column 3">>]} , {"type_errors", - ["Unbound variable zz at line 17, column 21\n", - "Cannot unify int\n" - " and list(int)\n" - "when checking the application at line 26, column 9 of\n" - " (::) : (int, list(int)) => list(int)\n" - "to arguments\n" - " x : int\n" - " x : int\n", - "Cannot unify string\n" - " and int\n" - "when checking the assignment of the field\n" - " x : map(string, string) (at line 9, column 46)\n" - "to the old value __x and the new value\n" - " __x {[\"foo\"] @ x = x + 1} : map(string, int)\n", - "Cannot unify int\n" - " and string\n" - "when checking the type of the expression at line 34, column 45\n" - " 1 : int\n" - "against the expected type\n" - " string\n", - "Cannot unify string\n" - " and int\n" - "when checking the type of the expression at line 34, column 50\n" - " \"bla\" : string\n" - "against the expected type\n" - " int\n", - "Cannot unify string\n" - " and int\n" - "when checking the type of the expression at line 32, column 18\n" - " \"x\" : string\n" - "against the expected type\n" - " int\n", - "Cannot unify string\n" - " and int\n" - "when checking the type of the expression at line 11, column 56\n" - " \"foo\" : string\n" - "against the expected type\n" - " int\n", - "Cannot unify int\n" - " and string\n" - "when comparing the types of the if-branches\n" - " - w : int (at line 38, column 13)\n" - " - z : string (at line 39, column 10)\n", - "Not a record type: string\n" - "arising from the projection of the field y (at line 22, column 38)\n", - "Not a record type: string\n" - "arising from an assignment of the field y (at line 21, column 42)\n", - "Not a record type: string\n" - "arising from an assignment of the field y (at line 20, column 38)\n", - "Not a record type: string\n" - "arising from an assignment of the field y (at line 19, column 35)\n", - "Ambiguous record type with field y (at line 13, column 25) could be one of\n" - " - r (at line 4, column 10)\n" - " - r' (at line 5, column 10)\n", - "Record type r2 does not have field y (at line 15, column 22)\n", - "The field z is missing when constructing an element of type r2 (at line 15, column 24)\n", - "Repeated name x in pattern\n" - " x :: x (at line 26, column 7)\n", - "No record type with fields y, z (at line 14, column 22)\n"]} + [<<"Unbound variable zz at line 17, column 21">>, + <<"Cannot unify int\n" + " and list(int)\n" + "when checking the application at line 26, column 9 of\n" + " (::) : (int, list(int)) => list(int)\n" + "to arguments\n" + " x : int\n" + " x : int">>, + <<"Cannot unify string\n" + " and int\n" + "when checking the assignment of the field\n" + " x : map(string, string) (at line 9, column 46)\n" + "to the old value __x and the new value\n" + " __x {[\"foo\"] @ x = x + 1} : map(string, int)">>, + <<"Cannot unify int\n" + " and string\n" + "when checking the type of the expression at line 34, column 45\n" + " 1 : int\n" + "against the expected type\n" + " string">>, + <<"Cannot unify string\n" + " and int\n" + "when checking the type of the expression at line 34, column 50\n" + " \"bla\" : string\n" + "against the expected type\n" + " int">>, + <<"Cannot unify string\n" + " and int\n" + "when checking the type of the expression at line 32, column 18\n" + " \"x\" : string\n" + "against the expected type\n" + " int">>, + <<"Cannot unify string\n" + " and int\n" + "when checking the type of the expression at line 11, column 56\n" + " \"foo\" : string\n" + "against the expected type\n" + " int">>, + <<"Cannot unify int\n" + " and string\n" + "when comparing the types of the if-branches\n" + " - w : int (at line 38, column 13)\n" + " - z : string (at line 39, column 10)">>, + <<"Not a record type: string\n" + "arising from the projection of the field y (at line 22, column 38)">>, + <<"Not a record type: string\n" + "arising from an assignment of the field y (at line 21, column 42)">>, + <<"Not a record type: string\n" + "arising from an assignment of the field y (at line 20, column 38)">>, + <<"Not a record type: string\n" + "arising from an assignment of the field y (at line 19, column 35)">>, + <<"Ambiguous record type with field y (at line 13, column 25) could be one of\n" + " - r (at line 4, column 10)\n" + " - r' (at line 5, column 10)">>, + <<"Record type r2 does not have field y (at line 15, column 22)">>, + <<"The field z is missing when constructing an element of type r2 (at line 15, column 24)">>, + <<"Repeated name x in pattern\n" + " x :: x (at line 26, column 7)">>, + <<"No record type with fields y, z (at line 14, column 22)">>]} , {"init_type_error", - ["Cannot unify string\n" - " and map(int, int)\n" - "when checking that 'init' returns a value of type 'state' at line 7, column 3\n"]} + [<<"Cannot unify string\n" + " and map(int, int)\n" + "when checking that 'init' returns a value of type 'state' at line 7, column 3">>]} , {"missing_state_type", - ["Cannot unify string\n" - " and ()\n" - "when checking that 'init' returns a value of type 'state' at line 5, column 3\n"]} + [<<"Cannot unify string\n" + " and ()\n" + "when checking that 'init' returns a value of type 'state' at line 5, column 3">>]} , {"missing_fields_in_record_expression", - ["The field x is missing when constructing an element of type r('a) (at line 7, column 40)\n", - "The field y is missing when constructing an element of type r(int) (at line 8, column 40)\n", - "The fields y, z are missing when constructing an element of type r('1) (at line 6, column 40)\n"]} + [<<"The field x is missing when constructing an element of type r('a) (at line 7, column 40)">>, + <<"The field y is missing when constructing an element of type r(int) (at line 8, column 40)">>, + <<"The fields y, z are missing when constructing an element of type r('1) (at line 6, column 40)">>]} ].