Files
mercury/compiler/foreign.m
Zoltan Somogyi f9fe8dcf61 Improve the error messages generated for determinism errors involving committed
Estimated hours taken: 8
Branches: main

Improve the error messages generated for determinism errors involving committed
choice contexts. Previously, we printed a message to the effect that e.g.
a cc pred is called in context that requires all solutions, but we didn't say
*why* the context requires all solutions. We now keep track of all the goals
to the right that could fail, since it is these goals that may reject the first
solution of a committed choice goal.

The motivation for this diff was the fact that I found that locating the
failing goal can be very difficult if the conjunction to the right is
a couple of hundred lines long. This would have been a nontrivial problem,
since (a) unifications involving values of user-defined types are committed
choice goals, and (b) we can expect uses of user-defined types to increase.

compiler/det_analysis.m:
	Keep track of goals to the right of the current goal that could fail,
	and include them in the error representation if required.

compiler/det_report.m:
	Include the list of failing goals to the right in the representations
	of determinism errors involving committed committed choice goals.

	Convert the last part of this module that wasn't using error_util
	to use error_util. Make most parts of this module just construct
	error message specifications; print those specifications (using
	error_util) in only a few places.

compiler/hlds_out.m:
	Add a function for use by the new code in det_report.m.

compiler/error_util.m:
	Add a function for use by the new code in det_report.m.

compiler/error_util.m:
compiler/compiler_util.m:
	Error_util is still changing reasonably often, and yet it is
	included in lots of modules, most of which need only a few simple
	non-parse-tree-related predicates from it (e.g. unexpected).
	Move those predicates to a new module, compiler_util.m. This also
	eliminates some undesirable dependencies from libs to parse_tree.

compiler/libs.m:
	Include compiler_util.m.

compiler/notes/compiler_design.html:
	Document compiler_util.m, and fix the documentation of some other
	modules.

compiler/*.m:
	Import compiler_util instead of or in addition to error_util.
	To make this easier, consistently use . instead of __ for module
	qualifying module names.

tests/invalid/det_errors_cc.{m,err_exp}:
	Add this new test case to test the error messages for cc contexts.

tests/invalid/det_errors_deet.{m,err_exp}:
	Add this new test case to test the error messages for unifications
	inside function symbols.

tests/invalid/Mmakefile:
	Add the new test cases.

tests/invalid/det_errors.err_exp:
tests/invalid/magicbox.err_exp:
	Change the expected output to conform to the change in det_report.m,
	which is now more consistent.
2005-10-28 02:11:03 +00:00

688 lines
26 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2000-2005 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
% This module defines predicates for interfacing with foreign languages.
% In particular, this module supports interfacing with languages
% other than the target of compilation.
% Main authors: trd, dgj.
% Parts of this code were originally written by dgj, and have since been
% moved here.
%-----------------------------------------------------------------------------%
:- module backend_libs__foreign.
:- interface.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module libs.globals.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_foreign.
:- import_module bool.
:- import_module io.
:- import_module list.
:- import_module std_util.
:- import_module string.
%-----------------------------------------------------------------------------%
% A type which is used to determine the string representation of a
% mercury type for various foreign languages.
%
:- type exported_type.
% Given a type which is not defined as a foreign type, get the
% exported_type representation of that type.
%
:- func non_foreign_type(mer_type) = exported_type.
% Does the foreign_type_body contain a definition usable
% when compiling to the given target.
%
:- pred have_foreign_type_for_backend(compilation_target::in,
foreign_type_body::in, bool::out) is det.
% Given an arbitary mercury type, get the exported_type representation
% of that type on the current backend.
%
:- func to_exported_type(module_info, mer_type) = exported_type.
% Does the implementation of the given foreign type body on
% the current backend use a user-defined comparison predicate.
%
:- func foreign_type_body_has_user_defined_eq_comp_pred(module_info,
foreign_type_body) = unify_compare is semidet.
% Find the current target backend from the module_info, and given
% a foreign_type_body, return the name of the foreign language type
% the identity of any user-defined unify/compare predicates, and the
% assertions applicable to that backend.
%
:- pred foreign_type_body_to_exported_type(module_info::in,
foreign_type_body::in, sym_name::out, maybe(unify_compare)::out,
list(foreign_type_assertion)::out) is det.
% Given the exported_type representation for a type, determine
% whether or not it is a foreign type, and if yes, return the foreign
% type's assertions.
%
:- func is_foreign_type(exported_type) = maybe(list(foreign_type_assertion)).
% Given a representation of a type, determine the string which
% corresponds to that type in the specified foreign language,
% for use with foreign language interfacing (`pragma export' or
% `pragma foreign_proc').
%
:- func to_type_string(foreign_language, exported_type) = string.
:- func to_type_string(foreign_language, module_info, mer_type) = string.
% Filter the decls for the given foreign language.
% The first return value is the list of matches, the second is
% the list of mis-matches.
%
:- pred filter_decls(foreign_language::in, foreign_decl_info::in,
foreign_decl_info::out, foreign_decl_info::out) is det.
% Filter the module imports for the given foreign language.
% The first return value is the list of matches, the second is
% the list of mis-matches.
%
:- pred filter_imports(foreign_language::in,
foreign_import_module_info::in, foreign_import_module_info::out,
foreign_import_module_info::out) is det.
% Filter the bodys for the given foreign language.
% The first return value is the list of matches, the second is
% the list of mis-matches.
%
:- pred filter_bodys(foreign_language::in, foreign_body_info::in,
foreign_body_info::out, foreign_body_info::out) is det.
% Given some foreign code, generate some suitable proxy code for
% calling the code via one of the given languages.
% This might mean, for example, generating a call to a
% forwarding function in C.
% The foreign language argument specifies which language is the
% target language, the other inputs are the name, types, input
% variables and so on for a piece of pragma foreign code.
% The outputs are the new attributes and implementation for this
% code.
% XXX This implementation is currently incomplete, so in future
% this interface may change.
%
:- pred extrude_pragma_implementation(list(foreign_language)::in,
list(pragma_var)::in, sym_name::in, pred_or_func::in, prog_context::in,
module_info::in, module_info::out,
pragma_foreign_proc_attributes::in, pragma_foreign_proc_attributes::out,
pragma_foreign_code_impl::in, pragma_foreign_code_impl::out) is det.
% make_pragma_import turns pragma imports into pragma foreign_code.
% Given the pred and proc info for this predicate, the name
% of the function to import, the context of the import pragma
% and the module_info, create a pragma_foreign_code_impl
% which imports the foreign function, and return the varset,
% pragma_vars, argument types and other information about the
% generated predicate body.
%
:- pred make_pragma_import(pred_info::in, proc_info::in, string::in,
prog_context::in, pragma_foreign_code_impl::out,
prog_varset::out, list(pragma_var)::out, list(mer_type)::out, arity::out,
pred_or_func::out, module_info::in, module_info::out, io::di, io::uo)
is det.
% The name of the #define which can be used to guard declarations with
% to prevent entities being declared twice.
%
:- func decl_guard(sym_name) = string.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.name_mangle.
:- import_module check_hlds.mode_util.
:- import_module check_hlds.type_util.
:- import_module hlds.code_model.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_out.
:- import_module hlds.hlds_pred.
:- import_module libs.compiler_util.
:- import_module libs.globals.
:- import_module parse_tree.error_util.
:- import_module parse_tree.modules.
:- import_module parse_tree.prog_out.
:- import_module parse_tree.prog_type.
:- import_module parse_tree.prog_util.
:- import_module assoc_list.
:- import_module int.
:- import_module list.
:- import_module map.
:- import_module require.
:- import_module std_util.
:- import_module string.
:- import_module term.
:- import_module varset.
filter_decls(WantedLang, Decls0, LangDecls, NotLangDecls) :-
IsWanted = (pred(foreign_decl_code(Lang, _, _, _)::in) is semidet :-
WantedLang = Lang),
list__filter(IsWanted, Decls0, LangDecls, NotLangDecls).
filter_imports(WantedLang, Imports0, LangImports, NotLangImports) :-
IsWanted = (pred(foreign_import_module(Lang, _, _)::in) is semidet :-
WantedLang = Lang),
list__filter(IsWanted, Imports0, LangImports, NotLangImports).
filter_bodys(WantedLang, Bodys0, LangBodys, NotLangBodys) :-
IsWanted = (pred(foreign_body_code(Lang, _, _)::in) is semidet :-
WantedLang = Lang),
list__filter(IsWanted, Bodys0, LangBodys, NotLangBodys).
extrude_pragma_implementation([], _PragmaVars, _PredName, _PredOrFunc,
_Context, !ModuleInfo, !NewAttributes, !Impl) :-
unexpected(this_file, "no suitable target languages available").
extrude_pragma_implementation([TargetLang | TargetLangs], _PragmaVars,
_PredName, _PredOrFunc, _Context, !ModuleInfo, !Attributes, !Impl) :-
% We just use the first target language for now, it might be nice
% to try a few others if the backend supports multiple ones.
ForeignLanguage = foreign_language(!.Attributes),
% If the foreign language is available as a target language,
% we don't need to do anything.
( list__member(ForeignLanguage, [TargetLang | TargetLangs]) ->
true
;
set_foreign_language(TargetLang, !Attributes),
extrude_pragma_implementation_2(TargetLang, ForeignLanguage,
!ModuleInfo, !Impl)
).
:- pred extrude_pragma_implementation_2(
foreign_language::in, foreign_language::in,
module_info::in, module_info::out,
pragma_foreign_code_impl::in, pragma_foreign_code_impl::out) is det.
% This isn't finished yet, and we probably won't implement it for C
% calling MC++. For C calling normal C++ we would generate a proxy
% function in C++ (implemented in a piece of C++ body code) with C
% linkage, and import that function. The backend would spit the C++
% body code into a separate file.
% The code would look a little like this:
% NewName = make_pred_name(ForeignLanguage, PredName),
% ( PredOrFunc = predicate ->
% ReturnCode = ""
% ;
% ReturnCode = "ReturnVal = "
% ),
% C_ExtraCode = "Some Extra Code To Run",
% create_pragma_import_c_code(PragmaVars, ModuleInfo0, "", VarString),
% module_add_foreign_body_code(cplusplus,
% C_ExtraCode, Context, ModuleInfo0, ModuleInfo),
% Impl = import(NewName, ReturnCode, VarString, no)
extrude_pragma_implementation_2(c, managed_cplusplus, _, _, _, _) :-
unimplemented_combination(c, managed_cplusplus).
extrude_pragma_implementation_2(c, csharp, _, _, _, _) :-
unimplemented_combination(c, csharp).
extrude_pragma_implementation_2(c, il, _, _, _, _) :-
unimplemented_combination(c, il).
extrude_pragma_implementation_2(c, java, _, _, _, _) :-
unimplemented_combination(c, java).
extrude_pragma_implementation_2(c, c, !ModuleInfo, !Impl).
% Don't do anything - C and MC++ are embedded inside MC++
% without any changes.
extrude_pragma_implementation_2(managed_cplusplus, managed_cplusplus,
!ModuleInfo, !Impl).
extrude_pragma_implementation_2(managed_cplusplus, c, !ModuleInfo, !Impl).
extrude_pragma_implementation_2(managed_cplusplus, csharp, _, _, _, _) :-
unimplemented_combination(managed_cplusplus, csharp).
extrude_pragma_implementation_2(managed_cplusplus, il, _, _, _, _) :-
unimplemented_combination(managed_cplusplus, il).
extrude_pragma_implementation_2(managed_cplusplus, java, _, _, _, _) :-
unimplemented_combination(managed_cplusplus, java).
extrude_pragma_implementation_2(csharp, csharp, !ModuleInfo, !Impl).
extrude_pragma_implementation_2(csharp, c, _, _, _, _) :-
unimplemented_combination(csharp, c).
extrude_pragma_implementation_2(csharp, managed_cplusplus, _, _, _, _) :-
unimplemented_combination(csharp, managed_cplusplus).
extrude_pragma_implementation_2(csharp, il, _, _, _, _) :-
unimplemented_combination(csharp, il).
extrude_pragma_implementation_2(csharp, java, _, _, _, _) :-
unimplemented_combination(csharp, java).
extrude_pragma_implementation_2(il, il, !ModuleInfo, !Impl).
extrude_pragma_implementation_2(il, c, _, _, _, _) :-
unimplemented_combination(il, c).
extrude_pragma_implementation_2(il, managed_cplusplus, _, _, _, _) :-
unimplemented_combination(il, managed_cplusplus).
extrude_pragma_implementation_2(il, csharp, _, _, _, _) :-
unimplemented_combination(il, csharp).
extrude_pragma_implementation_2(il, java, _, _, _, _) :-
unimplemented_combination(il, java).
extrude_pragma_implementation_2(java, java,
!ModuleInfo, !Impl).
extrude_pragma_implementation_2(java, c, _, _, _, _) :-
unimplemented_combination(java, c).
extrude_pragma_implementation_2(java, managed_cplusplus, _, _, _, _) :-
unimplemented_combination(java, managed_cplusplus).
extrude_pragma_implementation_2(java, csharp, _, _, _, _) :-
unimplemented_combination(java, csharp).
extrude_pragma_implementation_2(java, il, _, _, _, _) :-
unimplemented_combination(java, il).
:- pred unimplemented_combination(foreign_language::in, foreign_language::in)
is erroneous.
unimplemented_combination(Lang1, Lang2) :-
error("unimplemented: calling " ++ foreign_language_string(Lang2)
++ " foreign code from " ++ foreign_language_string(Lang1)).
% XXX We haven't implemented these functions yet.
% What is here is only a guide.
%
:- func make_pred_name(foreign_language, sym_name) = string.
make_pred_name(Lang, SymName) =
"mercury_" ++ simple_foreign_language_string(Lang) ++ "__" ++
make_pred_name_rest(Lang, SymName).
:- func make_pred_name_rest(foreign_language, sym_name) = string.
make_pred_name_rest(c, _SymName) = "some_c_name".
make_pred_name_rest(managed_cplusplus, qualified(ModuleSpec, Name)) =
make_pred_name_rest(managed_cplusplus, ModuleSpec) ++ "__" ++ Name.
make_pred_name_rest(managed_cplusplus, unqualified(Name)) = Name.
make_pred_name_rest(csharp, _SymName) = "some_csharp_name".
make_pred_name_rest(il, _SymName) = "some_il_name".
make_pred_name_rest(java, _SymName) = "some_java_name".
make_pragma_import(PredInfo, ProcInfo, C_Function, Context, PragmaImpl, VarSet,
PragmaVars, ArgTypes, Arity, PredOrFunc, !ModuleInfo, !IO) :-
% Lookup some information we need from the pred_info and proc_info.
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
pred_info_arg_types(PredInfo, ArgTypes),
proc_info_argmodes(ProcInfo, Modes),
proc_info_interface_code_model(ProcInfo, CodeModel),
% Build a list of argument variables, together with their names, modes,
% and types.
varset__init(VarSet0),
list__length(Modes, Arity),
varset__new_vars(VarSet0, Arity, Vars, VarSet),
create_pragma_vars(Vars, Modes, 0, PragmaVars),
assoc_list__from_corresponding_lists(PragmaVars, ArgTypes,
PragmaVarsAndTypes),
% Construct parts of the C_code string for calling a C_function.
% This C code fragment invokes the specified C function
% with the appropriate arguments from the list constructed
% above, passed in the appropriate manner (by value, or by
% passing the address to simulate pass-by-reference), and
% assigns the return value (if any) to the appropriate place.
% As this phase occurs before polymorphism, we don't know about
% the type-infos yet. polymorphism.m is responsible for adding
% the type-info arguments to the list of variables.
proc_info_declared_determinism(ProcInfo, MaybeDeclaredDetism),
handle_return_value(Context, MaybeDeclaredDetism, CodeModel, PredOrFunc,
PragmaVarsAndTypes, ArgPragmaVarsAndTypes, Return, !ModuleInfo, !IO),
assoc_list__keys(ArgPragmaVarsAndTypes, ArgPragmaVars),
create_pragma_import_c_code(ArgPragmaVars, !.ModuleInfo, "", Variables),
% Make an import implementation.
PragmaImpl = import(C_Function, Return, Variables, yes(Context)).
% handle_return_value(Contxt, DeclaredDetism, CodeModel, PredOrFunc, Args0,
% M, Args, C_Code0):
%
% Figures out what to do with the C function's return value, based on
% Mercury procedure's code model, whether it is a predicate or a function,
% and (if it is a function) the type and mode of the function result.
% Constructs a C code fragment `C_Code0' which is a string of the form
% "<Something> =" that assigns the return value to the appropriate place,
% if there is a return value, or is an empty string, if there is no return
% value. Returns in Args all of Args0 that must be passed as arguments
% (i.e. all of them, or all of them except the return value).
%
% Causes an error message to be emitted if the code_model is not compatible
% with the use of pragma import (ie. it is model_non).
%
:- pred handle_return_value(prog_context::in, maybe(determinism)::in,
code_model::in, pred_or_func::in,
assoc_list(pragma_var, mer_type)::in,
assoc_list(pragma_var, mer_type)::out,
string::out, module_info::in, module_info::out, io::di, io::uo) is det.
handle_return_value(Context, MaybeDeclaredDetism, CodeModel, PredOrFunc,
!Args, C_Code0, !ModuleInfo, !IO) :-
(
CodeModel = model_det,
(
PredOrFunc = function,
pred_args_to_func_args(!Args, RetArg),
RetArg = pragma_var(_, RetArgName, RetMode) - RetType,
mode_to_arg_mode(!.ModuleInfo, RetMode, RetType, RetArgMode),
RetArgMode = top_out,
\+ type_util__is_dummy_argument_type(!.ModuleInfo, RetType)
->
C_Code0 = RetArgName ++ " = "
;
C_Code0 = ""
)
;
CodeModel = model_semi,
% We treat semidet functions the same as semidet predicates,
% which means that for Mercury functions the Mercury return
% value becomes the last argument, and the C return value
% is a bool that is used to indicate success or failure.
C_Code0 = "SUCCESS_INDICATOR = "
;
CodeModel = model_non,
(
MaybeDeclaredDetism = yes(DeclaredDetism),
DetismStr = determinism_to_string(DeclaredDetism)
;
MaybeDeclaredDetism = no,
DetismStr = "multi or nondet"
),
ErrorPieces = [
words("Error: `pragma_import' declaration for"),
words("a procedure that has a determinism of"),
fixed(DetismStr), suffix(".")
],
write_error_pieces(Context, 0, ErrorPieces, !IO),
module_info_incr_errors(!ModuleInfo),
% The following are just dummy values - they will never actually
% be used.
C_Code0 = "\n#error ""cannot import nondet procedure""\n"
),
list__filter(include_import_arg(!.ModuleInfo), !Args).
% include_import_arg(M, Arg):
%
% Succeeds iff Arg should be included in the arguments of the C function.
% Fails if `Arg' has a type such as `io__state' that is just a dummy
% argument that should not be passed to C.
%
:- pred include_import_arg(module_info::in, pair(pragma_var, mer_type)::in)
is semidet.
include_import_arg(ModuleInfo, pragma_var(_Var, _Name, Mode) - Type) :-
mode_to_arg_mode(ModuleInfo, Mode, Type, ArgMode),
ArgMode \= top_unused,
\+ type_util__is_dummy_argument_type(ModuleInfo, Type).
% create_pragma_vars(Vars, Modes, ArgNum0, PragmaVars):
%
% Given list of vars and modes, and an initial argument number, allocate
% names to all the variables, and construct a single list containing
% the variables, names, and modes.
%
:- pred create_pragma_vars(list(prog_var)::in, list(mer_mode)::in, int::in,
list(pragma_var)::out) is det.
create_pragma_vars([], [], _Num, []).
create_pragma_vars([Var | Vars], [Mode | Modes], ArgNum0,
[PragmaVar | PragmaVars]) :-
% Figure out a name for the C variable which will hold this argument.
ArgNum = ArgNum0 + 1,
string__int_to_string(ArgNum, ArgNumString),
string__append("Arg", ArgNumString, ArgName),
PragmaVar = pragma_var(Var, ArgName, Mode),
create_pragma_vars(Vars, Modes, ArgNum, PragmaVars).
create_pragma_vars([_ | _], [], _, _) :-
unexpected(this_file, "create_pragma_vars: length mis-match").
create_pragma_vars([], [_ | _], _, _) :-
unexpected(this_file, "create_pragma_vars: length mis-match").
% create_pragma_import_c_code(PragmaVars, M, !C_Code):
%
% This predicate creates the C code fragments for each argument in
% PragmaVars, and appends them to C_Code0, returning C_Code.
%
:- pred create_pragma_import_c_code(list(pragma_var)::in, module_info::in,
string::in, string::out) is det.
create_pragma_import_c_code([], _ModuleInfo, !C_Code).
create_pragma_import_c_code([PragmaVar | PragmaVars], ModuleInfo, !C_Code) :-
PragmaVar = pragma_var(_Var, ArgName, Mode),
% Construct the C code fragment for passing this argument, and append it
% to !.C_Code. Note that C handles output arguments by passing the
% variable's address, so if the mode is output, we need to put an `&'
% before the variable name.
( mode_is_output(ModuleInfo, Mode) ->
!:C_Code = !.C_Code ++ "&"
;
true
),
!:C_Code = !.C_Code ++ ArgName,
(
PragmaVars = [_ | _],
!:C_Code = !.C_Code ++ ", "
;
PragmaVars = []
),
create_pragma_import_c_code(PragmaVars, ModuleInfo, !C_Code).
%-----------------------------------------------------------------------------%
have_foreign_type_for_backend(c, ForeignTypeBody,
( ForeignTypeBody ^ c = yes(_) -> yes ; no )).
have_foreign_type_for_backend(il, ForeignTypeBody,
( ForeignTypeBody ^ il = yes(_) -> yes ; no )).
have_foreign_type_for_backend(java, ForeignTypeBody,
( ForeignTypeBody ^ java = yes(_) -> yes ; no )).
have_foreign_type_for_backend(asm, ForeignTypeBody, Result) :-
have_foreign_type_for_backend(c, ForeignTypeBody, Result).
:- type exported_type
---> foreign(sym_name, list(foreign_type_assertion))
% A type defined by a pragma foreign_type, and the assertions
% on that foreign_type.
; mercury(mer_type).
% Any other mercury type.
non_foreign_type(Type) = mercury(Type).
to_exported_type(ModuleInfo, Type) = ExportType :-
module_info_get_type_table(ModuleInfo, Types),
(
type_to_ctor_and_args(Type, TypeCtor, _),
map__search(Types, TypeCtor, TypeDefn)
->
hlds_data__get_type_defn_body(TypeDefn, Body),
( Body = foreign_type(ForeignTypeBody) ->
foreign_type_body_to_exported_type(ModuleInfo, ForeignTypeBody,
ForeignTypeName, _, Assertions),
ExportType = foreign(ForeignTypeName, Assertions)
;
ExportType = mercury(Type)
)
;
ExportType = mercury(Type)
).
foreign_type_body_has_user_defined_eq_comp_pred(ModuleInfo, Body) =
UserEqComp :-
foreign_type_body_to_exported_type(ModuleInfo, Body, _,
MaybeUserEqComp, _),
MaybeUserEqComp = yes(UserEqComp).
foreign_type_body_to_exported_type(ModuleInfo, ForeignTypeBody, Name,
MaybeUserEqComp, Assertions) :-
ForeignTypeBody = foreign_type_body(MaybeIL, MaybeC, MaybeJava),
module_info_get_globals(ModuleInfo, Globals),
globals__get_target(Globals, Target),
(
Target = c,
(
MaybeC = yes(Data),
Data = foreign_type_lang_data(c(NameStr), MaybeUserEqComp,
Assertions),
Name = unqualified(NameStr)
;
MaybeC = no,
unexpected(this_file, "to_exported_type: no C type")
)
;
Target = il,
(
MaybeIL = yes(Data),
Data = foreign_type_lang_data(il(_, _, Name), MaybeUserEqComp,
Assertions)
;
MaybeIL = no,
unexpected(this_file, "to_exported_type: no IL type")
)
;
Target = java,
(
MaybeJava = yes(Data),
Data = foreign_type_lang_data(java(NameStr), MaybeUserEqComp,
Assertions),
Name = unqualified(NameStr)
;
MaybeJava = no,
unexpected(this_file, "to_exported_type: no Java type")
)
;
Target = asm,
(
MaybeC = yes(Data),
Data = foreign_type_lang_data(c(NameStr), MaybeUserEqComp,
Assertions),
Name = unqualified(NameStr)
;
MaybeC = no,
unexpected(this_file, "to_exported_type: no C type")
)
).
is_foreign_type(foreign(_, Assertions)) = yes(Assertions).
is_foreign_type(mercury(_)) = no.
to_type_string(Lang, ModuleInfo, Type) =
to_type_string(Lang, to_exported_type(ModuleInfo, Type)).
to_type_string(c, foreign(ForeignType, _)) = Result :-
( ForeignType = unqualified(Result0) ->
Result = Result0
;
unexpected(this_file, "to_type_string: qualified C type")
).
to_type_string(csharp, foreign(ForeignType, _)) = Result :-
sym_name_to_string(ForeignType, ".", Result).
to_type_string(managed_cplusplus, foreign(ForeignType, _)) = Result ++ " *" :-
sym_name_to_string(ForeignType, "::", Result).
to_type_string(il, foreign(ForeignType, _)) = Result :-
sym_name_to_string(ForeignType, ".", Result).
to_type_string(java, foreign(ForeignType, _)) = Result :-
sym_name_to_string(ForeignType, ".", Result).
% XXX does this do the right thing for high level data?
to_type_string(c, mercury(Type)) = Result :-
( Type = builtin(BuiltinType) ->
(
BuiltinType = int,
Result = "MR_Integer"
;
BuiltinType = float,
Result = "MR_Float"
;
BuiltinType = string,
Result = "MR_String"
;
BuiltinType = character,
Result = "MR_Char"
)
;
Result = "MR_Word"
).
to_type_string(csharp, mercury(_Type)) = _ :-
sorry(this_file, "to_type_string for csharp").
to_type_string(managed_cplusplus, mercury(Type)) = TypeString :-
( Type = variable(_, _) ->
TypeString = "MR_Box"
;
TypeString = to_type_string(c, mercury(Type))
).
to_type_string(il, mercury(_Type)) = _ :-
sorry(this_file, "to_type_string for il").
to_type_string(java, mercury(Type)) = Result :-
( Type = builtin(BuiltinType) ->
(
BuiltinType = int,
Result = "int"
;
BuiltinType = float,
Result = "double"
;
BuiltinType = string,
Result = "java.lang.String"
;
BuiltinType = character,
Result = "char"
)
;
Result = "java.lang.Object"
).
%-----------------------------------------------------------------------------%
decl_guard(ModuleName) = UppercaseModuleName ++ "_DECL_GUARD" :-
MangledModuleName = sym_name_mangle(ModuleName),
string__to_upper(MangledModuleName, UppercaseModuleName).
%-----------------------------------------------------------------------------%
:- func this_file = string.
this_file = "foreign.m".
%-----------------------------------------------------------------------------%
:- end_module foreign.
%-----------------------------------------------------------------------------%