Files
mercury/runtime/mercury_deconstruct.c
Zoltan Somogyi 2b559ad054 Move the RTTI-related parts of std_util.m to three new modules in the standard
Estimated hours taken: 8
Branches: main

Move the RTTI-related parts of std_util.m to three new modules in the standard
library, and (in the case of embedded C code) to new modules in the runtime.
The main reason for this is to allow a reorganization of some of the
RTTi-related functionality without breaking backward compatibility. However,
the new arrangement should also be easier to maintain.

Use a separate type_ctor_rep for functions, to distinguish them from predicates
for RTTI code. (At one point, I thought this could avoid the need for the
change to the initialization files mentioned below. It can't, but it is a good
idea in any case.)

library/std_util.m:
	Remove the functionality moved to the new modules, and replace them
	with type equivalences and forwarding code. There are no changes in
	the meanings of the user-visible predicates, with two exceptions.

	- First, the true, equivalence-expanded names of what used to be
	  std_util:type_desc and std_util:type_ctor_desc are now
	  type_desc:type_desc and type_desc: type_ctor_desc.
	- Second, deconstructing a function term now yields
	  "<<function>>" instead of "<<predicate>>".

	The intention is that the RTTI predicates in std_util.m will continue
	to work in a backwards-compatible manner for the near future, i.e. as
	the new modules are updated, the code in std_util will be updated to
	maintain the same functionality, modulo improvements such as avoiding
	unwanted exceptions. When the RTTI functionality in the other modules
	has stabilised, the RTTI predicates in std_util.m should be marked
	obsolete.

	The exported but non-documented functionality of std_util has been
	moved to one of the new modules without forwarding code, with one
	of the moved predicates being turned into the function it should have
	been in the first place.

library/construct.m:
library/deconstruct.m:
library/type_desc.m:
	Three new modules for the code moved from std_util.m.

library/library.m:
compiler/modules.m:
	Record the names of the three new library modules.

runtime/mercury.[ch]:
compiler/mlds_to_il.m:
	Record that type_desc is now in type_desc.m, not std_util.m.

compiler/static_term.m:
	Import the deconstruct module, since we are using its undocumented
	facilities.

runtime/Mmakefile:
	Mention the two new modules.

runtime/mercury_construct.[ch]:
runtime/mercury_type_desc.[ch]:
	Two new modules holding the C functions that used to be in foreign_code
	in std_util, now using MR_ instead of ML_ prefixes, and being more
	consistent about indentation.

runtime/mercury_type_info.h:
	Add a new type_ctor_rep for functions, separate from predicates.
	(It reuses the EQUIV_VAR type_ctor_rep, which hasn't been used
	in ages.)

	Use type_ctor_reps to distinguish between the type_ctor_infos of
	pred/0 and func/0. However, to create higher order typeinfos, we
	still need to know the addresses of the type_ctor_infos for
	pred/0 and func/0, and we still need to know the address of the
	type_ctor_info for tuples to create typeinfos for tuples. Since
	these three type_ctor_infos are defined in the library,
	we cannot access them directly from the runtime. We therefore need
	to access them indirectly in the usual manner, via address_of
	variables initialized by mkinit-generated code.

library/builtin.m:
library/private_builtin.m:
library/rtti_implementation.m:
runtime/mercury.c:
runtime/mercury_mcpp.{h,cpp}:
java/TypeCtorRep.java:
	Updates to accommondate the new function type_ctor_rep.

runtime/mercury_type_info.[ch]:
	Add some functions from foreign_code in std_util that fit in best here.

runtime/mercury_ml_expand_body.h:
runtime/mercury_tabling.h:
runtime/mercury_unify_compare_body.h:
	Delete the code for handling EQUIV_VAR, and add code for handling
	functions.

runtime/mercury_init.h:
runtime/mercury_wrapper.[ch]:
	Add three variables holding the address of the type_ctor_infos
	representing functions, predicates and tuples.

util/mkinit.c:
	Fill in these three variables.

tests/general/accumulator/construct.{m,exp}:
tests/general/accumulator/deconstruct.{m,exp}:
tests/hard_coded/construct.{m,exp}:
	Rename these tests by adding a _test at the ends of their names,
	in order to avoid collisions with the names of the new standard library
	modules. The test cases have not changed, with the exception of the :-
	module declaration of course.

tests/general/accumulator/Mmakefile:
tests/general/accumulator/INTRODUCED:
tests/hard_coded/Mmakefile:
	Record the name changes.

tests/hard_coded/existential_float.exp:
	Updated the expected output to reflect that deconstructions now print
	"<<function>>" instead of "<<predicate>>" when appropriate.

tests/hard_coded/higher_order_type_manip.exp:
	Updated the expected output to reflect the new name of what used to be
	std_util:type_desc.

trace/mercury_trace_browse.c:
trace/mercury_trace_external.c:
trace/mercury_trace_help.c:
	#include type_desc.h instead of std_util.h, since the C functions
	we want to call are now defined there.

trace/mercury_trace_vars.c:
	Update to account for the movement of type_desc from std_util to
	type_desc, and ensure that we don't refer to any type_ctor_infos
	in MLDS grades.
2002-01-30 05:09:13 +00:00

319 lines
10 KiB
C

/*
** vim:ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 2002 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.
*/
/*
** mercury_deconstruct.c
**
** This file provides utility functions for deconstructing terms, for use by
** the standard library.
*/
#include "mercury_imp.h"
#include "mercury_deconstruct.h"
#include "mercury_deconstruct_macros.h"
#define EXPAND_FUNCTION_NAME MR_expand_functor_args
#define EXPAND_TYPE_NAME MR_Expand_Functor_Args_Info
#define EXPAND_FUNCTOR_FIELD functor
#define EXPAND_ARGS_FIELD args
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_FUNCTOR_FIELD
#undef EXPAND_ARGS_FIELD
#define EXPAND_FUNCTION_NAME MR_expand_functor_args_limit
#define EXPAND_TYPE_NAME MR_Expand_Functor_Args_Limit_Info
#define EXPAND_FUNCTOR_FIELD functor
#define EXPAND_ARGS_FIELD args
#define EXPAND_APPLY_LIMIT
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_FUNCTOR_FIELD
#undef EXPAND_ARGS_FIELD
#undef EXPAND_APPLY_LIMIT
#define EXPAND_FUNCTION_NAME MR_expand_functor_only
#define EXPAND_TYPE_NAME MR_Expand_Functor_Only_Info
#define EXPAND_FUNCTOR_FIELD functor_only
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_FUNCTOR_FIELD
#define EXPAND_FUNCTION_NAME MR_expand_args_only
#define EXPAND_TYPE_NAME MR_Expand_Args_Only_Info
#define EXPAND_ARGS_FIELD args_only
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_ARGS_FIELD
#define EXPAND_FUNCTION_NAME MR_expand_chosen_arg_only
#define EXPAND_TYPE_NAME MR_Expand_Chosen_Arg_Only_Info
#define EXPAND_CHOSEN_ARG
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_CHOSEN_ARG
#define EXPAND_FUNCTION_NAME MR_expand_named_arg_only
#define EXPAND_TYPE_NAME MR_Expand_Chosen_Arg_Only_Info
#define EXPAND_NAMED_ARG
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_NAMED_ARG
/*
** MR_arg() is a subroutine used to implement arg/2, argument/2,
** and also store__arg_ref/5 in store.m.
** It takes the address of a term, its type, and an argument index.
** If the selected argument exists, it succeeds and returns the address
** of the argument, and its type; if it doesn't, it fails (i.e. returns FALSE).
**
** You need to wrap MR_{save/restore}_transient_hp() around
** calls to this function.
*/
bool
MR_arg(MR_TypeInfo type_info, MR_Word *term_ptr, int arg_index,
MR_TypeInfo *arg_type_info_ptr, MR_Word **arg_ptr,
MR_non_canon_handling noncanon_handling, MR_ConstString msg)
{
MR_Expand_Chosen_Arg_Only_Info expand_info;
MR_expand_chosen_arg_only(type_info, term_ptr, arg_index, &expand_info);
if (expand_info.non_canonical_type) {
switch (noncanon_handling) {
case MR_ALLOW_NONCANONICAL:
break;
case MR_FAIL_ON_NONCANONICAL:
return FALSE;
break;
case MR_ABORT_ON_NONCANONICAL:
MR_fatal_error(msg);
break;
default:
MR_fatal_error("MR_arg: bad noncanon_handling");
break;
}
}
/* Check range */
if (expand_info.chosen_index_exists) {
*arg_type_info_ptr = expand_info.chosen_type_info;
*arg_ptr = expand_info.chosen_value_ptr;
return TRUE;
}
return FALSE;
}
/*
** MR_named_arg() is a subroutine used to implement named_arg/2.
** It takes the address of a term, its type, and an argument name.
** If an argument with that name exists, it succeeds and returns the address
** of the argument, and its type; if it doesn't, it fails (i.e. returns FALSE).
**
** You need to wrap MR_{save/restore}_transient_hp() around
** calls to this function.
*/
bool
MR_named_arg(MR_TypeInfo type_info, MR_Word *term_ptr, MR_ConstString arg_name,
MR_TypeInfo *arg_type_info_ptr, MR_Word **arg_ptr,
MR_non_canon_handling noncanon_handling, MR_ConstString msg)
{
MR_Expand_Chosen_Arg_Only_Info expand_info;
MR_expand_named_arg_only(type_info, term_ptr, arg_name, &expand_info);
if (expand_info.non_canonical_type) {
switch (noncanon_handling) {
case MR_ALLOW_NONCANONICAL:
break;
case MR_FAIL_ON_NONCANONICAL:
return FALSE;
break;
case MR_ABORT_ON_NONCANONICAL:
MR_fatal_error(msg);
break;
default:
MR_fatal_error("MR_named_arg: bad noncanon_handling");
break;
}
}
/* Check range */
if (expand_info.chosen_index_exists) {
*arg_type_info_ptr = expand_info.chosen_type_info;
*arg_ptr = expand_info.chosen_value_ptr;
return TRUE;
}
return FALSE;
}
/*
** MR_named_arg_num() takes the address of a term, its type, and an argument
** name. If the given term has an argument with the given name, it succeeds and
** returns the argument number (counted starting from 0) of the argument;
** if it doesn't, it fails (i.e. returns FALSE).
**
** You need to wrap MR_{save/restore}_transient_hp() around
** calls to this function.
*/
bool
MR_named_arg_num(MR_TypeInfo type_info, MR_Word *term_ptr,
const char *arg_name, int *arg_num_ptr)
{
MR_TypeCtorInfo type_ctor_info;
MR_DuTypeLayout du_type_layout;
const MR_DuPtagLayout *ptag_layout;
const MR_DuFunctorDesc *functor_desc;
const MR_NotagFunctorDesc *notag_functor_desc;
MR_Word data;
int ptag;
MR_Word sectag;
MR_TypeInfo eqv_type_info;
int i;
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
switch (MR_type_ctor_rep(type_ctor_info)) {
case MR_TYPECTOR_REP_RESERVED_ADDR_USEREQ:
case MR_TYPECTOR_REP_RESERVED_ADDR:
{
MR_ReservedAddrTypeLayout ra_layout;
ra_layout = MR_type_ctor_layout(type_ctor_info).
layout_reserved_addr;
data = *term_ptr;
/*
** First check if this value is one of
** the numeric reserved addresses.
*/
if ((MR_Unsigned) data <
(MR_Unsigned) ra_layout->MR_ra_num_res_numeric_addrs)
{
/*
** If so, it must be a constant, and constants never have
** any arguments.
*/
return FALSE;
}
/*
** Next check if this value is one of the
** the symbolic reserved addresses.
*/
for (i = 0; i < ra_layout->MR_ra_num_res_symbolic_addrs; i++) {
if (data == (MR_Word) ra_layout->MR_ra_res_symbolic_addrs[i]) {
return FALSE;
}
}
/*
** Otherwise, it is not one of the reserved addresses,
** so handle it like a normal DU type.
*/
du_type_layout = ra_layout->MR_ra_other_functors;
goto du_type;
}
case MR_TYPECTOR_REP_DU_USEREQ:
case MR_TYPECTOR_REP_DU:
data = *term_ptr;
du_type_layout = MR_type_ctor_layout(type_ctor_info).layout_du;
/* fall through */
/*
** This label handles both the DU case and the second half of the
** RESERVED_ADDR case. `du_type_layout' and `data' must both be
** set before this code is entered.
*/
du_type:
ptag = MR_tag(data);
ptag_layout = &du_type_layout[ptag];
switch (ptag_layout->MR_sectag_locn) {
case MR_SECTAG_NONE:
functor_desc = ptag_layout->MR_sectag_alternatives[0];
break;
case MR_SECTAG_LOCAL:
sectag = MR_unmkbody(data);
functor_desc = ptag_layout->MR_sectag_alternatives[sectag];
break;
case MR_SECTAG_REMOTE:
sectag = MR_field(ptag, data, 0);
functor_desc = ptag_layout->MR_sectag_alternatives[sectag];
break;
case MR_SECTAG_VARIABLE:
MR_fatal_error("MR_named_arg_num(): unexpected variable");
}
if (functor_desc->MR_du_functor_arg_names == NULL) {
return FALSE;
}
for (i = 0; i < functor_desc->MR_du_functor_orig_arity; i++) {
if (functor_desc->MR_du_functor_arg_names[i] != NULL
&& streq(arg_name, functor_desc->MR_du_functor_arg_names[i]))
{
*arg_num_ptr = i;
return TRUE;
}
}
return FALSE;
case MR_TYPECTOR_REP_EQUIV:
eqv_type_info = MR_create_type_info(
MR_TYPEINFO_GET_FIRST_ORDER_ARG_VECTOR(type_info),
MR_type_ctor_layout(type_ctor_info).layout_equiv);
return MR_named_arg_num(eqv_type_info, term_ptr, arg_name,
arg_num_ptr);
case MR_TYPECTOR_REP_EQUIV_GROUND:
eqv_type_info = MR_pseudo_type_info_is_ground(
MR_type_ctor_layout(type_ctor_info).layout_equiv);
return MR_named_arg_num(eqv_type_info, term_ptr, arg_name,
arg_num_ptr);
case MR_TYPECTOR_REP_NOTAG:
case MR_TYPECTOR_REP_NOTAG_USEREQ:
case MR_TYPECTOR_REP_NOTAG_GROUND:
case MR_TYPECTOR_REP_NOTAG_GROUND_USEREQ:
notag_functor_desc = MR_type_ctor_functors(type_ctor_info).
functors_notag;
if (notag_functor_desc->MR_notag_functor_arg_name != NULL
&& streq(arg_name, notag_functor_desc->MR_notag_functor_arg_name))
{
*arg_num_ptr = 0;
return TRUE;
}
return FALSE;
default:
return FALSE;
}
}