/src/tools/semantics/types/impl/liberty_actual_type.e

http://github.com/tybor/Liberty · Specman e · 703 lines · 592 code · 80 blank · 31 comment · 33 complexity · 16ec3136cfa7fc7183cc711d68d45c1b 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. class LIBERTY_ACTUAL_TYPE
  16. --
  17. -- A type effectively defined, usually by an actual source file
  18. --
  19. inherit
  20. LIBERTY_KNOWN_TYPE
  21. redefine
  22. is_equal
  23. end
  24. insert
  25. EIFFEL_NODE_HANDLER
  26. undefine
  27. out_in_tagged_out_memory
  28. redefine
  29. is_equal
  30. end
  31. LIBERTY_ERROR_LEVELS
  32. undefine
  33. out_in_tagged_out_memory
  34. redefine
  35. is_equal
  36. end
  37. LIBERTY_ARRAY_MANIFEST_CONSTANTS
  38. undefine
  39. out_in_tagged_out_memory
  40. redefine
  41. is_equal
  42. end
  43. create {LIBERTY_UNIVERSE}
  44. make
  45. feature {ANY}
  46. current_entity: LIBERTY_CURRENT
  47. known_type: LIBERTY_ACTUAL_TYPE is
  48. do
  49. Result := Current
  50. end
  51. file: FIXED_STRING is
  52. do
  53. Result := descriptor.file
  54. end
  55. obsolete_message: STRING
  56. hash_code: INTEGER is
  57. do
  58. Result := descriptor.hash_code
  59. end
  60. is_equal (other: like Current): BOOLEAN is
  61. do
  62. Result := other = Current
  63. end
  64. is_obsolete: BOOLEAN is
  65. do
  66. Result := obsolete_message /= Void
  67. end
  68. cluster: LIBERTY_CLUSTER is
  69. do
  70. Result := descriptor.cluster
  71. end
  72. name: FIXED_STRING is
  73. do
  74. Result := descriptor.name
  75. end
  76. parameters: TRAVERSABLE[LIBERTY_TYPE] is
  77. do
  78. Result := descriptor.parameters
  79. end
  80. is_deferred: BOOLEAN is
  81. do
  82. Result := runtime_category = deferred_category
  83. end
  84. is_expanded: BOOLEAN is
  85. do
  86. Result := runtime_category = expanded_category
  87. end
  88. is_separate: BOOLEAN is
  89. do
  90. Result := runtime_category = separate_category
  91. end
  92. is_reference: BOOLEAN is
  93. do
  94. Result := runtime_category = reference_category
  95. end
  96. is_runtime_category_set: BOOLEAN is
  97. do
  98. Result := runtime_category /= 0
  99. end
  100. the_invariant: LIBERTY_INVARIANT
  101. has_feature (a_feature_name: LIBERTY_FEATURE_NAME): BOOLEAN is
  102. do
  103. Result := features.has(a_feature_name)
  104. end
  105. feature_definition (a_feature_name: LIBERTY_FEATURE_NAME): LIBERTY_FEATURE_DEFINITION is
  106. do
  107. Result := features.at(a_feature_name)
  108. end
  109. type_resolver: LIBERTY_TYPE_RESOLVER_IN_TYPE
  110. accept (visitor: LIBERTY_TYPE_VISITOR) is
  111. do
  112. visit.call([visitor, Current])
  113. end
  114. converts_to (target_type: LIBERTY_KNOWN_TYPE): BOOLEAN is
  115. do
  116. Result := has_converter(target_type)
  117. end
  118. do_convert (target_type: LIBERTY_ACTUAL_TYPE; a_converter: LIBERTY_TYPE_CONVERTER) is
  119. do
  120. converter(target_type).call([a_converter])
  121. end
  122. may_promote_current: BOOLEAN
  123. -- True if Current's type may be promoted in order to fix arithmetic operations (available only on a
  124. -- very few select kernel types such as integers, naturals and reals)
  125. is_built: BOOLEAN is
  126. do
  127. Result := builder.is_built
  128. end
  129. feature {LIBERTY_TYPE_LISTENER, LIBERTY_TYPE}
  130. add_listener (a_listener: LIBERTY_TYPE_LISTENER) is
  131. do
  132. a_listener.on_type_known(Current)
  133. if is_built then
  134. a_listener.on_type_built(Current)
  135. else
  136. listeners.add_last(a_listener)
  137. end
  138. ensure then
  139. is_built /= has_listener(a_listener)
  140. end
  141. feature {}
  142. fire_type_built is
  143. local
  144. i: INTEGER
  145. do
  146. from
  147. i := listeners.lower
  148. until
  149. i > listeners.upper
  150. loop
  151. listeners.item(i).on_type_built(Current)
  152. i := i + 1
  153. end
  154. listeners := Void
  155. end
  156. feature {LIBERTY_KNOWN_TYPE}
  157. full_name_in (buffer: STRING) is
  158. local
  159. i: INTEGER
  160. do
  161. buffer.append(cluster.name)
  162. buffer.extend('.')
  163. buffer.append(name)
  164. if not parameters.is_empty then
  165. buffer.extend('[')
  166. from
  167. i := parameters.lower
  168. until
  169. i > parameters.upper
  170. loop
  171. if i > parameters.lower then
  172. buffer.extend(',')
  173. end
  174. parameters.item(i).full_name_in(buffer)
  175. i := i + 1
  176. end
  177. buffer.extend(']')
  178. end
  179. end
  180. feature {ANY}
  181. debug_display (o: OUTPUT_STREAM; show_features: BOOLEAN) is
  182. local
  183. i: INTEGER; fn: LIBERTY_FEATURE_NAME; fd: LIBERTY_FEATURE_DEFINITION
  184. do
  185. if is_runtime_category_set then
  186. if is_expanded then
  187. o.put_string(once "expanded type ")
  188. elseif is_separate then
  189. o.put_string(once "separate type ")
  190. elseif is_deferred then
  191. o.put_string(once "deferred type ")
  192. else
  193. o.put_string(once "type ")
  194. end
  195. else
  196. o.put_string(once "type ")
  197. end
  198. o.put_line(full_name.out)
  199. o.put_string(once " building state: ")
  200. o.put_line(builder.current_state.out)
  201. if show_features then
  202. from
  203. i := features.lower
  204. until
  205. i > features.upper
  206. loop
  207. fn := features.key(i)
  208. fd := features.item(i)
  209. check
  210. fn = fd.feature_name
  211. end
  212. fd.debug_display(o, True)
  213. i := i + 1
  214. end
  215. end
  216. o.put_string(once "end -- type ")
  217. o.put_line(full_name.out)
  218. end
  219. feature {ANY} -- Inheritance
  220. is_conform_to (other: LIBERTY_KNOWN_TYPE): BOOLEAN is
  221. local
  222. i: INTEGER
  223. do
  224. if other = Current then
  225. Result := True
  226. elseif conformant_parents /= Void then
  227. from
  228. i := conformant_parents.lower
  229. until
  230. Result or else i > conformant_parents.upper
  231. loop
  232. Result := conformant_parents.item(i).is_conform_to(other)
  233. i := i + 1
  234. end
  235. if not Result and then other.same_base_class_as(Current) then
  236. Result := conformance_checker.inherits(other, Current)
  237. end
  238. end
  239. end
  240. is_non_conformant_child_of (other: LIBERTY_KNOWN_TYPE): BOOLEAN is
  241. local
  242. i: INTEGER
  243. do
  244. if other = Current then
  245. Result := True
  246. else
  247. if non_conformant_parents /= Void then
  248. from
  249. i := non_conformant_parents.lower
  250. until
  251. Result or else i > non_conformant_parents.upper
  252. loop
  253. Result := non_conformant_parents.item(i).is_non_conformant_child_of(other)
  254. i := i + 1
  255. end
  256. end
  257. if conformant_parents /= Void then
  258. from
  259. i := conformant_parents.lower
  260. until
  261. Result or else i > conformant_parents.upper
  262. loop
  263. Result := conformant_parents.item(i).is_non_conformant_child_of(other)
  264. i := i + 1
  265. end
  266. end
  267. if not Result and then other.same_base_class_as(Current) then
  268. Result := conformance_checker.inserts(other, Current)
  269. end
  270. end
  271. end
  272. feature {LIBERTY_KNOWN_TYPE}
  273. common_parent (other: LIBERTY_KNOWN_TYPE): LIBERTY_KNOWN_TYPE is
  274. -- To implement `common_conformant_parent_with'.
  275. -- Conformant common parent lookup.
  276. local
  277. i: INTEGER; t: LIBERTY_KNOWN_TYPE
  278. do
  279. from
  280. i := conformant_parents.lower
  281. until
  282. Result /= Void or else i > conformant_parents.upper
  283. loop
  284. t := conformant_parents.item(i)
  285. check
  286. by_definition: other /= t -- because of the `not_trivial' precondition: not is_conform_to(other)
  287. end
  288. if other.is_conform_to(t) then
  289. Result := t
  290. else
  291. Result := t.common_parent(other)
  292. end
  293. i := i + 1
  294. end
  295. end
  296. same_base_class_as (other: LIBERTY_ACTUAL_TYPE): BOOLEAN is
  297. do
  298. Result := name = other.name and then descriptor.cluster = other.descriptor.cluster
  299. end
  300. feature {LIBERTY_BUILDER_TOOLS}
  301. set_obsolete (message: like obsolete_message) is
  302. require
  303. message /= Void
  304. do
  305. obsolete_message := message
  306. ensure
  307. is_obsolete
  308. obsolete_message = message
  309. end
  310. set_deferred is
  311. require
  312. not is_runtime_category_set
  313. do
  314. runtime_category := deferred_category
  315. ensure
  316. is_runtime_category_set
  317. is_deferred
  318. end
  319. set_expanded is
  320. require
  321. not is_runtime_category_set
  322. do
  323. runtime_category := expanded_category
  324. ensure
  325. is_runtime_category_set
  326. is_expanded
  327. end
  328. set_separate is
  329. require
  330. not is_runtime_category_set
  331. do
  332. runtime_category := separate_category
  333. ensure
  334. is_runtime_category_set
  335. is_separate
  336. end
  337. set_reference is
  338. require
  339. not is_runtime_category_set
  340. do
  341. runtime_category := reference_category
  342. ensure
  343. is_runtime_category_set
  344. is_reference
  345. end
  346. add_parent (a_parent: LIBERTY_ACTUAL_TYPE; conformant: BOOLEAN) is
  347. require
  348. a_parent /= Void
  349. do
  350. torch.burn
  351. if conformant then
  352. if conformant_parents = no_parents then
  353. create {FAST_ARRAY[LIBERTY_ACTUAL_TYPE]} conformant_parents.with_capacity(2)
  354. end
  355. conformant_parents.add_last(a_parent)
  356. debug ("type.building")
  357. log.trace.put_string(name)
  358. log.trace.put_string(once ": adding conformant parent ")
  359. log.trace.put_line(a_parent.name)
  360. end
  361. else
  362. if non_conformant_parents = no_parents then
  363. create {FAST_ARRAY[LIBERTY_ACTUAL_TYPE]} non_conformant_parents.with_capacity(2)
  364. end
  365. non_conformant_parents.add_last(a_parent)
  366. debug ("type.building")
  367. log.trace.put_string(name)
  368. log.trace.put_string(once ": adding non-conformant parent ")
  369. log.trace.put_line(a_parent.name)
  370. end
  371. end
  372. end
  373. features: DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]
  374. set_invariant (a_invariant: like the_invariant) is
  375. do
  376. the_invariant := a_invariant
  377. ensure
  378. the_invariant = a_invariant
  379. end
  380. add_feature (a_feature: LIBERTY_FEATURE_DEFINITION) is
  381. require
  382. not has_feature(a_feature.feature_name)
  383. do
  384. features.add(a_feature, a_feature.feature_name)
  385. torch.burn
  386. ensure
  387. has_feature(a_feature.feature_name)
  388. feature_definition(a_feature.feature_name) = a_feature
  389. end
  390. replace_feature (a_feature: LIBERTY_FEATURE_DEFINITION) is
  391. require
  392. has_feature(a_feature.feature_name)
  393. feature_definition(a_feature.feature_name) /= a_feature
  394. local
  395. replaced_feature: LIBERTY_FEATURE_DEFINITION
  396. do
  397. replaced_feature := feature_definition(a_feature.feature_name)
  398. a_feature.copy_precursors(replaced_feature)
  399. features.put(a_feature, a_feature.feature_name)
  400. torch.burn
  401. ensure
  402. has_feature(a_feature.feature_name)
  403. feature_definition(a_feature.feature_name) = a_feature
  404. end
  405. descriptor_position: LIBERTY_POSITION is
  406. do
  407. Result := descriptor.position
  408. end
  409. feature {LIBERTY_UNIVERSE} -- Semantics building
  410. start_build (universe: LIBERTY_UNIVERSE) is
  411. require
  412. not errors.has_error
  413. do
  414. create builder.make(Current, universe)
  415. end
  416. build_more is
  417. require
  418. not is_built
  419. do
  420. builder.build_more
  421. if builder.is_built then
  422. fire_type_built
  423. end
  424. end
  425. set_may_promote_current is
  426. do
  427. may_promote_current:= True
  428. ensure
  429. may_promote_current
  430. end
  431. add_converter (target_type: LIBERTY_ACTUAL_TYPE; a_converter: like converter) is
  432. require
  433. not has_converter(target_type)
  434. do
  435. if converters = Void then
  436. create {HASHED_DICTIONARY[PROCEDURE[TUPLE[LIBERTY_TYPE_CONVERTER]], LIBERTY_KNOWN_TYPE]} converters.with_capacity(3)
  437. end
  438. converters.add(a_converter, target_type)
  439. ensure
  440. converter(target_type) = a_converter
  441. end
  442. has_converter (target_type: LIBERTY_KNOWN_TYPE): BOOLEAN is
  443. do
  444. Result := converters /= Void and then converters.fast_has(target_type)
  445. end
  446. converter (target_type: LIBERTY_ACTUAL_TYPE): PROCEDURE[TUPLE[LIBERTY_TYPE_CONVERTER]] is
  447. do
  448. Result := converters.fast_at(target_type)
  449. end
  450. feature {}
  451. check_validity is
  452. do
  453. --| TODO
  454. end
  455. feature {LIBERTY_TYPE_BUILDER}
  456. conformant_parents: COLLECTION[LIBERTY_ACTUAL_TYPE]
  457. non_conformant_parents: COLLECTION[LIBERTY_ACTUAL_TYPE]
  458. has_no_parents: BOOLEAN is
  459. do
  460. Result := conformant_parents = no_parents and then non_conformant_parents = no_parents
  461. end
  462. set_type_resolver (a_type_resolver: like type_resolver) is
  463. require
  464. a_type_resolver.current_type = Current
  465. type_resolver = Void
  466. do
  467. type_resolver := a_type_resolver
  468. ensure
  469. type_resolver = a_type_resolver
  470. end
  471. feature {LIBERTY_UNIVERSE, LIBERTY_TYPE_BUILDER}
  472. has_loaded_features: BOOLEAN is
  473. do
  474. Result := builder.has_loaded_features
  475. end
  476. feature {LIBERTY_REACHABLE, LIBERTY_REACHABLE_COLLECTION_MARKER}
  477. mark_reachable_code (mark: INTEGER) is
  478. local
  479. i: INTEGER; param: LIBERTY_TYPE
  480. do
  481. if not is_reachable then
  482. torch.burn
  483. log.trace.put_string(once "Marked reachable the type: ")
  484. log.trace.put_line(full_name)
  485. end
  486. if reachable_mark < mark then
  487. reachable_mark := mark
  488. types_marker.mark_reachable_code(mark, conformant_parents)
  489. types_marker.mark_reachable_code(mark, non_conformant_parents)
  490. from
  491. i := parameters.lower
  492. until
  493. i > parameters.upper
  494. loop
  495. param := parameters.item(i)
  496. if param.is_known and then param.known_type.is_runtime_category_set and then param.known_type.is_expanded then
  497. param.mark_reachable_code(mark)
  498. end
  499. i := i + 1
  500. end
  501. if has_manifest_array then
  502. mark_manifest_array_features(mark)
  503. end
  504. end
  505. end
  506. feature {LIBERTY_SEMANTICS_BUILDER}
  507. set_has_manifest_array is
  508. do
  509. has_manifest_array := True
  510. if reachable_mark > 0 then
  511. mark_manifest_array_features(reachable_mark)
  512. end
  513. ensure
  514. has_manifest_array
  515. end
  516. feature {LIBERTY_TYPE_MANIFEST_ARRAY_FEATURES_LISTENER}
  517. mark_manifest_array_features (mark: like reachable_mark) is
  518. local
  519. fd_put, fd_make, fd_creation: like feature_definition
  520. do
  521. if not is_built then
  522. add_listener(create {LIBERTY_TYPE_MANIFEST_ARRAY_FEATURES_LISTENER}.make(mark))
  523. else
  524. -- TODO: should do those lookups in ANY (because of possible renames)
  525. fd_creation := feature_definition(manifest_creation_feature_name) -- always exists (in ANY)
  526. if fd_creation.creation_clients = Void then
  527. -- TODO: error, "manifest_creation" feature should belong to the creation clause
  528. not_yet_implemented
  529. end
  530. if not has_feature(manifest_put_feature_name) then
  531. -- TODO: error, using manifest expressions but missing "manifest_put" feature
  532. not_yet_implemented
  533. else
  534. fd_put := feature_definition(manifest_put_feature_name)
  535. if fd_put.result_type /= Void then
  536. -- TODO: error, "manifest_put" feature should be a procedure
  537. not_yet_implemented
  538. end
  539. fd_put.mark_reachable_code(mark)
  540. end
  541. if not has_feature(manifest_make_feature_name) then
  542. -- TODO: error, using manifest expressions but missing "manifest_make" feature
  543. not_yet_implemented
  544. else
  545. fd_make := feature_definition(manifest_make_feature_name)
  546. if fd_make.result_type /= Void then
  547. -- TODO: error, "manifest_make" feature should be a procedure
  548. not_yet_implemented
  549. end
  550. fd_make.mark_reachable_code(mark)
  551. end
  552. end
  553. end
  554. feature {}
  555. types_marker: LIBERTY_REACHABLE_COLLECTION_MARKER[LIBERTY_ACTUAL_TYPE]
  556. feature {LIBERTY_UNIVERSE, LIBERTY_ACTUAL_TYPE}
  557. descriptor: LIBERTY_TYPE_DESCRIPTOR
  558. feature {LIBERTY_AST_HANDLER}
  559. ast: LIBERTY_AST_ONE_CLASS
  560. feature {}
  561. make (a_descriptor: like descriptor; a_conformance_checker: like conformance_checker; a_ast: like ast; a_visit: like visit) is
  562. require
  563. a_descriptor /= Void
  564. a_conformance_checker /= Void
  565. a_visit /= Void
  566. do
  567. descriptor := a_descriptor
  568. conformance_checker := a_conformance_checker
  569. ast := a_ast
  570. create {HASHED_DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]} features.with_capacity(50) -- ANY contains 50 features
  571. conformant_parents := no_parents
  572. non_conformant_parents := no_parents
  573. visit := a_visit
  574. create current_entity.make(Current, errors.unknown_position)
  575. create result_entity.make(Current, errors.unknown_position)
  576. create {FAST_ARRAY[LIBERTY_TYPE_LISTENER]} listeners.with_capacity(2)
  577. debug ("full_name")
  578. debug_full_name := full_name.out
  579. end
  580. ensure
  581. descriptor = a_descriptor
  582. conformance_checker = a_conformance_checker
  583. ast = a_ast
  584. not_yet_reachable: not is_reachable
  585. end
  586. runtime_category: INTEGER_8
  587. deferred_category: INTEGER_8 is 1
  588. expanded_category: INTEGER_8 is 2
  589. separate_category: INTEGER_8 is 4
  590. reference_category: INTEGER_8 is 8
  591. errors: LIBERTY_ERRORS
  592. builder: LIBERTY_TYPE_BUILDER
  593. visit: PROCEDURE[TUPLE[LIBERTY_TYPE_VISITOR, LIBERTY_ACTUAL_TYPE]]
  594. no_parents: COLLECTION[LIBERTY_ACTUAL_TYPE] is
  595. once
  596. create {FAST_ARRAY[LIBERTY_ACTUAL_TYPE]} Result.with_capacity(0)
  597. end
  598. conformance_checker: LIBERTY_GENERICS_CONFORMANCE_CHECKER
  599. converters: DICTIONARY[PROCEDURE[TUPLE[LIBERTY_TYPE_CONVERTER]], LIBERTY_KNOWN_TYPE]
  600. -- actually contains only LIBERTY_ACTUAL_TYPE objects but it helps to be able to check against
  601. -- LIBERTY_VOID_TYPE
  602. has_manifest_array: BOOLEAN
  603. -- True if some manifest array expression builds an object of this type
  604. debug_full_name: STRING
  605. invariant
  606. descriptor /= Void
  607. file /= Void
  608. features /= Void
  609. features.for_all(agent (fd: LIBERTY_FEATURE_DEFINITION; fn: LIBERTY_FEATURE_NAME): BOOLEAN is
  610. do
  611. Result := fd.feature_name.is_equal(fn)
  612. and then fd.current_type = Current
  613. end
  614. )
  615. parameters /= Void
  616. visit /= Void
  617. cluster /= Void
  618. conformant_parents /= Void
  619. non_conformant_parents /= Void
  620. builder /= Void implies builder.type = Current
  621. current_entity /= Void
  622. result_entity /= Void
  623. end -- class LIBERTY_ACTUAL_TYPE