mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-21 00:39:37 +00:00
Estimated hours taken: 200
First implementation of the standard library in managed C++.
configure.in:
Autodetect the .NET SDK, and set MS_DOTNET_SDK_DIR based on it.
Find the IL assembler, and set ILASM.
compiler/inlining.m:
Turn off inlining of pragma_foreign_code with the IL backend.
compiler/mlds_to_c.m:
Add a comment questioning the foreign language interfacing still to be
done in this backend, and remove the "inline target code" from
this list (since it has been completed).
compiler/mlds_to_il.m:
Generate code for :- external. We generate a forwarding
function to the expected implementation in
<modulename>__c_code.cpp
Rename all the classes to use MixedCase, and to put them in the
mercury.runtime namespace.
compiler/mlds_to_ilasm.m:
Don't use the System or mercury namespaces by default.
Change the names of the runtime cpp files to mercury_mcpp.dll
and mercury_il.dll.
Use c_util to output unops and binops.
doc/user_guide.texi:
Document MS_CL_NOASM, MS_CLFLAGS and EXTRA_MS_CLFLAGS.
library/*.m:
Rename pragma c_code as pragma foreign_code("C", ...).
Add pragma foreign_code for MC++.
Only a fraction of the predicates are implemented, everything
else simply throws and exception when called.
Implementations of predicates marked with :- external are
provided as pragma foreign_code, but are commented out.
library/Mmakefile:
runtime/Mmakefile:
Add targets for building the dlls for the library.
runtime/mercury_mcpp.cpp:
runtime/mercury_mcpp.h:
Implementation of the runtime.
runtime/mercury_il.il:
This file mainly implements things that can't be written in
managed C++ (e.g. function pointers).
scripts/Mmake.rules:
scripts/Mmake.vars.in:
Add rules for generating .dlls and .exes from .ils and .cpps.
1093 lines
30 KiB
Mathematica
1093 lines
30 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2001 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% File: builtin.m.
|
|
% Main author: fjh.
|
|
% Stability: low.
|
|
|
|
% This file is automatically imported into every module.
|
|
% It is intended for things that are part of the language,
|
|
% but which are implemented just as normal user-level code
|
|
% rather than with special coding in the compiler.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module builtin.
|
|
:- interface.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% TYPES.
|
|
|
|
% The types `character', `int', `float', and `string',
|
|
% and tuple types `{}', `{T}', `{T1, T2}', ...
|
|
% and the types `pred', `pred(T)', `pred(T1, T2)', `pred(T1, T2, T3)', ...
|
|
% and `func(T1) = T2', `func(T1, T2) = T3', `func(T1, T2, T3) = T4', ...
|
|
% are builtin and are implemented using special code in the
|
|
% type-checker. (XXX TODO: report an error for attempts to redefine
|
|
% these types.)
|
|
|
|
% The type c_pointer can be used by predicates which use the C interface.
|
|
:- type c_pointer.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% INSTS.
|
|
|
|
% The standard insts `free', `ground', and `bound(...)' are builtin
|
|
% and are implemented using special code in the parser and mode-checker.
|
|
|
|
% So are the standard unique insts `unique', `unique(...)',
|
|
% `mostly_unique', `mostly_unique(...)', and `clobbered'.
|
|
% The name `dead' is allowed as a synonym for `clobbered'.
|
|
% Similarly `mostly_dead' is a synonym for `mostly_clobbered'.
|
|
|
|
:- inst dead = clobbered.
|
|
:- inst mostly_dead = mostly_clobbered.
|
|
|
|
% The `any' inst used for the constraint solver interface is also builtin.
|
|
|
|
% Higher-order predicate insts `pred(<modes>) is <detism>'
|
|
% and higher-order functions insts `func(<modes>) = <mode> is det'
|
|
% are also builtin.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% MODES.
|
|
|
|
% The standard modes.
|
|
|
|
:- mode unused :: (free -> free).
|
|
:- mode output :: (free -> ground).
|
|
:- mode input :: (ground -> ground).
|
|
|
|
:- mode in :: (ground -> ground).
|
|
:- mode out :: (free -> ground).
|
|
|
|
:- mode in(Inst) :: (Inst -> Inst).
|
|
:- mode out(Inst) :: (free -> Inst).
|
|
:- mode di(Inst) :: (Inst -> clobbered).
|
|
:- mode mdi(Inst) :: (Inst -> mostly_clobbered).
|
|
|
|
% Unique modes. These are still not fully implemented.
|
|
|
|
% unique output
|
|
:- mode uo :: free -> unique.
|
|
|
|
% unique input
|
|
:- mode ui :: unique -> unique.
|
|
|
|
% destructive input
|
|
:- mode di :: unique -> clobbered.
|
|
|
|
% "Mostly" unique modes (unique except that that may be referenced
|
|
% again on backtracking).
|
|
|
|
% mostly unique output
|
|
:- mode muo :: free -> mostly_unique.
|
|
|
|
% mostly unique input
|
|
:- mode mui :: mostly_unique -> mostly_unique.
|
|
|
|
% mostly destructive input
|
|
:- mode mdi :: mostly_unique -> mostly_clobbered.
|
|
|
|
% Higher-order predicate modes are builtin.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% PREDICATES.
|
|
|
|
% Most of these probably ought to be moved to another
|
|
% module in the standard library such as std_util.m.
|
|
|
|
% copy/2 makes a deep copy of a data structure. The resulting copy is a
|
|
% `unique' value, so you can use destructive update on it.
|
|
|
|
:- pred copy(T, T).
|
|
:- mode copy(ui, uo) is det.
|
|
:- mode copy(in, uo) is det.
|
|
|
|
% unsafe_promise_unique/2 is used to promise the compiler that you have a
|
|
% `unique' copy of a data structure, so that you can use destructive update.
|
|
% It is used to work around limitations in the current support for unique
|
|
% modes. `unsafe_promise_unique(X, Y)' is the same as `Y = X' except that
|
|
% the compiler will assume that `Y' is unique.
|
|
%
|
|
% Note that misuse of this predicate may lead to unsound results:
|
|
% if there is more than one reference to the data in question,
|
|
% i.e. it is not `unique', then the behaviour is undefined.
|
|
% (If you lie to the compiler, the compiler will get its revenge!)
|
|
|
|
:- pred unsafe_promise_unique(T, T).
|
|
:- mode unsafe_promise_unique(in, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% A call to the function `promise_only_solution(Pred)' constitutes a
|
|
% promise on the part of the caller that `Pred' has at most one solution,
|
|
% i.e. that `not some [X1, X2] (Pred(X1), Pred(X2), X1 \= X2)'.
|
|
% `promise_only_solution(Pred)' presumes that this assumption is
|
|
% satisfied, and returns the X for which Pred(X) is true, if
|
|
% there is one.
|
|
%
|
|
% You can use `promise_only_solution' as a way of
|
|
% introducing `cc_multi' or `cc_nondet' code inside a
|
|
% `det' or `semidet' procedure.
|
|
%
|
|
% Note that misuse of this function may lead to unsound results:
|
|
% if the assumption is not satisfied, the behaviour is undefined.
|
|
% (If you lie to the compiler, the compiler will get its revenge!)
|
|
|
|
:- func promise_only_solution(pred(T)) = T.
|
|
:- mode promise_only_solution(pred(out) is cc_multi) = out is det.
|
|
:- mode promise_only_solution(pred(out) is cc_nondet) = out is semidet.
|
|
|
|
% `promise_only_solution_io' is like `promise_only_solution', but
|
|
% for procedures with unique modes (e.g. those that do IO).
|
|
%
|
|
% A call to `promise_only_solution_io(P, X, IO0, IO)' constitutes
|
|
% a promise on the part of the caller that for the given IO0,
|
|
% there is only one value of `X' and `IO' for which `P(X, IO0, IO)' is true.
|
|
% `promise_only_solution_io(P, X, IO0, IO)' presumes that this assumption
|
|
% is satisfied, and returns the X and IO for which `P(X, IO0, IO)' is true.
|
|
%
|
|
% Note that misuse of this predicate may lead to unsound results:
|
|
% if the assumption is not satisfied, the behaviour is undefined.
|
|
% (If you lie to the compiler, the compiler will get its revenge!)
|
|
|
|
:- pred promise_only_solution_io(pred(T, IO, IO), T, IO, IO).
|
|
:- mode promise_only_solution_io(pred(out, di, uo) is cc_multi,
|
|
out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
|
|
% We define !/0 (and !/2 for dcgs) to be equivalent to `true'. This is for
|
|
% backwards compatibility with Prolog systems. But of course it only works
|
|
% if all your cuts are green cuts.
|
|
|
|
:- pred ! is det.
|
|
|
|
:- pred !(T, T).
|
|
:- mode !(di, uo) is det.
|
|
:- mode !(in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% unify(X, Y) is true iff X = Y.
|
|
:- pred unify(T::in, T::in) is semidet.
|
|
|
|
:- type comparison_result ---> (=) ; (<) ; (>).
|
|
|
|
% compare(Res, X, Y) binds Res to =, <, or >
|
|
% depending on wheither X is =, <, or > Y in the
|
|
% standard ordering.
|
|
:- pred compare(comparison_result, T, T).
|
|
% Note to implementors: this mode must be first --
|
|
% compiler/higher_order.m depends on it.
|
|
:- mode compare(uo, in, in) is det.
|
|
:- mode compare(uo, ui, ui) is det.
|
|
:- mode compare(uo, ui, in) is det.
|
|
:- mode compare(uo, in, ui) is det.
|
|
|
|
% In addition, the following predicate-like constructs are builtin:
|
|
%
|
|
% :- pred (T = T).
|
|
% :- pred (T \= T).
|
|
% :- pred (pred , pred).
|
|
% :- pred (pred ; pred).
|
|
% :- pred (\+ pred).
|
|
% :- pred (not pred).
|
|
% :- pred (pred -> pred).
|
|
% :- pred (if pred then pred).
|
|
% :- pred (if pred then pred else pred).
|
|
% :- pred (pred => pred).
|
|
% :- pred (pred <= pred).
|
|
% :- pred (pred <=> pred).
|
|
%
|
|
% (pred -> pred ; pred).
|
|
% some Vars pred
|
|
% all Vars pred
|
|
% call/N
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module require, string, std_util, int, float, char, string, list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
promise_only_solution(Pred) = OutVal :-
|
|
call(cc_cast(Pred), OutVal).
|
|
|
|
:- func cc_cast(pred(T)) = pred(T).
|
|
:- mode cc_cast(pred(out) is cc_nondet) = out(pred(out) is semidet) is det.
|
|
:- mode cc_cast(pred(out) is cc_multi) = out(pred(out) is det) is det.
|
|
|
|
:- pragma foreign_code("C", cc_cast(X :: (pred(out) is cc_multi)) =
|
|
(Y :: out(pred(out) is det)),
|
|
[will_not_call_mercury, thread_safe],
|
|
"Y = X;").
|
|
:- pragma foreign_code("C", cc_cast(X :: (pred(out) is cc_nondet)) =
|
|
(Y :: out(pred(out) is semidet)),
|
|
[will_not_call_mercury, thread_safe],
|
|
"Y = X;").
|
|
:- pragma foreign_code("MC++", cc_cast(X :: (pred(out) is cc_multi)) =
|
|
(Y :: out(pred(out) is det)),
|
|
[will_not_call_mercury, thread_safe],
|
|
"Y = X;").
|
|
:- pragma foreign_code("MC++", cc_cast(X :: (pred(out) is cc_nondet)) =
|
|
(Y :: out(pred(out) is semidet)),
|
|
[will_not_call_mercury, thread_safe],
|
|
"Y = X;").
|
|
|
|
promise_only_solution_io(Pred, X) -->
|
|
call(cc_cast_io(Pred), X).
|
|
|
|
:- func cc_cast_io(pred(T, IO, IO)) = pred(T, IO, IO).
|
|
:- mode cc_cast_io(pred(out, di, uo) is cc_multi) =
|
|
out(pred(out, di, uo) is det) is det.
|
|
|
|
:- pragma foreign_code("C",
|
|
cc_cast_io(X :: (pred(out, di, uo) is cc_multi)) =
|
|
(Y :: out(pred(out, di, uo) is det)),
|
|
[will_not_call_mercury, thread_safe],
|
|
"Y = X;").
|
|
:- pragma foreign_code("MC++",
|
|
cc_cast_io(X :: (pred(out, di, uo) is cc_multi)) =
|
|
(Y :: out(pred(out, di, uo) is det)),
|
|
[will_not_call_mercury, thread_safe],
|
|
"Y = X;").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
!.
|
|
!(X, X).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- external(unify/2).
|
|
:- external(compare/3).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pragma foreign_decl("C", "#include ""mercury_type_info.h""").
|
|
|
|
:- pragma foreign_code("C", "
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
void sys_init_builtin_types_module(void); /* suppress gcc warning */
|
|
void sys_init_builtin_types_module(void) { return; }
|
|
#else
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, int, 0,
|
|
MR_TYPECTOR_REP_INT,
|
|
mercury__builtin_unify_int_2_0,
|
|
mercury__builtin_compare_int_3_0);
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, character, 0,
|
|
MR_TYPECTOR_REP_CHAR,
|
|
mercury__builtin_unify_character_2_0,
|
|
mercury__builtin_compare_character_3_0);
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, string, 0,
|
|
MR_TYPECTOR_REP_STRING,
|
|
mercury__builtin_unify_string_2_0,
|
|
mercury__builtin_compare_string_3_0);
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, float, 0,
|
|
MR_TYPECTOR_REP_FLOAT,
|
|
mercury__builtin_unify_float_2_0,
|
|
mercury__builtin_compare_float_3_0);
|
|
|
|
/*
|
|
** One of the following two is used for all higher-order types.
|
|
** Note that they use the same three predicates.
|
|
*/
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, func, 0,
|
|
MR_TYPECTOR_REP_PRED,
|
|
mercury__builtin_unify_pred_2_0,
|
|
mercury__builtin_compare_pred_3_0);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, pred, 0,
|
|
MR_TYPECTOR_REP_PRED,
|
|
mercury__builtin_unify_pred_2_0,
|
|
mercury__builtin_compare_pred_3_0);
|
|
|
|
/*
|
|
** All tuple types use the following type_ctor_info.
|
|
*/
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_NOCM(builtin, tuple, 0,
|
|
MR_TYPECTOR_REP_TUPLE,
|
|
mercury__builtin_unify_tuple_2_0,
|
|
mercury__builtin_compare_tuple_3_0);
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(void, 0, MR_TYPECTOR_REP_VOID);
|
|
|
|
#ifdef NATIVE_GC
|
|
|
|
/*
|
|
** The following type_ctor_infos are used only by accurate gc.
|
|
*/
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(succip, 0, MR_TYPECTOR_REP_SUCCIP);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(hp, 0, MR_TYPECTOR_REP_HP);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(curfr, 0, MR_TYPECTOR_REP_CURFR);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(maxfr, 0, MR_TYPECTOR_REP_MAXFR);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(redofr, 0, MR_TYPECTOR_REP_REDOFR);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(redoip, 0, MR_TYPECTOR_REP_REDOIP);
|
|
|
|
#endif /* NATIVE_GC */
|
|
|
|
/*
|
|
** The following type_ctor_infos are used both accurate gc and by the debugger.
|
|
*/
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(trailptr, 0, MR_TYPECTOR_REP_TRAIL_PTR);
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_UNUSED(ticket, 0, MR_TYPECTOR_REP_TICKET);
|
|
|
|
/*
|
|
INIT sys_init_builtin_types_module
|
|
*/
|
|
MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc builtin_types_module;
|
|
extern void mercury__private_builtin__init(void);
|
|
|
|
void sys_init_builtin_types_module(void); /* suppress gcc warning */
|
|
void sys_init_builtin_types_module(void) {
|
|
|
|
/*
|
|
** We had better call this init() because we use the
|
|
** labels for the special preds of int, float, pred,
|
|
** character and string. If they aren't initialized,
|
|
** we might initialize the type_ctor_info with
|
|
** garbage.
|
|
*/
|
|
mercury__private_builtin__init();
|
|
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_int_0, _int_);
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_float_0, _float_);
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_character_0, _character_);
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_string_0, _string_);
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_pred_0, _pred_);
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_func_0, _pred_);
|
|
MR_INIT_BUILTIN_TYPE_CTOR_INFO(
|
|
mercury_data___type_ctor_info_tuple_0, _tuple_);
|
|
MR_INIT_TYPE_CTOR_INFO_WITH_PRED(
|
|
mercury_data___type_ctor_info_void_0, mercury__unused_0_0);
|
|
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_int_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_float_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_character_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_string_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_pred_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_func_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_tuple_0);
|
|
MR_register_type_ctor_info(
|
|
&mercury_data___type_ctor_info_void_0);
|
|
}
|
|
|
|
#endif /* ! HIGHLEVEL_CODE */
|
|
|
|
").
|
|
|
|
:- pragma foreign_code("MC++", "
|
|
|
|
static void compare_3_p_0(MR_TypeInfo TypeInfo_for_T, MR_Word_Ref Res,
|
|
MR_Box X, MR_Box Y)
|
|
{
|
|
|
|
MR_TypeInfo type_info;
|
|
MR_TypeCtorInfo type_ctor_info;
|
|
int arity;
|
|
MR_TypeInfoParams params;
|
|
MR_Word *args;
|
|
MR_Box ComparePred;
|
|
|
|
type_info = (MR_TypeInfo) TypeInfo_for_T;
|
|
type_ctor_info = dynamic_cast<MR_Word> (type_info->GetValue(
|
|
MR_TYPEINFO_TYPE_CTOR_INFO_SLOT));
|
|
|
|
if (type_ctor_info == 0) {
|
|
type_ctor_info = type_info;
|
|
}
|
|
|
|
if (0) {
|
|
// XXX code for higher order still needs to be written...
|
|
} else {
|
|
arity = mercury::runtime::Convert::ToInt32(
|
|
type_ctor_info->GetValue(MR_TYPE_CTOR_INFO_ARITY_SLOT));
|
|
}
|
|
|
|
ComparePred = type_ctor_info->GetValue(
|
|
MR_TYPE_CTOR_INFO_COMPARE_PRED_SLOT);
|
|
|
|
switch(arity) {
|
|
case 0:
|
|
mercury::runtime::GenericCall::result_call_4(
|
|
ComparePred,
|
|
Res, X, Y);
|
|
break;
|
|
case 1:
|
|
mercury::runtime::GenericCall::result_call_5(
|
|
ComparePred,
|
|
type_info->GetValue(1),
|
|
Res, X, Y);
|
|
break;
|
|
case 2:
|
|
mercury::runtime::GenericCall::result_call_6(
|
|
ComparePred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
Res, X, Y);
|
|
break;
|
|
case 3:
|
|
mercury::runtime::GenericCall::result_call_7(
|
|
ComparePred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
type_info->GetValue(3),
|
|
Res, X, Y);
|
|
break;
|
|
case 4:
|
|
mercury::runtime::GenericCall::result_call_8(
|
|
ComparePred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
type_info->GetValue(3),
|
|
type_info->GetValue(4),
|
|
Res, X, Y);
|
|
break;
|
|
case 5:
|
|
mercury::runtime::GenericCall::result_call_9(
|
|
ComparePred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
type_info->GetValue(3),
|
|
type_info->GetValue(4),
|
|
type_info->GetValue(5),
|
|
Res, X, Y);
|
|
break;
|
|
default:
|
|
mercury::runtime::Errors::fatal_error(
|
|
""compare/3: type arity > 5 not supported"");
|
|
}
|
|
}
|
|
|
|
void compare_3_p_1(MR_TypeInfo TypeInfo_for_T, MR_Word_Ref Res,
|
|
MR_Box X, MR_Box Y)
|
|
{
|
|
compare_3_p_0(TypeInfo_for_T, Res, X, Y);
|
|
}
|
|
|
|
void compare_3_p_2(MR_TypeInfo TypeInfo_for_T, MR_Word_Ref Res,
|
|
MR_Box X, MR_Box Y)
|
|
{
|
|
compare_3_p_0(TypeInfo_for_T, Res, X, Y);
|
|
}
|
|
|
|
void compare_3_p_3(MR_TypeInfo TypeInfo_for_T, MR_Word_Ref Res,
|
|
MR_Box X, MR_Box Y)
|
|
{
|
|
compare_3_p_0(TypeInfo_for_T, Res, X, Y);
|
|
}
|
|
|
|
void copy_2_p_0(MR_TypeInfo TypeInfo_for_T,
|
|
MR_Box X, MR_Ref(MR_Box) Y)
|
|
{
|
|
// XXX this needs to be implemented -- just using Clone() won't work
|
|
// because it often does shallow copies.
|
|
mercury::runtime::Errors::SORRY(""foreign code for this function"");
|
|
}
|
|
|
|
void copy_2_p_1(MR_TypeInfo TypeInfo_for_T,
|
|
MR_Box X, MR_Ref(MR_Box) Y)
|
|
{
|
|
copy_2_p_0(TypeInfo_for_T, X, Y);
|
|
}
|
|
|
|
").
|
|
|
|
:- pragma foreign_code("MC++", "
|
|
|
|
static MR_Integer unify_2_p_0(MR_TypeInfo TypeInfo_for_T, MR_Box X, MR_Box Y)
|
|
{
|
|
int SUCCESS_INDICATOR;
|
|
MR_TypeInfo type_info;
|
|
MR_TypeCtorInfo type_ctor_info;
|
|
MR_Box tmp;
|
|
int arity;
|
|
MR_TypeInfoParams params;
|
|
MR_Box UnifyPred;
|
|
|
|
type_info = (MR_TypeInfo) TypeInfo_for_T;
|
|
|
|
type_ctor_info = dynamic_cast<MR_Word> (type_info->GetValue(
|
|
MR_TYPEINFO_TYPE_CTOR_INFO_SLOT));
|
|
if (type_ctor_info == 0) {
|
|
type_ctor_info = type_info;
|
|
}
|
|
|
|
// XXX insert code to handle higher order....
|
|
if (0) {
|
|
|
|
} else {
|
|
arity = mercury::runtime::Convert::ToInt32(
|
|
type_ctor_info->GetValue(MR_TYPE_CTOR_INFO_ARITY_SLOT));
|
|
}
|
|
|
|
UnifyPred = type_ctor_info->GetValue(
|
|
MR_TYPE_CTOR_INFO_UNIFY_PRED_SLOT);
|
|
|
|
switch(arity) {
|
|
case 0:
|
|
SUCCESS_INDICATOR =
|
|
mercury::runtime::GenericCall::semidet_call_3(
|
|
UnifyPred,
|
|
X, Y);
|
|
break;
|
|
case 1:
|
|
SUCCESS_INDICATOR =
|
|
mercury::runtime::GenericCall::semidet_call_4(
|
|
UnifyPred,
|
|
type_info->GetValue(1),
|
|
X, Y);
|
|
break;
|
|
case 2:
|
|
SUCCESS_INDICATOR =
|
|
mercury::runtime::GenericCall::semidet_call_5(
|
|
UnifyPred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
X, Y);
|
|
break;
|
|
case 3:
|
|
SUCCESS_INDICATOR =
|
|
mercury::runtime::GenericCall::semidet_call_6(
|
|
UnifyPred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
type_info->GetValue(3),
|
|
X, Y);
|
|
break;
|
|
case 4:
|
|
SUCCESS_INDICATOR =
|
|
mercury::runtime::GenericCall::semidet_call_7(
|
|
UnifyPred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
type_info->GetValue(3),
|
|
type_info->GetValue(4),
|
|
X, Y);
|
|
break;
|
|
case 5:
|
|
SUCCESS_INDICATOR =
|
|
mercury::runtime::GenericCall::semidet_call_8(
|
|
UnifyPred,
|
|
type_info->GetValue(1),
|
|
type_info->GetValue(2),
|
|
type_info->GetValue(3),
|
|
type_info->GetValue(4),
|
|
type_info->GetValue(5),
|
|
X, Y);
|
|
break;
|
|
default:
|
|
mercury::runtime::Errors::fatal_error(
|
|
""unify/2: type arity > 5 not supported"");
|
|
}
|
|
|
|
return SUCCESS_INDICATOR;
|
|
}
|
|
|
|
").
|
|
|
|
:- pragma foreign_code("MC++", "
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, int, 0, MR_TYPECTOR_REP_INT)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, character, 0, MR_TYPECTOR_REP_CHAR)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, string, 0, MR_TYPECTOR_REP_STRING)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, c_pointer, 0,
|
|
MR_TYPECTOR_REP_C_POINTER)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, void, 0, MR_TYPECTOR_REP_VOID)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, float, 0, MR_TYPECTOR_REP_FLOAT)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, func, 0, MR_TYPECTOR_REP_PRED)
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO(builtin, pred, 0, MR_TYPECTOR_REP_PRED)
|
|
|
|
static int
|
|
__Unify____int_0_0(MR_Integer x, MR_Integer y)
|
|
{
|
|
return x == y;
|
|
}
|
|
|
|
static int
|
|
__Unify____string_0_0(MR_String x, MR_String y)
|
|
{
|
|
return System::String::Equals(x, y);
|
|
}
|
|
|
|
static int
|
|
__Unify____character_0_0(MR_Char x, MR_Char y)
|
|
{
|
|
return x == y;
|
|
}
|
|
|
|
static int
|
|
__Unify____float_0_0(MR_Float x, MR_Float y)
|
|
{
|
|
/* XXX what should this function do when x and y are both NaNs? */
|
|
return x == y;
|
|
}
|
|
|
|
static int
|
|
__Unify____void_0_0(MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for type `void'"");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
__Unify____c_pointer_0_0(MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for type `c_pointer'"");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
__Unify____func_0_0(MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for `func' type"");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
__Unify____pred_0_0(MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for `pred' type"");
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
__Compare____int_0_0(
|
|
MR_Word_Ref result, MR_Integer x, MR_Integer y)
|
|
{
|
|
int r = (x > y ? MR_COMPARE_GREATER :
|
|
x == y ? MR_COMPARE_EQUAL :
|
|
MR_COMPARE_LESS);
|
|
MR_newenum(*result, r);
|
|
}
|
|
|
|
static void
|
|
__Compare____float_0_0(
|
|
MR_Word_Ref result, MR_Float x, MR_Float y)
|
|
{
|
|
/* XXX what should this function do when x and y are both NaNs? */
|
|
int r = (x > y ? MR_COMPARE_GREATER :
|
|
x == y ? MR_COMPARE_EQUAL :
|
|
x < y ? MR_COMPARE_LESS :
|
|
(mercury::runtime::Errors::fatal_error(
|
|
""incomparable floats in compare/3""),
|
|
MR_COMPARE_EQUAL));
|
|
MR_newenum(*result, r);
|
|
}
|
|
|
|
|
|
static void
|
|
__Compare____string_0_0(MR_Word_Ref result,
|
|
MR_String x, MR_String y)
|
|
{
|
|
int res = System::String::Compare(x, y);
|
|
int r = (res > 0 ? MR_COMPARE_GREATER :
|
|
res == 0 ? MR_COMPARE_EQUAL :
|
|
MR_COMPARE_LESS);
|
|
MR_newenum(*result, r);
|
|
}
|
|
|
|
static void
|
|
__Compare____character_0_0(
|
|
MR_Word_Ref result, MR_Char x, MR_Char y)
|
|
{
|
|
int r = (x > y ? MR_COMPARE_GREATER :
|
|
x == y ? MR_COMPARE_EQUAL :
|
|
MR_COMPARE_LESS);
|
|
MR_newenum(*result, r);
|
|
}
|
|
|
|
static void
|
|
__Compare____void_0_0(MR_Word_Ref result,
|
|
MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for type `void'"");
|
|
}
|
|
|
|
static void
|
|
__Compare____c_pointer_0_0(
|
|
MR_Word_Ref result, MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for type `c_pointer'"");
|
|
}
|
|
|
|
static void
|
|
__Compare____func_0_0(MR_Word_Ref result,
|
|
MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for `func' type"");
|
|
}
|
|
|
|
static void
|
|
__Compare____pred_0_0(MR_Word_Ref result,
|
|
MR_Word x, MR_Word y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for `pred' type"");
|
|
}
|
|
|
|
/*
|
|
** Unification procedures with the arguments boxed.
|
|
** These are just wrappers which call the unboxed version.
|
|
*/
|
|
|
|
static int
|
|
do_unify__int_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
return mercury::builtin__c_code::__Unify____int_0_0(
|
|
mercury::runtime::Convert::ToInt32(x),
|
|
mercury::runtime::Convert::ToInt32(y));
|
|
}
|
|
|
|
static int
|
|
do_unify__string_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
return mercury::builtin__c_code::__Unify____string_0_0(
|
|
dynamic_cast<MR_String>(x),
|
|
dynamic_cast<MR_String>(y));
|
|
}
|
|
|
|
static int
|
|
do_unify__float_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
return mercury::builtin__c_code::__Unify____float_0_0(
|
|
mercury::runtime::Convert::ToDouble(x),
|
|
mercury::runtime::Convert::ToDouble(y));
|
|
}
|
|
|
|
static int
|
|
do_unify__character_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
return mercury::builtin__c_code::__Unify____character_0_0(
|
|
mercury::runtime::Convert::ToChar(x),
|
|
mercury::runtime::Convert::ToChar(y));
|
|
}
|
|
|
|
static int
|
|
do_unify__void_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for type `void'"");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
do_unify__c_pointer_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
return mercury::builtin__c_code::__Unify____c_pointer_0_0(
|
|
dynamic_cast<MR_Word>(x),
|
|
dynamic_cast<MR_Word>(y));
|
|
}
|
|
|
|
static int
|
|
do_unify__func_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for `func' type"");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
do_unify__pred_0_0(MR_Box x, MR_Box y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called unify for `pred' type"");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** Comparison procedures with the arguments boxed.
|
|
** These are just wrappers which call the unboxed version.
|
|
*/
|
|
|
|
static void
|
|
do_compare__int_0_0(MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::builtin__c_code::__Compare____int_0_0(result,
|
|
mercury::runtime::Convert::ToInt32(x),
|
|
mercury::runtime::Convert::ToInt32(y));
|
|
}
|
|
|
|
static void
|
|
do_compare__string_0_0(MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::builtin__c_code::__Compare____string_0_0(result,
|
|
dynamic_cast<MR_String>(x),
|
|
dynamic_cast<MR_String>(y));
|
|
}
|
|
|
|
static void
|
|
do_compare__float_0_0(MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::builtin__c_code::__Compare____float_0_0(result,
|
|
mercury::runtime::Convert::ToDouble(x),
|
|
mercury::runtime::Convert::ToDouble(y));
|
|
}
|
|
|
|
static void
|
|
do_compare__character_0_0(
|
|
MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::builtin__c_code::__Compare____character_0_0(
|
|
result,
|
|
mercury::runtime::Convert::ToChar(x),
|
|
mercury::runtime::Convert::ToChar(y));
|
|
}
|
|
|
|
static void
|
|
do_compare__void_0_0(MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for type `void'"");
|
|
}
|
|
|
|
static void
|
|
do_compare__c_pointer_0_0(
|
|
MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::builtin__c_code::__Compare____c_pointer_0_0(
|
|
result,
|
|
dynamic_cast<MR_Word>(x),
|
|
dynamic_cast<MR_Word>(y));
|
|
}
|
|
|
|
static void
|
|
do_compare__func_0_0(MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for func type"");
|
|
}
|
|
|
|
static void
|
|
do_compare__pred_0_0(MR_Word_Ref result, MR_Box x, MR_Box y)
|
|
{
|
|
mercury::runtime::Errors::fatal_error(
|
|
""called compare/3 for pred type"");
|
|
}
|
|
|
|
").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% unsafe_promise_unique/2 is a compiler builtin.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
/* copy/2
|
|
:- pred copy(T, T).
|
|
:- mode copy(ui, uo) is det.
|
|
:- mode copy(in, uo) is det.
|
|
*/
|
|
|
|
/*************
|
|
Using `pragma c_code' doesn't work, due to the lack of support for
|
|
aliasing, and in particular the lack of support for `ui' modes.
|
|
:- pragma c_code(copy(Value::ui, Copy::uo), "
|
|
MR_save_transient_registers();
|
|
Copy = MR_deep_copy(&Value, TypeInfo_for_T, NULL, NULL);
|
|
MR_restore_transient_registers();
|
|
").
|
|
:- pragma c_code(copy(Value::in, Copy::uo), "
|
|
MR_save_transient_registers();
|
|
Copy = MR_deep_copy(&Value, TypeInfo_for_T, NULL, NULL);
|
|
MR_restore_transient_registers();
|
|
").
|
|
*************/
|
|
|
|
:- external(copy/2).
|
|
|
|
:- pragma c_header_code("#include ""mercury_deep_copy.h""").
|
|
|
|
:- pragma c_header_code("
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
void MR_CALL mercury__builtin__copy_2_p_0(MR_Mercury_Type_Info, MR_Box, MR_Box *);
|
|
void MR_CALL mercury__builtin__copy_2_p_1(MR_Mercury_Type_Info, MR_Box, MR_Box *);
|
|
#endif
|
|
").
|
|
|
|
:- pragma c_code("
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
|
|
void MR_CALL
|
|
mercury__builtin__copy_2_p_0(MR_Mercury_Type_Info type_info,
|
|
MR_Box value, MR_Box * copy)
|
|
{
|
|
MR_Word val = (MR_Word) value;
|
|
*copy = (MR_Box) MR_deep_copy(&val,
|
|
(MR_TypeInfo) type_info, NULL, NULL);
|
|
}
|
|
|
|
void MR_CALL
|
|
mercury__builtin__copy_2_p_1(MR_Mercury_Type_Info type_info, MR_Box x, MR_Box * y)
|
|
{
|
|
mercury__builtin__copy_2_p_0(type_info, x, y);
|
|
}
|
|
|
|
void sys_init_copy_module(void);
|
|
void sys_init_copy_module(void)
|
|
{
|
|
MR_init_entry(mercury__builtin__copy_2_p_0);
|
|
MR_init_entry(mercury__builtin__copy_2_p_1);
|
|
}
|
|
|
|
#else /* ! MR_HIGHLEVEL_CODE */
|
|
|
|
MR_define_extern_entry(mercury__copy_2_0);
|
|
MR_define_extern_entry(mercury__copy_2_1);
|
|
|
|
MR_BEGIN_MODULE(copy_module)
|
|
MR_init_entry(mercury__copy_2_0);
|
|
MR_init_entry(mercury__copy_2_1);
|
|
MR_BEGIN_CODE
|
|
|
|
#ifdef PROFILE_CALLS
|
|
#define fallthru(target, caller) { MR_tailcall((target), (caller)); }
|
|
#else
|
|
#define fallthru(target, caller)
|
|
#endif
|
|
|
|
MR_define_entry(mercury__copy_2_0);
|
|
fallthru(MR_ENTRY(mercury__copy_2_1), MR_ENTRY(mercury__copy_2_0))
|
|
MR_define_entry(mercury__copy_2_1);
|
|
{
|
|
MR_Word value, copy, type_info;
|
|
|
|
type_info = MR_r1;
|
|
value = MR_r2;
|
|
|
|
MR_save_transient_registers();
|
|
copy = MR_deep_copy(&value, (MR_TypeInfo) type_info, NULL, NULL);
|
|
MR_restore_transient_registers();
|
|
|
|
MR_r1 = copy;
|
|
MR_proceed();
|
|
}
|
|
MR_END_MODULE
|
|
|
|
/* Ensure that the initialization code for the above module gets run. */
|
|
|
|
/*
|
|
INIT sys_init_copy_module
|
|
*/
|
|
MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc copy_module;
|
|
void sys_init_copy_module(void);
|
|
/* extra declaration to suppress gcc -Wmissing-decl warning */
|
|
void sys_init_copy_module(void) {
|
|
copy_module();
|
|
}
|
|
|
|
#endif /* ! MR_HIGHLEVEL_CODE */
|
|
").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The type c_pointer can be used by predicates which use the C interface.
|
|
|
|
:- pragma c_code("
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
void sys_init_unify_c_pointer_module(void);
|
|
void sys_init_unify_c_pointer_module(void) { return; }
|
|
#else
|
|
|
|
MR_DEFINE_BUILTIN_TYPE_CTOR_INFO_PRED(builtin, c_pointer, 0,
|
|
MR_TYPECTOR_REP_C_POINTER,
|
|
mercury____Unify___builtin__c_pointer_0_0,
|
|
mercury____Compare___builtin__c_pointer_0_0);
|
|
|
|
MR_declare_entry(mercury____Unify___builtin__c_pointer_0_0);
|
|
MR_declare_entry(mercury____Index___builtin__c_pointer_0_0);
|
|
MR_declare_entry(mercury____Compare___builtin__c_pointer_0_0);
|
|
|
|
MR_BEGIN_MODULE(unify_c_pointer_module)
|
|
MR_init_entry(mercury____Unify___builtin__c_pointer_0_0);
|
|
MR_init_entry(mercury____Compare___builtin__c_pointer_0_0);
|
|
|
|
MR_BEGIN_CODE
|
|
MR_define_entry(mercury____Unify___builtin__c_pointer_0_0);
|
|
/*
|
|
** For c_pointer, we assume that equality and comparison
|
|
** can be based on object identity (i.e. using address comparisons).
|
|
** This is correct for types like io__stream, and necessary since
|
|
** the io__state contains a map(io__stream, filename).
|
|
** However, it might not be correct in general...
|
|
*/
|
|
MR_r1 = (MR_r1 == MR_r2);
|
|
MR_proceed();
|
|
|
|
MR_define_entry(mercury____Compare___builtin__c_pointer_0_0);
|
|
MR_r1 = (MR_r1 == MR_r2 ? MR_COMPARE_EQUAL :
|
|
MR_r1 < MR_r2 ? MR_COMPARE_LESS :
|
|
MR_COMPARE_GREATER);
|
|
MR_proceed();
|
|
|
|
MR_END_MODULE
|
|
|
|
/* Ensure that the initialization code for the above module gets run. */
|
|
/*
|
|
INIT sys_init_unify_c_pointer_module
|
|
*/
|
|
|
|
|
|
MR_MODULE_STATIC_OR_EXTERN MR_ModuleFunc unify_c_pointer_module;
|
|
void sys_init_unify_c_pointer_module(void);
|
|
/* duplicate declaration to suppress gcc -Wmissing-decl warning */
|
|
void sys_init_unify_c_pointer_module(void) {
|
|
unify_c_pointer_module();
|
|
|
|
MR_INIT_TYPE_CTOR_INFO(
|
|
mercury_data_builtin__type_ctor_info_c_pointer_0,
|
|
builtin__c_pointer_0_0);
|
|
|
|
MR_register_type_ctor_info(
|
|
&mercury_data_builtin__type_ctor_info_c_pointer_0);
|
|
}
|
|
|
|
#endif /* ! MR_HIGHLEVEL_CODE */
|
|
|
|
").
|
|
|
|
:- end_module builtin.
|
|
|
|
%-----------------------------------------------------------------------------%
|