[m-rev.] for review: adding promise ex declarations to the hlds with error checking
Lars Yencken
lljy at students.cs.mu.oz.au
Wed Feb 20 10:47:41 AEDT 2002
Ok, here's the proper relative diff, fixing also the missing '('.
Lars
================================================================
diff -u error_util.m error_util.m
--- error_util.m
+++ error_util.m
@@ -418,7 +418,7 @@
(
pred_info_get_goal_type(PredInfo, promise(PromiseType))
->
- Piece = promise_to_string(PromiseType)
+ Piece = "`" ++ promise_to_string(PromiseType) ++ "' declaration"
;
string__int_to_string(OrigArity, ArityPart),
string__append_list([
diff -u goal_util.m goal_util.m
--- goal_util.m
+++ goal_util.m
@@ -149,9 +149,11 @@
:- pred direct_subgoal(hlds_goal_expr, hlds_goal).
:- mode direct_subgoal(in, out) is nondet.
+ % returns all the predids that are used within a goal
:- pred predids_from_goal(hlds_goal, list(pred_id)).
:- mode predids_from_goal(in, out) is det.
-
+
+ % returns all the predids that are used in a list of goals
:- pred predids_from_goals(list(hlds_goal), list(pred_id)).
:- mode predids_from_goals(in, out) is det.
@@ -1297,10 +1299,10 @@
Goals = [],
PredIds = []
;
- Goals = [Goal|Rest],
+ Goals = [Goal | Rest],
predids_from_goal(Goal, PredIds0),
predids_from_goals(Rest, PredIds1),
- append(PredIds0, PredIds1, PredIds)
+ PredIds = PredIds0 ++ PredIds1
).
predids_from_goal(Goal, PredIds) :-
diff -u hlds_data.m hlds_data.m
--- hlds_data.m
+++ hlds_data.m
@@ -1041,12 +1041,9 @@
:- interface.
-:- type exclusive_id == pred_id.
-:- type exclusive_ids == list(pred_id).
-
%
- % A table recording all promse_ex declarations (i.e. promise_exclusive,
- % promise_exhaustive and promise_exclusive_exhaustive).
+ % A table recording exclusivity declarations (i.e. promise_exclusive
+ % and promise_exclusive_exhaustive).
%
% e.g. :- all [X]
% promise_exclusive
@@ -1057,22 +1054,38 @@
% ).
%
% promises that only one of p(X, Y) and q(X) can succeed at a time,
- % although whichever one succeeds may have multiple solutions.
-
+ % although whichever one succeeds may have multiple solutions. See
+ % notes/promise_ex.html for details of the declarations.
+ %
+
+ % an exclusive_id is the pred_id of an exclusivity declaration,
+ % and is useful in distinguishing between the arguments of the
+ % operations below on the exclusive_table
+:- type exclusive_id == pred_id.
+:- type exclusive_ids == list(pred_id).
+
:- type exclusive_table.
+ % initialise the exclusive_table
:- pred exclusive_table_init(exclusive_table).
:- mode exclusive_table_init(out) is det.
+ % search the exclusive table and return the list of exclusivity
+ % declarations that use the predicate given by pred_id
:- pred exclusive_table_search(exclusive_table, pred_id, exclusive_ids).
:- mode exclusive_table_search(in, in, out) is semidet.
+ % as for search, but aborts if no exclusivity declarations are
+ % found
:- pred exclusive_table_lookup(exclusive_table, pred_id, exclusive_ids).
:- mode exclusive_table_lookup(in, in, out) is det.
+ % optimises the exclusive_table
:- pred exclusive_table_optimize(exclusive_table, exclusive_table).
:- mode exclusive_table_optimize(in, out) is det.
+ % add to the exclusive table that pred_id is used in the
+ % exclusivity declaration exclusive_id
:- pred exclusive_table_add(pred_id, exclusive_id, exclusive_table,
exclusive_table).
:- mode exclusive_table_add(in, in, in, out) is det.
@@ -1081,27 +1094,30 @@
:- implementation.
-:- type exclusive_table == map(pred_id, exclusive_ids).
+:- import_module multi_map.
+
+:- type exclusive_table == multi_map(pred_id, exclusive_id).
-exclusive_table_init(map__init).
+exclusive_table_init(ExclusiveTable) :-
+ multi_map__init(ExclusiveTable).
exclusive_table_lookup(ExclusiveTable, PredId, ExclusiveIds) :-
- map__lookup(ExclusiveTable, PredId, ExclusiveIds).
+ multi_map__lookup(ExclusiveTable, PredId, ExclusiveIds).
exclusive_table_search(ExclusiveTable, Id, ExclusiveIds) :-
- map__search(ExclusiveTable, Id, ExclusiveIds).
+ multi_map__search(ExclusiveTable, Id, ExclusiveIds).
exclusive_table_optimize(ExclusiveTable0, ExclusiveTable) :-
- map__optimize(ExclusiveTable0, ExclusiveTable).
+ multi_map__optimize(ExclusiveTable0, ExclusiveTable).
exclusive_table_add(ExclusiveId, PredId, ExclusiveTable0, ExclusiveTable) :-
(
- map__search(ExclusiveTable0, PredId, ExclusiveIds)
+ multi_map__contains(ExclusiveTable0, PredId)
->
- map__det_update(ExclusiveTable0, PredId,
- [ExclusiveId|ExclusiveIds], ExclusiveTable)
+ multi_map__det_update(ExclusiveTable0, PredId, ExclusiveId,
+ ExclusiveTable)
;
- map__det_insert(ExclusiveTable0, PredId, [ExclusiveId],
+ multi_map__det_insert(ExclusiveTable0, PredId, ExclusiveId,
ExclusiveTable)
).
diff -u hlds_out.m hlds_out.m
--- hlds_out.m
+++ hlds_out.m
@@ -370,7 +370,8 @@
;
{ pred_info_get_goal_type(PredInfo, promise(PromiseType)) }
->
- io__write_string(prog_out__promise_to_string(PromiseType))
+ io__write_string("`" ++ prog_out__promise_to_string(PromiseType)
+ ++ "' declaration")
;
hlds_out__write_simple_call_id(PredOrFunc,
qualified(Module, Name), Arity)
@@ -415,8 +416,9 @@
(
{ Promise = promise(PromiseType) }
->
+ io__write_string("`"),
prog_out__write_promise_type(PromiseType),
- io__write_string(" declaration")
+ io__write_string("' declaration")
;
hlds_out__write_pred_or_func(PredOrFunc),
io__write_string(" `"),
@@ -955,16 +957,17 @@
% print initial formatting differently for assertions
( { PromiseType = true } ->
- io__write_string(":- promise all["),
+ io__write_string(":- promise all ["),
io__write_list(HeadVars, ", ", PrintVar),
io__write_string("] (\n")
;
- io__write_string(":- all["),
+ io__write_string(":- all ["),
io__write_list(HeadVars, ", ", PrintVar),
io__write_string("]"),
mercury_output_newline(Indent),
prog_out__write_promise_type(PromiseType),
- io__nl
+ mercury_output_newline(Indent),
+ io__write_string("(\n")
),
{ Clause = clause(_Modes, Goal, _Lang, _Context) },
diff -u make_hlds.m make_hlds.m
--- make_hlds.m
+++ make_hlds.m
@@ -802,19 +802,23 @@
add_item_clause(promise(PromiseType, Goal, VarSet, UnivVars),
Status, Status, Context, Module0, Module, Info0, Info) -->
- %
- % If the outermost existentially quantified variables
- % are placed in the head of the assertion, the
- % typechecker will avoid warning about unbound
- % type variables as this implicity adds a universal
- % quantification of the typevariables needed.
- %
+ %
+ % If the outermost universally quantified variables
+ % are placed in the head of the dummy predicate, the
+ % typechecker will avoid warning about unbound
+ % type variables as this implicity adds a universal
+ % quantification of the typevariables needed.
+ %
{ term__var_list_to_term_list(UnivVars, HeadVars) },
- ( { \+ PromiseType = true } ->
+
+ % extra error checking for promise ex declarations
+ ( { PromiseType \= true } ->
check_promise_ex_decl(UnivVars, PromiseType, Goal, Context)
;
[]
),
+
+ % add as dummy predicate
add_promise_clause(PromiseType, HeadVars, VarSet, Goal, Context, Status,
Module0, Module, Info0, Info).
@@ -8424,22 +8428,19 @@
%-----------------------------------------------------------------------------%
%
-% XXX promise_ex declarations
-%
+% promise ex error checking
%
+% The following predicates are used to perform extra error checking specific
+% to promise ex declarations (see notes/promise_ex.html). Currently, the
+% following checks are performed:
+% * check for universally quantified variables
+% * check if universal quantification is placed in the wrong
+% position (i.e. after the `promise_exclusive' rather than
+% before it)
+% * check that its goal is a disjunction and that each arm of the
+% disjunction has at most one call, and otherwise has only unifications
-:- type promise_ex_goal
- ---> ok(goals)
- ; error(string, prog_context).
-
- % Perform error checking for a promise ex declaration.
- % The following checks are done:
- % * check for universally quantified variables
- % * check if universal quantification is placed in the wrong
- % position (i.e. after the `promise_exclusive' rather than
- % before it)
- % * check that each arm of the disjunction has at most one call,
- % but otherwise has only unifications
+ % perform above checks on a promise ex declaration
:- pred check_promise_ex_decl(prog_vars, promise_type, goal, prog_context,
io__state, io__state).
:- mode check_promise_ex_decl(in, in, in, in, di, uo) is det.
@@ -8449,12 +8450,13 @@
{ UnivVars = [] },
promise_ex_error(PromiseType, Context, "declaration has no universally quantified variables")
;
- { UnivVars = [_|_] }
+ { UnivVars = [_ | _] }
),
check_promise_ex_goal(PromiseType, Goal).
-
- % strip off any existential quantification, then
+ % check for misplaced universal quantification, otherwise find the
+ % disjunction, flatten it out into list form and perform further
+ % checks
:- pred check_promise_ex_goal(promise_type, goal, io__state, io__state).
:- mode check_promise_ex_goal(in, in, di, uo) is det.
check_promise_ex_goal(PromiseType, GoalExpr - Context) -->
@@ -8462,8 +8464,8 @@
check_promise_ex_goal(PromiseType, Goal)
; { GoalExpr = ( _ ; _ ) } ->
{ flatten_to_disj_list(GoalExpr - Context, DisjList) },
- { list__map(flatten_to_cons_list, DisjList, DisjConsList) },
- check_list_cons_list(PromiseType, DisjConsList)
+ { list__map(flatten_to_conj_list, DisjList, DisjConsList) },
+ check_disjunction(PromiseType, DisjConsList)
; { GoalExpr = all(_UnivVars, Goal) } ->
promise_ex_error(PromiseType, Context, "universal quantification should come before the declaration name"),
check_promise_ex_goal(PromiseType, Goal)
@@ -8471,67 +8473,58 @@
promise_ex_error(PromiseType, Context, "goal in declaration is not a disjunction")
).
-
+ % turns the goal of a promise ex declaration into a list of goals,
+ % where each goal is an arm of the disjunction
:- pred flatten_to_disj_list(goal, goals).
:- mode flatten_to_disj_list(in, out) is det.
flatten_to_disj_list(GoalExpr - Context, GoalList) :-
( GoalExpr = ( GoalA ; GoalB ) ->
flatten_to_disj_list(GoalA, GoalListA),
flatten_to_disj_list(GoalB, GoalListB),
- append(GoalListA, GoalListB, GoalList)
+ GoalList = GoalListA ++ GoalListB
;
GoalList = [GoalExpr - Context]
).
-:- pred flatten_to_cons_list(goal, goals).
-:- mode flatten_to_cons_list(in, out) is det.
-flatten_to_cons_list(GoalExpr - Context, GoalList) :-
+ % takes a goal representing an arm of a disjunction and turn it into
+ % a list of conjunct goals
+:- pred flatten_to_conj_list(goal, goals).
+:- mode flatten_to_conj_list(in, out) is det.
+flatten_to_conj_list(GoalExpr - Context, GoalList) :-
( GoalExpr = ( GoalA , GoalB ) ->
- flatten_to_cons_list(GoalA, GoalListA),
- flatten_to_cons_list(GoalB, GoalListB),
- append(GoalListA, GoalListB, GoalList)
+ flatten_to_conj_list(GoalA, GoalListA),
+ flatten_to_conj_list(GoalB, GoalListB),
+ GoalList = GoalListA ++ GoalListB
;
GoalList = [GoalExpr - Context]
).
-:- pred check_list_cons_list(promise_type, list(goals), io__state, io__state).
-:- mode check_list_cons_list(in, in, di, uo) is det.
-check_list_cons_list(PromiseType, DisjConsList) -->
+ % taking a list of arms of the disjunction, check each arm
+ % individually
+:- pred check_disjunction(promise_type, list(goals), io__state, io__state).
+:- mode check_disjunction(in, in, di, uo) is det.
+check_disjunction(PromiseType, DisjConsList) -->
(
{ DisjConsList = [] }
;
- { DisjConsList = [ConsList|Rest] },
- check_cons_list(PromiseType, ConsList, no),
- check_list_cons_list(PromiseType, Rest)
+ { DisjConsList = [ConsList | Rest] },
+ check_disj_arm(PromiseType, ConsList, no),
+ check_disjunction(PromiseType, Rest)
).
-:- pred check_disj_goals(promise_type, list(goals), io__state, io__state).
-:- mode check_disj_goals(in, in, di, uo) is det.
-check_disj_goals(PromiseType, GoalList0) -->
- (
- { GoalList0 = [] }
- ;
- { GoalList0 = [Goal0|GoalList] },
- check_cons_list(PromiseType, Goal0, no),
- check_disj_goals(PromiseType, GoalList)
- ).
-
-
- % check a cons list of goals in a disj, ensuring that they are all
- % either unifications or calls
- % only one call is allowed per cons list, as each cons list represents
- % one arm of the disjunction
-:- pred check_cons_list(promise_type, goals, bool, io__state, io__state).
-:- mode check_cons_list(in, in, in, di, uo) is det.
-check_cons_list(PromiseType, Goals, CallUsed) -->
+ % only one goal in an arm is allowed to be a call, the rest must be
+ % unifications
+:- pred check_disj_arm(promise_type, goals, bool, io__state, io__state).
+:- mode check_disj_arm(in, in, in, di, uo) is det.
+check_disj_arm(PromiseType, Goals, CallUsed) -->
(
{ Goals = [] }
;
- { Goals = [GoalExpr - Context|Rest] },
+ { Goals = [GoalExpr - Context | Rest] },
( { GoalExpr = unify(_, _, _) } ->
- check_cons_list(PromiseType, Rest, CallUsed)
+ check_disj_arm(PromiseType, Rest, CallUsed)
; { GoalExpr = some(_, Goal) } ->
- check_cons_list(PromiseType, [Goal|Rest], CallUsed)
+ check_disj_arm(PromiseType, [Goal | Rest], CallUsed)
; { GoalExpr = call(_, _, _) } ->
(
{ CallUsed = no }
@@ -8539,26 +8532,26 @@
{ CallUsed = yes },
promise_ex_error(PromiseType, Context, "disjunct contains more than one call")
),
- check_cons_list(PromiseType, Rest, yes)
+ check_disj_arm(PromiseType, Rest, yes)
;
promise_ex_error(PromiseType, Context, "disjunct is not a call or unification"),
- check_cons_list(PromiseType, Rest, CallUsed)
+ check_disj_arm(PromiseType, Rest, CallUsed)
)
).
- % called for any promise_ex_error
+ % called for any error in the above checks
:- pred promise_ex_error(promise_type, prog_context, string,
io__state, io__state).
:- mode promise_ex_error(in, in, in, di, uo) is det.
promise_ex_error(PromiseType, Context, Message) -->
- io__set_exit_status(1),
- prog_out__write_context(Context),
- io__write_string("In " ++
- prog_out__promise_to_string(PromiseType) ++ " declaration:\n"),
- prog_out__write_context(Context),
- io__write_string(" error: "),
- io__write_string(Message),
- io__nl.
+ { ErrorPieces = [
+ words("In"),
+ fixed("`" ++ prog_out__promise_to_string(PromiseType) ++ "' declaration:"),
+ nl,
+ words("error:"),
+ words(Message)
+ ] },
+ error_util__write_error_pieces(Context, 0, ErrorPieces).
%------------------------------------------------------------------------------%
diff -u post_typecheck.m post_typecheck.m
--- post_typecheck.m
+++ post_typecheck.m
@@ -728,9 +728,10 @@
hlds_goal).
:- mode store_promise(in, in, in, out, out) is det.
store_promise(PromiseType, Module0, PromiseId, Module, Goal) :-
- (
- % case for assertions
- PromiseType = true,
+ (
+ % case for assertions
+ PromiseType = true
+ ->
module_info_assertion_table(Module0, AssertTable0),
assertion_table_add_assertion(PromiseId, AssertTable0,
AssertionId, AssertTable),
@@ -740,30 +741,27 @@
assertion__record_preds_used_in(Goal, AssertionId, Module1,
Module)
;
- % case for exclusivity
- PromiseType = exclusive,
- promise_ex_goal(PromiseId, Module0, Goal),
- predids_from_goal(Goal, PredIds),
- module_info_exclusive_table(Module0, Table0),
- list__foldl(exclusive_table_add(PromiseId), PredIds, Table0,
- Table),
- module_info_set_exclusive_table(Module0, Table, Module)
- ;
- % case for exclusivity
- PromiseType = exclusive_exhaustive,
+ % case for exclusivity
+ (
+ PromiseType = exclusive
+ ;
+ PromiseType = exclusive_exhaustive
+ )
+ ->
promise_ex_goal(PromiseId, Module0, Goal),
predids_from_goal(Goal, PredIds),
module_info_exclusive_table(Module0, Table0),
list__foldl(exclusive_table_add(PromiseId), PredIds, Table0,
Table),
module_info_set_exclusive_table(Module0, Table, Module)
+
;
- % case for exhaustiveness -- not yet implemented
- PromiseType = exhaustive,
+ % case for exhaustiveness -- XXX not yet implemented
promise_ex_goal(PromiseId, Module0, Goal),
Module0 = Module
).
+ % get the goal from a promise_ex declaration
:- pred promise_ex_goal(pred_id, module_info, hlds_goal).
:- mode promise_ex_goal(in, in, out) is det.
promise_ex_goal(ExclusiveDecl, Module, Goal) :-
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list