mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
compiler/parse_vars.m:
Move parse_and_check_quant_vars here from parse_item.m, since
parse_type_defn.m can also use it (after a slight generalization).
Change its argument order to put related arguments next to each other.
Replace the "existentially quantified/universally quantified" wording
with just "quantified", since the prohibition on repeated variables
exists regardless of the existential/universal distinction. The context
will still say whether the error is inside a "some" scope or
an "all" scope.
Include a final period in a color region, as we do in other diagnostics.
compiler/parse_item.m:
Delete the moved code.
compiler/parse_type_defn.m:
Call parse_and_check_quant_vars instead of reimplementing it.
tests/invalid_nodepend/exist_cons_repeated_tvar.err_exp:
tests/invalid_nodepend/quant_pred_repeated_tvar.err_exp:
Update the expected diagnostics.
391 lines
15 KiB
Mathematica
391 lines
15 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2016, 2019, 2022, 2024 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This module defines predicates that parse lists of variables.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.parse_vars.
|
|
:- interface.
|
|
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.maybe_error.
|
|
|
|
:- import_module cord.
|
|
:- import_module list.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type quantifier_type
|
|
---> quant_type_exist
|
|
; quant_type_univ.
|
|
|
|
:- type var_or_type_var
|
|
---> ordinary_var
|
|
; type_var.
|
|
|
|
:- pred parse_and_check_quant_vars(quantifier_type::in, var_or_type_var::in,
|
|
cord(format_piece)::in, varset::in, term::in, maybe1(list(var))::out)
|
|
is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% parse_possibly_repeated_vars(Term, VarSet, ContextPieces, MaybeVars):
|
|
%
|
|
% Parse Term as a list of quantified variables Vars. If successful,
|
|
% return ok1(Vars). If not, return an error message that has
|
|
% ContextPieces as a prefix.
|
|
%
|
|
:- pred parse_possibly_repeated_vars(term(T)::in, varset(T)::in,
|
|
cord(format_piece)::in, maybe1(list(var(T)))::out) is det.
|
|
|
|
:- type plain_state_vars(T)
|
|
---> plain_state_vars(
|
|
list(var(T)), % plain variables
|
|
list(var(T)) % !V state variables
|
|
).
|
|
|
|
% parse_vars_state_vars(Term, VarSet, ContextPieces, MaybeVars):
|
|
%
|
|
% The same as parse_vars, but parse not just ordinary variables V,
|
|
% but also state variables !SV.
|
|
%
|
|
:- pred parse_vars_state_vars(term(T)::in, varset(T)::in,
|
|
cord(format_piece)::in, maybe1(plain_state_vars(T))::out) is det.
|
|
|
|
:- type plain_state_dot_colon_vars(T)
|
|
---> plain_state_dot_colon_vars(
|
|
list(var(T)), % plain variables
|
|
list(var(T)), % !V state variables
|
|
list(var(T)), % !.V state variables
|
|
list(var(T)) % !:V state variables
|
|
).
|
|
|
|
% parse_vars_state_dot_colon_vars(Term, VarSet, ContextPieces, MaybeVars):
|
|
%
|
|
% The same as parse_vars, but parse not just ordinary variables V,
|
|
% but also state variables !SV, !.SV and !:SV.
|
|
%
|
|
:- pred parse_vars_state_dot_colon_vars(term(T)::in, varset(T)::in,
|
|
cord(format_piece)::in, maybe1(plain_state_dot_colon_vars(T))::out)
|
|
is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module parse_tree.parse_tree_out_term.
|
|
|
|
:- import_module bag.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
parse_and_check_quant_vars(QuantType, VarOrTypeVar, InitContextPieces,
|
|
VarSet, VarsTerm, MaybeVars) :-
|
|
% Both versions of VarContextPieces should be statically allocated terms.
|
|
(
|
|
QuantType = quant_type_exist,
|
|
VarsContextPieces = [lower_case_next_if_not_first,
|
|
words("In first argument of"), quote("some"), suffix(":"), nl]
|
|
;
|
|
QuantType = quant_type_univ,
|
|
VarsContextPieces = [lower_case_next_if_not_first,
|
|
words("In first argument of"), quote("all"), suffix(":"), nl]
|
|
),
|
|
ContextPieces = InitContextPieces ++ cord.from_list(VarsContextPieces),
|
|
parse_possibly_repeated_vars(VarsTerm, VarSet, ContextPieces, MaybeVars0),
|
|
(
|
|
MaybeVars0 = ok1(QuantVars),
|
|
QuantVarsBag = bag.from_list(QuantVars),
|
|
DuplicateQuantVars = bag.to_list_only_duplicates(QuantVarsBag),
|
|
(
|
|
DuplicateQuantVars = [],
|
|
MaybeVars = MaybeVars0
|
|
;
|
|
DuplicateQuantVars = [_ | _],
|
|
list.map(varset.lookup_name(VarSet), DuplicateQuantVars,
|
|
DuplicateQuantVarNames),
|
|
(
|
|
VarOrTypeVar = ordinary_var,
|
|
Vars = "variables"
|
|
;
|
|
VarOrTypeVar = type_var,
|
|
Vars = "type variables"
|
|
),
|
|
Pieces = VarsContextPieces ++ [lower_case_next_if_not_first,
|
|
words("Error: a list of"), words(Vars),
|
|
words("being quantified may include each variable just once,"),
|
|
words("but here,")] ++
|
|
fixed_list_to_color_pieces(color_subject, "and", [],
|
|
DuplicateQuantVarNames) ++
|
|
[words(choose_number(DuplicateQuantVarNames, "is", "are"))] ++
|
|
color_as_incorrect([words("repeated.")]) ++ [nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt,
|
|
get_term_context(VarsTerm), Pieces),
|
|
MaybeVars = error1([Spec])
|
|
)
|
|
;
|
|
MaybeVars0 = error1(_),
|
|
MaybeVars = MaybeVars0
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
parse_possibly_repeated_vars(Term, VarSet, ContextPieces, MaybeVars) :-
|
|
( if Term = term.functor(term.atom("[]"), [], _) then
|
|
MaybeVars = ok1([])
|
|
else if Term = term.functor(term.atom("[|]"), [HeadTerm, TailTerm], _) then
|
|
(
|
|
HeadTerm = term.variable(HeadVar0, _),
|
|
MaybeHeadVar = ok1(HeadVar0)
|
|
;
|
|
HeadTerm = term.functor(_, _, _),
|
|
generate_unexpected_term_message(ContextPieces, VarSet,
|
|
"variable", HeadTerm, Spec),
|
|
MaybeHeadVar = error1([Spec])
|
|
),
|
|
parse_possibly_repeated_vars(TailTerm, VarSet, ContextPieces,
|
|
MaybeTailVars),
|
|
( if
|
|
MaybeHeadVar = ok1(HeadVar),
|
|
MaybeTailVars = ok1(TailVars)
|
|
then
|
|
MaybeVars = ok1([HeadVar | TailVars])
|
|
else
|
|
Specs = get_any_errors1(MaybeHeadVar) ++
|
|
get_any_errors1(MaybeTailVars),
|
|
MaybeVars = error1(Specs)
|
|
)
|
|
else
|
|
generate_unexpected_term_message(ContextPieces, VarSet,
|
|
"list of variables", Term, Spec),
|
|
MaybeVars = error1([Spec])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type ordinary_state_var(T)
|
|
---> os_ordinary_var(var(T))
|
|
; os_state_var(var(T)).
|
|
|
|
parse_vars_state_vars(Term, VarSet, ContextPieces, MaybeVars) :-
|
|
( if Term = functor(atom("[]"), [], _) then
|
|
MaybeVars = ok1(plain_state_vars([], []))
|
|
else if Term = functor(atom("[|]"), [HeadTerm, TailTerm], _) then
|
|
( if
|
|
(
|
|
HeadTerm = variable(V0, _),
|
|
VarKind0 = os_ordinary_var(V0)
|
|
;
|
|
HeadTerm = functor(atom("!"), [variable(SV0, _)], _),
|
|
VarKind0 = os_state_var(SV0)
|
|
)
|
|
then
|
|
MaybeHeadVar = ok1(VarKind0)
|
|
else
|
|
generate_unexpected_term_message(ContextPieces, VarSet,
|
|
"variable or state variable", HeadTerm, HeadSpec),
|
|
MaybeHeadVar = error1([HeadSpec])
|
|
),
|
|
parse_vars_state_vars(TailTerm, VarSet, ContextPieces, MaybeTailVars),
|
|
( if
|
|
MaybeHeadVar = ok1(VarKind),
|
|
MaybeTailVars = ok1(plain_state_vars(TailVars, TailStateVars))
|
|
then
|
|
(
|
|
VarKind = os_ordinary_var(V),
|
|
( if list.member(V, TailVars) then
|
|
generate_repeated_var_msg(ContextPieces, VarSet,
|
|
HeadTerm, Spec),
|
|
MaybeVars = error1([Spec])
|
|
else
|
|
Vars = [V | TailVars],
|
|
MaybeVars = ok1(plain_state_vars(Vars, TailStateVars))
|
|
)
|
|
;
|
|
VarKind = os_state_var(SV),
|
|
( if list.member(SV, TailStateVars) then
|
|
generate_repeated_state_var_msg(ContextPieces, VarSet,
|
|
HeadTerm, Spec),
|
|
MaybeVars = error1([Spec])
|
|
else
|
|
StateVars = [SV | TailStateVars],
|
|
MaybeVars = ok1(plain_state_vars(TailVars, StateVars))
|
|
)
|
|
)
|
|
else
|
|
Specs = get_any_errors1(MaybeHeadVar) ++
|
|
get_any_errors1(MaybeTailVars),
|
|
MaybeVars = error1(Specs)
|
|
)
|
|
else
|
|
generate_unexpected_term_message(ContextPieces, VarSet,
|
|
"list of variables and/or state variables", Term, Spec),
|
|
MaybeVars = error1([Spec])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type ordinary_state_dot_colon_var(T)
|
|
---> osdc_ordinary_var(var(T))
|
|
; osdc_state_var(var(T))
|
|
; osdc_dot_var(var(T))
|
|
; osdc_colon_var(var(T)).
|
|
|
|
parse_vars_state_dot_colon_vars(Term, VarSet, ContextPieces, MaybeVars) :-
|
|
( if Term = functor(atom("[]"), [], _) then
|
|
MaybeVars = ok1(plain_state_dot_colon_vars([], [], [], []))
|
|
else if Term = functor(atom("[|]"), [HeadTerm, Tail], _) then
|
|
( if
|
|
(
|
|
HeadTerm = variable(V0, _),
|
|
VarKind0 = osdc_ordinary_var(V0)
|
|
;
|
|
HeadTerm = functor(atom("!"), [variable(SV0, _)], _),
|
|
VarKind0 = osdc_state_var(SV0)
|
|
;
|
|
HeadTerm = functor(atom("!."), [variable(SV0, _)], _),
|
|
VarKind0 = osdc_dot_var(SV0)
|
|
;
|
|
HeadTerm = functor(atom("!:"), [variable(SV0, _)], _),
|
|
VarKind0 = osdc_colon_var(SV0)
|
|
)
|
|
then
|
|
MaybeHeadVar = ok1(VarKind0)
|
|
else
|
|
generate_unexpected_term_message(ContextPieces, VarSet,
|
|
"variable or state variable", HeadTerm, HeadSpec),
|
|
MaybeHeadVar = error1([HeadSpec])
|
|
),
|
|
parse_vars_state_dot_colon_vars(Tail, VarSet, ContextPieces,
|
|
MaybeTailVars),
|
|
( if
|
|
MaybeHeadVar = ok1(VarKind),
|
|
MaybeTailVars = ok1(plain_state_dot_colon_vars(TailVars,
|
|
TailStateVars, TailDotVars, TailColonVars))
|
|
then
|
|
(
|
|
VarKind = osdc_ordinary_var(V),
|
|
( if list.member(V, TailVars) then
|
|
generate_repeated_var_msg(ContextPieces, VarSet,
|
|
HeadTerm, Spec),
|
|
MaybeVars = error1([Spec])
|
|
else
|
|
Vars = [V | TailVars],
|
|
MaybeVars = ok1(plain_state_dot_colon_vars(Vars,
|
|
TailStateVars, TailDotVars, TailColonVars))
|
|
)
|
|
;
|
|
VarKind = osdc_state_var(SV),
|
|
( if
|
|
( list.member(SV, TailStateVars )
|
|
; list.member(SV, TailDotVars )
|
|
; list.member(SV, TailColonVars )
|
|
)
|
|
then
|
|
generate_repeated_var_msg(ContextPieces, VarSet,
|
|
HeadTerm, Spec),
|
|
MaybeVars = error1([Spec])
|
|
else
|
|
StateVars = [SV | TailStateVars],
|
|
MaybeVars = ok1(plain_state_dot_colon_vars(TailVars,
|
|
StateVars, TailDotVars, TailColonVars))
|
|
)
|
|
;
|
|
VarKind = osdc_dot_var(SV),
|
|
( if
|
|
( list.member(SV, TailStateVars )
|
|
; list.member(SV, TailDotVars )
|
|
; list.member(SV, TailColonVars )
|
|
)
|
|
then
|
|
generate_repeated_var_msg(ContextPieces, VarSet,
|
|
HeadTerm, Spec),
|
|
MaybeVars = error1([Spec])
|
|
else
|
|
DotVars = [SV | TailDotVars],
|
|
MaybeVars = ok1(plain_state_dot_colon_vars(TailVars,
|
|
TailStateVars, DotVars, TailColonVars))
|
|
)
|
|
;
|
|
VarKind = osdc_colon_var(SV),
|
|
( if
|
|
( list.member(SV, TailStateVars )
|
|
; list.member(SV, TailDotVars )
|
|
; list.member(SV, TailColonVars )
|
|
)
|
|
then
|
|
generate_repeated_var_msg(ContextPieces, VarSet,
|
|
HeadTerm, Spec),
|
|
MaybeVars = error1([Spec])
|
|
else
|
|
ColonVars = [SV | TailColonVars],
|
|
MaybeVars = ok1(plain_state_dot_colon_vars(TailVars,
|
|
TailStateVars, TailDotVars, ColonVars))
|
|
)
|
|
)
|
|
else
|
|
HeadSpecs = get_any_errors1(MaybeHeadVar),
|
|
TailSpecs = get_any_errors1(MaybeTailVars),
|
|
MaybeVars = error1(HeadSpecs ++ TailSpecs)
|
|
)
|
|
else
|
|
generate_unexpected_term_message(ContextPieces, VarSet,
|
|
"list of variables and/or state variables", Term, Spec),
|
|
MaybeVars = error1([Spec])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred generate_repeated_var_msg(cord(format_piece)::in,
|
|
varset(T)::in, term(T)::in, error_spec::out) is det.
|
|
|
|
generate_repeated_var_msg(ContextPieces, VarSet, Term, Spec) :-
|
|
TermStr = describe_error_term(VarSet, Term),
|
|
Pieces = cord.list(ContextPieces) ++ [lower_case_next_if_not_first] ++
|
|
color_as_incorrect([words("Repeated variable")]) ++
|
|
color_as_subject([words(TermStr), suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt,
|
|
get_term_context(Term), Pieces).
|
|
|
|
:- pred generate_repeated_state_var_msg(cord(format_piece)::in,
|
|
varset(T)::in, term(T)::in, error_spec::out) is det.
|
|
|
|
generate_repeated_state_var_msg(ContextPieces, VarSet, Term, Spec) :-
|
|
TermStr = describe_error_term(VarSet, Term),
|
|
Pieces = cord.list(ContextPieces) ++ [lower_case_next_if_not_first] ++
|
|
color_as_incorrect([words("Repeated state variable")]) ++
|
|
color_as_subject([words(TermStr), suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt,
|
|
get_term_context(Term), Pieces).
|
|
|
|
:- pred generate_unexpected_term_message(cord(format_piece)::in,
|
|
varset(T)::in, string::in, term(T)::in, error_spec::out) is det.
|
|
|
|
generate_unexpected_term_message(ContextPieces, VarSet, Expected, Term,
|
|
Spec) :-
|
|
TermStr = describe_error_term(VarSet, Term),
|
|
Pieces = cord.list(ContextPieces) ++ [lower_case_next_if_not_first,
|
|
words("Expected a")] ++
|
|
color_as_correct([words(Expected), suffix(",")]) ++
|
|
[words("got")] ++
|
|
color_as_incorrect([quote(TermStr), suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_t2pt,
|
|
get_term_context(Term), Pieces).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.parse_vars.
|
|
%---------------------------------------------------------------------------%
|