PageRenderTime 63ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/library/xslt/src/style/xm_xslt_general_variable.e

http://github.com/gobo-eiffel/gobo
Specman e | 500 lines | 402 code | 53 blank | 45 comment | 45 complexity | 2a0b6bf3a5844b6898bbf5e2ee23791b MD5 | raw file
  1. note
  2. description:
  3. "Objects that implement common behaviour between %
  4. %xsl:variable xsl:param and xsl:with-param elements"
  5. library: "Gobo Eiffel XSLT Library"
  6. copyright: "Copyright (c) 2004-2015, Colin Adams and others"
  7. license: "MIT License"
  8. date: "$Date$"
  9. revision: "$Revision$"
  10. deferred class XM_XSLT_GENERAL_VARIABLE
  11. inherit
  12. XM_XSLT_STYLE_ELEMENT
  13. redefine
  14. validate, returned_item_type, may_contain_sequence_constructor
  15. end
  16. XM_XSLT_PROCEDURE
  17. XM_XPATH_ROLE
  18. feature -- Access
  19. as_type: detachable XM_XPATH_SEQUENCE_TYPE
  20. -- Type declared by "as" attribute
  21. select_expression: detachable XM_XPATH_EXPRESSION
  22. -- Optional expression given by "select" attribute
  23. allows_required: BOOLEAN
  24. -- Is the "required" attribute allowed?
  25. do
  26. Result := False
  27. end
  28. allows_value: BOOLEAN
  29. -- Is the "select" attribute allowed?
  30. do
  31. Result := True
  32. end
  33. allows_tunnel: BOOLEAN
  34. -- Is the "tunnel" attribute allowed to be "yes"?
  35. variable_name: STRING
  36. -- Name of variable;
  37. -- For use in diagnostics - lexically, a QName
  38. do
  39. if attached internal_variable_name as l_internal_variable_name then
  40. Result := l_internal_variable_name
  41. else
  42. Result := ""
  43. end
  44. end
  45. variable_fingerprint: INTEGER
  46. -- Fingerprint of the variable name
  47. local
  48. l_name: detachable STRING
  49. do
  50. -- If an expression has a forwards reference to this variable, `variable_fingerprint' can be
  51. -- called before `prepare_attributes' is called.
  52. -- We need to allow for this. But we'll deal with any errors
  53. -- when we come round to processing this attribute, to avoid duplicate error messages
  54. -- TODO: this won't establish the required type in time to optimize an expression containing
  55. -- a forwards reference to the variable
  56. if internal_variable_name = Void then
  57. Result := -1 -- not yet known
  58. l_name := attribute_value_by_name ("", Name_attribute)
  59. if l_name /= Void and then is_qname (l_name) then
  60. STRING_.left_adjust (l_name)
  61. STRING_.right_adjust (l_name)
  62. -- TODO: whilst this is probably referentially transparent (last_generated_name_code is really only a tempory)
  63. -- it would be better to pass a DS_CELL
  64. generate_name_code (l_name)
  65. Result := fingerprint_from_name_code (last_generated_name_code)
  66. end
  67. else
  68. Result := cached_variable_fingerprint
  69. end
  70. ensure
  71. variable_fingerprint_nearly_positive: Result > -2
  72. end
  73. feature -- Status report
  74. may_contain_sequence_constructor: BOOLEAN
  75. -- Is `Current' allowed to contain a sequence constructor?
  76. do
  77. Result := True
  78. end
  79. is_redundant_variable: BOOLEAN
  80. -- Is `Current' a redundant variable?
  81. is_global_variable: BOOLEAN
  82. -- Is `Current' a global variable?
  83. do
  84. Result := is_top_level
  85. end
  86. is_required_parameter: BOOLEAN
  87. -- Is this a required parameter?
  88. is_implicitly_required_parameter: BOOLEAN
  89. -- Is this a parameter where default value does not match required type?
  90. is_tunnel_parameter: BOOLEAN
  91. -- Is this a tunnel parameter?
  92. feature -- Status setting
  93. set_redundant_variable
  94. -- Mark as a redundant variable
  95. require
  96. attributes_not_prepared: not attributes_prepared
  97. do
  98. is_redundant_variable := True
  99. ensure
  100. redundant_variable_set: is_redundant_variable = True
  101. end
  102. prepare_attributes
  103. -- Set the attribute list for the element.
  104. local
  105. a_cursor: DS_ARRAYED_LIST_CURSOR [INTEGER]
  106. a_name_code: INTEGER
  107. an_expanded_name, a_select_attribute, an_as_attribute, a_required_attribute, a_tunnel_attribute: detachable STRING
  108. an_error: XM_XPATH_ERROR_VALUE
  109. l_internal_variable_name: like internal_variable_name
  110. do
  111. if attached attribute_collection as l_attribute_collection then
  112. from
  113. a_cursor := l_attribute_collection.name_code_cursor
  114. a_cursor.start
  115. until
  116. a_cursor.after or any_compile_errors
  117. loop
  118. a_name_code := a_cursor.item
  119. an_expanded_name := shared_name_pool.expanded_name_from_name_code (a_name_code)
  120. if STRING_.same_string (an_expanded_name, Name_attribute) then
  121. l_internal_variable_name := attribute_value_by_index (a_cursor.index)
  122. STRING_.left_adjust (l_internal_variable_name)
  123. STRING_.right_adjust (l_internal_variable_name)
  124. internal_variable_name := l_internal_variable_name
  125. elseif STRING_.same_string (an_expanded_name, Select_attribute) then
  126. a_select_attribute := attribute_value_by_index (a_cursor.index)
  127. elseif STRING_.same_string (an_expanded_name, As_attribute) then
  128. an_as_attribute := attribute_value_by_index (a_cursor.index)
  129. elseif STRING_.same_string (an_expanded_name, Required_attribute) and then allows_required then
  130. a_required_attribute := attribute_value_by_index (a_cursor.index)
  131. STRING_.left_adjust (a_required_attribute)
  132. STRING_.right_adjust (a_required_attribute)
  133. elseif STRING_.same_string (an_expanded_name, Tunnel_attribute) and then allows_tunnel then
  134. a_tunnel_attribute := attribute_value_by_index (a_cursor.index)
  135. STRING_.left_adjust (a_tunnel_attribute)
  136. STRING_.right_adjust (a_tunnel_attribute)
  137. else
  138. check_unknown_attribute (a_name_code)
  139. end
  140. a_cursor.forth
  141. variant
  142. l_attribute_collection.number_of_attributes + 1 - a_cursor.index
  143. end
  144. if not attached internal_variable_name as l_internal_variable_name_2 then
  145. report_absence ("name")
  146. elseif not is_qname (l_internal_variable_name_2) then
  147. create an_error.make_from_string ("Name attribute must be a valid QName", Xpath_errors_uri, "XTSE0020", Static_error)
  148. report_compile_error (an_error)
  149. else
  150. STRING_.left_adjust (l_internal_variable_name_2)
  151. STRING_.right_adjust (l_internal_variable_name_2)
  152. generate_name_code (l_internal_variable_name_2)
  153. cached_variable_fingerprint := fingerprint_from_name_code (last_generated_name_code)
  154. end
  155. end
  156. if a_select_attribute /= Void then
  157. if not allows_value then
  158. create an_error.make_from_string ("Function parameters cannot have a default value", Xpath_errors_uri, "XTSE0760", Static_error)
  159. report_compile_error (an_error)
  160. else
  161. generate_expression (a_select_attribute)
  162. check postcondition_of_generate_expression: attached last_generated_expression as l_new_select_expression then
  163. select_expression := l_new_select_expression
  164. if attached l_new_select_expression.error_value as l_error_value then
  165. check is_error: l_new_select_expression.is_error end
  166. report_compile_error (l_error_value)
  167. end
  168. end
  169. end
  170. end
  171. prepare_attributes_2 (a_required_attribute, a_tunnel_attribute, an_as_attribute)
  172. attributes_prepared := True
  173. end
  174. validate
  175. -- Check that the stylesheet element is valid.
  176. local
  177. l_message: STRING
  178. l_child_iterator: XM_XPATH_SEQUENCE_ITERATOR [XM_XPATH_NODE]
  179. l_first_node: XM_XPATH_NODE
  180. l_error: XM_XPATH_ERROR_VALUE
  181. l_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]
  182. do
  183. if select_expression /= Void and then has_child_nodes then
  184. l_message := STRING_.concat ("An ", node_name)
  185. l_message := STRING_.appended_string (l_message, " element with a select attribute must be empty")
  186. create l_error.make_from_string (l_message, Xpath_errors_uri, "XTSE0620", Static_error)
  187. report_compile_error (l_error)
  188. elseif has_child_nodes and then not allows_value then
  189. create l_error.make_from_string ("Function parameters must be empty", Xpath_errors_uri, "XTSE0760", Static_error)
  190. report_compile_error (l_error)
  191. else
  192. if attached as_type as l_as_type then check_against_required_type (l_as_type) end
  193. if not any_compile_errors then
  194. if select_expression = Void and then allows_value then
  195. is_text_only := True
  196. l_child_iterator := new_axis_iterator (Child_axis)
  197. l_child_iterator.start
  198. if l_child_iterator.after then
  199. if not attached as_type as l_as_type_2 then
  200. create {XM_XPATH_STRING_VALUE} select_expression.make ("")
  201. elseif is_param then
  202. if not is_required_parameter then
  203. if l_as_type_2.cardinality_allows_zero then
  204. create {XM_XPATH_EMPTY_SEQUENCE} select_expression.make
  205. else
  206. -- The implicit default value () is not valid for the required type,
  207. -- so we treat it as if there is no default
  208. is_implicitly_required_parameter := True
  209. end
  210. end
  211. else -- not an xsl:param
  212. if l_as_type_2.cardinality_allows_zero then
  213. create {XM_XPATH_EMPTY_SEQUENCE} select_expression.make
  214. else
  215. create l_error.make_from_string ("Default value () is not valid for the declared type", Xpath_errors_uri, "XTTE0570", Type_error)
  216. report_compile_error (l_error)
  217. end
  218. end
  219. else -- at least one child node
  220. l_first_node := l_child_iterator.item
  221. l_child_iterator.forth
  222. if l_child_iterator.after then
  223. -- There is exactly one child node
  224. if l_first_node.node_type = Text_node then
  225. constant_text := l_first_node.string_value
  226. end
  227. end
  228. -- Determine if the temporary tree can only contain text nodes
  229. is_text_only := common_child_item_type = text_node_kind_test
  230. end
  231. end
  232. end
  233. end
  234. if attached select_expression as l_select_expression then
  235. create l_replacement.make (Void)
  236. type_check_expression (l_replacement, "select", l_select_expression)
  237. select_expression := l_replacement.item
  238. end
  239. end
  240. check_against_required_type (a_required_type: XM_XPATH_SEQUENCE_TYPE)
  241. -- Check the expression conforms to `as_type'.
  242. require
  243. no_compile_errors: not any_compile_errors
  244. required_type_not_void: a_required_type /= Void
  245. local
  246. l_role: XM_XPATH_ROLE_LOCATOR
  247. l_type_checker: XM_XPATH_TYPE_CHECKER
  248. l_error: STRING
  249. do
  250. if is_param then
  251. l_error := "XTTE0600"
  252. else
  253. l_error := "XTTE0570"
  254. end
  255. create l_role.make (Variable_role, variable_name, 1, Xpath_errors_uri, l_error)
  256. if attached select_expression as l_select_expression then
  257. create l_type_checker
  258. l_type_checker.static_type_check (static_context, l_select_expression, a_required_type, False, l_role)
  259. if l_type_checker.is_static_type_check_error then
  260. check postcondition_of_static_type_check: attached l_type_checker.static_type_check_error as l_static_type_check_error then
  261. report_compile_error (l_static_type_check_error)
  262. end
  263. else
  264. select_expression := l_type_checker.checked_expression
  265. end
  266. else
  267. -- do the check later
  268. end
  269. end
  270. feature {XM_XSLT_STYLE_ELEMENT} -- Restricted
  271. returned_item_type: XM_XPATH_ITEM_TYPE
  272. -- Type of item returned by this instruction;
  273. -- This is EMPTY for a variable: we are not
  274. -- interested in the type of the variable, but in what the xsl:variable constributes
  275. -- to the result of the sequence constructor it is part of.
  276. do
  277. Result := empty_item
  278. end
  279. feature {NONE} -- Implementation
  280. cached_variable_fingerprint: INTEGER
  281. -- Cache for `variable_fingerprint'
  282. is_text_only: BOOLEAN
  283. -- Is the value of `Current' computed solely from text nodes?
  284. constant_text: detachable STRING
  285. -- Value of `Current' when it has a single text node child
  286. initialize_instruction (a_executable: XM_XSLT_EXECUTABLE; a_variable: XM_XSLT_COMPILED_GENERAL_VARIABLE)
  287. -- Initialize - common code called from the `compile' routine of all subclasses.
  288. require
  289. executable_not_void: a_executable /= Void
  290. variable_not_void: a_variable /= Void
  291. local
  292. l_document: XM_XSLT_COMPILED_DOCUMENT
  293. l_role: XM_XPATH_ROLE_LOCATOR
  294. l_type_checker: XM_XPATH_TYPE_CHECKER
  295. l_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]
  296. l_last_generated_expression: like last_generated_expression
  297. l_select_expression: like select_expression
  298. do
  299. a_variable.initialize_variable (select_expression, as_type, variable_fingerprint)
  300. a_variable.set_required_parameter (is_required_parameter)
  301. a_variable.set_implicitly_required_parameter (is_implicitly_required_parameter)
  302. a_variable.set_tunnel_parameter (is_tunnel_parameter)
  303. -- Handle the "temporary tree" case by creating a Document sub-instruction
  304. -- to construct and return a document node.
  305. if has_child_nodes then
  306. if as_type = Void then
  307. compile_sequence_constructor (a_executable, new_axis_iterator (Child_axis), True)
  308. l_last_generated_expression := last_generated_expression
  309. if l_last_generated_expression = Void then
  310. create {XM_XPATH_EMPTY_SEQUENCE} l_last_generated_expression.make
  311. last_generated_expression := l_last_generated_expression
  312. end
  313. check attached base_uri as l_base_uri then
  314. create l_document.make (a_executable, is_text_only, constant_text, l_base_uri, l_last_generated_expression)
  315. end
  316. select_expression := l_document
  317. a_variable.set_selector (l_document)
  318. else
  319. compile_sequence_constructor (a_executable, new_axis_iterator (Child_axis), True)
  320. if not attached last_generated_expression as l_last_generated_expression_2 then
  321. create {XM_XPATH_EMPTY_SEQUENCE} l_select_expression.make
  322. select_expression := l_select_expression
  323. else
  324. l_select_expression := l_last_generated_expression_2
  325. select_expression := l_select_expression
  326. end
  327. if attached as_type as l_as_type then
  328. create l_replacement.make (Void)
  329. l_select_expression.simplify (l_replacement)
  330. check postcondition_of_simplify: attached l_replacement.item as l_replacement_item then
  331. l_select_expression := l_replacement_item
  332. select_expression := l_select_expression
  333. end
  334. if attached l_select_expression.error_value as l_error_value then
  335. check is_error: l_select_expression.is_error end
  336. report_compile_error (l_error_value)
  337. else
  338. create l_role.make (Variable_role, variable_name, 1, Xpath_errors_uri, "XTTE0570")
  339. create l_type_checker
  340. l_type_checker.static_type_check (static_context, l_select_expression, l_as_type, False, l_role)
  341. if l_type_checker.is_static_type_check_error then
  342. check postcondition_of_static_type_check: attached l_type_checker.static_type_check_error as l_static_type_check_error then
  343. report_compile_error (l_static_type_check_error)
  344. end
  345. else
  346. check postcondition_of_static_type_check: attached l_type_checker.checked_expression as l_checked_expression then
  347. l_select_expression := l_checked_expression
  348. select_expression := l_select_expression
  349. end
  350. end
  351. end
  352. a_variable.set_selector (l_select_expression)
  353. end
  354. end
  355. end
  356. if is_global_variable then
  357. initialize_global_variable (a_variable.as_global_variable, a_executable)
  358. end
  359. end
  360. initialize_global_variable (a_global_variable: XM_XSLT_GLOBAL_VARIABLE; a_executable: XM_XSLT_EXECUTABLE)
  361. -- Initialize global variable.
  362. require
  363. global_variable: is_global_variable and then a_global_variable /= Void
  364. executable_not_void: a_executable /= Void
  365. local
  366. l_expression: detachable XM_XPATH_EXPRESSION
  367. l_trace_wrapper: XM_XSLT_TRACE_INSTRUCTION
  368. l_replacement: DS_CELL [detachable XM_XPATH_EXPRESSION]
  369. do
  370. if attached select_expression as l_select_expression then
  371. create l_replacement.make (Void)
  372. l_select_expression.simplify (l_replacement)
  373. check postcondition_of_simplify: attached l_replacement.item as l_replacement_item then
  374. l_expression := l_replacement_item
  375. end
  376. if attached l_expression.error_value as l_error_value then
  377. check is_error: l_expression.is_error end
  378. report_compile_error (l_error_value)
  379. else
  380. l_replacement.put (Void)
  381. check attached static_context as l_static_context then
  382. l_expression.check_static_type (l_replacement, l_static_context, any_node_test)
  383. end
  384. check postcondition_of_check_static_type: attached l_replacement.item as l_replacement_item then
  385. l_expression := l_replacement_item
  386. end
  387. if not l_expression.is_error then
  388. l_replacement.put (Void)
  389. check attached static_context as l_static_context then
  390. l_expression.optimize (l_replacement, l_static_context, any_node_test)
  391. end
  392. check postcondition_of_optimize: attached l_replacement.item as l_replacement_item then
  393. l_expression := l_replacement_item
  394. end
  395. end
  396. if attached l_expression.error_value as l_error_value then
  397. check is_error: l_expression.is_error end
  398. report_compile_error (l_error_value)
  399. else
  400. if configuration.is_tracing then
  401. create l_trace_wrapper.make (l_expression, a_executable, Current)
  402. check attached principal_stylesheet as l_principal_stylesheet then
  403. l_trace_wrapper.set_source_location (l_principal_stylesheet.module_number (system_id), line_number)
  404. end
  405. l_expression := l_trace_wrapper
  406. end
  407. allocate_slots (l_expression, slot_manager)
  408. a_global_variable.set_slot_manager (slot_manager)
  409. end
  410. end
  411. end
  412. a_global_variable.set_selector (l_expression)
  413. end
  414. prepare_attributes_2 (a_required_attribute, a_tunnel_attribute, an_as_attribute: detachable STRING)
  415. -- Prepare attributes - stage 2.
  416. local
  417. l_error: XM_XPATH_ERROR_VALUE
  418. do
  419. if a_required_attribute /= Void then
  420. if STRING_.same_string (a_required_attribute, "yes") then
  421. is_required_parameter := True
  422. elseif STRING_.same_string (a_required_attribute, "no") then
  423. is_required_parameter := False
  424. else
  425. create l_error.make_from_string ("The attribute 'required' must be set to 'yes' or 'no'", Xpath_errors_uri, "XTSE0020", Static_error)
  426. report_compile_error (l_error)
  427. end
  428. end
  429. if a_tunnel_attribute /= Void then
  430. if STRING_.same_string (a_tunnel_attribute, "yes") then
  431. is_tunnel_parameter := True
  432. elseif STRING_.same_string (a_tunnel_attribute, "no") then
  433. is_tunnel_parameter := False
  434. else
  435. create l_error.make_from_string ("The attribute 'tunnel' must be set to 'yes' or 'no'", Xpath_errors_uri, "XTSE0020", Static_error)
  436. report_compile_error (l_error)
  437. end
  438. end
  439. if an_as_attribute /= Void then
  440. generate_sequence_type (an_as_attribute)
  441. as_type := last_generated_sequence_type
  442. end
  443. end
  444. internal_variable_name: detachable like variable_name
  445. -- Name of variable;
  446. -- For use in diagnostics - lexically, a QName
  447. end