mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 21:03:53 +00:00
Estimated hours taken: 220
Aditi update syntax, type and mode checking.
Change the hlds_goal for constructions in preparation for
structure reuse to avoid making multiple conflicting changes.
compiler/hlds_goal.m:
Merge `higher_order_call' and `class_method_call' into a single
`generic_call' goal type. This also has alternatives for the
various Aditi builtins for which type declarations can't
be written.
Remove the argument types field from higher-order/class method calls.
It wasn't used often, and wasn't updated by optimizations
such as inlining. The types can be obtained from the vartypes
field of the proc_info.
Add a `lambda_eval_method' field to lambda_goals.
Add a field to constructions to identify which RL code fragment should
be used for an top-down Aditi closure.
Add fields to constructions to hold structure reuse information.
This is currently ignored -- the changes to implement structure
reuse will be committed to the alias branch.
This is included here to avoid lots of CVS conflicts caused by
changing the definition of `hlds_goal' twice.
Add a field to `some' goals to specify whether the quantification
can be removed. This is used to make it easier to ensure that
indexes are used for updates.
Add a field to lambda_goals to describe whether the modes were
guessed by the compiler and may need fixing up after typechecking
works out the argument types.
Add predicate `hlds_goal__generic_call_id' to work out a call_id
for a generic call for use in error messages.
compiler/purity.m:
compiler/post_typecheck.m:
Fill in the modes of Aditi builtin calls and closure constructions.
This needs to know which are the `aditi__state' arguments, so
it must be done after typechecking.
compiler/prog_data.m:
Added `:- type sym_name_and_arity ---> sym_name/arity'.
Add a type `lambda_eval_method', which describes how a closure
is to be executed. The alternatives are normal Mercury execution,
bottom-up execution by Aditi and top-down execution by Aditi.
compiler/prog_out.m:
Add predicate `prog_out__write_sym_name_and_arity', which
replaces duplicated inline code in a few places.
compiler/hlds_data.m:
Add a `lambda_eval_method' field to `pred_const' cons_ids and
`pred_closure_tag' cons_tags.
compiler/hlds_pred.m:
Remove type `pred_call_id', replace it with type `simple_call_id',
which combines a `pred_or_func' and a `sym_name_and_arity'.
Add a type `call_id' which describes all the different types of call,
including normal calls, higher-order and class-method calls
and Aditi builtins.
Add `aditi_top_down' to the type `marker'.
Remove `aditi_interface' from type `marker'. Interfacing to
Aditi predicates is now handled by `generic_call' hlds_goals.
Add a type `rl_exprn_id' which identifies a predicate to
be executed top-down by Aditi.
Add a `maybe(rl_exprn_id)' field to type `proc_info'.
Add predicate `adjust_func_arity' to convert between the arity
of a function to its arity as a predicate.
Add predicates `get_state_args' and `get_state_args_det' to
extract the DCG state arguments from an argument list.
Add predicate `pred_info_get_call_id' to get a `simple_call_id'
for a predicate for use in error messages.
compiler/hlds_out.m:
Write the new representation for call_ids.
Add a predicate `hlds_out__write_call_arg_id' which
replaces similar code in mode_errors.m and typecheck.m.
compiler/prog_io_goal.m:
Add support for `aditi_bottom_up' and `aditi_top_down' annotations
on pred expressions.
compiler/prog_io_util.m:
compiler/prog_io_pragma.m:
Add predicates
- `prog_io_util:parse_name_and_arity' to parse `SymName/Arity'
(moved from prog_io_pragma.m).
- `prog_io_util:parse_pred_or_func_name_and_arity to parse
`pred SymName/Arity' or `func SymName/Arity'.
- `prog_io_util:parse_pred_or_func_and_args' to parse terms resembling
a clause head (moved from prog_io_pragma.m).
compiler/type_util.m:
Add support for `aditi_bottom_up' and `aditi_top_down' annotations
on higher-order types.
Add predicates `construct_higher_order_type',
`construct_higher_order_pred_type' and
`construct_higher_order_func_type' to avoid some code duplication.
compiler/mode_util.m:
Add predicate `unused_mode/1', which returns `builtin:unused'.
Add functions `aditi_di_mode/0', `aditi_ui_mode/0' and
`aditi_uo_mode/0' which return `in', `in', and `out', but will
be changed to return `di', `ui' and `uo' when alias tracking
is implemented.
compiler/goal_util.m:
Add predicate `goal_util__generic_call_vars' which returns
any arguments to a generic_call which are not in the argument list,
for example the closure passed to a higher-order call or
the typeclass_info for a class method call.
compiler/llds.m:
compiler/exprn_aux.m:
compiler/dupelim.m:
compiler/llds_out.m:
compiler/opt_debug.m:
Add builtin labels for the Aditi update operations.
compiler/hlds_module.m:
Add predicate predicate_table_search_pf_sym, used for finding
possible matches for a call with the wrong number of arguments.
compiler/intermod.m:
Don't write predicates which build `aditi_top_down' goals,
because there is currently no way to tell importing modules
which RL code fragment to use.
compiler/simplify.m:
Obey the `cannot_remove' field of explicit quantification goals.
compiler/make_hlds.m:
Parse Aditi updates.
Don't typecheck clauses for which syntax errors in Aditi updates
are found - this avoids spurious "undefined predicate `aditi_insert/3'"
errors.
Factor out some common code to handle terms of the form `Head :- Body'.
Factor out common code in the handling of pred and func expressions.
compiler/typecheck.m:
Typecheck Aditi builtins.
Allow the argument types of matching predicates to be adjusted
when typechecking the higher-order arguments of Aditi builtins.
Change `typecheck__resolve_pred_overloading' to take a list of
argument types rather than a `map(var, type)' and a list of
arguments to allow a transformation to be performed on the
argument types before passing them.
compiler/error_util.m:
Move the part of `report_error_num_args' which writes
"wrong number of arguments (<x>; expected <y>)" from
typecheck.m for use by make_hlds.m when reporting errors
for Aditi builtins.
compiler/modes.m:
compiler/unique_modes.m:
compiler/modecheck_call.m:
Modecheck Aditi builtins.
compiler/lambda.m:
Handle the markers for predicates introduced for
`aditi_top_down' and `aditi_bottom_up' lambda expressions.
compiler/polymorphism.m:
Add extra type_infos to `aditi_insert' calls
describing the tuple to insert.
compiler/call_gen.m:
Generate code for Aditi builtins.
compiler/unify_gen.m:
compiler/bytecode_gen.m:
Abort on `aditi_top_down' and `aditi_bottom_up' lambda
expressions - code generation for them is not yet implemented.
compiler/magic.m:
Use the `aditi_call' generic_call rather than create
a new procedure for each Aditi predicate called from C.
compiler/rl_out.pp:
compiler/rl_gen.m:
compiler/rl.m:
Move some utility code used by magic.m and call_gen.m into rl.m.
Remove an XXX comment about reference counting being not yet
implemented - Evan has fixed that.
library/ops.m:
compiler/mercury_to_mercury.m:
doc/transition_guide.texi:
Add unary prefix operators `aditi_bottom_up' and `aditi_top_down',
used as qualifiers on lambda expressions.
Add infix operator `==>' to separate the tuples in an
`aditi_modify' call.
compiler/follow_vars.m:
Thread a `map(prog_var, type)' through, needed because
type information is no longer held in higher-order call goals.
compiler/table_gen.m:
Use the `make_*_construction' predicates in hlds_goal.m
to construct constants.
compiler/*.m:
Trivial changes to add extra fields to hlds_goal structures.
doc/reference_manual.texi:
Document Aditi updates.
Use @samp{pragma base_relation} instead of
@samp{:- pragma base_relation} throughout the Aditi documentation
to be consistent with other parts of the reference manual.
tests/valid/Mmakefile:
tests/valid/aditi_update.m:
tests/valid/aditi.m:
Test case.
tests/valid/Mmakefile:
Remove some hard-coded --intermodule-optimization rules which are
no longer needed because `mmake depend' is now run in this directory.
tests/invalid/*.err_exp:
Fix expected output for changes in reporting of call_ids
in typecheck.m.
tests/invalid/Mmakefile
tests/invalid/aditi_update_errors.{m,err_exp}:
tests/invalid/aditi_update_mode_errors.{m,err_exp}:
Test error messages for Aditi updates.
tests/valid/aditi.m:
tests/invalid/aditi.m:
Cut down version of extras/aditi/aditi.m to provide basic declarations
for Aditi compilation such as `aditi__state' and the modes
`aditi_di', `aditi_uo' and `aditi_ui'. Installing extras/aditi/aditi.m
somewhere would remove the need for these.
969 lines
31 KiB
Mathematica
969 lines
31 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998-1999 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.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: rl.m
|
|
% Main author: stayl
|
|
%
|
|
% Intermediate form used for optimization of Aditi-RL code.
|
|
%
|
|
% Generated by rl_gen.m.
|
|
% Human readable debugging output by rl_dump.m.
|
|
% Output to RL bytecodes by rl_out.m.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
:- module rl.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_data, hlds_goal, hlds_module, hlds_pred.
|
|
:- import_module instmap, prog_data.
|
|
:- import_module assoc_list, list, std_util, map, set.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type rl_code == list(rl_proc).
|
|
|
|
:- type rl_proc
|
|
---> rl_proc(
|
|
rl_proc_name,
|
|
list(relation_id), % input argument relations
|
|
list(relation_id), % output argument relations
|
|
set(relation_id), % memoed relations
|
|
relation_info_map, % all relations used by the procedure
|
|
list(rl_instruction),
|
|
list(pred_proc_id) % list of Mercury procedures contained
|
|
% in this RL procedure
|
|
).
|
|
|
|
:- type rl_proc_name
|
|
---> rl_proc_name(
|
|
string, % user
|
|
string, % module
|
|
string, % name
|
|
int % arity
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type relation_id == int.
|
|
|
|
:- type relation_info_map == map(relation_id, relation_info).
|
|
|
|
:- type relation_info
|
|
---> relation_info(
|
|
relation_type,
|
|
list(type), % schema
|
|
list(index_spec),
|
|
% Only used for base relations - other relations
|
|
% may have different indexes at different times.
|
|
string % name
|
|
).
|
|
|
|
:- type relation_type
|
|
---> permanent(pred_proc_id)
|
|
; temporary(relation_state).
|
|
|
|
% It may be possible that we only want to materialise a relation
|
|
% along certain branches. That should be fairly simple to fix later
|
|
% if it is necessary.
|
|
:- type relation_state
|
|
---> materialised
|
|
; stream.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% A key range gives an upper and lower bound for the part of the
|
|
% indexed relation to search. For example, a simple B-tree join
|
|
% algorithm takes a tuple from first relation and uses it to build
|
|
% a key-range for the (indexed) second relation. The join condition
|
|
% is then applied to the tuple from the first relation and every tuple
|
|
% in the second which falls within the key range.
|
|
:- type key_range
|
|
---> key_range(
|
|
bounding_tuple, % lower bound
|
|
bounding_tuple, % upper bound
|
|
maybe(list(type)), % schema of the tuple used to generate
|
|
% the key range - there isn't one
|
|
% for selects.
|
|
list(type) % schema of the tuple used to search
|
|
% the B-tree index
|
|
).
|
|
|
|
:- type bounding_tuple
|
|
---> infinity % -infinity for lower bound,
|
|
% +infinity for upper bound
|
|
; bound(
|
|
assoc_list(int, key_attr)
|
|
% attributes of the key tuple, the
|
|
% associated integer is the index
|
|
% in a full tuple for that index
|
|
% attribute.
|
|
)
|
|
.
|
|
|
|
:- type key_attr
|
|
---> functor(cons_id, (type), list(key_attr))
|
|
; infinity % -infinity for lower bound,
|
|
% +infinity for upper
|
|
% This is currently not supported,
|
|
% since there may not be a way to
|
|
% construct a term representing
|
|
% infinity.
|
|
; input_field(int)
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% instruction and a comment.
|
|
:- type rl_instruction == pair(rl_instr, string).
|
|
|
|
:- type rl_instr
|
|
--->
|
|
join(
|
|
output_rel, % output
|
|
relation_id, % input 1
|
|
relation_id, % input 2
|
|
join_type,
|
|
rl_goal % join condition
|
|
)
|
|
;
|
|
subtract( % output = input 1 - input 2
|
|
output_rel, % output
|
|
relation_id, % input 1
|
|
relation_id, % input 2
|
|
subtract_type,
|
|
rl_goal % subtraction condition
|
|
)
|
|
;
|
|
% A difference is just a special case of subtract.
|
|
% The inputs must be sorted and have the same schema.
|
|
difference( % output = input 1 - input 2
|
|
output_rel, % output
|
|
relation_id, % input 1
|
|
relation_id, % input 2
|
|
difference_type
|
|
)
|
|
;
|
|
% A projection may have any number of output relations to
|
|
% avoid multiple traversals over the input relation.
|
|
% This also does selection - the expressions are allowed to
|
|
% fail.
|
|
% All but one of the outputs must be materialised - at the
|
|
% moment we materialise them all because it is difficult
|
|
% to ensure correctness for streams with side-effects.
|
|
project(
|
|
output_rel, % output (may be a stream)
|
|
relation_id, % input
|
|
rl_goal, % projection expression for
|
|
% stream output
|
|
assoc_list(output_rel, rl_goal),
|
|
% other outputs (materialised)
|
|
project_type
|
|
)
|
|
;
|
|
union(
|
|
output_rel, % output
|
|
list(relation_id), % inputs
|
|
union_type
|
|
)
|
|
;
|
|
% Output = Input1 U Input2, Difference = Input1 - Input2
|
|
% Input1 must have a B-tree index, and is destructively
|
|
% updated to create Output.
|
|
union_diff(
|
|
relation_id, % output (uo) (same indexes as input 1)
|
|
relation_id, % input 1 (di)
|
|
relation_id, % input 2 (in)
|
|
output_rel, % difference (out)
|
|
index_spec,
|
|
maybe(output_rel)
|
|
% Used by rl_liveness.m to make sure that
|
|
% the di input has a single reference. The
|
|
% relation_id is used to hold a copy of the
|
|
% di relation if required. The indexes should
|
|
% be added to the copy if it is made.
|
|
)
|
|
;
|
|
% Insert a relation into another relation.
|
|
% The input relation is destructively updated.
|
|
insert(
|
|
relation_id, % output (uo) (same indexes as di input)
|
|
relation_id, % relation to be inserted into (di)
|
|
relation_id, % relation to insert (in)
|
|
insert_type,
|
|
maybe(output_rel)
|
|
% Used by rl_liveness.m to make sure that
|
|
% the di input has a single reference. The
|
|
% relation_id is used to hold a copy of the
|
|
% di relation if required. The indexes should
|
|
% be added to the copy if it is made.
|
|
)
|
|
;
|
|
sort(
|
|
output_rel, % output
|
|
relation_id, % input
|
|
sort_attrs % attributes to sort on
|
|
)
|
|
;
|
|
% Make the output variable refer to the same relation
|
|
% as the input without copying.
|
|
ref(
|
|
relation_id, % output
|
|
relation_id % input
|
|
)
|
|
;
|
|
% Make a copy of the input relation, making sure the
|
|
% output has the given set of indexes.
|
|
% This could be a bit slow, because the system can't just
|
|
% copy the files, but has to do a full
|
|
copy(
|
|
output_rel, % output
|
|
relation_id % input
|
|
)
|
|
;
|
|
% If there are multiple references to the input, copy the
|
|
% input to the output, otherwise make the output a reference
|
|
% to the input. To introduce this, the compiler must know that
|
|
% there are no later references in the code to the input
|
|
% relation.
|
|
% Make sure the output has the given set of indexes, even
|
|
% if it isn't copied.
|
|
make_unique(
|
|
output_rel, % output
|
|
relation_id % input
|
|
)
|
|
;
|
|
% Create an empty relation.
|
|
init(output_rel)
|
|
;
|
|
% add a tuple to a relation.
|
|
insert_tuple(
|
|
output_rel, % output
|
|
relation_id, % input
|
|
rl_goal
|
|
)
|
|
;
|
|
% call an RL procedure
|
|
call(
|
|
rl_proc_name, % called procedure
|
|
list(relation_id), % input argument relations
|
|
list(output_rel), % output argument relations
|
|
set(relation_id) % subset of the inputs which
|
|
% must be saved across the call,
|
|
% filled in by rl_liveness.m.
|
|
)
|
|
;
|
|
aggregate(
|
|
output_rel, % output relation
|
|
relation_id, % input relation
|
|
pred_proc_id, % predicate to produce the
|
|
% initial accumulator for
|
|
% each group
|
|
pred_proc_id % predicate to update the
|
|
% accumulator for each tuple.
|
|
)
|
|
;
|
|
% Make sure the relation has the given index.
|
|
% We don't include a remove_index operation because it
|
|
% would be very expensive and probably not very useful.
|
|
add_index(output_rel)
|
|
;
|
|
% Empty a relation. This will be expensive for permanent
|
|
% relations due to logging.
|
|
clear(relation_id)
|
|
;
|
|
% Drop a pointer to a temporary relation. The relation
|
|
% is left unchanged, but may be garbage collected if
|
|
% there are no references to it.
|
|
unset(relation_id)
|
|
;
|
|
label(label_id)
|
|
;
|
|
conditional_goto(goto_cond, label_id)
|
|
;
|
|
goto(label_id)
|
|
;
|
|
comment
|
|
.
|
|
|
|
% An output relation first clears the initial contents of the
|
|
% relation, then initialises the relation with the given set
|
|
% of indexes.
|
|
:- type output_rel
|
|
---> output_rel(
|
|
relation_id,
|
|
list(index_spec)
|
|
).
|
|
|
|
:- type goto_cond
|
|
---> empty(relation_id)
|
|
; and(goto_cond, goto_cond)
|
|
; or(goto_cond, goto_cond)
|
|
; not(goto_cond).
|
|
|
|
:- type join_type
|
|
---> nested_loop
|
|
; sort_merge(sort_spec, sort_spec)
|
|
; index(index_spec, key_range)
|
|
% The second relation is indexed.
|
|
% Each tuple in the first relation
|
|
% is used to create a key range
|
|
% for accessing the second. The goal
|
|
% builds the lower and upper bounds
|
|
% on the key range from the input
|
|
% tuple from the first relation.
|
|
; cross
|
|
; semi % The output tuple is copied from the
|
|
% first input tuple. An output projection
|
|
% must be done as a separate operation.
|
|
.
|
|
|
|
:- type subtract_type
|
|
---> nested_loop
|
|
; sort_merge(sort_spec, sort_spec)
|
|
; index(index_spec, key_range)
|
|
.
|
|
|
|
:- type difference_type
|
|
---> sort_merge(sort_spec)
|
|
.
|
|
|
|
:- type project_type
|
|
---> filter
|
|
; index(index_spec, key_range)
|
|
.
|
|
|
|
:- type union_type
|
|
---> sort_merge(sort_spec)
|
|
.
|
|
|
|
:- type insert_type
|
|
---> append
|
|
; index(index_spec).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type sort_spec
|
|
---> sort_var(int) % Some operations, such as union,
|
|
% expect their inputs to be sorted
|
|
% on all attributes, but don't care
|
|
% in which order or direction.
|
|
; attributes(sort_attrs)
|
|
% Sort on the given attributes.
|
|
.
|
|
|
|
:- type sort_attrs == assoc_list(int, sort_dir).
|
|
|
|
:- type sort_dir
|
|
---> ascending
|
|
; descending
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% We delay converting join conditions to the lower level representation
|
|
% for as long as possible because they are easier to deal with in
|
|
% hlds_goal form.
|
|
:- type rl_goal
|
|
---> rl_goal(
|
|
maybe(pred_proc_id),
|
|
% Predicate from which the expression was
|
|
% taken - used to avoid unnecessarily merging
|
|
% varsets. Should be `no' if the varset
|
|
% contains vars from multiple procs.
|
|
prog_varset,
|
|
map(prog_var, type),
|
|
instmap, % instmap before goal
|
|
rl_goal_inputs,
|
|
rl_goal_outputs,
|
|
list(hlds_goal),
|
|
list(rl_var_bounds)
|
|
).
|
|
|
|
:- type rl_goal_inputs
|
|
---> no_inputs
|
|
; one_input(list(prog_var))
|
|
; two_inputs(list(prog_var), list(prog_var))
|
|
.
|
|
|
|
:- type rl_goal_outputs == maybe(list(prog_var)).
|
|
|
|
% A key_term is an intermediate form of a key_attr which keeps
|
|
% aliasing information. This can be converted into a key_range
|
|
% later. The set of variables attached to each node is the
|
|
% set of all variables in the goal which were found by rl_key.m
|
|
% to have that value.
|
|
:- type key_term == pair(key_term_node, set(prog_var)).
|
|
:- type key_term_node
|
|
---> functor(cons_id, (type), list(key_term))
|
|
; var
|
|
.
|
|
|
|
:- type rl_var_bounds == map(prog_var, pair(key_term)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type label_id == int.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl__default_temporary_state(module_info::in,
|
|
relation_state::out) is det.
|
|
|
|
% rl__instr_relations(Instr, InputRels, OutputRels).
|
|
:- pred rl__instr_relations(rl_instruction::in,
|
|
list(relation_id)::out, list(relation_id)::out) is det.
|
|
|
|
% Return all relations referenced by a goto condition.
|
|
:- pred rl__goto_cond_relations(goto_cond::in,
|
|
list(relation_id)::out) is det.
|
|
|
|
% Is the instructions a label, goto or conditional goto.
|
|
:- pred rl__instr_ends_block(rl_instruction).
|
|
:- mode rl__instr_ends_block(in) is semidet.
|
|
|
|
% Strip off the index specification from an output relation.
|
|
:- pred rl__output_rel_relation(output_rel::in, relation_id::out) is det.
|
|
|
|
% Get a sort specification sorting ascending on all attributes.
|
|
:- pred rl__ascending_sort_spec(list(type)::in, sort_attrs::out) is det.
|
|
|
|
% Get a list of all attributes for a given schema.
|
|
:- pred rl__attr_list(list(T)::in, list(int)::out) is det.
|
|
|
|
% Succeed if the goal contain any of the variables corresponding
|
|
% to the attributes of the given input tuple.
|
|
:- pred rl__goal_is_independent_of_input(tuple_num::in,
|
|
rl_goal::in, rl_goal::out) is semidet.
|
|
|
|
% Swap the inputs of a goal such as a join condition which
|
|
% as two input relations.
|
|
:- pred rl__swap_goal_inputs(rl_goal::in, rl_goal::out) is det.
|
|
|
|
% Succeed if the goal produces an output tuple.
|
|
:- pred rl__goal_produces_tuple(rl_goal::in) is semidet.
|
|
|
|
:- type tuple_num
|
|
---> one
|
|
; two
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Find out the name of the RL procedure corresponding
|
|
% to the given Mercury procedure.
|
|
:- pred rl__get_entry_proc_name(module_info, pred_proc_id, rl_proc_name).
|
|
:- mode rl__get_entry_proc_name(in, in, out) is det.
|
|
|
|
% Work out the name for a permanent relation.
|
|
:- pred rl__permanent_relation_name(module_info::in,
|
|
pred_id::in, string::out) is det.
|
|
|
|
% rl__get_permanent_relation_info(ModuleInfo, PredId,
|
|
% Owner, Module, Name, Arity, RelationName, SchemaString).
|
|
:- pred rl__get_permanent_relation_info(module_info::in, pred_id::in,
|
|
string::out, string::out, string::out, int::out,
|
|
string::out, string::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred rl__proc_name_to_string(rl_proc_name::in, string::out) is det.
|
|
:- pred rl__label_id_to_string(label_id::in, string::out) is det.
|
|
:- pred rl__relation_id_to_string(relation_id::in, string::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% rl__schemas_to_strings(ModuleInfo, SchemaLists,
|
|
% TypeDecls, SchemaStrings)
|
|
%
|
|
% Convert a list of lists of types to a list of schema strings,
|
|
% with the declarations for the types used in TypeDecls.
|
|
:- pred rl__schemas_to_strings(module_info::in,
|
|
list(list(type))::in, string::out, list(string)::out) is det.
|
|
|
|
% Convert a list of types to a schema string.
|
|
:- pred rl__schema_to_string(module_info::in,
|
|
list(type)::in, string::out) is det.
|
|
|
|
% Produce names acceptable to Aditi (just wrap single
|
|
% quotes around non-alphanumeric-and-underscore names).
|
|
:- pred rl__mangle_and_quote_type_name(type_id::in, list(type)::in,
|
|
string::out) is det.
|
|
:- pred rl__mangle_and_quote_ctor_name(sym_name::in,
|
|
int::in, string::out) is det.
|
|
|
|
% The expression stuff expects that constructor
|
|
% and type names are unquoted.
|
|
:- pred rl__mangle_type_name(type_id::in, list(type)::in,
|
|
string::out) is det.
|
|
:- pred rl__mangle_ctor_name(sym_name::in, int::in, string::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module code_util, globals, llds_out, options, prog_out.
|
|
:- import_module prog_util, type_util.
|
|
:- import_module bool, int, require, string.
|
|
|
|
rl__default_temporary_state(ModuleInfo, TmpState) :-
|
|
module_info_globals(ModuleInfo, Globals),
|
|
globals__lookup_bool_option(Globals, detect_rl_streams, Streams),
|
|
(
|
|
Streams = yes,
|
|
TmpState = stream
|
|
;
|
|
Streams = no,
|
|
% We have to assume that everything must be materialised.
|
|
TmpState = materialised
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__instr_relations(join(output_rel(Output, _), Input1, Input2, _, _) - _,
|
|
[Input1, Input2], [Output]).
|
|
rl__instr_relations(subtract(output_rel(Output, _),
|
|
Input1, Input2, _, _) - _, [Input1, Input2], [Output]).
|
|
rl__instr_relations(difference(output_rel(Output, _),
|
|
Input1, Input2, _) - _, [Input1, Input2], [Output]).
|
|
rl__instr_relations(project(OutputRel,
|
|
Input, _, OtherOutputRels, _) - _,
|
|
[Input], Outputs) :-
|
|
assoc_list__keys(OtherOutputRels, OutputRels),
|
|
list__map(rl__output_rel_relation,
|
|
[OutputRel | OutputRels], Outputs).
|
|
rl__instr_relations(union(OutputRel, Inputs, _) - _, Inputs, [Output]) :-
|
|
rl__output_rel_relation(OutputRel, Output).
|
|
rl__instr_relations(union_diff(UoOutput, DiInput, Input,
|
|
output_rel(Diff, _), _, _) - _,
|
|
[DiInput, Input], [UoOutput, Diff]).
|
|
rl__instr_relations(insert(DiOutput, DiInput, Input, _, _) - _,
|
|
[DiInput, Input], [DiOutput]).
|
|
rl__instr_relations(sort(output_rel(Output, _), Input, _) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(init(output_rel(Rel, _)) - _, [], [Rel]).
|
|
rl__instr_relations(insert_tuple(output_rel(Output, _), Input, _) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(add_index(output_rel(Rel, _)) - _, [Rel], [Rel]).
|
|
rl__instr_relations(clear(Rel) - _, [], [Rel]).
|
|
rl__instr_relations(unset(Rel) - _, [], [Rel]).
|
|
rl__instr_relations(label(_) - _, [], []).
|
|
rl__instr_relations(goto(_) - _, [], []).
|
|
rl__instr_relations(comment - _, [], []).
|
|
rl__instr_relations(conditional_goto(Cond, _) - _, Inputs, []) :-
|
|
rl__goto_cond_relations(Cond, Inputs).
|
|
rl__instr_relations(ref(Output, Input) - _, [Input], [Output]).
|
|
rl__instr_relations(copy(output_rel(Output, _), Input) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(make_unique(output_rel(Output, _), Input) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(aggregate(output_rel(Output, _), Input, _, _) - _,
|
|
[Input], [Output]).
|
|
rl__instr_relations(call(_, Inputs, OutputRels, _) - _,
|
|
Inputs, Outputs) :-
|
|
list__map(rl__output_rel_relation, OutputRels, Outputs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__instr_ends_block(goto(_) - _).
|
|
rl__instr_ends_block(label(_) - _).
|
|
rl__instr_ends_block(conditional_goto(_, _) - _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__output_rel_relation(output_rel(Output, _), Output).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__goto_cond_relations(empty(Rel), [Rel]).
|
|
rl__goto_cond_relations(and(Cond1, Cond2), Rels) :-
|
|
rl__goto_cond_relations(Cond1, Rels1),
|
|
rl__goto_cond_relations(Cond2, Rels2),
|
|
list__append(Rels1, Rels2, Rels).
|
|
rl__goto_cond_relations(or(Cond1, Cond2), Rels) :-
|
|
rl__goto_cond_relations(Cond1, Rels1),
|
|
rl__goto_cond_relations(Cond2, Rels2),
|
|
list__append(Rels1, Rels2, Rels).
|
|
rl__goto_cond_relations(not(Cond), Rels) :-
|
|
rl__goto_cond_relations(Cond, Rels).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__ascending_sort_spec(Schema, Attrs) :-
|
|
GetAttr =
|
|
lambda([_::in, Attr::out, Index0::in, Index::out] is det, (
|
|
Attr = Index0 - ascending,
|
|
Index is Index0 + 1
|
|
)),
|
|
list__map_foldl(GetAttr, Schema, Attrs, 0, _).
|
|
|
|
rl__attr_list(Schema, Attrs) :-
|
|
rl__attr_list_2(0, Schema, Attrs).
|
|
|
|
:- pred rl__attr_list_2(int::in, list(T)::in,
|
|
list(int)::out) is det.
|
|
|
|
rl__attr_list_2(_, [], []).
|
|
rl__attr_list_2(Index, [_ | Types], [Index | Attrs]) :-
|
|
NextIndex is Index + 1,
|
|
rl__attr_list_2(NextIndex, Types, Attrs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__goal_is_independent_of_input(InputNo, RLGoal0, RLGoal) :-
|
|
RLGoal0 = rl_goal(A, B, C, D, Inputs0, MaybeOutputs, Goals, H),
|
|
rl__select_input_args(InputNo, Inputs0, Inputs, InputArgs),
|
|
set__list_to_set(InputArgs, InputArgSet),
|
|
\+ (
|
|
MaybeOutputs = yes(Outputs),
|
|
set__list_to_set(Outputs, OutputSet),
|
|
set__intersect(OutputSet, InputArgSet, OutputIntersection),
|
|
\+ set__empty(OutputIntersection)
|
|
),
|
|
\+ (
|
|
list__member(Goal, Goals),
|
|
Goal = _ - GoalInfo,
|
|
goal_info_get_nonlocals(GoalInfo, NonLocals),
|
|
set__intersect(NonLocals, InputArgSet, Intersection),
|
|
\+ set__empty(Intersection)
|
|
),
|
|
RLGoal = rl_goal(A, B, C, D, Inputs, MaybeOutputs, Goals, H).
|
|
|
|
:- pred rl__select_input_args(tuple_num::in, rl_goal_inputs::in,
|
|
rl_goal_inputs::out, list(prog_var)::out) is det.
|
|
|
|
rl__select_input_args(_, no_inputs, _, _) :-
|
|
error("rl__select_input_args").
|
|
rl__select_input_args(one, one_input(Args), no_inputs, Args).
|
|
rl__select_input_args(two, one_input(_), _, _) :-
|
|
error("rl__select_input_args").
|
|
rl__select_input_args(one, two_inputs(Args, Args2),
|
|
one_input(Args2), Args).
|
|
rl__select_input_args(two, two_inputs(Args1, Args),
|
|
one_input(Args1), Args).
|
|
|
|
rl__swap_goal_inputs(RLGoal0, RLGoal) :-
|
|
RLGoal0 = rl_goal(A, B, C, D, Inputs0, F, G, H),
|
|
( Inputs0 = two_inputs(Inputs1, Inputs2) ->
|
|
RLGoal = rl_goal(A, B, C, D, two_inputs(Inputs2, Inputs1),
|
|
F, G, H)
|
|
;
|
|
error("rl__swap_inputs: goal does not have two inputs to swap")
|
|
).
|
|
|
|
rl__goal_produces_tuple(RLGoal) :-
|
|
RLGoal = rl_goal(_, _, _, _, _, yes(_), _, _).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__get_entry_proc_name(ModuleInfo, proc(PredId, ProcId), ProcName) :-
|
|
code_util__make_proc_label(ModuleInfo, PredId, ProcId, Label),
|
|
llds_out__get_proc_label(Label, no, ProcLabel),
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
pred_info_module(PredInfo, PredModule0),
|
|
pred_info_get_aditi_owner(PredInfo, Owner),
|
|
prog_out__sym_name_to_string(PredModule0, PredModule),
|
|
ProcName = rl_proc_name(Owner, PredModule, ProcLabel, 2).
|
|
|
|
rl__permanent_relation_name(ModuleInfo, PredId, ProcName) :-
|
|
rl__get_permanent_relation_info(ModuleInfo, PredId, Owner,
|
|
Module, _, _, Name, _),
|
|
string__format("%s/%s/%s", [s(Owner), s(Module), s(Name)],
|
|
ProcName).
|
|
|
|
rl__get_permanent_relation_info(ModuleInfo, PredId, Owner, PredModule,
|
|
PredName, PredArity, RelName, SchemaString) :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
pred_info_name(PredInfo, PredName),
|
|
pred_info_module(PredInfo, PredModule0),
|
|
prog_out__sym_name_to_string(PredModule0, PredModule),
|
|
pred_info_get_aditi_owner(PredInfo, Owner),
|
|
pred_info_arity(PredInfo, PredArity),
|
|
string__format("%s__%i", [s(PredName), i(PredArity)], RelName),
|
|
pred_info_arg_types(PredInfo, ArgTypes0),
|
|
type_util__remove_aditi_state(ArgTypes0, ArgTypes0, ArgTypes),
|
|
rl__schema_to_string(ModuleInfo, ArgTypes, SchemaString).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__proc_name_to_string(rl_proc_name(User, Module, Pred, Arity), Str) :-
|
|
string__int_to_string(Arity, ArStr),
|
|
string__append_list([User, "/", Module, "/", Pred, "/", ArStr], Str).
|
|
|
|
rl__label_id_to_string(Label, Str) :-
|
|
string__int_to_string(Label, Str0),
|
|
string__append("label", Str0, Str).
|
|
|
|
rl__relation_id_to_string(RelationId, Str) :-
|
|
string__int_to_string(RelationId, Str0),
|
|
string__append("Rel", Str0, Str).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
|
|
rl__schemas_to_strings(ModuleInfo, SchemaList, TypeDecls, SchemaStrings) :-
|
|
map__init(GatheredTypes0),
|
|
set__init(RecursiveTypes0),
|
|
rl__schemas_to_strings_2(ModuleInfo, GatheredTypes0, RecursiveTypes0,
|
|
SchemaList, "", TypeDecls, [], SchemaStrings).
|
|
|
|
:- pred rl__schemas_to_strings_2(module_info::in, gathered_types::in,
|
|
set(full_type_id)::in, list(list(type))::in,
|
|
string::in, string::out, list(string)::in, list(string)::out) is det.
|
|
|
|
rl__schemas_to_strings_2(_, _, _, [], TypeDecls, TypeDecls,
|
|
SchemaStrings0, SchemaStrings) :-
|
|
list__reverse(SchemaStrings0, SchemaStrings).
|
|
rl__schemas_to_strings_2(ModuleInfo, GatheredTypes0, RecursiveTypes0,
|
|
[Schema0 | Schemas], TypeDecls0, TypeDecls,
|
|
SchemaStrings0, SchemaStrings) :-
|
|
strip_prog_contexts(Schema0, Schema),
|
|
set__init(Parents0),
|
|
rl__gather_types(ModuleInfo, Parents0, Schema,
|
|
GatheredTypes0, GatheredTypes1,
|
|
RecursiveTypes0, RecursiveTypes1,
|
|
TypeDecls0, TypeDecls1,
|
|
"", SchemaString),
|
|
rl__schemas_to_strings_2(ModuleInfo, GatheredTypes1, RecursiveTypes1,
|
|
Schemas, TypeDecls1, TypeDecls,
|
|
[SchemaString | SchemaStrings0], SchemaStrings).
|
|
|
|
rl__schema_to_string(ModuleInfo, Types0, SchemaString) :-
|
|
map__init(GatheredTypes0),
|
|
set__init(RecursiveTypes0),
|
|
set__init(Parents0),
|
|
strip_prog_contexts(Types0, Types),
|
|
rl__gather_types(ModuleInfo, Parents0, Types,
|
|
GatheredTypes0, _, RecursiveTypes0, _, "", Decls,
|
|
"", SchemaString0),
|
|
string__append_list([Decls, "(", SchemaString0, ")"], SchemaString).
|
|
|
|
% Map from type to name and type definition string
|
|
:- type gathered_types == map(pair(type_id, list(type)), string).
|
|
:- type full_type_id == pair(type_id, list(type)).
|
|
|
|
% Go over a list of types collecting declarations for all the
|
|
% types used in the list.
|
|
:- pred rl__gather_types(module_info::in, set(full_type_id)::in,
|
|
list(type)::in, gathered_types::in, gathered_types::out,
|
|
set(full_type_id)::in, set(full_type_id)::out,
|
|
string::in, string::out, string::in, string::out) is det.
|
|
|
|
rl__gather_types(_, _, [], GatheredTypes, GatheredTypes,
|
|
RecursiveTypes, RecursiveTypes, Decls, Decls,
|
|
TypeString, TypeString).
|
|
rl__gather_types(ModuleInfo, Parents, [Type | Types], GatheredTypes0,
|
|
GatheredTypes, RecursiveTypes0, RecursiveTypes,
|
|
Decls0, Decls, TypeString0, TypeString) :-
|
|
rl__gather_type(ModuleInfo, Parents, Type, GatheredTypes0,
|
|
GatheredTypes1, RecursiveTypes0, RecursiveTypes1,
|
|
Decls0, Decls1, ThisTypeString),
|
|
( Types = [] ->
|
|
Comma = ""
|
|
;
|
|
Comma = ","
|
|
),
|
|
string__append_list([TypeString0, ThisTypeString, Comma], TypeString1),
|
|
rl__gather_types(ModuleInfo, Parents, Types, GatheredTypes1,
|
|
GatheredTypes, RecursiveTypes1, RecursiveTypes,
|
|
Decls1, Decls, TypeString1, TypeString).
|
|
|
|
:- pred rl__gather_type(module_info::in, set(full_type_id)::in, (type)::in,
|
|
gathered_types::in, gathered_types::out, set(full_type_id)::in,
|
|
set(full_type_id)::out, string::in, string::out,
|
|
string::out) is det.
|
|
|
|
rl__gather_type(ModuleInfo, Parents, Type, GatheredTypes0, GatheredTypes,
|
|
RecursiveTypes0, RecursiveTypes, Decls0, Decls, ThisType) :-
|
|
classify_type(Type, ModuleInfo, ClassifiedType0),
|
|
( ClassifiedType0 = enum_type ->
|
|
ClassifiedType = user_type
|
|
;
|
|
ClassifiedType = ClassifiedType0
|
|
),
|
|
(
|
|
ClassifiedType = enum_type,
|
|
% this is converted to user_type above
|
|
error("rl__gather_type: enum type")
|
|
;
|
|
ClassifiedType = polymorphic_type,
|
|
error("rl__gather_type: polymorphic type")
|
|
;
|
|
ClassifiedType = char_type,
|
|
GatheredTypes = GatheredTypes0,
|
|
RecursiveTypes = RecursiveTypes0,
|
|
Decls = Decls0,
|
|
ThisType = ":I"
|
|
;
|
|
ClassifiedType = int_type,
|
|
GatheredTypes = GatheredTypes0,
|
|
RecursiveTypes = RecursiveTypes0,
|
|
Decls = Decls0,
|
|
ThisType = ":I"
|
|
;
|
|
ClassifiedType = float_type,
|
|
GatheredTypes = GatheredTypes0,
|
|
RecursiveTypes = RecursiveTypes0,
|
|
Decls = Decls0,
|
|
ThisType = ":D"
|
|
;
|
|
ClassifiedType = str_type,
|
|
GatheredTypes = GatheredTypes0,
|
|
RecursiveTypes = RecursiveTypes0,
|
|
Decls = Decls0,
|
|
ThisType = ":S"
|
|
;
|
|
ClassifiedType = pred_type,
|
|
error("rl__gather_type: pred type")
|
|
;
|
|
ClassifiedType = user_type,
|
|
(
|
|
type_to_type_id(Type, TypeId, Args),
|
|
type_constructors(Type, ModuleInfo, Ctors)
|
|
->
|
|
( set__member(TypeId - Args, Parents) ->
|
|
set__insert(RecursiveTypes0, TypeId - Args,
|
|
RecursiveTypes1)
|
|
;
|
|
RecursiveTypes1 = RecursiveTypes0
|
|
),
|
|
(
|
|
map__search(GatheredTypes0, TypeId - Args,
|
|
MangledTypeName0)
|
|
->
|
|
GatheredTypes = GatheredTypes0,
|
|
Decls = Decls0,
|
|
MangledTypeName = MangledTypeName0,
|
|
RecursiveTypes = RecursiveTypes1
|
|
;
|
|
set__insert(Parents, TypeId - Args,
|
|
Parents1),
|
|
rl__mangle_and_quote_type_name(TypeId,
|
|
Args, MangledTypeName),
|
|
|
|
% Record that we have seen this type
|
|
% before processing the sub-terms.
|
|
map__det_insert(GatheredTypes0, TypeId - Args,
|
|
MangledTypeName, GatheredTypes1),
|
|
|
|
rl__gather_constructors(ModuleInfo,
|
|
Parents1, Ctors, GatheredTypes1,
|
|
GatheredTypes, RecursiveTypes1,
|
|
RecursiveTypes, Decls0, Decls1,
|
|
"", CtorDecls),
|
|
|
|
% Recursive types are marked by a
|
|
% second colon before their declaration.
|
|
( set__member(TypeId - Args, RecursiveTypes) ->
|
|
RecursiveSpec = ":"
|
|
;
|
|
RecursiveSpec = ""
|
|
),
|
|
string__append_list(
|
|
[Decls1, RecursiveSpec, ":",
|
|
MangledTypeName, "=", CtorDecls, " "],
|
|
Decls)
|
|
),
|
|
string__append(":T", MangledTypeName, ThisType)
|
|
;
|
|
error("rl__gather_type: type_constructors failed")
|
|
)
|
|
).
|
|
|
|
:- pred rl__gather_constructors(module_info::in, set(full_type_id)::in,
|
|
list(constructor)::in, map(full_type_id, string)::in,
|
|
map(full_type_id, string)::out, set(full_type_id)::in,
|
|
set(full_type_id)::out, string::in, string::out,
|
|
string::in, string::out) is det.
|
|
|
|
rl__gather_constructors(_, _, [], GatheredTypes, GatheredTypes,
|
|
RecursiveTypes, RecursiveTypes, Decls, Decls,
|
|
CtorDecls, CtorDecls).
|
|
rl__gather_constructors(ModuleInfo, Parents, [Ctor | Ctors],
|
|
GatheredTypes0, GatheredTypes, RecursiveTypes0, RecursiveTypes,
|
|
Decls0, Decls, CtorDecls0, CtorDecls) :-
|
|
Ctor = ctor(_, _, CtorName, Args),
|
|
list__length(Args, Arity),
|
|
rl__mangle_and_quote_ctor_name(CtorName, Arity, MangledCtorName),
|
|
|
|
Snd = lambda([Pair::in, Second::out] is det, Pair = _ - Second),
|
|
list__map(Snd, Args, ArgTypes),
|
|
rl__gather_types(ModuleInfo, Parents, ArgTypes, GatheredTypes0,
|
|
GatheredTypes1, RecursiveTypes0, RecursiveTypes1,
|
|
Decls0, Decls1, "", ArgList),
|
|
( Ctors = [] ->
|
|
Sep = ""
|
|
;
|
|
Sep = "|"
|
|
),
|
|
% Note that [] should be output as '[]'().
|
|
string__append_list(
|
|
[CtorDecls0, MangledCtorName, "(", ArgList, ")", Sep],
|
|
CtorDecls1),
|
|
rl__gather_constructors(ModuleInfo, Parents, Ctors,
|
|
GatheredTypes1, GatheredTypes, RecursiveTypes1, RecursiveTypes,
|
|
Decls1, Decls, CtorDecls1, CtorDecls).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
rl__mangle_and_quote_type_name(TypeId, Args, MangledTypeName) :-
|
|
rl__mangle_type_name(TypeId, Args, MangledTypeName0),
|
|
rl__maybe_quote_name(MangledTypeName0, MangledTypeName).
|
|
|
|
rl__mangle_type_name(TypeId, Args, MangledTypeName) :-
|
|
rl__mangle_type_name_2(TypeId, Args, "", MangledTypeName).
|
|
|
|
:- pred rl__mangle_type_name_2(type_id::in, list(type)::in,
|
|
string::in, string::out) is det.
|
|
|
|
rl__mangle_type_name_2(TypeId, Args, MangledTypeName0, MangledTypeName) :-
|
|
(
|
|
TypeId = qualified(Module0, Name) - Arity,
|
|
prog_out__sym_name_to_string(Module0, Module),
|
|
string__append_list([MangledTypeName0, Module, "__", Name],
|
|
MangledTypeName1)
|
|
;
|
|
TypeId = unqualified(TypeName) - Arity,
|
|
string__append(MangledTypeName0, TypeName, MangledTypeName1)
|
|
),
|
|
string__int_to_string(Arity, ArStr),
|
|
string__append_list([MangledTypeName1, "___", ArStr],
|
|
MangledTypeName2),
|
|
( Args = [] ->
|
|
MangledTypeName = MangledTypeName2
|
|
;
|
|
list__foldl(rl__mangle_type_arg, Args,
|
|
MangledTypeName2, MangledTypeName)
|
|
).
|
|
|
|
:- pred rl__mangle_type_arg((type)::in, string::in, string::out) is det.
|
|
|
|
rl__mangle_type_arg(Arg, String0, String) :-
|
|
string__append(String0, "___", String1),
|
|
( type_to_type_id(Arg, ArgTypeId, ArgTypeArgs) ->
|
|
rl__mangle_type_name_2(ArgTypeId, ArgTypeArgs,
|
|
String1, String)
|
|
;
|
|
error("rl__mangle_type_arg: type_to_type_id failed")
|
|
).
|
|
|
|
rl__mangle_ctor_name(CtorName, _Arity, MangledCtorName) :-
|
|
unqualify_name(CtorName, MangledCtorName).
|
|
|
|
rl__mangle_and_quote_ctor_name(CtorName, Arity, MangledCtorName) :-
|
|
rl__mangle_ctor_name(CtorName, Arity, MangledCtorName0),
|
|
rl__maybe_quote_name(MangledCtorName0, MangledCtorName).
|
|
|
|
:- pred rl__maybe_quote_name(string::in, string::out) is det.
|
|
|
|
rl__maybe_quote_name(Name0, Name) :-
|
|
( string__is_alnum_or_underscore(Name0) ->
|
|
Name = Name0
|
|
;
|
|
string__append_list(["'", Name0, "'"], Name)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|