OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [libcdl/] [infer.cxx] - Blame information for rev 857

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//{{{  Banner                                   
2
 
3
//============================================================================
4
//
5
//      infer.cxx
6
//
7
//      Inference for common conflicts.
8
//
9
//============================================================================
10
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####                                        
11
// -------------------------------------------                              
12
// This file is part of the eCos host tools.                                
13
// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.            
14
//
15
// This program is free software; you can redistribute it and/or modify     
16
// it under the terms of the GNU General Public License as published by     
17
// the Free Software Foundation; either version 2 or (at your option) any   
18
// later version.                                                           
19
//
20
// This program is distributed in the hope that it will be useful, but      
21
// WITHOUT ANY WARRANTY; without even the implied warranty of               
22
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
23
// General Public License for more details.                                 
24
//
25
// You should have received a copy of the GNU General Public License        
26
// along with this program; if not, write to the                            
27
// Free Software Foundation, Inc., 51 Franklin Street,                      
28
// Fifth Floor, Boston, MA  02110-1301, USA.                                
29
// -------------------------------------------                              
30
// ####ECOSHOSTGPLCOPYRIGHTEND####                                          
31
//============================================================================
32
//#####DESCRIPTIONBEGIN####
33
//
34
// Author(s):   bartv
35
// Contact(s):  bartv
36
// Date:        1999/11/1
37
// Version:     0.01
38
//
39
//####DESCRIPTIONEND####
40
//============================================================================
41
 
42
//}}}
43
//{{{  #include's                               
44
 
45
// ----------------------------------------------------------------------------
46
#include "cdlconfig.h"
47
 
48
// Get the infrastructure types, assertions, tracing and similar
49
// facilities.
50
#include <cyg/infra/cyg_ass.h>
51
#include <cyg/infra/cyg_trac.h>
52
 
53
// <cdlcore.hxx> defines everything implemented in this module.
54
// It implicitly supplies <string>, <vector> and <map> because
55
// the class definitions rely on these headers.
56
#include <cdlcore.hxx>
57
 
58
//}}}
59
 
60
//{{{  CdlInfer class                           
61
 
62
//{{{  Description                              
63
 
64
// ----------------------------------------------------------------------------
65
// The following functions provide the main entry points for inference.
66
//
67
// 1) bool CdlInfer::make_active(CdlTransaction, CdlValuable, level)
68
//    Do whatever it takes to make the valuable active in
69
//    a clean sub-transaction, if possible.
70
// 2) bool CdlInfer::make_inactive(CdlTransaction, CdlValuable, level)
71
//    Do whatever it takes to make the valuable inactive.
72
// 3) bool CdlInfer::set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, level)
73
//    Try to set the valuable to the specified value, taking into
74
//    account the different flavors.
75
// 4) bool CdlInfer::set_valuable_bool(CdlTransaction, CdlValuable, bool, level)
76
//    Similar to (3) but deals with the boolean aspect of the valuable
77
//    rather than the data part.
78
// 5) bool CdlInfer::subexpr(CdlTransaction, CdlExpression, int index, CdlSimpleValue& goal, level)
79
//    Process a sub-expression and try to make it evaluate to the
80
//    goal.
81
// 6) bool CdlInfer::subexpr_bool(CdlTransaction, CdlExpression, int index, bool goal, level)
82
//    Ditto but only deal with boolean goals. If the expression starts to
83
//    involve arithmetic etc. then we need to move to CdlInfer::subexpr()
84
//
85
//    As might be expected, the sub-expression handlers contain a big
86
//    switch statement and calls into various auxiliary functions when
87
//    necessary.
88
//
89
// For convenience the various entry points check whether or not the
90
// desired condition is already satisfied.
91
 
92
//}}}
93
//{{{  Forward declarations                     
94
 
95
// ----------------------------------------------------------------------------
96
 
97
static bool infer_handle_interface_value(CdlTransaction, CdlInterface, CdlSimpleValue&, int);
98
static bool infer_handle_reference_bool(CdlTransaction, CdlValuable, bool, int);
99
 
100
//}}}
101
//{{{  CdlInfer::make_active()                  
102
 
103
// ----------------------------------------------------------------------------
104
// Making a node active. This requires the following conditions to be
105
// satisfied:
106
// 1) the parent must be made active
107
// 2) if the parent has flavor bool or booldata, it must be enabled
108
// 3) any active_if properties 
109
 
110
bool
111
CdlInfer::make_active(CdlTransaction transaction, CdlNode node, int level)
112
{
113
    CYG_REPORT_FUNCNAMETYPE("CdlInfer::make_active", "result %d");
114
    CYG_REPORT_FUNCARG3XV(transaction, node, level);
115
    CYG_PRECONDITION_CLASSC(transaction);
116
    CYG_PRECONDITION_CLASSC(node);
117
 
118
    bool result = false;
119
    if (transaction->is_active(node)) {
120
        result = true;
121
        CYG_REPORT_RETVAL(result);
122
        return result;
123
    }
124
 
125
    CdlContainer parent = node->get_parent();
126
    CYG_ASSERT_CLASSC(parent);
127
    if (!transaction->is_active(parent)) {
128
        if (!CdlInfer::make_active(transaction, parent, level)) {
129
            CYG_REPORT_RETVAL(result);
130
            return result;
131
        }
132
    }
133
    // The parent is now active. Does it have to be enabled as well?
134
    CdlValuable parent_valuable = dynamic_cast<CdlValuable>(static_cast<CdlNode>(parent));
135
    if (0 != parent_valuable) {
136
        CdlValueFlavor flavor = parent_valuable->get_flavor();
137
        if (((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) &&
138
            !parent_valuable->is_enabled(transaction)) {
139
            if (!CdlInfer::set_valuable_bool(transaction, parent_valuable, true, level)) {
140
                CYG_REPORT_RETVAL(result);
141
                return result;
142
            }
143
        }
144
    }
145
    // The parent is now active and enabled. Are there any active_if properties to worry about?
146
    CdlValuable valuable = dynamic_cast<CdlValuable>(node);
147
    if (0 != valuable) {
148
        std::vector<CdlProperty_GoalExpression> active_if_goals;
149
        std::vector<CdlProperty_GoalExpression>::iterator goal_i;
150
        valuable->get_active_if_conditions(active_if_goals);
151
        for (goal_i = active_if_goals.begin(); goal_i != active_if_goals.end(); goal_i++) {
152
 
153
            CdlEvalContext context(transaction, valuable, *goal_i);
154
            try {
155
                if (!(*goal_i)->eval(context)) {
156
                    CdlExpression expr = (*goal_i)->get_expression();
157
                    if (!CdlInfer::subexpr_bool(transaction, expr, expr->first_subexpression, true, level)) {
158
                        CYG_REPORT_RETVAL(result);
159
                        return result;
160
                    }
161
                }
162
            } catch(...) {
163
                CYG_REPORT_RETVAL(result);
164
                return result;
165
            }
166
        }
167
 
168
    }
169
 
170
    result = transaction->is_active(node);
171
    CYG_REPORT_RETVAL(result);
172
    return result;
173
}
174
 
175
//}}}
176
//{{{  CdlInfer::make_inactive()                
177
 
178
// ----------------------------------------------------------------------------
179
// Making a node inactive can be done in three ways:
180
// 1) if the parent is boolean, try disabling it
181
// 2) otherwise if the parent can be made inactive, that will do
182
//    fine.
183
// 3) if there are any active_if properties, they could be considered
184
//    as well. For now this possibility is ignored.
185
 
186
bool
187
CdlInfer::make_inactive(CdlTransaction transaction, CdlNode node, int level)
188
{
189
    CYG_REPORT_FUNCNAMETYPE("CdlInfer::make_inactive", "result %d");
190
    CYG_REPORT_FUNCARG3XV(transaction, node, level);
191
    CYG_PRECONDITION_CLASSC(transaction);
192
    CYG_PRECONDITION_CLASSC(node);
193
 
194
    bool result = false;
195
    if (!transaction->is_active(node)) {
196
        result = true;
197
        CYG_REPORT_RETVAL(result);
198
        return result;
199
    }
200
 
201
    CdlContainer parent = node->get_parent();
202
    if (0 == parent) {
203
        // No point in trying to disable the entire configuration.
204
        CYG_REPORT_RETVAL(result);
205
        return result;
206
    }
207
 
208
    CdlValuable  parent_valuable = dynamic_cast<CdlValuable>(parent);
209
    if (0 != parent_valuable) {
210
        CdlValueFlavor flavor = parent_valuable->get_flavor();
211
        if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
212
            // Since the current node is active the parent must currently be enabled.
213
            // A sub-transaction is needed because an alternative approach is
214
            // possible later on.
215
            CdlTransaction subtransaction = transaction->make(transaction->get_conflict());
216
            if (CdlInfer::set_valuable_bool(subtransaction, parent_valuable, false, level)) {
217
                subtransaction->commit();
218
                delete subtransaction;
219
                result = true;
220
                CYG_REPORT_RETVAL(result);
221
                return result;
222
            } else {
223
                subtransaction->cancel();
224
                delete subtransaction;
225
            }
226
        }
227
    }
228
 
229
    // It is not possible to disable the parent. How about making it inactive?
230
    if (CdlInfer::make_inactive(transaction, parent, level)) {
231
        result = true;
232
        CYG_REPORT_RETVAL(result);
233
        return result;
234
    }
235
 
236
    // For now do not try to mess about with active_if conditions.
237
 
238
    CYG_REPORT_RETVAL(result);
239
    return result;
240
}
241
 
242
//}}}
243
//{{{  CdlInfer::set_valuable_value()           
244
 
245
// ----------------------------------------------------------------------------
246
// Deal with the value part of a valuable. The valuable is known to exist
247
// and be active, so this code only deals with the actual value part.
248
 
249
bool
250
CdlInfer::set_valuable_value(CdlTransaction transaction, CdlValuable valuable, CdlSimpleValue& goal, int level)
251
{
252
    CYG_REPORT_FUNCNAMETYPE("CdlInfer::set_valuable_value", "result %d");
253
    CYG_REPORT_FUNCARG3XV(transaction, valuable, level);
254
    CYG_PRECONDITION_CLASSC(transaction);
255
    CYG_PRECONDITION_CLASSC(valuable);
256
    CYG_PRECONDITIONC(transaction->is_active(valuable));
257
 
258
    bool result = false;
259
 
260
    const CdlValue& current_value = transaction->get_whole_value(valuable);
261
    CdlValueFlavor  flavor        = current_value.get_flavor();
262
    bool bool_goal                = goal.get_bool_value();
263
 
264
    switch(flavor) {
265
      default                  :
266
      case CdlValueFlavor_None :
267
          break;
268
 
269
      case CdlValueFlavor_Bool :
270
          if (bool_goal == current_value.is_enabled()) {
271
              result = true;
272
          } else {
273
              if (valuable->is_modifiable() &&
274
                  (0 == dynamic_cast<CdlLoadable>(valuable)) &&
275
                  !transaction->changed_by_user(valuable)) {
276
 
277
                  valuable->set_enabled(transaction, bool_goal, CdlValueSource_Inferred);
278
                  valuable->set_source(transaction, CdlValueSource_Inferred);
279
                  result = transaction->resolve_recursion(level);
280
              }
281
 
282
          }
283
          break;
284
 
285
      case CdlValueFlavor_BoolData :
286
          if (!bool_goal && !current_value.is_enabled()) {
287
              result = true;
288
          } else if (bool_goal && current_value.is_enabled() && (goal == current_value.get_simple_value())) {
289
              result = true;
290
          } else {
291
              if (valuable->is_modifiable() &&
292
                  (0 == dynamic_cast<CdlLoadable>(valuable)) &&
293
                  !transaction->changed_by_user(valuable)) {
294
 
295
                  if (!bool_goal) {
296
                      valuable->disable(transaction, CdlValueSource_Inferred);
297
                  } else {
298
                      valuable->enable_and_set_value(transaction, goal, CdlValueSource_Inferred);
299
                  }
300
                  valuable->set_source(transaction, CdlValueSource_Inferred);
301
                  result = transaction->resolve_recursion(level);
302
              } else if (0 != dynamic_cast<CdlInterface>(valuable)) {
303
                  // Interfaces are not directly modifiable, but their implementors are.
304
                  result = infer_handle_interface_value(transaction, dynamic_cast<CdlInterface>(valuable), goal, level);
305
              }
306
          }
307
          break;
308
 
309
      case CdlValueFlavor_Data:
310
        // Now check whether or not the valuable already has the desired value
311
        if (goal == current_value.get_simple_value()) {
312
            result = true;
313
        } else {
314
            if (valuable->is_modifiable() &&
315
                (0 == dynamic_cast<CdlLoadable>(valuable)) &&
316
                !transaction->changed_by_user(valuable)) {
317
 
318
                // Make the change, propagate, and perform further resolution.
319
                valuable->set_value(transaction, goal, CdlValueSource_Inferred);
320
                valuable->set_source(transaction, CdlValueSource_Inferred);
321
                result = transaction->resolve_recursion(level);
322
            } else if (0 != dynamic_cast<CdlInterface>(valuable)) {
323
                // Interfaces are not directly modifiable, but their implementors are.
324
                result = infer_handle_interface_value(transaction, dynamic_cast<CdlInterface>(valuable), goal, level);
325
            }
326
        }
327
        break;
328
    }
329
 
330
    CYG_REPORT_RETVAL(result);
331
    return result;
332
}
333
 
334
//}}}
335
//{{{  CdlInfer::set_valuable_bool()            
336
 
337
// ----------------------------------------------------------------------------
338
// Deal with the boolean part of a valuable. It is assumed that active vs.
339
// inactive is dealt with elsewhere so this code only needs to worry
340
// about the valuable itself.
341
 
342
bool
343
CdlInfer::set_valuable_bool(CdlTransaction transaction, CdlValuable valuable, bool goal, int level)
344
{
345
    CYG_REPORT_FUNCNAMETYPE("CdlInfer::set_valuable_bool", "result %d");
346
    CYG_REPORT_FUNCARG4XV(transaction, valuable, goal, level);
347
    CYG_PRECONDITION_CLASSC(transaction);
348
    CYG_PRECONDITION_CLASSC(valuable);
349
 
350
    bool result = false;
351
 
352
    // Examine the current flavor. If None or Data then the valuable
353
    // is always enabled. If BoolData or Boolean then the condition
354
    // may be satisfied already, otherwise an attempt must be made
355
    // to change the value and see what happens.
356
    CdlValueFlavor flavor = valuable->get_flavor();
357
    if (CdlValueFlavor_None == flavor) {
358
        if (goal) {
359
            result = true;
360
        }
361
        CYG_REPORT_RETVAL(result);
362
        return result;
363
    }
364
 
365
    if (CdlValueFlavor_Data == flavor) {
366
        std::string value = valuable->get_value(transaction);
367
        if (goal) {
368
            if (("" != value) && ("0" != value)) {
369
                result = true;
370
            }
371
        } else {
372
            if (("" == value) || ("0" == value)) {
373
                result = true;
374
            }
375
        }
376
        CYG_REPORT_RETVAL(result);
377
        return result;
378
    }
379
 
380
    CYG_ASSERTC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor));
381
    bool enabled = valuable->is_enabled(transaction);
382
    if (enabled == goal) {
383
        result = true;
384
        CYG_REPORT_RETVAL(result);
385
        return result;
386
    }
387
 
388
    // enabled != goal, and we have a boolean or booldata item.
389
    // Before we actually try making any changes, is this sensible?
390
    if (!valuable->is_modifiable() ||
391
        (0 != dynamic_cast<CdlLoadable>(valuable)) ||
392
        transaction->changed_by_user(valuable)) {
393
 
394
        CYG_REPORT_RETVAL(result);
395
        return result;
396
    }
397
    // If we are about to disable a container, better check that this would
398
    // not annoy the user either
399
    if (!goal) {
400
        CdlContainer container = dynamic_cast<CdlContainer>(valuable);
401
        if ((0 != container) && transaction->subnode_changed_by_user(container)) {
402
            CYG_REPORT_RETVAL(result);
403
            return result;
404
        }
405
    }
406
 
407
    // Try to change the state, propagate, and perform further resolution.
408
    valuable->set_enabled(transaction, goal, CdlValueSource_Inferred);
409
    valuable->set_source(transaction, CdlValueSource_Inferred);
410
    result = transaction->resolve_recursion(level);
411
 
412
    CYG_REPORT_RETVAL(result);
413
    return result;
414
}
415
 
416
//}}}
417
//{{{  infer_choose()                           
418
 
419
// ----------------------------------------------------------------------------
420
// Given two sub-transactions which may or may not have succeeded, pick the
421
// preferred one. This happens for many binary operators.
422
 
423
static bool
424
infer_lhs_preferable(CdlTransaction lhs_transaction, bool lhs_result, CdlTransaction rhs_transaction, bool rhs_result)
425
{
426
    CYG_REPORT_FUNCNAMETYPE("infer_choose2", "result %d");
427
    CYG_REPORT_FUNCARG4XV(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
428
    CYG_PRECONDITIONC(lhs_result || rhs_result);
429
 
430
    bool result = true;
431
 
432
    if (lhs_result && !rhs_result) {
433
        // Only the lhs succeeded.
434
        result = true;
435
    } else if (!lhs_result && rhs_result) {
436
        // Only the rhs succeeded.
437
        result = false;
438
    } else if (lhs_result && rhs_result) {
439
        // Both sides succeeded. Next check for user_confirmation.
440
        bool lhs_confirm_needed = lhs_transaction->user_confirmation_required();
441
        bool rhs_confirm_needed = rhs_transaction->user_confirmation_required();
442
        if (lhs_confirm_needed && !rhs_confirm_needed) {
443
            result = false;
444
        } else if (!lhs_confirm_needed && rhs_confirm_needed) {
445
            result = true;
446
        } else {
447
            // Neither or both of the two sides need user confirmation, so they
448
            // are equal in that respect
449
            if (lhs_transaction->is_preferable_to(rhs_transaction)) {
450
                result = true;
451
            } else {
452
                result = false;
453
            }
454
        }
455
    }
456
 
457
    CYG_REPORT_RETVAL(result);
458
    return result;
459
}
460
 
461
// A variant which will actually do the commits and cancels. This is
462
// commonly required when doing inferences of binary operators.
463
static bool
464
infer_choose2(CdlTransaction lhs_transaction, bool lhs_result, CdlTransaction rhs_transaction, bool rhs_result)
465
{
466
    CYG_REPORT_FUNCNAMETYPE("infer_choose2", "result %d");
467
    CYG_REPORT_FUNCARG4XV(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
468
    bool result = false;
469
 
470
    if (lhs_result || rhs_result) {
471
        bool lhs_preferable = infer_lhs_preferable(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
472
        if (lhs_preferable) {
473
            rhs_transaction->cancel();
474
            lhs_transaction->commit();
475
        } else {
476
            lhs_transaction->cancel();
477
            rhs_transaction->commit();
478
        }
479
        result = true;
480
    } else {
481
        // Neither side succeeded.
482
        lhs_transaction->cancel();
483
        rhs_transaction->cancel();
484
    }
485
 
486
    // Zero or one of these transactions will have been committed,
487
    // neither is still necessary.
488
    delete lhs_transaction;
489
    delete rhs_transaction;
490
 
491
    CYG_REPORT_RETVAL(result);
492
    return result;
493
}
494
 
495
//}}}
496
//{{{  infer_handle_interface()                 
497
 
498
// ----------------------------------------------------------------------------
499
// Set an interface to a specific value, which should be some number n.
500
// If (n == 0) then all implementers must be disabled or made inactive.
501
// If (n == 1) then exactly one of the implementers must be active and enabled.
502
// Other combinations are not considered here, they could lead to an
503
// exponential explosion.
504
 
505
static bool
506
infer_handle_interface_value(CdlTransaction transaction, CdlInterface interface, CdlSimpleValue& goal, int level)
507
{
508
    CYG_REPORT_FUNCNAMETYPE("infer_handle_reference_bool", "result %d");
509
    CYG_REPORT_FUNCARG4XV(transaction, interface, &goal, level);
510
    bool result = false;
511
 
512
    if (goal.has_integer_value()) {
513
        cdl_int real_goal = goal.get_integer_value();
514
        if (real_goal == interface->get_integer_value(transaction)) {
515
            result = true;
516
        } else if (0 == real_goal) {
517
            // All implementers must be disabled or made inactive. This
518
            // can be achieved by creating a sub-transaction and calling
519
            // infer_handle_reference_bool() on all of the implementers.
520
            //
521
            // However there are no guarantees that the result is what
522
            // is intended. Updating a later implementer may as a side
523
            // effect cause an earlier one to become active again. Also
524
            // there may be confusion with valuables with the data
525
            // flavor being given a value of 0. Hence a final check is
526
            // needed that the new interface value really is the desired goal.
527
            CdlTransaction sub_transaction;
528
            std::vector<CdlValuable> implementers;
529
            std::vector<CdlValuable>::const_iterator impl_i;
530
 
531
            sub_transaction = transaction->make(transaction->get_conflict());
532
            try {
533
                interface->get_implementers(implementers);
534
                for (impl_i = implementers.begin(); impl_i != implementers.end(); impl_i++) {
535
                    (void) infer_handle_reference_bool(sub_transaction, *impl_i, false, level);
536
                }
537
                if (0 == interface->get_integer_value(sub_transaction)) {
538
                    sub_transaction->commit();
539
                    result = true;
540
                } else {
541
                    sub_transaction->cancel();
542
                }
543
            } catch (...) {
544
                delete sub_transaction;
545
                throw;
546
            }
547
            delete sub_transaction;
548
            sub_transaction = 0;
549
 
550
        } else if (1 == real_goal) {
551
            // This is a bit trickier than the above. We need n
552
            // sub-transactions, one per implementer. In each
553
            // sub-transaction we try to set exactly one of the
554
            // implementers to enabled and the rest to disabled.
555
            std::vector<CdlValuable>    implementers;
556
            unsigned int                impl_count;
557
            unsigned int                i, j;
558
 
559
            interface->get_implementers(implementers);
560
            impl_count = implementers.size();
561
            std::vector<CdlTransaction> sub_transactions;
562
            std::vector<bool>           results;
563
 
564
            try {
565
                for (i = 0; i < impl_count; i++) {
566
                    CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
567
                    sub_transactions.push_back(sub_transaction);
568
                    results.push_back(false);
569
                    results[i]          = false;
570
                }
571
                for (i = 0; i < impl_count; i++) {
572
                    for (j = 0; j < impl_count; j++) {
573
                        (void) infer_handle_reference_bool(sub_transactions[i], implementers[j], (i == j), level);
574
                    }
575
                    if (1 == interface->get_integer_value(sub_transactions[i])) {
576
                        results[i] = true;
577
                    }
578
                }
579
 
580
                // At this point we may have some combination of successful and unsucessful
581
                // sub-transactions, and it is time to choose the best one.
582
                CdlTransaction  preferred = 0;
583
                for (i = 0; i < impl_count; i++) {
584
                    if (results[i]) {
585
                        preferred = sub_transactions[i];
586
                        break;
587
                    }
588
                }
589
 
590
                for (j = i + 1; j < impl_count; j++) {
591
                    if (results[j]) {
592
                        if (!infer_lhs_preferable(preferred, true, sub_transactions[j], true)) {
593
                            preferred = sub_transactions[j];
594
                        }
595
                    }
596
                }
597
 
598
                // Now either preferred == 0, i.e. all
599
                // sub-transactions failed and we want to cancel them
600
                // all. Or we have a viable sub-transaction.
601
                for (i = 0; i < impl_count; i++) {
602
                    if (preferred == sub_transactions[i]) {
603
                        sub_transactions[i]->commit();
604
                        result = true;
605
                    } else {
606
                        sub_transactions[i]->cancel();
607
                    }
608
                    delete sub_transactions[i];
609
                    sub_transactions[i] = 0;
610
                }
611
 
612
            } catch(...) {
613
                for (i = 0; i < sub_transactions.size(); i++) {
614
                    if (0 != sub_transactions[i]) {
615
                        sub_transactions[i]->cancel();
616
                        delete sub_transactions[i];
617
                        sub_transactions[i] = 0;
618
                    }
619
                }
620
            }
621
        }
622
    }
623
 
624
    CYG_REPORT_RETVAL(result);
625
    return result;
626
}
627
 
628
//}}}
629
//{{{  infer_handle_reference()                 
630
 
631
// ----------------------------------------------------------------------------
632
// We are processing an expression and have reached a point where we
633
// need <reference>, !<reference> or <reference>==<value>. The
634
// reference may currently be unbound, in which case 0 is the only
635
// goal that can be satisfied. If the reference is bound then it may
636
// be possible to satisfy the goal by setting the value. In addition
637
// it is necessary to worry about active vs. inactive state.
638
 
639
static bool
640
infer_handle_reference_bool(CdlTransaction transaction, CdlValuable valuable, bool goal, int level)
641
{
642
    CYG_REPORT_FUNCNAMETYPE("infer_handle_reference_bool", "result %d");
643
    CYG_REPORT_FUNCARG4XV(transaction, valuable, goal, level);
644
 
645
    bool result = false;
646
    if (0 == valuable) {
647
        if (!goal) {
648
            result = true;
649
        }
650
        CYG_REPORT_RETVAL(result);
651
        return result;
652
    }
653
 
654
    // If the valuable should evaluate to true then it must be both active
655
    // and be either enabled or have a non-zero value.
656
    if (goal) {
657
        if (!transaction->is_active(valuable)) {
658
            if (!CdlInfer::make_active(transaction, valuable, level)) {
659
                CYG_REPORT_RETVAL(result);
660
                return result;
661
            }
662
        }
663
        if (CdlInfer::set_valuable_bool(transaction, valuable, true, level)) {
664
            result = true;
665
        }
666
 
667
    } else {
668
        // If the valuable should evaluate to false then it must be either
669
        // inactive or it must be disabled or have a zero value.
670
        if (!transaction->is_active(valuable)) {
671
            // The goal is already satisfied, no need to proceed
672
            result = true;
673
            CYG_REPORT_RETVAL(result);
674
            return result;
675
        }
676
 
677
        // There is a choice to be made so two sub-transactions are
678
        // needed. Disabling is generally preferred to making inactive.
679
        CdlTransaction value_transaction    = transaction->make(transaction->get_conflict());
680
        CdlTransaction inactive_transaction = 0;
681
        bool value_result = CdlInfer::set_valuable_bool(value_transaction, valuable, false, level);
682
        if (value_result && !value_transaction->user_confirmation_required()) {
683
            value_transaction->commit();
684
            delete value_transaction;
685
            value_transaction = 0;
686
            result = true;
687
            CYG_REPORT_RETVAL(result);
688
            return result;
689
        }
690
 
691
        inactive_transaction = transaction->make(transaction->get_conflict());
692
        bool inactive_result = CdlInfer::make_inactive(inactive_transaction, valuable, level);
693
        if (!inactive_result) {
694
            if (value_result) {
695
                // Changing the value is the only solution.
696
                inactive_transaction->cancel();
697
                value_transaction->commit();
698
                result = true;
699
            } else {
700
                inactive_transaction->cancel();
701
                value_transaction->cancel();
702
                result = false;
703
            }
704
        } else {
705
            if (!value_result) {
706
                // Making the valuable inactive is the only solution.
707
                value_transaction->cancel();
708
                inactive_transaction->commit();
709
                result = true;
710
            } else if (!inactive_transaction->user_confirmation_required()) {
711
                // Disabling the valuable would require user confirmation, making it inactive does not
712
                value_transaction->cancel();
713
                inactive_transaction->commit();
714
                result = true;
715
            } else {
716
                // Both approaches are valid but would require user confirmation.
717
                // Pick the preferred one.
718
                if (value_transaction->is_preferable_to(inactive_transaction)) {
719
                    inactive_transaction->cancel();
720
                    value_transaction->commit();
721
                    result = true;
722
                } else {
723
                    value_transaction->cancel();
724
                    inactive_transaction->commit();
725
                    result = true;
726
                }
727
            }
728
        }
729
 
730
        delete value_transaction;
731
        delete inactive_transaction;
732
        value_transaction = 0;
733
        inactive_transaction = 0;
734
    }
735
 
736
    CYG_REPORT_RETVAL(result);
737
    return result;
738
}
739
 
740
// ----------------------------------------------------------------------------
741
// Try to set a valuable to a particular value. Of course the reference
742
// may not be bound yet.
743
//
744
// First check whether or not the valuable is currently active. If it is
745
// inactive and the goal is 0 then we have succeeded. If it is active and
746
// the goal is 0 then we could try to make the valuable inactive, but
747
// this possibility is ignored for now in case it leads to unexpected
748
// behaviour. If it is active then we try to set the value, using
749
// CdlInfer::set_valuable_value().
750
 
751
static bool
752
infer_handle_reference_value(CdlTransaction transaction, CdlValuable valuable, CdlSimpleValue& goal, int level)
753
{
754
    CYG_REPORT_FUNCNAMETYPE("infer_handle_reference", "result %d");
755
    CYG_REPORT_FUNCARG3XV(transaction, valuable, level);
756
 
757
    bool result = false;
758
 
759
    if (0 == valuable) {
760
        if (goal == (cdl_int) 0) {
761
            result = true;
762
        }
763
    } else {
764
 
765
        bool active = transaction->is_active(valuable);
766
        if (!active) {
767
            if (goal == (cdl_int) 0) {
768
                result = true;
769
            }
770
        } else {
771
            result = CdlInfer::set_valuable_value(transaction, valuable, goal, level);
772
        }
773
    }
774
 
775
    CYG_REPORT_RETVAL(result);
776
    return result;
777
}
778
 
779
//}}}
780
//{{{  infer_handle_xxx_constant()              
781
 
782
// ----------------------------------------------------------------------------
783
// Somewhere in the expression processing we have encountered a string
784
// constant. The expression cannot be changed, so either the goal matches
785
// the constant or it does not.
786
static bool
787
infer_handle_string_constant_bool(CdlSimpleValue& constant, bool goal)
788
{
789
    CYG_REPORT_FUNCNAMETYPE("infer_handle_string_constant_bool", "result %d");
790
    bool result = false;
791
 
792
    if (goal) {
793
        if (("" != constant.get_value()) && ("0" != constant.get_value())) {
794
            result = true;
795
        }
796
    } else {
797
        if (("" == constant.get_value()) || ("0" == constant.get_value())) {
798
            result = true;
799
        }
800
    }
801
 
802
    CYG_REPORT_RETVAL(result);
803
    return result;
804
}
805
 
806
static bool
807
infer_handle_string_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
808
{
809
    CYG_REPORT_FUNCNAMETYPE("infer_handle_string_constant_value", "result %d");
810
    bool result = false;
811
 
812
    if (constant.get_value() == goal.get_value()) {
813
        result = true;
814
    }
815
 
816
    CYG_REPORT_RETVAL(result);
817
    return result;
818
}
819
 
820
// ----------------------------------------------------------------------------
821
// Integers are also fairly straightforward.
822
static bool
823
infer_handle_integer_constant_bool(CdlSimpleValue& constant, bool goal)
824
{
825
    CYG_REPORT_FUNCNAMETYPE("infer_handle_integer_constant_bool", "result %d");
826
    CYG_PRECONDITIONC(constant.has_integer_value());
827
    bool result = false;
828
 
829
    if (goal) {
830
        if (0 != constant.get_integer_value()) {
831
            result = true;
832
        }
833
    } else {
834
        if (0 == constant.get_integer_value()) {
835
            result = true;
836
        }
837
    }
838
 
839
    CYG_REPORT_RETVAL(result);
840
    return result;
841
}
842
 
843
static bool
844
infer_handle_integer_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
845
{
846
    CYG_REPORT_FUNCNAMETYPE("infer_handle_integer_constant_value", "result %d");
847
    CYG_PRECONDITIONC(constant.has_integer_value());
848
    bool result = false;
849
 
850
    if (goal.has_integer_value() && (constant.get_integer_value() == goal.get_integer_value())) {
851
        result = true;
852
    }
853
 
854
    CYG_REPORT_RETVAL(result);
855
    return result;
856
}
857
 
858
// ----------------------------------------------------------------------------
859
// Doubles are also straightforward, except than an exact comparision may
860
// be too strict. There is not a lot that can be done about this right now.
861
// Future enhancements to CDL may support tolerances.
862
static bool
863
infer_handle_double_constant_bool(CdlSimpleValue& constant, bool goal)
864
{
865
    CYG_REPORT_FUNCNAMETYPE("infer_handle_double_constant_bool", "result %d");
866
    CYG_PRECONDITIONC(constant.has_double_value());
867
    bool result = false;
868
 
869
    if (goal) {
870
        if (0.0 != constant.get_double_value()) {
871
            result = true;
872
        }
873
    } else {
874
        if (0.0 == constant.get_double_value()) {
875
            result = true;
876
        }
877
    }
878
 
879
    CYG_REPORT_RETVAL(result);
880
    return result;
881
}
882
 
883
static bool
884
infer_handle_double_constant_value(CdlSimpleValue& constant, CdlSimpleValue& goal)
885
{
886
    CYG_REPORT_FUNCNAMETYPE("infer_handle_double_constant_value", "result %d");
887
    CYG_PRECONDITIONC(constant.has_double_value());
888
    bool result = false;
889
 
890
    if (goal.has_double_value() && (constant.get_double_value() == goal.get_double_value())) {
891
        result = true;
892
    }
893
 
894
    CYG_REPORT_RETVAL(result);
895
    return result;
896
}
897
 
898
//}}}
899
//{{{  infer_handle_logical_xxx()               
900
 
901
// ----------------------------------------------------------------------------
902
// Logical not simply involves inverting the goal and then trying to infer
903
// the rest of the sub-expression. There is little point in touching
904
// the other arguments.
905
static bool
906
infer_handle_logical_NOT_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
907
{
908
    CYG_REPORT_FUNCNAMETYPE("infer_handle_logical_NOT_bool", "result %d");
909
 
910
    bool result = CdlInfer::subexpr_bool(transaction, expr, index, !goal, level);
911
    CYG_REPORT_RETVAL(result);
912
    return result;
913
}
914
 
915
// ----------------------------------------------------------------------------
916
// Depending on the goal, we want either both sides of the AND to evaluate to
917
// true, or we want one of the sides to evaluate to false.
918
static bool
919
infer_handle_AND_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
920
                      bool goal, int level)
921
{
922
    CYG_REPORT_FUNCNAMETYPE("infer_handle_AND_bool", "result %d");
923
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
924
    CYG_PRECONDITION_CLASSC(transaction);
925
    CYG_PRECONDITION_CLASSC(expr);
926
    CYG_PRECONDITIONC(lhs != rhs);
927
 
928
    bool result = false;
929
 
930
    if (goal) {
931
        // Both sides must be true in the same transaction, in case
932
        // the solutions overlap in conflicting ways. A sub-transaction
933
        // is still used to avoid polluting current values if the lhs
934
        // can be inferred but not the rhs.
935
        CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
936
        if (CdlInfer::subexpr_bool(sub_transaction, expr, lhs, true, level) &&
937
            CdlInfer::subexpr_bool(sub_transaction, expr, rhs, true, level)) {
938
            sub_transaction->commit();
939
            result = true;
940
        } else {
941
            sub_transaction->cancel();
942
        }
943
        delete sub_transaction;
944
    } else {
945
        // We need to try out both sides of the OR and see which one is preferable.
946
        // An optimization would be to only try the LHS, but trying both allows
947
        // for a more informed choice.
948
        CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
949
        CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
950
        bool lhs_result = CdlInfer::subexpr_bool(lhs_transaction, expr, lhs, false, level);
951
        bool rhs_result = CdlInfer::subexpr_bool(rhs_transaction, expr, rhs, false, level);
952
 
953
        result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
954
    }
955
 
956
    CYG_REPORT_RETVAL(result);
957
    return result;
958
}
959
 
960
// ----------------------------------------------------------------------------
961
// The support for the other logical operations involves basically minor
962
// variants of the above.
963
 
964
static bool
965
infer_handle_OR_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
966
                     bool goal, int level)
967
{
968
    CYG_REPORT_FUNCNAMETYPE("infer_handle_OR_bool", "result %d");
969
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
970
    CYG_PRECONDITION_CLASSC(transaction);
971
    CYG_PRECONDITION_CLASSC(expr);
972
    CYG_PRECONDITIONC(lhs != rhs);
973
 
974
 
975
    bool result = false;
976
 
977
    if (goal) {
978
        // We need to try out both sides of the OR and see which one is preferable.
979
        // An optimization would be to only try the LHS, but trying both allows
980
        // for a more informed choice.
981
        CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
982
        CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
983
        bool lhs_result = CdlInfer::subexpr_bool(lhs_transaction, expr, lhs, true, level);
984
        bool rhs_result = CdlInfer::subexpr_bool(rhs_transaction, expr, rhs, true, level);
985
 
986
        result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
987
    } else {
988
 
989
        // !(A || B) -> !A && !B
990
        CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
991
        if (CdlInfer::subexpr_bool(sub_transaction, expr, lhs, false, level) &&
992
            CdlInfer::subexpr_bool(sub_transaction, expr, rhs, false, level)) {
993
            sub_transaction->commit();
994
            result = true;
995
        } else {
996
            sub_transaction->cancel();
997
        }
998
        delete sub_transaction;
999
    }
1000
 
1001
    CYG_REPORT_RETVAL(result);
1002
    return result;
1003
}
1004
 
1005
// ----------------------------------------------------------------------------
1006
 
1007
static bool
1008
infer_handle_IMPLIES_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1009
                     bool goal, int level)
1010
{
1011
    CYG_REPORT_FUNCNAMETYPE("infer_handle_implies_bool", "result %d");
1012
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1013
    CYG_PRECONDITION_CLASSC(transaction);
1014
    CYG_PRECONDITION_CLASSC(expr);
1015
    CYG_PRECONDITIONC(lhs != rhs);
1016
 
1017
 
1018
    bool result = false;
1019
 
1020
    if (goal) {
1021
        // A implies B -> !A || B
1022
        // Given a choice between !A or B, arguably the "implies"
1023
        // operator has the connotation that B is preferred. All other
1024
        // things being equal, infer_choose2() will prefer the rhs
1025
        // over the lhs so this is achieved automagically.
1026
 
1027
        CdlTransaction lhs_transaction = transaction->make(transaction->get_conflict());
1028
        CdlTransaction rhs_transaction = transaction->make(transaction->get_conflict());
1029
        bool lhs_result = CdlInfer::subexpr_bool(lhs_transaction, expr, lhs, false, level);
1030
        bool rhs_result = CdlInfer::subexpr_bool(rhs_transaction, expr, rhs, true, level);
1031
 
1032
        result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1033
 
1034
    } else {
1035
 
1036
        // !(A implies B) -> !(!A || B) -> (A && !B)
1037
        CdlTransaction sub_transaction = transaction->make(transaction->get_conflict());
1038
        if (CdlInfer::subexpr_bool(sub_transaction, expr, lhs, true, level) &&
1039
            CdlInfer::subexpr_bool(sub_transaction, expr, rhs, false, level)) {
1040
            sub_transaction->commit();
1041
            result = true;
1042
        } else {
1043
            sub_transaction->cancel();
1044
        }
1045
        delete sub_transaction;
1046
    }
1047
 
1048
    CYG_REPORT_RETVAL(result);
1049
    return result;
1050
}
1051
 
1052
// ----------------------------------------------------------------------------
1053
 
1054
static bool
1055
infer_handle_XOR_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1056
                     bool goal, int level)
1057
{
1058
    CYG_REPORT_FUNCNAMETYPE("infer_handle_XOR_bool", "result %d");
1059
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1060
    CYG_PRECONDITION_CLASSC(transaction);
1061
    CYG_PRECONDITION_CLASSC(expr);
1062
    CYG_PRECONDITIONC(lhs != rhs);
1063
 
1064
 
1065
    bool result = false;
1066
 
1067
    if (goal) {
1068
        // (A xor B) -> (A && !B) || (!A && B)
1069
 
1070
        CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1071
        CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1072
        bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, true, level) &&
1073
                        CdlInfer::subexpr_bool(sub1, expr, rhs, false, level));
1074
        bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, false, level) &&
1075
                        CdlInfer::subexpr_bool(sub2, expr, rhs, true, level));
1076
 
1077
        result = infer_choose2(sub1, result1, sub2, result2);
1078
 
1079
    } else {
1080
 
1081
        // !(A xor B) -> (!A && !B) || (A && B)
1082
        CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1083
        CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1084
        bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, false, level) &&
1085
                        CdlInfer::subexpr_bool(sub1, expr, rhs, false, level));
1086
        bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, true, level) &&
1087
                        CdlInfer::subexpr_bool(sub2, expr, rhs, true, level));
1088
 
1089
        result = infer_choose2(sub1, result1, sub2, result2);
1090
    }
1091
 
1092
    CYG_REPORT_RETVAL(result);
1093
    return result;
1094
}
1095
 
1096
// ----------------------------------------------------------------------------
1097
 
1098
static bool
1099
infer_handle_EQV_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs,
1100
                     bool goal, int level)
1101
{
1102
    CYG_REPORT_FUNCNAMETYPE("infer_handle_EQV_bool", "result %d");
1103
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1104
    CYG_PRECONDITION_CLASSC(transaction);
1105
    CYG_PRECONDITION_CLASSC(expr);
1106
    CYG_PRECONDITIONC(lhs != rhs);
1107
 
1108
 
1109
    bool result = false;
1110
 
1111
    if (goal) {
1112
        // (A eqv B) -> (A && B) || (!A && !B)
1113
 
1114
        CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1115
        CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1116
        bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, true, level) &&
1117
                        CdlInfer::subexpr_bool(sub1, expr, rhs, true, level));
1118
        bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, false, level) &&
1119
                        CdlInfer::subexpr_bool(sub2, expr, rhs, false, level));
1120
 
1121
        result = infer_choose2(sub1, result1, sub2, result2);
1122
    } else {
1123
        // !(A eqv B) -> (A && !B) || (!A && B)
1124
 
1125
        CdlTransaction sub1 = transaction->make(transaction->get_conflict());
1126
        CdlTransaction sub2 = transaction->make(transaction->get_conflict());
1127
        bool result1 = (CdlInfer::subexpr_bool(sub1, expr, lhs, true, level) &&
1128
                        CdlInfer::subexpr_bool(sub1, expr, rhs, false, level));
1129
        bool result2 = (CdlInfer::subexpr_bool(sub2, expr, lhs, false, level) &&
1130
                        CdlInfer::subexpr_bool(sub2, expr, rhs, true, level));
1131
 
1132
        result = infer_choose2(sub1, result1, sub2, result2);
1133
    }
1134
 
1135
    CYG_REPORT_RETVAL(result);
1136
    return result;
1137
}
1138
 
1139
//}}}
1140
//{{{  infer_handle_Equal()                     
1141
 
1142
// ----------------------------------------------------------------------------
1143
// Handle expressions of the form A == B. This can be achieved either by
1144
// evaluating B and trying to assign the result to A, or vice versa. There
1145
// is a problem if assigning to one side has a side effect on the other, e.g.
1146
//
1147
//   requires { xyzzy == (xyzzy + 3) }
1148
//
1149
// This has to be guarded against by reevaluating the expression.
1150
//
1151
// At present this code only copes with equality, not inequality.
1152
 
1153
static bool
1154
infer_handle_equal_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs, bool goal, int level)
1155
{
1156
    CYG_REPORT_FUNCNAMETYPE("infer_handle_equal_bool", "result %d");
1157
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1158
    CYG_PRECONDITION_CLASSC(transaction);
1159
    CYG_PRECONDITION_CLASSC(expr);
1160
    CYG_PRECONDITIONC(lhs != rhs);
1161
 
1162
    bool result = false;
1163
    if (goal) {
1164
 
1165
        // We need two sub-transactions, The lhs_transaction is for evaluating the lhs
1166
        // and trying to update the rhs. 
1167
        CdlTransaction  lhs_transaction = transaction->make(transaction->get_conflict());
1168
        bool            lhs_result = false;
1169
        try {
1170
            CdlSimpleValue  lhs_value;
1171
            CdlEvalContext  lhs_context(lhs_transaction);
1172
            expr->eval_subexpression(lhs_context, lhs, lhs_value);
1173
            lhs_result = CdlInfer::subexpr_value(lhs_transaction, expr, rhs, lhs_value, level);
1174
            if (lhs_result) {
1175
                CdlSimpleValue check;
1176
                expr->eval_subexpression(lhs_context, lhs, check);
1177
                if (lhs_value != check) {
1178
                    lhs_result = false;
1179
                }
1180
            }
1181
        } catch (...) {
1182
            lhs_result = false;
1183
        }
1184
 
1185
        CdlTransaction  rhs_transaction = transaction->make(transaction->get_conflict());
1186
        bool            rhs_result = false;
1187
        try {
1188
            CdlSimpleValue  rhs_value;
1189
            CdlEvalContext  rhs_context(rhs_transaction);
1190
            expr->eval_subexpression(rhs_context, rhs, rhs_value);
1191
            rhs_result = CdlInfer::subexpr_value(rhs_transaction, expr, lhs, rhs_value, level);
1192
            if (rhs_result) {
1193
                CdlSimpleValue check;
1194
                expr->eval_subexpression(rhs_context, rhs, check);
1195
                if (rhs_value != check) {
1196
                    rhs_result = false;
1197
                }
1198
            }
1199
        } catch (...) {
1200
            rhs_result = false;
1201
        }
1202
 
1203
        result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1204
    }
1205
 
1206
    CYG_REPORT_RETVAL(result);
1207
    return result;
1208
}
1209
 
1210
//}}}
1211
//{{{  infer_handle_numerical_equal()           
1212
 
1213
// ----------------------------------------------------------------------------
1214
// Handle expressions of the form A == B, where the comparison has to be
1215
// numerical in basis. This is used primarily for operators like <=
1216
// and >.
1217
 
1218
static bool
1219
infer_handle_numerical_equal_bool(CdlTransaction transaction, CdlExpression expr, unsigned int lhs, unsigned int rhs, bool goal, int level)
1220
{
1221
    CYG_REPORT_FUNCNAMETYPE("infer_handle_numerical_equal_bool", "result %d");
1222
    CYG_REPORT_FUNCARG4XV(transaction, expr, lhs, rhs);
1223
    CYG_PRECONDITION_CLASSC(transaction);
1224
    CYG_PRECONDITION_CLASSC(expr);
1225
    CYG_PRECONDITIONC(lhs != rhs);
1226
 
1227
    bool result = false;
1228
    if (goal) {
1229
 
1230
        // We need two sub-transactions, The lhs_transaction is for evaluating the lhs
1231
        // and trying to update the rhs. 
1232
        CdlTransaction  lhs_transaction = transaction->make(transaction->get_conflict());
1233
        bool            lhs_result = false;
1234
        try {
1235
            CdlSimpleValue  lhs_value;
1236
            CdlEvalContext  lhs_context(lhs_transaction);
1237
            expr->eval_subexpression(lhs_context, lhs, lhs_value);
1238
            if (lhs_value.has_integer_value() || lhs_value.has_double_value()) {
1239
                lhs_result = CdlInfer::subexpr_value(lhs_transaction, expr, rhs, lhs_value, level);
1240
                if (lhs_result) {
1241
                    CdlSimpleValue check;
1242
                    expr->eval_subexpression(lhs_context, lhs, check);
1243
                    if (lhs_value != check) {
1244
                        lhs_result = false;
1245
                    }
1246
                }
1247
            }
1248
        } catch (...) {
1249
            lhs_result = false;
1250
        }
1251
 
1252
        CdlTransaction  rhs_transaction = transaction->make(transaction->get_conflict());
1253
        bool            rhs_result = false;
1254
        try {
1255
            CdlSimpleValue  rhs_value;
1256
            CdlEvalContext  rhs_context(rhs_transaction);
1257
            expr->eval_subexpression(rhs_context, rhs, rhs_value);
1258
            if (rhs_value.has_integer_value() || rhs_value.has_double_value()) {
1259
                rhs_result = CdlInfer::subexpr_value(rhs_transaction, expr, lhs, rhs_value, level);
1260
                if (rhs_result) {
1261
                    CdlSimpleValue check;
1262
                    expr->eval_subexpression(rhs_context, rhs, check);
1263
                    if (rhs_value != check) {
1264
                        rhs_result = false;
1265
                    }
1266
                }
1267
            }
1268
        } catch (...) {
1269
            rhs_result = false;
1270
        }
1271
 
1272
        result = infer_choose2(lhs_transaction, lhs_result, rhs_transaction, rhs_result);
1273
    }
1274
 
1275
    CYG_REPORT_RETVAL(result);
1276
    return result;
1277
}
1278
 
1279
//}}}
1280
//{{{  CdlInfer::subexpr_bool()                 
1281
 
1282
// ----------------------------------------------------------------------------
1283
bool
1284
CdlInfer::subexpr_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
1285
{
1286
    CYG_REPORT_FUNCNAMETYPE("CdlInfer::subexpr_bool", "result %d");
1287
    CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
1288
    CYG_PRECONDITION_CLASSC(transaction);
1289
    CYG_PRECONDITION_CLASSC(expr);
1290
    CYG_PRECONDITIONC((0 <= index) && (index < expr->sub_expressions.size()));
1291
 
1292
    bool result = false;
1293
    CdlSubexpression& subexpr = expr->sub_expressions[index];
1294
 
1295
    switch(subexpr.op) {
1296
 
1297
      case CdlExprOp_Reference :
1298
          // The most common case. Follow the reference, and call the appropriate function.
1299
          // Note that the reference may be unbound.
1300
          {
1301
              CdlNode node = expr->references[subexpr.reference_index].get_destination();
1302
              CdlValuable valuable = 0;
1303
              if (0 != node) {
1304
                  valuable = dynamic_cast<CdlValuable>(node);
1305
              }
1306
              result = infer_handle_reference_bool(transaction, valuable, goal, level);
1307
              break;
1308
          }
1309
 
1310
      case CdlExprOp_StringConstant :
1311
          result = infer_handle_string_constant_bool(subexpr.constants, goal);
1312
          break;
1313
 
1314
      case CdlExprOp_IntegerConstant :
1315
          result = infer_handle_integer_constant_bool(subexpr.constants, goal);
1316
          break;
1317
 
1318
      case CdlExprOp_DoubleConstant :
1319
          result = infer_handle_double_constant_bool(subexpr.constants, goal);
1320
          break;
1321
 
1322
      case CdlExprOp_LogicalNot :
1323
          result = infer_handle_logical_NOT_bool(transaction, expr, subexpr.lhs_index, goal, level);
1324
          break;
1325
 
1326
      case CdlExprOp_And :
1327
          result = infer_handle_AND_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1328
          break;
1329
 
1330
      case CdlExprOp_Or :
1331
          result = infer_handle_OR_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1332
          break;
1333
 
1334
      case CdlExprOp_Implies :
1335
          result = infer_handle_IMPLIES_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1336
          break;
1337
 
1338
      case CdlExprOp_Xor :
1339
          result = infer_handle_XOR_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1340
          break;
1341
 
1342
      case CdlExprOp_Eqv :
1343
          result = infer_handle_EQV_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1344
          break;
1345
 
1346
      case CdlExprOp_Equal :
1347
          result = infer_handle_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, goal, level);
1348
          break;
1349
 
1350
      case CdlExprOp_NotEqual :
1351
          result = infer_handle_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, !goal, level);
1352
          break;
1353
 
1354
          // <= is satisfied by a numerical equality. However the inverse relation > cannot be handled that way
1355
          // The other comparison operators are much the same.
1356
      case CdlExprOp_LessEqual :
1357
      case CdlExprOp_GreaterEqual :
1358
          if (goal) {
1359
              result = infer_handle_numerical_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, true, level);
1360
          }
1361
          break;
1362
 
1363
      case CdlExprOp_LessThan :
1364
      case CdlExprOp_GreaterThan :
1365
          if (!goal) {
1366
              result = infer_handle_numerical_equal_bool(transaction, expr, subexpr.lhs_index, subexpr.rhs_index, true, level);
1367
          }
1368
          break;
1369
 
1370
      case CdlExprOp_Function :
1371
          result = CdlFunction::infer_bool(transaction, expr, index, goal, level);
1372
          break;
1373
 
1374
      default:
1375
          // No other inferences are implemented at this stage.
1376
          break;
1377
    }
1378
 
1379
    CYG_REPORT_RETVAL(result);
1380
    return result;
1381
}
1382
 
1383
//}}}
1384
//{{{  CdlInfer::subexpr_value()                
1385
 
1386
bool
1387
CdlInfer::subexpr_value(CdlTransaction transaction, CdlExpression expr, unsigned int index, CdlSimpleValue& goal, int level)
1388
{
1389
    CYG_REPORT_FUNCNAMETYPE("CdlInfer::subexpr_value", "result %d");
1390
    CYG_REPORT_FUNCARG4XV(transaction, expr, index, level);
1391
    CYG_PRECONDITION_CLASSC(transaction);
1392
    CYG_PRECONDITION_CLASSC(expr);
1393
    CYG_PRECONDITIONC((0 <= index) && (index < expr->sub_expressions.size()));
1394
 
1395
    bool result = false;
1396
    CdlSubexpression& subexpr = expr->sub_expressions[index];
1397
 
1398
    switch(subexpr.op) {
1399
 
1400
      case CdlExprOp_Reference          :
1401
          // The most common case. Follow the reference, and call the appropriate function.
1402
          // Note that the reference may be unbound.
1403
          {
1404
              CdlNode node = expr->references[subexpr.reference_index].get_destination();
1405
              CdlValuable valuable = 0;
1406
              if (0 != node) {
1407
                  valuable = dynamic_cast<CdlValuable>(node);
1408
              }
1409
              result = infer_handle_reference_value(transaction, valuable, goal, level);
1410
              break;
1411
          }
1412
 
1413
      case CdlExprOp_StringConstant     :
1414
          result = infer_handle_string_constant_value(subexpr.constants, goal);
1415
          break;
1416
 
1417
      case CdlExprOp_IntegerConstant    :
1418
          result = infer_handle_integer_constant_value(subexpr.constants, goal);
1419
          break;
1420
 
1421
      case CdlExprOp_DoubleConstant     :
1422
          result = infer_handle_double_constant_value(subexpr.constants, goal);
1423
          break;
1424
 
1425
      case CdlExprOp_LogicalNot         :
1426
      case CdlExprOp_And                :
1427
      case CdlExprOp_Or                 :
1428
      case CdlExprOp_Implies            :
1429
      case CdlExprOp_Xor                :
1430
      case CdlExprOp_Eqv                :
1431
      {
1432
          bool  new_goal = true;
1433
          if (("0" == goal.get_value()) || ("" == goal.get_value())) {
1434
              new_goal = false;
1435
          }
1436
          result = CdlInfer::subexpr_bool(transaction, expr, index, new_goal, level);
1437
          break;
1438
      }
1439
 
1440
      case CdlExprOp_Function :
1441
          result = CdlFunction::infer_value(transaction, expr, index, goal, level);
1442
          break;
1443
 
1444
      default:
1445
          // No other inferences are implemented at this stage.
1446
          break;
1447
    }
1448
 
1449
    CYG_REPORT_RETVAL(result);
1450
    return result;
1451
}
1452
 
1453
//}}}
1454
 
1455
//}}}
1456
//{{{  Illegal value resolution                 
1457
 
1458
// ----------------------------------------------------------------------------
1459
// This is not yet implemented.
1460
 
1461
bool
1462
CdlConflict_IllegalValueBody::inner_resolve(CdlTransaction transaction, int level)
1463
{
1464
    CYG_REPORT_FUNCNAMETYPE("CdlConflict_IllegalValue::inner_resolve", "result %d");
1465
    CYG_REPORT_FUNCARG3XV(this, transaction, level);
1466
    CYG_PRECONDITION_THISC();
1467
    CYG_PRECONDITION_CLASSC(transaction);
1468
 
1469
    CYG_UNUSED_PARAM(CdlTransaction, transaction);
1470
 
1471
    CYG_REPORT_RETVAL(false);
1472
    return false;
1473
}
1474
 
1475
//}}}
1476
//{{{  Requires resolution                      
1477
 
1478
// ----------------------------------------------------------------------------
1479
// The entry point for this code is
1480
// CdlConflict_RequiresBody::resolve(). "this" is a requires conflict
1481
// that needs to be resolved, if possible. There are twos argument: a
1482
// sub-transaction, which should be filled in with the solution if
1483
// possible; and a recursion level indicator, 0 if this is a top-level
1484
// inference engine invocation rather than a recursive one. There are
1485
// additional static parameters inference_recursion_limit and
1486
// inference_override which control details of the inference process.
1487
//
1488
// As an example of what is involved in an inference, consider the
1489
// simple case of a "requires XXX" property. This constraint may not
1490
// be satisfied because XXX is disabled,  because XXX is inactive,
1491
// or both.
1492
//
1493
// Assume for simplicity that XXX is already active. The inference
1494
// engine can now figure out that XXX must be enabled (it must be
1495
// of type bool or booldata, or else the conflict would not have
1496
// arisen). This is achieved by creating a sub-transaction,
1497
// enabling XXX in that sub-transaction, propagating the
1498
// sub-transaction and performing further inference. The inference
1499
// is successfull if no new conflicts are introduced.
1500
//
1501
// However, even if a solution is found it is not necessarily
1502
// acceptable without user confirmation, subject to
1503
// inference_override. This is handled in part by the transaction
1504
// class itself, in the resolve() and user_confirmation_required()
1505
// members. In cases where the inference engine can choose between
1506
// several alternatives it needs to consider this issue for each one.
1507
// Resolving a requires conflict. There are three ways of tackling
1508
// this problem, in order of preference:
1509
//
1510
// 1) change the terms in the expression to make it evaluate to
1511
//    true.
1512
// 2) disable the source so that the requires property is no longer
1513
//    relevant.
1514
// 3) make the source inactive, with the same effect.
1515
//
1516
// The first one should always be tried. If it is entirely successful
1517
// then there is no point in looking any further. If user confirmation
1518
// is required then the second approach should be tried. If that is
1519
// entirely successful then there is no point in looking further.
1520
// If user confirmation is required then the third approach should
1521
// be tried.
1522
 
1523
bool
1524
CdlConflict_RequiresBody::inner_resolve(CdlTransaction transaction, int level)
1525
{
1526
    CYG_REPORT_FUNCNAME("CdlConflict_Requires::inner_resolve");
1527
    CYG_REPORT_FUNCARG3XV(this, transaction, level);
1528
    CYG_PRECONDITION_THISC();
1529
    CYG_PRECONDITION_CLASSC(transaction);
1530
 
1531
    bool result = false;
1532
 
1533
    CdlProperty_GoalExpression  gexpr   = dynamic_cast<CdlProperty_GoalExpression>(this->get_property());
1534
    CdlExpression               expr    = gexpr->get_expression();
1535
 
1536
    // Only create the sub-transactions when needed.
1537
    CdlTransaction expr_transaction     = 0;
1538
    CdlTransaction disable_transaction  = 0;
1539
    CdlTransaction inactive_transaction = 0;
1540
 
1541
    // Keep track of the preferred solution found to date.
1542
    CdlTransaction preferred_transaction = 0;
1543
 
1544
    expr_transaction = transaction->make(this);
1545
    if (!CdlInfer::subexpr_bool(expr_transaction, expr, expr->first_subexpression, true, level)) {
1546
        // No luck here.
1547
        expr_transaction->cancel();
1548
        delete expr_transaction;
1549
        expr_transaction = 0;
1550
    } else {
1551
        // We have a possible solution. How acceptable is it?
1552
        if (!expr_transaction->user_confirmation_required()) {
1553
            // Whoopee.
1554
            expr_transaction->commit();
1555
            delete expr_transaction;
1556
            result = true;
1557
            CYG_REPORT_RETVAL(result);
1558
            return result;
1559
        } else {
1560
            // Maybe we can do better.
1561
            preferred_transaction = expr_transaction;
1562
            expr_transaction = 0;
1563
        }
1564
    }
1565
 
1566
    // Disabling the source only makes sense if we have a bool or booldata item.
1567
    CdlValuable valuable = dynamic_cast<CdlValuable>(this->get_node());
1568
    CYG_ASSERT_CLASSC(valuable);
1569
 
1570
    if ((CdlValueFlavor_Bool == valuable->get_flavor()) || (CdlValueFlavor_BoolData == valuable->get_flavor())) {
1571
        disable_transaction = transaction->make(this);
1572
        if (!CdlInfer::set_valuable_bool(disable_transaction, valuable, false, level)) {
1573
            // No luck here either.
1574
            disable_transaction->cancel();
1575
            delete disable_transaction;
1576
            disable_transaction = 0;
1577
        } else {
1578
            if (!disable_transaction->user_confirmation_required()) {
1579
                disable_transaction->commit();
1580
                delete disable_transaction;
1581
                if (0 != preferred_transaction) {
1582
                    preferred_transaction->cancel();
1583
                    delete preferred_transaction;
1584
                    preferred_transaction = 0;
1585
                }
1586
                result = true;
1587
                CYG_REPORT_RETVAL(result);
1588
                return result;
1589
            } else if (0 == preferred_transaction) {
1590
                preferred_transaction = disable_transaction;
1591
            } else if (!preferred_transaction->is_preferable_to(disable_transaction)) {
1592
                preferred_transaction->cancel();
1593
                delete preferred_transaction;
1594
                preferred_transaction = disable_transaction;
1595
                disable_transaction = 0;
1596
            } else {
1597
                disable_transaction->cancel();
1598
                delete disable_transaction;
1599
                disable_transaction = 0;
1600
            }
1601
        }
1602
    }
1603
 
1604
    // Now try for the inactive approach. This may work in cases where the disable
1605
    // approach does not if e.g. there are dependencies between two nodes in the
1606
    // same container, or if the source of the conflict is not boolean.
1607
    inactive_transaction = transaction->make(this);
1608
    if (!CdlInfer::make_inactive(inactive_transaction, valuable, level)) {
1609
        inactive_transaction->cancel();
1610
        delete inactive_transaction;
1611
        inactive_transaction = 0;
1612
    } else {
1613
        if (!inactive_transaction->user_confirmation_required()) {
1614
            inactive_transaction->commit();
1615
            delete inactive_transaction;
1616
            if (0 != preferred_transaction) {
1617
                preferred_transaction->cancel();
1618
                delete preferred_transaction;
1619
                preferred_transaction = 0;
1620
            }
1621
            result = true;
1622
            CYG_REPORT_RETVAL(result);
1623
            return result;
1624
        } else if (0 == preferred_transaction) {
1625
            preferred_transaction = inactive_transaction;
1626
        } else if (!preferred_transaction->is_preferable_to(inactive_transaction)) {
1627
            preferred_transaction->cancel();
1628
            delete preferred_transaction;
1629
            preferred_transaction = inactive_transaction;
1630
            inactive_transaction = 0;
1631
        } else {
1632
            inactive_transaction->cancel();
1633
            delete inactive_transaction;
1634
            inactive_transaction = 0;
1635
        }
1636
    }
1637
 
1638
    // Is there any solution at all? If so then use the currently-preferred one.
1639
    if (0 != preferred_transaction) {
1640
        preferred_transaction->commit();
1641
        delete preferred_transaction;
1642
        preferred_transaction = 0;
1643
        result = true;
1644
    }
1645
 
1646
    CYG_REPORT_RETVAL(result);
1647
    return result;
1648
}
1649
 
1650
//}}}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.