mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 14:57:03 +00:00
Estimated hours taken: 3
Implement a new `:- pragma source_file("<source file name>").' declaration,
and a `#<line number>' directive, to make it more convenient to use
preprocessors or to use Mercury as a target language.
prog_data.m:
Add `source_file' pragma.
make_hlds.m, module_qual.m:
Ignore `pragma source_file' declarations.
mercury_to_mercury.m:
Print `pragma source_file' declarations.
Simplify a couple of unnecessarily complicated bits of code.
prog_io.m:
Parse `source_file' pragmas. When parsing items, check for them;
handle `pragma source_file' declarations by keeping track of the
source file name, and passing it to parser__parse_term/4.
Also, change the "Error: module should start with a `:- module'
declaration" message from an error to a warning.
Also, fix the capitalization in a bunch of error messages:
change from "Error: Blah" to "Error: blah".
348 lines
12 KiB
Mathematica
348 lines
12 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995 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 prog_data.
|
|
:- interface.
|
|
:- import_module hlds_pred.
|
|
:- import_module string, int, list, varset, term, std_util, require.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% 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 program ---> module(
|
|
module_name,
|
|
item_list
|
|
).
|
|
|
|
:- type item_list == list(item_and_context).
|
|
|
|
:- type item_and_context == pair(item, term__context).
|
|
|
|
:- type item ---> pred_clause(varset, sym_name, list(term), goal)
|
|
% VarNames, PredName, HeadArgs, ClauseBody
|
|
; func_clause(varset, sym_name, list(term), term,
|
|
goal)
|
|
% VarNames, PredName, HeadArgs, Result,
|
|
% ClauseBody
|
|
; type_defn(varset, type_defn, condition)
|
|
; inst_defn(varset, inst_defn, condition)
|
|
; mode_defn(varset, mode_defn, condition)
|
|
; module_defn(varset, module_defn)
|
|
; pred(varset, sym_name, list(type_and_mode),
|
|
maybe(determinism), condition)
|
|
% VarNames, PredName, ArgTypes,
|
|
% Deterministicness, Cond
|
|
; func(varset, sym_name, list(type_and_mode),
|
|
type_and_mode,
|
|
maybe(determinism), condition)
|
|
% VarNames, PredName, ArgTypes,
|
|
% ReturnType,
|
|
% Deterministicness, Cond
|
|
; pred_mode(varset, sym_name, list(mode),
|
|
maybe(determinism), condition)
|
|
% VarNames, PredName, ArgModes,
|
|
% Deterministicness, Cond
|
|
; func_mode(varset, sym_name, list(mode), mode,
|
|
maybe(determinism), condition)
|
|
% VarNames, PredName, ArgModes,
|
|
% ReturnValueMode,
|
|
% Deterministicness, Cond
|
|
; pragma(pragma_type)
|
|
; nothing.
|
|
% used for items that should be ignored
|
|
% (currently only NU-Prolog `when' declarations,
|
|
% which are silently ignored for backwards
|
|
% compatibility).
|
|
|
|
:- type type_and_mode ---> type_only(type)
|
|
; type_and_mode(type, mode).
|
|
|
|
:- type pragma_type ---> c_header_code(string)
|
|
; c_code(string)
|
|
; c_code(c_is_recursive, sym_name,
|
|
list(pragma_var), varset, string)
|
|
% Whether or not the C code may call Mercury,
|
|
% PredName, Vars/Mode, VarNames, C Code
|
|
; memo(sym_name, int)
|
|
% Predname, Arity
|
|
; inline(sym_name, int)
|
|
% Predname, Arity
|
|
; obsolete(sym_name, int)
|
|
% Predname, Arity
|
|
; export(sym_name, list(mode), string)
|
|
% Predname, Modes, C function name.
|
|
; source_file(string).
|
|
% Source file name.
|
|
|
|
% 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 c_is_recursive
|
|
---> recursive % possibly recursive
|
|
; non_recursive. % definitely not recursive
|
|
|
|
:- type pragma_var ---> pragma_var(var, string, mode).
|
|
% variable, name, mode
|
|
% we explicitly store the name because we
|
|
% need the real name in code_gen
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% 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, term__context).
|
|
:- type goal_expr ---> (goal,goal)
|
|
; true
|
|
% could use conj(goals) instead
|
|
; {goal;goal} % {...} quotes ';'/2.
|
|
; fail
|
|
% could use disj(goals) instead
|
|
; not(goal)
|
|
; some(vars,goal)
|
|
; all(vars,goal)
|
|
; implies(goal,goal)
|
|
; equivalent(goal,goal)
|
|
; if_then(vars,goal,goal)
|
|
; if_then_else(vars,goal,goal,goal)
|
|
; call(sym_name, list(term))
|
|
; unify(term, term).
|
|
|
|
:- type goals == list(goal).
|
|
:- type vars == list(var).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how types are represented.
|
|
|
|
% one day we might allow types to take
|
|
% value parameters as well as type parameters.
|
|
|
|
% type_defn/3 define above
|
|
|
|
:- type type_defn ---> du_type(sym_name, list(type_param),
|
|
list(constructor))
|
|
; uu_type(sym_name, list(type_param), list(type))
|
|
; eqv_type(sym_name, list(type_param), type)
|
|
; abstract_type(sym_name, list(type_param)).
|
|
|
|
:- type constructor == pair(sym_name, list(type)).
|
|
|
|
% probably type parameters should be variables not terms.
|
|
:- type type_param == term.
|
|
|
|
% Module qualified types are represented as ':'/2 terms.
|
|
% Use type_util:type_to_type_id to convert a type to a qualified
|
|
% type_id and a list of arguments.
|
|
% type_util:construct_type to construct a type from a type_id
|
|
% and a list of arguments.
|
|
:- type (type) == term.
|
|
|
|
:- type tvar == var. % used for type variables
|
|
:- type tvarset == varset. % used for sets of type variables
|
|
:- type tsubst == map(tvar, type). % used for type substitutions
|
|
|
|
% 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).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% 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.
|
|
|
|
% inst_defn/3 defined above
|
|
|
|
:- type inst_defn ---> eqv_inst(sym_name, list(inst_param), inst)
|
|
; abstract_inst(sym_name, list(inst_param)).
|
|
|
|
% probably inst parameters should be variables not terms
|
|
:- type inst_param == term.
|
|
|
|
:- type (inst) ---> any(uniqueness)
|
|
; free
|
|
; free(type)
|
|
; bound(uniqueness, list(bound_inst))
|
|
% The list(bound_inst) must be sorted
|
|
; ground(uniqueness, maybe(pred_inst_info))
|
|
% The pred_inst_info is used for
|
|
% higher-order pred modes
|
|
; not_reached
|
|
; inst_var(var)
|
|
; defined_inst(inst_name)
|
|
% An abstract inst is a defined inst which
|
|
% has been declared but not actually been
|
|
% defined (yet).
|
|
; abstract_inst(sym_name, list(inst)).
|
|
|
|
:- type uniqueness
|
|
---> shared % there might be other references
|
|
; unique % there is only one reference
|
|
; mostly_unique % there is only one reference
|
|
% but there might be more on
|
|
% backtracking
|
|
; clobbered % this was the only reference, but
|
|
% the data has already been reused
|
|
; mostly_clobbered.
|
|
% this was the only reference, but
|
|
% the data has already been reused;
|
|
% however, there may be more references
|
|
% on backtracking, so we will need to
|
|
% restore the old value on backtracking
|
|
|
|
% higher-order predicate terms are given the inst
|
|
% `ground(shared, yes(PredInstInfo))'
|
|
% where the PredInstInfo contains the extra modes and the determinism
|
|
% for the predicate. Note that the higher-order predicate term
|
|
% itself must be ground.
|
|
|
|
:- type pred_inst_info
|
|
---> pred_inst_info(
|
|
pred_or_func, % is this a higher-order func
|
|
% mode or a higher-order pred
|
|
% mode?
|
|
list(mode), % the modes of the additional
|
|
% (i.e. not-yet-supplied)
|
|
% arguments of the pred;
|
|
% for a function, this includes
|
|
% the mode of the return value
|
|
% as the last element of the
|
|
% list.
|
|
determinism % the determinism of the
|
|
% predicate or function
|
|
).
|
|
|
|
:- type bound_inst ---> functor(cons_id, list(inst)).
|
|
|
|
:- 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)
|
|
; 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.
|
|
:- 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.
|
|
% "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(sym_name, list(inst_param), mode).
|
|
|
|
:- type (mode) ---> ((inst) -> (inst))
|
|
; user_defined_mode(sym_name, list(inst)).
|
|
|
|
% mode/4 defined above
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how module-system declarations (such as imports
|
|
% and exports) are represented.
|
|
|
|
:- type module_defn ---> module(module_name)
|
|
; interface
|
|
; implementation
|
|
; imported
|
|
% this is used internally by the compiler,
|
|
% to identify declarations which originally
|
|
% came from some other module
|
|
; external(sym_name_specifier)
|
|
; end_module(module_name)
|
|
; export(sym_list)
|
|
; import(sym_list)
|
|
; use(sym_list).
|
|
:- 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 module_specifier == string.
|
|
:- type module_name == string.
|
|
:- type arity == int.
|
|
|
|
%-----------------------------------------------------------------------------%
|