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