/src/tools/semantics/types/type_builder/liberty_type_parent_features_loader.e

http://github.com/tybor/Liberty · Specman e · 411 lines · 362 code · 18 blank · 31 comment · 18 complexity · 5fb9bb5578e97cd939e758d65bfa07ac 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_TYPE_PARENT_FEATURES_LOADER
  16. --
  17. -- Loads the type's parents' features.
  18. --
  19. -- Also loads the parent invariant.
  20. --
  21. insert
  22. LIBERTY_TYPE_BUILDER_TOOLS
  23. creation {LIBERTY_TYPE_BUILDER}
  24. make
  25. feature {}
  26. make (a_builder: like builder; a_current_entity: like current_entity; a_universe: like universe; a_effective_generic_parameters: like effective_generic_parameters; a_redefined_features: like redefined_features) is
  27. require
  28. a_builder /= Void
  29. a_current_entity /= Void
  30. a_universe /= Void
  31. a_effective_generic_parameters /= Void
  32. a_redefined_features /= Void
  33. do
  34. builder := a_builder
  35. current_entity := a_current_entity
  36. type := a_current_entity.result_type
  37. universe := a_universe
  38. effective_generic_parameters := a_effective_generic_parameters
  39. create {HASHED_DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]} parent_features.with_capacity(50) -- ANY contains 50 features
  40. redefined_features := a_redefined_features
  41. ensure
  42. builder = a_builder
  43. current_entity = a_current_entity
  44. universe = a_universe
  45. effective_generic_parameters = a_effective_generic_parameters
  46. redefined_features = a_redefined_features
  47. end
  48. universe: LIBERTY_UNIVERSE
  49. feature {LIBERTY_TYPE_BUILDER}
  50. load is
  51. local
  52. has_parents: BOOLEAN
  53. do
  54. has_parents := inject_parents(type.ast.inherit_clause, False)
  55. has_parents := inject_parents(type.ast.insert_clause, has_parents)
  56. if not has_parents and then not errors.has_error then
  57. inject_parent_invariant(universe.type_any)
  58. inject_parent_features(universe.type_any, Void)
  59. end
  60. push_parent_features_in_type
  61. if not redefined_features.is_empty then
  62. builder.set_redefined_features(redefined_features)
  63. end
  64. end
  65. feature {}
  66. inject_parents (parents: LIBERTY_AST_LIST[LIBERTY_AST_PARENT]; had_parents: BOOLEAN): BOOLEAN is
  67. local
  68. i: INTEGER; parent_clause: LIBERTY_AST_PARENT
  69. parent: LIBERTY_TYPE; actual_parent: LIBERTY_ACTUAL_TYPE
  70. do
  71. from
  72. Result := had_parents
  73. i := parents.list_lower
  74. until
  75. errors.has_error or else i > parents.list_upper
  76. loop
  77. parent_clause := parents.list_item(i)
  78. parent := type_lookup.resolver.type(parent_clause.type_definition)
  79. if parent = Void then
  80. --|*** TODO: error, parent not found
  81. not_yet_implemented
  82. end
  83. actual_parent ::= parent.known_type
  84. check
  85. type.is_child_of(actual_parent)
  86. end
  87. inject_parent_invariant(actual_parent)
  88. inject_parent_features(actual_parent, parent_clause.parent_clause)
  89. Result := True
  90. i := i + 1
  91. end
  92. end
  93. inject_parent_invariant (parent: LIBERTY_ACTUAL_TYPE) is
  94. do
  95. --|*** TODO
  96. end
  97. inject_parent_features (parent: LIBERTY_ACTUAL_TYPE; clause: LIBERTY_AST_PARENT_CLAUSE) is
  98. local
  99. i: INTEGER; fd, parent_fd, actual_fd: LIBERTY_FEATURE_DEFINITION; feature_name: LIBERTY_FEATURE_NAME
  100. pf: like parent_features; rf_count: INTEGER
  101. precursor_feature: LIBERTY_FEATURE
  102. do
  103. create {HASHED_DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]} pf.with_capacity(parent.features.count)
  104. from
  105. i := parent.features.lower
  106. until
  107. i > parent.features.upper
  108. loop
  109. feature_name := parent.features.key(i)
  110. parent_fd := parent.features.item(i)
  111. check
  112. parent_fd.current_type = parent
  113. end
  114. fd := parent_fd.specialized_in(type)
  115. check
  116. fd /= parent_fd
  117. end
  118. if fd.has_precursor(parent) then
  119. breakpoint
  120. else
  121. precursor_feature := fd.the_feature.specialized_in(type)
  122. fd.add_precursor(precursor_feature, parent)
  123. end
  124. pf.add(fd, feature_name)
  125. i := i + 1
  126. end
  127. if clause /= Void and then clause.has_clauses then
  128. rename_features(pf, clause.rename_clause, parent)
  129. export_features(pf, clause.export_clause)
  130. undefine_features(parent, pf, clause.undefine_clause)
  131. rf_count := redefine_features(parent, pf, clause.redefine_clause)
  132. if rf_count > 0 and then redefined_features.is_empty then
  133. -- create a new collection because the default empty collection is shared
  134. create {HASHED_DICTIONARY[LIBERTY_FEATURE_REDEFINED, LIBERTY_FEATURE_NAME]} redefined_features.with_capacity(rf_count)
  135. end
  136. end
  137. from
  138. i := pf.lower
  139. until
  140. i > pf.upper
  141. loop
  142. feature_name := pf.key(i)
  143. fd := pf.item(i)
  144. actual_fd := parent_features.reference_at(feature_name)
  145. if actual_fd = Void then
  146. parent_features.add(fd, feature_name)
  147. debug ("type.building.internals")
  148. log.trace.put_string(once " <=> ")
  149. log.trace.put_string(parent.full_name)
  150. log.trace.put_string(once ": late binding down to ")
  151. log.trace.put_string(type.full_name)
  152. log.trace.put_string(once " of feature ")
  153. log.trace.put_line(feature_name.full_name)
  154. end
  155. precursor_feature := fd.the_feature.specialized_in(type)
  156. check
  157. precursor_feature.current_type = type
  158. end
  159. fd.the_feature.bind(precursor_feature, type)
  160. if not fd.has_precursor(parent) then
  161. fd.add_precursor(precursor_feature, parent)
  162. end
  163. actual_fd := fd
  164. else
  165. debug ("type.building.internals")
  166. log.trace.put_string(once " <=> ")
  167. log.trace.put_string(parent.full_name)
  168. log.trace.put_string(once ": joining in ")
  169. log.trace.put_string(type.full_name)
  170. log.trace.put_string(once " of feature ")
  171. log.trace.put_line(feature_name.full_name)
  172. end
  173. actual_fd.join(fd, parent)
  174. check
  175. actual_fd.feature_name.is_equal(feature_name)
  176. end
  177. actual_fd.the_feature.bind(actual_fd.the_feature, type)
  178. end
  179. actual_fd.the_feature.add_if_redefined(type, feature_name, redefined_features)
  180. check
  181. actual_fd.has_precursor(parent)
  182. actual_fd.the_feature.bound(type) = actual_fd.the_feature
  183. end
  184. i := i + 1
  185. end
  186. end
  187. rename_features (pf: like parent_features; clause: LIBERTY_AST_PARENT_RENAME; parent: LIBERTY_ACTUAL_TYPE) is
  188. local
  189. i: INTEGER; r: LIBERTY_AST_RENAME; old_name, new_name: LIBERTY_FEATURE_NAME
  190. fd, fd2: LIBERTY_FEATURE_DEFINITION
  191. do
  192. from
  193. i := clause.list_lower
  194. until
  195. i > clause.list_upper
  196. loop
  197. r := clause.list_item(i)
  198. create old_name.make_from_ast(r.old_name.feature_name_or_alias, type.ast, type.file)
  199. create new_name.make_from_ast(r.new_name.feature_name_or_alias, type.ast, type.file)
  200. fd := pf.reference_at(old_name)
  201. if fd = Void then
  202. errors.add_position(old_name.position)
  203. errors.set(level_error, once "Cannot rename inexistent feature: " + old_name.name)
  204. else
  205. fd2 := pf.reference_at(new_name)
  206. if fd2 = Void then
  207. pf.remove(old_name)
  208. fd.re_name(new_name)
  209. pf.add(fd, new_name)
  210. else
  211. pf.remove(old_name)
  212. fd2.join(fd, parent)
  213. --|*** TODO: how to know that that particular join provoked an error?
  214. --if errors.has_error then
  215. -- errors.add_position(new_name.position)
  216. -- errors.set(level_error, once "Cannot rename feature (another feature with the same name exists): " + new_name.name)
  217. --end
  218. end
  219. end
  220. i := i + 1
  221. end
  222. end
  223. export_features (pf: like parent_features; clause: LIBERTY_AST_PARENT_EXPORT) is
  224. local
  225. i, j: INTEGER; e: LIBERTY_AST_EXPORT; ef: LIBERTY_AST_EXPORT_FEATURES; feature_name: LIBERTY_FEATURE_NAME; fn: LIBERTY_AST_FEATURE_NAME
  226. clients: COLLECTION[LIBERTY_TYPE]
  227. fd: LIBERTY_FEATURE_DEFINITION
  228. do
  229. from
  230. i := clause.list_lower
  231. until
  232. i > clause.list_upper
  233. loop
  234. e := clause.list_item(i)
  235. clients := list_clients(e.clients)
  236. ef := e.features
  237. if ef.is_all then
  238. from
  239. j := pf.lower
  240. until
  241. j > pf.upper
  242. loop
  243. --|*** TODO: wrong! "all" should only change the clients of those not specifically changed.
  244. pf.item(j).set_clients(clients)
  245. j := j + 1
  246. end
  247. else
  248. from
  249. j := ef.feature_names.lower
  250. until
  251. j > ef.feature_names.upper
  252. loop
  253. fn ::= ef.feature_names.item(j)
  254. create feature_name.make_from_ast(fn.feature_name_or_alias, type.ast, type.file)
  255. fd := pf.reference_at(feature_name)
  256. if fd = Void then
  257. errors.add_position(feature_name.position)
  258. errors.set(level_error, once "Cannot change export of inexistent feature: " + feature_name.name)
  259. else
  260. fd.set_clients(clients)
  261. end
  262. j := j + 1
  263. end
  264. end
  265. i := i + 1
  266. end
  267. end
  268. undefine_features (parent: LIBERTY_ACTUAL_TYPE; pf: like parent_features; clause: LIBERTY_AST_PARENT_UNDEFINE) is
  269. -- replace the feature by a LIBERTY_FEATURE_DEFERRED
  270. local
  271. i: INTEGER; feature_name: LIBERTY_FEATURE_NAME; fd: LIBERTY_FEATURE_DEFINITION
  272. inherited_feature: LIBERTY_FEATURE; deferred_feature: LIBERTY_FEATURE_DEFERRED
  273. do
  274. from
  275. i := clause.list_lower
  276. until
  277. i > clause.list_upper
  278. loop
  279. create feature_name.make_from_ast(clause.list_item(i).feature_name_or_alias, type.ast, type.file)
  280. fd := pf.reference_at(feature_name)
  281. if fd = Void then
  282. errors.add_position(feature_name.position)
  283. errors.set(level_error, once "Cannot undefine inexistent feature: " + feature_name.name)
  284. elseif fd.is_frozen then
  285. errors.add_position(feature_name.position)
  286. errors.set(level_error, once "Cannot undefine frozen feature: " + feature_name.name)
  287. else
  288. inherited_feature := fd.the_feature.specialized_in(type)
  289. create deferred_feature.make(type)
  290. deferred_feature.set_precondition(inherited_feature.precondition)
  291. deferred_feature.set_postcondition(inherited_feature.postcondition)
  292. deferred_feature.set_context(inherited_feature.context)
  293. deferred_feature.set_type_resolver(inherited_feature.type_resolver, True)
  294. debug ("type.building.internals")
  295. log.trace.put_string(once " <=> ")
  296. log.trace.put_string(parent.full_name)
  297. log.trace.put_string(once ": late binding down to ")
  298. log.trace.put_string(type.full_name)
  299. log.trace.put_string(once " of undefined feature ")
  300. log.trace.put_line(feature_name.full_name)
  301. end
  302. deferred_feature.replace(inherited_feature, type)
  303. fd.set_the_feature(deferred_feature)
  304. end
  305. i := i + 1
  306. end
  307. end
  308. redefine_features (parent: LIBERTY_ACTUAL_TYPE; pf: like parent_features; clause: LIBERTY_AST_PARENT_REDEFINE): INTEGER is
  309. -- replace the feature by a LIBERTY_FEATURE_REDEFINED
  310. local
  311. i: INTEGER; feature_name: LIBERTY_FEATURE_NAME; fd: LIBERTY_FEATURE_DEFINITION
  312. inherited_feature: LIBERTY_FEATURE; redefined_feature: LIBERTY_FEATURE
  313. do
  314. Result := clause.list_count
  315. if Result > 0 then
  316. from
  317. i := clause.list_lower
  318. until
  319. i > clause.list_upper
  320. loop
  321. create feature_name.make_from_ast(clause.list_item(i).feature_name_or_alias, type.ast, type.file)
  322. fd := pf.reference_at(feature_name)
  323. if fd = Void then
  324. errors.add_position(feature_name.position)
  325. errors.set(level_error, once "Cannot redefine inexistent feature: " + feature_name.name)
  326. elseif fd.is_frozen then
  327. errors.add_position(feature_name.position)
  328. errors.set(level_error, once "Cannot redefine frozen feature: " + feature_name.name)
  329. else
  330. inherited_feature := fd.the_feature.specialized_in(type)
  331. if inherited_feature.bound(type).id = inherited_feature.id then
  332. create {LIBERTY_FEATURE_REDEFINED} redefined_feature.make(type)
  333. redefined_feature.set_precondition(inherited_feature.precondition)
  334. redefined_feature.set_postcondition(inherited_feature.postcondition)
  335. redefined_feature.set_context(inherited_feature.context)
  336. redefined_feature.set_type_resolver(inherited_feature.type_resolver, True)
  337. debug ("type.building.internals")
  338. log.trace.put_string(once " <=> ")
  339. log.trace.put_string(parent.full_name)
  340. log.trace.put_string(once ": late binding down to ")
  341. log.trace.put_string(type.full_name)
  342. log.trace.put_string(once " of redefined feature ")
  343. log.trace.put_line(feature_name.full_name)
  344. end
  345. redefined_feature.replace(inherited_feature, type)
  346. else
  347. --|*** TODO: ??? is it possible to have a non-related feature here???
  348. redefined_feature := inherited_feature.bound(type)
  349. end
  350. fd.set_the_feature(redefined_feature)
  351. end
  352. i := i + 1
  353. end
  354. end
  355. end
  356. push_parent_features_in_type is
  357. local
  358. i: INTEGER
  359. fn, k: LIBERTY_FEATURE_NAME
  360. f: LIBERTY_FEATURE_DEFINITION
  361. do
  362. from
  363. i := parent_features.lower
  364. until
  365. i > parent_features.upper
  366. loop
  367. f := parent_features.item(i)
  368. fn := f.feature_name
  369. debug
  370. k := parent_features.key(i)
  371. check
  372. fn.is_equal(k)
  373. end
  374. end
  375. if not type.has_feature(fn) then
  376. torch.burn
  377. type.add_feature(f)
  378. else
  379. check
  380. type.features.reference_at(fn) = f
  381. end
  382. end
  383. i := i + 1
  384. end
  385. end
  386. feature {}
  387. parent_features: DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]
  388. redefined_features: DICTIONARY[LIBERTY_FEATURE_REDEFINED, LIBERTY_FEATURE_NAME]
  389. current_entity: LIBERTY_CURRENT
  390. invariant
  391. parent_features /= Void
  392. redefined_features /= Void
  393. end -- class LIBERTY_TYPE_PARENT_FEATURES_LOADER