Files
mercury/compiler/parse_vars.m
2019-10-15 21:48:09 +11:00

362 lines
14 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2016 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_util.
:- import_module parse_tree.maybe_error.
:- import_module cord.
:- import_module list.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
% 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_component)::in, maybe1(list(var(T)))::out) is det.
% parse_vars(Term, VarSet, ContextPieces, MaybeVars):
%
% The same as parse_possibly_repeated_vars, but generate an error
% if a variable is in the list more than once.
%
:- pred parse_vars(term(T)::in, varset(T)::in,
cord(format_component)::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_component)::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_component)::in, maybe1(plain_state_dot_colon_vars(T))::out)
is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module parse_tree.parse_tree_out_term.
%---------------------------------------------------------------------------%
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,
"a 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,
"a list of variables", Term, Spec),
MaybeVars = error1([Spec])
).
parse_vars(Term, VarSet, ContextPieces, MaybeVars) :-
( if Term = functor(atom("[]"), [], _) then
MaybeVars = ok1([])
else if Term = functor(atom("[|]"), [HeadTerm, TailTerm], _) then
(
HeadTerm = variable(HeadVar0, _),
MaybeHeadVar = ok1(HeadVar0)
;
HeadTerm = functor(_, _, _),
generate_unexpected_term_message(ContextPieces, VarSet,
"a variable", HeadTerm, HeadSpec),
MaybeHeadVar = error1([HeadSpec])
),
parse_vars(TailTerm, VarSet, ContextPieces, MaybeTailVars),
( if
MaybeHeadVar = ok1(HeadVar),
MaybeTailVars = ok1(TailVars)
then
( if list.member(HeadVar, TailVars) then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
Vars = [HeadVar | TailVars],
MaybeVars = ok1(Vars)
)
else
Specs = get_any_errors1(MaybeHeadVar) ++
get_any_errors1(MaybeTailVars),
MaybeVars = error1(Specs)
)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a 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,
"a 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,
"a 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,
"a 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,
"a list of variables and/or state variables", Term, Spec),
MaybeVars = error1([Spec])
).
%---------------------------------------------------------------------------%
:- pred generate_repeated_var_msg(cord(format_component)::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,
words("Repeated variable"), words(TermStr), suffix("."), nl],
Spec = simplest_spec(severity_error, phase_term_to_parse_tree,
get_term_context(Term), Pieces).
:- pred generate_repeated_state_var_msg(cord(format_component)::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,
words("Repeated state variable"), words(TermStr), suffix("."), nl],
Spec = simplest_spec(severity_error, phase_term_to_parse_tree,
get_term_context(Term), Pieces).
:- pred generate_unexpected_term_message(cord(format_component)::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"), words(Expected), suffix(","),
words("got"), quote(TermStr), suffix("."), nl],
Spec = simplest_spec(severity_error, phase_term_to_parse_tree,
get_term_context(Term), Pieces).
%---------------------------------------------------------------------------%
:- end_module parse_tree.parse_vars.
%---------------------------------------------------------------------------%