/src/lib/regular_expression/internal/regular_expression_string_scanner.e

http://github.com/tybor/Liberty · Specman e · 244 lines · 159 code · 25 blank · 60 comment · 3 complexity · ed6bfdfe7fd7f42fc36c745ed281e68d MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. class REGULAR_EXPRESSION_STRING_SCANNER
  5. --
  6. -- Facility to scan strings
  7. -- TODO improve it by using STRING_HANDLER and string's storage
  8. --
  9. feature {ANY} -- make
  10. make
  11. -- Initialise the attributes.
  12. do
  13. create last_string.make(10)
  14. end
  15. feature {ANY} -- basic
  16. scanned_string: ABSTRACT_STRING
  17. -- The expression being currently build.
  18. set_scanned_string (string: like scanned_string)
  19. -- Set the 'scanned_string' with 'string'.
  20. do
  21. scanned_string := string
  22. clear_error
  23. goto_position(scanned_string.lower)
  24. ensure
  25. has_no_error: not has_error
  26. definition: scanned_string = string
  27. at_the_begin: position = scanned_string.lower
  28. end
  29. feature {ANY} -- error management
  30. has_error: BOOLEAN
  31. -- True when an error was encountered
  32. clear_error
  33. -- Remove the error flag
  34. do
  35. has_error := False
  36. ensure
  37. has_no_error: not has_error
  38. end
  39. last_error: STRING
  40. -- Returns a string recorded for the error.
  41. require
  42. has_error: has_error
  43. do
  44. Result := last_string
  45. ensure
  46. not_void: Result /= Void
  47. end
  48. set_error (message: STRING)
  49. -- Set has_error and last_error.
  50. -- The explaining error string 'last_error'
  51. -- is created as follow: "Error at position 'position': 'message'.".
  52. require
  53. message_not_void: message /= Void
  54. has_no_error: not has_error
  55. do
  56. has_error := True
  57. last_string.clear_count
  58. last_string.append_string(once "Error at position ")
  59. position.append_in(last_string)
  60. last_string.append_string(once ": ")
  61. last_string.append_string(message)
  62. last_string.append_character('.')
  63. ensure
  64. has_error: has_error
  65. end
  66. feature {ANY} -- scanning
  67. position: INTEGER
  68. -- The scanned position.
  69. -- It is the position of 'last_character'.
  70. last_character: CHARACTER
  71. -- The scanned character.
  72. -- The last character read from 'scanned_string'.
  73. valid_last_character: BOOLEAN
  74. -- True when 'last_character' is valid.
  75. -- Is like 'scanned_string.valid_index(position)'
  76. valid_previous_character: BOOLEAN
  77. -- True if the position-1 is a valid position.
  78. require
  79. scanned_string /= Void
  80. do
  81. Result := scanned_string.valid_index(position - 1)
  82. ensure
  83. definition: Result = scanned_string.valid_index(position - 1)
  84. end
  85. previous_character: like last_character
  86. -- The character at position-1.
  87. require
  88. valid_previous_character
  89. do
  90. Result := scanned_string.item(position - 1)
  91. ensure
  92. definition: Result = scanned_string.item(position - 1)
  93. end
  94. valid_next_character: BOOLEAN
  95. -- True if the position+1 is a valid position.
  96. require
  97. scanned_string /= Void
  98. do
  99. Result := scanned_string.valid_index(position + 1)
  100. ensure
  101. definition: Result = scanned_string.valid_index(position + 1)
  102. end
  103. next_character: like last_character
  104. -- The character at position+1.
  105. require
  106. valid_next_character
  107. do
  108. Result := scanned_string.item(position + 1)
  109. ensure
  110. definition: Result = scanned_string.item(position + 1)
  111. end
  112. end_of_input: BOOLEAN
  113. -- True when all the characters of 'scanned_string'
  114. -- are scanned.
  115. do
  116. Result := not valid_last_character
  117. ensure
  118. implies_last_character_not_valid: Result implies not valid_last_character
  119. end
  120. goto_position (pos: INTEGER)
  121. -- Change the currently scanned position to 'pos'.
  122. -- Updates 'last_character' and 'valid_last_character' to
  123. -- reflect the new position value.
  124. require
  125. has_no_error: not has_error
  126. scanned_string /= Void
  127. do
  128. position := pos
  129. valid_last_character := scanned_string.valid_index(pos)
  130. if valid_last_character then
  131. last_character := scanned_string.item(pos)
  132. end
  133. ensure
  134. has_no_error: not has_error
  135. position_set: position = pos
  136. validity_updated: valid_last_character = scanned_string.valid_index(position)
  137. character_updated: valid_last_character implies last_character = scanned_string.item(position)
  138. end
  139. read_character
  140. -- Reads the next character.
  141. require
  142. has_no_error: not has_error
  143. not_at_end: not end_of_input
  144. do
  145. goto_position(position + 1)
  146. ensure
  147. next_position: position > old position
  148. has_no_error: not has_error
  149. end
  150. read_integer
  151. -- Reads an integer value beginning at the
  152. -- currently scanned position.
  153. -- The read value is stored in 'last_integer'.
  154. require
  155. has_no_error: not has_error
  156. not_at_end: not end_of_input
  157. begin_with_a_digit: last_character.is_decimal_digit
  158. do
  159. from
  160. last_integer := last_character.decimal_value
  161. read_character
  162. until
  163. end_of_input or else not last_character.is_decimal_digit
  164. loop
  165. last_integer := 10 * last_integer + last_character.decimal_value
  166. read_character
  167. end
  168. ensure
  169. has_no_error: not has_error
  170. digits_eaten: end_of_input or else not last_character.is_decimal_digit
  171. end
  172. saved_position: INTEGER
  173. -- The saved position (only one is currently enough).
  174. save_position
  175. -- Saves the current scanning position.
  176. require
  177. not_at_end: not end_of_input
  178. do
  179. saved_position := position
  180. ensure
  181. not_at_end: not end_of_input
  182. position_kept: position = old position
  183. saved_position_set: saved_position = position
  184. end
  185. restore_saved_position
  186. -- Restore the scanning position to the last saved one.
  187. do
  188. goto_position(saved_position)
  189. ensure
  190. position_restored: position = old saved_position
  191. not_at_end: not end_of_input
  192. end
  193. last_string: STRING
  194. -- A string buffer.
  195. last_integer: INTEGER
  196. -- An integer buffer.
  197. invariant
  198. last_string_not_void: last_string /= Void
  199. end -- class REGULAR_EXPRESSION_STRING_SCANNER
  200. --
  201. -- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
  202. --
  203. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  204. -- of this software and associated documentation files (the "Software"), to deal
  205. -- in the Software without restriction, including without limitation the rights
  206. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  207. -- copies of the Software, and to permit persons to whom the Software is
  208. -- furnished to do so, subject to the following conditions:
  209. --
  210. -- The above copyright notice and this permission notice shall be included in
  211. -- all copies or substantial portions of the Software.
  212. --
  213. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  214. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  215. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  216. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  217. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  218. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  219. -- THE SOFTWARE.