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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [infer.cxx] - Blame information for rev 403

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

Line No. Rev Author Line
1 26 unneback
//{{{  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
//}}}

powered by: WebSVN 2.1.0

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