mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
The new --warn-unneeded-initial-statevar option asks the compiler
to warn about code such as
pred_a(!.X, ...) :-
... code that uses !.X, but does not update it ...
In this case, the preferred fix is to just replace all occurrences
of !.X with X.
The new --warn-unneeded-final-statevar option asks the compiler
to warn about code such as
pred_a(!X, ...) :-
... code that maybe uses !.X, but does not update it ...
In this case, the preferred fix also involves replacing all occurrences
of !.X with X, but it also involves either deleting the argument
containing !:X (the best option), or, if there is some reason why
the predicate's signature must stay unchanged, to replace !:X with X as well.
And if the clause body does not actually refer to either !.X or !:X, then
*both* arguments represented by !X should be deleted.
The first option is a style warning; the second option, due to the
signature change it may call for, is a non-style warning.
Both options have a version whose name adds a "-lambda" suffix, and which
does the same warnings for the heads of lambda expressions, not clauses.
Note that several of the modules below, including some that help to implement
the warnings, also contain code changes that result from *acting* on
the new warnings, e.g. by deleting unneeded statevar arguments.
Other, similar changes will also come after this diff is committed.
compiler/options.m:
doc/user_guide.texi:
Document the new options.
compiler/state_var.m:
Gather the information needed to decide what code merits the new warnings.
Do so in three stages:
- when processing the head of a clause or of a lambda expression,
- when processing the body goal of that clause or lambda expression,
- when finishing up the processing of the clause or lambda expression.
Add a predicate to generate the warnings for lambda expressions.
Do not generate the warnings for clauses. This is because whether or not
we want to warn about state vars in some clauses depends on the properties
of *other* clauses of the same predicate, and state_var.m has access
to only one clause at a time. Instead,
- return the info needed by the warning-generating code in pre_typecheck.m
(one of the first passes we execute after adding all clauses
to the HLDS), and
- we export some functionality for use by that code.
Switch to a convention for naming the program variables corresponding
to the middle (non-initial, non-final) versions of state variables
whose output is affected by changes in the code of the clause body goal
only if they involve that specific state variable.
Give some predicates more descriptive names.
compiler/make_hlds.m:
Make state_var.m and its new functionality visible from outside
the make_hlds package.
compiler/add_clause.m:
Record the information gathered by state_var.m in each clause.
compiler/hlds_clauses.m:
Add a slot to each clause for this information.
Give some predicates more descriptive names.
compiler/headvar_names.m:
Use the contents of the new slots to detect whether any clauses
have unused state vars, and if so, return the chosen consensus names
of the head vars to the code of pre_typecheck.m, which uses this info
as part of the implementation of the new warnings.
compiler/pre_typecheck.m:
Implement the new warnings.
compiler/mercury_compile_front_end.m:
Record the warnings that pre_typecheck.m can now return.
compiler/error_spec.m:
compiler/write_error_spec.m:
Add unsigned versions of the format pieces involving ints, for use
by the new code in pre_typecheck.m, and implement them.
compiler/hlds_out_util.m:
compiler/maybe_util.m:
Move two related types from hlds_out_util.m to maybe_util.m,
in order to allow pre_typecheck.m to use one of them.
compiler/hlds_args.m:
Add a new utility function for use by the new code above.
compiler/foreign.m:
Act on the new warnings by deleting the long-unused predicates
being warned about.
compiler/post_typecheck.m:
Speed up this traversal. (I originally thought to implement
the new warnings in this pass.)
compiler/add_foreign_proc.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_type.m:
compiler/build_mode_constraints.m:
compiler/call_gen.m:
compiler/check_typeclass.m:
compiler/clause_to_proc.m:
compiler/code_loc_dep.m:
compiler/delay_info.m:
compiler/delay_partial_inst.m:
compiler/dense_switch.m:
compiler/det_check_goal.m:
compiler/det_infer_goal.m:
compiler/disj_gen.m:
compiler/du_type_layout.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/hlds_pred.m:
compiler/hlds_rtti.m:
compiler/inst_merge.m:
compiler/instance_method_clauses.m:
compiler/intermod.m:
compiler/interval.m:
compiler/ite_gen.m:
compiler/lookup_switch.m:
compiler/make_hlds_passes.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mode_errors.m:
compiler/parse_string_format.m:
compiler/passes_aux.m:
compiler/polymorphism.m:
compiler/polymorphism_info.m:
compiler/polymorphism_type_info.m:
compiler/pragma_c_gen.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/quantification.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_conj.m:
compiler/string_switch.m:
compiler/superhomogeneous.m:
compiler/switch_gen.m:
compiler/tag_switch.m:
compiler/type_constraints.m:
compiler/typecheck.m:
compiler/typecheck_clauses.m:
compiler/typecheck_coerce.m:
compiler/typecheck_error_unify.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_proc.m:
compiler/var_origins.m:
Conform to the changes above, and/or act on the new warnings.
browser/diff.m:
library/bit_buffer.m:
library/getopt.m:
library/getopt_io.m:
library/io.error_util.m:
library/io.file.m:
library/mercury_term_lexer.m:
library/parsing_utils.m:
library/pretty_printer.m:
library/robdd.m:
library/rtti_implementation.m:
library/string.builder.m:
library/string.parse_runtime.m:
mdbcomp/feedback.m:
Act on the new warnings.
tests/hard_coded/sv_nested_closures.m:
Change this test's code to avoid the new warnings, since
(if --halt-at-warn is ever enabled) the warnings would interfere
with its job .
tests/invalid/bug197.err_exp:
tests/invalid/bug487.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid/try_detism.err_exp:
tests/warnings/singleton_test_state_var.err_exp:
Expect variable names for the middle versions of state vars
using the new naming scheme.
623 lines
23 KiB
Mathematica
623 lines
23 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ts=4 sw=4 et ft=mercury
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2014-2015, 2019-2020, 2024-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: parse_string_format.m.
|
|
%
|
|
% This module parses format strings for the compiler; the module
|
|
% library/string.parse_runtime.m does the same job for the runtime system.
|
|
% Any changes here, in the parts of this module below the code of
|
|
% merge_adjacent_const_strs, will probably also require a corresponding
|
|
% change there.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.simplify.parse_string_format.
|
|
:- interface.
|
|
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module char.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module string.
|
|
:- import_module string.parse_util.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% An abtract representation of a polytype, with the actual value
|
|
% to be printed replaced by the variable that will hold that value
|
|
% at runtime.
|
|
:- type abstract_poly_type
|
|
---> apt_f(prog_var, prog_context)
|
|
; apt_i(prog_var, prog_context)
|
|
; apt_i8(prog_var, prog_context)
|
|
; apt_i16(prog_var, prog_context)
|
|
; apt_i32(prog_var, prog_context)
|
|
; apt_i64(prog_var, prog_context)
|
|
; apt_u(prog_var, prog_context)
|
|
; apt_u8(prog_var, prog_context)
|
|
; apt_u16(prog_var, prog_context)
|
|
; apt_u32(prog_var, prog_context)
|
|
; apt_u64(prog_var, prog_context)
|
|
; apt_s(prog_var, prog_context)
|
|
; apt_c(prog_var, prog_context).
|
|
|
|
:- type compiler_format_maybe_width
|
|
---> compiler_no_specified_width
|
|
; compiler_manifest_width(int)
|
|
; compiler_var_width(prog_var).
|
|
|
|
:- type compiler_format_maybe_prec
|
|
---> compiler_no_specified_prec
|
|
; compiler_manifest_prec(int)
|
|
; compiler_var_prec(prog_var).
|
|
|
|
:- type compiler_format_spec
|
|
---> compiler_const_string(
|
|
prog_context,
|
|
string
|
|
)
|
|
; compiler_spec_char(
|
|
prog_context,
|
|
string_format_flags,
|
|
compiler_format_maybe_width,
|
|
prog_var
|
|
)
|
|
; compiler_spec_string(
|
|
prog_context,
|
|
string_format_flags,
|
|
compiler_format_maybe_width,
|
|
compiler_format_maybe_prec,
|
|
prog_var
|
|
)
|
|
; compiler_spec_signed_int(
|
|
prog_context,
|
|
string_format_flags,
|
|
compiler_format_maybe_width,
|
|
compiler_format_maybe_prec,
|
|
int_size,
|
|
prog_var
|
|
)
|
|
; compiler_spec_unsigned_int(
|
|
prog_context,
|
|
string_format_flags,
|
|
compiler_format_maybe_width,
|
|
compiler_format_maybe_prec,
|
|
string_format_int_base,
|
|
int_size,
|
|
prog_var
|
|
)
|
|
; compiler_spec_uint(
|
|
prog_context,
|
|
string_format_flags,
|
|
compiler_format_maybe_width,
|
|
compiler_format_maybe_prec,
|
|
string_format_int_base,
|
|
uint_size,
|
|
prog_var
|
|
)
|
|
; compiler_spec_float(
|
|
prog_context,
|
|
string_format_flags,
|
|
compiler_format_maybe_width,
|
|
compiler_format_maybe_prec,
|
|
string_format_float_kind,
|
|
prog_var
|
|
).
|
|
|
|
:- type int_size
|
|
---> int_size_word
|
|
; int_size_8
|
|
; int_size_16
|
|
; int_size_32
|
|
; int_size_64.
|
|
|
|
:- type uint_size
|
|
---> uint_size_word
|
|
; uint_size_8
|
|
; uint_size_16
|
|
; uint_size_32
|
|
; uint_size_64.
|
|
|
|
% Parse the entire format string. Return either a list of things to be
|
|
% formatted and printed, or a list of error messages.
|
|
%
|
|
:- pred parse_format_string_abstract(list(char)::in,
|
|
list(abstract_poly_type)::in, prog_context::in,
|
|
maybe_errors(list(compiler_format_spec), string_format_error)::out)
|
|
is det.
|
|
|
|
% Optimize the code that we will generate from this call to a format
|
|
% predicate by merging together any adjacent string constant specifiers.
|
|
% When we parse the format string at runtime, we don't do this, since
|
|
% the time the time taken by this merging would almost certainly be greater
|
|
% than the time saved by it, but at compile time, we spread the cost
|
|
% over many executions.
|
|
%
|
|
:- pred merge_adjacent_const_strs(list(compiler_format_spec)::in,
|
|
list(compiler_format_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
parse_format_string_abstract(Chars, PolyTypes, Context, MaybeSpecs) :-
|
|
compiler_parse_format_string(Chars, PolyTypes, Context, 1, Specs, Errors),
|
|
(
|
|
Errors = [HeadError | TailErrors],
|
|
MaybeSpecs = error(HeadError, TailErrors)
|
|
;
|
|
Errors = [],
|
|
MaybeSpecs = ok(Specs)
|
|
).
|
|
|
|
% This predicate parses the entire format string. When it encounters
|
|
% something that looks like a conversion specification (i.e. it starts
|
|
% with a '%' character), but which cannot be parsed as one, it records
|
|
% an error message, and keeps going.
|
|
%
|
|
% Note that making this predicate use an accumulator for the lists
|
|
% of specs and errors seen so far would yield cleaner code,
|
|
% but would probably be slower since our caller would have to unreverse
|
|
% the list of specs we return.
|
|
%
|
|
% The lack of tail recursion here should not be a problem, since no
|
|
% format string will be long enough to make us consume too much stack.
|
|
%
|
|
:- pred compiler_parse_format_string(list(char)::in,
|
|
list(abstract_poly_type)::in, prog_context::in, int::in,
|
|
list(compiler_format_spec)::out, list(string_format_error)::out) is det.
|
|
|
|
compiler_parse_format_string(!.Chars, !.PolyTypes, Context, SpecNum,
|
|
Specs, Errors) :-
|
|
gather_non_percent_chars(!.Chars, NonConversionSpecChars, GatherEndedBy),
|
|
(
|
|
GatherEndedBy = found_end_of_string,
|
|
Specs0 = [],
|
|
(
|
|
!.PolyTypes = [],
|
|
Errors = []
|
|
;
|
|
!.PolyTypes = [_ | _],
|
|
Error = error_extra_polytypes(SpecNum, list.length(!.PolyTypes)),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
GatherEndedBy = found_percent(!:Chars),
|
|
parse_conversion_specification(!Chars, !PolyTypes, Context,
|
|
SpecNum, HeadSpec, HeadErrors),
|
|
compiler_parse_format_string(!.Chars, !.PolyTypes, Context,
|
|
SpecNum + 1, TailSpecs, TailErrors),
|
|
(
|
|
HeadErrors = [],
|
|
Specs0 = [HeadSpec | TailSpecs],
|
|
Errors = TailErrors
|
|
;
|
|
HeadErrors = [_ | _],
|
|
Specs0 = TailSpecs,
|
|
Errors = HeadErrors ++ TailErrors
|
|
)
|
|
),
|
|
(
|
|
NonConversionSpecChars = [],
|
|
Specs = Specs0
|
|
;
|
|
NonConversionSpecChars = [_ | _],
|
|
NonConversionSpecString =
|
|
string.from_char_list(NonConversionSpecChars),
|
|
StringConst = compiler_const_string(Context, NonConversionSpecString),
|
|
Specs = [StringConst | Specs0]
|
|
).
|
|
|
|
% Each conversion specification starts with the character '%' (which
|
|
% our caller has already read) and ends with a conversion specifier.
|
|
% In between there may be (in this order) zero or more flags, an optional
|
|
% minimum field width, and an optional precision.
|
|
%
|
|
:- pred parse_conversion_specification(list(char)::in, list(char)::out,
|
|
list(abstract_poly_type)::in, list(abstract_poly_type)::out,
|
|
prog_context::in, int::in,
|
|
compiler_format_spec::out, list(string_format_error)::out) is det.
|
|
|
|
parse_conversion_specification(!Chars, !PolyTypes, Context, SpecNum,
|
|
Spec, Errors) :-
|
|
Flags0 = string_format_flags(flag_hash_clear, flag_space_clear,
|
|
flag_zero_clear, flag_minus_clear, flag_plus_clear),
|
|
gather_flag_chars(!Chars, Flags0, Flags),
|
|
get_optional_width(!Chars, !PolyTypes, SpecNum, MaybeWidth, WidthErrors),
|
|
get_optional_prec(!Chars, !PolyTypes, SpecNum, MaybePrec, PrecErrors),
|
|
get_first_spec(!Chars, !PolyTypes, Context, Flags,
|
|
MaybeWidth, MaybePrec, SpecNum, Spec, SpecErrors),
|
|
Errors = WidthErrors ++ PrecErrors ++ SpecErrors.
|
|
|
|
% Do we have a minimum field width? If yes, get it.
|
|
%
|
|
:- pred get_optional_width(list(char)::in, list(char)::out,
|
|
list(abstract_poly_type)::in, list(abstract_poly_type)::out, int::in,
|
|
compiler_format_maybe_width::out, list(string_format_error)::out) is det.
|
|
|
|
get_optional_width(!Chars, !PolyTypes, SpecNum, MaybeWidth, Errors) :-
|
|
( if !.Chars = ['*' | !:Chars] then
|
|
(
|
|
!.PolyTypes = [PolyType | !:PolyTypes],
|
|
( if PolyType = apt_i(PolyWidthVar, _Context) then
|
|
MaybeWidth = compiler_var_width(PolyWidthVar),
|
|
Errors = []
|
|
else
|
|
MaybeWidth = compiler_no_specified_width,
|
|
Errors = [error_nonint_star_width(SpecNum,
|
|
abstract_poly_type_to_kind(PolyType))]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
MaybeWidth = compiler_no_specified_width,
|
|
Errors = [error_missing_star_width(SpecNum)]
|
|
)
|
|
else if get_nonzero_number_prefix(!Chars, Width) then
|
|
MaybeWidth = compiler_manifest_width(Width),
|
|
Errors = []
|
|
else
|
|
MaybeWidth = compiler_no_specified_width,
|
|
Errors = []
|
|
).
|
|
|
|
% Do we have a precision? If yes, get it.
|
|
%
|
|
:- pred get_optional_prec(list(char)::in, list(char)::out,
|
|
list(abstract_poly_type)::in, list(abstract_poly_type)::out, int::in,
|
|
compiler_format_maybe_prec::out, list(string_format_error)::out) is det.
|
|
|
|
get_optional_prec(!Chars, !PolyTypes, SpecNum, MaybePrec, Errors) :-
|
|
( if !.Chars = ['.' | !:Chars] then
|
|
( if !.Chars = ['*' | !:Chars] then
|
|
(
|
|
!.PolyTypes = [PolyType | !:PolyTypes],
|
|
( if PolyType = apt_i(PolyPrecVar, _Context) then
|
|
MaybePrec = compiler_var_prec(PolyPrecVar),
|
|
Errors = []
|
|
else
|
|
MaybePrec = compiler_no_specified_prec,
|
|
Errors = [error_nonint_star_prec(SpecNum,
|
|
abstract_poly_type_to_kind(PolyType))]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
MaybePrec = compiler_no_specified_prec,
|
|
Errors = [error_missing_star_prec(SpecNum)]
|
|
)
|
|
else
|
|
% This treats an empty string as an EXPLICIT zero.
|
|
get_number_prefix(!Chars, Prec),
|
|
MaybePrec = compiler_manifest_prec(Prec),
|
|
Errors = []
|
|
)
|
|
else
|
|
MaybePrec = compiler_no_specified_prec,
|
|
Errors = []
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% get_first_spec(!Chars, !PolyTypes, Flags, MaybeWidth, MaybePrec,
|
|
% SpecNum, Spec, Errors):
|
|
%
|
|
% Try to read one conversion specifier, whose percent sign, flags,
|
|
% width and precision have already been read, from !Chars.
|
|
%
|
|
% If successful, consume the corresponding abstract_poly_type
|
|
% from !PolyTypes, we return the specifier as Spec and return
|
|
% an empty error list.
|
|
%
|
|
% If there is a problem, we return a garbage Spec and a nonempty
|
|
% errors list. We also consume the abstract_poly_type that corresponds
|
|
% (or at least, looks like it corresponds) to the specifier,
|
|
% if there is one.
|
|
%
|
|
:- pred get_first_spec(list(char)::in, list(char)::out,
|
|
list(abstract_poly_type)::in, list(abstract_poly_type)::out,
|
|
prog_context::in, string_format_flags::in,
|
|
compiler_format_maybe_width::in, compiler_format_maybe_prec::in, int::in,
|
|
compiler_format_spec::out, list(string_format_error)::out) is det.
|
|
|
|
get_first_spec(!Chars, !PolyTypes, OverallContext, _Flags,
|
|
_MaybeWidth, _MaybePrec, SpecNum, Spec, Errors) :-
|
|
!.Chars = [],
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [error_no_specifier(SpecNum, list.length(!.PolyTypes))].
|
|
get_first_spec(!Chars, !PolyTypes, OverallContext, Flags,
|
|
MaybeWidth, MaybePrec, SpecNum, Spec, Errors) :-
|
|
!.Chars = [SpecChar | !:Chars],
|
|
( if
|
|
parse_spec(SpecChar, !PolyTypes, OverallContext, Flags,
|
|
MaybeWidth, MaybePrec, SpecNum, SpecPrime, ErrorsPrime)
|
|
then
|
|
Spec = SpecPrime,
|
|
Errors = ErrorsPrime
|
|
else
|
|
Error = error_unknown_specifier(SpecNum, SpecChar),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
).
|
|
|
|
:- pred parse_spec(char::in,
|
|
list(abstract_poly_type)::in, list(abstract_poly_type)::out,
|
|
prog_context::in, string_format_flags::in,
|
|
compiler_format_maybe_width::in, compiler_format_maybe_prec::in, int::in,
|
|
compiler_format_spec::out, list(string_format_error)::out) is semidet.
|
|
|
|
parse_spec(SpecChar, !PolyTypes, OverallContext, !.Flags,
|
|
MaybeWidth, MaybePrec, SpecNum, Spec, Errors) :-
|
|
require_switch_arms_det [SpecChar]
|
|
(
|
|
SpecChar = '%',
|
|
Spec = compiler_const_string(OverallContext, "%"),
|
|
Errors = []
|
|
;
|
|
( SpecChar = 'd'
|
|
; SpecChar = 'i'
|
|
),
|
|
(
|
|
!.PolyTypes = [SpecPolyType | !:PolyTypes],
|
|
(
|
|
(
|
|
SpecPolyType = apt_i(IntVar, PolyContext),
|
|
IntSize = int_size_word
|
|
;
|
|
SpecPolyType = apt_i8(IntVar, PolyContext),
|
|
IntSize = int_size_8
|
|
;
|
|
SpecPolyType = apt_i16(IntVar, PolyContext),
|
|
IntSize = int_size_16
|
|
;
|
|
SpecPolyType = apt_i32(IntVar, PolyContext),
|
|
IntSize = int_size_32
|
|
;
|
|
SpecPolyType = apt_i64(IntVar, PolyContext),
|
|
IntSize = int_size_64
|
|
),
|
|
% Base is always decimal
|
|
Spec = compiler_spec_signed_int(PolyContext, !.Flags,
|
|
MaybeWidth, MaybePrec, IntSize, IntVar),
|
|
Errors = []
|
|
;
|
|
( SpecPolyType = apt_f(_, _)
|
|
; SpecPolyType = apt_u(_, _)
|
|
; SpecPolyType = apt_u8(_, _)
|
|
; SpecPolyType = apt_u16(_, _)
|
|
; SpecPolyType = apt_u32(_, _)
|
|
; SpecPolyType = apt_u64(_, _)
|
|
; SpecPolyType = apt_c(_, _)
|
|
; SpecPolyType = apt_s(_, _)
|
|
),
|
|
Error = error_wrong_polytype(SpecNum, SpecChar,
|
|
abstract_poly_type_to_kind(SpecPolyType)),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
Error = error_no_polytype(SpecNum, SpecChar),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
(
|
|
SpecChar = 'o',
|
|
Base = base_octal
|
|
;
|
|
SpecChar = 'u',
|
|
Base = base_decimal
|
|
;
|
|
SpecChar = 'x',
|
|
Base = base_hex_lc
|
|
;
|
|
SpecChar = 'X',
|
|
Base = base_hex_uc
|
|
;
|
|
SpecChar = 'p',
|
|
Base = base_hex_p,
|
|
% XXX This should not be necessary.
|
|
!Flags ^ flag_hash := flag_hash_set
|
|
),
|
|
(
|
|
!.PolyTypes = [SpecPolyType | !:PolyTypes],
|
|
(
|
|
(
|
|
SpecPolyType = apt_i(IntVar, PolyContext),
|
|
IntSize = int_size_word
|
|
;
|
|
SpecPolyType = apt_i8(IntVar, PolyContext),
|
|
IntSize = int_size_8
|
|
;
|
|
SpecPolyType = apt_i16(IntVar, PolyContext),
|
|
IntSize = int_size_16
|
|
;
|
|
SpecPolyType = apt_i32(IntVar, PolyContext),
|
|
IntSize = int_size_32
|
|
;
|
|
SpecPolyType = apt_i64(IntVar, PolyContext),
|
|
IntSize = int_size_64
|
|
),
|
|
Spec = compiler_spec_unsigned_int(PolyContext, !.Flags,
|
|
MaybeWidth, MaybePrec, Base, IntSize, IntVar),
|
|
Errors = []
|
|
;
|
|
(
|
|
SpecPolyType = apt_u(UIntVar, PolyContext),
|
|
UIntSize = uint_size_word
|
|
;
|
|
SpecPolyType = apt_u8(UIntVar, PolyContext),
|
|
UIntSize = uint_size_8
|
|
;
|
|
SpecPolyType = apt_u16(UIntVar, PolyContext),
|
|
UIntSize = uint_size_16
|
|
;
|
|
SpecPolyType = apt_u32(UIntVar, PolyContext),
|
|
UIntSize = uint_size_32
|
|
;
|
|
SpecPolyType = apt_u64(UIntVar, PolyContext),
|
|
UIntSize = uint_size_64
|
|
),
|
|
Spec = compiler_spec_uint(PolyContext, !.Flags,
|
|
MaybeWidth, MaybePrec, Base, UIntSize, UIntVar),
|
|
Errors = []
|
|
;
|
|
( SpecPolyType = apt_f(_, _)
|
|
; SpecPolyType = apt_c(_, _)
|
|
; SpecPolyType = apt_s(_, _)
|
|
),
|
|
Error = error_wrong_polytype(SpecNum, SpecChar,
|
|
abstract_poly_type_to_kind(SpecPolyType)),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
Error = error_no_polytype(SpecNum, SpecChar),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
(
|
|
SpecChar = 'e',
|
|
FloatKind = kind_e_scientific_lc
|
|
;
|
|
SpecChar = 'E',
|
|
FloatKind = kind_e_scientific_uc
|
|
;
|
|
SpecChar = 'f',
|
|
FloatKind = kind_f_plain_lc
|
|
;
|
|
SpecChar = 'F',
|
|
FloatKind = kind_f_plain_uc
|
|
;
|
|
SpecChar = 'g',
|
|
FloatKind = kind_g_flexible_lc
|
|
;
|
|
SpecChar = 'G',
|
|
FloatKind = kind_g_flexible_uc
|
|
),
|
|
(
|
|
!.PolyTypes = [SpecPolyType | !:PolyTypes],
|
|
( if SpecPolyType = apt_f(FloatVar, PolyContext) then
|
|
Spec = compiler_spec_float(PolyContext,
|
|
!.Flags, MaybeWidth, MaybePrec, FloatKind, FloatVar),
|
|
Errors = []
|
|
else
|
|
Error = error_wrong_polytype(SpecNum, SpecChar,
|
|
abstract_poly_type_to_kind(SpecPolyType)),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
Error = error_no_polytype(SpecNum, SpecChar),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
SpecChar = 'c',
|
|
(
|
|
!.PolyTypes = [SpecPolyType | !:PolyTypes],
|
|
( if SpecPolyType = apt_c(CharVar, PolyContext) then
|
|
% XXX Should we generate an error if MaybePrec = yes(...)?
|
|
Spec = compiler_spec_char(PolyContext,
|
|
!.Flags, MaybeWidth, CharVar),
|
|
Errors = []
|
|
else
|
|
Error = error_wrong_polytype(SpecNum, SpecChar,
|
|
abstract_poly_type_to_kind(SpecPolyType)),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
Error = error_no_polytype(SpecNum, SpecChar),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
SpecChar = 's',
|
|
(
|
|
!.PolyTypes = [SpecPolyType | !:PolyTypes],
|
|
( if SpecPolyType = apt_s(StrVar, PolyContext) then
|
|
Spec = compiler_spec_string(PolyContext,
|
|
!.Flags, MaybeWidth, MaybePrec, StrVar),
|
|
Errors = []
|
|
else
|
|
Error = error_wrong_polytype(SpecNum, SpecChar,
|
|
abstract_poly_type_to_kind(SpecPolyType)),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
;
|
|
!.PolyTypes = [],
|
|
Error = error_no_polytype(SpecNum, SpecChar),
|
|
Spec = compiler_const_string(OverallContext, ""),
|
|
Errors = [Error]
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func abstract_poly_type_to_kind(abstract_poly_type) = poly_kind.
|
|
|
|
abstract_poly_type_to_kind(apt_c(_, _)) = poly_kind_char.
|
|
abstract_poly_type_to_kind(apt_s(_, _)) = poly_kind_str.
|
|
abstract_poly_type_to_kind(apt_i(_, _)) = poly_kind_int.
|
|
abstract_poly_type_to_kind(apt_i8(_, _)) = poly_kind_int8.
|
|
abstract_poly_type_to_kind(apt_i16(_, _)) = poly_kind_int16.
|
|
abstract_poly_type_to_kind(apt_i32(_, _)) = poly_kind_int32.
|
|
abstract_poly_type_to_kind(apt_i64(_, _)) = poly_kind_int64.
|
|
abstract_poly_type_to_kind(apt_u(_, _)) = poly_kind_uint.
|
|
abstract_poly_type_to_kind(apt_u8(_, _)) = poly_kind_uint8.
|
|
abstract_poly_type_to_kind(apt_u16(_, _)) = poly_kind_uint16.
|
|
abstract_poly_type_to_kind(apt_u32(_, _)) = poly_kind_uint32.
|
|
abstract_poly_type_to_kind(apt_u64(_, _)) = poly_kind_uint64.
|
|
abstract_poly_type_to_kind(apt_f(_, _)) = poly_kind_float.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
merge_adjacent_const_strs([], []).
|
|
merge_adjacent_const_strs([HeadSpec | TailSpecs], MergedSpecs) :-
|
|
merge_adjacent_const_strs(TailSpecs, TailMergedSpecs),
|
|
(
|
|
HeadSpec = compiler_const_string(HeadContext, HeadConstString),
|
|
( if
|
|
TailMergedSpecs = [FirstTailMergedSpec | LaterTailMergedSpecs],
|
|
FirstTailMergedSpec =
|
|
compiler_const_string(_TailContext, TailConstString)
|
|
then
|
|
HeadMergedSpec = compiler_const_string(HeadContext,
|
|
HeadConstString ++ TailConstString),
|
|
MergedSpecs = [HeadMergedSpec | LaterTailMergedSpecs]
|
|
else
|
|
MergedSpecs = [HeadSpec | TailMergedSpecs]
|
|
)
|
|
;
|
|
( HeadSpec = compiler_spec_char(_, _, _, _)
|
|
; HeadSpec = compiler_spec_string(_, _, _, _, _)
|
|
; HeadSpec = compiler_spec_signed_int(_, _, _, _, _, _)
|
|
; HeadSpec = compiler_spec_unsigned_int(_, _, _, _, _, _, _)
|
|
; HeadSpec = compiler_spec_uint(_, _, _, _, _, _, _)
|
|
; HeadSpec = compiler_spec_float(_, _, _, _, _, _)
|
|
),
|
|
MergedSpecs = [HeadSpec | TailMergedSpecs]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module check_hlds.simplify.parse_string_format.
|
|
%---------------------------------------------------------------------------%
|