PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/library/xpath/src/value/xm_xpath_duration_value.e

http://github.com/gobo-eiffel/gobo
Specman e | 369 lines | 289 code | 50 blank | 30 comment | 35 complexity | b79f6455adeb30bada07cba4dbb597da MD5 | raw file
  1. note
  2. description:
  3. "Objects that represent XPath duration values"
  4. library: "Gobo Eiffel XPath Library"
  5. copyright: "Copyright (c) 2005-2018, Colin Adams and others"
  6. license: "MIT License"
  7. date: "$Date$"
  8. revision: "$Revision$"
  9. class XM_XPATH_DURATION_VALUE
  10. inherit
  11. XM_XPATH_ATOMIC_VALUE
  12. redefine
  13. is_duration_value, as_duration_value, hash_code
  14. end
  15. KL_IMPORTED_INTEGER_ROUTINES
  16. export {NONE} all end
  17. KL_IMPORTED_DOUBLE_ROUTINES
  18. export {NONE} all end
  19. create
  20. make, make_from_duration
  21. feature {NONE} -- Initialization
  22. make (a_duration: STRING)
  23. -- Create from lexical duration.
  24. require
  25. lexical_duration: a_duration /= Void and then is_duration (a_duration)
  26. local
  27. a_parser: XM_XPATH_DURATION_PARSER
  28. do
  29. make_atomic_value
  30. create a_parser.make
  31. duration := a_parser.string_to_duration (a_duration)
  32. end
  33. make_from_duration (a_duration: like duration)
  34. -- Create from duration.
  35. require
  36. duration_not_void: a_duration /= Void
  37. do
  38. make_atomic_value
  39. duration := a_duration
  40. end
  41. feature -- Access
  42. item_type: XM_XPATH_ITEM_TYPE
  43. -- Data type of the expression, where know
  44. do
  45. Result := type_factory.duration_type
  46. if Result /= Void then
  47. -- Bug in SE 1.0 and 1.1: Make sure that
  48. -- that `Result' is not optimized away.
  49. end
  50. end
  51. string_value: STRING
  52. -- Value of the item as a string
  53. local
  54. l_string: STRING
  55. do
  56. -- XML Schema does not define a canonical representation. We omit all zero components,
  57. -- unless the duration is zero-length, in which case we output PT0S.
  58. if duration.year = 0 and then duration.month = 0 and then duration.day = 0
  59. and then duration.hour = 0 and then duration.minute = 0
  60. and then duration.second = 0 and then duration.millisecond = 0 then
  61. Result := "PT0S"
  62. elseif not is_normal then
  63. Result := normalized_duration.string_value
  64. else
  65. if is_negative then Result := "-P" else Result := "P" end
  66. if duration.year /= 0 then Result := Result + duration.year.abs.out + "Y" end
  67. if duration.month /= 0 then Result := Result + duration.month.abs.out + "M" end
  68. if duration.day /= 0 then Result := Result + duration.day.abs.out + "D" end
  69. if duration.hour /= 0 or else duration.minute /= 0
  70. or else duration.second /= 0 or else duration.millisecond /= 0 then
  71. Result := Result + "T"
  72. end
  73. if duration.hour /= 0 then Result := Result + duration.hour.abs.out + "H" end
  74. if duration.minute /= 0 then Result := Result + duration.minute.abs.out + "M" end
  75. if duration.second /= 0 or else duration.millisecond /= 0 then
  76. Result := Result + duration.second.abs.out
  77. if duration.millisecond /= 0 then
  78. Result := Result + "."
  79. l_string := duration.millisecond.abs.out
  80. from until l_string.count = 3 loop
  81. l_string.insert_character ('0', 1)
  82. end
  83. from until l_string.item (l_string.count) /= '0' loop
  84. l_string.remove_tail (1)
  85. end
  86. Result := Result + l_string
  87. end
  88. Result := Result + "S"
  89. end
  90. end
  91. end
  92. hash_code: INTEGER
  93. -- Hash code value
  94. do
  95. Result := duration.hash_code
  96. end
  97. seconds: MA_DECIMAL
  98. -- Seconds component (including milliseconds)
  99. local
  100. l_string, l_milliseconds: STRING
  101. do
  102. l_string := duration.second.out
  103. if duration.millisecond /= 0 then
  104. l_milliseconds := duration.millisecond.abs.out
  105. from until l_milliseconds.count = 3 loop
  106. l_milliseconds.insert_character ('0', 1)
  107. end
  108. from until l_milliseconds.item (l_milliseconds.count) /= '0' loop
  109. l_milliseconds.remove_tail (1)
  110. end
  111. l_string := l_string + "." + l_milliseconds
  112. end
  113. create Result.make_from_string (l_string)
  114. ensure
  115. result_not_void: Result /= Void
  116. end
  117. duration: DT_DATE_TIME_DURATION
  118. -- Duration
  119. feature -- Comparison
  120. same_expression (other: XM_XPATH_EXPRESSION): BOOLEAN
  121. -- Are `Current' and `other' the same expression?
  122. local
  123. l_duration: like duration
  124. do
  125. if other.is_duration_value then
  126. l_duration := other.as_duration_value.duration
  127. Result := duration.year = l_duration.year
  128. and then duration.month = l_duration.month
  129. and then duration.day = l_duration.day
  130. and then duration.hour = l_duration.hour
  131. and then duration.minute = l_duration.minute
  132. and then duration.second = l_duration.second
  133. and then duration.millisecond = l_duration.millisecond
  134. end
  135. end
  136. equal_duration (a_other: XM_XPATH_DURATION_VALUE): BOOLEAN
  137. -- Is `Current' equal to `a_other'?
  138. -- XPath functions and operators says two xs:durations are equal iff all their seconds count and their months count are equal
  139. do
  140. Result := normalized_duration.same_expression (a_other.normalized_duration)
  141. end
  142. three_way_comparison (other: XM_XPATH_ATOMIC_VALUE; a_context: detachable XM_XPATH_CONTEXT): INTEGER
  143. -- Comparison of `Current' to `other'
  144. local
  145. l_duration: like duration
  146. do
  147. l_duration := other.as_duration_value.duration
  148. if duration < l_duration then
  149. Result := -1
  150. elseif duration > l_duration then
  151. Result := 1
  152. end
  153. end
  154. feature -- Status report
  155. is_normal: BOOLEAN
  156. -- Is `duration' in normal form?
  157. do
  158. Result := duration.month.abs < 12 and then duration.hour.abs < 24
  159. and then (duration.month < 0 implies duration.hour <= 0)
  160. and then (duration.hour < 0 implies duration.month <= 0)
  161. and then (duration.year < 0 implies duration.hour <= 0)
  162. and then duration.is_time_canonical
  163. end
  164. is_negative: BOOLEAN
  165. -- Is `Current' a negative duration?
  166. require
  167. in_normal_form: is_normal
  168. do
  169. Result := duration.year < 0 or else duration.month < 0
  170. or else duration.day < 0 or else duration.hour < 0
  171. or else duration.minute < 0 or else duration.second < 0
  172. or else duration.millisecond < 0
  173. end
  174. is_duration (a_duration: STRING): BOOLEAN
  175. -- Is `a_duration' a valid duration?
  176. require
  177. lexical_duration_not_void: a_duration /= Void
  178. local
  179. a_parser: XM_XPATH_DURATION_PARSER
  180. do
  181. create a_parser.make
  182. Result := a_parser.is_duration (a_duration)
  183. end
  184. is_duration_value: BOOLEAN
  185. -- Is `Current' an xs:duration value?
  186. do
  187. Result := True
  188. end
  189. is_comparable (other: XM_XPATH_ATOMIC_VALUE): BOOLEAN
  190. -- Is `other' comparable to `Current'?
  191. do
  192. Result := False -- xs:duration may only be compared for equality
  193. end
  194. is_convertible (a_required_type: XM_XPATH_ITEM_TYPE): BOOLEAN
  195. -- Is `Current' convertible to `a_required_type'?
  196. do
  197. if a_required_type = any_item or else a_required_type = type_factory.any_atomic_type
  198. or else a_required_type = type_factory.duration_type
  199. or else a_required_type = type_factory.day_time_duration_type
  200. or else a_required_type = type_factory.year_month_duration_type
  201. or else a_required_type = type_factory.string_type
  202. or else a_required_type = type_factory.untyped_atomic_type then
  203. Result := True
  204. end
  205. end
  206. display (a_level: INTEGER)
  207. -- Diagnostic print of expression structure to `std.error'
  208. local
  209. l_string: STRING
  210. do
  211. l_string := STRING_.appended_string (indentation (a_level), "duration (")
  212. l_string := STRING_.appended_string (l_string, string_value)
  213. l_string := STRING_.appended_string (l_string, ")")
  214. std.error.put_string (l_string)
  215. std.error.put_new_line
  216. end
  217. feature -- Conversions
  218. as_duration_value: XM_XPATH_DURATION_VALUE
  219. -- `Current' seen as an xs:duration value
  220. do
  221. Result := Current
  222. end
  223. convert_to_type (a_required_type: XM_XPATH_ITEM_TYPE)
  224. -- Convert `Current' to `a_required_type'
  225. local
  226. a_duration: like duration
  227. do
  228. if a_required_type = any_item or else a_required_type = type_factory.any_atomic_type
  229. or else a_required_type = type_factory.duration_type then
  230. converted_value := Current
  231. elseif a_required_type = type_factory.string_type then
  232. create {XM_XPATH_STRING_VALUE} converted_value.make (string_value)
  233. elseif a_required_type = type_factory.untyped_atomic_type then
  234. create {XM_XPATH_STRING_VALUE} converted_value.make_untyped_atomic (string_value)
  235. elseif a_required_type = type_factory.year_month_duration_type then
  236. create a_duration.make (duration.year, duration.month, 0, 0, 0, 0)
  237. create {XM_XPATH_MONTHS_DURATION_VALUE} converted_value.make_from_duration (a_duration)
  238. elseif a_required_type = type_factory.day_time_duration_type then
  239. create a_duration.make_precise (0, 0, duration.day, duration.hour, duration.minute, duration.second, duration.millisecond)
  240. create {XM_XPATH_SECONDS_DURATION_VALUE} converted_value.make_from_duration (a_duration)
  241. end
  242. end
  243. feature -- Basic operations
  244. plus (other: XM_XPATH_DURATION_VALUE): XM_XPATH_ITEM
  245. -- Addition of `other' to `Current'
  246. require
  247. other_duration_not_void: other /= Void
  248. do
  249. create {XM_XPATH_INVALID_ITEM} Result.make_from_string ("Only descendants of xs:duration may be added", Gexslt_eiffel_type_uri, "DURATION-ADDITION", Dynamic_error)
  250. ensure
  251. result_may_be_in_error: Result /= Void
  252. end
  253. minus (other: XM_XPATH_DURATION_VALUE): XM_XPATH_ITEM
  254. -- Subtraction of `other' from `Current'
  255. require
  256. other_duration_not_void: other /= Void
  257. do
  258. create {XM_XPATH_INVALID_ITEM} Result.make_from_string ("Only descendants of xs:duration may be subtracted", Gexslt_eiffel_type_uri, "DURATION-SUBTRACTION", Dynamic_error)
  259. ensure
  260. result_may_be_in_error: Result /= Void
  261. end
  262. multiply (a_scalar: DOUBLE): XM_XPATH_ITEM
  263. -- Multiplication of `Current' by `a_scalar'
  264. require
  265. non_zero_double: a_scalar /= 0 -- and then not a_scalar.is_infinity and then not a_scalar.is_nan
  266. do
  267. create {XM_XPATH_INVALID_ITEM} Result.make_from_string ("Only descendants of xs:duration may be subtracted", Gexslt_eiffel_type_uri, "DURATION-SUBTRACTION", Dynamic_error)
  268. ensure
  269. result_may_be_in_error: Result /= Void
  270. end
  271. scalar_divide (a_scalar: DOUBLE): XM_XPATH_ITEM
  272. -- Division of `Current' by `a_scalar'
  273. require
  274. non_zero_double: a_scalar /= 0 -- and then not a_scalar.is_infinity and then not a_scalar.is_nan
  275. do
  276. create {XM_XPATH_INVALID_ITEM} Result.make_from_string ("Only descendants of xs:duration may be subtracted", Gexslt_eiffel_type_uri, "DURATION-SUBTRACTION", Dynamic_error)
  277. ensure
  278. result_may_be_in_error: Result /= Void
  279. end
  280. divide (other: XM_XPATH_DURATION_VALUE): XM_XPATH_ITEM
  281. -- Division of `other' into `Current'
  282. require
  283. other_duration_not_void: other /= Void
  284. do
  285. create {XM_XPATH_INVALID_ITEM} Result.make_from_string ("Only descendants of xs:duration may be divided", Gexslt_eiffel_type_uri, "DURATION-DIVISION", Dynamic_error)
  286. ensure
  287. result_may_be_in_error: Result /= Void
  288. end
  289. feature {XM_XPATH_DURATION_VALUE} -- Implementation
  290. normalized_duration: XM_XPATH_DURATION_VALUE
  291. -- Normal form of `duration'
  292. local
  293. a_year, a_month, a_day, an_hour: INTEGER
  294. a_minute, a_second, a_millisecond: INTEGER
  295. total_months, total_hours, total_minutes: INTEGER
  296. a_duration: like duration
  297. do
  298. total_months := duration.year * 12 + duration.month
  299. a_year := total_months.abs // 12
  300. a_month := total_months.abs \\ 12
  301. a_second := duration.second_count.abs \\ 60
  302. a_millisecond := duration.millisecond_count.abs \\ 1000
  303. total_minutes := duration.second_count.abs // 60
  304. a_minute := total_minutes \\ 60
  305. total_hours := total_minutes // 60
  306. an_hour := total_hours \\ 24
  307. a_day := duration.day.abs + total_hours // 24
  308. if total_months < 0 or else duration.millisecond_count < 0 then
  309. create a_duration.make_precise (-a_year, -a_month, -a_day, -an_hour, -a_minute, -a_second, -a_millisecond)
  310. else
  311. create a_duration.make_precise (a_year, a_month, a_day, an_hour, a_minute, a_second, a_millisecond)
  312. end
  313. create Result.make_from_duration (a_duration)
  314. ensure
  315. normal_duration: Result /= Void and then Result.is_normal
  316. end
  317. invariant
  318. duration_not_void: duration /= Void
  319. end