PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/tool/geant/src/geant_target.e

http://github.com/gobo-eiffel/gobo
Specman e | 719 lines | 558 code | 81 blank | 80 comment | 34 complexity | 4c1da2d6a192fb53e498072210470db8 MD5 | raw file
  1. note
  2. description:
  3. "Target of geant build file"
  4. library: "Gobo Eiffel Ant"
  5. copyright: "Copyright (c) 2001-2018, Sven Ehrke and others"
  6. license: "MIT License"
  7. date: "$Date$"
  8. revision: "$Revision$"
  9. class GEANT_TARGET
  10. inherit
  11. GEANT_GROUP
  12. redefine
  13. initialize, valid_xml_element,
  14. is_target, associated_target,
  15. prepare_variables_before_execution, execute, execute_element
  16. end
  17. create
  18. make
  19. feature {NONE} -- Initialization
  20. initialize
  21. -- Initialize current Target
  22. local
  23. a_xml_element: XM_ELEMENT
  24. a_tester: UC_STRING_EQUALITY_TESTER
  25. a_obsolete_element: XM_ELEMENT
  26. a_exports: DS_ARRAYED_LIST [STRING]
  27. a_elements: DS_LINKED_LIST [XM_ELEMENT]
  28. a_name: STRING
  29. a_argument_element: GEANT_ARGUMENT_ELEMENT
  30. a_local_element: GEANT_LOCAL_ELEMENT
  31. a_global_element: GEANT_GLOBAL_ELEMENT
  32. cs: DS_LINKED_LIST_CURSOR [XM_ELEMENT]
  33. do
  34. a_xml_element := xml_element
  35. -- name:
  36. if not attached xml_element.attribute_by_name (Name_attribute_name) as l_name_attribute then
  37. exit_application (1, <<"Element 'target' without attribute 'name' found.",
  38. " Make sure each target has an associated attribute 'name'.">>)
  39. set_name ("no_name")
  40. else
  41. set_name (l_name_attribute.value)
  42. end
  43. -- obsolete:
  44. a_obsolete_element := a_xml_element.element_by_name (Obsolete_element_name)
  45. if a_obsolete_element /= Void and then attached a_obsolete_element.text as l_text then
  46. set_obsolete_message (l_text)
  47. end
  48. -- export:
  49. if attached a_xml_element.attribute_by_name (Export_attribute_name) as l_export_attribute then
  50. a_exports := string_tokens (
  51. l_export_attribute.value, ',')
  52. else
  53. create a_exports.make (1)
  54. a_exports.put (Project_name_any, 1)
  55. end
  56. create a_tester
  57. a_exports.set_equality_tester (a_tester)
  58. set_exports (a_exports)
  59. -- once:
  60. if has_attribute (Once_attribute_name) then
  61. set_execute_once (boolean_value (Once_attribute_name))
  62. end
  63. -- formal arguments:
  64. formal_arguments := Empty_argument_variables
  65. a_elements := elements_by_name (Argument_element_name)
  66. if a_elements.count /= 0 then
  67. create formal_arguments.make
  68. cs := a_elements.new_cursor
  69. from cs.start until cs.after loop
  70. create a_argument_element.make (cs.item)
  71. if a_argument_element.has_name and then a_argument_element.name.count > 0 then
  72. a_name := a_argument_element.name
  73. formal_arguments.force_last ("dummy_value", a_name)
  74. project.trace_debug (<<"found formal argument '", a_name, "'%N">>)
  75. end
  76. cs.forth
  77. end
  78. end
  79. -- locals declaration:
  80. formal_locals := Empty_variables
  81. a_elements := elements_by_name (Local_element_name)
  82. if a_elements.count /= 0 then
  83. create formal_locals.make
  84. cs := a_elements.new_cursor
  85. from cs.start until cs.after loop
  86. create a_local_element.make (cs.item)
  87. if a_local_element.has_name and then a_local_element.name.count > 0 then
  88. a_name := a_local_element.name
  89. formal_locals.force_last ("", a_name) --| this is formal variable, the value is ignored at this point.
  90. project.trace_debug (<<"found local declaration '", a_name, "'%N">>)
  91. if formal_arguments.has (a_name) then
  92. project.log (<<" [local] name=", a_name, " warning: conflict with arguments variable." >>)
  93. end
  94. --| if a_local_element.has_value, the value will be set, when the element is processed
  95. end
  96. cs.forth
  97. end
  98. end
  99. -- globals declaration:
  100. formal_globals := Empty_variables
  101. a_elements := elements_by_name (Global_element_name)
  102. if a_elements.count /= 0 then
  103. create formal_globals.make
  104. cs := a_elements.new_cursor
  105. from cs.start until cs.after loop
  106. create a_global_element.make (cs.item)
  107. if a_global_element.has_name and then a_global_element.name.count > 0 then
  108. a_name := a_global_element.name
  109. formal_globals.force_last ("", a_name) --| this is formal variable, the value is ignored at this point.
  110. --| if a_global_element.has_value, the value will be set, when the element is processed
  111. project.trace_debug (<<"found global declaration '", a_name, "'%N">>)
  112. if formal_arguments.has (a_name) then
  113. project.log (<<" [global] name=", a_name, " warning: conflict with arguments variable." >>)
  114. elseif formal_locals.has (a_name) then
  115. project.log (<<" [global] name=", a_name, " warning: conflict with locals variable." >>)
  116. end
  117. end
  118. cs.forth
  119. end
  120. end
  121. Precursor {GEANT_GROUP}
  122. end
  123. feature -- Access
  124. is_target: BOOLEAN = True
  125. -- Is Current a GEANT_TARGET ?
  126. dependencies: STRING
  127. -- STRING representation of dependencies
  128. require
  129. has_dependencies: has_dependencies
  130. do
  131. check precondition: attached xml_element.attribute_by_name (Depend_attribute_name) as l_depend_attribute then
  132. Result := l_depend_attribute.value
  133. end
  134. ensure
  135. dependencies_not_void: Result /= Void
  136. end
  137. name: STRING
  138. -- Name of target
  139. obsolete_message: detachable STRING
  140. -- Obsolete message if any
  141. exports: DS_ARRAYED_LIST [STRING]
  142. -- Exports of target
  143. origin: GEANT_PROJECT
  144. -- Origin of target (see ETL for definition)
  145. do
  146. Result := seed.project
  147. ensure
  148. origin_not_void: Result /= Void
  149. end
  150. associated_target: GEANT_TARGET
  151. -- Associated target
  152. do
  153. Result := Current
  154. end
  155. full_name: STRING
  156. -- `Name' prepended with (`project.name' + ".")
  157. do
  158. Result := STRING_.cloned_string (project.name)
  159. Result.append_character ('.')
  160. Result := STRING_.appended_string (Result, name)
  161. ensure
  162. full_name_not_void: Result /= Void
  163. definition: STRING_.same_string (Result, STRING_.concat (STRING_.concat (project.name, "."), name))
  164. end
  165. precursor_target: detachable like Current
  166. -- Precursor of current target if this target
  167. -- was redefined
  168. redefining_target: detachable like Current
  169. -- Redefining target of current target if present;
  170. -- Used for polymorphic calls
  171. seed: like Current
  172. -- Original version of this target in most remote ancestor
  173. do
  174. from
  175. Result := Current
  176. until
  177. not attached Result.precursor_target as l_precursor_target
  178. loop
  179. Result := l_precursor_target
  180. end
  181. ensure
  182. seed_not_void: Result /= Void
  183. current_if_no_precursor_target: precursor_target = Void implies Result = Current
  184. seed_has_no_precursor: Result.precursor_target = Void
  185. end
  186. final_target: like Current
  187. -- Final target of this target in redefinition chain
  188. do
  189. from
  190. Result := Current
  191. until
  192. not attached Result.redefining_target as l_redefining_target
  193. loop
  194. Result := l_redefining_target
  195. end
  196. ensure
  197. final_target_not_void: Result /= Void
  198. current_if_no_redefining_target: redefining_target = Void implies Result = Current
  199. final_target_has_no_redefining_target: Result.redefining_target = Void
  200. end
  201. formal_arguments: GEANT_ARGUMENT_VARIABLES
  202. -- Formal arguments of this target
  203. formal_locals: GEANT_VARIABLES
  204. -- Formal locals of this target
  205. formal_globals: GEANT_VARIABLES
  206. -- Formal globals of this target
  207. prepared_arguments_from_formal_arguments (a_arguments: like formal_arguments): like formal_arguments
  208. -- Prepared actual arguments arguments for `formal_arguments';
  209. -- Numbered arguments are replaced by their associated named arguments according
  210. -- to `formal_arguments';
  211. -- Application is terminated in case there is a mismatch between `a_arguments' and
  212. -- `formal_arguments'
  213. require
  214. a_arguments_not_void: a_arguments /= Void
  215. a_arguments_and_formals_have_same_count: a_arguments.count = formal_arguments.count
  216. do
  217. -- Default Result is `a_arguments' if nothing needs to be changed:
  218. Result := a_arguments
  219. -- Check that actual and formal arguments match:
  220. if a_arguments.count /= formal_arguments.count then
  221. exit_application (1, <<" error: number of actual and formal arguments do not match for target '", name, "' (", a_arguments.count.out, " against ", formal_arguments.count.out, ")">>)
  222. end
  223. if a_arguments.has_numbered_keys then
  224. Result := named_from_numbered_arguments (a_arguments)
  225. end
  226. if not Result.has_same_keys (formal_arguments) then
  227. exit_application (1, <<" error: actual and formal arguments do not match for target '", name, "'">>)
  228. end
  229. end
  230. named_from_numbered_arguments (a_arguments: like formal_arguments): like formal_arguments
  231. -- Clone of `a_arguments' where number keys have been replaced by their
  232. -- corresponding names from `formal_arguments'
  233. require
  234. a_arguments_not_void: a_arguments /= Void
  235. a_arguments_and_formals_have_same_count: a_arguments.count = formal_arguments.count
  236. a_arguments_has_numbered_arguments: a_arguments.has_numbered_keys
  237. local
  238. csa: DS_HASH_TABLE_CURSOR [STRING, STRING]
  239. csf: DS_HASH_TABLE_CURSOR [STRING, STRING]
  240. do
  241. create Result.make
  242. csa := a_arguments.new_cursor
  243. csf :=formal_arguments.new_cursor
  244. csa.start
  245. csf.start
  246. from until csa.after loop
  247. Result.force_last (csa.item, csf.key)
  248. csa.forth
  249. csf.forth
  250. end
  251. end
  252. feature -- Status report
  253. is_executed: BOOLEAN
  254. -- Was this target executed already?
  255. execute_once: BOOLEAN
  256. -- Is this target supposed to be executed only once?
  257. is_exported_to_any: BOOLEAN
  258. -- Is this target exported to any project?
  259. do
  260. if exports /= Void then
  261. Result := exports.has (Project_name_any)
  262. end
  263. ensure
  264. definition: Result implies (exports /= Void and then exports.has (Project_name_any))
  265. end
  266. is_exported_to_project (a_project: GEANT_PROJECT): BOOLEAN
  267. -- Is this target exported to project named `a_project_name'?
  268. require
  269. a_project_not_void: a_project /= Void
  270. local
  271. i, nb: INTEGER
  272. a_project_name: STRING
  273. an_export: STRING
  274. do
  275. if exports /= Void then
  276. a_project_name := a_project.name
  277. nb := exports.count
  278. from i := 1 until i > nb loop
  279. an_export := exports.item (i)
  280. if STRING_.same_string (a_project_name, an_export) then
  281. Result := True
  282. i := nb + 1 -- Jump out of the loop.
  283. elseif a_project.has_parent_with_name (an_export) then
  284. Result := True
  285. i := nb + 1 -- Jump out of the loop.
  286. else
  287. i := i + 1
  288. end
  289. end
  290. end
  291. end
  292. has_dependencies: BOOLEAN
  293. -- Has current target dependent on other targets?
  294. do
  295. Result := xml_element.has_attribute_by_name (Depend_attribute_name)
  296. ensure
  297. definition: Result = xml_element.has_attribute_by_name (Depend_attribute_name)
  298. end
  299. valid_xml_element (an_xml_element: like xml_element): BOOLEAN
  300. -- Is `an_xml_element' a valid xml element?
  301. do
  302. Result := attached an_xml_element.attribute_by_name (Name_attribute_name) as l_name_attribute and then
  303. l_name_attribute.value.count > 0
  304. ensure then
  305. has_name_attribute: Result implies an_xml_element.has_attribute_by_name (Name_attribute_name)
  306. has_non_empty_name_attribute: Result implies attached an_xml_element.attribute_by_name (Name_attribute_name) as l_name_attribute and then l_name_attribute.value.count > 0
  307. end
  308. conflicts_with (a_target: like Current): BOOLEAN
  309. -- Does current target or one of it's precursors
  310. -- have a `full_name' which is equal to the `full_name'
  311. -- of `a_target' or one of it's precursors?
  312. require
  313. a_target_not_void: a_target /= Void
  314. do
  315. Result := STRING_.same_string (seed.full_name, a_target.seed.full_name)
  316. end
  317. formal_arguments_match (a_target: like Current): BOOLEAN
  318. -- Does `formal_arguments' match `a_target.formal_arguments'?
  319. require
  320. a_target_not_void: a_target /= Void
  321. do
  322. Result := formal_arguments.has_same_keys (a_target.formal_arguments)
  323. end
  324. has_precursor_target (a_target: like Current): BOOLEAN
  325. -- Is current target or one of it's precursors `a_target'?
  326. require
  327. a_target_not_void: a_target /= Void
  328. local
  329. a_precursor_target: like Current
  330. do
  331. from
  332. a_precursor_target := precursor_target
  333. until
  334. a_precursor_target = Void or else Result
  335. loop
  336. Result := a_precursor_target = a_target
  337. a_precursor_target := a_precursor_target.precursor_target
  338. end
  339. end
  340. has_redefining_target (a_target: like Current): BOOLEAN
  341. -- Is current target or one of it's `redefining_target's `a_target'?
  342. require
  343. a_target_not_void: a_target /= Void
  344. local
  345. a_redefining_target: like Current
  346. do
  347. from
  348. a_redefining_target := redefining_target
  349. until
  350. a_redefining_target = Void or else Result
  351. loop
  352. Result := a_redefining_target = a_target
  353. a_redefining_target := a_redefining_target.redefining_target
  354. end
  355. end
  356. feature -- Setting
  357. set_name (a_name: STRING)
  358. -- Set `name' to `a_name'.
  359. require
  360. a_name_not_void: a_name /= Void
  361. a_name_not_empty: a_name.count > 0
  362. do
  363. name := a_name
  364. ensure
  365. name_set: name = a_name
  366. end
  367. set_obsolete_message (a_obsolete_message: STRING)
  368. -- Set `obsolete_message' to `a_obsolete_message'.
  369. require
  370. a_obsolete_message_not_void: a_obsolete_message /= Void
  371. a_obsolete_message_not_empty: a_obsolete_message.count > 0
  372. do
  373. obsolete_message := a_obsolete_message
  374. ensure
  375. obsolete_message_set: obsolete_message = a_obsolete_message
  376. end
  377. set_exports (a_exports: like exports)
  378. -- Set `exports' to `a_exports'.
  379. require
  380. a_exports_not_void: a_exports /= Void
  381. do
  382. exports := a_exports
  383. ensure
  384. exports_set: exports = a_exports
  385. end
  386. set_executed (a_is_executed: BOOLEAN)
  387. -- Set `is_executed' to `a_is_executed'.
  388. do
  389. is_executed := a_is_executed
  390. ensure
  391. is_executed_set: is_executed = a_is_executed
  392. end
  393. set_execute_once (a_execute_once: BOOLEAN)
  394. -- Set `execute_once' to `a_execute_once'.
  395. do
  396. execute_once := a_execute_once
  397. ensure
  398. execute_once_set: execute_once = a_execute_once
  399. end
  400. set_precursor_target (a_precursor_target: GEANT_TARGET)
  401. -- Set `precursor_target' to `a_precursor_target'.
  402. require
  403. a_precursor_target_not_void: a_precursor_target /= Void
  404. a_precursor_target_not_current: a_precursor_target /= Current
  405. no_circular_target_chain: not a_precursor_target.has_precursor_target (Current)
  406. do
  407. precursor_target := a_precursor_target
  408. ensure
  409. precursor_target_set: precursor_target = a_precursor_target
  410. end
  411. set_redefining_target (a_redefining_target: GEANT_TARGET)
  412. -- Set `redefining_target' to `a_redefining_target'.
  413. require
  414. a_redefining_target_not_void: a_redefining_target /= Void
  415. a_redefining_target_not_current: a_redefining_target /= Current
  416. no_circular_target_chain: not a_redefining_target.has_redefining_target (Current)
  417. do
  418. redefining_target := a_redefining_target
  419. ensure
  420. redefining_target_set: redefining_target = a_redefining_target
  421. end
  422. feature -- Processing
  423. show_precursors
  424. -- Show list of precursors.
  425. local
  426. a_precursor_target: like Current
  427. a_message: DS_ARRAYED_LIST [STRING]
  428. do
  429. from
  430. a_precursor_target := Current
  431. create a_message.make (10)
  432. a_message.force_last (" precursor list: ")
  433. until
  434. a_precursor_target = Void
  435. loop
  436. a_message.force_last ("'")
  437. a_message.force_last (a_precursor_target.full_name)
  438. a_message.force_last ("'")
  439. a_precursor_target := a_precursor_target.precursor_target
  440. if a_precursor_target /= Void then
  441. a_message.force_last (", ")
  442. end
  443. end
  444. project.trace_debug (a_message.to_array)
  445. end
  446. execute
  447. -- Execute all tasks of `a_target' in sequential order.
  448. do
  449. if not execute_once or else not is_executed then
  450. if is_enabled then
  451. if project.options.verbose then
  452. project.trace (<<"">>)
  453. project.trace (<<project.name, ".", project.target_name (Current), ":">>)
  454. project.trace (<<"">>)
  455. end
  456. if attached obsolete_message as l_obsolete_message then
  457. project.log (<<"target `", project.name, ".", project.target_name (Current), "%' is obsolete. ", l_obsolete_message>>)
  458. end
  459. Precursor {GEANT_GROUP}
  460. -- Mark target as already executed:
  461. set_executed (True)
  462. end
  463. end
  464. end
  465. feature {NONE} -- Execution implementation
  466. prepare_variables_before_execution
  467. -- Prepare variables before tasks execution
  468. local
  469. a_arguments: GEANT_ARGUMENT_VARIABLES
  470. a_locals: GEANT_VARIABLES
  471. cursor: DS_HASH_TABLE_CURSOR [STRING, STRING]
  472. do
  473. -- Prepare arguments:
  474. a_arguments := target_arguments_stack.item
  475. target_arguments_stack.remove
  476. a_arguments := prepared_arguments_from_formal_arguments (a_arguments)
  477. target_arguments_stack.force (a_arguments)
  478. --| Prepare locals:
  479. --| to be sure local variable ${foo} does not return a globals variable's value
  480. --| the locals stack needs to have an entry for each locals.
  481. a_locals := target_locals_stack.item
  482. check no_locals: a_locals.count = 0 end
  483. if formal_locals.count > 0 then
  484. from
  485. cursor := formal_locals.new_cursor
  486. cursor.start
  487. until
  488. cursor.after
  489. loop
  490. if cursor.item = Void then
  491. a_locals.force_last (create {STRING}.make_empty, cursor.key)
  492. --| we can not set Void, otherwise the interpreter
  493. --| will look in the global variables
  494. --| Suggestion: fixed the interpreter to allow Void value.
  495. else
  496. a_locals.force_last (cursor.item, cursor.key)
  497. end
  498. cursor.forth
  499. end
  500. end
  501. --| No need to prepare globals, since the container already exists `project.variables'
  502. Precursor {GEANT_GROUP}
  503. end
  504. execute_element (a_xml_element: XM_ELEMENT)
  505. -- Execute command defined through `a_xml_element'.
  506. local
  507. var_decl: GEANT_NAME_VALUE_ELEMENT
  508. conv_xml_element: XM_ELEMENT
  509. do
  510. if
  511. STRING_.same_string (a_xml_element.name, Local_element_name) or
  512. STRING_.same_string (a_xml_element.name, Global_element_name)
  513. then
  514. create var_decl.make (a_xml_element)
  515. if var_decl.has_value then
  516. conv_xml_element := a_xml_element.cloned_object
  517. conv_xml_element.set_name (Set_attribute_name)
  518. execute_task (conv_xml_element)
  519. end
  520. elseif
  521. not STRING_.same_string (a_xml_element.name, Description_element_name) and
  522. not STRING_.same_string (a_xml_element.name, Argument_element_name) and
  523. not STRING_.same_string (a_xml_element.name, Obsolete_element_name)
  524. then
  525. execute_task (a_xml_element)
  526. end
  527. end
  528. feature -- Dependencies
  529. dependent_targets: DS_ARRAYED_STACK [GEANT_TARGET]
  530. -- All dependent targets
  531. local
  532. a_dependent_target: GEANT_TARGET
  533. a_value: STRING
  534. a_dependent_targets: DS_ARRAYED_LIST [STRING]
  535. i: INTEGER
  536. do
  537. create Result.make (10)
  538. if has_dependencies then
  539. -- Check for targets separated by commas:
  540. a_dependent_targets := string_tokens (dependencies, ',')
  541. if project.options.debug_mode then
  542. show_dependent_targets (a_dependent_targets)
  543. end
  544. -- Find all targets.
  545. from i := 1 until i > a_dependent_targets.count loop
  546. a_value := a_dependent_targets.item (i)
  547. if attached project.targets as l_targets and then l_targets.has (a_value) then
  548. a_dependent_target := l_targets.item (a_value).final_target
  549. Result.force (a_dependent_target)
  550. else
  551. exit_application (1, <<"geant error: unknown dependent target '", a_value, "%'">>)
  552. end
  553. i := i + 1
  554. end
  555. end
  556. ensure
  557. dependent_targets_not_void: Result /= Void
  558. end
  559. show_dependent_targets (a_dependent_targets: DS_ARRAYED_LIST [STRING])
  560. -- Show dependent targets.
  561. local
  562. i: INTEGER
  563. do
  564. std.output.put_line ("======= DEPENDENCIES ==========")
  565. from i := 1 until i > a_dependent_targets.count loop
  566. std.output.put_line (a_dependent_targets.item (i))
  567. i := i + 1
  568. end
  569. std.output.put_line ("=================")
  570. end
  571. feature {NONE} -- Constants
  572. Obsolete_element_name: STRING
  573. -- Name of xml subelement for obsolete
  574. once
  575. Result := "obsolete"
  576. ensure
  577. attribute_name_not_void: Result /= Void
  578. attribute_name_not_empty: Result.count > 0
  579. end
  580. Argument_element_name: STRING
  581. -- Name of xml subelement for arguments
  582. once
  583. Result := "argument"
  584. ensure
  585. attribute_name_not_void: Result /= Void
  586. attribute_name_not_empty: Result.count > 0
  587. end
  588. Name_attribute_name: STRING
  589. -- "name" attribute name
  590. once
  591. Result := "name"
  592. ensure
  593. attribute_name_not_void: Result /= Void
  594. attribute_name_not_empty: Result.count > 0
  595. end
  596. Set_attribute_name: STRING
  597. -- "set" attribute name
  598. once
  599. Result := "set"
  600. ensure
  601. attribute_name_not_void: Result /= Void
  602. attribute_name_not_empty: Result.count > 0
  603. end
  604. Depend_attribute_name: STRING
  605. -- "depend" attribute name
  606. once
  607. Result := "depend"
  608. ensure
  609. attribute_name_not_void: Result /= Void
  610. attribute_name_not_empty: Result.count > 0
  611. end
  612. Export_attribute_name: STRING
  613. -- "export" attribute name
  614. once
  615. Result := "export"
  616. ensure
  617. export_name_not_void: Result /= Void
  618. export_name_not_empty: Result.count > 0
  619. end
  620. Once_attribute_name: STRING
  621. -- "once" attribute name
  622. once
  623. Result := "once"
  624. ensure
  625. once_name_not_void: Result /= Void
  626. once_name_not_empty: Result.count > 0
  627. end
  628. Project_name_any: STRING
  629. -- Project name "ANY"
  630. once
  631. Result := "ANY"
  632. ensure
  633. Project_name_any_not_void: Result /= Void
  634. Project_name_any_not_empty: Result.count > 0
  635. end
  636. invariant
  637. no_void_export: exports /= Void implies not exports.has_void
  638. end