]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/libcdl/infer.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / libcdl / infer.cxx
1 //{{{  Banner                                   
2
3 //============================================================================
4 //
5 //      infer.cxx
6 //
7 //      Inference for common conflicts.
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //                                                                          
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
14 //
15 // This file is part of the eCos host tools.
16 //
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) 
20 // any later version.
21 // 
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 
25 // more details.
26 // 
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.
30 //
31 // ----------------------------------------------------------------------------
32 //                                                                          
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
36 //
37 // Author(s):   bartv
38 // Contact(s):  bartv
39 // Date:        1999/11/1
40 // Version:     0.01
41 //
42 //####DESCRIPTIONEND####
43 //============================================================================
44
45 //}}}
46 //{{{  #include's                               
47
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
50
51 // Get the infrastructure types, assertions, tracing and similar
52 // facilities.
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55
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>
60
61 //}}}
62
63 //{{{  CdlInfer class                           
64
65 //{{{  Description                              
66
67 // ----------------------------------------------------------------------------
68 // The following functions provide the main entry points for inference.
69 //
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
83 //    goal.
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()
87 //
88 //    As might be expected, the sub-expression handlers contain a big
89 //    switch statement and calls into various auxiliary functions when
90 //    necessary.
91 //
92 // For convenience the various entry points check whether or not the
93 // desired condition is already satisfied.
94
95 //}}}
96 //{{{  Forward declarations                     
97
98 // ----------------------------------------------------------------------------
99
100 static bool infer_handle_interface_value(CdlTransaction, CdlInterface, CdlSimpleValue&, int);
101 static bool infer_handle_reference_bool(CdlTransaction, CdlValuable, bool, int);
102
103 //}}}
104 //{{{  CdlInfer::make_active()                  
105
106 // ----------------------------------------------------------------------------
107 // Making a node active. This requires the following conditions to be
108 // satisfied:
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 
112
113 bool
114 CdlInfer::make_active(CdlTransaction transaction, CdlNode node, int level)
115 {
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);
120
121     bool result = false;
122     if (transaction->is_active(node)) {
123         result = true;
124         CYG_REPORT_RETVAL(result);
125         return result;
126     }
127     
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);
133             return result;
134         }
135     }
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);
144                 return result;
145             }
146         }
147     }
148     // The parent is now active and enabled. Are there any active_if properties to worry about?
149     CdlValuable valuable = dynamic_cast<CdlValuable>(node);
150     if (0 != valuable) {
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++) {
155             
156             CdlEvalContext context(transaction, valuable, *goal_i);
157             try {
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);
162                         return result;
163                     }
164                 }
165             } catch(...) {
166                 CYG_REPORT_RETVAL(result);
167                 return result;
168             }
169         }
170         
171     }
172     
173     result = transaction->is_active(node);
174     CYG_REPORT_RETVAL(result);
175     return result;
176 }
177
178 //}}}
179 //{{{  CdlInfer::make_inactive()                
180
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
185 //    fine.
186 // 3) if there are any active_if properties, they could be considered
187 //    as well. For now this possibility is ignored.
188
189 bool
190 CdlInfer::make_inactive(CdlTransaction transaction, CdlNode node, int level)
191 {
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);
196
197     bool result = false;
198     if (!transaction->is_active(node)) {
199         result = true;
200         CYG_REPORT_RETVAL(result);
201         return result;
202     }
203
204     CdlContainer parent = node->get_parent();
205     if (0 == parent) {
206         // No point in trying to disable the entire configuration.
207         CYG_REPORT_RETVAL(result);
208         return result;
209     }
210     
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;
222                 result = true;
223                 CYG_REPORT_RETVAL(result);
224                 return result;
225             } else {
226                 subtransaction->cancel();
227                 delete subtransaction;
228             }
229         }
230     }
231
232     // It is not possible to disable the parent. How about making it inactive?
233     if (CdlInfer::make_inactive(transaction, parent, level)) {
234         result = true;
235         CYG_REPORT_RETVAL(result);
236         return result;
237     }
238
239     // For now do not try to mess about with active_if conditions.
240     
241     CYG_REPORT_RETVAL(result);
242     return result;
243 }
244
245 //}}}
246 //{{{  CdlInfer::set_valuable_value()           
247
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.
251
252 bool
253 CdlInfer::set_valuable_value(CdlTransaction transaction, CdlValuable valuable, CdlSimpleValue& goal, int level)
254 {
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));
260
261     bool result = false;
262
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();
266
267     switch(flavor) {
268       default                  :
269       case CdlValueFlavor_None :
270           break;
271
272       case CdlValueFlavor_Bool :
273           if (bool_goal == current_value.is_enabled()) {
274               result = true;
275           } else {
276               if (valuable->is_modifiable() &&
277                   (0 == dynamic_cast<CdlLoadable>(valuable)) &&
278                   !transaction->changed_by_user(valuable)) {
279
280                   valuable->set_enabled(transaction, bool_goal, CdlValueSource_Inferred);
281                   valuable->set_source(transaction, CdlValueSource_Inferred);
282                   result = transaction->resolve_recursion(level);
283               }
284
285           }
286           break;
287
288       case CdlValueFlavor_BoolData :
289           if (!bool_goal && !current_value.is_enabled()) {
290               result = true;
291           } else if (bool_goal && current_value.is_enabled() && (goal == current_value.get_simple_value())) {
292               result = true;
293           } else {
294               if (valuable->is_modifiable() &&
295                   (0 == dynamic_cast<CdlLoadable>(valuable)) &&
296                   !transaction->changed_by_user(valuable)) {
297                   
298                   if (!bool_goal) {
299                       valuable->disable(transaction, CdlValueSource_Inferred);
300                   } else {
301                       valuable->enable_and_set_value(transaction, goal, CdlValueSource_Inferred);
302                   }
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);
308               }
309           }
310           break;
311
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()) {
315             result = true;
316         } else {
317             if (valuable->is_modifiable() &&
318                 (0 == dynamic_cast<CdlLoadable>(valuable)) &&
319                 !transaction->changed_by_user(valuable)) {
320     
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);
328             }
329         }
330         break;
331     }
332     
333     CYG_REPORT_RETVAL(result);
334     return result;
335 }
336
337 //}}}
338 //{{{  CdlInfer::set_valuable_bool()            
339
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.
344
345 bool
346 CdlInfer::set_valuable_bool(CdlTransaction transaction, CdlValuable valuable, bool goal, int level)
347 {
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);
352
353     bool result = false;
354
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) {
361         if (goal) {
362             result = true;
363         }
364         CYG_REPORT_RETVAL(result);
365         return result;
366     }
367
368     if (CdlValueFlavor_Data == flavor) {
369         std::string value = valuable->get_value(transaction);
370         if (goal) {
371             if (("" != value) && ("0" != value)) {
372                 result = true;
373             }
374         } else {
375             if (("" == value) || ("0" == value)) {
376                 result = true;
377             }
378         }
379         CYG_REPORT_RETVAL(result);
380         return result;
381     }
382     
383     CYG_ASSERTC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor));
384     bool enabled = valuable->is_enabled(transaction);
385     if (enabled == goal) {
386         result = true;
387         CYG_REPORT_RETVAL(result);
388         return result;
389     }
390
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)) {
396
397         CYG_REPORT_RETVAL(result);
398         return result;
399     }
400     // If we are about to disable a container, better check that this would
401     // not annoy the user either
402     if (!goal) {
403         CdlContainer container = dynamic_cast<CdlContainer>(valuable);
404         if ((0 != container) && transaction->subnode_changed_by_user(container)) {
405             CYG_REPORT_RETVAL(result);
406             return result;
407         }
408     }
409     
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);
414     
415     CYG_REPORT_RETVAL(result);
416     return result;
417 }
418
419 //}}}
420 //{{{  infer_choose()                           
421
422 // ----------------------------------------------------------------------------
423 // Given two sub-transactions which may or may not have succeeded, pick the
424 // preferred one. This happens for many binary operators.
425
426 static bool
427 infer_lhs_preferable(CdlTransaction lhs_transaction, bool lhs_result, CdlTransaction rhs_transaction, bool rhs_result)
428 {
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);
432     
433     bool result = true;
434     
435     if (lhs_result && !rhs_result) {
436         // Only the lhs succeeded.
437         result = true;
438     } else if (!lhs_result && rhs_result) {
439         // Only the rhs succeeded.
440         result = false;
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) {
446             result = false;
447         } else if (!lhs_confirm_needed && rhs_confirm_needed) {
448             result = true;
449         } else {
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)) {
453                 result = true;
454             } else {
455                 result = false;
456             }
457         }
458     }
459
460     CYG_REPORT_RETVAL(result);
461     return result;
462 }
463
464 // A variant which will actually do the commits and cancels. This is
465 // commonly required when doing inferences of binary operators.
466 static bool
467 infer_choose2(CdlTransaction lhs_transaction, bool lhs_result, CdlTransaction rhs_transaction, bool rhs_result)
468 {
469     CYG_REPORT_FUNCNAMETYPE("infer_choose2", "result %d");
470     CYG_REPORT_FUNCARG4XV(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
471     bool result = false;
472
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();
478         } else {
479             lhs_transaction->cancel();
480             rhs_transaction->commit();
481         }
482         result = true;
483     } else {
484         // Neither side succeeded.
485         lhs_transaction->cancel();
486         rhs_transaction->cancel();
487     }
488     
489     // Zero or one of these transactions will have been committed,
490     // neither is still necessary.
491     delete lhs_transaction;
492     delete rhs_transaction;
493
494     CYG_REPORT_RETVAL(result);
495     return result;
496 }
497
498 //}}}
499 //{{{  infer_handle_interface()                 
500
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.
507
508 static bool
509 infer_handle_interface_value(CdlTransaction transaction, CdlInterface interface, CdlSimpleValue& goal, int level)
510 {
511     CYG_REPORT_FUNCNAMETYPE("infer_handle_reference_bool", "result %d");
512     CYG_REPORT_FUNCARG4XV(transaction, interface, &goal, level);
513     bool result = false;
514
515     if (goal.has_integer_value()) {
516         cdl_int real_goal = goal.get_integer_value();
517         if (real_goal == interface->get_integer_value(transaction)) {
518             result = true;
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.
523             //
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;
533
534             sub_transaction = transaction->make(transaction->get_conflict());
535             try {
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);
539                 }
540                 if (0 == interface->get_integer_value(sub_transaction)) {
541                     sub_transaction->commit();
542                     result = true;
543                 } else {
544                     sub_transaction->cancel();
545                 }
546             } catch (...) {
547                 delete sub_transaction;
548                 throw;
549             }
550             delete sub_transaction;
551             sub_transaction = 0;
552             
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;
560             unsigned int                i, j;
561             
562             interface->get_implementers(implementers);
563             impl_count = implementers.size();
564             std::vector<CdlTransaction> sub_transactions;
565             std::vector<bool>           results;
566
567             try {
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);
572                     results[i]          = false;
573                 }
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);
577                     }
578                     if (1 == interface->get_integer_value(sub_transactions[i])) {
579                         results[i] = true;
580                     }
581                 }
582                 
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++) {
587                     if (results[i]) {
588                         preferred = sub_transactions[i];
589                         break;
590                     }
591                 }
592
593                 for (j = i + 1; j < impl_count; j++) {
594                     if (results[j]) {
595                         if (!infer_lhs_preferable(preferred, true, sub_transactions[j], true)) {
596                             preferred = sub_transactions[j];
597                         }
598                     }
599                 }
600
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();
607                         result = true;
608                     } else {
609                         sub_transactions[i]->cancel();
610                     }
611                     delete sub_transactions[i];
612                     sub_transactions[i] = 0;
613                 }
614                 
615             } catch(...) {
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;
621                     }
622                 }
623             }
624         }
625     }
626     
627     CYG_REPORT_RETVAL(result);
628     return result;
629 }
630
631 //}}}
632 //{{{  infer_handle_reference()                 
633
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.
641
642 static bool
643 infer_handle_reference_bool(CdlTransaction transaction, CdlValuable valuable, bool goal, int level)
644 {
645     CYG_REPORT_FUNCNAMETYPE("infer_handle_reference_bool", "result %d");
646     CYG_REPORT_FUNCARG4XV(transaction, valuable, goal, level);
647
648     bool result = false;
649     if (0 == valuable) {
650         if (!goal) {
651             result = true;
652         }
653         CYG_REPORT_RETVAL(result);
654         return result;
655     }
656
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.
659     if (goal) {
660         if (!transaction->is_active(valuable)) {
661             if (!CdlInfer::make_active(transaction, valuable, level)) {
662                 CYG_REPORT_RETVAL(result);
663                 return result;
664             }
665         }
666         if (CdlInfer::set_valuable_bool(transaction, valuable, true, level)) {
667             result = true;
668         }
669
670     } else {
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
675             result = true;
676             CYG_REPORT_RETVAL(result);
677             return result;
678         }
679         
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;
689             result = true;
690             CYG_REPORT_RETVAL(result);
691             return result;
692         }
693
694         inactive_transaction = transaction->make(transaction->get_conflict());
695         bool inactive_result = CdlInfer::make_inactive(inactive_transaction, valuable, level);
696         if (!inactive_result) {
697             if (value_result) {
698                 // Changing the value is the only solution.
699                 inactive_transaction->cancel();
700                 value_transaction->commit();
701                 result = true;
702             } else {
703                 inactive_transaction->cancel();
704                 value_transaction->cancel();
705                 result = false;
706             }
707         } else {
708             if (!value_result) {
709                 // Making the valuable inactive is the only solution.
710                 value_transaction->cancel();
711                 inactive_transaction->commit();
712                 result = true;
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();
717                 result = true;
718             } else {
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();
724                     result = true;
725                 } else {
726                     value_transaction->cancel();
727                     inactive_transaction->commit();
728                     result = true;
729                 }
730             }
731         }
732
733         delete value_transaction;
734         delete inactive_transaction;
735         value_transaction = 0;
736         inactive_transaction = 0;
737     }
738     
739     CYG_REPORT_RETVAL(result);
740     return result;
741 }
742
743 // ----------------------------------------------------------------------------
744 // Try to set a valuable to a particular value. Of course the reference
745 // may not be bound yet.
746 //
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().
753
754 static bool
755 infer_handle_reference_value(CdlTransaction transaction, CdlValuable valuable, CdlSimpleValue& goal, int level)
756 {
757     CYG_REPORT_FUNCNAMETYPE("infer_handle_reference", "result %d");
758     CYG_REPORT_FUNCARG3XV(transaction, valuable, level);
759
760     bool result = false;
761
762     if (0 == valuable) {
763         if (goal == (cdl_int) 0) {
764             result = true;
765         }
766     } else {
767     
768         bool active = transaction->is_active(valuable);
769         if (!active) {
770             if (goal == (cdl_int) 0) {
771                 result = true;
772             }
773         } else {
774             result = CdlInfer::set_valuable_value(transaction, valuable, goal, level);
775         }
776     }
777     
778     CYG_REPORT_RETVAL(result);
779     return result;
780 }
781
782 //}}}
783 //{{{  infer_handle_xxx_constant()              
784
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.
789 static bool
790 infer_handle_string_constant_bool(CdlSimpleValue& constant, bool goal)
791 {
792     CYG_REPORT_FUNCNAMETYPE("infer_handle_string_constant_bool", "result %d");
793     bool result = false;
794
795     if (goal) {
796         if (("" != constant.get_value()) && ("0" != constant.get_value())) {
797             result = true;
798         }
799     } else {
800         if (("" == constant.get_value()) || ("0" == constant.get_value())) {
801             result = true;
802         }
803     }
804
805     CYG_REPORT_RETVAL(result);
806     return result;
807 }
808
809 static bool
810 infer_handle_string_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
811 {
812     CYG_REPORT_FUNCNAMETYPE("infer_handle_string_constant_value", "result %d");
813     bool result = false;
814
815     if (constant.get_value() == goal.get_value()) {
816         result = true;
817     }
818
819     CYG_REPORT_RETVAL(result);
820     return result;
821 }
822
823 // ----------------------------------------------------------------------------
824 // Integers are also fairly straightforward.
825 static bool
826 infer_handle_integer_constant_bool(CdlSimpleValue& constant, bool goal)
827 {
828     CYG_REPORT_FUNCNAMETYPE("infer_handle_integer_constant_bool", "result %d");
829     CYG_PRECONDITIONC(constant.has_integer_value());
830     bool result = false;
831
832     if (goal) {
833         if (0 != constant.get_integer_value()) {
834             result = true;
835         }
836     } else {
837         if (0 == constant.get_integer_value()) {
838             result = true;
839         }
840     }
841     
842     CYG_REPORT_RETVAL(result);
843     return result;
844 }
845
846 static bool
847 infer_handle_integer_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
848 {
849     CYG_REPORT_FUNCNAMETYPE("infer_handle_integer_constant_value", "result %d");
850     CYG_PRECONDITIONC(constant.has_integer_value());
851     bool result = false;
852
853     if (goal.has_integer_value() && (constant.get_integer_value() == goal.get_integer_value())) {
854         result = true;
855     }
856
857     CYG_REPORT_RETVAL(result);
858     return result;
859 }
860
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.
865 static bool
866 infer_handle_double_constant_bool(CdlSimpleValue& constant, bool goal)
867 {
868     CYG_REPORT_FUNCNAMETYPE("infer_handle_double_constant_bool", "result %d");
869     CYG_PRECONDITIONC(constant.has_double_value());
870     bool result = false;
871
872     if (goal) {
873         if (0.0 != constant.get_double_value()) {
874             result = true;
875         }
876     } else {
877         if (0.0 == constant.get_double_value()) {
878             result = true;
879         }
880     }
881
882     CYG_REPORT_RETVAL(result);
883     return result;
884 }
885
886 static bool
887 infer_handle_double_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
888 {
889     CYG_REPORT_FUNCNAMETYPE("infer_handle_double_constant_value", "result %d");
890     CYG_PRECONDITIONC(constant.has_double_value());
891     bool result = false;
892
893     if (goal.has_double_value() && (constant.get_double_value() == goal.get_double_value())) {
894         result = true;
895     }
896
897     CYG_REPORT_RETVAL(result);
898     return result;
899 }
900
901 //}}}
902 //{{{  infer_handle_logical_xxx()               
903
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.
908 static bool
909 infer_handle_logical_NOT_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
910 {
911     CYG_REPORT_FUNCNAMETYPE("infer_handle_logical_NOT_bool", "result %d");
912
913     bool result = CdlInfer::subexpr_bool(transaction, expr, index, !goal, level);
914     CYG_REPORT_RETVAL(result);
915     return result;
916 }
917
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.
921 static bool
922 infer_handle_AND_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
923                       bool goal, int level)
924 {
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);
930
931     bool result = false;
932     
933     if (goal) {
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();
942             result = true;
943         } else {
944             sub_transaction->cancel();
945         }
946         delete sub_transaction;
947     } else {
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);
955
956         result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
957     }
958
959     CYG_REPORT_RETVAL(result);
960     return result;
961 }
962
963 // ----------------------------------------------------------------------------
964 // The support for the other logical operations involves basically minor
965 // variants of the above.
966
967 static bool
968 infer_handle_OR_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
969                      bool goal, int level)
970 {
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);
976
977
978     bool result = false;
979     
980     if (goal) {
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);
988
989         result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
990     } else {
991         
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();
997             result = true;
998         } else {
999             sub_transaction->cancel();
1000         }
1001         delete sub_transaction;
1002     }
1003     
1004     CYG_REPORT_RETVAL(result);
1005     return result;
1006 }
1007
1008 // ----------------------------------------------------------------------------
1009
1010 static bool
1011 infer_handle_IMPLIES_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1012                      bool goal, int level)
1013 {
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);
1019
1020
1021     bool result = false;
1022     
1023     if (goal) {
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.
1029         
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);
1034
1035         result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1036         
1037     } else {
1038         
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();
1044             result = true;
1045         } else {
1046             sub_transaction->cancel();
1047         }
1048         delete sub_transaction;
1049     }
1050     
1051     CYG_REPORT_RETVAL(result);
1052     return result;
1053 }
1054
1055 // ----------------------------------------------------------------------------
1056
1057 static bool
1058 infer_handle_XOR_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1059                      bool goal, int level)
1060 {
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);
1066
1067
1068     bool result = false;
1069     
1070     if (goal) {
1071         // (A xor B) -> (A && !B) || (!A && B)
1072
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));
1079                            
1080         result = infer_choose2(sub1, result1, sub2, result2);
1081         
1082     } else {
1083         
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));
1091                            
1092         result = infer_choose2(sub1, result1, sub2, result2);
1093     }
1094     
1095     CYG_REPORT_RETVAL(result);
1096     return result;
1097 }
1098
1099 // ----------------------------------------------------------------------------
1100
1101 static bool
1102 infer_handle_EQV_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1103                      bool goal, int level)
1104 {
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);
1110
1111
1112     bool result = false;
1113     
1114     if (goal) {
1115         // (A eqv B) -> (A && B) || (!A && !B)
1116
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));
1123                            
1124         result = infer_choose2(sub1, result1, sub2, result2);
1125     } else {
1126         // !(A eqv B) -> (A && !B) || (!A && B)
1127
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));
1134                            
1135         result = infer_choose2(sub1, result1, sub2, result2);
1136     }
1137     
1138     CYG_REPORT_RETVAL(result);
1139     return result;
1140 }
1141
1142 //}}}
1143 //{{{  infer_handle_Equal()                     
1144
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.
1149 //
1150 //   requires { xyzzy == (xyzzy + 3) }
1151 //
1152 // This has to be guarded against by reevaluating the expression.
1153 //
1154 // At present this code only copes with equality, not inequality.
1155
1156 static bool
1157 infer_handle_equal_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs, bool goal, int level)
1158 {
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);
1164
1165     bool result = false;
1166     if (goal) {
1167         
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;
1172         try {
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);
1177             if (lhs_result) {
1178                 CdlSimpleValue check;
1179                 expr->eval_subexpression(lhs_context, lhs, check);
1180                 if (lhs_value != check) {
1181                     lhs_result = false;
1182                 }
1183             }
1184         } catch (...) {
1185             lhs_result = false;
1186         }
1187         
1188         CdlTransaction  rhs_transaction = transaction->make(transaction->get_conflict());
1189         bool            rhs_result = false;
1190         try {
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);
1195             if (rhs_result) {
1196                 CdlSimpleValue check;
1197                 expr->eval_subexpression(rhs_context, rhs, check);
1198                 if (rhs_value != check) {
1199                     rhs_result = false;
1200                 }
1201             }
1202         } catch (...) {
1203             rhs_result = false;
1204         }
1205
1206         result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1207     }
1208     
1209     CYG_REPORT_RETVAL(result);
1210     return result;
1211 }
1212
1213 //}}}
1214 //{{{  infer_handle_numerical_equal()           
1215
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 <=
1219 // and >.
1220
1221 static bool
1222 infer_handle_numerical_equal_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs, bool goal, int level)
1223 {
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);
1229
1230     bool result = false;
1231     if (goal) {
1232         
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;
1237         try {
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);
1243                 if (lhs_result) {
1244                     CdlSimpleValue check;
1245                     expr->eval_subexpression(lhs_context, lhs, check);
1246                     if (lhs_value != check) {
1247                         lhs_result = false;
1248                     }
1249                 }
1250             }
1251         } catch (...) {
1252             lhs_result = false;
1253         }
1254         
1255         CdlTransaction  rhs_transaction = transaction->make(transaction->get_conflict());
1256         bool            rhs_result = false;
1257         try {
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);
1263                 if (rhs_result) {
1264                     CdlSimpleValue check;
1265                     expr->eval_subexpression(rhs_context, rhs, check);
1266                     if (rhs_value != check) {
1267                         rhs_result = false;
1268                     }
1269                 }
1270             }
1271         } catch (...) {
1272             rhs_result = false;
1273         }
1274
1275         result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1276     }
1277     
1278     CYG_REPORT_RETVAL(result);
1279     return result;
1280 }
1281
1282 //}}}
1283 //{{{  CdlInfer::subexpr_bool()                 
1284
1285 // ----------------------------------------------------------------------------
1286 bool
1287 CdlInfer::subexpr_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
1288 {
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()));
1294     
1295     bool result = false;
1296     CdlSubexpression& subexpr = expr->sub_expressions[index];
1297
1298     switch(subexpr.op) {
1299         
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.
1303           {
1304               CdlNode node = expr->references[subexpr.reference_index].get_destination();
1305               CdlValuable valuable = 0;
1306               if (0 != node) {
1307                   valuable = dynamic_cast<CdlValuable>(node);
1308               }
1309               result = infer_handle_reference_bool(transaction, valuable, goal, level);
1310               break;
1311           }
1312           
1313       case CdlExprOp_StringConstant :
1314           result = infer_handle_string_constant_bool(subexpr.constants, goal);
1315           break;
1316                                                 
1317       case CdlExprOp_IntegerConstant :
1318           result = infer_handle_integer_constant_bool(subexpr.constants, goal);
1319           break;
1320           
1321       case CdlExprOp_DoubleConstant :
1322           result = infer_handle_double_constant_bool(subexpr.constants, goal);
1323           break;
1324
1325       case CdlExprOp_LogicalNot :
1326           result = infer_handle_logical_NOT_bool(transaction, expr, subexpr.lhs_index, goal, level);
1327           break;
1328           
1329       case CdlExprOp_And :
1330           result = infer_handle_AND_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1331           break;
1332           
1333       case CdlExprOp_Or :
1334           result = infer_handle_OR_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1335           break;
1336
1337       case CdlExprOp_Implies :
1338           result = infer_handle_IMPLIES_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1339           break;
1340         
1341       case CdlExprOp_Xor :
1342           result = infer_handle_XOR_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1343           break;
1344         
1345       case CdlExprOp_Eqv :
1346           result = infer_handle_EQV_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1347           break;
1348         
1349       case CdlExprOp_Equal :
1350           result = infer_handle_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1351           break;
1352
1353       case CdlExprOp_NotEqual :
1354           result = infer_handle_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, !goal, level);
1355           break;
1356
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 :
1361           if (goal) {
1362               result = infer_handle_numerical_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, true, level);
1363           }
1364           break;
1365
1366       case CdlExprOp_LessThan :
1367       case CdlExprOp_GreaterThan :
1368           if (!goal) {
1369               result = infer_handle_numerical_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, true, level);
1370           }
1371           break;
1372           
1373       case CdlExprOp_Function :
1374           result = CdlFunction::infer_bool(transaction, expr, index, goal, level);
1375           break;
1376               
1377       default:
1378           // No other inferences are implemented at this stage.
1379           break;
1380     }
1381
1382     CYG_REPORT_RETVAL(result);
1383     return result;
1384 }
1385
1386 //}}}
1387 //{{{  CdlInfer::subexpr_value()                
1388
1389 bool
1390 CdlInfer::subexpr_value(CdlTransaction transaction, CdlExpression expr, unsigned int index, CdlSimpleValue& goal, int level)
1391 {
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()));
1397     
1398     bool result = false;
1399     CdlSubexpression& subexpr = expr->sub_expressions[index];
1400
1401     switch(subexpr.op) {
1402         
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.
1406           {
1407               CdlNode node = expr->references[subexpr.reference_index].get_destination();
1408               CdlValuable valuable = 0;
1409               if (0 != node) {
1410                   valuable = dynamic_cast<CdlValuable>(node);
1411               }
1412               result = infer_handle_reference_value(transaction, valuable, goal, level);
1413               break;
1414           }
1415           
1416       case CdlExprOp_StringConstant     :
1417           result = infer_handle_string_constant_value(subexpr.constants, goal);
1418           break;
1419                                                 
1420       case CdlExprOp_IntegerConstant    :
1421           result = infer_handle_integer_constant_value(subexpr.constants, goal);
1422           break;
1423           
1424       case CdlExprOp_DoubleConstant     :
1425           result = infer_handle_double_constant_value(subexpr.constants, goal);
1426           break;
1427
1428       case CdlExprOp_LogicalNot         :
1429       case CdlExprOp_And                :
1430       case CdlExprOp_Or                 :
1431       case CdlExprOp_Implies            :
1432       case CdlExprOp_Xor                :
1433       case CdlExprOp_Eqv                :
1434       {
1435           bool  new_goal = true;
1436           if (("0" == goal.get_value()) || ("" == goal.get_value())) {
1437               new_goal = false;
1438           }
1439           result = CdlInfer::subexpr_bool(transaction, expr, index, new_goal, level);
1440           break;
1441       }
1442           
1443       case CdlExprOp_Function :
1444           result = CdlFunction::infer_value(transaction, expr, index, goal, level);
1445           break;
1446         
1447       default:
1448           // No other inferences are implemented at this stage.
1449           break;
1450     }
1451
1452     CYG_REPORT_RETVAL(result);
1453     return result;
1454 }
1455
1456 //}}}
1457
1458 //}}}
1459 //{{{  Illegal value resolution                 
1460
1461 // ----------------------------------------------------------------------------
1462 // This is not yet implemented.
1463
1464 bool
1465 CdlConflict_IllegalValueBody::inner_resolve(CdlTransaction transaction, int level)
1466 {
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);
1471
1472     CYG_UNUSED_PARAM(CdlTransaction, transaction);
1473     
1474     CYG_REPORT_RETVAL(false);
1475     return false;
1476 }
1477
1478 //}}}
1479 //{{{  Requires resolution                      
1480
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.
1490 //
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,
1494 // or both.
1495 //
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.
1503 //
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:
1512 //
1513 // 1) change the terms in the expression to make it evaluate to
1514 //    true.
1515 // 2) disable the source so that the requires property is no longer
1516 //    relevant.
1517 // 3) make the source inactive, with the same effect.
1518 //
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
1524 // be tried.
1525
1526 bool
1527 CdlConflict_RequiresBody::inner_resolve(CdlTransaction transaction, int level)
1528 {
1529     CYG_REPORT_FUNCNAME("CdlConflict_Requires::inner_resolve");
1530     CYG_REPORT_FUNCARG3XV(this, transaction, level);
1531     CYG_PRECONDITION_THISC();
1532     CYG_PRECONDITION_CLASSC(transaction);
1533
1534     bool result = false;
1535
1536     CdlProperty_GoalExpression  gexpr   = dynamic_cast<CdlProperty_GoalExpression>(this->get_property());
1537     CdlExpression               expr    = gexpr->get_expression();
1538     
1539     // Only create the sub-transactions when needed.
1540     CdlTransaction expr_transaction     = 0;
1541     CdlTransaction disable_transaction  = 0;
1542     CdlTransaction inactive_transaction = 0;
1543
1544     // Keep track of the preferred solution found to date.
1545     CdlTransaction preferred_transaction = 0;
1546
1547     expr_transaction = transaction->make(this);
1548     if (!CdlInfer::subexpr_bool(expr_transaction, expr, expr->first_subexpression, true, level)) {
1549         // No luck here.
1550         expr_transaction->cancel();
1551         delete expr_transaction;
1552         expr_transaction = 0;
1553     } else {
1554         // We have a possible solution. How acceptable is it?
1555         if (!expr_transaction->user_confirmation_required()) {
1556             // Whoopee.
1557             expr_transaction->commit();
1558             delete expr_transaction;
1559             result = true;
1560             CYG_REPORT_RETVAL(result);
1561             return result;
1562         } else {
1563             // Maybe we can do better.
1564             preferred_transaction = expr_transaction;
1565             expr_transaction = 0;
1566         }
1567     }
1568
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);
1572
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;
1580         } else {
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;
1588                 }
1589                 result = true;
1590                 CYG_REPORT_RETVAL(result);
1591                 return 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;
1599             } else {
1600                 disable_transaction->cancel();
1601                 delete disable_transaction;
1602                 disable_transaction = 0;
1603             }
1604         }
1605     }
1606
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;
1615     } else {
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;
1623             }
1624             result = true;
1625             CYG_REPORT_RETVAL(result);
1626             return 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;
1634         } else {
1635             inactive_transaction->cancel();
1636             delete inactive_transaction;
1637             inactive_transaction = 0;
1638         }
1639     }
1640
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;
1646         result = true;
1647     }
1648     
1649     CYG_REPORT_RETVAL(result);
1650     return result;
1651 }
1652
1653 //}}}