PageRenderTime 134ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 0ms

/library/xpath/src/expression/xm_xpath_mapped_path_expression.e

http://github.com/gobo-eiffel/gobo
Specman e | 417 lines | 334 code | 50 blank | 33 comment | 27 complexity | 152ce44a9060496388c2e474bfb52cc2 MD5 | raw file
  1. note
  2. description:
  3. "XPath Path Expressions consisting of a node set followed by atomic-valued step"
  4. library: "Gobo Eiffel XPath Library"
  5. copyright: "Copyright (c) 2007-2015, Colin Adams and others"
  6. license: "MIT License"
  7. date: "$Date$"
  8. revision: "$Revision$"
  9. class XM_XPATH_MAPPED_PATH_EXPRESSION
  10. inherit
  11. XM_XPATH_COMPUTED_EXPRESSION
  12. redefine
  13. is_mapped_path_expression, as_mapped_path_expression, compute_special_properties,
  14. create_iterator, create_node_iterator, promote, compute_dependencies,
  15. same_expression, sub_expressions
  16. end
  17. XM_XPATH_CONTEXT_MAPPING_FUNCTION
  18. XM_XPATH_NODE_MAPPING_FUNCTION
  19. create
  20. make
  21. feature {NONE} -- Initialization
  22. make (a_start, a_step: like start; a_is_hybrid: BOOLEAN)
  23. -- Initialize `Current'.
  24. require
  25. a_start_not_void: a_start /= Void
  26. a_step_not_void: a_step /= Void
  27. do
  28. step := a_step -- to honour invariant
  29. set_start (a_start)
  30. set_step (a_step)
  31. is_hybrid := a_is_hybrid
  32. compute_static_properties
  33. initialized := True
  34. ensure
  35. static_properties_computed: are_static_properties_computed
  36. start_set: start = a_start
  37. step_set: step = a_step
  38. is_hybrid_set: is_hybrid = a_is_hybrid
  39. end
  40. feature -- Access
  41. start: XM_XPATH_EXPRESSION
  42. -- Starting node-set
  43. step: XM_XPATH_EXPRESSION
  44. -- Step from each node in starting node-set
  45. item_type: XM_XPATH_ITEM_TYPE
  46. --Determine the data type of the expression, if possible
  47. do
  48. Result := step.item_type
  49. end
  50. sub_expressions: DS_ARRAYED_LIST [XM_XPATH_EXPRESSION]
  51. -- Immediate sub-expressions of `Current'
  52. do
  53. create Result.make (2)
  54. Result.set_equality_tester (expression_tester)
  55. Result.put (start, 1)
  56. Result.put (step, 2)
  57. end
  58. feature -- Comparison
  59. same_expression (a_other: XM_XPATH_EXPRESSION): BOOLEAN
  60. -- Are `Current' and `a_other' the same expression?
  61. do
  62. if a_other.is_mapped_path_expression then
  63. Result := start.same_expression (a_other.as_mapped_path_expression.start) and then step.same_expression (a_other.as_mapped_path_expression.step)
  64. end
  65. end
  66. feature -- Status report
  67. is_hybrid: BOOLEAN
  68. -- Is `Current' a potential hybrid of nodes and atomic values?
  69. is_mapped_path_expression: BOOLEAN
  70. -- Is `Current' a mapped path expression?
  71. do
  72. Result := True
  73. end
  74. display (a_level: INTEGER)
  75. -- Diagnostic print of expression structure to `std.error'
  76. local
  77. l_string: STRING
  78. do
  79. l_string := STRING_.appended_string (indentation (a_level), "map /")
  80. std.error.put_string (l_string)
  81. std.error.put_new_line
  82. start.display (a_level + 1)
  83. step.display (a_level + 1)
  84. end
  85. feature -- Status setting
  86. compute_dependencies
  87. -- Compute dependencies on context.
  88. do
  89. if not are_intrinsic_dependencies_computed then
  90. compute_intrinsic_dependencies
  91. end
  92. set_dependencies (start)
  93. if step.depends_upon_xslt_context then
  94. set_depends_upon_xslt_context
  95. end
  96. end
  97. feature -- Optimization
  98. check_static_type (a_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]; a_context: XM_XPATH_STATIC_CONTEXT; a_context_item_type: detachable XM_XPATH_ITEM_TYPE)
  99. -- Perform static type-checking of `Current' and its subexpressions.
  100. do
  101. -- Original path expression has been checked already
  102. a_replacement.put (Current)
  103. end
  104. optimize (a_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]; a_context: XM_XPATH_STATIC_CONTEXT; a_context_item_type: detachable XM_XPATH_ITEM_TYPE)
  105. -- Perform optimization of `Current' and its subexpressions.
  106. local
  107. l_offer: XM_XPATH_PROMOTION_OFFER
  108. l_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]
  109. do
  110. create l_replacement.make (Void)
  111. start.optimize (l_replacement, a_context, a_context_item_type)
  112. check postcondition_of_optimize: attached l_replacement.item as l_replacement_item then
  113. if start /= l_replacement_item then
  114. set_start (l_replacement_item)
  115. end
  116. end
  117. if start.is_error then
  118. set_replacement (a_replacement, start)
  119. else
  120. l_replacement.put (Void)
  121. step.optimize (l_replacement, a_context, start.item_type)
  122. check postcondition_of_optimize: attached l_replacement.item as l_replacement_item then
  123. if step /= l_replacement_item then
  124. set_step (l_replacement_item)
  125. end
  126. end
  127. if step.is_error then
  128. set_replacement (a_replacement, step)
  129. else
  130. -- If any subexpressions within the step are not dependent on the focus,
  131. -- and if they cannot create new nodes, then promote them:
  132. -- This causes them to be evaluated once, outside the path expression
  133. create l_offer.make (Focus_independent, Void, Current, False, start.context_document_nodeset)
  134. promote_sub_expressions (a_replacement, a_context, a_context_item_type, l_offer)
  135. end
  136. end
  137. end
  138. promote (a_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]; a_offer: XM_XPATH_PROMOTION_OFFER)
  139. -- Promote this subexpression.
  140. local
  141. l_promotion: detachable XM_XPATH_EXPRESSION
  142. l_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]
  143. do
  144. a_offer.accept (Current)
  145. l_promotion := a_offer.accepted_expression
  146. if l_promotion /= Void then
  147. set_replacement (a_replacement, l_promotion)
  148. else
  149. a_replacement.put (Current)
  150. create l_replacement.make (Void)
  151. start.promote (l_replacement, a_offer)
  152. check postcondition_of_promote: attached l_replacement.item as l_replacement_item then
  153. if start /= l_replacement_item then
  154. set_start (l_replacement_item)
  155. reset_static_properties
  156. end
  157. end
  158. if a_offer.action = Inline_variable_references or a_offer.action = Replace_current then
  159. -- Don't pass on other requests. We could pass them on, but only after augmenting
  160. -- them to say we are interested in subexpressions that don't depend on either the
  161. -- outer context or the inner context.
  162. l_replacement.put (Void)
  163. step.promote (l_replacement, a_offer)
  164. check postcondition_of_promote: attached l_replacement.item as l_replacement_item then
  165. if step /= l_replacement_item then
  166. set_step (l_replacement_item)
  167. reset_static_properties
  168. end
  169. end
  170. end
  171. end
  172. end
  173. feature -- Evaluation
  174. create_iterator (a_context: XM_XPATH_CONTEXT)
  175. -- Create iterator over the values of a sequence.
  176. local
  177. l_iterator: XM_XPATH_SEQUENCE_ITERATOR [XM_XPATH_ITEM]
  178. l_other_context: XM_XPATH_CONTEXT
  179. l_last_iterator: like last_iterator
  180. do
  181. start.create_iterator (a_context)
  182. check postcondition_of_create_iterator: attached start.last_iterator as l_start_last_iterator then
  183. l_iterator := l_start_last_iterator
  184. if l_iterator.is_error then
  185. last_iterator := l_iterator
  186. else
  187. if a_context.has_push_processing then
  188. l_other_context := a_context.new_minor_context
  189. else
  190. l_other_context := a_context.new_context
  191. end
  192. l_other_context.set_current_iterator (l_iterator)
  193. if is_node_sequence then
  194. create {XM_XPATH_NODE_MAPPING_ITERATOR} last_iterator.make (l_iterator.as_node_iterator, Current, l_other_context)
  195. else
  196. create {XM_XPATH_CONTEXT_MAPPING_ITERATOR} l_last_iterator.make (Current, l_other_context)
  197. last_iterator := l_last_iterator
  198. if is_hybrid then
  199. l_iterator := l_last_iterator.another
  200. l_iterator.start
  201. if l_iterator.is_error then
  202. last_iterator := l_iterator
  203. elseif l_iterator.after then
  204. create {XM_XPATH_EMPTY_ITERATOR [XM_XPATH_NODE]} last_iterator.make
  205. elseif l_iterator.item.is_atomic_value then
  206. create {XM_XPATH_ITEM_MAPPING_ITERATOR} last_iterator.make (l_last_iterator, create {XM_XPATH_HOMOGENEOUS_ITEM_CHECKER}.make)
  207. else
  208. create {XM_XPATH_NODE_MAPPING_ITERATOR} l_last_iterator.make (l_last_iterator, create {XM_XPATH_HOMOGENEOUS_NODE_CHECKER}.make, l_other_context)
  209. create {XM_XPATH_DOCUMENT_ORDER_ITERATOR} last_iterator.make (l_last_iterator.as_node_iterator, create {XM_XPATH_GLOBAL_ORDER_COMPARER})
  210. end
  211. end
  212. end
  213. end
  214. end
  215. end
  216. create_node_iterator (a_context: XM_XPATH_CONTEXT)
  217. -- Create an iterator over a node sequence
  218. local
  219. l_iterator: XM_XPATH_SEQUENCE_ITERATOR [XM_XPATH_NODE]
  220. l_other_context: XM_XPATH_CONTEXT
  221. do
  222. start.create_node_iterator (a_context)
  223. check postcondition_of_create_node_iterator: attached start.last_node_iterator as l_last_node_iterator then
  224. l_iterator := l_last_node_iterator
  225. if l_iterator.is_error then
  226. last_node_iterator := l_iterator
  227. else
  228. if a_context.has_push_processing then
  229. l_other_context := a_context.new_minor_context
  230. else
  231. l_other_context := a_context.new_context
  232. end
  233. l_other_context.set_current_iterator (l_iterator)
  234. create {XM_XPATH_NODE_MAPPING_ITERATOR} last_node_iterator.make (l_iterator, Current, l_other_context)
  235. end
  236. end
  237. end
  238. map (a_context: XM_XPATH_CONTEXT)
  239. -- Map `a_context.context_item' to a sequence
  240. do
  241. step.create_iterator (a_context)
  242. last_mapped_sequence := step.last_iterator
  243. end
  244. map_nodes (a_item: XM_XPATH_ITEM; a_context: XM_XPATH_CONTEXT)
  245. -- Map `a_item' to a sequence
  246. do
  247. step.create_node_iterator (a_context)
  248. last_node_iterator := step.last_node_iterator
  249. end
  250. feature {XM_XPATH_PATH_EXPRESSION} -- Local
  251. set_start (a_start: XM_XPATH_EXPRESSION)
  252. -- Set `start'.
  253. require
  254. start_not_void: a_start /= Void
  255. do
  256. start := a_start
  257. adopt_child_expression (start)
  258. ensure
  259. start_set: start = a_start
  260. end
  261. set_step (a_step: XM_XPATH_EXPRESSION)
  262. -- Set `start'.
  263. require
  264. step_not_void: a_step /= Void
  265. do
  266. step := a_step
  267. adopt_child_expression (step)
  268. ensure
  269. step_set: step = a_step
  270. end
  271. feature -- Conversion
  272. as_mapped_path_expression: XM_XPATH_MAPPED_PATH_EXPRESSION
  273. -- `Current' seen as a mapped path expression
  274. do
  275. Result := Current
  276. end
  277. feature {XM_XPATH_EXPRESSION} -- Restricted
  278. compute_cardinality
  279. -- Compute cardinality.
  280. local
  281. c1, c2: INTEGER
  282. do
  283. if not start.are_cardinalities_computed then
  284. check
  285. start_is_computed: start.is_computed_expression
  286. -- as it can't be a value
  287. end
  288. start.as_computed_expression.compute_cardinality
  289. end
  290. if not step.are_cardinalities_computed then
  291. check
  292. step_is_computed: step.is_computed_expression
  293. -- as it can't be a value
  294. end
  295. step.as_computed_expression.compute_cardinality
  296. end
  297. c1 := start.cardinality
  298. c2 := step.cardinality
  299. set_cardinality (multiply_cardinality (c1, c2))
  300. are_cardinalities_computed := True
  301. end
  302. feature {NONE} -- Implementation
  303. promote_sub_expressions (a_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION];
  304. a_context: XM_XPATH_STATIC_CONTEXT; a_context_item_type: detachable XM_XPATH_ITEM_TYPE; a_offer: XM_XPATH_PROMOTION_OFFER)
  305. -- Promote any subexpressions within the step are not dependent on the focus.
  306. -- This causes them to be evaluated once, outside the path expression.
  307. require
  308. promotion_offer_not_void: a_offer /= Void
  309. a_replacement_not_void: a_replacement /= Void
  310. not_replaced: a_replacement.item = Void
  311. local
  312. l_expression: XM_XPATH_EXPRESSION
  313. l_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]
  314. do
  315. create l_replacement.make (Void)
  316. step.promote (l_replacement, a_offer)
  317. check postcondition_of_promote: attached l_replacement.item as l_replacement_item then
  318. if step /= l_replacement_item then
  319. set_step (l_replacement_item)
  320. reset_static_properties
  321. end
  322. end
  323. if step.is_error then
  324. set_replacement (a_replacement, step)
  325. else
  326. reset_static_properties
  327. if a_offer.containing_expression /= Current then
  328. l_replacement.put (Void)
  329. check attached a_offer.containing_expression as l_containing_expression then
  330. l_containing_expression.check_static_type (l_replacement, a_context, a_context_item_type)
  331. check postcondition_of_check_static_type: attached l_replacement.item as l_replacement_item then
  332. l_expression := l_replacement_item
  333. l_replacement.put (Void)
  334. l_expression.optimize (l_replacement, a_context, a_context_item_type)
  335. check postcondition_of_optimize: attached l_replacement.item as l_replacement_item2 then
  336. set_replacement (a_replacement, l_replacement_item2)
  337. end
  338. end
  339. end
  340. else
  341. a_replacement.put (Current)
  342. end
  343. end
  344. end
  345. compute_special_properties
  346. -- Compute special properties.
  347. local
  348. l_expression: XM_XPATH_COMPUTED_EXPRESSION
  349. do
  350. Precursor
  351. if not are_cardinalities_computed then compute_cardinality end
  352. if not start.are_special_properties_computed then
  353. l_expression := start.as_computed_expression
  354. l_expression.compute_special_properties
  355. end
  356. if not step.are_special_properties_computed then
  357. l_expression := step.as_computed_expression
  358. l_expression.compute_special_properties
  359. end
  360. if start.non_creating and then step.non_creating then
  361. set_non_creating
  362. end
  363. end
  364. invariant
  365. start_not_void: start /= Void
  366. step_not_void: step /= Void
  367. end