Files
mercury/compiler/prog_io_goal.m
Julien Fischer 05ce757fdf Fix bug #241: a typo was preventing require_semidet scopes from being
Branches: main, 11.07

Fix bug #241: a typo was preventing require_semidet scopes from being
recognised.

compiler/prog_io.m;
	Fix a typo: s/require_semi/require_semidet/

tests/valid/Mmakefile:
tests/valid/require_bug.m:
	Add a test the above.
2011-12-03 13:35:16 +00:00

1995 lines
78 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1996-2011 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_io_goal.m.
% Main authors: fjh, zs.
%
% This module defines the predicates that parse goals.
%
%-----------------------------------------------------------------------------%
:- module parse_tree.prog_io_goal.
:- interface.
:- import_module parse_tree.error_util.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_item.
:- import_module parse_tree.prog_io_util.
:- import_module list.
:- import_module term.
%-----------------------------------------------------------------------------%
% Convert a single term into a goal.
%
:- pred parse_goal(term::in, list(format_component)::in, maybe1(goal)::out,
prog_varset::in, prog_varset::out) is det.
% Convert a term, possibly starting with `some [Vars]', into
% a list of the quantified variables, a list of quantified
% state variables, and a goal. (If the term doesn't start
% with `some [Vars]', we return empty lists of variables.)
%
:- pred parse_some_vars_goal(term::in, list(format_component)::in,
maybe3(list(prog_var), list(prog_var), goal)::out,
prog_varset::in, prog_varset::out) is det.
% parse_pred_expression/3 converts the first argument to a :-/2
% higher-order pred expression into a list of variables, a list
% of their corresponding modes, and a determinism.
%
:- pred parse_pred_expression(term::in, ho_groundness::out,
lambda_eval_method::out, list(prog_term)::out, list(mer_mode)::out,
determinism::out) is semidet.
% parse_dcg_pred_expression/3 converts the first argument to a -->/2
% higher-order DCG pred expression into a list of arguments, a list
% of their corresponding modes and the two DCG argument modes, and a
% determinism.
% This is a variant of the higher-order pred syntax:
% `(pred(Var1::Mode1, ..., VarN::ModeN, DCG0Mode, DCGMode)
% is Det --> Goal)'.
%
% For `any' insts replace `pred' with `any_pred'.
%
:- pred parse_dcg_pred_expression(term::in, ho_groundness::out,
lambda_eval_method::out, list(prog_term)::out, list(mer_mode)::out,
determinism::out) is semidet.
% parse_func_expression/3 converts the first argument to a :-/2
% higher-order func expression into a list of arguments, a list
% of their corresponding modes, and a determinism. The syntax
% of a higher-order func expression is
% `(func(Var1::Mode1, ..., VarN::ModeN) = (VarN1::ModeN1) is Det
% :- Goal)'
% or
% `(func(Var1, ..., VarN) = (VarN1) is Det :- Goal)'
% where the modes are assumed to be `in' for the
% function arguments and `out' for the result
% or
% `(func(Var1, ..., VarN) = (VarN1) :- Goal)'
% where the modes are assumed as above, and the
% determinism is assumed to be det
% or
% `(func(Var1, ..., VarN) = (VarN1)). '
%
% For `any' insts replace `func' with `any_func'.
%
:- pred parse_func_expression(term::in, ho_groundness::out,
lambda_eval_method::out, list(prog_term)::out, list(mer_mode)::out,
determinism::out) is semidet.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.mercury_to_mercury.
:- import_module parse_tree.prog_io.
:- import_module parse_tree.prog_io_sym_name.
:- import_module parse_tree.prog_io_util.
:- import_module parse_tree.prog_mode.
:- import_module parse_tree.prog_out.
:- import_module assoc_list.
:- import_module char.
:- import_module maybe.
:- import_module pair.
:- import_module solutions.
:- import_module string.
:- import_module term.
:- import_module varset.
%-----------------------------------------------------------------------------%
parse_goal(Term, ContextPieces, MaybeGoal, !VarSet) :-
% We could do some error-checking here, but all errors are picked up
% in either the type-checker or parser anyway.
% First, get the goal context.
(
Term = term.functor(_, _, Context)
;
Term = term.variable(_, Context)
),
% We just check if it matches the appropriate pattern for one of the
% builtins. If it doesn't match any of the builtins, then it's just
% a predicate call.
(
% Check for builtins...
Term = term.functor(term.atom(Name), Args, Context),
parse_goal_2(Name, Args, Context, ContextPieces, MaybeGoalPrime,
!VarSet)
->
MaybeGoal = MaybeGoalPrime
;
% It's not a builtin.
term.coerce(Term, ArgsTerm),
% Check for predicate calls.
( try_parse_sym_name_and_args(ArgsTerm, SymName, Args) ->
GoalExpr = call_expr(SymName, Args, purity_pure)
;
% A call to a free variable, or to a number or string.
% Just translate it into a call to call/1 - the typechecker
% will catch calls to numbers and strings.
GoalExpr = call_expr(unqualified("call"), [ArgsTerm], purity_pure)
),
Goal = GoalExpr - Context,
MaybeGoal = ok1(Goal)
).
%-----------------------------------------------------------------------------%
:- pred parse_goal_2(string::in, list(term)::in, term.context::in,
list(format_component)::in, maybe1(goal)::out,
prog_varset::in, prog_varset::out) is semidet.
parse_goal_2(Functor, Args, Context, ContextPieces, MaybeGoal, !VarSet) :-
% Since (A -> B) has different semantics in standard Prolog
% (A -> B ; fail) than it does in NU-Prolog or Mercury (A -> B ; true),
% for the moment we'll just disallow it.
% For consistency we also disallow if-then without the else.
% XXX We should update ContextPieces as we recurse down.
(
Functor = "true",
Args = [],
MaybeGoal = ok1(true_expr - Context)
;
Functor = "fail",
Args = [],
MaybeGoal = ok1(fail_expr - Context)
;
Functor = "=",
Args = [ATerm0, BTerm0],
term.coerce(ATerm0, ATerm),
term.coerce(BTerm0, BTerm),
MaybeGoal = ok1(unify_expr(ATerm, BTerm, purity_pure) - Context)
;
Functor = ",",
Args = [ATerm, BTerm],
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeBGoal = ok1(BGoal)
->
MaybeGoal = ok1(conj_expr(AGoal, BGoal) - Context)
;
ASpecs = get_any_errors1(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(ASpecs ++ BSpecs)
)
;
Functor = "&",
Args = [ATerm, BTerm],
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeBGoal = ok1(BGoal)
->
MaybeGoal = ok1(par_conj_expr(AGoal, BGoal) - Context)
;
ASpecs = get_any_errors1(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(ASpecs ++ BSpecs)
)
;
Functor = ";",
Args = [ATerm, BTerm],
( ATerm = term.functor(term.atom("->"), [XTerm, YTerm], _Context) ->
parse_some_vars_goal(XTerm, ContextPieces, MaybeXGoal, !VarSet),
parse_goal(YTerm, ContextPieces, MaybeYGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeXGoal = ok3(Vars, StateVars, XGoal),
MaybeYGoal = ok1(YGoal),
MaybeBGoal = ok1(BGoal)
->
Goal = if_then_else_expr(Vars, StateVars, XGoal, YGoal, BGoal)
- Context,
MaybeGoal = ok1(Goal)
;
XSpecs = get_any_errors3(MaybeXGoal),
YSpecs = get_any_errors1(MaybeYGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(XSpecs ++ YSpecs ++ BSpecs)
)
;
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeBGoal = ok1(BGoal)
->
MaybeGoal = ok1(disj_expr(AGoal, BGoal) - Context)
;
ASpecs = get_any_errors1(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(ASpecs ++ BSpecs)
)
)
;
Functor = "else",
Args = [IfTerm, CTerm],
(
IfTerm = term.functor(term.atom("if"),
[term.functor(term.atom("then"), [ATerm, BTerm], _)], _)
->
parse_some_vars_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
parse_goal(CTerm, ContextPieces, MaybeCGoal, !VarSet),
(
MaybeAGoal = ok3(Vars, StateVars, AGoal),
MaybeBGoal = ok1(BGoal),
MaybeCGoal = ok1(CGoal)
->
Goal = if_then_else_expr(Vars, StateVars, AGoal, BGoal, CGoal)
- Context,
MaybeGoal = ok1(Goal)
;
ASpecs = get_any_errors3(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
CSpecs = get_any_errors1(MaybeCGoal),
MaybeGoal = error1(ASpecs ++ BSpecs ++ CSpecs)
)
;
% `else' can also be part of a `try' goal.
parse_else_then_try_term(
term.functor(term.atom("else"), [IfTerm, CTerm], Context),
[], no, Context, ContextPieces, MaybeGoal, !VarSet)
)
;
Functor = "then",
Args = [TryTerm, ThenTerm],
parse_then_try_term(
term.functor(atom("then"), [TryTerm, ThenTerm], Context),
no, [], no, Context, ContextPieces, MaybeGoal, !VarSet)
;
Functor = "catch",
Args = [ElseThenTryTerm, CatchTerm],
parse_catch_then_try_term(
term.functor(atom("catch"), [ElseThenTryTerm, CatchTerm], Context),
no, Context, ContextPieces, MaybeGoal, !VarSet)
;
Functor = "catch_any",
Args = [TermA, ArrowTerm],
parse_catch_any_term(ArrowTerm, Context, ContextPieces,
MaybeCatchAnyExpr, !VarSet),
(
MaybeCatchAnyExpr = ok1(CatchAnyExpr),
( TermA = term.functor(atom("catch"), _, _) ->
parse_catch_then_try_term(TermA, yes(CatchAnyExpr),
Context, ContextPieces, MaybeGoal, !VarSet)
;
parse_else_then_try_term(TermA, [], yes(CatchAnyExpr),
Context, ContextPieces, MaybeGoal, !VarSet)
)
;
MaybeCatchAnyExpr = error1(Specs),
MaybeGoal = error1(Specs)
)
;
( Functor = "not"
; Functor = "\\+"
),
Args = [ATerm],
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeGoal = ok1(not_expr(AGoal) - Context)
;
MaybeAGoal = error1(_),
MaybeGoal = MaybeAGoal
)
;
Functor = "all",
Args = [QVarsTerm, SubTerm],
% Extract any state variables in the quantifier.
varset.coerce(!.VarSet, GenericVarSet),
parse_quantifier_vars(QVarsTerm, GenericVarSet, ContextPieces,
MaybeStateVarsAndVars),
% XXX We should update ContextPieces, instead of supplying [].
parse_goal(SubTerm, [], MaybeSubGoal, !VarSet),
(
MaybeStateVarsAndVars = ok2(Vars0, StateVars0),
MaybeSubGoal = ok1(SubGoal)
->
list.map(term.coerce_var, Vars0, Vars),
list.map(term.coerce_var, StateVars0, StateVars),
SubGoal = SubGoalExpr - SubContext,
(
Vars = [],
StateVars = [],
GoalExpr = SubGoalExpr
;
Vars = [],
StateVars = [_ | _],
GoalExpr = all_state_vars_expr(StateVars, SubGoal)
;
Vars = [_ | _],
StateVars = [],
GoalExpr = all_expr(Vars, SubGoal)
;
Vars = [_ | _], StateVars = [_ | _],
GoalExpr = all_expr(Vars,
all_state_vars_expr(StateVars, SubGoal)
- SubContext)
),
Goal = GoalExpr - Context,
MaybeGoal = ok1(Goal)
;
VarsSpecs = get_any_errors2(MaybeStateVarsAndVars),
SubGoalSpecs = get_any_errors1(MaybeSubGoal),
MaybeGoal = error1(VarsSpecs ++ SubGoalSpecs)
)
;
Functor = "<=",
Args = [ATerm, BTerm],
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeBGoal = ok1(BGoal)
->
MaybeGoal = ok1(implies_expr(BGoal, AGoal) - Context)
;
ASpecs = get_any_errors1(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(ASpecs ++ BSpecs)
)
;
Functor = "=>",
Args = [ATerm, BTerm],
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeBGoal = ok1(BGoal)
->
MaybeGoal = ok1(implies_expr(AGoal, BGoal) - Context)
;
ASpecs = get_any_errors1(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(ASpecs ++ BSpecs)
)
;
Functor = "<=>",
Args = [ATerm, BTerm],
parse_goal(ATerm, ContextPieces, MaybeAGoal, !VarSet),
parse_goal(BTerm, ContextPieces, MaybeBGoal, !VarSet),
(
MaybeAGoal = ok1(AGoal),
MaybeBGoal = ok1(BGoal)
->
MaybeGoal = ok1(equivalent_expr(AGoal, BGoal) - Context)
;
ASpecs = get_any_errors1(MaybeAGoal),
BSpecs = get_any_errors1(MaybeBGoal),
MaybeGoal = error1(ASpecs ++ BSpecs)
)
;
Functor = "some",
Args = [QVarsTerm, SubTerm],
% Extract any state variables in the quantifier.
UpdatedContextPieces = ContextPieces ++ [lower_case_next_if_not_first,
words("In first argument of"), quote("some"), suffix(":")],
varset.coerce(!.VarSet, GenericVarSet),
parse_quantifier_vars(QVarsTerm, GenericVarSet, UpdatedContextPieces,
MaybeStateVarsAndVars),
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeStateVarsAndVars = ok2(Vars0, StateVars0),
MaybeSubGoal = ok1(SubGoal)
->
list.map(term.coerce_var, Vars0, Vars),
list.map(term.coerce_var, StateVars0, StateVars),
SubGoal = SubGoalExpr - SubContext,
(
Vars = [],
StateVars = [],
GoalExpr = SubGoalExpr
;
Vars = [],
StateVars = [_ | _],
GoalExpr = some_state_vars_expr(StateVars, SubGoal)
;
Vars = [_ | _],
StateVars = [],
GoalExpr = some_expr(Vars, SubGoal)
;
Vars = [_ | _],
StateVars = [_ | _],
GoalExpr = some_expr(Vars,
some_state_vars_expr(StateVars, SubGoal)
- SubContext)
),
Goal = GoalExpr - Context,
MaybeGoal = ok1(Goal)
;
VarsSpecs = get_any_errors2(MaybeStateVarsAndVars),
SubGoalSpecs = get_any_errors1(MaybeSubGoal),
MaybeGoal = error1(VarsSpecs ++ SubGoalSpecs)
)
;
Functor = "trace",
Args = [ParamsTerm, SubTerm],
varset.coerce(!.VarSet, GenericVarSet),
parse_trace_params(GenericVarSet, Context, ParamsTerm, MaybeParams),
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeParams = ok1(Params),
MaybeSubGoal = ok1(SubGoal)
->
convert_trace_params(Params, MaybeComponents),
(
MaybeComponents = ok4(CompileTime, RunTime, MaybeIO, MutVars),
GoalExpr = trace_expr(CompileTime, RunTime, MaybeIO, MutVars,
SubGoal),
MaybeGoal = ok1(GoalExpr - Context)
;
MaybeComponents = error4(Specs),
MaybeGoal = error1(Specs)
)
;
ParamsSpecs = get_any_errors1(MaybeParams),
SubGoalSpecs = get_any_errors1(MaybeSubGoal),
MaybeGoal = error1(ParamsSpecs ++ SubGoalSpecs)
)
;
Functor = "atomic",
Args = [ParamsTerm, SubTerm],
varset.coerce(!.VarSet, GenericVarSet),
parse_atomic_params(Context, ParamsTerm, GenericVarSet, MaybeParams),
parse_atomic_subexpr(SubTerm, MaybeSubGoals, !VarSet),
(
MaybeParams = ok1(Params),
MaybeSubGoals = ok2(MainGoal, OrElseGoals)
->
convert_atomic_params(ParamsTerm, Params, MaybeComponents),
(
MaybeComponents = ok3(Outer, Inner, MaybeOutputVars),
GoalExpr = atomic_expr(Outer, Inner, MaybeOutputVars, MainGoal,
OrElseGoals),
MaybeGoal = ok1(GoalExpr - Context)
;
MaybeComponents = error3(Specs),
MaybeGoal = error1(Specs)
)
;
ParamsSpecs = get_any_errors1(MaybeParams),
SubGoalSpecs = get_any_errors2(MaybeSubGoals),
MaybeGoal = error1(ParamsSpecs ++ SubGoalSpecs)
)
;
( Functor = "promise_equivalent_solutions"
; Functor = "promise_equivalent_solution_sets"
),
Args = [VarsTerm, SubTerm],
varset.coerce(!.VarSet, GenericVarSet),
parse_vars_and_state_vars(VarsTerm, GenericVarSet, ContextPieces,
MaybeVars),
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeVars = ok4(Vars0, StateVars0, DotSVars0, ColonSVars0),
MaybeSubGoal = ok1(SubGoal)
->
list.map(term.coerce_var, Vars0, Vars),
list.map(term.coerce_var, StateVars0, StateVars),
list.map(term.coerce_var, DotSVars0, DotSVars),
list.map(term.coerce_var, ColonSVars0, ColonSVars),
(
Functor = "promise_equivalent_solutions",
MaybeGoal = ok1(promise_equivalent_solutions_expr(Vars,
StateVars, DotSVars, ColonSVars, SubGoal) - Context)
;
Functor = "promise_equivalent_solution_sets",
MaybeGoal = ok1(promise_equivalent_solution_sets_expr(Vars,
StateVars, DotSVars, ColonSVars, SubGoal) - Context)
)
;
VarsSpecs = get_any_errors4(MaybeVars),
SubGoalSpecs = get_any_errors1(MaybeSubGoal),
MaybeGoal = error1(VarsSpecs ++ SubGoalSpecs)
)
;
Functor = "arbitrary",
Args = [VarsTerm, SubTerm],
varset.coerce(!.VarSet, GenericVarSet),
parse_vars_and_state_vars(VarsTerm, GenericVarSet, ContextPieces,
MaybeVars),
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeVars = ok4(Vars0, StateVars0, DotSVars0, ColonSVars0),
MaybeSubGoal = ok1(SubGoal)
->
list.map(term.coerce_var, Vars0, Vars),
list.map(term.coerce_var, StateVars0, StateVars),
list.map(term.coerce_var, DotSVars0, DotSVars),
list.map(term.coerce_var, ColonSVars0, ColonSVars),
MaybeGoal = ok1(promise_equivalent_solution_arbitrary_expr(Vars,
StateVars, DotSVars, ColonSVars, SubGoal) - Context)
;
VarsSpecs = get_any_errors4(MaybeVars),
SubGoalSpecs = get_any_errors1(MaybeSubGoal),
MaybeGoal = error1(VarsSpecs ++ SubGoalSpecs)
)
;
(
Functor = "promise_pure",
Purity = purity_pure
;
Functor = "promise_semipure",
Purity = purity_semipure
;
Functor = "promise_impure",
Purity = purity_impure
),
Args = [SubTerm],
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeSubGoal = ok1(SubGoal),
Goal = promise_purity_expr(Purity, SubGoal) - Context,
MaybeGoal = ok1(Goal)
;
MaybeSubGoal = error1(Specs),
MaybeGoal = error1(Specs)
)
;
(
Functor = "require_det",
Detism = detism_det
;
Functor = "require_semidet",
Detism = detism_semi
;
Functor = "require_multi",
Detism = detism_multi
;
Functor = "require_nondet",
Detism = detism_non
;
Functor = "require_cc_multi",
Detism = detism_cc_multi
;
Functor = "require_cc_nondet",
Detism = detism_cc_non
;
Functor = "require_erroneous",
Detism = detism_erroneous
;
Functor = "require_failure",
Detism = detism_failure
),
Args = [SubTerm],
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeSubGoal = ok1(SubGoal),
Goal = require_detism_expr(Detism, SubGoal) - Context,
MaybeGoal = ok1(Goal)
;
MaybeSubGoal = error1(Specs),
MaybeGoal = error1(Specs)
)
;
Functor = "require_complete_switch",
Args = [VarsTerm, SubTerm],
varset.coerce(!.VarSet, GenericVarSet),
parse_vars(VarsTerm, GenericVarSet, ContextPieces, MaybeVars),
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeVars = ok1(Vars0),
MaybeSubGoal = ok1(SubGoal)
->
(
Vars0 = [],
SubGoal = _ - SubContext,
RCSPieces = ContextPieces ++
[words("Error: the first argument of"),
words("require_complete_switch"),
words("must contain a variable."), nl],
RCSSpec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(SubContext, [always(RCSPieces)])]),
MaybeGoal = error1([RCSSpec])
;
Vars0 = [Var0],
term.coerce_var(Var0, Var),
MaybeGoal = ok1(require_complete_switch_expr(Var, SubGoal)
- Context)
;
Vars0 = [_, _ | _],
SubGoal = _ - SubContext,
RCSPieces = ContextPieces ++
[words("Error: the first argument of"),
words("require_complete_switch"),
words("cannot contain more than one variable."), nl],
RCSSpec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(SubContext, [always(RCSPieces)])]),
MaybeGoal = error1([RCSSpec])
)
;
VarsSpecs = get_any_errors1(MaybeVars),
SubGoalSpecs = get_any_errors1(MaybeSubGoal),
MaybeGoal = error1(VarsSpecs ++ SubGoalSpecs)
)
;
(
Functor = "impure",
Purity = purity_impure
;
Functor = "semipure",
Purity = purity_semipure
),
Args = [SubTerm],
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeSubGoal = ok1(SubGoal),
SubGoal = SubGoalExpr - _SubContext,
( SubGoalExpr = call_expr(Pred, CallArgs, purity_pure) ->
MaybeGoal = ok1(call_expr(Pred, CallArgs, Purity) - Context)
; SubGoalExpr = unify_expr(ProgTerm1, ProgTerm2, purity_pure) ->
MaybeGoal = ok1(unify_expr(ProgTerm1, ProgTerm2, Purity)
- Context)
;
% Inappropriate placement of an impurity marker, so we treat
% it like a predicate call. typecheck.m prints out something
% descriptive for these errors.
%
% XXX we could return MaybeGoal = error1 here.
purity_name(Purity, PurityString),
term.coerce(SubTerm, CoercedSubTerm),
GoalExpr = call_expr(unqualified(PurityString),
[CoercedSubTerm], purity_pure),
MaybeGoal = ok1(GoalExpr - Context)
)
;
MaybeSubGoal = error1(_),
MaybeGoal = MaybeSubGoal
)
;
Functor = "event",
Args = [SubTerm],
parse_goal(SubTerm, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeSubGoal = ok1(SubGoal),
( SubGoal = call_expr(SymName, CallArgs, Purity) - SubContext ->
(
SymName = unqualified(EventName),
Purity = purity_pure
->
Goal = event_expr(EventName, CallArgs) - Context,
MaybeGoal = ok1(Goal)
;
some [!Specs] (
!:Specs = [],
(
SymName = unqualified(_)
;
SymName = qualified(_, _),
QualPieces = ContextPieces ++
[lower_case_next_if_not_first,
words("Error: event name"),
words("must not be qualified."), nl],
QualSpec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(SubContext,
[always(QualPieces)])]),
!:Specs = [QualSpec | !.Specs]
),
(
Purity = purity_pure
;
( Purity = purity_semipure
; Purity = purity_impure
),
PurityPieces = ContextPieces ++
[lower_case_next_if_not_first,
words("Error: event cannot be"),
words("impure or semipure."), nl],
PuritySpec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(SubContext,
[always(PurityPieces)])]),
!:Specs = [PuritySpec | !.Specs]
),
MaybeGoal = error1(!.Specs)
)
)
;
Pieces = ContextPieces ++ [lower_case_next_if_not_first,
words("Error: event prefix must not precede anything"),
words("other than a call."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(SubTerm), [always(Pieces)])]),
MaybeGoal = error1([Spec])
)
;
MaybeSubGoal = error1(Specs),
MaybeGoal = error1(Specs)
)
;
Functor = "is",
Args = [ATerm0, BTerm0],
% The following is a temporary hack to handle `is' in the parser -
% we ought to handle it in the code generation - but then `is/2' itself
% is a bit of a hack.
term.coerce(ATerm0, ATerm),
term.coerce(BTerm0, BTerm),
MaybeGoal = ok1(unify_expr(ATerm, BTerm, purity_pure) - Context)
).
%-----------------------------------------------------------------------------%
parse_some_vars_goal(Term, ContextPieces, MaybeVarsAndGoal, !VarSet) :-
( Term = term.functor(term.atom("some"), [QVarsTerm, SubTerm], _Context) ->
UpdatedContextPieces = ContextPieces ++ [lower_case_next_if_not_first,
words("In first argument of"), quote("some"), suffix(":")],
varset.coerce(!.VarSet, GenericVarSet),
parse_quantifier_vars(QVarsTerm, GenericVarSet, UpdatedContextPieces,
MaybeVars),
GoalTerm = SubTerm
;
MaybeVars = ok2([], []),
GoalTerm = Term
),
parse_goal(GoalTerm, ContextPieces, MaybeGoal, !VarSet),
(
MaybeVars = ok2(Vars0, StateVars0),
MaybeGoal = ok1(Goal)
->
list.map(term.coerce_var, Vars0, Vars),
list.map(term.coerce_var, StateVars0, StateVars),
MaybeVarsAndGoal = ok3(Vars, StateVars, Goal)
;
VarsSpecs = get_any_errors2(MaybeVars),
GoalSpecs = get_any_errors1(MaybeGoal),
MaybeVarsAndGoal = error3(VarsSpecs ++ GoalSpecs)
).
%-----------------------------------------------------------------------------%
:- type trace_component
---> trace_component_compiletime(trace_expr(trace_compiletime))
; trace_component_runtime(trace_expr(trace_runtime))
; trace_component_maybe_io(prog_var)
; trace_component_mutable_var(trace_mutable_var).
:- pred parse_trace_params(varset::in, context::in, term::in,
maybe1(assoc_list(trace_component, term.context))::out) is det.
parse_trace_params(VarSet, Context, Term, MaybeComponentsContexts) :-
( Term = term.functor(term.atom("[]"), [], _) ->
MaybeComponentsContexts = ok1([])
; Term = term.functor(term.atom("[|]"), [HeadTerm, TailTerm], _) ->
parse_trace_component(VarSet, Term, HeadTerm,
MaybeHeadComponentContext),
parse_trace_params(VarSet, Context, TailTerm,
MaybeTailComponentsContexts),
(
MaybeHeadComponentContext = ok1(HeadComponentContext),
MaybeTailComponentsContexts = ok1(TailComponentsContexts)
->
MaybeComponentsContexts =
ok1([HeadComponentContext | TailComponentsContexts])
;
HeadSpecs = get_any_errors1(MaybeHeadComponentContext),
TailSpecs = get_any_errors1(MaybeTailComponentsContexts),
MaybeComponentsContexts = error1(HeadSpecs ++ TailSpecs)
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid trace goal parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]),
MaybeComponentsContexts = error1([Spec])
).
:- pred parse_trace_component(varset::in, term::in, term::in,
maybe1(pair(trace_component, term.context))::out) is det.
parse_trace_component(VarSet, _ErrorTerm, Term, MaybeComponentContext) :-
(
Term = term.functor(Functor, SubTerms, Context),
Functor = term.atom(Atom)
->
(
( Atom = "compiletime"
; Atom = "compile_time"
)
->
( SubTerms = [SubTerm] ->
parse_trace_tree(parse_trace_compiletime(VarSet), SubTerm,
MaybeCompileTime),
(
MaybeCompileTime = ok1(CompileTime),
Component = trace_component_compiletime(CompileTime),
MaybeComponentContext = ok1(Component - Context)
;
MaybeCompileTime = error1(Specs),
MaybeComponentContext = error1(Specs)
)
;
Pieces = [words("Error:"), fixed(Atom),
words("takes exactly one argument,"),
words("which should be a boolean expression"),
words("of compile-time tests."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
( Atom = "runtime"
; Atom = "run_time"
)
->
( SubTerms = [SubTerm] ->
parse_trace_tree(parse_trace_runtime(VarSet), SubTerm,
MaybeRunTime),
(
MaybeRunTime = ok1(RunTime),
Component = trace_component_runtime(RunTime),
MaybeComponentContext = ok1(Component - Context)
;
MaybeRunTime = error1(Specs),
MaybeComponentContext = error1(Specs)
)
;
Pieces = [words("Error:"), fixed(Atom),
words("takes exactly one argument,"),
words("which should be a boolean expression"),
words("of run-time tests."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Atom = "io"
->
( SubTerms = [SubTerm] ->
(
SubTerm = term.functor(term.atom("!"),
[term.variable(Var, _)], _)
->
term.coerce_var(Var, ProgVar),
Component = trace_component_maybe_io(ProgVar),
MaybeComponentContext = ok1(Component - Context)
;
Pieces = [words("Error: the argument of"), fixed(Atom),
words("should be a state variable."), nl],
Spec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(get_term_context(SubTerm),
[always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Pieces = [words("Error:"), fixed(Atom),
words("takes exactly one argument,"),
words("which should be a state variable name."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Atom = "state"
->
( SubTerms = [SubTermA, SubTermB] ->
( SubTermA = term.functor(term.atom(MutableName), [], _) ->
MaybeMutable = ok1(MutableName)
;
MutablePieces = [words("Error: the first argument of"),
fixed(Atom), words("should be"),
words("the name of a mutable variable."), nl],
MutableSpec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(get_term_context(SubTermA),
[always(MutablePieces)])]),
MaybeMutable = error1([MutableSpec])
),
(
SubTermB = term.functor(term.atom("!"),
[term.variable(Var, _)], _)
->
MaybeVar = ok1(Var)
;
VarPieces = [words("Error: the second argument of"),
fixed(Atom), words("should be"),
words("a state variable name."), nl],
VarSpec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(get_term_context(SubTermB),
[always(VarPieces)])]),
MaybeVar = error1([VarSpec])
),
(
MaybeMutable = ok1(FinalMutable),
MaybeVar = ok1(FinalVar)
->
term.coerce_var(FinalVar, ProgVar),
MutableVar = trace_mutable_var(FinalMutable, ProgVar),
Component = trace_component_mutable_var(MutableVar),
MaybeComponentContext = ok1(Component - Context)
;
VarSpecs = get_any_errors1(MaybeVar),
MutableSpecs = get_any_errors1(MaybeMutable),
MaybeComponentContext =
error1(VarSpecs ++ MutableSpecs)
)
;
Pieces = [words("Error:"), fixed(Atom),
words("takes exactly two arguments,"),
words("which should be"),
words("the name of a mutable variable"),
words("and a state variable name."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid trace goal parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid trace goal parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
).
:- pred parse_trace_tree(pred(term, maybe1(T))::in(pred(in, out) is det),
term::in, maybe1(trace_expr(T))::out) is det.
parse_trace_tree(BaseParser, Term, MaybeTree) :-
(
Term = term.functor(term.atom(Atom), [LTerm, RTerm], _),
(
Atom = "or",
Op = trace_or
;
Atom = "and",
Op = trace_and
)
->
parse_trace_tree(BaseParser, LTerm, MaybeLExpr),
parse_trace_tree(BaseParser, RTerm, MaybeRExpr),
(
MaybeLExpr = ok1(LExpr),
MaybeRExpr = ok1(RExpr)
->
MaybeTree = ok1(trace_op(Op, LExpr, RExpr))
;
LSpecs = get_any_errors1(MaybeLExpr),
RSpecs = get_any_errors1(MaybeRExpr),
MaybeTree = error1(LSpecs ++ RSpecs)
)
;
Term = term.functor(term.atom("not"), [SubTerm], _)
->
parse_trace_tree(BaseParser, SubTerm, MaybeSubExpr),
(
MaybeSubExpr = ok1(SubExpr)
->
MaybeTree = ok1(trace_not(SubExpr))
;
SubSpecs = get_any_errors1(MaybeSubExpr),
MaybeTree = error1(SubSpecs)
)
;
BaseParser(Term, MaybeBase),
(
MaybeBase = ok1(Base),
MaybeTree = ok1(trace_base(Base))
;
MaybeBase = error1(Specs),
MaybeTree = error1(Specs)
)
).
:- pred parse_trace_compiletime(varset::in, term::in,
maybe1(trace_compiletime)::out) is det.
parse_trace_compiletime(VarSet, Term, MaybeCompiletime) :-
(
Term = term.functor(Functor, SubTerms, TermContext),
Functor = term.atom(Atom)
->
( Atom = "flag" ->
( SubTerms = [SubTerm] ->
( SubTerm = term.functor(term.string(FlagName), [], _) ->
Compiletime = trace_flag(FlagName),
MaybeCompiletime = ok1(Compiletime)
;
Pieces = [words("Error: compile_time parameter"),
quote("flag"),
words("takes a string as argument."), nl],
Spec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
;
Pieces = [words("Error: compile_time parameter"),
quote("flag"), words("takes just one argument."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
; Atom = "grade" ->
( SubTerms = [SubTerm] ->
(
SubTerm = term.functor(term.atom(GradeName), [], _),
parse_trace_grade_name(GradeName, TraceGrade)
->
Compiletime = trace_grade(TraceGrade),
MaybeCompiletime = ok1(Compiletime)
;
solutions(valid_trace_grade_name, ValidGradeNames),
Pieces = [words("invalid grade test;"),
words("valid grade tests are")] ++
list_to_pieces(ValidGradeNames) ++
[suffix("."), nl],
Spec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
;
Pieces = [words("Error: compile_time parameter"),
quote("grade"), words("takes just one argument."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
; Atom = "tracelevel" ->
( SubTerms = [SubTerm] ->
(
SubTerm = term.functor(term.atom(LevelName), [], _),
(
LevelName = "shallow",
Level = trace_level_shallow
;
LevelName = "deep",
Level = trace_level_deep
)
->
Compiletime = trace_trace_level(Level),
MaybeCompiletime = ok1(Compiletime)
;
Pieces = [words("Error: compile_time parameter"),
quote("tracelevel"), words("takes just"),
quote("shallow"), words("or"), quote("deep"),
words("as argument."), nl],
Spec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
;
Pieces = [words("Error: compile_time parameter"),
quote("tracelevel"),
words("takes just one argument."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid compile_time parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid compile_time parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]),
MaybeCompiletime = error1([Spec])
).
:- pred parse_trace_runtime(varset::in, term::in,
maybe1(trace_runtime)::out) is det.
parse_trace_runtime(VarSet, Term, MaybeRuntime) :-
(
Term = term.functor(Functor, SubTerms, TermContext),
Functor = term.atom(Atom)
->
( Atom = "env" ->
( SubTerms = [SubTerm] ->
(
SubTerm = term.functor(SubFunctor, [], _),
( SubFunctor = term.string(EnvVarName)
; SubFunctor = term.atom(EnvVarName)
),
EnvVarChars = string.to_char_list(EnvVarName),
list.filter(env_var_is_acceptable_char,
EnvVarChars, _, [])
->
Runtime = trace_envvar(EnvVarName),
MaybeRuntime = ok1(Runtime)
;
Pieces = [words("Error: run_time parameter"), quote("env"),
words("takes an identifier as argument."), nl],
Spec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(get_term_context(SubTerm),
[always(Pieces)])]),
MaybeRuntime = error1([Spec])
)
;
Pieces = [words("Error: run_time parameter"), quote("env"),
words("takes just one argument."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeRuntime = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid run_time parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeRuntime = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid run_time parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]),
MaybeRuntime = error1([Spec])
).
:- pred env_var_is_acceptable_char(char::in) is semidet.
env_var_is_acceptable_char(Char) :-
% This definition must be consistent with the check applied in
% util/mkinit.c.
(
char.is_alnum(Char)
;
Char = '_'
).
:- pred convert_trace_params(assoc_list(trace_component, term.context)::in,
maybe4(maybe(trace_expr(trace_compiletime)),
maybe(trace_expr(trace_runtime)), maybe(prog_var),
list(trace_mutable_var))::out) is det.
convert_trace_params(Components, MaybeParams) :-
convert_trace_params_2(Components, no, no, no, [], [], MaybeParams).
:- pred convert_trace_params_2(assoc_list(trace_component, term.context)::in,
maybe(trace_expr(trace_compiletime))::in,
maybe(trace_expr(trace_runtime))::in,
maybe(prog_var)::in, list(trace_mutable_var)::in,
list(error_spec)::in,
maybe4(maybe(trace_expr(trace_compiletime)),
maybe(trace_expr(trace_runtime)), maybe(prog_var),
list(trace_mutable_var))::out) is det.
convert_trace_params_2([], MaybeCompileTime, MaybeRunTime, MaybeIO,
MutableVars, Specs, MaybeParams) :-
(
Specs = [],
MaybeParams = ok4(MaybeCompileTime, MaybeRunTime, MaybeIO, MutableVars)
;
Specs = [_ | _],
MaybeParams = error4(Specs)
).
convert_trace_params_2([Component - Context | ComponentsContexts],
!.MaybeCompileTime, !.MaybeRunTime, !.MaybeIO, !.MutableVars,
!.Specs, MaybeParams) :-
(
Component = trace_component_compiletime(CompileTime),
(
!.MaybeCompileTime = no,
!:MaybeCompileTime = yes(CompileTime)
;
!.MaybeCompileTime = yes(_),
Pieces = [words("Duplicate compile_time trace parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
!:Specs = [Spec | !.Specs]
)
;
Component = trace_component_runtime(RunTime),
(
!.MaybeRunTime = no,
!:MaybeRunTime = yes(RunTime)
;
!.MaybeRunTime = yes(_),
Pieces = [words("Duplicate run_time trace parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
!:Specs = [Spec | !.Specs]
)
;
Component = trace_component_maybe_io(IOStateVar),
(
!.MaybeIO = no,
!:MaybeIO = yes(IOStateVar)
;
!.MaybeIO = yes(_),
Pieces = [words("Duplicate io trace parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
!:Specs = [Spec | !.Specs]
)
;
Component = trace_component_mutable_var(MutableVar),
!:MutableVars = !.MutableVars ++ [MutableVar]
),
convert_trace_params_2(ComponentsContexts, !.MaybeCompileTime,
!.MaybeRunTime, !.MaybeIO, !.MutableVars, !.Specs, MaybeParams).
%-----------------------------------------------------------------------------%
:- pred parse_catch_any_term(term::in, term.context::in,
list(format_component)::in, maybe1(catch_any_expr)::out,
prog_varset::in, prog_varset::out) is semidet.
parse_catch_any_term(ArrowTerm, _Context, ContextPieces, MaybeCatchAny,
!VarSet) :-
ArrowTerm = term.functor(atom("->"), [VarTerm0, GoalTerm], TermContext),
( VarTerm0 = term.variable(Var0, _) ->
term.coerce_var(Var0, Var),
parse_goal(GoalTerm, ContextPieces, MaybeGoal, !VarSet),
(
MaybeGoal = ok1(Goal),
CatchAny = catch_any_expr(Var, Goal),
MaybeCatchAny = ok1(CatchAny)
;
MaybeGoal = error1(Error),
MaybeCatchAny = error1(Error)
)
;
Pieces = [words("Error: the argument of catch_any"),
words("should be a variable."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeCatchAny = error1([Spec])
).
:- pred parse_catch_then_try_term(term::in, maybe(catch_any_expr)::in,
term.context::in, list(format_component)::in, maybe1(goal)::out,
prog_varset::in, prog_varset::out) is semidet.
parse_catch_then_try_term(CatchElseThenTryTerm, MaybeCatchAnyExpr,
Context, ContextPieces, MaybeGoal, !VarSet) :-
CatchElseThenTryTerm = term.functor(atom("catch"), [TermA, TermB], _),
parse_sub_catch_terms(TermB, Context, ContextPieces, MaybeCatches,
!VarSet),
(
MaybeCatches = ok1(Catches),
parse_else_then_try_term(TermA, Catches, MaybeCatchAnyExpr,
Context, ContextPieces, MaybeGoal, !VarSet)
;
MaybeCatches = error1(Error),
MaybeGoal = error1(Error)
).
:- pred parse_sub_catch_terms(term::in, term.context::in,
list(format_component)::in, maybe1(list(catch_expr))::out,
prog_varset::in, prog_varset::out) is semidet.
parse_sub_catch_terms(Term, Context, ContextPieces, MaybeCatches, !VarSet) :-
( Term = functor(atom("catch"), [CatchArrowTerm, SubTerm], _) ->
parse_catch_arrow_term(CatchArrowTerm, Context, ContextPieces,
MaybeCatch, !VarSet),
(
MaybeCatch = ok1(Catch),
parse_sub_catch_terms(SubTerm, Context, ContextPieces,
MaybeCatches0, !VarSet),
(
MaybeCatches0 = ok1(Catches0),
MaybeCatches = ok1([Catch | Catches0])
;
MaybeCatches0 = error1(Error),
MaybeCatches = error1(Error)
)
;
MaybeCatch = error1(Error),
MaybeCatches = error1(Error)
)
;
parse_catch_arrow_term(Term, Context, ContextPieces, MaybeCatch,
!VarSet),
(
MaybeCatch = ok1(Catch),
MaybeCatches = ok1([Catch])
;
MaybeCatch = error1(Error),
MaybeCatches = error1(Error)
)
).
:- pred parse_catch_arrow_term(term::in, term.context::in,
list(format_component)::in, maybe1(catch_expr)::out,
prog_varset::in, prog_varset::out) is semidet.
parse_catch_arrow_term(CatchArrowTerm, _Context, ContextPieces, MaybeCatch,
!VarSet) :-
CatchArrowTerm = term.functor(atom("->"), [PatternTerm0, GoalTerm], _),
term.coerce(PatternTerm0, PatternTerm),
parse_goal(GoalTerm, ContextPieces, MaybeGoal, !VarSet),
(
MaybeGoal = ok1(Goal),
Catch = catch_expr(PatternTerm, Goal),
MaybeCatch = ok1(Catch)
;
MaybeGoal = error1(Error),
MaybeCatch = error1(Error)
).
:- pred parse_else_then_try_term(term::in, list(catch_expr)::in,
maybe(catch_any_expr)::in, term.context::in, list(format_component)::in,
maybe1(goal)::out, prog_varset::in, prog_varset::out) is semidet.
parse_else_then_try_term(Term, CatchExprs, MaybeCatchAnyExpr,
Context, ContextPieces, MaybeGoal, !VarSet) :-
% `else' part may or may not exist in `try' goals.
( Term = term.functor(term.atom("else"), [ThenTerm, ElseTerm], _) ->
parse_goal(ElseTerm, ContextPieces, MaybeElseGoal0, !VarSet),
(
MaybeElseGoal0 = ok1(ElseGoal),
parse_then_try_term(ThenTerm, yes(ElseGoal), CatchExprs,
MaybeCatchAnyExpr, Context, ContextPieces, MaybeGoal, !VarSet)
;
MaybeElseGoal0 = error1(Specs),
MaybeGoal = error1(Specs)
)
;
parse_then_try_term(Term, no, CatchExprs, MaybeCatchAnyExpr,
Context, ContextPieces, MaybeGoal, !VarSet)
).
:- pred parse_then_try_term(term::in, maybe(goal)::in, list(catch_expr)::in,
maybe(catch_any_expr)::in, term.context::in, list(format_component)::in,
maybe1(goal)::out, prog_varset::in, prog_varset::out) is semidet.
parse_then_try_term(ThenTryTerm, MaybeElse, CatchExprs, MaybeCatchAnyExpr,
Context, ContextPieces, MaybeGoal, !VarSet) :-
ThenTryTerm = term.functor(term.atom("then"), [TryTerm, ThenTerm], _),
TryTerm = term.functor(term.atom("try"), [ParamsTerm, TryGoalTerm], _),
varset.coerce(!.VarSet, GenericVarSet),
parse_try_params(GenericVarSet, Context, ParamsTerm, MaybeParams),
parse_goal(TryGoalTerm, ContextPieces, MaybeTryGoal, !VarSet),
parse_goal(ThenTerm, ContextPieces, MaybeThenGoal, !VarSet),
(
MaybeParams = ok1(Params),
MaybeTryGoal = ok1(TryGoal),
MaybeThenGoal = ok1(ThenGoal)
->
convert_try_params(Params, MaybeComponents),
(
MaybeComponents = ok1(MaybeIO),
GoalExpr = try_expr(MaybeIO, TryGoal, ThenGoal, MaybeElse,
CatchExprs, MaybeCatchAnyExpr),
MaybeGoal = ok1(GoalExpr - Context)
;
MaybeComponents = error1(Specs),
MaybeGoal = error1(Specs)
)
;
ParamsSpecs = get_any_errors1(MaybeParams),
TryGoalSpecs = get_any_errors1(MaybeTryGoal),
ThenGoalSpecs = get_any_errors1(MaybeThenGoal),
MaybeGoal = error1(ParamsSpecs ++ TryGoalSpecs ++ ThenGoalSpecs)
).
:- type try_component
---> try_component_maybe_io(prog_var).
:- pred parse_try_params(varset::in, context::in, term::in,
maybe1(assoc_list(try_component, term.context))::out) is det.
parse_try_params(VarSet, Context, Term, MaybeComponentsContexts) :-
( Term = term.functor(term.atom("[]"), [], _) ->
MaybeComponentsContexts = ok1([])
; Term = term.functor(term.atom("[|]"), [HeadTerm, TailTerm], _) ->
parse_try_component(VarSet, Term, HeadTerm,
MaybeHeadComponentContext),
parse_try_params(VarSet, Context, TailTerm,
MaybeTailComponentsContexts),
(
MaybeHeadComponentContext = ok1(HeadComponentContext),
MaybeTailComponentsContexts = ok1(TailComponentsContexts)
->
MaybeComponentsContexts =
ok1([HeadComponentContext | TailComponentsContexts])
;
HeadSpecs = get_any_errors1(MaybeHeadComponentContext),
TailSpecs = get_any_errors1(MaybeTailComponentsContexts),
MaybeComponentsContexts = error1(HeadSpecs ++ TailSpecs)
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid try goal parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]),
MaybeComponentsContexts = error1([Spec])
).
:- pred parse_try_component(varset::in, term::in, term::in,
maybe1(pair(try_component, term.context))::out) is det.
parse_try_component(VarSet, _ErrorTerm, Term, MaybeComponentContext) :-
(
Term = term.functor(Functor, SubTerms, Context),
Functor = term.atom(Atom)
->
( Atom = "io" ->
( SubTerms = [SubTerm] ->
(
SubTerm = term.functor(term.atom("!"),
[term.variable(Var, _)], _)
->
term.coerce_var(Var, ProgVar),
Component = try_component_maybe_io(ProgVar),
MaybeComponentContext = ok1(Component - Context)
;
Pieces = [words("Error: the argument of"), fixed(Atom),
words("should be a state variable."), nl],
Spec = error_spec(severity_error,
phase_term_to_parse_tree,
[simple_msg(get_term_context(SubTerm),
[always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Pieces = [words("Error:"), fixed(Atom),
words("takes exactly one argument,"),
words("which should be a state variable name."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid try goal parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
TermStr = describe_error_term(VarSet, Term),
Pieces = [words("Error: invalid try goal parameter"),
quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
).
:- pred convert_try_params(assoc_list(try_component, term.context)::in,
maybe1(maybe(prog_var))::out) is det.
convert_try_params(Components, MaybeParams) :-
convert_try_params_2(Components, no, [], MaybeParams).
:- pred convert_try_params_2(assoc_list(try_component, term.context)::in,
maybe(prog_var)::in, list(error_spec)::in,
maybe1(maybe(prog_var))::out) is det.
convert_try_params_2([], MaybeIO, Specs, MaybeParams) :-
(
Specs = [],
MaybeParams = ok1(MaybeIO)
;
Specs = [_ | _],
MaybeParams = error1(Specs)
).
convert_try_params_2([Component - Context | ComponentsContexts],
!.MaybeIO, !.Specs, MaybeParams) :-
Component = try_component_maybe_io(IOStateVar),
(
!.MaybeIO = no,
!:MaybeIO = yes(IOStateVar)
;
!.MaybeIO = yes(_),
Pieces = [words("Duplicate io try parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
!:Specs = [Spec | !.Specs]
),
convert_try_params_2(ComponentsContexts, !.MaybeIO, !.Specs, MaybeParams).
%-----------------------------------------------------------------------------%
:- type atomic_component
---> atomic_component_inner(atomic_component_state)
; atomic_component_outer(atomic_component_state)
; atomic_component_vars(list(prog_var)).
:- pred parse_atomic_params(context::in, term::in, varset::in,
maybe1(assoc_list(atomic_component, term.context))::out) is det.
parse_atomic_params(Context, Term, VarSet, MaybeComponentsContexts) :-
( Term = term.functor(term.atom("[]"), [], _) ->
MaybeComponentsContexts = ok1([])
; Term = term.functor(term.atom("[|]"), [HeadTerm, TailTerm], _) ->
parse_atomic_component(Term, HeadTerm, VarSet, MaybeHeadComponent),
parse_atomic_params(Context, TailTerm, VarSet,
MaybeTailComponentsContexts),
(
MaybeHeadComponent = ok1(HeadComponent),
MaybeTailComponentsContexts = ok1(TailComponentsContexts)
->
MaybeComponentsContexts =
ok1([HeadComponent | TailComponentsContexts])
;
HeadSpecs = get_any_errors1(MaybeHeadComponent),
TailSpecs = get_any_errors1(MaybeTailComponentsContexts),
MaybeComponentsContexts = error1(HeadSpecs ++ TailSpecs)
)
;
(
Term = term.functor(_, _, TermContext),
Pieces = [words("Invalid atomic goal parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeComponentsContexts = error1([Spec])
;
Term = term.variable(_, TermContext),
Pieces = [words("Expected atomic goal parameter, found variable."),
nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeComponentsContexts = error1([Spec])
)
).
:- pred parse_atomic_subterm(string::in, term::in, term::in,
maybe1(atomic_component_state)::out) is det.
parse_atomic_subterm(Name, ErrorTerm, Term, MaybeComponentState) :-
(
Term = term.functor(_, SubTerms, TermContext),
( parse_atomic_component_state_or_pair(SubTerms, ComponentState) ->
MaybeComponentState = ok1(ComponentState)
;
Pieces = [words("Error:"), words(Name),
words("takes exactly one argument,"),
words("which should be a state variable"),
words("or a pair of variables."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(TermContext, [always(Pieces)])]),
MaybeComponentState = error1([Spec])
)
;
Term = term.variable(_, _TermContext),
Pieces = [words("Error: expected atomic goal parameter,"),
words("found variable."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(ErrorTerm), [always(Pieces)])]),
MaybeComponentState = error1([Spec])
).
:- pred parse_atomic_component(term::in, term::in, varset::in,
maybe1(pair(atomic_component, term.context))::out) is det.
parse_atomic_component(ErrorTerm, Term, VarSet, MaybeComponentContext) :-
(
Term = term.functor(Functor, SubTerms, Context),
( Functor = term.atom(Atom) ->
% XXX Make parse_atomic_subterm do the postprocessing done here.
( Atom = "outer" ->
parse_atomic_subterm(Atom, ErrorTerm, Term,
MaybeComponentSubTerm),
(
MaybeComponentSubTerm = ok1(CompTerm),
Component = atomic_component_outer(CompTerm),
MaybeComponentContext = ok1(Component - Context)
;
MaybeComponentSubTerm = error1(Specs),
MaybeComponentContext = error1(Specs)
)
; Atom = "inner" ->
parse_atomic_subterm(Atom, ErrorTerm, Term,
MaybeComponentSubTerm),
(
MaybeComponentSubTerm = ok1(CompTerm),
Component = atomic_component_inner(CompTerm),
MaybeComponentContext = ok1(Component - Context)
;
MaybeComponentSubTerm = error1(Specs),
MaybeComponentContext = error1(Specs)
)
; Atom = "vars" ->
( SubTerms = [SubTerm] ->
ContextPieces = [words("In"), quote("vars"),
words("specifier of atomic scope:")],
parse_vars(SubTerm, VarSet, ContextPieces, MaybeVars),
(
MaybeVars = ok1(Vars),
list.map(term.coerce_var, Vars, ProgVars),
Component = atomic_component_vars(ProgVars),
MaybeComponentContext = ok1(Component - Context)
;
MaybeVars = error1(Specs),
MaybeComponentContext = error1(Specs)
)
;
Pieces = [words(Atom), words("takes exact one argument,"),
words("which should be a list of variable names."),
nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Pieces = [words("Invalid atomic goal parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Pieces = [words("Invalid atomic goal parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
)
;
Term = term.variable(_, _Context),
Pieces = [words("Expected atomic goal parameter, found variable."),
nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(ErrorTerm), [always(Pieces)])]),
MaybeComponentContext = error1([Spec])
).
:- pred parse_atomic_component_state_or_pair(list(term)::in,
atomic_component_state::out) is semidet.
parse_atomic_component_state_or_pair(SubTerms, State) :-
(
SubTerms = [Term],
Term = term.functor(term.atom("!"), [term.variable(Var, _)], _)
->
term.coerce_var(Var, ProgVar),
State = atomic_state_var(ProgVar)
;
SubTerms = [TermA, TermB],
TermA = term.variable(VarA, _),
TermB = term.variable(VarB, _)
->
term.coerce_var(VarA, ProgVarA),
term.coerce_var(VarB, ProgVarB),
State = atomic_var_pair(ProgVarA, ProgVarB)
;
fail
).
% XXX reorder the predicates above
:- pred convert_atomic_params(term::in,
assoc_list(atomic_component, term.context)::in,
maybe3(atomic_component_state, atomic_component_state,
maybe(list(prog_var)))::out) is det.
convert_atomic_params(ErrorTerm, ComponentsContexts, MaybeParams) :-
convert_atomic_params_2(get_term_context(ErrorTerm), ComponentsContexts,
no, no, no, [], MaybeParams).
:- pred convert_atomic_params_2(term.context::in,
assoc_list(atomic_component, term.context)::in,
maybe(atomic_component_state)::in,
maybe(atomic_component_state)::in,
maybe(list(prog_var))::in, list(error_spec)::in,
maybe3(atomic_component_state, atomic_component_state,
maybe(list(prog_var)))::out) is det.
convert_atomic_params_2(Context, [], MaybeOuter, MaybeInner, MaybeVars,
Specs, MaybeParams) :-
(
Specs = [],
(
MaybeOuter = yes(Outer),
MaybeInner = yes(Inner),
MaybeParams = ok3(Outer, Inner, MaybeVars)
;
MaybeOuter = yes(_),
MaybeInner = no,
Pieces = [words("Atomic goal is missing"),
words("a specification of the inner STM state."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeParams = error3([Spec])
;
MaybeOuter = no,
MaybeInner = yes(_),
Pieces = [words("Atomic goal is missing"),
words("a specification of the outer STM state."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeParams = error3([Spec])
;
MaybeOuter = no,
MaybeInner = no,
Pieces = [words("Atomic goal is missing"),
words("a specification of both"),
words("the outer and inner STM states."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeParams = error3([Spec])
)
;
Specs = [_ | _],
MaybeParams = error3(Specs)
).
convert_atomic_params_2(Context,
[Component - CompContext | ComponentsContexts],
!.MaybeOuter, !.MaybeInner, !.MaybeVars, !.Specs, MaybeParams) :-
(
Component = atomic_component_outer(Outer),
(
!.MaybeOuter = no,
!:MaybeOuter = yes(Outer)
;
!.MaybeOuter = yes(_),
% XXX We should specify the duplicate parameter.
Pieces = [words("Duplicate outer atomic parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(CompContext, [always(Pieces)])]),
!:Specs = !.Specs ++ [Spec]
)
;
Component = atomic_component_inner(Inner),
(
!.MaybeInner = no,
!:MaybeInner = yes(Inner)
;
!.MaybeInner = yes(_),
% XXX We should specify the duplicate parameter.
Pieces = [words("Duplicate inner atomic parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(CompContext, [always(Pieces)])]),
!:Specs = !.Specs ++ [Spec]
)
;
Component = atomic_component_vars(Vars),
(
!.MaybeVars = no,
!:MaybeVars = yes(Vars)
;
!.MaybeVars = yes(_),
% XXX We should specify the duplicate parameter.
Pieces = [words("Duplicate atomic vars parameter."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(CompContext, [always(Pieces)])]),
!:Specs = !.Specs ++ [Spec]
)
),
convert_atomic_params_2(Context, ComponentsContexts,
!.MaybeOuter, !.MaybeInner, !.MaybeVars, !.Specs, MaybeParams).
:- pred parse_atomic_subexpr(term::in, maybe2(goal, goals)::out,
prog_varset::in, prog_varset::out) is det.
parse_atomic_subexpr(Term, MaybeSubExpr, !VarSet) :-
parse_atomic_subgoals_as_list(Term, MaybeGoalList, !VarSet),
(
MaybeGoalList = ok1(GoalList),
(
GoalList = [],
Pieces = [words("Error: atomic scope must have a goal."), nl],
Context = get_term_context(Term),
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(Context, [always(Pieces)])]),
MaybeSubExpr = error2([Spec])
;
GoalList = [MainSubGoalExpr | OrElseAlternativeSubExpr],
MaybeSubExpr = ok2(MainSubGoalExpr, OrElseAlternativeSubExpr)
)
;
MaybeGoalList = error1(Specs),
MaybeSubExpr = error2(Specs)
).
:- pred parse_atomic_subgoals_as_list(term::in, maybe1(list(goal))::out,
prog_varset::in, prog_varset::out) is det.
parse_atomic_subgoals_as_list(Term, MaybeGoals, !VarSet) :-
(
Term = term.functor(term.atom("or_else"), [LeftGoal, RightGoal], _)
->
parse_atomic_subgoals_as_list(LeftGoal, MaybeLeftGoalList, !VarSet),
parse_atomic_subgoals_as_list(RightGoal, MaybeRightGoalList, !VarSet),
(
MaybeLeftGoalList = ok1(LeftGoalList),
MaybeRightGoalList = ok1(RightGoalList)
->
MaybeGoals = ok1(LeftGoalList ++ RightGoalList)
;
LeftSpecs = get_any_errors1(MaybeLeftGoalList),
RightSpecs = get_any_errors1(MaybeRightGoalList),
MaybeGoals = error1(LeftSpecs ++ RightSpecs)
)
;
% XXX Provide better ContextPieces.
ContextPieces = [],
parse_goal(Term, ContextPieces, MaybeSubGoal, !VarSet),
(
MaybeSubGoal = ok1(SubGoal),
MaybeGoals = ok1([SubGoal])
;
MaybeSubGoal = error1(Specs),
MaybeGoals = error1(Specs)
)
).
%-----------------------------------------------------------------------------%
:- pred parse_lambda_arg(term::in, prog_term::out, mer_mode::out) is semidet.
parse_lambda_arg(Term, ArgTerm, Mode) :-
Term = term.functor(term.atom("::"), [ArgTerm0, ModeTerm], _),
term.coerce(ArgTerm0, ArgTerm),
convert_mode(allow_constrained_inst_var, ModeTerm, Mode0),
constrain_inst_vars_in_mode(Mode0, Mode).
%-----------------------------------------------------------------------------%
%
% Code for parsing pred/func expressions
%
parse_pred_expression(PredTerm, Groundness, lambda_normal, Args, Modes, Det) :-
PredTerm = term.functor(term.atom("is"), [PredArgsTerm, DetTerm], _),
DetTerm = term.functor(term.atom(DetString), [], _),
standard_det(DetString, Det),
PredArgsTerm = term.functor(term.atom(Name), PredArgsList, _),
(
Name = "pred",
Groundness = ho_ground
;
Name = "any_pred",
Groundness = ho_any
),
parse_pred_expr_args(PredArgsList, Args, Modes),
inst_var_constraints_are_self_consistent_in_modes(Modes).
parse_dcg_pred_expression(PredTerm, Groundness, lambda_normal, Args, Modes,
Det) :-
PredTerm = term.functor(term.atom("is"), [PredArgsTerm, DetTerm], _),
DetTerm = term.functor(term.atom(DetString), [], _),
standard_det(DetString, Det),
PredArgsTerm = term.functor(term.atom(Name), PredArgsList, _),
(
Name = "pred",
Groundness = ho_ground
;
Name = "any_pred",
Groundness = ho_any
),
parse_dcg_pred_expr_args(PredArgsList, Args, Modes),
inst_var_constraints_are_self_consistent_in_modes(Modes).
parse_func_expression(FuncTerm, Groundness, lambda_normal, Args, Modes, Det) :-
% Parse a func expression with specified modes and determinism.
FuncTerm = term.functor(term.atom("is"), [EqTerm, DetTerm], _),
EqTerm = term.functor(term.atom("="), [FuncArgsTerm, RetTerm], _),
DetTerm = term.functor(term.atom(DetString), [], _),
standard_det(DetString, Det),
FuncArgsTerm = term.functor(term.atom(Name), FuncArgsList, _),
(
Name = "func",
Groundness = ho_ground
;
Name = "any_func",
Groundness = ho_any
),
( parse_pred_expr_args(FuncArgsList, Args0, Modes0) ->
parse_lambda_arg(RetTerm, RetArg, RetMode),
list.append(Args0, [RetArg], Args),
list.append(Modes0, [RetMode], Modes),
inst_var_constraints_are_self_consistent_in_modes(Modes)
;
% The argument modes default to `in',
% the return mode defaults to `out'.
in_mode(InMode),
out_mode(OutMode),
list.length(FuncArgsList, NumArgs),
list.duplicate(NumArgs, InMode, Modes0),
RetMode = OutMode,
list.append(Modes0, [RetMode], Modes),
list.append(FuncArgsList, [RetTerm], Args1),
list.map(term.coerce, Args1, Args)
).
parse_func_expression(FuncTerm, Groundness, lambda_normal, Args, Modes, Det) :-
% Parse a func expression with unspecified modes and determinism.
FuncTerm = term.functor(term.atom("="), [FuncArgsTerm, RetTerm], _),
FuncArgsTerm = term.functor(term.atom(Name), Args0, _),
(
Name = "func",
Groundness = ho_ground
;
Name = "any_func",
Groundness = ho_any
),
% The argument modes default to `in', the return mode defaults to `out',
% and the determinism defaults to `det'.
in_mode(InMode),
out_mode(OutMode),
list.length(Args0, NumArgs),
list.duplicate(NumArgs, InMode, Modes0),
RetMode = OutMode,
Det = detism_det,
list.append(Modes0, [RetMode], Modes),
inst_var_constraints_are_self_consistent_in_modes(Modes),
list.append(Args0, [RetTerm], Args1),
list.map(term.coerce, Args1, Args).
:- pred parse_pred_expr_args(list(term)::in, list(prog_term)::out,
list(mer_mode)::out) is semidet.
parse_pred_expr_args([], [], []).
parse_pred_expr_args([Term | Terms], [Arg | Args], [Mode | Modes]) :-
parse_lambda_arg(Term, Arg, Mode),
parse_pred_expr_args(Terms, Args, Modes).
% parse_dcg_pred_expr_args is like parse_pred_expr_args except
% that the last two elements of the list are the modes of the
% two DCG arguments.
%
:- pred parse_dcg_pred_expr_args(list(term)::in, list(prog_term)::out,
list(mer_mode)::out) is semidet.
parse_dcg_pred_expr_args([DCGModeTermA, DCGModeTermB], [],
[DCGModeA, DCGModeB]) :-
convert_mode(allow_constrained_inst_var, DCGModeTermA, DCGModeA0),
convert_mode(allow_constrained_inst_var, DCGModeTermB, DCGModeB0),
constrain_inst_vars_in_mode(DCGModeA0, DCGModeA),
constrain_inst_vars_in_mode(DCGModeB0, DCGModeB).
parse_dcg_pred_expr_args([Term | Terms], [Arg | Args], [Mode | Modes]) :-
Terms = [_, _ | _],
parse_lambda_arg(Term, Arg, Mode),
parse_dcg_pred_expr_args(Terms, Args, Modes).
%-----------------------------------------------------------------------------%
:- end_module parse_tree.prog_io_goal.
%-----------------------------------------------------------------------------%