stupidedi 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. data/README.md +215 -0
  2. data/Rakefile +108 -0
  3. data/bin/edi-ed +71 -0
  4. data/bin/edi-pp +81 -0
  5. data/doc/Defining.md +0 -0
  6. data/doc/Generating.md +321 -0
  7. data/doc/LICENSE.md +0 -0
  8. data/doc/Navigating.md +645 -0
  9. data/doc/Parsing.md +0 -0
  10. data/doc/Serializing.md +7 -0
  11. data/doc/Tokenizing.md +0 -0
  12. data/doc/Validating.md +0 -0
  13. data/doc/design/Parser.md +0 -0
  14. data/doc/design/Reader.md +0 -0
  15. data/lib/ruby/array.rb +164 -0
  16. data/lib/ruby/blank.rb +67 -0
  17. data/lib/ruby/enumerable.rb +35 -0
  18. data/lib/ruby/exception.rb +33 -0
  19. data/lib/ruby/hash.rb +4 -0
  20. data/lib/ruby/instance_exec.rb +26 -0
  21. data/lib/ruby/module.rb +79 -0
  22. data/lib/ruby/object.rb +63 -0
  23. data/lib/ruby/string.rb +73 -0
  24. data/lib/ruby/symbol.rb +24 -0
  25. data/lib/ruby/to_d.rb +81 -0
  26. data/lib/ruby/to_date.rb +33 -0
  27. data/lib/ruby/to_time.rb +24 -0
  28. data/lib/ruby/try.rb +43 -0
  29. data/lib/stupidedi/blank_slate.rb +11 -0
  30. data/lib/stupidedi/builder/builder_dsl.rb +281 -0
  31. data/lib/stupidedi/builder/constraint_table.rb +418 -0
  32. data/lib/stupidedi/builder/generation.rb +112 -0
  33. data/lib/stupidedi/builder/instruction.rb +102 -0
  34. data/lib/stupidedi/builder/instruction_table.rb +204 -0
  35. data/lib/stupidedi/builder/navigation.rb +655 -0
  36. data/lib/stupidedi/builder/state_machine.rb +55 -0
  37. data/lib/stupidedi/builder/states/abstract_state.rb +332 -0
  38. data/lib/stupidedi/builder/states/failure_state.rb +69 -0
  39. data/lib/stupidedi/builder/states/functional_group_state.rb +97 -0
  40. data/lib/stupidedi/builder/states/initial_state.rb +63 -0
  41. data/lib/stupidedi/builder/states/interchange_state.rb +94 -0
  42. data/lib/stupidedi/builder/states/loop_state.rb +79 -0
  43. data/lib/stupidedi/builder/states/table_state.rb +96 -0
  44. data/lib/stupidedi/builder/states/transaction_set_state.rb +112 -0
  45. data/lib/stupidedi/builder/states/transmission_state.rb +59 -0
  46. data/lib/stupidedi/builder/tokenization.rb +196 -0
  47. data/lib/stupidedi/builder.rb +23 -0
  48. data/lib/stupidedi/color.rb +93 -0
  49. data/lib/stupidedi/config/code_list_config.rb +42 -0
  50. data/lib/stupidedi/config/editor_config.rb +51 -0
  51. data/lib/stupidedi/config/functional_group_config.rb +62 -0
  52. data/lib/stupidedi/config/interchange_config.rb +79 -0
  53. data/lib/stupidedi/config/transaction_set_config.rb +91 -0
  54. data/lib/stupidedi/config.rb +101 -0
  55. data/lib/stupidedi/editor/00501.rb +341 -0
  56. data/lib/stupidedi/editor/005010/N2.rb +0 -0
  57. data/lib/stupidedi/editor/005010/N3.rb +0 -0
  58. data/lib/stupidedi/editor/005010/N4.rb +63 -0
  59. data/lib/stupidedi/editor/005010/NM1.rb +0 -0
  60. data/lib/stupidedi/editor/005010.rb +469 -0
  61. data/lib/stupidedi/editor/X222-HC837.rb +195 -0
  62. data/lib/stupidedi/editor/abstract_ed.rb +36 -0
  63. data/lib/stupidedi/editor/claim_ack.rb +9 -0
  64. data/lib/stupidedi/editor/implementation_ack.rb +213 -0
  65. data/lib/stupidedi/editor/interchange_ack.rb +9 -0
  66. data/lib/stupidedi/editor/result.rb +100 -0
  67. data/lib/stupidedi/editor/result_set.rb +69 -0
  68. data/lib/stupidedi/editor/transaction_set_ed.rb +275 -0
  69. data/lib/stupidedi/editor/transmission_ed.rb +90 -0
  70. data/lib/stupidedi/editor.rb +37 -0
  71. data/lib/stupidedi/either.rb +287 -0
  72. data/lib/stupidedi/exceptions/invalid_element_error.rb +8 -0
  73. data/lib/stupidedi/exceptions/invalid_schema_error.rb +8 -0
  74. data/lib/stupidedi/exceptions/output_error.rb +8 -0
  75. data/lib/stupidedi/exceptions/parse_error.rb +8 -0
  76. data/lib/stupidedi/exceptions/stupidedi_error.rb +8 -0
  77. data/lib/stupidedi/exceptions/tokenize_error.rb +8 -0
  78. data/lib/stupidedi/exceptions/zipper_error.rb +8 -0
  79. data/lib/stupidedi/exceptions.rb +11 -0
  80. data/lib/stupidedi/guides/005010/X214-HN277.rb +409 -0
  81. data/lib/stupidedi/guides/005010/X221-HP835.rb +613 -0
  82. data/lib/stupidedi/guides/005010/X221A1-HP835.rb +613 -0
  83. data/lib/stupidedi/guides/005010/X222-HC837P.rb +2291 -0
  84. data/lib/stupidedi/guides/005010/X222A1-HC837P.rb +2297 -0
  85. data/lib/stupidedi/guides/005010/X231-FA999.rb +123 -0
  86. data/lib/stupidedi/guides/005010/X231A1-FA999.rb +119 -0
  87. data/lib/stupidedi/guides/005010/element_reqs.rb +38 -0
  88. data/lib/stupidedi/guides/005010/guide_builder.rb +180 -0
  89. data/lib/stupidedi/guides/005010/segment_reqs.rb +32 -0
  90. data/lib/stupidedi/guides/005010.rb +64 -0
  91. data/lib/stupidedi/guides.rb +5 -0
  92. data/lib/stupidedi/inspect.rb +26 -0
  93. data/lib/stupidedi/reader/input/abstract_input.rb +133 -0
  94. data/lib/stupidedi/reader/input/delegated_input.rb +111 -0
  95. data/lib/stupidedi/reader/input/file_input.rb +155 -0
  96. data/lib/stupidedi/reader/input.rb +30 -0
  97. data/lib/stupidedi/reader/position.rb +69 -0
  98. data/lib/stupidedi/reader/result.rb +168 -0
  99. data/lib/stupidedi/reader/segment_dict.rb +175 -0
  100. data/lib/stupidedi/reader/separators.rb +85 -0
  101. data/lib/stupidedi/reader/stream_reader.rb +172 -0
  102. data/lib/stupidedi/reader/token_reader.rb +466 -0
  103. data/lib/stupidedi/reader/tokens/component_element_tok.rb +56 -0
  104. data/lib/stupidedi/reader/tokens/composite_element_tok.rb +64 -0
  105. data/lib/stupidedi/reader/tokens/repeated_element_tok.rb +64 -0
  106. data/lib/stupidedi/reader/tokens/segment_tok.rb +51 -0
  107. data/lib/stupidedi/reader/tokens/simple_element_tok.rb +63 -0
  108. data/lib/stupidedi/reader.rb +121 -0
  109. data/lib/stupidedi/schema/abstract_def.rb +74 -0
  110. data/lib/stupidedi/schema/abstract_use.rb +73 -0
  111. data/lib/stupidedi/schema/code_list.rb +94 -0
  112. data/lib/stupidedi/schema/element_def.rb +173 -0
  113. data/lib/stupidedi/schema/element_req.rb +56 -0
  114. data/lib/stupidedi/schema/element_use.rb +251 -0
  115. data/lib/stupidedi/schema/functional_group_def.rb +114 -0
  116. data/lib/stupidedi/schema/interchange_def.rb +93 -0
  117. data/lib/stupidedi/schema/loop_def.rb +152 -0
  118. data/lib/stupidedi/schema/repeat_count.rb +85 -0
  119. data/lib/stupidedi/schema/segment_def.rb +108 -0
  120. data/lib/stupidedi/schema/segment_req.rb +43 -0
  121. data/lib/stupidedi/schema/segment_use.rb +98 -0
  122. data/lib/stupidedi/schema/syntax_note.rb +63 -0
  123. data/lib/stupidedi/schema/table_def.rb +139 -0
  124. data/lib/stupidedi/schema/transaction_set_def.rb +88 -0
  125. data/lib/stupidedi/schema.rb +28 -0
  126. data/lib/stupidedi/sets/absolute_set.rb +297 -0
  127. data/lib/stupidedi/sets/abstract_set.rb +174 -0
  128. data/lib/stupidedi/sets/null_set.rb +125 -0
  129. data/lib/stupidedi/sets/relative_complement.rb +137 -0
  130. data/lib/stupidedi/sets/relative_set.rb +269 -0
  131. data/lib/stupidedi/sets/universal_set.rb +104 -0
  132. data/lib/stupidedi/sets.rb +57 -0
  133. data/lib/stupidedi/tail_call.rb +109 -0
  134. data/lib/stupidedi/thread_local.rb +174 -0
  135. data/lib/stupidedi/values/abstract_element_val.rb +19 -0
  136. data/lib/stupidedi/values/abstract_val.rb +130 -0
  137. data/lib/stupidedi/values/composite_element_val.rb +95 -0
  138. data/lib/stupidedi/values/functional_group_val.rb +102 -0
  139. data/lib/stupidedi/values/interchange_val.rb +86 -0
  140. data/lib/stupidedi/values/invalid_envelope_val.rb +61 -0
  141. data/lib/stupidedi/values/invalid_segment_val.rb +78 -0
  142. data/lib/stupidedi/values/loop_val.rb +70 -0
  143. data/lib/stupidedi/values/repeated_element_val.rb +105 -0
  144. data/lib/stupidedi/values/segment_val.rb +104 -0
  145. data/lib/stupidedi/values/segment_val_group.rb +20 -0
  146. data/lib/stupidedi/values/simple_element_val.rb +80 -0
  147. data/lib/stupidedi/values/table_val.rb +66 -0
  148. data/lib/stupidedi/values/transaction_set_val.rb +66 -0
  149. data/lib/stupidedi/values/transmission_val.rb +52 -0
  150. data/lib/stupidedi/values.rb +21 -0
  151. data/lib/stupidedi/version.rb +3 -0
  152. data/lib/stupidedi/versions/functional_groups/004010/element_defs.rb +54 -0
  153. data/lib/stupidedi/versions/functional_groups/004010/element_reqs.rb +18 -0
  154. data/lib/stupidedi/versions/functional_groups/004010/element_types/date_val.rb +527 -0
  155. data/lib/stupidedi/versions/functional_groups/004010/element_types/fixnum_val.rb +335 -0
  156. data/lib/stupidedi/versions/functional_groups/004010/element_types/float_val.rb +299 -0
  157. data/lib/stupidedi/versions/functional_groups/004010/element_types/identifier_val.rb +287 -0
  158. data/lib/stupidedi/versions/functional_groups/004010/element_types/string_val.rb +338 -0
  159. data/lib/stupidedi/versions/functional_groups/004010/element_types/time_val.rb +309 -0
  160. data/lib/stupidedi/versions/functional_groups/004010/element_types.rb +124 -0
  161. data/lib/stupidedi/versions/functional_groups/004010/functional_group_def.rb +30 -0
  162. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/GE.rb +20 -0
  163. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/GS.rb +27 -0
  164. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/SE.rb +20 -0
  165. data/lib/stupidedi/versions/functional_groups/004010/segment_defs/ST.rb +20 -0
  166. data/lib/stupidedi/versions/functional_groups/004010/segment_defs.rb +23 -0
  167. data/lib/stupidedi/versions/functional_groups/004010/segment_reqs.rb +18 -0
  168. data/lib/stupidedi/versions/functional_groups/004010/syntax_notes.rb +174 -0
  169. data/lib/stupidedi/versions/functional_groups/004010.rb +38 -0
  170. data/lib/stupidedi/versions/functional_groups/005010/element_defs.rb +1405 -0
  171. data/lib/stupidedi/versions/functional_groups/005010/element_reqs.rb +18 -0
  172. data/lib/stupidedi/versions/functional_groups/005010/element_types/date_val.rb +577 -0
  173. data/lib/stupidedi/versions/functional_groups/005010/element_types/fixnum_val.rb +322 -0
  174. data/lib/stupidedi/versions/functional_groups/005010/element_types/float_val.rb +354 -0
  175. data/lib/stupidedi/versions/functional_groups/005010/element_types/identifier_val.rb +368 -0
  176. data/lib/stupidedi/versions/functional_groups/005010/element_types/operators.rb +117 -0
  177. data/lib/stupidedi/versions/functional_groups/005010/element_types/string_val.rb +398 -0
  178. data/lib/stupidedi/versions/functional_groups/005010/element_types/time_val.rb +327 -0
  179. data/lib/stupidedi/versions/functional_groups/005010/element_types.rb +132 -0
  180. data/lib/stupidedi/versions/functional_groups/005010/functional_group_def.rb +30 -0
  181. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AK1.rb +21 -0
  182. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AK2.rb +21 -0
  183. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AK9.rb +28 -0
  184. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/AMT.rb +21 -0
  185. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/BHT.rb +24 -0
  186. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/BPR.rb +49 -0
  187. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CAS.rb +56 -0
  188. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CL1.rb +22 -0
  189. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CLM.rb +41 -0
  190. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CLP.rb +34 -0
  191. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CN1.rb +24 -0
  192. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CR1.rb +32 -0
  193. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CR2.rb +35 -0
  194. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CR3.rb +25 -0
  195. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CRC.rb +26 -0
  196. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CTP.rb +36 -0
  197. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CTX.rb +24 -0
  198. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/CUR.rb +57 -0
  199. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DMG.rb +34 -0
  200. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DN1.rb +22 -0
  201. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DN2.rb +24 -0
  202. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DTM.rb +24 -0
  203. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/DTP.rb +21 -0
  204. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/FRM.rb +25 -0
  205. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/GE.rb +20 -0
  206. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/GS.rb +27 -0
  207. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/HCP.rb +39 -0
  208. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/HI.rb +31 -0
  209. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/HL.rb +22 -0
  210. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/IK3.rb +22 -0
  211. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/IK4.rb +22 -0
  212. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/IK5.rb +24 -0
  213. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/K3.rb +21 -0
  214. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/LIN.rb +69 -0
  215. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/LQ.rb +22 -0
  216. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/LX.rb +19 -0
  217. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/MEA.rb +39 -0
  218. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/MIA.rb +45 -0
  219. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/MOA.rb +28 -0
  220. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N1.rb +24 -0
  221. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N2.rb +20 -0
  222. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N3.rb +20 -0
  223. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/N4.rb +30 -0
  224. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/NM1.rb +35 -0
  225. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/NTE.rb +20 -0
  226. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/OI.rb +24 -0
  227. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PAT.rb +31 -0
  228. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PER.rb +32 -0
  229. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PLB.rb +40 -0
  230. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PRV.rb +26 -0
  231. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PS1.rb +21 -0
  232. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/PWK.rb +30 -0
  233. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/QTY.rb +25 -0
  234. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/RDM.rb +23 -0
  235. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/REF.rb +23 -0
  236. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SBR.rb +28 -0
  237. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SE.rb +20 -0
  238. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/ST.rb +21 -0
  239. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/STC.rb +30 -0
  240. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV1.rb +44 -0
  241. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV2.rb +29 -0
  242. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV3.rb +30 -0
  243. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SV5.rb +29 -0
  244. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SVC.rb +26 -0
  245. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/SVD.rb +24 -0
  246. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TOO.rb +21 -0
  247. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TRN.rb +22 -0
  248. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TS2.rb +40 -0
  249. data/lib/stupidedi/versions/functional_groups/005010/segment_defs/TS3.rb +45 -0
  250. data/lib/stupidedi/versions/functional_groups/005010/segment_defs.rb +227 -0
  251. data/lib/stupidedi/versions/functional_groups/005010/segment_reqs.rb +18 -0
  252. data/lib/stupidedi/versions/functional_groups/005010/syntax_notes.rb +165 -0
  253. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/FA999.rb +38 -0
  254. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HB271.rb +85 -0
  255. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HC837.rb +163 -0
  256. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HI278.rb +64 -0
  257. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HN277.rb +74 -0
  258. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HP835.rb +68 -0
  259. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HR276.rb +57 -0
  260. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HS270.rb +53 -0
  261. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/RA820.rb +240 -0
  262. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs.rb +68 -0
  263. data/lib/stupidedi/versions/functional_groups/005010.rb +38 -0
  264. data/lib/stupidedi/versions/functional_groups.rb +8 -0
  265. data/lib/stupidedi/versions/interchanges/00401/element_defs.rb +224 -0
  266. data/lib/stupidedi/versions/interchanges/00401/interchange_def.rb +45 -0
  267. data/lib/stupidedi/versions/interchanges/00401/segment_defs/IEA.rb +20 -0
  268. data/lib/stupidedi/versions/interchanges/00401/segment_defs/ISA.rb +34 -0
  269. data/lib/stupidedi/versions/interchanges/00401/segment_defs/TA1.rb +23 -0
  270. data/lib/stupidedi/versions/interchanges/00401/segment_defs.rb +28 -0
  271. data/lib/stupidedi/versions/interchanges/00401.rb +23 -0
  272. data/lib/stupidedi/versions/interchanges/00501/element_defs.rb +269 -0
  273. data/lib/stupidedi/versions/interchanges/00501/interchange_def.rb +47 -0
  274. data/lib/stupidedi/versions/interchanges/00501/segment_defs/IEA.rb +20 -0
  275. data/lib/stupidedi/versions/interchanges/00501/segment_defs/ISA.rb +34 -0
  276. data/lib/stupidedi/versions/interchanges/00501/segment_defs/ISB.rb +18 -0
  277. data/lib/stupidedi/versions/interchanges/00501/segment_defs/ISE.rb +18 -0
  278. data/lib/stupidedi/versions/interchanges/00501/segment_defs/TA1.rb +23 -0
  279. data/lib/stupidedi/versions/interchanges/00501/segment_defs/TA3.rb +18 -0
  280. data/lib/stupidedi/versions/interchanges/00501/segment_defs.rb +37 -0
  281. data/lib/stupidedi/versions/interchanges/00501.rb +23 -0
  282. data/lib/stupidedi/versions/interchanges.rb +8 -0
  283. data/lib/stupidedi/versions.rb +6 -0
  284. data/lib/stupidedi/writer/claredi.rb +142 -0
  285. data/lib/stupidedi/writer/default.rb +124 -0
  286. data/lib/stupidedi/writer.rb +6 -0
  287. data/lib/stupidedi/zipper/abstract_cursor.rb +351 -0
  288. data/lib/stupidedi/zipper/dangling_cursor.rb +103 -0
  289. data/lib/stupidedi/zipper/edited_cursor.rb +157 -0
  290. data/lib/stupidedi/zipper/memoized_cursor.rb +131 -0
  291. data/lib/stupidedi/zipper/path.rb +124 -0
  292. data/lib/stupidedi/zipper/root_cursor.rb +120 -0
  293. data/lib/stupidedi/zipper.rb +25 -0
  294. data/lib/stupidedi.rb +66 -0
  295. data/spec/examples/integration/generating.example +551 -0
  296. data/spec/examples/integration/navigating.example +214 -0
  297. data/spec/examples/integration/parsing.example +445 -0
  298. data/spec/examples/ruby/array.example +476 -0
  299. data/spec/examples/ruby/blank.example +62 -0
  300. data/spec/examples/ruby/count.example +68 -0
  301. data/spec/examples/ruby/object.example +99 -0
  302. data/spec/examples/ruby/string.example +111 -0
  303. data/spec/examples/ruby/symbol.example +117 -0
  304. data/spec/examples/ruby/to_d.example +90 -0
  305. data/spec/examples/ruby/try.example +50 -0
  306. data/spec/examples/stupidedi/either.example +375 -0
  307. data/spec/examples/stupidedi/reader/failure.example +68 -0
  308. data/spec/examples/stupidedi/reader/input/delegated_input.example +292 -0
  309. data/spec/examples/stupidedi/reader/separators.example +73 -0
  310. data/spec/examples/stupidedi/reader/stream_reader.example +48 -0
  311. data/spec/examples/stupidedi/reader/success.example +34 -0
  312. data/spec/examples/stupidedi/reader/token_reader.example +775 -0
  313. data/spec/examples/stupidedi/reader.example +168 -0
  314. data/spec/examples/stupidedi/sets/absolute_set.example +1577 -0
  315. data/spec/examples/stupidedi/sets/null_set.example +2 -0
  316. data/spec/examples/stupidedi/sets/relative_set.example +2 -0
  317. data/spec/examples/stupidedi/sets/universal_set.example +1 -0
  318. data/spec/examples/stupidedi/versions/005010/element_types/an.example +201 -0
  319. data/spec/examples/stupidedi/versions/005010/element_types/dt.example +258 -0
  320. data/spec/examples/stupidedi/versions/005010/element_types/id.example +192 -0
  321. data/spec/examples/stupidedi/versions/005010/element_types/nn.example +177 -0
  322. data/spec/examples/stupidedi/versions/005010/element_types/r.example +178 -0
  323. data/spec/examples/stupidedi/versions/005010/element_types/tm.example +2 -0
  324. data/spec/examples/stupidedi/zipper/abstract_cursor.example +417 -0
  325. data/spec/examples/stupidedi/zipper.example +9 -0
  326. data/spec/fixtures/X186-AG824/1-bad.txt +21 -0
  327. data/spec/fixtures/X186-AG824/1-good.txt +17 -0
  328. data/spec/fixtures/X186-AG824/2-bad.txt +26 -0
  329. data/spec/fixtures/X186-AG824/2-good.txt +21 -0
  330. data/spec/fixtures/X186-AG824/3-bad.txt +87 -0
  331. data/spec/fixtures/X186-AG824/3-good.txt +61 -0
  332. data/spec/fixtures/X212-HN277/1-bad.txt +54 -0
  333. data/spec/fixtures/X212-HN277/1-good.txt +46 -0
  334. data/spec/fixtures/X212-HN277/2-bad.txt +37 -0
  335. data/spec/fixtures/X212-HN277/2-good.txt +29 -0
  336. data/spec/fixtures/X212-HN277/3-bad.txt +22 -0
  337. data/spec/fixtures/X212-HN277/3-good.txt +17 -0
  338. data/spec/fixtures/X212-HN277/4-bad.txt +30 -0
  339. data/spec/fixtures/X212-HN277/4-good.txt +24 -0
  340. data/spec/fixtures/X212-HR276/1-bad.txt +53 -0
  341. data/spec/fixtures/X212-HR276/1-good.txt +46 -0
  342. data/spec/fixtures/X212-HR276/2-bad.txt +45 -0
  343. data/spec/fixtures/X212-HR276/2-good.txt +38 -0
  344. data/spec/fixtures/X212-HR276/3-bad.txt +32 -0
  345. data/spec/fixtures/X212-HR276/3-good.txt +26 -0
  346. data/spec/fixtures/X212-HR276/4-bad.txt +32 -0
  347. data/spec/fixtures/X212-HR276/4-good.txt +26 -0
  348. data/spec/fixtures/X214-HN277/1-bad.txt +58 -0
  349. data/spec/fixtures/X214-HN277/1-good.txt +47 -0
  350. data/spec/fixtures/X214-HN277/2-bad.txt +34 -0
  351. data/spec/fixtures/X214-HN277/2-good.txt +22 -0
  352. data/spec/fixtures/X214-HN277/3-bad.txt +64 -0
  353. data/spec/fixtures/X214-HN277/3-good.txt +54 -0
  354. data/spec/fixtures/X214-HN277/4-bad.txt +77 -0
  355. data/spec/fixtures/X214-HN277/4-good.txt +63 -0
  356. data/spec/fixtures/X216-HI278/1-bad.txt +42 -0
  357. data/spec/fixtures/X216-HI278/1-good.txt +27 -0
  358. data/spec/fixtures/X216-HI278/2-bad.txt +43 -0
  359. data/spec/fixtures/X216-HI278/2-good.txt +29 -0
  360. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-1.txt +24 -0
  361. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-1_Clean.txt +20 -0
  362. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-2.txt +46 -0
  363. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-2_Clean.txt +30 -0
  364. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-3.txt +38 -0
  365. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-3_Clean.txt +24 -0
  366. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4a.txt +39 -0
  367. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4a_Clean.txt +24 -0
  368. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4b.txt +43 -0
  369. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-4b_Clean.txt +25 -0
  370. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-5.txt +63 -0
  371. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-5_Clean.txt +41 -0
  372. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-6.txt +36 -0
  373. data/spec/fixtures/X217-HI278/Sample_278_Request_5010X217-6_Clean.txt +20 -0
  374. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-1r.txt +34 -0
  375. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-1r_Clean.txt +23 -0
  376. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-2r.txt +46 -0
  377. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-2r_Clean.txt +31 -0
  378. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-3r.txt +44 -0
  379. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-3r_Clean.txt +26 -0
  380. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-4ar_Clean.txt +28 -0
  381. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-4br_Clean.txt +35 -0
  382. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-5r.txt +60 -0
  383. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-5r_Clean.txt +42 -0
  384. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-6r.txt +40 -0
  385. data/spec/fixtures/X217-HI278/Sample_278_Response_5010X217-6r_Clean.txt +24 -0
  386. data/spec/fixtures/X218-RA820/1-bad.txt +31 -0
  387. data/spec/fixtures/X218-RA820/1-good.txt +25 -0
  388. data/spec/fixtures/X218-RA820/2-bad.txt +37 -0
  389. data/spec/fixtures/X218-RA820/2-good.txt +29 -0
  390. data/spec/fixtures/X218-RA820/3-bad.txt +29 -0
  391. data/spec/fixtures/X218-RA820/3-good.txt +23 -0
  392. data/spec/fixtures/X218-RA820/4-bad.txt +36 -0
  393. data/spec/fixtures/X218-RA820/4-good.txt +27 -0
  394. data/spec/fixtures/X220-BE834/1-bad.txt +35 -0
  395. data/spec/fixtures/X220-BE834/1-good.txt +29 -0
  396. data/spec/fixtures/X220-BE834/10-bad.txt +26 -0
  397. data/spec/fixtures/X220-BE834/10-good.txt +19 -0
  398. data/spec/fixtures/X220-BE834/2-bad.txt +31 -0
  399. data/spec/fixtures/X220-BE834/2-good.txt +23 -0
  400. data/spec/fixtures/X220-BE834/3-bad.txt +36 -0
  401. data/spec/fixtures/X220-BE834/3-good.txt +26 -0
  402. data/spec/fixtures/X220-BE834/4-bad.txt +27 -0
  403. data/spec/fixtures/X220-BE834/4-good.txt +21 -0
  404. data/spec/fixtures/X220-BE834/5-bad.txt +26 -0
  405. data/spec/fixtures/X220-BE834/5-good.txt +17 -0
  406. data/spec/fixtures/X220-BE834/6-bad.txt +25 -0
  407. data/spec/fixtures/X220-BE834/6-good.txt +20 -0
  408. data/spec/fixtures/X220-BE834/7-bad.txt +25 -0
  409. data/spec/fixtures/X220-BE834/7-good.txt +20 -0
  410. data/spec/fixtures/X220-BE834/8-bad.txt +25 -0
  411. data/spec/fixtures/X220-BE834/8-good.txt +20 -0
  412. data/spec/fixtures/X220-BE834/9-bad.txt +27 -0
  413. data/spec/fixtures/X220-BE834/9-good.txt +21 -0
  414. data/spec/fixtures/X221-HP835/1-bad.txt +58 -0
  415. data/spec/fixtures/X221-HP835/1-good.txt +40 -0
  416. data/spec/fixtures/X221-HP835/2-bad.txt +51 -0
  417. data/spec/fixtures/X221-HP835/2-good.txt +40 -0
  418. data/spec/fixtures/X221-HP835/3a-bad.txt +78 -0
  419. data/spec/fixtures/X221-HP835/3a-good.txt +49 -0
  420. data/spec/fixtures/X221-HP835/3b-bad.txt +60 -0
  421. data/spec/fixtures/X221-HP835/3b-good.txt +32 -0
  422. data/spec/fixtures/X221-HP835/3c-bad.txt +55 -0
  423. data/spec/fixtures/X221-HP835/3c-good.txt +34 -0
  424. data/spec/fixtures/X222-HC837/1-bad.txt +60 -0
  425. data/spec/fixtures/X222-HC837/1-good.txt +53 -0
  426. data/spec/fixtures/X222-HC837/10a-bad.txt +52 -0
  427. data/spec/fixtures/X222-HC837/10a-good.txt +40 -0
  428. data/spec/fixtures/X222-HC837/10b-bad.txt +99 -0
  429. data/spec/fixtures/X222-HC837/10b-good.txt +80 -0
  430. data/spec/fixtures/X222-HC837/10c-bad.txt +105 -0
  431. data/spec/fixtures/X222-HC837/10c-good.txt +80 -0
  432. data/spec/fixtures/X222-HC837/11-bad.txt +69 -0
  433. data/spec/fixtures/X222-HC837/11-good.txt +45 -0
  434. data/spec/fixtures/X222-HC837/12-bad.txt +73 -0
  435. data/spec/fixtures/X222-HC837/12-good.txt +51 -0
  436. data/spec/fixtures/X222-HC837/13-bad.txt +64 -0
  437. data/spec/fixtures/X222-HC837/13-good.txt +46 -0
  438. data/spec/fixtures/X222-HC837/3a-bad.txt +83 -0
  439. data/spec/fixtures/X222-HC837/3a-good.txt +59 -0
  440. data/spec/fixtures/X222-HC837/3b-bad.txt +97 -0
  441. data/spec/fixtures/X222-HC837/3b-good.txt +70 -0
  442. data/spec/fixtures/X222-HC837/3c-bad.txt +95 -0
  443. data/spec/fixtures/X222-HC837/3c-good.txt +74 -0
  444. data/spec/fixtures/X222-HC837/4-bad.txt +67 -0
  445. data/spec/fixtures/X222-HC837/4-good.txt +48 -0
  446. data/spec/fixtures/X222-HC837/5-bad.txt +73 -0
  447. data/spec/fixtures/X222-HC837/5-good.txt +60 -0
  448. data/spec/fixtures/X222-HC837/6-bad.txt +50 -0
  449. data/spec/fixtures/X222-HC837/6-good.txt +39 -0
  450. data/spec/fixtures/X222-HC837/7-bad.txt +93 -0
  451. data/spec/fixtures/X222-HC837/7-good.txt +78 -0
  452. data/spec/fixtures/X222-HC837/8-bad.txt +64 -0
  453. data/spec/fixtures/X222-HC837/8-good.txt +52 -0
  454. data/spec/fixtures/X222-HC837/9-bad.txt +56 -0
  455. data/spec/fixtures/X222-HC837/9-good.txt +38 -0
  456. data/spec/fixtures/X223-HC837/1-bad.txt +66 -0
  457. data/spec/fixtures/X223-HC837/1-good.txt +53 -0
  458. data/spec/fixtures/X223-HC837/2-bad.txt +69 -0
  459. data/spec/fixtures/X223-HC837/2-good.txt +60 -0
  460. data/spec/fixtures/X223-HC837/3-bad.txt +89 -0
  461. data/spec/fixtures/X223-HC837/3-good.txt +61 -0
  462. data/spec/fixtures/X223-HC837/4-bad.txt +60 -0
  463. data/spec/fixtures/X223-HC837/4-good.txt +40 -0
  464. data/spec/fixtures/X223-HC837/5-bad.txt +75 -0
  465. data/spec/fixtures/X223-HC837/5-good.txt +58 -0
  466. data/spec/fixtures/X224-HC837/1-bad.txt +54 -0
  467. data/spec/fixtures/X224-HC837/1-good.txt +44 -0
  468. data/spec/fixtures/X224-HC837/2a-bad.txt +52 -0
  469. data/spec/fixtures/X224-HC837/2a-good.txt +42 -0
  470. data/spec/fixtures/X224-HC837/2b-bad.txt +67 -0
  471. data/spec/fixtures/X224-HC837/2b-good.txt +52 -0
  472. data/spec/fixtures/X224-HC837/3-bad.txt +67 -0
  473. data/spec/fixtures/X224-HC837/3-good.txt +51 -0
  474. data/spec/fixtures/X224-HC837/4-bad.txt +49 -0
  475. data/spec/fixtures/X224-HC837/4-good.txt +40 -0
  476. data/spec/fixtures/X230-FA997/1-bad.txt +19 -0
  477. data/spec/fixtures/X230-FA997/1-good.txt +16 -0
  478. data/spec/fixtures/X231-FA999/1-bad.txt +20 -0
  479. data/spec/fixtures/X231-FA999/1-good.txt +20 -0
  480. data/spec/fixtures/X279-HB271/1-bad.txt +36 -0
  481. data/spec/fixtures/X279-HB271/1-good.txt +30 -0
  482. data/spec/fixtures/X279-HB271/2-bad.txt +22 -0
  483. data/spec/fixtures/X279-HB271/2-good.txt +16 -0
  484. data/spec/fixtures/X279-HB271/3-bad.txt +44 -0
  485. data/spec/fixtures/X279-HB271/3-good.txt +36 -0
  486. data/spec/fixtures/X279-HS270/1-bad.txt +29 -0
  487. data/spec/fixtures/X279-HS270/1-good.txt +23 -0
  488. data/spec/fixtures/X279-HS270/2-bad.txt +32 -0
  489. data/spec/fixtures/X279-HS270/2-good.txt +25 -0
  490. data/spec/spec_helper.rb +34 -0
  491. data/spec/support/fixtures.rb +26 -0
  492. data/spec/support/matchers/either_matchers.rb +26 -0
  493. data/spec/support/matchers/navigation_matchers.rb +247 -0
  494. data/spec/support/node.rb +41 -0
  495. data/spec/support/quickcheck/characters.rb +28 -0
  496. data/spec/support/quickcheck/property.rb +105 -0
  497. data/spec/support/quickcheck/serialized_edi.rb +399 -0
  498. data/spec/support/quickcheck.rb +302 -0
  499. data/spec/support/rcov.rb +34 -0
  500. metadata +577 -0
@@ -0,0 +1,655 @@
1
+ module Stupidedi
2
+ module Builder
3
+
4
+ module Navigation
5
+
6
+ # @group Querying the Current Position
7
+ #########################################################################
8
+
9
+ # @return [Array<InstructionTable>]
10
+ def successors
11
+ @active.map{|a| a.node.instructions }
12
+ end
13
+
14
+ # Is there exactly one valid parse tree in the current state?
15
+ def deterministic?
16
+ @active.length == 1
17
+ end
18
+
19
+ def empty?
20
+ value = @active.head.node.zipper
21
+
22
+ until value.root?
23
+ value = value.up
24
+ end
25
+
26
+ value.node.children.empty?
27
+ end
28
+
29
+ # Is this the first segment?
30
+ def first?
31
+ value = @active.head.node.zipper
32
+
33
+ until value.root?
34
+ return false unless value.first?
35
+ value = value.up
36
+ end
37
+
38
+ return true
39
+ end
40
+
41
+ # Is this the last segment?
42
+ def last?
43
+ value = @active.head.node.zipper
44
+
45
+ until value.root?
46
+ return false unless value.last?
47
+ value = value.up
48
+ end
49
+
50
+ return true
51
+ end
52
+
53
+ # Returns the number of segments apart the current state is from the
54
+ # given `StateMachine`'s state. Note the direction is not indicated by
55
+ # the return value, so `a.distance(b) == b.distance(a)` for all states
56
+ # `a` and `b`.
57
+ #
58
+ # @example
59
+ # m.distance(m) #=> Either.success(0)
60
+ # m.next(10).flatmap{|n| n.distance(m) } #=> Either.success(10)
61
+ #
62
+ # @return [Either<Integer>]
63
+ #
64
+ # @note This method uses AbstractCursor#between, which assumes the two
65
+ # cursors point to the same tree. If that is not the case, the results
66
+ # are undefined.
67
+ def distance(other)
68
+ zipper.flatmap do |a|
69
+ other.zipper.map do |b|
70
+ a.between(b).count(&:segment?) - 1
71
+ end
72
+ end
73
+ end
74
+
75
+ # @group Accessing the Current Node
76
+ #########################################################################
77
+
78
+ # Returns the current position within the parse tree, if the current state
79
+ # is deterministic.
80
+ #
81
+ # @return [Either<Zipper::AbstractCursor<Values::AbstractVal>>]
82
+ def zipper
83
+ if deterministic?
84
+ Either.success(@active.head.node.zipper)
85
+ else
86
+ Either.failure("non-deterministic state")
87
+ end
88
+ end
89
+
90
+ # Extracts the segment from the current state, if the current state is
91
+ # deterministic and positioned on a segment.
92
+ #
93
+ # @return [Either<Zipper::AbstractCursor<Values::SegmentVal>>]
94
+ def segment
95
+ zipper.flatmap do |z|
96
+ if z.node.segment?
97
+ Either.success(z)
98
+ else
99
+ Either.failure("not a segment")
100
+ end
101
+ end
102
+ end
103
+
104
+ # Extracts the *mth* element from the current segment, if the current
105
+ # state is deterministic. Accepts optional arguments to extract a specific
106
+ # occurrence of a repeated element and/or a specific component from a
107
+ # composite element.
108
+ #
109
+ # @return [Either<Zipper::AbstractCursor<Values::AbstractElementVal>>]
110
+ def element(m, n = nil, o = nil)
111
+ segment.flatmap do |s|
112
+ unless m >= 1
113
+ raise ArgumentError,
114
+ "argument must be positive"
115
+ end
116
+
117
+ if s.node.invalid?
118
+ # InvalidSegmentVal doesn't have child AbstractElementVals, its
119
+ # children are SimpleElementTok, CompositeElementTok, etc, which
120
+ # are not parsed values.
121
+ return Either.failure("invalid segment")
122
+ end
123
+
124
+ designator = s.node.id.to_s
125
+ definition = s.node.definition
126
+ length = definition.element_uses.length
127
+
128
+ unless m <= length
129
+ raise ArgumentError,
130
+ "#{designator} segment has only #{length} elements"
131
+ end
132
+
133
+ designator << "%02d" % m
134
+ value = s.child(m - 1)
135
+
136
+ if n.nil?
137
+ return Either.success(value)
138
+ elsif value.node.repeated?
139
+ unless n >= 1
140
+ raise ArgumentError,
141
+ "argument must be positive"
142
+ end
143
+
144
+ limit = value.node.definition.repeat_count
145
+ unless limit.include?(n)
146
+ raise ArgumentError,
147
+ "#{designator} can only occur #{limit.max} times"
148
+ end
149
+
150
+ unless value.node.children.defined_at?(n - 1)
151
+ return Either.failure("#{designator} occurs only #{value.node.children.length} times")
152
+ end
153
+
154
+ value = value.child(n - 1)
155
+ n, o = o, nil
156
+
157
+ return Either.success(value) if n.nil?
158
+ end
159
+
160
+ unless value.node.composite?
161
+ raise ArgumentError,
162
+ "#{designator} is a simple element"
163
+ end
164
+
165
+ unless o.nil?
166
+ raise ArgumentError,
167
+ "#{designator} is a non-repeatable composite element"
168
+ end
169
+
170
+ unless n >= 1
171
+ raise ArgumentError,
172
+ "argument must be positive"
173
+ end
174
+
175
+ length = definition.element_uses.at(m - 1).definition.component_uses.length
176
+ unless n <= length
177
+ raise ArgumentError,
178
+ "#{designator} has only #{length} components"
179
+ end
180
+
181
+ if value.node.empty?
182
+ Either.failure("#{designator} is empty")
183
+ else
184
+ Either.success(value.child(n - 1))
185
+ end
186
+ end
187
+ end
188
+
189
+ # @group Navigating the Tree
190
+ #########################################################################
191
+
192
+ # Returns a new `StateMachine` positioned on the first segment in
193
+ # the parse tree, if there are any segments in the parse tree.
194
+ #
195
+ # @return [Either<StateMachine>]
196
+ def first
197
+ active = roots.map do |zipper|
198
+ state = zipper
199
+ value = zipper.node.zipper
200
+
201
+ until value.node.segment? or value.leaf?
202
+ value = value.down
203
+ state = state.down
204
+ end
205
+
206
+ unless value.node.segment?
207
+ return Either.failure("no segments")
208
+ end
209
+
210
+ # Synchronize the two parallel state and value nodes
211
+ unless value.eql?(state.node.zipper)
212
+ state = state.replace(state.node.copy(:zipper => value))
213
+ end
214
+
215
+ state
216
+ end
217
+
218
+ Either.success(StateMachine.new(@config, active))
219
+ end
220
+
221
+ # Returns a new `StateMachine` positioned on the last segment in
222
+ # the parse tree, if there are any segments in the parse tree.
223
+ #
224
+ # @return [Either<StateMachine>]
225
+ def last
226
+ active = roots.map do |zipper|
227
+ state = zipper
228
+ value = zipper.node.zipper
229
+
230
+ until value.node.segment? or value.leaf?
231
+ value = value.down.last
232
+ state = state.down.last
233
+ end
234
+
235
+ unless value.node.segment?
236
+ return Either.failure("no segments")
237
+ end
238
+
239
+ # Synchronize the two parallel state and value nodes
240
+ unless value.eql?(state.node.zipper)
241
+ state = state.replace(state.node.copy(:zipper => value))
242
+ end
243
+
244
+ state
245
+ end
246
+
247
+ Either.success(StateMachine.new(@config, active))
248
+ end
249
+
250
+ # Returns a new `StateMachine` positioned on the first segment of the
251
+ # parent structure. For example, when the current segment belongs to a
252
+ # loop but it's not the first segment in that loop, this method will
253
+ # rewind to the first segment in the loop. If the current position is
254
+ # the first segment of a loop, this method will rewind to the first
255
+ # segment in the loop's parent structure.
256
+ #
257
+ # @return [Either<StateMachine>]
258
+ def parent
259
+ active = []
260
+
261
+ @active.each do |zipper|
262
+ state = zipper
263
+ value = zipper.node.zipper
264
+
265
+ while value.first? and not value.root?
266
+ value = value.up
267
+ state = state.up
268
+ end
269
+
270
+ if value.root?
271
+ break
272
+ end
273
+
274
+ value = value.first
275
+ state = state.first
276
+
277
+ until value.node.segment?
278
+ value = value.down
279
+ state = state.down
280
+ end
281
+
282
+ # Synchronize the two parallel state and value nodes
283
+ unless value.eql?(state.node.zipper)
284
+ state = state.replace(state.node.copy(:zipper => value))
285
+ end
286
+
287
+ active << state
288
+ end
289
+
290
+ if active.empty?
291
+ Either.failure("no parent segment")
292
+ else
293
+ Either.success(StateMachine.new(@config, active))
294
+ end
295
+ end
296
+
297
+ # Returns a new `StateMachine` positioned on the next segment, if
298
+ # there is a next segment. Optionally, a `count` argument may be
299
+ # provided that indicates how many segments to advance.
300
+ #
301
+ # @return [StateMachine]
302
+ def next(count = 1)
303
+ unless count > 0
304
+ raise ArgumentError,
305
+ "count must be positive"
306
+ end
307
+
308
+ active = @active.map do |zipper|
309
+ state = zipper
310
+ value = zipper.node.zipper
311
+
312
+ count.times do
313
+ while not value.root? and value.last?
314
+ value = value.up
315
+ state = state.up
316
+ end
317
+
318
+ if value.root?
319
+ return Either.failure("cannot move to next after last segment")
320
+ end
321
+
322
+ value = value.next
323
+ state = state.next
324
+
325
+ until value.node.segment?
326
+ value = value.down
327
+ state = state.down
328
+ end
329
+ end
330
+
331
+ # Synchronize the two parallel state and value nodes
332
+ unless value.eql?(state.node.zipper)
333
+ state = state.replace(state.node.copy(:zipper => value))
334
+ end
335
+
336
+ state
337
+ end
338
+
339
+ Either.success(StateMachine.new(@config, active))
340
+ end
341
+
342
+ # Returns a new `StateMachine` positioned on the previous segment, if
343
+ # there is a previous segment. Optionally, a `count` argument may be
344
+ # provided that indicates how many segments to rewind.
345
+ #
346
+ # @return [Either<StateMachine>]
347
+ def prev(count = 1)
348
+ unless count > 0
349
+ raise ArgumentError,
350
+ "count must be positive"
351
+ end
352
+
353
+ active = @active.map do |zipper|
354
+ state = zipper
355
+ value = zipper.node.zipper
356
+
357
+ count.times do
358
+ while not value.root? and value.first?
359
+ value = value.up
360
+ state = state.up
361
+ end
362
+
363
+ if value.root?
364
+ return Either.failure("cannot move to prev before first segment")
365
+ end
366
+
367
+ state = state.prev
368
+ value = value.prev
369
+
370
+ until value.node.segment?
371
+ value = value.down.last
372
+ state = state.down.last
373
+ end
374
+ end
375
+
376
+ # Synchronize the two parallel state and value nodes
377
+ unless value.eql?(state.node.zipper)
378
+ state = state.replace(state.node.copy(:zipper => value))
379
+ end
380
+
381
+ state
382
+ end
383
+
384
+ Either.success(StateMachine.new(@config, active))
385
+ end
386
+
387
+ # Returns a `StateMachine` positioned on the next matching segment,
388
+ # excluding {InvalidSegmentVal}s, that satisfies the given element
389
+ # constraints. The search space is limited to certain related elements
390
+ # described in [Navigating.md]
391
+ #
392
+ # @example
393
+ # machine.find(:ST, nil, nil, "005010X222")
394
+ #
395
+ # @return [Either<StateMachine>]
396
+ def find(id, *elements)
397
+ __find(false, id, elements)
398
+ end
399
+
400
+ # Returns a `StateMachine` positioned on the next matching segment,
401
+ # including {InvalidSegmentVal}s, that satisfies the given element
402
+ # constraints. The search space is limited to certain related elements
403
+ # described in [Navigating.md]
404
+ #
405
+ # @example
406
+ # machine.find!(:ST, nil, nil, "005010X222")
407
+ #
408
+ # @return [Either<StateMachine>]
409
+ def find!(id, *elements)
410
+ __find(true, id, elements)
411
+ end
412
+
413
+ # @return [Integer]
414
+ def count(id, *elements)
415
+ __count(false, id, elements)
416
+ end
417
+
418
+ # @return [Integer]
419
+ def count!(id, *elements)
420
+ __count(true, id, elements)
421
+ end
422
+
423
+ def iterate(id, *elements)
424
+ m = find(id, *elements)
425
+ while m.defined?
426
+ m = m.flatmap do |n|
427
+ yield(n)
428
+ n.find(id, *elements)
429
+ end
430
+ end
431
+ end
432
+
433
+ private
434
+
435
+ # @return [Either<StateMachine>]
436
+ def __find(invalid, id, elements)
437
+ reachable = false
438
+ matches = []
439
+
440
+ @active.each do |zipper|
441
+ matched = false
442
+ filter_tok = mksegment_tok(zipper.node.segment_dict, id, elements, nil)
443
+
444
+ instructions = zipper.node.instructions.matches(filter_tok, true)
445
+ reachable ||= !instructions.empty?
446
+
447
+ instructions.each do |op|
448
+ break if matched
449
+
450
+ # Every transition follows the same shape
451
+ # 1. Move upward a number of nodes
452
+ # 2. Move left a number of nodes
453
+ # 3. Move downward a number of nodes
454
+ # 4. Stop on a segment
455
+
456
+ state = zipper
457
+ value = zipper.node.zipper
458
+
459
+ # 1. Move upward (possibly zero times)
460
+ op.pop_count.times do
461
+ value = value.up
462
+ state = state.up
463
+ end
464
+
465
+ # 2. We know from the instruction `op` the *maximum* number of
466
+ # nodes to move left, but not exactly how many. Instead, we
467
+ # know what the InstructionTable is when we get there.
468
+ target = zipper.node.instructions.pop(op.pop_count).drop(op.drop_count)
469
+
470
+ until state.last?
471
+ state = state.next
472
+ value = value.next
473
+
474
+ # 2. Even if the InstructionTable matches, we still need to
475
+ # descend to some segment and compare it to the criteria. In
476
+ # most circumstances, this segment is directly below this
477
+ if target.eql?(state.node.instructions)
478
+
479
+ # 3. Move downward a number of nodes. Ultimately, we need to
480
+ # descend to a segment, but we have to be careful...
481
+ _value = value
482
+ _state = state
483
+
484
+ # 3. If the segment we're searching for belongs in a new subtree,
485
+ # but it's not the only segment that might have "opened" that
486
+ # subtree (eg, Summary Table in 835 can begin with PLB or SE)
487
+ # then maybe the segment we're looking for comes *after* the
488
+ # first segment in this subtree.
489
+ single = op.push.nil?
490
+ single ||= op.segment_use.nil?
491
+ single ||= 1 >= zipper.node.instructions.instructions.count do |x|
492
+ x.push.present? and
493
+ (# This is hairy, but we know the instruction is pushing some
494
+ # number of nested subtrees. We know from each AbstractState
495
+ # subclass that we both either push a single subtree
496
+ op.segment_use.parent.eql?(x.segment_use.try(:parent)) or
497
+ # Or this instruction pushes one subtree while the other one
498
+ # pushes two (eg, a new loop inside of a table)
499
+ op.segment_use.parent.eql?(x.segment_use.try(:parent).try(:parent)) or
500
+ # Or this instruction pushes two subtrees (eg, a new loop in
501
+ # a new table) and the other also pushes two subtrees.
502
+ op.segment_use.parent.parent.eql?(x.segment_use.try(:parent)))
503
+ end
504
+
505
+ unless _value.node.segment?
506
+ _value = _value.down
507
+ _state = _state.down
508
+ end
509
+
510
+ while true
511
+ __value = _value
512
+ __state = _state
513
+
514
+ # Descend to the first segment
515
+ until __value.node.segment?
516
+ __value = __value.down
517
+ __state = __state.down
518
+ end
519
+
520
+ matched =
521
+ if __value.node.invalid?
522
+ invalid and not __filter?(filter_tok, __value.node)
523
+ else
524
+ # Note op.segment_use.nil? is true when searching for ISA,
525
+ # GS, and ST, because we can't know the SegmentUse until we
526
+ # deconstruct the token and looked up the versions numbers
527
+ # in the Config.
528
+ (op.segment_use.nil? or op.segment_use.eql?(__value.node.usage)) \
529
+ and not filter?(filter_tok, __value.node)
530
+ end
531
+
532
+ # 4. Stop on a segment
533
+ if matched
534
+ unless __value.eql?(__state.node.zipper)
535
+ __state = __state.replace(__state.node.copy(:zipper => __value))
536
+ end
537
+
538
+ matches << __state
539
+ break
540
+ end
541
+
542
+ break if single
543
+ break if _value.last?
544
+
545
+ _value = _value.next
546
+ _state = _state.next
547
+ end
548
+
549
+ # 4. Stop on a segment
550
+ break if matched
551
+
552
+ elsif target.length > state.node.instructions.length
553
+ # The ancestor state can't be one of the rightward siblings,
554
+ # since the length of instruction tables is non-increasing as
555
+ # we move rightward
556
+ break
557
+ end
558
+ end
559
+ end
560
+ end
561
+
562
+ if not reachable
563
+ raise Exceptions::ParseError,
564
+ "#{id} segment cannot be reached from the current state"
565
+ elsif matches.empty?
566
+ Either.failure("#{id}(#{elements.map(&:inspect).join(", ")}) segment does not occur")
567
+ else
568
+ Either.success(StateMachine.new(@config, matches))
569
+ end
570
+ end
571
+
572
+ # Returns true if the constraints modeled in `filter_tok` are not
573
+ # satisfied by the given `segment_val`, otherwise returns false.
574
+ def filter?(filter_tok, segment_val)
575
+ return true unless filter_tok.id == segment_val.id
576
+
577
+ filter_tok.element_toks.zip(segment_val.children) do |f_tok, e_val|
578
+ if f_tok.simple?
579
+ return true unless f_tok.blank? or e_val == f_tok.value
580
+ elsif f_tok.composite?
581
+ f_tok.component_toks.zip(e_val.children) do |c_tok, c_val|
582
+ return true unless c_tok.blank? or c_val == c_tok.value
583
+ end
584
+ elsif f_tok.present?
585
+ raise Exceptions::ParseError,
586
+ "only simple and component elements can be filtered"
587
+ end
588
+ end
589
+
590
+ false
591
+ end
592
+
593
+ # Returns true if the constraints modeled in `filter_tok` are not
594
+ # satisfied by the given `invalid_val`, otherwise returns false.
595
+ def __filter?(filter_tok, invalid_val)
596
+ return true unless filter_tok.id == invalid_val.id
597
+
598
+ children = invalid_val.segment_tok.element_toks
599
+ filter_tok.element_toks.zip(children) do |f_tok, e_tok|
600
+ if f_tok.simple?
601
+ return true unless f_tok.blank? or f_tok.value == e_tok.value
602
+ elsif f_tok.composite?
603
+ children = e_tok.component_toks
604
+ f_tok.component_toks.zip(children) do |f_com, e_com|
605
+ return true unless f_com.blank? or f_com.value == e_com.value
606
+ end
607
+ elsif f_tok.present?
608
+ raise Exceptions::ParseError,
609
+ "only simple and component elements can be filtered"
610
+ end
611
+ end
612
+
613
+ false
614
+ end
615
+
616
+ # @return [Integer]
617
+ def __count(invalid, id, elements)
618
+ cursor = __find(invalid, id, elements)
619
+ count = 0
620
+
621
+ while cursor.defined?
622
+ count += 1
623
+ cursor = cursor.flatmap{|c| c.send(:__find, invalid, id, elements) }
624
+ end
625
+
626
+ count
627
+ end
628
+
629
+ # Returns the cursor positioned at the root of the parse tree linked
630
+ # from each state.
631
+ #
632
+ # @return [Array<Zipper::RootCursor>]
633
+ def roots
634
+ @active.map do |zipper|
635
+ state = zipper
636
+ value = zipper.node.zipper
637
+
638
+ zipper.depth.times do
639
+ value = value.up
640
+ state = state.up
641
+ end
642
+
643
+ # Synchronize the two parallel state and value nodes
644
+ unless value.eql?(state.node.zipper)
645
+ state = state.replace(state.node.copy(:zipper => value))
646
+ end
647
+
648
+ state
649
+ end
650
+ end
651
+
652
+ end
653
+
654
+ end
655
+ end
@@ -0,0 +1,55 @@
1
+ module Stupidedi
2
+ module Builder
3
+
4
+ class StateMachine
5
+ include Inspect
6
+ include Navigation
7
+ include Generation
8
+ include Tokenization
9
+
10
+ # @return [Config]
11
+ attr_reader :config
12
+
13
+ # @return [Array<Zipper::AbstractCursor>]
14
+ attr_reader :active
15
+
16
+ def initialize(config, active)
17
+ @config, @active = config, active
18
+ end
19
+
20
+ # @return [Reader::Separators]
21
+ def separators
22
+ @active.head.node.separators
23
+ end
24
+
25
+ # @return [void]
26
+ def pretty_print(q)
27
+ q.text "StateMachine[#{@active.length}]"
28
+ q.group 2, "(", ")" do
29
+ q.breakable ""
30
+ @active.each do |s|
31
+ unless q.current_group.first?
32
+ q.text ","
33
+ q.breakable
34
+ end
35
+ q.pp s.node.zipper.node
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ class << StateMachine
42
+ # @group Constructors
43
+ #########################################################################
44
+
45
+ # @return [StateMachine]
46
+ def build(config)
47
+ StateMachine.new(config, InitialState.start.cons)
48
+ end
49
+
50
+ # @endgroup
51
+ #########################################################################
52
+ end
53
+
54
+ end
55
+ end