/src/tools/semantics/code/liberty_feature.e
Specman e | 949 lines | 839 code | 81 blank | 29 comment | 52 complexity | 912f0b01addbbb6ff125da9dcd7e89d8 MD5 | raw file
1-- This file is part of Liberty Eiffel. 2-- 3-- Liberty Eiffel is free software: you can redistribute it and/or modify 4-- it under the terms of the GNU General Public License as published by 5-- the Free Software Foundation, version 3 of the License. 6-- 7-- Liberty Eiffel is distributed in the hope that it will be useful, 8-- but WITHOUT ANY WARRANTY; without even the implied warranty of 9-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10-- GNU General Public License for more details. 11-- 12-- You should have received a copy of the GNU General Public License 13-- along with Liberty Eiffel. If not, see <http://www.gnu.org/licenses/>. 14-- 15deferred class LIBERTY_FEATURE 16 17inherit 18 LIBERTY_TAGGED 19 redefine 20 is_equal 21 end 22 23insert 24 LIBERTY_REACHABLE_MARKED 25 redefine 26 is_equal 27 end 28 HASHABLE 29 VISITABLE 30 redefine 31 is_equal 32 end 33 LOGGING 34 redefine 35 is_equal 36 end 37 38feature {ANY} 39 id: INTEGER 40 -- The feature's unique id (does not change through specialization) 41 42 definition_type: LIBERTY_ACTUAL_TYPE 43 -- The type where the feature is written 44 45 original: like Current 46 -- The original feature in `definition_type', useful to tag things (such as once results...) 47 48 is_redefined: BOOLEAN 49 -- True if this feature is proxied by a LIBERTY_REDEFINED_FEATURE and should not be used by itself. 50 51 current_type: LIBERTY_ACTUAL_TYPE is 52 do 53 Result := context.current_type 54 end 55 56 result_type: LIBERTY_TYPE is 57 require 58 has_context 59 do 60 Result := context.result_type 61 end 62 63 hash_code: INTEGER is 64 do 65 Result := id 66 end 67 68 is_equal (other: like Current): BOOLEAN is 69 do 70 Result := id = other.id 71 end 72 73 context: LIBERTY_FEATURE_DEFINITION_CONTEXT 74 type_resolver: LIBERTY_TYPE_RESOLVER_IN_FEATURE 75 76 precondition: LIBERTY_REQUIRE 77 postcondition: LIBERTY_ENSURE 78 79 obsolete_message: STRING 80 81 is_obsolete: BOOLEAN is 82 do 83 Result := obsolete_message /= Void 84 end 85 86 parameters: TRAVERSABLE[LIBERTY_PARAMETER] is 87 require 88 has_context 89 do 90 Result := context.parameters 91 ensure 92 exists: Result /= Void 93 end 94 95 has_context: BOOLEAN is 96 do 97 Result := context /= Void 98 end 99 100 has_accelerator: BOOLEAN is 101 do 102 Result := accelerator /= Void 103 end 104 105 accelerate_call (a: LIBERTY_FEATURE_ACCELERATOR) is 106 require 107 has_accelerator 108 do 109 accelerator.call([a, Current]) 110 end 111 112feature {LIBERTY_REACHABLE, LIBERTY_REACHABLE_COLLECTION_MARKER} 113 mark_reachable_code (mark: like reachable_mark) is 114 do 115 if current_type.is_reachable then 116 if not is_reachable then 117 debug ("mark.reachable") 118 log.trace.put_string(once "Marked reachable the feature: ") 119 log.trace.put_line(out) 120 end 121 torch.burn 122 end 123 if reachable_mark < mark then 124 do_mark_reachable_code(mark) 125 end 126 end 127 end 128 129feature {} 130 do_mark_reachable_code (mark: like reachable_mark) is 131 require 132 current_type.is_reachable 133 reachable_mark < mark 134 mark > 0 135 local 136 i: INTEGER 137 do 138 reachable_mark := mark 139 if precondition /= Void then 140 precondition.mark_reachable_code(mark) 141 end 142 if postcondition /= Void then 143 postcondition.mark_reachable_code(mark) 144 end 145 from 146 i := child_bindings_memory.lower 147 until 148 i > child_bindings_memory.upper 149 loop 150 child_bindings_memory.item(i).mark_reachable_code(mark) 151 i := i + 1 152 end 153 ensure 154 reachable_mark >= mark 155 end 156 157feature {LIBERTY_FEATURE_ENTITY} 158 can_check_agent_signature (a_agent_call: LIBERTY_CALL_EXPRESSION): BOOLEAN is 159 require 160 a_agent_call /= Void 161 local 162 i: INTEGER 163 do 164 if result_type = Void or else result_type.is_known then 165 from 166 Result := a_agent_call.target = Void or else a_agent_call.target.is_open_argument 167 i := parameters.lower 168 until 169 not Result or else i > parameters.upper 170 loop 171 Result := parameters.item(i).result_type.is_known 172 i := i + 1 173 end 174 end 175 ensure 176 can_also_check_result_type: Result implies (result_type = Void or else result_type.is_known) 177 end 178 179 agent_signature (a_agent_call: LIBERTY_CALL_EXPRESSION): COLLECTION[LIBERTY_KNOWN_TYPE] is 180 require 181 can_check_agent_signature(a_agent_call) 182 a_agent_call.is_agent_call 183 local 184 i: INTEGER 185 do 186 if a_agent_call.target = Void or else not a_agent_call.target.is_open_argument then 187 create {FAST_ARRAY[LIBERTY_KNOWN_TYPE]} Result.with_capacity(parameters.count) 188 else 189 create {FAST_ARRAY[LIBERTY_KNOWN_TYPE]} Result.with_capacity(parameters.count + 1) 190 Result.add_last(current_type) 191 end 192 from 193 i := parameters.lower 194 until 195 i > parameters.upper 196 loop 197 Result.add_last(parameters.item(i).result_type.known_type) 198 i := i + 1 199 end 200 end 201 202 check_agent_signature (a_agent_call: LIBERTY_CALL_EXPRESSION) is 203 require 204 can_check_agent_signature(a_agent_call) 205 a_agent_call.is_agent_call 206 local 207 i, j: INTEGER 208 do 209 if a_agent_call.target = Void or else not a_agent_call.is_open_argument then 210 i := 0 211 else 212 if parameters.is_empty then 213 crash --| TODO: error, bad number of arguments 214 end 215 if not a_agent_call.target.result_type.known_type.is_conform_to(parameters.first.result_type.known_type) 216 and then not a_agent_call.target.result_type.known_type.converts_to(parameters.first.result_type.known_type) then 217 crash --| TODO: error, bad argument type 218 end 219 i := 1 220 end 221 if a_agent_call.actuals.count /= 0 then 222 if a_agent_call.actuals.count /= parameters.count + i then 223 crash --| TODO: error, bad number of arguments 224 end 225 from 226 i := parameters.lower + i 227 j := a_agent_call.actuals.lower 228 until 229 i > parameters.upper 230 loop 231 if not parameters.item(i).result_type.known_type.is_conform_to(a_agent_call.actuals.item(j).result_type.known_type) 232 and then not parameters.item(i).result_type.known_type.converts_to(a_agent_call.actuals.item(j).result_type.known_type) then 233 crash --| TODO: error, bad argument type 234 end 235 i := i + 1 236 j := j + 1 237 end 238 end 239 end 240 241feature {ANY} 242 frozen debug_display (o: OUTPUT_STREAM; tab: INTEGER) is 243 do 244 tabulate(o, tab) 245 do_debug_display(o, tab) 246 debug_display_bindings(o, tab) 247 end 248 249feature {LIBERTY_FEATURE} 250 do_debug_display (o: OUTPUT_STREAM; tab: INTEGER) is 251 local 252 t: STRING 253 do 254 o.put_character('{') 255 o.put_string(context.current_type.full_name) 256 o.put_string(once "->") 257 o.put_string(definition_type.full_name) 258 o.put_character('}') 259 o.put_character(' ') 260 t := generating_type 261 t := t.substring(17, t.upper) 262 t.to_lower 263 o.put_string(t) 264 context.debug_display_signature(o) 265 o.put_character(' ') 266 o.put_character('@') 267 o.put_line(to_pointer.out) 268 end 269 270 debug_display_bindings (o: OUTPUT_STREAM; tab: INTEGER) is 271 do 272 debug_display_parent_bindings(o, tab) 273 debug_display_child_bindings(o, tab) 274 end 275 276 debug_display_parent_bindings (o: OUTPUT_STREAM; tab: INTEGER) is 277 local 278 i: INTEGER 279 do 280 tabulate(o, tab) 281 o.put_line(once "Parent bindings:") 282 from 283 i := parent_bindings_memory.lower 284 until 285 i > parent_bindings_memory.upper 286 loop 287 tabulate(o, tab) 288 o.put_string(once " * ") 289 o.put_integer(i+1) 290 o.put_character('/') 291 o.put_integer(parent_bindings_memory.count) 292 o.put_string(once ": ") 293 parent_bindings_memory.item(i).do_debug_display(o, tab + 1) 294 --|*** TODO: looks like there is a parent cycle in NUMERIC.is_equal <-> COMPARABLE.is_equal 295 -- parent_bindings_memory.item(i).debug_display_parent_bindings(o, tab + 1) 296 i := i + 1 297 end 298 end 299 300 debug_display_child_bindings (o: OUTPUT_STREAM; tab: INTEGER) is 301 local 302 i: INTEGER 303 do 304 tabulate(o, tab) 305 o.put_line(once "Child bindings:") 306 from 307 i := child_bindings_memory.lower 308 until 309 i > child_bindings_memory.upper 310 loop 311 tabulate(o, tab) 312 o.put_string(once " * ") 313 o.put_integer(i) 314 o.put_character('/') 315 o.put_integer(child_bindings_memory.count) 316 o.put_string(once ": ") 317 o.put_string(child_bindings_memory.key(i).full_name) 318 o.put_string(once " => ") 319 child_bindings_memory.item(i).do_debug_display(o, tab + 1) 320 -- if child_bindings_memory.item(i) /= Current then 321 -- child_bindings_memory.item(i).debug_display_child_bindings(o, tab + 1) 322 -- end 323 i := i + 1 324 end 325 end 326 327 tabulate (o: OUTPUT_STREAM; tab: INTEGER) is 328 local 329 i: INTEGER 330 do 331 from 332 i := 1 333 until 334 i > tab 335 loop 336 o.put_string(once " ") 337 i := i + 1 338 end 339 end 340 341feature {LIBERTY_FEATURE_DEFINITION} 342 join (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 343 require 344 a_type /= Void 345 a_feature /= Void 346 current_fd.the_feature = Current 347 other_fd.the_feature = a_feature 348 not is_redefined 349 do 350 Result := do_join(a_type, a_feature, current_fd, other_fd) 351 bind_or_replace(Result, a_type, Result = Current) 352 a_feature.bind_or_replace(Result, a_type, Result = a_feature) 353 ensure 354 not errors.has_error implies Result /= Void 355 end 356 357feature {} 358 do_join (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 359 require 360 a_type /= Void 361 a_feature /= Void 362 current_fd.the_feature = Current 363 other_fd.the_feature = a_feature 364 deferred 365 ensure 366 not errors.has_error implies Result /= Void 367 end 368 369feature {LIBERTY_FEATURE} 370 joined_attribute (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_ATTRIBUTE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 371 require 372 a_type /= Void 373 a_feature /= Void 374 current_fd.the_feature = Current 375 other_fd.the_feature = a_feature 376 deferred 377 ensure 378 not errors.has_error implies Result /= Void 379 end 380 381 joined_constant (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_CONSTANT; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 382 require 383 a_type /= Void 384 a_feature /= Void 385 current_fd.the_feature = Current 386 other_fd.the_feature = a_feature 387 deferred 388 ensure 389 not errors.has_error implies Result /= Void 390 end 391 392 joined_deferred (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_DEFERRED; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 393 require 394 a_type /= Void 395 a_feature /= Void 396 current_fd.the_feature = Current 397 other_fd.the_feature = a_feature 398 deferred 399 ensure 400 not errors.has_error implies Result /= Void 401 end 402 403 joined_do (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_DO; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 404 require 405 a_type /= Void 406 a_feature /= Void 407 current_fd.the_feature = Current 408 other_fd.the_feature = a_feature 409 deferred 410 ensure 411 not errors.has_error implies Result /= Void 412 end 413 414 joined_external (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_EXTERNAL; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 415 require 416 a_type /= Void 417 a_feature /= Void 418 current_fd.the_feature = Current 419 other_fd.the_feature = a_feature 420 deferred 421 ensure 422 not errors.has_error implies Result /= Void 423 end 424 425 joined_once (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_ONCE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 426 require 427 a_type /= Void 428 a_feature /= Void 429 current_fd.the_feature = Current 430 other_fd.the_feature = a_feature 431 deferred 432 ensure 433 not errors.has_error implies Result /= Void 434 end 435 436 joined_redefined (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_REDEFINED; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 437 require 438 a_type /= Void 439 a_feature /= Void 440 current_fd.the_feature = Current 441 other_fd.the_feature = a_feature 442 deferred 443 ensure 444 not errors.has_error implies Result /= Void 445 end 446 447 joined_unique (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_UNIQUE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is 448 require 449 a_type /= Void 450 a_feature /= Void 451 current_fd.the_feature = Current 452 other_fd.the_feature = a_feature 453 deferred 454 ensure 455 not errors.has_error implies Result /= Void 456 end 457 458feature {ANY} 459 is_bound (type: LIBERTY_KNOWN_TYPE): BOOLEAN is 460 local 461 known: LIBERTY_ACTUAL_TYPE 462 do 463 if known ?:= type then 464 known ::= type 465 Result := child_bindings_memory.fast_has(known) 466 end 467 end 468 469 bound (type: LIBERTY_KNOWN_TYPE): LIBERTY_FEATURE is 470 local 471 known: LIBERTY_ACTUAL_TYPE 472 do 473 if known ?:= type then 474 known ::= type 475 Result := child_bindings_memory.fast_reference_at(known) 476 end 477 if Result = Void then 478 Result := Current 479 end 480 ensure 481 Result /= Void 482 not is_bound(type) implies Result = Current 483 end 484 485 specialized_in (a_type: LIBERTY_ACTUAL_TYPE): like Current is 486 do 487 if a_type = current_type or else not a_type.is_child_of(current_type) then 488 Result := Current 489 else 490 Result ::= specialized.fast_reference_at(a_type) 491 check 492 Result /= Current 493 end 494 if Result = Void then 495 is_specializing := True 496 Result := twin 497 is_specializing := False 498 specialized.add(Result, a_type) 499 Result.set_specialized_in(Current, context.specialized_in(a_type)) 500 if not is_redefined then 501 debug ("feature.specialization") 502 log.trace.put_line(once " Binding specialized feature") 503 end 504 bind_or_replace(Result, a_type, True) 505 end 506 end 507 end 508 ensure 509 Result.id = id 510 ;(current_type = a_type or not a_type.is_child_of(current_type)) implies Result = Current 511 ;(current_type /= a_type and a_type.is_child_of(current_type)) implies (Result /= Current and then Result.current_type = a_type) 512 end 513 514feature {LIBERTY_TYPE_PARENT_FEATURES_LOADER} 515 add_if_redefined (type: LIBERTY_ACTUAL_TYPE; name: LIBERTY_FEATURE_NAME; redefined_features: DICTIONARY[LIBERTY_FEATURE_REDEFINED, LIBERTY_FEATURE_NAME]) is 516 do 517 -- nothing 518 end 519 520feature {LIBERTY_FEATURE} 521 set_specialized_in (a_original: like Current; a_context: like context) is 522 require 523 is_specializing 524 a_original.id = id 525 do 526 original := a_original 527 context := a_context 528 check type_resolver /= Void end 529 create type_resolver.specialized(type_resolver.feature_name, Current, type_resolver.parent.specialized_in(a_context.current_type)) 530 if precondition /= Void then 531 precondition := precondition.specialized_in(a_context.current_type) 532 end 533 if postcondition /= Void then 534 postcondition := postcondition.specialized_in(a_context.current_type) 535 end 536 537 -- Current is a twin of another feature, be sure to correctly create again the bindings 538 -- (avoid shared collections) 539 create {FAST_ARRAY[LIBERTY_FEATURE]} parent_bindings_memory.with_capacity(1) 540 create {HASHED_DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]} child_bindings_memory.with_capacity(3) 541 542 is_specializing := False 543 ensure 544 original = a_original 545 end 546 547feature {LIBERTY_FEATURE} 548 has_parent_binding (a_parent: LIBERTY_FEATURE): BOOLEAN is 549 do 550 Result := Current = a_parent or else parent_bindings_memory.fast_has(a_parent) 551 end 552 553 add_parent_binding (a_parent: LIBERTY_FEATURE) is 554 require 555 a_parent /= Void 556 a_parent /= Current 557 not is_redefined 558 do 559 if has_parent_binding(a_parent) then 560 debug ("feature.binding") 561 log.trace.put_line(once " => parent already added") 562 end 563 else 564 parent_bindings_memory.add_last(a_parent) 565 debug ("feature.binding") 566 log.trace.put_line(once " => added parent to child") 567 end 568 end 569 end 570 571 remove_parent_binding (a_parent: LIBERTY_FEATURE) is 572 require 573 a_parent /= Current 574 has_parent_binding(a_parent) 575 local 576 i: INTEGER 577 do 578 i := parent_bindings_memory.fast_first_index_of(a_parent) 579 parent_bindings_memory.remove(i) 580 end 581 582 bind_or_replace (child: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE; bind_current: BOOLEAN) is 583 require 584 not is_redefined 585 bind_current implies type = child.current_type 586 no_cycles: child /= Current implies not has_parent_binding(child) 587 local 588 i, j: INTEGER; removed: LIBERTY_FEATURE 589 do 590 check 591 child /= Current implies parent_bindings /= child.parent_bindings 592 end 593 594 if child /= Current and then child.has_parent_binding(Current) then 595 breakpoint 596 end 597 598 debug ("feature.binding") 599 log.trace.put_string(once " Binding child: ") 600 child.do_debug_display(log.trace, 2) 601 if bind_current then 602 log.trace.put_string(once " to Current: ") 603 else 604 log.trace.put_string(once " replacing Current: ") 605 end 606 do_debug_display(log.trace, 2) 607 end 608 609 from 610 i := parent_bindings_memory.lower 611 until 612 i > parent_bindings_memory.upper 613 loop 614 debug ("feature.binding") 615 log.trace.put_string(once " * Will bind parent #") 616 log.trace.put_integer(i+1) 617 log.trace.put_character('/') 618 log.trace.put_integer(parent_bindings_memory.count) 619 log.trace.put_string(once ": ") 620 parent_bindings_memory.item(i).do_debug_display(log.trace, 3) 621 end 622 removed := parent_bindings_memory.item(i).do_bind(child, Current, type) 623 if removed = Void then 624 i := i + 1 625 else 626 debug ("feature.binding") 627 log.trace.put_line(once " -> adding removed child's parents") 628 end 629 from 630 j := removed.parent_bindings.lower 631 until 632 j > removed.parent_bindings.upper 633 loop 634 if removed.parent_bindings.item(j) /= Current then 635 add_parent_binding(removed.parent_bindings.item(j)) 636 end 637 j := j + 1 638 end 639 end 640 end 641 642 if bind_current then 643 debug ("feature.binding") 644 log.trace.put_string(once " * Will bind Current: ") 645 do_debug_display(log.trace, 3) 646 end 647 removed := do_bind(child, Current, type) 648 check 649 removed /= Void implies removed.parent_bindings.is_empty -- i.e. removing a just-created feature, no precious data to be kept 650 end 651 end 652 653 debug ("feature.binding") 654 log.trace.put_string(once " Final parent bindings of ") 655 child.do_debug_display(log.trace, 1) 656 from 657 i := child.parent_bindings.lower 658 until 659 i > child.parent_bindings.upper 660 loop 661 log.trace.put_string(once " * ") 662 log.trace.put_integer(i+1) 663 log.trace.put_character('/') 664 log.trace.put_integer(child.parent_bindings.count) 665 log.trace.put_string(once ": ") 666 child.parent_bindings.item(i).do_debug_display(log.trace, 2) 667 i := i + 1 668 end 669 end 670 ensure 671 parent_bindings_memory.for_all(agent (c, p: LIBERTY_FEATURE): BOOLEAN is 672 do 673 debug ("feature.binding") 674 log.trace.put_string(once " Checking ") 675 p.do_debug_display(log.trace, 1) 676 end 677 Result := c.has_parent_binding(p) 678 if not Result then 679 breakpoint 680 end 681 end (child, ?) 682 ) 683 parent_bindings_memory.for_all(agent (c, p: LIBERTY_FEATURE; t: LIBERTY_ACTUAL_TYPE): BOOLEAN is 684 do 685 Result := p.is_bound(t) and then bound(t) = c 686 if not Result then 687 breakpoint 688 end 689 end (child, ?, type) 690 ) 691 end 692 693 do_bind (child, target: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE): LIBERTY_FEATURE is 694 -- Returns the replaced child if it exists 695 require 696 child /= Current implies not has_parent_binding(child) 697 not is_redefined 698 do 699 Result := child_bindings_memory.fast_reference_at(type) 700 if Result = child then 701 check 702 Result.has_parent_binding(Current) 703 end 704 debug ("feature.binding") 705 log.trace.put_line(once " -> already bound.") 706 end 707 Result := Void 708 else 709 if Result /= Void then 710 debug ("feature.binding") 711 log.trace.put_string(once " -> remove old child: ") 712 Result.do_debug_display(log.trace, 4) 713 end 714 child_bindings_memory.fast_remove(type) 715 Result.remove_parent_binding(Current) 716 else 717 check 718 not child_bindings_memory.fast_has(type) 719 end 720 end 721 debug ("feature.binding") 722 log.trace.put_line(once " -> adding new child") 723 end 724 child_bindings_memory.add(child, type) 725 if child /= Current then 726 child.add_parent_binding(Current) 727 end 728 end 729 end 730 731 parent_bindings: TRAVERSABLE[LIBERTY_FEATURE] is 732 -- Flat structure: all parents of the feature are here. 733 do 734 Result := parent_bindings_memory 735 end 736 737 child_bindings: MAP[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE] is 738 -- Flat structure: all heirs of the feature are here. 739 do 740 Result := child_bindings_memory 741 end 742 743feature {LIBERTY_BUILDER_TOOLS} 744 bind (child: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE) is 745 require 746 not is_redefined 747 truly_bind: child /= Current implies child.current_type /= current_type 748 no_cycles: child /= Current implies not has_parent_binding(child) 749 bind_current: type = child.current_type 750 do 751 bind_or_replace(child, type, True) 752 ensure 753 parent_bindings_memory.is_equal(old parent_bindings_memory.twin) 754 child.has_parent_binding(Current) 755 is_bound(type) and then bound(type) = child 756 end 757 758 replace (new: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE) is 759 require 760 not new.is_redefined 761 truly_replace: new /= Current and then new.current_type = current_type 762 no_cycles: not new.has_parent_binding(Current) 763 do 764 is_specializing := True -- well, not exactly- but Current is dead, baby. 765 new.bind_or_replace(Current, type, False) 766 end 767 768feature {LIBERTY_FEATURE_DEFINITION_CONTEXT} 769 find_precursor (a_parent: LIBERTY_ACTUAL_TYPE): LIBERTY_FEATURE is 770 do 771 if a_parent = Void then 772 Result := find_closest_precursor 773 else 774 Result := find_parent_precursor(a_parent) 775 end 776 Result := Result.specialized_in(current_type) 777 end 778 779feature {} 780 find_closest_precursor: LIBERTY_FEATURE is 781 local 782 i: INTEGER; candidate: LIBERTY_FEATURE 783 do 784 from 785 i := parent_bindings_memory.lower 786 until 787 i > parent_bindings_memory.upper 788 loop 789 candidate := parent_bindings_memory.item(i) 790 if Result = Void or else candidate.current_type.is_child_of(Result.current_type) then 791 Result := candidate 792 end 793 i := i + 1 794 end 795 ensure 796 Result /= Void 797 Result /= Current 798 end 799 800 find_parent_precursor (a_parent: LIBERTY_ACTUAL_TYPE): LIBERTY_FEATURE is 801 require 802 a_parent /= Void 803 local 804 i: INTEGER; candidate: LIBERTY_FEATURE 805 do 806 from 807 i := parent_bindings_memory.lower 808 until 809 i > parent_bindings_memory.upper 810 loop 811 candidate := parent_bindings_memory.item(i) 812 if candidate.current_type = a_parent or else candidate.current_type.is_child_of(a_parent) then 813 if Result = Void or else candidate.current_type.is_child_of(Result.current_type) then 814 Result := candidate 815 end 816 end 817 i := i + 1 818 end 819 ensure 820 Result /= Void 821 Result /= Current 822 end 823 824feature {LIBERTY_BUILDER_TOOLS, LIBERTY_FEATURE_DEFINITION} 825 set_type_resolver (a_type_resolver: like type_resolver; a_replace: BOOLEAN) is 826 require 827 a_type_resolver.local_context = context 828 a_type_resolver.the_feature /= Void implies a_replace 829 type_resolver = Void 830 do 831 if a_replace or else a_type_resolver.the_feature = Void then 832 a_type_resolver.set_the_feature(Current, a_replace) 833 end 834 type_resolver := a_type_resolver 835 ensure 836 type_resolver = a_type_resolver 837 a_replace implies type_resolver.the_feature = Current 838 end 839 840 set_context (a_context: like context) is 841 require 842 a_context /= Void 843 do 844 context := a_context 845 ensure 846 context = a_context 847 end 848 849 set_precondition (assertions: like precondition) is 850 do 851 precondition := assertions 852 ensure 853 precondition = assertions 854 end 855 856 set_postcondition (assertions: like postcondition) is 857 do 858 postcondition := assertions 859 ensure 860 postcondition = assertions 861 end 862 863 set_obsolete (a_obsolete: like obsolete_message) is 864 do 865 obsolete_message := a_obsolete 866 ensure 867 a_obsolete /= Void implies is_obsolete 868 obsolete_message = a_obsolete 869 end 870 871feature {LIBERTY_FEATURE_REDEFINED} 872 set_is_redefined is 873 do 874 is_redefined := True 875 end 876 877feature {} 878 make (a_definition_type: like definition_type; a_accelerator: like accelerator) is 879 require 880 a_definition_type /= Void 881 do 882 create {FAST_ARRAY[LIBERTY_FEATURE]} parent_bindings_memory.with_capacity(1) 883 definition_type := a_definition_type 884 create {HASHED_DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]} child_bindings_memory.with_capacity(3) 885 create {HASHED_DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]} specialized.with_capacity(3) 886 accelerator := a_accelerator 887 888 ids_provider.increment 889 id := ids_provider.value 890 original := Current 891 ensure 892 definition_type = a_definition_type 893 accelerator = a_accelerator 894 original = Current 895 end 896 897 parent_bindings_memory: COLLECTION[LIBERTY_FEATURE] 898 child_bindings_memory: DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE] 899 900 accelerator: PROCEDURE[TUPLE[LIBERTY_FEATURE_ACCELERATOR, LIBERTY_FEATURE]] 901 specialized: DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE] 902 903 errors: LIBERTY_ERRORS 904 torch: LIBERTY_ENLIGHTENING_THE_WORLD 905 906 is_specializing: BOOLEAN 907 908 ids_provider: COUNTER is 909 once 910 create Result 911 end 912 913invariant 914 child_bindings_memory /= Void 915 specialized /= Void 916 definition_type /= Void 917 parent_bindings_memory /= Void 918 original.id = id 919 920 context = Void implies parent_bindings_memory.is_empty 921 is_redefined implies (parent_bindings_memory.is_empty and child_bindings_memory.is_empty) 922 923 not is_specializing implies child_bindings_memory.for_all(agent (c: LIBERTY_FEATURE): BOOLEAN is 924 do 925 Result := c.has_parent_binding(Current) 926 if not Result then 927 breakpoint 928 end 929 end 930 ) 931 932 not parent_bindings_memory.fast_has(Current) 933 not is_specializing implies parent_bindings_memory.for_all(agent (p: LIBERTY_FEATURE): BOOLEAN is 934 local 935 c: LIBERTY_FEATURE 936 do 937 if p.is_bound(current_type) then 938 c := p.bound(current_type) 939 Result := c = Current -- should be "c = Current" but for the `specialized_in' twin 940 if not Result then 941 breakpoint 942 end 943 else 944 Result := True 945 end 946 end 947 ) 948 949end -- class LIBERTY_FEATURE