/src/tools/semantics/code/liberty_feature.e

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