mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 13:23:53 +00:00
Estimated hours taken: 100
Branches: main
Make definitions of abstract types available when generating
code for importing modules. This is necessary for the .NET
back-end, and for `:- pragma export' on the C back-end.
compiler/prog_data.m:
compiler/modules.m:
compiler/make.dependencies.m:
compiler/recompilation.version.m:
Handle implementation sections in interface files.
There is a new pseudo-declaration `abstract_imported'
which is applied to items from the implementation
section of an interface file. `abstract_imported'
items may not be used in the error checking passes
for the curent module.
compiler/equiv_type_hlds.m:
compiler/notes/compiler_design.html:
New file.
Go over the HLDS expanding all types fully after
semantic checking has been run.
compiler/mercury_compile.m:
Add the new pass.
Don't write the `.opt' file if there are any errors.
compiler/instmap.m:
Add a predicate instmap_delta_map_foldl to apply
a procedure to all insts in an instmap.
compiler/equiv_type.m:
Export predicates for use by equiv_type_hlds.m
Reorder arguments so state variables and higher-order
programming can be used.
compiler/prog_data.m:
compiler/prog_io_pragma.m:
compiler/make_hlds.m:
compiler/mercury_to_mercury.m:
Handle `:- pragma foreign_type' as a form of type
declaration rather than a pragma.
compiler/hlds_data.m:
compiler/*.m:
Add a field to the type_info_cell_constructor cons_id
to identify the type_ctor, which is needed by
equiv_type_hlds.m.
compiler/module_qual.m:
Donn't allow items from the implementation section of
interface files to match items in the current module.
compiler/*.m:
tests/*/*.m:
Add missing imports which only became apparent with
the bug fixes above.
Remove unnecessary imports which only became apparent with
the bug fixes above.
tests/hard_coded/Mmakefile:
tests/hard_coded/export_test2.{m,exp}:
Test case.
tests/invalid/Mmakefile:
tests/invalid/missing_interface_import2.{m,err_exp}:
Test case.
1465 lines
41 KiB
Mathematica
1465 lines
41 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2003 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.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: prog_data.m.
|
|
% Main author: fjh.
|
|
%
|
|
% This module defines a data structure for representing Mercury programs.
|
|
%
|
|
% This data structure specifies basically the same information as is
|
|
% contained in the source code, but in a parse tree rather than a flat file.
|
|
% Simplifications are done only by make_hlds.m, which transforms
|
|
% the parse tree which we built here into the HLDS.
|
|
|
|
:- module parse_tree__prog_data.
|
|
|
|
:- interface.
|
|
|
|
% This module should NOT import hlds*.m, either directly or indirectly.
|
|
% Any types which are needed in both the parse tree and in the HLDS
|
|
% should be defined here, rather than in hlds*.m.
|
|
|
|
:- import_module libs__globals.
|
|
:- import_module libs__options.
|
|
:- import_module parse_tree__inst.
|
|
:- import_module recompilation.
|
|
|
|
:- import_module bool, list, assoc_list, map, set, varset, term, std_util.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how programs (and parse errors) are represented.
|
|
|
|
:- type message_list == list(pair(string, term)).
|
|
% the error/warning message, and the
|
|
% term to which it relates
|
|
|
|
:- type compilation_unit
|
|
---> module(
|
|
module_name,
|
|
item_list
|
|
).
|
|
|
|
:- type item_list == list(item_and_context).
|
|
|
|
:- type item_and_context == pair(item, prog_context).
|
|
|
|
:- type item
|
|
---> clause(
|
|
cl_varset :: prog_varset,
|
|
cl_pred_or_func :: pred_or_func,
|
|
cl_predname :: sym_name,
|
|
cl_head_args :: list(prog_term),
|
|
cl_body :: goal
|
|
)
|
|
|
|
% `:- type ...':
|
|
% a definition of a type, or a declaration of an abstract type.
|
|
; type_defn(
|
|
td_tvarset :: tvarset,
|
|
td_ctor_name :: sym_name,
|
|
td_ctor_args :: list(type_param),
|
|
td_ctor_defn :: type_defn,
|
|
td_cond :: condition
|
|
)
|
|
|
|
% `:- inst ... = ...':
|
|
% a definition of an inst.
|
|
; inst_defn(
|
|
id_varset :: inst_varset,
|
|
id_inst_name :: sym_name,
|
|
id_inst_args :: list(inst_var),
|
|
id_inst_defn :: inst_defn,
|
|
id_cond :: condition
|
|
)
|
|
|
|
% `:- mode ... = ...':
|
|
% a definition of a mode.
|
|
; mode_defn(
|
|
md_varset :: inst_varset,
|
|
md_mode_name :: sym_name,
|
|
md_mode_args :: list(inst_var),
|
|
md_mode_defn :: mode_defn,
|
|
md_cond :: condition
|
|
)
|
|
|
|
; module_defn(
|
|
module_defn_varset :: prog_varset,
|
|
module_defn_module_defn :: module_defn
|
|
)
|
|
|
|
% `:- pred ...' or `:- func ...':
|
|
% a predicate or function declaration.
|
|
% This specifies the type of the predicate or function,
|
|
% and it may optionally also specify the mode and determinism.
|
|
; pred_or_func(
|
|
pf_tvarset :: tvarset,
|
|
pf_instvarset :: inst_varset,
|
|
pf_existqvars :: existq_tvars,
|
|
pf_which :: pred_or_func,
|
|
pf_name :: sym_name,
|
|
pf_arg_decls :: list(type_and_mode),
|
|
pf_maybe_with_type :: maybe(type),
|
|
pf_maybe_with_inst :: maybe(inst),
|
|
pf_maybe_detism :: maybe(determinism),
|
|
pf_cond :: condition,
|
|
pf_purity :: purity,
|
|
pf_class_context :: class_constraints
|
|
)
|
|
% The WithType and WithInst fields hold the `with_type`
|
|
% and `with_inst` annotations, which are syntactic
|
|
% sugar that is expanded by equiv_type.m
|
|
% equiv_type.m will set these fields to `no'.
|
|
|
|
% `:- mode ...':
|
|
% a mode declaration for a predicate or function.
|
|
; pred_or_func_mode(
|
|
pfm_instvarset :: inst_varset,
|
|
pfm_which :: maybe(pred_or_func),
|
|
pfm_name :: sym_name,
|
|
pfm_arg_modes :: list(mode),
|
|
pfm_maybe_with_inst :: maybe(inst),
|
|
pfm_maybe_detism :: maybe(determinism),
|
|
pfm_cond :: condition
|
|
)
|
|
% The WithInst field holds the `with_inst` annotation,
|
|
% which is syntactic sugar that is expanded by
|
|
% equiv_type.m. equiv_type.m will set the field to `no'.
|
|
|
|
; pragma(
|
|
pragma_type :: pragma_type
|
|
)
|
|
|
|
; promise(
|
|
prom_type :: promise_type,
|
|
prom_clause :: goal,
|
|
prom_varset :: prog_varset,
|
|
prom_univ_quant_vars :: prog_vars
|
|
)
|
|
|
|
; typeclass(
|
|
tc_constraints :: list(class_constraint),
|
|
tc_class_name :: class_name,
|
|
tc_class_params :: list(tvar),
|
|
tc_class_methods :: class_interface,
|
|
tc_varset :: tvarset
|
|
)
|
|
|
|
; instance(
|
|
ci_deriving_class :: list(class_constraint),
|
|
ci_class_name :: class_name,
|
|
ci_types :: list(type),
|
|
ci_method_instances :: instance_body,
|
|
ci_varset :: tvarset,
|
|
ci_module_containing_instance :: module_name
|
|
)
|
|
|
|
; nothing(
|
|
nothing_maybe_warning :: maybe(item_warning)
|
|
).
|
|
% used for items that should be ignored (e.g.
|
|
% NU-Prolog `when' declarations, which are silently
|
|
% ignored for backwards compatibility).
|
|
|
|
% indicates the type of information the compiler should get from the
|
|
% declaration's clause
|
|
:- type promise_type
|
|
% promise ex declarations
|
|
---> exclusive % each disjunct is mutually exclusive
|
|
; exhaustive % disjunction cannot fail
|
|
; exclusive_exhaustive % both of the above
|
|
|
|
% assertions
|
|
; true. % promise goal is true
|
|
|
|
:- type type_and_mode
|
|
---> type_only(type)
|
|
; type_and_mode(type, mode).
|
|
|
|
:- type pred_or_func
|
|
---> predicate
|
|
; function.
|
|
|
|
% Purity indicates whether a goal can have side effects or can
|
|
% depend on global state. See purity.m and the "Purity" section
|
|
% of the Mercury language reference manual.
|
|
:- type purity ---> pure
|
|
; (semipure)
|
|
; (impure).
|
|
|
|
% The `determinism' type specifies how many solutions a given
|
|
% procedure may have. Procedures for manipulating this type
|
|
% are defined in det_analysis.m and hlds_data.m.
|
|
:- type determinism
|
|
---> det
|
|
; semidet
|
|
; nondet
|
|
; multidet
|
|
; cc_nondet
|
|
; cc_multidet
|
|
; erroneous
|
|
; failure.
|
|
|
|
% The `is_solver_type' type specifies whether a type is a "solver" type,
|
|
% for which `any' insts are interpreted as "don't know", or a non-solver
|
|
% type for which `any' is the same as `bound(...)'.
|
|
:- type is_solver_type
|
|
---> non_solver_type
|
|
% The inst `any' is always `bound' for this type.
|
|
; solver_type.
|
|
% The inst `any' is not always `bound' for this type
|
|
% (i.e. the type was declared with
|
|
% `:- solver type ...').
|
|
|
|
:- type item_warning
|
|
---> item_warning(
|
|
maybe(option), % Option controlling whether the
|
|
% warning should be reported.
|
|
string, % The warning.
|
|
term % The term to which it relates.
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Pragmas
|
|
%
|
|
|
|
:- type pragma_type
|
|
%
|
|
% Foreign language interfacing pragmas
|
|
%
|
|
% a foreign language declaration, such as C
|
|
% header code.
|
|
---> foreign_decl(
|
|
decl_lang :: foreign_language,
|
|
decl_decl :: string
|
|
)
|
|
|
|
; foreign_code(
|
|
code_lang :: foreign_language,
|
|
code_code :: string)
|
|
|
|
; foreign_proc(
|
|
proc_attrs :: pragma_foreign_proc_attributes,
|
|
proc_name :: sym_name,
|
|
proc_p_or_f :: pred_or_func,
|
|
proc_vars :: list(pragma_var),
|
|
proc_varset :: prog_varset,
|
|
proc_impl :: pragma_foreign_code_impl
|
|
% Set of foreign proc attributes, eg.:
|
|
% what language this code is in
|
|
% whether or not the code may call Mercury,
|
|
% whether or not the code is thread-safe
|
|
% PredName, Predicate or Function, Vars/Mode,
|
|
% VarNames, Foreign Code Implementation Info
|
|
)
|
|
|
|
; foreign_import_module(
|
|
imp_lang :: foreign_language,
|
|
imp_module :: module_name
|
|
% Equivalent to
|
|
% `:- pragma foreign_decl(Lang, "#include <module>.h").'
|
|
% except that the name of the header file is not
|
|
% hard-coded, and mmake can use the dependency
|
|
% information.
|
|
)
|
|
|
|
; export(
|
|
exp_predname :: sym_name,
|
|
exp_p_or_f :: pred_or_func,
|
|
exp_modes :: list(mode),
|
|
exp_foreign_name :: string
|
|
% Predname, Predicate/function, Modes,
|
|
% foreign function name.
|
|
)
|
|
|
|
; import(
|
|
import_pred_name :: sym_name,
|
|
import_p_or_f :: pred_or_func,
|
|
import_modes :: list(mode),
|
|
import_attrs :: pragma_foreign_proc_attributes,
|
|
import_foreign_name :: string
|
|
% Predname, Predicate/function, Modes,
|
|
% Set of foreign proc attributes, eg.:
|
|
% whether or not the foreign code may call Mercury,
|
|
% whether or not the foreign code is thread-safe
|
|
% foreign function name.
|
|
)
|
|
%
|
|
% Optimization pragmas
|
|
%
|
|
; type_spec(
|
|
tspec_pred_name :: sym_name,
|
|
tspec_new_name :: sym_name,
|
|
tspec_arity :: arity,
|
|
tspec_p_or_f :: maybe(pred_or_func),
|
|
tspec_modes :: maybe(list(mode)),
|
|
tspec_tsubst :: type_subst,
|
|
tspec_tvarset :: tvarset,
|
|
tspec_items :: set(item_id)
|
|
% PredName, SpecializedPredName, Arity,
|
|
% PredOrFunc, Modes if a specific procedure was
|
|
% specified, type substitution (using the variable
|
|
% names from the pred declaration), TVarSet,
|
|
% Equivalence types used
|
|
)
|
|
|
|
; inline(
|
|
inline_name :: sym_name,
|
|
inline_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; no_inline(
|
|
noinline_name :: sym_name,
|
|
noinline_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; unused_args(
|
|
unused_p_or_f :: pred_or_func,
|
|
unused_name :: sym_name,
|
|
unused_arity :: arity,
|
|
unused_mode :: mode_num,
|
|
unused_args :: list(int)
|
|
% PredName, Arity, Mode number, Removed arguments.
|
|
% Used for inter-module unused argument
|
|
% removal, should only appear in .opt files.
|
|
)
|
|
|
|
%
|
|
% Diagnostics pragmas (pragmas related to compiler warnings/errors)
|
|
%
|
|
|
|
; obsolete(
|
|
obsolete_name :: sym_name,
|
|
obsolete_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; source_file(
|
|
source_file :: string
|
|
% Source file name.
|
|
)
|
|
|
|
%
|
|
% Evaluation method pragmas
|
|
%
|
|
|
|
; tabled(
|
|
tabled_method :: eval_method,
|
|
tabled_name :: sym_name,
|
|
tabled_arity :: int,
|
|
tabled_p_or_f :: maybe(pred_or_func),
|
|
tabled_mode :: maybe(list(mode))
|
|
% Tabling type, Predname, Arity, PredOrFunc?, Mode?
|
|
)
|
|
|
|
; fact_table(
|
|
fact_table_name :: sym_name,
|
|
fact_table_arity :: arity,
|
|
fact_table_file :: string
|
|
% Predname, Arity, Fact file name.
|
|
)
|
|
|
|
; reserve_tag(
|
|
restag_type :: sym_name,
|
|
restag_arity :: arity
|
|
% Typename, Arity
|
|
)
|
|
|
|
%
|
|
% Aditi pragmas
|
|
%
|
|
; aditi(
|
|
aditi_name :: sym_name,
|
|
aditi_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; base_relation(
|
|
baserel_name :: sym_name,
|
|
baserel_arity :: arity
|
|
% Predname, Arity
|
|
%
|
|
% Eventually, these should only occur in
|
|
% automatically generated database interface
|
|
% files, but for now there's no such thing,
|
|
% so they can occur in user programs.
|
|
)
|
|
|
|
; aditi_index(
|
|
index_name :: sym_name,
|
|
index_arity :: arity,
|
|
index_spec :: index_spec
|
|
% PredName, Arity, IndexType, Attributes
|
|
%
|
|
% Specify an index on a base relation.
|
|
)
|
|
|
|
; naive(
|
|
naive_name :: sym_name,
|
|
naive_arity :: arity
|
|
% Predname, Arity
|
|
% Use naive evaluation.
|
|
)
|
|
|
|
; psn(
|
|
psn_name :: sym_name,
|
|
psn_arity :: arity
|
|
% Predname, Arity
|
|
% Use predicate semi-naive evaluation.
|
|
)
|
|
|
|
; aditi_memo(
|
|
aditimemo_name :: sym_name,
|
|
aditimemo_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; aditi_no_memo(
|
|
aditinomemo_name :: sym_name,
|
|
aditinomemo_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; supp_magic(
|
|
suppmagic_name :: sym_name,
|
|
suppmagic_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; context(
|
|
context_name :: sym_name,
|
|
context_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; owner(
|
|
owner_name :: sym_name,
|
|
owner_arity :: arity,
|
|
owner_id :: string
|
|
% PredName, Arity, String.
|
|
)
|
|
|
|
%
|
|
% Purity pragmas
|
|
%
|
|
|
|
; promise_pure(
|
|
pure_name :: sym_name,
|
|
pure_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; promise_semipure(
|
|
semipure_name :: sym_name,
|
|
semipure_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
%
|
|
% Termination analysis pragmas
|
|
%
|
|
|
|
; termination_info(
|
|
terminfo_p_or_f :: pred_or_func,
|
|
terminfo_name :: sym_name,
|
|
terminfo_mode :: list(mode),
|
|
terminfo_args :: maybe(pragma_arg_size_info),
|
|
terminfo_term :: maybe(pragma_termination_info)
|
|
% the list(mode) is the declared argmodes of the
|
|
% procedure, unless there are no declared argmodes,
|
|
% in which case the inferred argmodes are used.
|
|
% This pragma is used to define information about a
|
|
% predicates termination properties. It is most
|
|
% useful where the compiler has insufficient
|
|
% information to be able to analyse the predicate.
|
|
% This includes c_code, and imported predicates.
|
|
% termination_info pragmas are used in opt and
|
|
% trans_opt files.
|
|
)
|
|
|
|
; terminates(
|
|
term_name :: sym_name,
|
|
term_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; does_not_terminate(
|
|
noterm_name :: sym_name,
|
|
noterm_arity :: arity
|
|
% Predname, Arity
|
|
)
|
|
|
|
; check_termination(
|
|
checkterm_name :: sym_name,
|
|
checkterm_arity :: arity
|
|
% Predname, Arity
|
|
).
|
|
|
|
%
|
|
% Stuff for the foreign interfacing pragmas.
|
|
%
|
|
|
|
%
|
|
% A foreign_language_type represents a type that is defined in a
|
|
% foreign language and accessed in Mercury (most likely through
|
|
% pragma foreign_type).
|
|
% Currently we only support foreign_language_types for IL.
|
|
%
|
|
|
|
|
|
%
|
|
% It is important to distinguish between IL value types and
|
|
% reference types, the compiler may need to generate different code
|
|
% for each of these cases.
|
|
%
|
|
|
|
:- type foreign_language_type
|
|
---> il(il_foreign_type)
|
|
; c(c_foreign_type)
|
|
; java(java_foreign_type)
|
|
.
|
|
|
|
:- type il_foreign_type
|
|
---> il(
|
|
ref_or_val, % An indicator of whether the type is a
|
|
% reference of value type.
|
|
string, % The location of the .NET name (the
|
|
% assembly)
|
|
sym_name % The .NET type name
|
|
).
|
|
|
|
:- type c_foreign_type
|
|
---> c(
|
|
string % The C type name
|
|
).
|
|
|
|
:- type java_foreign_type
|
|
---> java(
|
|
string % The Java type name
|
|
).
|
|
|
|
:- type ref_or_val
|
|
---> reference
|
|
; value.
|
|
|
|
%
|
|
% Stuff for tabling pragmas
|
|
%
|
|
|
|
% The evaluation method that should be used for a procedure.
|
|
% Ignored for Aditi procedures.
|
|
:- type eval_method
|
|
---> eval_normal % normal mercury
|
|
% evaluation
|
|
; eval_loop_check % loop check only
|
|
; eval_memo % memoing + loop check
|
|
; eval_table_io( % memoing I/O actions for debugging
|
|
table_io_is_decl,
|
|
table_io_is_unitize
|
|
)
|
|
; eval_minimal. % minimal model
|
|
% evaluation
|
|
|
|
:- type table_io_is_decl
|
|
---> table_io_decl % The procedure is tabled for
|
|
% declarative debugging.
|
|
; table_io_proc. % The procedure is tabled only for
|
|
% procedural debugging.
|
|
|
|
:- type table_io_is_unitize
|
|
---> table_io_unitize % The procedure is tabled for I/O
|
|
% together with its Mercury
|
|
% descendants.
|
|
; table_io_alone. % The procedure is tabled for I/O
|
|
% by itself; it can have no Mercury
|
|
% descendants.
|
|
|
|
%
|
|
% Stuff for the `aditi_index' pragma
|
|
%
|
|
|
|
% For Aditi base relations, an index_spec specifies how the base
|
|
% relation is indexed.
|
|
:- type index_spec
|
|
---> index_spec(
|
|
index_type,
|
|
list(int) % which attributes are being indexed on
|
|
% (attribute numbers start at 1)
|
|
).
|
|
|
|
% Hash indexes?
|
|
:- type index_type
|
|
---> unique_B_tree
|
|
; non_unique_B_tree.
|
|
|
|
%
|
|
% Stuff for the `termination_info' pragma.
|
|
% See term_util.m.
|
|
%
|
|
|
|
:- type pragma_arg_size_info
|
|
---> finite(int, list(bool))
|
|
% The termination constant is a finite integer.
|
|
% The list of bool has a 1:1 correspondence
|
|
% with the input arguments of the procedure.
|
|
% It stores whether the argument contributes
|
|
% to the size of the output arguments.
|
|
; infinite.
|
|
% There is no finite integer for which the
|
|
% above equation is true.
|
|
|
|
:- type pragma_termination_info
|
|
---> cannot_loop % This procedure definitely terminates for all
|
|
% possible inputs.
|
|
; can_loop. % This procedure might not terminate.
|
|
|
|
|
|
%
|
|
% Stuff for the `unused_args' pragma.
|
|
%
|
|
|
|
% This `mode_num' type is only used for mode numbers written out in
|
|
% automatically-generateed `pragma unused_args' pragmas in `.opt'
|
|
% files.
|
|
% The mode_num gets converted to an HLDS proc_id by make_hlds.m.
|
|
% We don't want to use the `proc_id' type here since the parse tree
|
|
% (prog_data.m) should not depend on the HLDS.
|
|
:- type mode_num == int.
|
|
|
|
%
|
|
% Stuff for the `type_spec' pragma.
|
|
%
|
|
|
|
% The type substitution for a `pragma type_spec' declaration.
|
|
% Elsewhere in the compiler we generally use the `tsubst' type
|
|
% which is a map rather than an assoc_list.
|
|
:- type type_subst == assoc_list(tvar, type).
|
|
|
|
%
|
|
% Stuff for `foreign_code' pragma.
|
|
%
|
|
|
|
% This type holds information about the implementation details
|
|
% of procedures defined via `pragma foreign_code'.
|
|
%
|
|
% All the strings in this type may be accompanied by the context
|
|
% of their appearance in the source code. These contexts are
|
|
% used to tell the foreign language compiler where the included
|
|
% code comes from, to allow it to generate error messages that
|
|
% refer to the original appearance of the code in the Mercury
|
|
% program.
|
|
% The context is missing if the foreign code was constructed by
|
|
% the compiler.
|
|
% Note that nondet pragma foreign definitions might not be
|
|
% possible in all foreign languages.
|
|
:- type pragma_foreign_code_impl
|
|
---> ordinary( % This is a foreign language
|
|
% definition of a model_det
|
|
% or model_semi procedure. (We
|
|
% also allow model_non, until
|
|
% everyone has had time to adapt
|
|
% to the new way
|
|
% of handling model_non pragmas.)
|
|
string, % The code of the procedure.
|
|
maybe(prog_context)
|
|
)
|
|
; nondet( % This is a foreign language
|
|
% definition of a model_non
|
|
% procedure.
|
|
string,
|
|
maybe(prog_context),
|
|
% The info saved for the time when
|
|
% backtracking reenters this procedure
|
|
% is stored in a data structure.
|
|
% This arg contains the field
|
|
% declarations.
|
|
|
|
string,
|
|
maybe(prog_context),
|
|
% Gives the code to be executed when
|
|
% the procedure is called for the first
|
|
% time. This code may access the input
|
|
% variables.
|
|
|
|
string,
|
|
maybe(prog_context),
|
|
% Gives the code to be executed when
|
|
% control backtracks into the procedure.
|
|
% This code may not access the input
|
|
% variables.
|
|
|
|
pragma_shared_code_treatment,
|
|
% How should the shared code be
|
|
% treated during code generation.
|
|
string,
|
|
maybe(prog_context)
|
|
% Shared code that is executed after
|
|
% both the previous code fragments.
|
|
% May not access the input variables.
|
|
)
|
|
; import(
|
|
string, % Pragma imported C func name
|
|
string, % Code to handle return value
|
|
string, % Comma seperated variables which
|
|
% the import function is called
|
|
% with.
|
|
|
|
maybe(prog_context)
|
|
).
|
|
|
|
% The use of this type is explained in the comment at the top of
|
|
% pragma_c_gen.m.
|
|
:- type pragma_shared_code_treatment
|
|
---> duplicate
|
|
; share
|
|
; automatic.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Stuff for type classes
|
|
%
|
|
|
|
% A class constraint represents a constraint that a given
|
|
% list of types is a member of the specified type class.
|
|
% It is an invariant of this data structure that
|
|
% the types in a class constraint do not contain any
|
|
% information in their prog_context fields.
|
|
% This invariant is needed to ensure that we can do
|
|
% unifications, map__lookups, etc., and get the
|
|
% expected semantics.
|
|
% (This invariant now applies to all types, but is
|
|
% especially important here.)
|
|
:- type class_constraint
|
|
---> constraint(class_name, list(type)).
|
|
|
|
:- type class_constraints
|
|
---> constraints(
|
|
univ_constraints :: list(class_constraint),
|
|
% universally quantified constraints
|
|
exist_constraints :: list(class_constraint)
|
|
% existentially quantified constraints
|
|
).
|
|
|
|
:- type class_name == sym_name.
|
|
|
|
:- type class_interface
|
|
---> abstract
|
|
; concrete(list(class_method)).
|
|
|
|
% The name class_method is a slight misnomer;
|
|
% this type actually represents any declaration
|
|
% that occurs in the body of a type class definition.
|
|
% Such declarations may either declare class methods,
|
|
% or they may declare modes of class methods.
|
|
:- type class_method
|
|
% pred_or_func(...) here represents a `pred ...' or `func ...'
|
|
% declaration in a type class body, which declares
|
|
% a predicate or function method. Such declarations
|
|
% specify the type of the predicate or function,
|
|
% and may optionally also specify the mode and determinism.
|
|
---> pred_or_func(tvarset, inst_varset, existq_tvars, pred_or_func,
|
|
sym_name, list(type_and_mode), maybe(type),
|
|
maybe(inst), maybe(determinism),
|
|
condition, purity, class_constraints, prog_context)
|
|
% TypeVarNames, InstVarNames,
|
|
% ExistentiallyQuantifiedTypeVars,
|
|
% PredOrFunc, PredName, ArgTypes, WithType, Determinism,
|
|
% Cond, Purity, ClassContext, Context
|
|
|
|
% pred_or_func_mode(...) here represents a `mode ...'
|
|
% declaration in a type class body. Such a declaration
|
|
% declares a mode for one of the type class methods.
|
|
; pred_or_func_mode(inst_varset, maybe(pred_or_func), sym_name,
|
|
list(mode), maybe(inst), maybe(determinism),
|
|
condition, prog_context)
|
|
% InstVarNames, MaybePredOrFunc, PredName, ArgModes,
|
|
% Determinism, WithInst, Cond
|
|
% Context
|
|
%
|
|
% For mode declarations using `with_inst` we don't
|
|
% know whether it's a predicate or function until
|
|
% we've expanded the inst.
|
|
.
|
|
|
|
:- type instance_method
|
|
---> instance_method(pred_or_func, sym_name, instance_proc_def,
|
|
arity, prog_context).
|
|
% PredOrFunc, Method, Instance, Arity,
|
|
% Line number of declaration
|
|
|
|
:- type instance_proc_def
|
|
% defined using the `pred(...) is <Name>' syntax
|
|
---> name(sym_name)
|
|
|
|
% defined using clauses
|
|
; clauses(
|
|
list(item) % the items must be either
|
|
% pred_clause or func_clause items
|
|
)
|
|
.
|
|
|
|
:- type instance_body
|
|
---> abstract
|
|
; concrete(instance_methods).
|
|
|
|
:- type instance_methods == list(instance_method).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Some more stuff for `pragma c_code'.
|
|
%
|
|
|
|
% an abstract type for representing a set of
|
|
% `pragma_c_code_attribute's.
|
|
:- type pragma_foreign_proc_attributes.
|
|
|
|
:- pred default_attributes(foreign_language, pragma_foreign_proc_attributes).
|
|
:- mode default_attributes(in, out) is det.
|
|
|
|
:- pred may_call_mercury(pragma_foreign_proc_attributes, may_call_mercury).
|
|
:- mode may_call_mercury(in, out) is det.
|
|
|
|
:- pred set_may_call_mercury(pragma_foreign_proc_attributes, may_call_mercury,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode set_may_call_mercury(in, in, out) is det.
|
|
|
|
:- pred thread_safe(pragma_foreign_proc_attributes, thread_safe).
|
|
:- mode thread_safe(in, out) is det.
|
|
|
|
:- pred purity(pragma_foreign_proc_attributes, purity).
|
|
:- mode purity(in, out) is det.
|
|
|
|
:- pred legacy_purity_behaviour(pragma_foreign_proc_attributes, bool).
|
|
:- mode legacy_purity_behaviour(in, out) is det.
|
|
|
|
:- pred set_thread_safe(pragma_foreign_proc_attributes, thread_safe,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode set_thread_safe(in, in, out) is det.
|
|
|
|
:- pred foreign_language(pragma_foreign_proc_attributes, foreign_language).
|
|
:- mode foreign_language(in, out) is det.
|
|
|
|
:- pred set_foreign_language(pragma_foreign_proc_attributes, foreign_language,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode set_foreign_language(in, in, out) is det.
|
|
|
|
:- pred tabled_for_io(pragma_foreign_proc_attributes, tabled_for_io).
|
|
:- mode tabled_for_io(in, out) is det.
|
|
|
|
:- pred set_tabled_for_io(pragma_foreign_proc_attributes, tabled_for_io,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode set_tabled_for_io(in, in, out) is det.
|
|
|
|
:- pred set_purity(pragma_foreign_proc_attributes, purity,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode set_purity(in, in, out) is det.
|
|
|
|
:- pred set_legacy_purity_behaviour(pragma_foreign_proc_attributes, bool,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode set_legacy_purity_behaviour(in, in, out) is det.
|
|
|
|
:- pred add_extra_attribute(pragma_foreign_proc_attributes,
|
|
pragma_foreign_proc_extra_attribute,
|
|
pragma_foreign_proc_attributes).
|
|
:- mode add_extra_attribute(in, in, out) is det.
|
|
|
|
:- func extra_attributes(pragma_foreign_proc_attributes)
|
|
= pragma_foreign_proc_extra_attributes.
|
|
|
|
% For pragma c_code, there are two different calling conventions,
|
|
% one for C code that may recursively call Mercury code, and another
|
|
% more efficient one for the case when we know that the C code will
|
|
% not recursively invoke Mercury code.
|
|
:- type may_call_mercury
|
|
---> may_call_mercury
|
|
; will_not_call_mercury.
|
|
|
|
% If thread_safe execution is enabled, then we need to put a mutex
|
|
% around the C code for each `pragma c_code' declaration, unless
|
|
% it's declared to be thread_safe.
|
|
:- type thread_safe
|
|
---> not_thread_safe
|
|
; thread_safe.
|
|
|
|
:- type tabled_for_io
|
|
---> not_tabled_for_io
|
|
; tabled_for_io
|
|
; tabled_for_io_unitize
|
|
; tabled_for_descendant_io.
|
|
|
|
:- type pragma_var
|
|
---> pragma_var(prog_var, string, mode).
|
|
% variable, name, mode
|
|
% we explicitly store the name because we need the real
|
|
% name in code_gen
|
|
|
|
:- type pragma_foreign_proc_extra_attribute
|
|
---> max_stack_size(int).
|
|
|
|
:- type pragma_foreign_proc_extra_attributes ==
|
|
list(pragma_foreign_proc_extra_attribute).
|
|
|
|
% Convert the foreign code attributes to their source code
|
|
% representations suitable for placing in the attributes list of
|
|
% the pragma (not all attributes have one).
|
|
% In particular, the foreign language attribute needs to be
|
|
% handled separately as it belongs at the start of the pragma.
|
|
:- pred attributes_to_strings(pragma_foreign_proc_attributes::in,
|
|
list(string)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Goals
|
|
%
|
|
|
|
% Here's how clauses and goals are represented.
|
|
% a => b --> implies(a, b)
|
|
% a <= b --> implies(b, a) [just flips the goals around!]
|
|
% a <=> b --> equivalent(a, b)
|
|
|
|
% clause/4 defined above
|
|
|
|
:- type goal == pair(goal_expr, prog_context).
|
|
|
|
:- type goal_expr
|
|
% conjunctions
|
|
---> (goal , goal) % (non-empty) conjunction
|
|
; true % empty conjunction
|
|
; {goal & goal} % parallel conjunction
|
|
% (The curly braces just quote the '&'/2.)
|
|
|
|
% disjunctions
|
|
; {goal ; goal} % (non-empty) disjunction
|
|
% (The curly braces just quote the ';'/2.)
|
|
; fail % empty disjunction
|
|
|
|
% quantifiers
|
|
; { some(prog_vars, goal) }
|
|
% existential quantification
|
|
% (The curly braces just quote the 'some'/2.)
|
|
; all(prog_vars, goal) % universal quantification
|
|
; some_state_vars(prog_vars, goal)
|
|
; all_state_vars(prog_vars, goal)
|
|
% state variables extracted from
|
|
% some/2 and all/2 quantifiers.
|
|
|
|
% implications
|
|
; implies(goal, goal) % A => B
|
|
; equivalent(goal, goal) % A <=> B
|
|
|
|
% negation and if-then-else
|
|
; not(goal)
|
|
; if_then(prog_vars, prog_vars, goal, goal)
|
|
% if_then(SomeVars, StateVars, If, Then)
|
|
; if_then_else(prog_vars, prog_vars, goal, goal, goal)
|
|
% if_then_else(SomeVars, StateVars,
|
|
% If, Then, Else)
|
|
|
|
% atomic goals
|
|
; call(sym_name, list(prog_term), purity)
|
|
; unify(prog_term, prog_term, purity).
|
|
|
|
:- type goals == list(goal).
|
|
|
|
% These type equivalences are for the type of program variables
|
|
% and associated structures.
|
|
|
|
:- type prog_var_type ---> prog_var_type.
|
|
:- type prog_var == var(prog_var_type).
|
|
:- type prog_varset == varset(prog_var_type).
|
|
:- type prog_substitution == substitution(prog_var_type).
|
|
:- type prog_term == term(prog_var_type).
|
|
:- type prog_vars == list(prog_var).
|
|
|
|
% A prog_context is just a term__context.
|
|
|
|
:- type prog_context == term__context.
|
|
|
|
% Describe how a lambda expression is to be evaluated.
|
|
%
|
|
% `normal' is the top-down Mercury execution algorithm.
|
|
%
|
|
% `lambda_eval_method's other than `normal' are used for lambda
|
|
% expressions constructed for arguments of the builtin Aditi
|
|
% update constructs.
|
|
%
|
|
% `aditi_bottom_up' expressions are used as database queries to
|
|
% produce a set of tuples to be inserted or deleted.
|
|
:- type lambda_eval_method
|
|
---> normal
|
|
; (aditi_bottom_up)
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Types
|
|
%
|
|
|
|
% This is how types are represented.
|
|
|
|
% one day we might allow types to take
|
|
% value parameters as well as type parameters.
|
|
|
|
% type_defn/3 is defined above as a constructor for item/0
|
|
|
|
:- type type_defn
|
|
---> du_type(list(constructor), is_solver_type, maybe(unify_compare))
|
|
; eqv_type(type)
|
|
; abstract_type(is_solver_type)
|
|
; foreign_type(foreign_language_type, maybe(unify_compare))
|
|
.
|
|
|
|
:- type constructor
|
|
---> ctor(
|
|
existq_tvars,
|
|
list(class_constraint), % existential constraints
|
|
sym_name,
|
|
list(constructor_arg)
|
|
).
|
|
|
|
:- type constructor_arg ==
|
|
pair(
|
|
maybe(ctor_field_name),
|
|
type
|
|
).
|
|
|
|
:- type ctor_field_name == sym_name.
|
|
|
|
% unify_compare gives the user-defined unification and/or comparison
|
|
% predicates for a noncanonical type, if they are known.
|
|
% The value `abstract_noncanonical_type' represents a discriminated
|
|
% union type whose definition uses the syntax
|
|
% `where type_is_abstract_noncanonical' and has been read from a .int2
|
|
% file. This means we know that the type has a noncanonical
|
|
% representation, but we don't know what the unification/comparison
|
|
% predicates are.
|
|
:- type unify_compare
|
|
---> unify_compare(
|
|
unify :: maybe(equality_pred),
|
|
compare :: maybe(comparison_pred)
|
|
)
|
|
; abstract_noncanonical_type.
|
|
|
|
% An equality_pred specifies the name of a user-defined predicate
|
|
% used for equality on a type. See the chapter on them in the
|
|
% Mercury Language Reference Manual.
|
|
:- type equality_pred == sym_name.
|
|
|
|
% The name of a user-defined comparison predicate.
|
|
:- type comparison_pred == sym_name.
|
|
|
|
% probably type parameters should be variables not terms.
|
|
:- type type_param == term(tvar_type).
|
|
|
|
% Module qualified types are represented as ':'/2 terms.
|
|
% Use type_util:type_to_ctor_and_args to convert a type to a qualified
|
|
% type_ctor and a list of arguments.
|
|
% type_util:construct_type to construct a type from a type_ctor
|
|
% and a list of arguments.
|
|
%
|
|
% The `term__context's of the type terms must be empty (as
|
|
% returned by term__context_init). prog_io_util__convert_type
|
|
% ensures this is the case. There are at least two reasons that this
|
|
% is required:
|
|
% - Various parts of the code to handle typeclasses creates maps
|
|
% indexed by `class_constraint's, which contain types.
|
|
% - Smart recompilation requires that the items which occur in
|
|
% interface files can be unified using the builtin unification
|
|
% operation.
|
|
:- type (type) == term(tvar_type).
|
|
:- type type_term == term(tvar_type).
|
|
|
|
:- type tvar_type ---> type_var.
|
|
:- type tvar == var(tvar_type).
|
|
% used for type variables
|
|
:- type tvarset == varset(tvar_type).
|
|
% used for sets of type variables
|
|
:- type tsubst == map(tvar, type). % used for type substitutions
|
|
|
|
:- type type_ctor == pair(sym_name, arity).
|
|
|
|
% existq_tvars is used to record the set of type variables which are
|
|
% existentially quantified
|
|
:- type existq_tvars == list(tvar).
|
|
|
|
% Types may have arbitrary assertions associated with them
|
|
% (eg. you can define a type which represents sorted lists).
|
|
% Similarly, pred declarations can have assertions attached.
|
|
% The compiler will ignore these assertions - they are intended
|
|
% to be used by other tools, such as the debugger.
|
|
|
|
:- type condition
|
|
---> true
|
|
; where(term).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% insts and modes
|
|
%
|
|
|
|
% This is how instantiatednesses and modes are represented.
|
|
% Note that while we use the normal term data structure to represent
|
|
% type terms (see above), we need a separate data structure for inst
|
|
% terms.
|
|
|
|
% The `inst' data type itself is defined in the module `inst.m'.
|
|
|
|
:- type inst_var_type ---> inst_var_type.
|
|
:- type inst_var == var(inst_var_type).
|
|
:- type inst_term == term(inst_var_type).
|
|
:- type inst_varset == varset(inst_var_type).
|
|
|
|
% inst_defn/3 defined above
|
|
|
|
:- type inst_defn
|
|
---> eqv_inst(inst)
|
|
; abstract_inst.
|
|
|
|
% An `inst_name' is used as a key for the inst_table.
|
|
% It is either a user-defined inst `user_inst(Name, Args)',
|
|
% or some sort of compiler-generated inst, whose name
|
|
% is a representation of it's meaning.
|
|
%
|
|
% For example, `merge_inst(InstA, InstB)' is the name used for the
|
|
% inst that results from merging InstA and InstB using `merge_inst'.
|
|
% Similarly `unify_inst(IsLive, InstA, InstB, IsReal)' is
|
|
% the name for the inst that results from a call to
|
|
% `abstractly_unify_inst(IsLive, InstA, InstB, IsReal)'.
|
|
% And `ground_inst' and `any_inst' are insts that result
|
|
% from unifying an inst with `ground' or `any', respectively.
|
|
% `typed_inst' is an inst with added type information.
|
|
% `typed_ground(Uniq, Type)' a equivalent to
|
|
% `typed_inst(ground(Uniq, no), Type)'.
|
|
% Note that `typed_ground' is a special case of `typed_inst',
|
|
% and `ground_inst' and `any_inst' are special cases of `unify_inst'.
|
|
% The reason for having the special cases is efficiency.
|
|
|
|
:- type inst_name
|
|
---> user_inst(sym_name, list(inst))
|
|
; merge_inst(inst, inst)
|
|
; unify_inst(is_live, inst, inst, unify_is_real)
|
|
; ground_inst(inst_name, is_live, uniqueness, unify_is_real)
|
|
; any_inst(inst_name, is_live, uniqueness, unify_is_real)
|
|
; shared_inst(inst_name)
|
|
; mostly_uniq_inst(inst_name)
|
|
; typed_ground(uniqueness, type)
|
|
; typed_inst(type, inst_name).
|
|
|
|
% Note: `is_live' records liveness in the sense used by
|
|
% mode analysis. This is not the same thing as the notion of liveness
|
|
% used by code generation. See compiler/notes/glossary.html.
|
|
:- type is_live ---> live ; dead.
|
|
|
|
% Unifications of insts fall into two categories, "real" and "fake".
|
|
% The "real" inst unifications correspond to real unifications,
|
|
% and are not allowed to unify with `clobbered' insts (unless
|
|
% the unification would be `det').
|
|
% Any inst unification which is associated with some code that
|
|
% will actually examine the contents of the variables in question
|
|
% must be "real". Inst unifications that are not associated with
|
|
% some real code that examines the variables' values are "fake".
|
|
% "Fake" inst unifications are used for procedure calls in implied
|
|
% modes, where the final inst of the var must be computed by
|
|
% unifying its initial inst with the procedure's final inst,
|
|
% so that if you pass a ground var to a procedure whose mode
|
|
% is `free -> list_skeleton', the result is ground, not list_skeleton.
|
|
% But these fake unifications must be allowed to unify with `clobbered'
|
|
% insts. Hence we pass down a flag to `abstractly_unify_inst' which
|
|
% specifies whether or not to allow unifications with clobbered values.
|
|
|
|
:- type unify_is_real
|
|
---> real_unify
|
|
; fake_unify.
|
|
|
|
% mode_defn/3 defined above
|
|
|
|
:- type mode_defn
|
|
---> eqv_mode(mode).
|
|
|
|
:- type (mode)
|
|
---> ((inst) -> (inst))
|
|
; user_defined_mode(sym_name, list(inst)).
|
|
|
|
% mode/4 defined above
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Module system
|
|
%
|
|
|
|
% This is how module-system declarations (such as imports
|
|
% and exports) are represented.
|
|
|
|
:- type module_defn
|
|
---> module(module_name)
|
|
; end_module(module_name)
|
|
|
|
; interface
|
|
; implementation
|
|
|
|
; private_interface
|
|
% This is used internally by the compiler,
|
|
% to identify items which originally
|
|
% came from an implementation section
|
|
% for a module that contains sub-modules;
|
|
% such items need to be exported to the
|
|
% sub-modules.
|
|
|
|
; imported(import_locn)
|
|
% This is used internally by the compiler,
|
|
% to identify declarations which originally
|
|
% came from some other module imported with
|
|
% a `:- import_module' declaration, and which
|
|
% section the module was imported.
|
|
; used(import_locn)
|
|
% This is used internally by the compiler,
|
|
% to identify declarations which originally
|
|
% came from some other module and for which
|
|
% all uses must be module qualified. This
|
|
% applies to items from modules imported using
|
|
% `:- use_module', and items from `.opt'
|
|
% and `.int2' files. It also records from which
|
|
% section the module was imported.
|
|
; abstract_imported
|
|
% This is used internally by the compiler,
|
|
% to identify items which originally
|
|
% came from the implementation section
|
|
% of an interface file; usually type
|
|
% declarations (especially equivalence types)
|
|
% which should be used in code generation
|
|
% but not in type checking.
|
|
; opt_imported
|
|
% This is used internally by the compiler,
|
|
% to identify items which originally
|
|
% came from a .opt file.
|
|
; transitively_imported
|
|
% This is used internally by the compiler,
|
|
% to identify items which originally
|
|
% came from a `.opt' or `.int2' file.
|
|
% These should not be allowed to
|
|
% match items in the current module.
|
|
% Note that unlike `:- interface', `:- implementation'
|
|
% and the other pseudo-declarations `:- imported(interface)',
|
|
% etc., a `:- transitively_imported' declaration
|
|
% applies to all of the following items in the list,
|
|
% not just up to the next pseudo-declaration.
|
|
|
|
; external(sym_name_specifier)
|
|
|
|
; export(sym_list)
|
|
; import(sym_list)
|
|
; use(sym_list)
|
|
|
|
; include_module(list(module_name))
|
|
|
|
% This is used to represent the version numbers
|
|
% of items in an interface file for use in
|
|
% smart recompilation.
|
|
; version_numbers(module_name, recompilation__version_numbers).
|
|
|
|
:- type section
|
|
---> implementation
|
|
; interface.
|
|
|
|
% An import_locn is used to describe the place where an item was
|
|
% imported from.
|
|
:- type import_locn
|
|
--->
|
|
% The item is from a module imported in the implementation.
|
|
implementation
|
|
|
|
% The item is from a module imported in the interface.
|
|
; interface
|
|
|
|
% The item is from a module imported by an ancestor.
|
|
; ancestor
|
|
|
|
% The item is from the private interface of an ancestor module.
|
|
; ancestor_private_interface
|
|
.
|
|
|
|
:- type sym_list
|
|
---> sym(list(sym_specifier))
|
|
; pred(list(pred_specifier))
|
|
; func(list(func_specifier))
|
|
; cons(list(cons_specifier))
|
|
; op(list(op_specifier))
|
|
; adt(list(adt_specifier))
|
|
; type(list(type_specifier))
|
|
; module(list(module_specifier)).
|
|
|
|
:- type sym_specifier
|
|
---> sym(sym_name_specifier)
|
|
; typed_sym(typed_cons_specifier)
|
|
; pred(pred_specifier)
|
|
; func(func_specifier)
|
|
; cons(cons_specifier)
|
|
; op(op_specifier)
|
|
; adt(adt_specifier)
|
|
; type(type_specifier)
|
|
; module(module_specifier).
|
|
:- type pred_specifier
|
|
---> sym(sym_name_specifier)
|
|
; name_args(sym_name, list(type)).
|
|
:- type func_specifier == cons_specifier.
|
|
:- type cons_specifier
|
|
---> sym(sym_name_specifier)
|
|
; typed(typed_cons_specifier).
|
|
:- type typed_cons_specifier
|
|
---> name_args(sym_name, list(type))
|
|
; name_res(sym_name_specifier, type)
|
|
; name_args_res(sym_name, list(type), type).
|
|
:- type adt_specifier == sym_name_specifier.
|
|
:- type type_specifier == sym_name_specifier.
|
|
:- type op_specifier
|
|
---> sym(sym_name_specifier)
|
|
% operator fixity specifiers not yet implemented
|
|
; fixity(sym_name_specifier, fixity).
|
|
:- type fixity
|
|
---> infix
|
|
; prefix
|
|
; postfix
|
|
; binary_prefix
|
|
; binary_postfix.
|
|
:- type sym_name_specifier
|
|
---> name(sym_name)
|
|
; name_arity(sym_name, arity).
|
|
:- type sym_name
|
|
---> unqualified(string)
|
|
; qualified(module_specifier, string).
|
|
:- type sym_name_and_arity
|
|
---> sym_name / arity.
|
|
|
|
:- type module_specifier == sym_name.
|
|
:- type module_name == sym_name.
|
|
:- type arity == int.
|
|
|
|
% Describes whether an item can be used without an
|
|
% explicit module qualifier.
|
|
:- type need_qualifier
|
|
---> must_be_qualified
|
|
; may_be_unqualified.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds__purity.
|
|
|
|
:- import_module string.
|
|
|
|
:- type pragma_foreign_proc_attributes
|
|
---> attributes(
|
|
foreign_language :: foreign_language,
|
|
may_call_mercury :: may_call_mercury,
|
|
thread_safe :: thread_safe,
|
|
tabled_for_io :: tabled_for_io,
|
|
purity :: purity,
|
|
% there is some special case behaviour for
|
|
% pragma c_code and pragma import purity
|
|
% if legacy_purity_behaviour is `yes'
|
|
legacy_purity_behaviour :: bool,
|
|
extra_attributes ::
|
|
list(pragma_foreign_proc_extra_attribute)
|
|
).
|
|
|
|
|
|
default_attributes(Language,
|
|
attributes(Language, may_call_mercury, not_thread_safe,
|
|
not_tabled_for_io, impure, no, [])).
|
|
|
|
may_call_mercury(Attrs, Attrs ^ may_call_mercury).
|
|
|
|
thread_safe(Attrs, Attrs ^ thread_safe).
|
|
|
|
foreign_language(Attrs, Attrs ^ foreign_language).
|
|
|
|
tabled_for_io(Attrs, Attrs ^ tabled_for_io).
|
|
|
|
purity(Attrs, Attrs ^ purity).
|
|
|
|
legacy_purity_behaviour(Attrs, Attrs ^ legacy_purity_behaviour).
|
|
|
|
set_may_call_mercury(Attrs0, MayCallMercury, Attrs) :-
|
|
Attrs = Attrs0 ^ may_call_mercury := MayCallMercury.
|
|
|
|
set_thread_safe(Attrs0, ThreadSafe, Attrs) :-
|
|
Attrs = Attrs0 ^ thread_safe := ThreadSafe.
|
|
|
|
set_foreign_language(Attrs0, ForeignLanguage, Attrs) :-
|
|
Attrs = Attrs0 ^ foreign_language := ForeignLanguage.
|
|
|
|
set_tabled_for_io(Attrs0, TabledForIo, Attrs) :-
|
|
Attrs = Attrs0 ^ tabled_for_io := TabledForIo.
|
|
|
|
set_purity(Attrs0, Purity, Attrs) :-
|
|
Attrs = Attrs0 ^ purity := Purity.
|
|
|
|
set_legacy_purity_behaviour(Attrs0, Legacy, Attrs) :-
|
|
Attrs = Attrs0 ^ legacy_purity_behaviour := Legacy.
|
|
|
|
attributes_to_strings(Attrs, StringList) :-
|
|
% We ignore Lang because it isn't an attribute that you can put
|
|
% in the attribute list -- the foreign language specifier string
|
|
% is at the start of the pragma.
|
|
Attrs = attributes(_Lang, MayCallMercury, ThreadSafe, TabledForIO,
|
|
Purity, _LegacyBehaviour, ExtraAttributes),
|
|
(
|
|
MayCallMercury = may_call_mercury,
|
|
MayCallMercuryStr = "may_call_mercury"
|
|
;
|
|
MayCallMercury = will_not_call_mercury,
|
|
MayCallMercuryStr = "will_not_call_mercury"
|
|
),
|
|
(
|
|
ThreadSafe = not_thread_safe,
|
|
ThreadSafeStr = "not_thread_safe"
|
|
;
|
|
ThreadSafe = thread_safe,
|
|
ThreadSafeStr = "thread_safe"
|
|
),
|
|
(
|
|
TabledForIO = tabled_for_io,
|
|
TabledForIOStr = "tabled_for_io"
|
|
;
|
|
TabledForIO = tabled_for_io_unitize,
|
|
TabledForIOStr = "tabled_for_io_unitize"
|
|
;
|
|
TabledForIO = tabled_for_descendant_io,
|
|
TabledForIOStr = "tabled_for_descendant_io"
|
|
;
|
|
TabledForIO = not_tabled_for_io,
|
|
TabledForIOStr = "not_tabled_for_io"
|
|
),
|
|
(
|
|
Purity = pure,
|
|
PurityStrList = ["promise_pure"]
|
|
;
|
|
Purity = (semipure),
|
|
PurityStrList = ["promise_semipure"]
|
|
;
|
|
Purity = (impure),
|
|
PurityStrList = []
|
|
),
|
|
StringList = [MayCallMercuryStr, ThreadSafeStr, TabledForIOStr |
|
|
PurityStrList] ++
|
|
list__map(extra_attribute_to_string, ExtraAttributes).
|
|
|
|
add_extra_attribute(Attributes0, NewAttribute,
|
|
Attributes0 ^ extra_attributes :=
|
|
[NewAttribute | Attributes0 ^ extra_attributes]).
|
|
|
|
:- func extra_attribute_to_string(pragma_foreign_proc_extra_attribute)
|
|
= string.
|
|
extra_attribute_to_string(max_stack_size(Size)) =
|
|
"max_stack_size(" ++ string__int_to_string(Size) ++ ")".
|
|
|
|
%-----------------------------------------------------------------------------%
|