3 //============================================================================
7 // Inference for common conflicts.
9 //============================================================================
10 //####COPYRIGHTBEGIN####
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
15 // This file is part of the eCos host tools.
17 // This program is free software; you can redistribute it and/or modify it
18 // under the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 of the License, or (at your option)
22 // This program is distributed in the hope that it will be useful, but WITHOUT
23 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
27 // You should have received a copy of the GNU General Public License along with
28 // this program; if not, write to the Free Software Foundation, Inc.,
29 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 // ----------------------------------------------------------------------------
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
42 //####DESCRIPTIONEND####
43 //============================================================================
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
51 // Get the infrastructure types, assertions, tracing and similar
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
56 // <cdlcore.hxx> defines everything implemented in this module.
57 // It implicitly supplies <string>, <vector> and <map> because
58 // the class definitions rely on these headers.
59 #include <cdlcore.hxx>
67 // ----------------------------------------------------------------------------
68 // The following functions provide the main entry points for inference.
70 // 1) bool CdlInfer::make_active(CdlTransaction, CdlValuable, level)
71 // Do whatever it takes to make the valuable active in
72 // a clean sub-transaction, if possible.
73 // 2) bool CdlInfer::make_inactive(CdlTransaction, CdlValuable, level)
74 // Do whatever it takes to make the valuable inactive.
75 // 3) bool CdlInfer::set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, level)
76 // Try to set the valuable to the specified value, taking into
77 // account the different flavors.
78 // 4) bool CdlInfer::set_valuable_bool(CdlTransaction, CdlValuable, bool, level)
79 // Similar to (3) but deals with the boolean aspect of the valuable
80 // rather than the data part.
81 // 5) bool CdlInfer::subexpr(CdlTransaction, CdlExpression, int index, CdlSimpleValue& goal, level)
82 // Process a sub-expression and try to make it evaluate to the
84 // 6) bool CdlInfer::subexpr_bool(CdlTransaction, CdlExpression, int index, bool goal, level)
85 // Ditto but only deal with boolean goals. If the expression starts to
86 // involve arithmetic etc. then we need to move to CdlInfer::subexpr()
88 // As might be expected, the sub-expression handlers contain a big
89 // switch statement and calls into various auxiliary functions when
92 // For convenience the various entry points check whether or not the
93 // desired condition is already satisfied.
96 //{{{ Forward declarations
98 // ----------------------------------------------------------------------------
100 static bool infer_handle_interface_value(CdlTransaction, CdlInterface, CdlSimpleValue&, int);
101 static bool infer_handle_reference_bool(CdlTransaction, CdlValuable, bool, int);
104 //{{{ CdlInfer::make_active()
106 // ----------------------------------------------------------------------------
107 // Making a node active. This requires the following conditions to be
109 // 1) the parent must be made active
110 // 2) if the parent has flavor bool or booldata, it must be enabled
111 // 3) any active_if properties
114 CdlInfer::make_active(CdlTransaction transaction, CdlNode node, int level)
116 CYG_REPORT_FUNCNAMETYPE("CdlInfer::make_active", "result %d");
117 CYG_REPORT_FUNCARG3XV(transaction, node, level);
118 CYG_PRECONDITION_CLASSC(transaction);
119 CYG_PRECONDITION_CLASSC(node);
122 if (transaction->is_active(node)) {
124 CYG_REPORT_RETVAL(result);
128 CdlContainer parent = node->get_parent();
129 CYG_ASSERT_CLASSC(parent);
130 if (!transaction->is_active(parent)) {
131 if (!CdlInfer::make_active(transaction, parent, level)) {
132 CYG_REPORT_RETVAL(result);
136 // The parent is now active. Does it have to be enabled as well?
137 CdlValuable parent_valuable = dynamic_cast<CdlValuable>(static_cast<CdlNode>(parent));
138 if (0 != parent_valuable) {
139 CdlValueFlavor flavor = parent_valuable->get_flavor();
140 if (((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) &&
141 !parent_valuable->is_enabled(transaction)) {
142 if (!CdlInfer::set_valuable_bool(transaction, parent_valuable, true, level)) {
143 CYG_REPORT_RETVAL(result);
148 // The parent is now active and enabled. Are there any active_if properties to worry about?
149 CdlValuable valuable = dynamic_cast<CdlValuable>(node);
151 std::vector<CdlProperty_GoalExpression> active_if_goals;
152 std::vector<CdlProperty_GoalExpression>::iterator goal_i;
153 valuable->get_active_if_conditions(active_if_goals);
154 for (goal_i = active_if_goals.begin(); goal_i != active_if_goals.end(); goal_i++) {
156 CdlEvalContext context(transaction, valuable, *goal_i);
158 if (!(*goal_i)->eval(context)) {
159 CdlExpression expr = (*goal_i)->get_expression();
160 if (!CdlInfer::subexpr_bool(transaction, expr, expr->first_subexpression, true, level)) {
161 CYG_REPORT_RETVAL(result);
166 CYG_REPORT_RETVAL(result);
173 result = transaction->is_active(node);
174 CYG_REPORT_RETVAL(result);
179 //{{{ CdlInfer::make_inactive()
181 // ----------------------------------------------------------------------------
182 // Making a node inactive can be done in three ways:
183 // 1) if the parent is boolean, try disabling it
184 // 2) otherwise if the parent can be made inactive, that will do
186 // 3) if there are any active_if properties, they could be considered
187 // as well. For now this possibility is ignored.
190 CdlInfer::make_inactive(CdlTransaction transaction, CdlNode node, int level)
192 CYG_REPORT_FUNCNAMETYPE("CdlInfer::make_inactive", "result %d");
193 CYG_REPORT_FUNCARG3XV(transaction, node, level);
194 CYG_PRECONDITION_CLASSC(transaction);
195 CYG_PRECONDITION_CLASSC(node);
198 if (!transaction->is_active(node)) {
200 CYG_REPORT_RETVAL(result);
204 CdlContainer parent = node->get_parent();
206 // No point in trying to disable the entire configuration.
207 CYG_REPORT_RETVAL(result);
211 CdlValuable parent_valuable = dynamic_cast<CdlValuable>(parent);
212 if (0 != parent_valuable) {
213 CdlValueFlavor flavor = parent_valuable->get_flavor();
214 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
215 // Since the current node is active the parent must currently be enabled.
216 // A sub-transaction is needed because an alternative approach is
217 // possible later on.
218 CdlTransaction subtransaction = transaction->make(transaction->get_conflict());
219 if (CdlInfer::set_valuable_bool(subtransaction, parent_valuable, false, level)) {
220 subtransaction->commit();
221 delete subtransaction;
223 CYG_REPORT_RETVAL(result);
226 subtransaction->cancel();
227 delete subtransaction;
232 // It is not possible to disable the parent. How about making it inactive?
233 if (CdlInfer::make_inactive(transaction, parent, level)) {
235 CYG_REPORT_RETVAL(result);
239 // For now do not try to mess about with active_if conditions.
241 CYG_REPORT_RETVAL(result);
246 //{{{ CdlInfer::set_valuable_value()
248 // ----------------------------------------------------------------------------
249 // Deal with the value part of a valuable. The valuable is known to exist
250 // and be active, so this code only deals with the actual value part.
253 CdlInfer::set_valuable_value(CdlTransaction transaction, CdlValuable valuable, CdlSimpleValue& goal, int level)
255 CYG_REPORT_FUNCNAMETYPE("CdlInfer::set_valuable_value", "result %d");
256 CYG_REPORT_FUNCARG3XV(transaction, valuable, level);
257 CYG_PRECONDITION_CLASSC(transaction);
258 CYG_PRECONDITION_CLASSC(valuable);
259 CYG_PRECONDITIONC(transaction->is_active(valuable));
263 const CdlValue& current_value = transaction->get_whole_value(valuable);
264 CdlValueFlavor flavor = current_value.get_flavor();
265 bool bool_goal = goal.get_bool_value();
269 case CdlValueFlavor_None :
272 case CdlValueFlavor_Bool :
273 if (bool_goal == current_value.is_enabled()) {
276 if (valuable->is_modifiable() &&
277 (0 == dynamic_cast<CdlLoadable>(valuable)) &&
278 !transaction->changed_by_user(valuable)) {
280 valuable->set_enabled(transaction, bool_goal, CdlValueSource_Inferred);
281 valuable->set_source(transaction, CdlValueSource_Inferred);
282 result = transaction->resolve_recursion(level);
288 case CdlValueFlavor_BoolData :
289 if (!bool_goal && !current_value.is_enabled()) {
291 } else if (bool_goal && current_value.is_enabled() && (goal == current_value.get_simple_value())) {
294 if (valuable->is_modifiable() &&
295 (0 == dynamic_cast<CdlLoadable>(valuable)) &&
296 !transaction->changed_by_user(valuable)) {
299 valuable->disable(transaction, CdlValueSource_Inferred);
301 valuable->enable_and_set_value(transaction, goal, CdlValueSource_Inferred);
303 valuable->set_source(transaction, CdlValueSource_Inferred);
304 result = transaction->resolve_recursion(level);
305 } else if (0 != dynamic_cast<CdlInterface>(valuable)) {
306 // Interfaces are not directly modifiable, but their implementors are.
307 result = infer_handle_interface_value(transaction, dynamic_cast<CdlInterface>(valuable), goal, level);
312 case CdlValueFlavor_Data:
313 // Now check whether or not the valuable already has the desired value
314 if (goal == current_value.get_simple_value()) {
317 if (valuable->is_modifiable() &&
318 (0 == dynamic_cast<CdlLoadable>(valuable)) &&
319 !transaction->changed_by_user(valuable)) {
321 // Make the change, propagate, and perform further resolution.
322 valuable->set_value(transaction, goal, CdlValueSource_Inferred);
323 valuable->set_source(transaction, CdlValueSource_Inferred);
324 result = transaction->resolve_recursion(level);
325 } else if (0 != dynamic_cast<CdlInterface>(valuable)) {
326 // Interfaces are not directly modifiable, but their implementors are.
327 result = infer_handle_interface_value(transaction, dynamic_cast<CdlInterface>(valuable), goal, level);
333 CYG_REPORT_RETVAL(result);
338 //{{{ CdlInfer::set_valuable_bool()
340 // ----------------------------------------------------------------------------
341 // Deal with the boolean part of a valuable. It is assumed that active vs.
342 // inactive is dealt with elsewhere so this code only needs to worry
343 // about the valuable itself.
346 CdlInfer::set_valuable_bool(CdlTransaction transaction, CdlValuable valuable, bool goal, int level)
348 CYG_REPORT_FUNCNAMETYPE("CdlInfer::set_valuable_bool", "result %d");
349 CYG_REPORT_FUNCARG4XV(transaction, valuable, goal, level);
350 CYG_PRECONDITION_CLASSC(transaction);
351 CYG_PRECONDITION_CLASSC(valuable);
355 // Examine the current flavor. If None or Data then the valuable
356 // is always enabled. If BoolData or Boolean then the condition
357 // may be satisfied already, otherwise an attempt must be made
358 // to change the value and see what happens.
359 CdlValueFlavor flavor = valuable->get_flavor();
360 if (CdlValueFlavor_None == flavor) {
364 CYG_REPORT_RETVAL(result);
368 if (CdlValueFlavor_Data == flavor) {
369 std::string value = valuable->get_value(transaction);
371 if (("" != value) && ("0" != value)) {
375 if (("" == value) || ("0" == value)) {
379 CYG_REPORT_RETVAL(result);
383 CYG_ASSERTC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor));
384 bool enabled = valuable->is_enabled(transaction);
385 if (enabled == goal) {
387 CYG_REPORT_RETVAL(result);
391 // enabled != goal, and we have a boolean or booldata item.
392 // Before we actually try making any changes, is this sensible?
393 if (!valuable->is_modifiable() ||
394 (0 != dynamic_cast<CdlLoadable>(valuable)) ||
395 transaction->changed_by_user(valuable)) {
397 CYG_REPORT_RETVAL(result);
400 // If we are about to disable a container, better check that this would
401 // not annoy the user either
403 CdlContainer container = dynamic_cast<CdlContainer>(valuable);
404 if ((0 != container) && transaction->subnode_changed_by_user(container)) {
405 CYG_REPORT_RETVAL(result);
410 // Try to change the state, propagate, and perform further resolution.
411 valuable->set_enabled(transaction, goal, CdlValueSource_Inferred);
412 valuable->set_source(transaction, CdlValueSource_Inferred);
413 result = transaction->resolve_recursion(level);
415 CYG_REPORT_RETVAL(result);
422 // ----------------------------------------------------------------------------
423 // Given two sub-transactions which may or may not have succeeded, pick the
424 // preferred one. This happens for many binary operators.
427 infer_lhs_preferable(CdlTransaction lhs_transaction, bool lhs_result, CdlTransaction rhs_transaction, bool rhs_result)
429 CYG_REPORT_FUNCNAMETYPE("infer_choose2", "result %d");
430 CYG_REPORT_FUNCARG4XV(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
431 CYG_PRECONDITIONC(lhs_result || rhs_result);
435 if (lhs_result && !rhs_result) {
436 // Only the lhs succeeded.
438 } else if (!lhs_result && rhs_result) {
439 // Only the rhs succeeded.
441 } else if (lhs_result && rhs_result) {
442 // Both sides succeeded. Next check for user_confirmation.
443 bool lhs_confirm_needed = lhs_transaction->user_confirmation_required();
444 bool rhs_confirm_needed = rhs_transaction->user_confirmation_required();
445 if (lhs_confirm_needed && !rhs_confirm_needed) {
447 } else if (!lhs_confirm_needed && rhs_confirm_needed) {
450 // Neither or both of the two sides need user confirmation, so they
451 // are equal in that respect
452 if (lhs_transaction->is_preferable_to(rhs_transaction)) {
460 CYG_REPORT_RETVAL(result);
464 // A variant which will actually do the commits and cancels. This is
465 // commonly required when doing inferences of binary operators.
467 infer_choose2(CdlTransaction lhs_transaction, bool lhs_result, CdlTransaction rhs_transaction, bool rhs_result)
469 CYG_REPORT_FUNCNAMETYPE("infer_choose2", "result %d");
470 CYG_REPORT_FUNCARG4XV(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
473 if (lhs_result || rhs_result) {
474 bool lhs_preferable = infer_lhs_preferable(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
475 if (lhs_preferable) {
476 rhs_transaction->cancel();
477 lhs_transaction->commit();
479 lhs_transaction->cancel();
480 rhs_transaction->commit();
484 // Neither side succeeded.
485 lhs_transaction->cancel();
486 rhs_transaction->cancel();
489 // Zero or one of these transactions will have been committed,
490 // neither is still necessary.
491 delete lhs_transaction;
492 delete rhs_transaction;
494 CYG_REPORT_RETVAL(result);
499 //{{{ infer_handle_interface()
501 // ----------------------------------------------------------------------------
502 // Set an interface to a specific value, which should be some number n.
503 // If (n == 0) then all implementers must be disabled or made inactive.
504 // If (n == 1) then exactly one of the implementers must be active and enabled.
505 // Other combinations are not considered here, they could lead to an
506 // exponential explosion.
509 infer_handle_interface_value(CdlTransaction transaction, CdlInterface interface, CdlSimpleValue& goal, int level)
511 CYG_REPORT_FUNCNAMETYPE("infer_handle_reference_bool", "result %d");
512 CYG_REPORT_FUNCARG4XV(transaction, interface, &goal, level);
515 if (goal.has_integer_value()) {
516 cdl_int real_goal = goal.get_integer_value();
517 if (real_goal == interface->get_integer_value(transaction)) {
519 } else if (0 == real_goal) {
520 // All implementers must be disabled or made inactive. This
521 // can be achieved by creating a sub-transaction and calling
522 // infer_handle_reference_bool() on all of the implementers.
524 // However there are no guarantees that the result is what
525 // is intended. Updating a later implementer may as a side
526 // effect cause an earlier one to become active again. Also
527 // there may be confusion with valuables with the data
528 // flavor being given a value of 0. Hence a final check is
529 // needed that the new interface value really is the desired goal.
530 CdlTransaction sub_transaction;
531 std::vector<CdlValuable> implementers;
532 std::vector<CdlValuable>::const_iterator impl_i;
534 sub_transaction = transaction->make(transaction->get_conflict());
536 interface->get_implementers(implementers);
537 for (impl_i = implementers.begin(); impl_i != implementers.end(); impl_i++) {
538 (void) infer_handle_reference_bool(sub_transaction, *impl_i, false, level);
540 if (0 == interface->get_integer_value(sub_transaction)) {
541 sub_transaction->commit();
544 sub_transaction->cancel();
547 delete sub_transaction;
550 delete sub_transaction;
553 } else if (1 == real_goal) {
554 // This is a bit trickier than the above. We need n
555 // sub-transactions, one per implementer. In each
556 // sub-transaction we try to set exactly one of the
557 // implementers to enabled and the rest to disabled.
558 std::vector<CdlValuable> implementers;
559 unsigned int impl_count;
562 interface->get_implementers(implementers);
563 impl_count = implementers.size();
564 std::vector<CdlTransaction> sub_transactions;
565 std::vector<bool> results;
568 for (i = 0; i < impl_count; i++) {
569 CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
570 sub_transactions.push_back(sub_transaction);
571 results.push_back(false);
574 for (i = 0; i < impl_count; i++) {
575 for (j = 0; j < impl_count; j++) {
576 (void) infer_handle_reference_bool(sub_transactions[i], implementers[j], (i == j), level);
578 if (1 == interface->get_integer_value(sub_transactions[i])) {
583 // At this point we may have some combination of successful and unsucessful
584 // sub-transactions, and it is time to choose the best one.
585 CdlTransaction preferred = 0;
586 for (i = 0; i < impl_count; i++) {
588 preferred = sub_transactions[i];
593 for (j = i + 1; j < impl_count; j++) {
595 if (!infer_lhs_preferable(preferred, true, sub_transactions[j], true)) {
596 preferred = sub_transactions[j];
601 // Now either preferred == 0, i.e. all
602 // sub-transactions failed and we want to cancel them
603 // all. Or we have a viable sub-transaction.
604 for (i = 0; i < impl_count; i++) {
605 if (preferred == sub_transactions[i]) {
606 sub_transactions[i]->commit();
609 sub_transactions[i]->cancel();
611 delete sub_transactions[i];
612 sub_transactions[i] = 0;
616 for (i = 0; i < sub_transactions.size(); i++) {
617 if (0 != sub_transactions[i]) {
618 sub_transactions[i]->cancel();
619 delete sub_transactions[i];
620 sub_transactions[i] = 0;
627 CYG_REPORT_RETVAL(result);
632 //{{{ infer_handle_reference()
634 // ----------------------------------------------------------------------------
635 // We are processing an expression and have reached a point where we
636 // need <reference>, !<reference> or <reference>==<value>. The
637 // reference may currently be unbound, in which case 0 is the only
638 // goal that can be satisfied. If the reference is bound then it may
639 // be possible to satisfy the goal by setting the value. In addition
640 // it is necessary to worry about active vs. inactive state.
643 infer_handle_reference_bool(CdlTransaction transaction, CdlValuable valuable, bool goal, int level)
645 CYG_REPORT_FUNCNAMETYPE("infer_handle_reference_bool", "result %d");
646 CYG_REPORT_FUNCARG4XV(transaction, valuable, goal, level);
653 CYG_REPORT_RETVAL(result);
657 // If the valuable should evaluate to true then it must be both active
658 // and be either enabled or have a non-zero value.
660 if (!transaction->is_active(valuable)) {
661 if (!CdlInfer::make_active(transaction, valuable, level)) {
662 CYG_REPORT_RETVAL(result);
666 if (CdlInfer::set_valuable_bool(transaction, valuable, true, level)) {
671 // If the valuable should evaluate to false then it must be either
672 // inactive or it must be disabled or have a zero value.
673 if (!transaction->is_active(valuable)) {
674 // The goal is already satisfied, no need to proceed
676 CYG_REPORT_RETVAL(result);
680 // There is a choice to be made so two sub-transactions are
681 // needed. Disabling is generally preferred to making inactive.
682 CdlTransaction value_transaction = transaction->make(transaction->get_conflict());
683 CdlTransaction inactive_transaction = 0;
684 bool value_result = CdlInfer::set_valuable_bool(value_transaction, valuable, false, level);
685 if (value_result && !value_transaction->user_confirmation_required()) {
686 value_transaction->commit();
687 delete value_transaction;
688 value_transaction = 0;
690 CYG_REPORT_RETVAL(result);
694 inactive_transaction = transaction->make(transaction->get_conflict());
695 bool inactive_result = CdlInfer::make_inactive(inactive_transaction, valuable, level);
696 if (!inactive_result) {
698 // Changing the value is the only solution.
699 inactive_transaction->cancel();
700 value_transaction->commit();
703 inactive_transaction->cancel();
704 value_transaction->cancel();
709 // Making the valuable inactive is the only solution.
710 value_transaction->cancel();
711 inactive_transaction->commit();
713 } else if (!inactive_transaction->user_confirmation_required()) {
714 // Disabling the valuable would require user confirmation, making it inactive does not
715 value_transaction->cancel();
716 inactive_transaction->commit();
719 // Both approaches are valid but would require user confirmation.
720 // Pick the preferred one.
721 if (value_transaction->is_preferable_to(inactive_transaction)) {
722 inactive_transaction->cancel();
723 value_transaction->commit();
726 value_transaction->cancel();
727 inactive_transaction->commit();
733 delete value_transaction;
734 delete inactive_transaction;
735 value_transaction = 0;
736 inactive_transaction = 0;
739 CYG_REPORT_RETVAL(result);
743 // ----------------------------------------------------------------------------
744 // Try to set a valuable to a particular value. Of course the reference
745 // may not be bound yet.
747 // First check whether or not the valuable is currently active. If it is
748 // inactive and the goal is 0 then we have succeeded. If it is active and
749 // the goal is 0 then we could try to make the valuable inactive, but
750 // this possibility is ignored for now in case it leads to unexpected
751 // behaviour. If it is active then we try to set the value, using
752 // CdlInfer::set_valuable_value().
755 infer_handle_reference_value(CdlTransaction transaction, CdlValuable valuable, CdlSimpleValue& goal, int level)
757 CYG_REPORT_FUNCNAMETYPE("infer_handle_reference", "result %d");
758 CYG_REPORT_FUNCARG3XV(transaction, valuable, level);
763 if (goal == (cdl_int) 0) {
768 bool active = transaction->is_active(valuable);
770 if (goal == (cdl_int) 0) {
774 result = CdlInfer::set_valuable_value(transaction, valuable, goal, level);
778 CYG_REPORT_RETVAL(result);
783 //{{{ infer_handle_xxx_constant()
785 // ----------------------------------------------------------------------------
786 // Somewhere in the expression processing we have encountered a string
787 // constant. The expression cannot be changed, so either the goal matches
788 // the constant or it does not.
790 infer_handle_string_constant_bool(CdlSimpleValue& constant, bool goal)
792 CYG_REPORT_FUNCNAMETYPE("infer_handle_string_constant_bool", "result %d");
796 if (("" != constant.get_value()) && ("0" != constant.get_value())) {
800 if (("" == constant.get_value()) || ("0" == constant.get_value())) {
805 CYG_REPORT_RETVAL(result);
810 infer_handle_string_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
812 CYG_REPORT_FUNCNAMETYPE("infer_handle_string_constant_value", "result %d");
815 if (constant.get_value() == goal.get_value()) {
819 CYG_REPORT_RETVAL(result);
823 // ----------------------------------------------------------------------------
824 // Integers are also fairly straightforward.
826 infer_handle_integer_constant_bool(CdlSimpleValue& constant, bool goal)
828 CYG_REPORT_FUNCNAMETYPE("infer_handle_integer_constant_bool", "result %d");
829 CYG_PRECONDITIONC(constant.has_integer_value());
833 if (0 != constant.get_integer_value()) {
837 if (0 == constant.get_integer_value()) {
842 CYG_REPORT_RETVAL(result);
847 infer_handle_integer_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
849 CYG_REPORT_FUNCNAMETYPE("infer_handle_integer_constant_value", "result %d");
850 CYG_PRECONDITIONC(constant.has_integer_value());
853 if (goal.has_integer_value() && (constant.get_integer_value() == goal.get_integer_value())) {
857 CYG_REPORT_RETVAL(result);
861 // ----------------------------------------------------------------------------
862 // Doubles are also straightforward, except than an exact comparision may
863 // be too strict. There is not a lot that can be done about this right now.
864 // Future enhancements to CDL may support tolerances.
866 infer_handle_double_constant_bool(CdlSimpleValue& constant, bool goal)
868 CYG_REPORT_FUNCNAMETYPE("infer_handle_double_constant_bool", "result %d");
869 CYG_PRECONDITIONC(constant.has_double_value());
873 if (0.0 != constant.get_double_value()) {
877 if (0.0 == constant.get_double_value()) {
882 CYG_REPORT_RETVAL(result);
887 infer_handle_double_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
889 CYG_REPORT_FUNCNAMETYPE("infer_handle_double_constant_value", "result %d");
890 CYG_PRECONDITIONC(constant.has_double_value());
893 if (goal.has_double_value() && (constant.get_double_value() == goal.get_double_value())) {
897 CYG_REPORT_RETVAL(result);
902 //{{{ infer_handle_logical_xxx()
904 // ----------------------------------------------------------------------------
905 // Logical not simply involves inverting the goal and then trying to infer
906 // the rest of the sub-expression. There is little point in touching
907 // the other arguments.
909 infer_handle_logical_NOT_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
911 CYG_REPORT_FUNCNAMETYPE("infer_handle_logical_NOT_bool", "result %d");
913 bool result = CdlInfer::subexpr_bool(transaction, expr, index, !goal, level);
914 CYG_REPORT_RETVAL(result);
918 // ----------------------------------------------------------------------------
919 // Depending on the goal, we want either both sides of the AND to evaluate to
920 // true, or we want one of the sides to evaluate to false.
922 infer_handle_AND_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
923 bool goal, int level)
925 CYG_REPORT_FUNCNAMETYPE("infer_handle_AND_bool", "result %d");
926 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
927 CYG_PRECONDITION_CLASSC(transaction);
928 CYG_PRECONDITION_CLASSC(expr);
929 CYG_PRECONDITIONC(lhs != rhs);
934 // Both sides must be true in the same transaction, in case
935 // the solutions overlap in conflicting ways. A sub-transaction
936 // is still used to avoid polluting current values if the lhs
937 // can be inferred but not the rhs.
938 CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
939 if (CdlInfer::subexpr_bool(sub_transaction, expr, lhs, true, level) &&
940 CdlInfer::subexpr_bool(sub_transaction, expr, rhs, true, level)) {
941 sub_transaction->commit();
944 sub_transaction->cancel();
946 delete sub_transaction;
948 // We need to try out both sides of the OR and see which one is preferable.
949 // An optimization would be to only try the LHS, but trying both allows
950 // for a more informed choice.
951 CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
952 CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
953 bool lhs_result = CdlInfer::subexpr_bool(lhs_transaction, expr, lhs, false, level);
954 bool rhs_result = CdlInfer::subexpr_bool(rhs_transaction, expr, rhs, false, level);
956 result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
959 CYG_REPORT_RETVAL(result);
963 // ----------------------------------------------------------------------------
964 // The support for the other logical operations involves basically minor
965 // variants of the above.
968 infer_handle_OR_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
969 bool goal, int level)
971 CYG_REPORT_FUNCNAMETYPE("infer_handle_OR_bool", "result %d");
972 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
973 CYG_PRECONDITION_CLASSC(transaction);
974 CYG_PRECONDITION_CLASSC(expr);
975 CYG_PRECONDITIONC(lhs != rhs);
981 // We need to try out both sides of the OR and see which one is preferable.
982 // An optimization would be to only try the LHS, but trying both allows
983 // for a more informed choice.
984 CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
985 CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
986 bool lhs_result = CdlInfer::subexpr_bool(lhs_transaction, expr, lhs, true, level);
987 bool rhs_result = CdlInfer::subexpr_bool(rhs_transaction, expr, rhs, true, level);
989 result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
992 // !(A || B) -> !A && !B
993 CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
994 if (CdlInfer::subexpr_bool(sub_transaction, expr, lhs, false, level) &&
995 CdlInfer::subexpr_bool(sub_transaction, expr, rhs, false, level)) {
996 sub_transaction->commit();
999 sub_transaction->cancel();
1001 delete sub_transaction;
1004 CYG_REPORT_RETVAL(result);
1008 // ----------------------------------------------------------------------------
1011 infer_handle_IMPLIES_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1012 bool goal, int level)
1014 CYG_REPORT_FUNCNAMETYPE("infer_handle_implies_bool", "result %d");
1015 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1016 CYG_PRECONDITION_CLASSC(transaction);
1017 CYG_PRECONDITION_CLASSC(expr);
1018 CYG_PRECONDITIONC(lhs != rhs);
1021 bool result = false;
1024 // A implies B -> !A || B
1025 // Given a choice between !A or B, arguably the "implies"
1026 // operator has the connotation that B is preferred. All other
1027 // things being equal, infer_choose2() will prefer the rhs
1028 // over the lhs so this is achieved automagically.
1030 CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
1031 CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
1032 bool lhs_result = CdlInfer::subexpr_bool(lhs_transaction, expr, lhs, false, level);
1033 bool rhs_result = CdlInfer::subexpr_bool(rhs_transaction, expr, rhs, true, level);
1035 result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1039 // !(A implies B) -> !(!A || B) -> (A && !B)
1040 CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
1041 if (CdlInfer::subexpr_bool(sub_transaction, expr, lhs, true, level) &&
1042 CdlInfer::subexpr_bool(sub_transaction, expr, rhs, false, level)) {
1043 sub_transaction->commit();
1046 sub_transaction->cancel();
1048 delete sub_transaction;
1051 CYG_REPORT_RETVAL(result);
1055 // ----------------------------------------------------------------------------
1058 infer_handle_XOR_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1059 bool goal, int level)
1061 CYG_REPORT_FUNCNAMETYPE("infer_handle_XOR_bool", "result %d");
1062 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1063 CYG_PRECONDITION_CLASSC(transaction);
1064 CYG_PRECONDITION_CLASSC(expr);
1065 CYG_PRECONDITIONC(lhs != rhs);
1068 bool result = false;
1071 // (A xor B) -> (A && !B) || (!A && B)
1073 CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1074 CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1075 bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, true, level) &&
1076 CdlInfer::subexpr_bool(sub1, expr, rhs, false, level));
1077 bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, false, level) &&
1078 CdlInfer::subexpr_bool(sub2, expr, rhs, true, level));
1080 result = infer_choose2(sub1, result1, sub2, result2);
1084 // !(A xor B) -> (!A && !B) || (A && B)
1085 CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1086 CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1087 bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, false, level) &&
1088 CdlInfer::subexpr_bool(sub1, expr, rhs, false, level));
1089 bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, true, level) &&
1090 CdlInfer::subexpr_bool(sub2, expr, rhs, true, level));
1092 result = infer_choose2(sub1, result1, sub2, result2);
1095 CYG_REPORT_RETVAL(result);
1099 // ----------------------------------------------------------------------------
1102 infer_handle_EQV_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1103 bool goal, int level)
1105 CYG_REPORT_FUNCNAMETYPE("infer_handle_EQV_bool", "result %d");
1106 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1107 CYG_PRECONDITION_CLASSC(transaction);
1108 CYG_PRECONDITION_CLASSC(expr);
1109 CYG_PRECONDITIONC(lhs != rhs);
1112 bool result = false;
1115 // (A eqv B) -> (A && B) || (!A && !B)
1117 CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1118 CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1119 bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, true, level) &&
1120 CdlInfer::subexpr_bool(sub1, expr, rhs, true, level));
1121 bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, false, level) &&
1122 CdlInfer::subexpr_bool(sub2, expr, rhs, false, level));
1124 result = infer_choose2(sub1, result1, sub2, result2);
1126 // !(A eqv B) -> (A && !B) || (!A && B)
1128 CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1129 CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1130 bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, true, level) &&
1131 CdlInfer::subexpr_bool(sub1, expr, rhs, false, level));
1132 bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, false, level) &&
1133 CdlInfer::subexpr_bool(sub2, expr, rhs, true, level));
1135 result = infer_choose2(sub1, result1, sub2, result2);
1138 CYG_REPORT_RETVAL(result);
1143 //{{{ infer_handle_Equal()
1145 // ----------------------------------------------------------------------------
1146 // Handle expressions of the form A == B. This can be achieved either by
1147 // evaluating B and trying to assign the result to A, or vice versa. There
1148 // is a problem if assigning to one side has a side effect on the other, e.g.
1150 // requires { xyzzy == (xyzzy + 3) }
1152 // This has to be guarded against by reevaluating the expression.
1154 // At present this code only copes with equality, not inequality.
1157 infer_handle_equal_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs, bool goal, int level)
1159 CYG_REPORT_FUNCNAMETYPE("infer_handle_equal_bool", "result %d");
1160 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1161 CYG_PRECONDITION_CLASSC(transaction);
1162 CYG_PRECONDITION_CLASSC(expr);
1163 CYG_PRECONDITIONC(lhs != rhs);
1165 bool result = false;
1168 // We need two sub-transactions, The lhs_transaction is for evaluating the lhs
1169 // and trying to update the rhs.
1170 CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
1171 bool lhs_result = false;
1173 CdlSimpleValue lhs_value;
1174 CdlEvalContext lhs_context(lhs_transaction);
1175 expr->eval_subexpression(lhs_context, lhs, lhs_value);
1176 lhs_result = CdlInfer::subexpr_value(lhs_transaction, expr, rhs, lhs_value, level);
1178 CdlSimpleValue check;
1179 expr->eval_subexpression(lhs_context, lhs, check);
1180 if (lhs_value != check) {
1188 CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
1189 bool rhs_result = false;
1191 CdlSimpleValue rhs_value;
1192 CdlEvalContext rhs_context(rhs_transaction);
1193 expr->eval_subexpression(rhs_context, rhs, rhs_value);
1194 rhs_result = CdlInfer::subexpr_value(rhs_transaction, expr, lhs, rhs_value, level);
1196 CdlSimpleValue check;
1197 expr->eval_subexpression(rhs_context, rhs, check);
1198 if (rhs_value != check) {
1206 result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1209 CYG_REPORT_RETVAL(result);
1214 //{{{ infer_handle_numerical_equal()
1216 // ----------------------------------------------------------------------------
1217 // Handle expressions of the form A == B, where the comparison has to be
1218 // numerical in basis. This is used primarily for operators like <=
1222 infer_handle_numerical_equal_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs, bool goal, int level)
1224 CYG_REPORT_FUNCNAMETYPE("infer_handle_numerical_equal_bool", "result %d");
1225 CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1226 CYG_PRECONDITION_CLASSC(transaction);
1227 CYG_PRECONDITION_CLASSC(expr);
1228 CYG_PRECONDITIONC(lhs != rhs);
1230 bool result = false;
1233 // We need two sub-transactions, The lhs_transaction is for evaluating the lhs
1234 // and trying to update the rhs.
1235 CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
1236 bool lhs_result = false;
1238 CdlSimpleValue lhs_value;
1239 CdlEvalContext lhs_context(lhs_transaction);
1240 expr->eval_subexpression(lhs_context, lhs, lhs_value);
1241 if (lhs_value.has_integer_value() || lhs_value.has_double_value()) {
1242 lhs_result = CdlInfer::subexpr_value(lhs_transaction, expr, rhs, lhs_value, level);
1244 CdlSimpleValue check;
1245 expr->eval_subexpression(lhs_context, lhs, check);
1246 if (lhs_value != check) {
1255 CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
1256 bool rhs_result = false;
1258 CdlSimpleValue rhs_value;
1259 CdlEvalContext rhs_context(rhs_transaction);
1260 expr->eval_subexpression(rhs_context, rhs, rhs_value);
1261 if (rhs_value.has_integer_value() || rhs_value.has_double_value()) {
1262 rhs_result = CdlInfer::subexpr_value(rhs_transaction, expr, lhs, rhs_value, level);
1264 CdlSimpleValue check;
1265 expr->eval_subexpression(rhs_context, rhs, check);
1266 if (rhs_value != check) {
1275 result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1278 CYG_REPORT_RETVAL(result);
1283 //{{{ CdlInfer::subexpr_bool()
1285 // ----------------------------------------------------------------------------
1287 CdlInfer::subexpr_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
1289 CYG_REPORT_FUNCNAMETYPE("CdlInfer::subexpr_bool", "result %d");
1290 CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
1291 CYG_PRECONDITION_CLASSC(transaction);
1292 CYG_PRECONDITION_CLASSC(expr);
1293 CYG_PRECONDITIONC((0 <= index) && (index < expr->sub_expressions.size()));
1295 bool result = false;
1296 CdlSubexpression& subexpr = expr->sub_expressions[index];
1298 switch(subexpr.op) {
1300 case CdlExprOp_Reference :
1301 // The most common case. Follow the reference, and call the appropriate function.
1302 // Note that the reference may be unbound.
1304 CdlNode node = expr->references[subexpr.reference_index].get_destination();
1305 CdlValuable valuable = 0;
1307 valuable = dynamic_cast<CdlValuable>(node);
1309 result = infer_handle_reference_bool(transaction, valuable, goal, level);
1313 case CdlExprOp_StringConstant :
1314 result = infer_handle_string_constant_bool(subexpr.constants, goal);
1317 case CdlExprOp_IntegerConstant :
1318 result = infer_handle_integer_constant_bool(subexpr.constants, goal);
1321 case CdlExprOp_DoubleConstant :
1322 result = infer_handle_double_constant_bool(subexpr.constants, goal);
1325 case CdlExprOp_LogicalNot :
1326 result = infer_handle_logical_NOT_bool(transaction, expr, subexpr.lhs_index, goal, level);
1329 case CdlExprOp_And :
1330 result = infer_handle_AND_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1334 result = infer_handle_OR_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1337 case CdlExprOp_Implies :
1338 result = infer_handle_IMPLIES_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1341 case CdlExprOp_Xor :
1342 result = infer_handle_XOR_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1345 case CdlExprOp_Eqv :
1346 result = infer_handle_EQV_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1349 case CdlExprOp_Equal :
1350 result = infer_handle_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1353 case CdlExprOp_NotEqual :
1354 result = infer_handle_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, !goal, level);
1357 // <= is satisfied by a numerical equality. However the inverse relation > cannot be handled that way
1358 // The other comparison operators are much the same.
1359 case CdlExprOp_LessEqual :
1360 case CdlExprOp_GreaterEqual :
1362 result = infer_handle_numerical_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, true, level);
1366 case CdlExprOp_LessThan :
1367 case CdlExprOp_GreaterThan :
1369 result = infer_handle_numerical_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, true, level);
1373 case CdlExprOp_Function :
1374 result = CdlFunction::infer_bool(transaction, expr, index, goal, level);
1378 // No other inferences are implemented at this stage.
1382 CYG_REPORT_RETVAL(result);
1387 //{{{ CdlInfer::subexpr_value()
1390 CdlInfer::subexpr_value(CdlTransaction transaction, CdlExpression expr, unsigned int index, CdlSimpleValue& goal, int level)
1392 CYG_REPORT_FUNCNAMETYPE("CdlInfer::subexpr_value", "result %d");
1393 CYG_REPORT_FUNCARG4XV(transaction, expr, index, level);
1394 CYG_PRECONDITION_CLASSC(transaction);
1395 CYG_PRECONDITION_CLASSC(expr);
1396 CYG_PRECONDITIONC((0 <= index) && (index < expr->sub_expressions.size()));
1398 bool result = false;
1399 CdlSubexpression& subexpr = expr->sub_expressions[index];
1401 switch(subexpr.op) {
1403 case CdlExprOp_Reference :
1404 // The most common case. Follow the reference, and call the appropriate function.
1405 // Note that the reference may be unbound.
1407 CdlNode node = expr->references[subexpr.reference_index].get_destination();
1408 CdlValuable valuable = 0;
1410 valuable = dynamic_cast<CdlValuable>(node);
1412 result = infer_handle_reference_value(transaction, valuable, goal, level);
1416 case CdlExprOp_StringConstant :
1417 result = infer_handle_string_constant_value(subexpr.constants, goal);
1420 case CdlExprOp_IntegerConstant :
1421 result = infer_handle_integer_constant_value(subexpr.constants, goal);
1424 case CdlExprOp_DoubleConstant :
1425 result = infer_handle_double_constant_value(subexpr.constants, goal);
1428 case CdlExprOp_LogicalNot :
1429 case CdlExprOp_And :
1431 case CdlExprOp_Implies :
1432 case CdlExprOp_Xor :
1433 case CdlExprOp_Eqv :
1435 bool new_goal = true;
1436 if (("0" == goal.get_value()) || ("" == goal.get_value())) {
1439 result = CdlInfer::subexpr_bool(transaction, expr, index, new_goal, level);
1443 case CdlExprOp_Function :
1444 result = CdlFunction::infer_value(transaction, expr, index, goal, level);
1448 // No other inferences are implemented at this stage.
1452 CYG_REPORT_RETVAL(result);
1459 //{{{ Illegal value resolution
1461 // ----------------------------------------------------------------------------
1462 // This is not yet implemented.
1465 CdlConflict_IllegalValueBody::inner_resolve(CdlTransaction transaction, int level)
1467 CYG_REPORT_FUNCNAMETYPE("CdlConflict_IllegalValue::inner_resolve", "result %d");
1468 CYG_REPORT_FUNCARG3XV(this, transaction, level);
1469 CYG_PRECONDITION_THISC();
1470 CYG_PRECONDITION_CLASSC(transaction);
1472 CYG_UNUSED_PARAM(CdlTransaction, transaction);
1474 CYG_REPORT_RETVAL(false);
1479 //{{{ Requires resolution
1481 // ----------------------------------------------------------------------------
1482 // The entry point for this code is
1483 // CdlConflict_RequiresBody::resolve(). "this" is a requires conflict
1484 // that needs to be resolved, if possible. There are twos argument: a
1485 // sub-transaction, which should be filled in with the solution if
1486 // possible; and a recursion level indicator, 0 if this is a top-level
1487 // inference engine invocation rather than a recursive one. There are
1488 // additional static parameters inference_recursion_limit and
1489 // inference_override which control details of the inference process.
1491 // As an example of what is involved in an inference, consider the
1492 // simple case of a "requires XXX" property. This constraint may not
1493 // be satisfied because XXX is disabled, because XXX is inactive,
1496 // Assume for simplicity that XXX is already active. The inference
1497 // engine can now figure out that XXX must be enabled (it must be
1498 // of type bool or booldata, or else the conflict would not have
1499 // arisen). This is achieved by creating a sub-transaction,
1500 // enabling XXX in that sub-transaction, propagating the
1501 // sub-transaction and performing further inference. The inference
1502 // is successfull if no new conflicts are introduced.
1504 // However, even if a solution is found it is not necessarily
1505 // acceptable without user confirmation, subject to
1506 // inference_override. This is handled in part by the transaction
1507 // class itself, in the resolve() and user_confirmation_required()
1508 // members. In cases where the inference engine can choose between
1509 // several alternatives it needs to consider this issue for each one.
1510 // Resolving a requires conflict. There are three ways of tackling
1511 // this problem, in order of preference:
1513 // 1) change the terms in the expression to make it evaluate to
1515 // 2) disable the source so that the requires property is no longer
1517 // 3) make the source inactive, with the same effect.
1519 // The first one should always be tried. If it is entirely successful
1520 // then there is no point in looking any further. If user confirmation
1521 // is required then the second approach should be tried. If that is
1522 // entirely successful then there is no point in looking further.
1523 // If user confirmation is required then the third approach should
1527 CdlConflict_RequiresBody::inner_resolve(CdlTransaction transaction, int level)
1529 CYG_REPORT_FUNCNAME("CdlConflict_Requires::inner_resolve");
1530 CYG_REPORT_FUNCARG3XV(this, transaction, level);
1531 CYG_PRECONDITION_THISC();
1532 CYG_PRECONDITION_CLASSC(transaction);
1534 bool result = false;
1536 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(this->get_property());
1537 CdlExpression expr = gexpr->get_expression();
1539 // Only create the sub-transactions when needed.
1540 CdlTransaction expr_transaction = 0;
1541 CdlTransaction disable_transaction = 0;
1542 CdlTransaction inactive_transaction = 0;
1544 // Keep track of the preferred solution found to date.
1545 CdlTransaction preferred_transaction = 0;
1547 expr_transaction = transaction->make(this);
1548 if (!CdlInfer::subexpr_bool(expr_transaction, expr, expr->first_subexpression, true, level)) {
1550 expr_transaction->cancel();
1551 delete expr_transaction;
1552 expr_transaction = 0;
1554 // We have a possible solution. How acceptable is it?
1555 if (!expr_transaction->user_confirmation_required()) {
1557 expr_transaction->commit();
1558 delete expr_transaction;
1560 CYG_REPORT_RETVAL(result);
1563 // Maybe we can do better.
1564 preferred_transaction = expr_transaction;
1565 expr_transaction = 0;
1569 // Disabling the source only makes sense if we have a bool or booldata item.
1570 CdlValuable valuable = dynamic_cast<CdlValuable>(this->get_node());
1571 CYG_ASSERT_CLASSC(valuable);
1573 if ((CdlValueFlavor_Bool == valuable->get_flavor()) || (CdlValueFlavor_BoolData == valuable->get_flavor())) {
1574 disable_transaction = transaction->make(this);
1575 if (!CdlInfer::set_valuable_bool(disable_transaction, valuable, false, level)) {
1576 // No luck here either.
1577 disable_transaction->cancel();
1578 delete disable_transaction;
1579 disable_transaction = 0;
1581 if (!disable_transaction->user_confirmation_required()) {
1582 disable_transaction->commit();
1583 delete disable_transaction;
1584 if (0 != preferred_transaction) {
1585 preferred_transaction->cancel();
1586 delete preferred_transaction;
1587 preferred_transaction = 0;
1590 CYG_REPORT_RETVAL(result);
1592 } else if (0 == preferred_transaction) {
1593 preferred_transaction = disable_transaction;
1594 } else if (!preferred_transaction->is_preferable_to(disable_transaction)) {
1595 preferred_transaction->cancel();
1596 delete preferred_transaction;
1597 preferred_transaction = disable_transaction;
1598 disable_transaction = 0;
1600 disable_transaction->cancel();
1601 delete disable_transaction;
1602 disable_transaction = 0;
1607 // Now try for the inactive approach. This may work in cases where the disable
1608 // approach does not if e.g. there are dependencies between two nodes in the
1609 // same container, or if the source of the conflict is not boolean.
1610 inactive_transaction = transaction->make(this);
1611 if (!CdlInfer::make_inactive(inactive_transaction, valuable, level)) {
1612 inactive_transaction->cancel();
1613 delete inactive_transaction;
1614 inactive_transaction = 0;
1616 if (!inactive_transaction->user_confirmation_required()) {
1617 inactive_transaction->commit();
1618 delete inactive_transaction;
1619 if (0 != preferred_transaction) {
1620 preferred_transaction->cancel();
1621 delete preferred_transaction;
1622 preferred_transaction = 0;
1625 CYG_REPORT_RETVAL(result);
1627 } else if (0 == preferred_transaction) {
1628 preferred_transaction = inactive_transaction;
1629 } else if (!preferred_transaction->is_preferable_to(inactive_transaction)) {
1630 preferred_transaction->cancel();
1631 delete preferred_transaction;
1632 preferred_transaction = inactive_transaction;
1633 inactive_transaction = 0;
1635 inactive_transaction->cancel();
1636 delete inactive_transaction;
1637 inactive_transaction = 0;
1641 // Is there any solution at all? If so then use the currently-preferred one.
1642 if (0 != preferred_transaction) {
1643 preferred_transaction->commit();
1644 delete preferred_transaction;
1645 preferred_transaction = 0;
1649 CYG_REPORT_RETVAL(result);