tediparse 2.0.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 (176) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +319 -0
  3. data/LICENSE +26 -0
  4. data/README.md +308 -0
  5. data/Rakefile +33 -0
  6. data/bin/tediparse +102 -0
  7. data/doc/Defining.md +97 -0
  8. data/doc/Generating-Grammars.md +241 -0
  9. data/doc/Generating.md +332 -0
  10. data/doc/Navigating.md +670 -0
  11. data/doc/Parsing.md +133 -0
  12. data/doc/README.md +51 -0
  13. data/doc/Serializing.md +100 -0
  14. data/doc/Tokenizing.md +136 -0
  15. data/doc/Validating.md +140 -0
  16. data/lib/ruby/array.rb +226 -0
  17. data/lib/ruby/blank.rb +52 -0
  18. data/lib/ruby/exception.rb +14 -0
  19. data/lib/ruby/hash.rb +14 -0
  20. data/lib/ruby/module.rb +60 -0
  21. data/lib/ruby/object.rb +56 -0
  22. data/lib/ruby/string.rb +89 -0
  23. data/lib/ruby/to_d.rb +82 -0
  24. data/lib/ruby/to_date.rb +26 -0
  25. data/lib/ruby/to_time.rb +21 -0
  26. data/lib/ruby/try.rb +46 -0
  27. data/lib/stupidedi/builder.rb +6 -0
  28. data/lib/stupidedi/color.rb +94 -0
  29. data/lib/stupidedi/config/code_list_config.rb +45 -0
  30. data/lib/stupidedi/config/functional_group_config.rb +72 -0
  31. data/lib/stupidedi/config/interchange_config.rb +86 -0
  32. data/lib/stupidedi/config/transaction_set_config.rb +73 -0
  33. data/lib/stupidedi/config.rb +100 -0
  34. data/lib/stupidedi/either.rb +286 -0
  35. data/lib/stupidedi/exceptions/invalid_element_error.rb +7 -0
  36. data/lib/stupidedi/exceptions/invalid_schema_error.rb +7 -0
  37. data/lib/stupidedi/exceptions/missing_grammar_error.rb +50 -0
  38. data/lib/stupidedi/exceptions/output_error.rb +7 -0
  39. data/lib/stupidedi/exceptions/parse_error.rb +7 -0
  40. data/lib/stupidedi/exceptions/stupidedi_error.rb +7 -0
  41. data/lib/stupidedi/exceptions/tokenize_error.rb +7 -0
  42. data/lib/stupidedi/exceptions/zipper_error.rb +7 -0
  43. data/lib/stupidedi/exceptions.rb +13 -0
  44. data/lib/stupidedi/inspect.rb +26 -0
  45. data/lib/stupidedi/interchanges/element_types/separator_val.rb +79 -0
  46. data/lib/stupidedi/interchanges/element_types/special_val.rb +48 -0
  47. data/lib/stupidedi/interchanges/element_types.rb +11 -0
  48. data/lib/stupidedi/interchanges.rb +21 -0
  49. data/lib/stupidedi/parser/builder_dsl.rb +292 -0
  50. data/lib/stupidedi/parser/constraint_table.rb +566 -0
  51. data/lib/stupidedi/parser/generation.rb +147 -0
  52. data/lib/stupidedi/parser/identifier_stack.rb +248 -0
  53. data/lib/stupidedi/parser/instruction.rb +112 -0
  54. data/lib/stupidedi/parser/instruction_table.rb +222 -0
  55. data/lib/stupidedi/parser/navigation.rb +786 -0
  56. data/lib/stupidedi/parser/state_machine.rb +62 -0
  57. data/lib/stupidedi/parser/states/abstract_state.rb +385 -0
  58. data/lib/stupidedi/parser/states/failure_state.rb +69 -0
  59. data/lib/stupidedi/parser/states/functional_group_state.rb +101 -0
  60. data/lib/stupidedi/parser/states/initial_state.rb +62 -0
  61. data/lib/stupidedi/parser/states/interchange_state.rb +96 -0
  62. data/lib/stupidedi/parser/states/loop_state.rb +74 -0
  63. data/lib/stupidedi/parser/states/table_state.rb +90 -0
  64. data/lib/stupidedi/parser/states/transaction_set_state.rb +120 -0
  65. data/lib/stupidedi/parser/states/transmission_state.rb +59 -0
  66. data/lib/stupidedi/parser/tokenization.rb +195 -0
  67. data/lib/stupidedi/parser.rb +32 -0
  68. data/lib/stupidedi/reader/input/abstract_input.rb +137 -0
  69. data/lib/stupidedi/reader/input/delegated_input.rb +112 -0
  70. data/lib/stupidedi/reader/input/file_input.rb +157 -0
  71. data/lib/stupidedi/reader/input.rb +31 -0
  72. data/lib/stupidedi/reader/position.rb +78 -0
  73. data/lib/stupidedi/reader/result.rb +172 -0
  74. data/lib/stupidedi/reader/segment_dict.rb +176 -0
  75. data/lib/stupidedi/reader/separators.rb +90 -0
  76. data/lib/stupidedi/reader/stream_reader.rb +173 -0
  77. data/lib/stupidedi/reader/token_reader.rb +465 -0
  78. data/lib/stupidedi/reader/tokens/component_element_tok.rb +71 -0
  79. data/lib/stupidedi/reader/tokens/composite_element_tok.rb +85 -0
  80. data/lib/stupidedi/reader/tokens/repeated_element_tok.rb +74 -0
  81. data/lib/stupidedi/reader/tokens/segment_tok.rb +74 -0
  82. data/lib/stupidedi/reader/tokens/simple_element_tok.rb +76 -0
  83. data/lib/stupidedi/reader.rb +121 -0
  84. data/lib/stupidedi/schema/abstract_def.rb +76 -0
  85. data/lib/stupidedi/schema/abstract_element_def.rb +35 -0
  86. data/lib/stupidedi/schema/abstract_element_use.rb +47 -0
  87. data/lib/stupidedi/schema/abstract_use.rb +79 -0
  88. data/lib/stupidedi/schema/code_list.rb +99 -0
  89. data/lib/stupidedi/schema/component_element_use.rb +76 -0
  90. data/lib/stupidedi/schema/composite_element_def.rb +103 -0
  91. data/lib/stupidedi/schema/composite_element_use.rb +78 -0
  92. data/lib/stupidedi/schema/element_req.rb +57 -0
  93. data/lib/stupidedi/schema/functional_group_def.rb +124 -0
  94. data/lib/stupidedi/schema/generation/definition_generator.rb +139 -0
  95. data/lib/stupidedi/schema/generation/element_generator.rb +221 -0
  96. data/lib/stupidedi/schema/generation/flat_file_reader.rb +551 -0
  97. data/lib/stupidedi/schema/generation/functional_group_generator.rb +64 -0
  98. data/lib/stupidedi/schema/generation/interchange_generator.rb +145 -0
  99. data/lib/stupidedi/schema/generation/master_loader_generator.rb +121 -0
  100. data/lib/stupidedi/schema/generation/models.rb +85 -0
  101. data/lib/stupidedi/schema/generation/module_loader_generator.rb +64 -0
  102. data/lib/stupidedi/schema/generation/registration_generator.rb +230 -0
  103. data/lib/stupidedi/schema/generation/runner.rb +161 -0
  104. data/lib/stupidedi/schema/generation/segment_generator.rb +130 -0
  105. data/lib/stupidedi/schema/generation/support.rb +78 -0
  106. data/lib/stupidedi/schema/generation/support_modules_generator.rb +126 -0
  107. data/lib/stupidedi/schema/generation/version_modules.rb +35 -0
  108. data/lib/stupidedi/schema/generation.rb +94 -0
  109. data/lib/stupidedi/schema/interchange_def.rb +103 -0
  110. data/lib/stupidedi/schema/loop_def.rb +156 -0
  111. data/lib/stupidedi/schema/repeat_count.rb +86 -0
  112. data/lib/stupidedi/schema/segment_def.rb +122 -0
  113. data/lib/stupidedi/schema/segment_req.rb +46 -0
  114. data/lib/stupidedi/schema/segment_use.rb +99 -0
  115. data/lib/stupidedi/schema/simple_element_def.rb +51 -0
  116. data/lib/stupidedi/schema/simple_element_use.rb +83 -0
  117. data/lib/stupidedi/schema/syntax_note.rb +52 -0
  118. data/lib/stupidedi/schema/table_def.rb +178 -0
  119. data/lib/stupidedi/schema/transaction_set_def.rb +125 -0
  120. data/lib/stupidedi/schema.rb +30 -0
  121. data/lib/stupidedi/sets.rb +42 -0
  122. data/lib/stupidedi/transaction_sets/builder/dsl.rb +192 -0
  123. data/lib/stupidedi/transaction_sets/builder.rb +188 -0
  124. data/lib/stupidedi/transaction_sets/common/implementations/element_reqs.rb +37 -0
  125. data/lib/stupidedi/transaction_sets/common/implementations/segment_reqs.rb +31 -0
  126. data/lib/stupidedi/transaction_sets/common/implementations.rb +11 -0
  127. data/lib/stupidedi/transaction_sets/common.rb +8 -0
  128. data/lib/stupidedi/transaction_sets/validation/ambiguity.rb +395 -0
  129. data/lib/stupidedi/transaction_sets/validation/implementation.rb +12 -0
  130. data/lib/stupidedi/transaction_sets/validation.rb +9 -0
  131. data/lib/stupidedi/transaction_sets.rb +25 -0
  132. data/lib/stupidedi/values/abstract_element_val.rb +19 -0
  133. data/lib/stupidedi/values/abstract_val.rb +133 -0
  134. data/lib/stupidedi/values/composite_element_val.rb +102 -0
  135. data/lib/stupidedi/values/functional_group_val.rb +105 -0
  136. data/lib/stupidedi/values/interchange_val.rb +102 -0
  137. data/lib/stupidedi/values/invalid_envelope_val.rb +61 -0
  138. data/lib/stupidedi/values/invalid_segment_val.rb +89 -0
  139. data/lib/stupidedi/values/loop_val.rb +73 -0
  140. data/lib/stupidedi/values/repeated_element_val.rb +113 -0
  141. data/lib/stupidedi/values/segment_val.rb +105 -0
  142. data/lib/stupidedi/values/segment_val_group.rb +20 -0
  143. data/lib/stupidedi/values/simple_element_val.rb +80 -0
  144. data/lib/stupidedi/values/table_val.rb +69 -0
  145. data/lib/stupidedi/values/transaction_set_val.rb +69 -0
  146. data/lib/stupidedi/values/transmission_val.rb +56 -0
  147. data/lib/stupidedi/values.rb +22 -0
  148. data/lib/stupidedi/version.rb +4 -0
  149. data/lib/stupidedi/versions/common/element_reqs.rb +13 -0
  150. data/lib/stupidedi/versions/common/element_types/an.rb +386 -0
  151. data/lib/stupidedi/versions/common/element_types/dt.rb +572 -0
  152. data/lib/stupidedi/versions/common/element_types/id.rb +304 -0
  153. data/lib/stupidedi/versions/common/element_types/nn.rb +312 -0
  154. data/lib/stupidedi/versions/common/element_types/operators.rb +128 -0
  155. data/lib/stupidedi/versions/common/element_types/r.rb +342 -0
  156. data/lib/stupidedi/versions/common/element_types/simple_element.rb +73 -0
  157. data/lib/stupidedi/versions/common/element_types/tm.rb +347 -0
  158. data/lib/stupidedi/versions/common/element_types.rb +29 -0
  159. data/lib/stupidedi/versions/common/segment_reqs.rb +15 -0
  160. data/lib/stupidedi/versions/common/syntax_notes.rb +172 -0
  161. data/lib/stupidedi/versions/common.rb +11 -0
  162. data/lib/stupidedi/versions.rb +25 -0
  163. data/lib/stupidedi/writer/claredi.rb +178 -0
  164. data/lib/stupidedi/writer/default.rb +119 -0
  165. data/lib/stupidedi/writer.rb +7 -0
  166. data/lib/stupidedi/zipper/abstract_cursor.rb +351 -0
  167. data/lib/stupidedi/zipper/dangling_cursor.rb +103 -0
  168. data/lib/stupidedi/zipper/edited_cursor.rb +157 -0
  169. data/lib/stupidedi/zipper/memoized_cursor.rb +133 -0
  170. data/lib/stupidedi/zipper/path.rb +132 -0
  171. data/lib/stupidedi/zipper/root_cursor.rb +120 -0
  172. data/lib/stupidedi/zipper/stack_cursor.rb +107 -0
  173. data/lib/stupidedi/zipper.rb +45 -0
  174. data/lib/stupidedi.rb +69 -0
  175. data/lib/tediparse.rb +1 -0
  176. metadata +249 -0
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class StateMachine
7
+ include Inspect
8
+ include Navigation
9
+ include Generation
10
+ include Tokenization
11
+
12
+ # @return [Config]
13
+ attr_reader :config
14
+
15
+ # @return [Array<Zipper::AbstractCursor<StateMachine::AbstractState>>]
16
+ attr_reader :active
17
+
18
+ def initialize(config, active)
19
+ @config, @active = config, active
20
+ end
21
+
22
+ def copy(changes = {})
23
+ StateMachine.new \
24
+ changes.fetch(:config, @config),
25
+ changes.fetch(:active, @active)
26
+ end
27
+
28
+ # @return [Reader::Separators]
29
+ def separators
30
+ @active.head.node.separators
31
+ end
32
+
33
+ # @return [void]
34
+ def pretty_print(q)
35
+ q.text "StateMachine[#{@active.length}]"
36
+ q.group 2, "(", ")" do
37
+ q.breakable ""
38
+ @active.each do |s|
39
+ unless q.current_group.first?
40
+ q.text ","
41
+ q.breakable
42
+ end
43
+ q.pp s.node.zipper.node
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ class << StateMachine
50
+ # @group Constructors
51
+ #########################################################################
52
+
53
+ # @return [StateMachine]
54
+ def build(config, zipper = Zipper::Tree)
55
+ StateMachine.new(config, InitialState.start(zipper).cons)
56
+ end
57
+
58
+ # @endgroup
59
+ #########################################################################
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,385 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class AbstractState
7
+ include Inspect
8
+
9
+ # @return [Reader::Separators]
10
+ abstract :separators
11
+
12
+ # @return [Reader::SegmentDict]
13
+ abstract :segment_dict
14
+
15
+ # @return [Zipper::AbstractCursor<Values::SegmentVal>]
16
+ abstract :zipper
17
+
18
+ # @return [Array<AbstractState>]
19
+ abstract :children
20
+
21
+ # @return [InstructionTable]
22
+ abstract :instructions
23
+
24
+ def leaf?
25
+ false
26
+ end
27
+
28
+ # @return [void]
29
+ def pretty_print(q)
30
+ q.text self.class.name.split("::").last
31
+ q.group(2, "(", ")") do
32
+ q.breakable ""
33
+
34
+ children.each do |e|
35
+ unless q.current_group.first?
36
+ q.text ","
37
+ q.breakable
38
+ end
39
+ q.pp e
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ class << AbstractState
46
+ # @group Constructors
47
+ #########################################################################
48
+
49
+ # @return [Zipper::AbstractCursor]
50
+ abstract :push, :args => %w(zipper parent segment_tok segment_use config)
51
+
52
+ # @group SegmentVal Construction
53
+ #########################################################################
54
+
55
+ # @return [Values::SegmentVal]
56
+ def mksegment(segment_tok, segment_use)
57
+ segment_def = segment_use.definition
58
+ element_uses = segment_def.element_uses
59
+ element_toks = segment_tok.element_toks
60
+
61
+ position = segment_tok.position
62
+ element_vals = []
63
+ element_idx = "00"
64
+ element_uses.zip(element_toks) do |element_use, element_tok|
65
+ element_idx = element_idx.succ
66
+ position = element_tok.position if element_tok
67
+
68
+ element_vals <<
69
+ if element_tok.nil?
70
+ if element_use.repeatable?
71
+ Values::RepeatedElementVal.empty(element_use)
72
+ else
73
+ element_use.empty(position)
74
+ end
75
+ else
76
+ mkelement("#{segment_def.id}#{element_idx}", element_use, element_tok)
77
+ end
78
+ end
79
+
80
+ segment_use.value(element_vals, segment_tok.position)
81
+ end
82
+
83
+ # @return [Values::SimpleElementVal, Values::CompositeElementVal, Values::RepeatedElementVal]
84
+ def mkelement(designator, element_use, element_tok)
85
+ if element_use.simple?
86
+ if element_use.repeatable?
87
+ element_toks = element_tok.element_toks
88
+ element_vals = element_toks.map do |element_tok1|
89
+ mksimple(designator, element_use, element_tok1)
90
+ end
91
+
92
+ mkrepeated(designator, element_use, element_vals)
93
+ else
94
+ mksimple(designator, element_use, element_tok)
95
+ end
96
+ else
97
+ if element_use.repeatable?
98
+ element_toks = element_tok.element_toks
99
+ element_vals = element_toks.map do |element_tok1|
100
+ mkcomposite(designator, element_use, element_tok1)
101
+ end
102
+
103
+ mkrepeated(designator, element_use, element_vals)
104
+ else
105
+ mkcomposite(designator, element_use, element_tok)
106
+ end
107
+ end
108
+ end
109
+
110
+ # @return [Values::RepeatedElementVal]
111
+ def mkrepeated(designator, element_use, element_vals)
112
+ # @todo: Position
113
+ Values::RepeatedElementVal.build(element_vals, element_use)
114
+ end
115
+
116
+ # @return [Values::CompositeElementVal]
117
+ def mkcomposite(designator, composite_use, composite_tok)
118
+ composite_def = composite_use.definition
119
+ component_uses = composite_def.component_uses
120
+ component_toks = composite_tok.component_toks
121
+
122
+ position = composite_tok.position
123
+ component_vals = []
124
+ component_idx = "00"
125
+ component_uses.zip(component_toks) do |component_use, component_tok|
126
+ component_idx = component_idx.succ
127
+ position = component_tok.position if component_tok
128
+
129
+ component_vals <<
130
+ if component_tok.nil?
131
+ component_use.empty(position)
132
+ else
133
+ mksimple("#{designator}-#{component_idx}", component_use, component_tok)
134
+ end
135
+ end
136
+
137
+ composite_use.value(component_vals, composite_tok.position)
138
+ end
139
+
140
+ # @return [Values::SimpleElementVal]
141
+ def mksimple(designator, element_use, element_tok)
142
+ # We don't validate that element_tok is simple because the TokenReader
143
+ # will always produce a SimpleElementTok given a SimpleElementUse from
144
+ # the SegmentDef. On the other hand, the BuilderDsl API will throw an
145
+ # exception if the programmer constructs the wrong kind of element
146
+ # according to the SegmentDef.
147
+
148
+ if element_tok.value == :default
149
+ allowed_vals = element_use.allowed_values
150
+
151
+ if element_use.requirement.forbidden?
152
+ element_use.empty(element_tok.position)
153
+ elsif allowed_vals.empty?
154
+ element_use.empty(element_tok.position)
155
+ elsif allowed_vals.size == 1
156
+ element_use.value(allowed_vals.first, element_tok.position)
157
+ else
158
+ raise Exceptions::ParseError,
159
+ "#{designator} cannot be inferred"
160
+ end
161
+ elsif element_tok.value == :not_used
162
+ if element_use.requirement.forbidden?
163
+ element_use.empty(element_tok.position)
164
+ else
165
+ raise Exceptions::ParseError,
166
+ "#{designator} is not forbidden"
167
+ end
168
+ elsif element_tok.value == :blank
169
+ element_use.empty(element_tok.position)
170
+ else
171
+ element_use.value(element_tok.value, element_tok.position)
172
+ end
173
+ end
174
+
175
+ # @group Instruction Generation
176
+ #########################################################################
177
+
178
+ # Builds a sequence of {Instruction} values that corresponds to the given
179
+ # sequence of `segment_uses`
180
+ #
181
+ # @return [Array<Instruction>]
182
+ def sequence(segment_uses, offset = 0)
183
+ instructions = []
184
+ buffer = []
185
+ last = nil
186
+
187
+ segment_uses.each do |s|
188
+ unless last.nil? or s.position == last.position
189
+ drop_count =
190
+ if buffer.length == 1 and not last.repeatable?
191
+ offset
192
+ else
193
+ offset - buffer.length
194
+ end
195
+
196
+ buffer.each do |u|
197
+ instructions << Instruction.new(nil, u, 0, drop_count, nil)
198
+ end
199
+
200
+ buffer.clear
201
+ end
202
+
203
+ buffer << s
204
+ last = s
205
+ offset += 1
206
+ end
207
+
208
+ # Flush the buffer one last time
209
+ unless buffer.empty?
210
+ drop_count =
211
+ if buffer.length == 1 and not last.repeatable?
212
+ offset
213
+ else
214
+ offset - buffer.length
215
+ end
216
+
217
+ buffer.each do |u|
218
+ instructions << Instruction.new(nil, u, 0, drop_count, nil)
219
+ end
220
+ end
221
+
222
+ instructions
223
+ end
224
+
225
+ # Builds a sequence of {Instruction} values that corresponds to the given
226
+ # sequence of `loop_defs`
227
+ #
228
+ # @deprecated Use {#interleaved_sequence} instead, which handles mixed
229
+ # SegmentUse and LoopDef children.
230
+ # @return [Array<Instruction>]
231
+ def lsequence(loop_defs, offset = 0)
232
+ instructions = []
233
+ buffer = []
234
+ last = nil
235
+
236
+ loop_defs.each do |l|
237
+ unless last.nil? or l.entry_segment_use.position == last.entry_segment_use.position
238
+ drop_count =
239
+ if buffer.length == 1 and not last.repeatable?
240
+ offset
241
+ else
242
+ offset - buffer.length
243
+ end
244
+
245
+ buffer.each do |u|
246
+ instructions << Instruction.new(nil, u, 0, drop_count, LoopState)
247
+ end
248
+ buffer.clear
249
+ end
250
+
251
+ buffer << l.entry_segment_use
252
+ last = l
253
+ offset += 1
254
+ end
255
+
256
+ # Flush the buffer one last time
257
+ unless buffer.nil?
258
+ drop_count =
259
+ if buffer.length == 1 and not last.repeatable?
260
+ offset
261
+ else
262
+ offset - buffer.length
263
+ end
264
+
265
+ buffer.each do |u|
266
+ instructions << Instruction.new(nil, u, 0, drop_count, LoopState)
267
+ end
268
+ end
269
+
270
+ instructions
271
+ end
272
+
273
+ # Builds a sequence of {Instruction} values that corresponds to a mixed
274
+ # sequence of SegmentUse and LoopDef children (supporting interleaved patterns).
275
+ #
276
+ # @param children [Array<Schema::SegmentUse, Schema::LoopDef>]
277
+ # @param offset [Integer]
278
+ # @param skip_first [Boolean] if true, skip the first child (for non-repeatable entry segments)
279
+ # @return [Array<Instruction>]
280
+ def interleaved_sequence(children, offset = 0, skip_first: false)
281
+ children = children.drop(1) if skip_first
282
+
283
+ instructions = []
284
+ buffer = []
285
+ last_pos = nil
286
+
287
+ children.each do |child|
288
+ current_pos = child.is_a?(Schema::SegmentUse) ? child.position : child.entry_segment_use.position
289
+ is_repeatable = child.is_a?(Schema::SegmentUse) ? child.repeatable? : child.repeatable?
290
+
291
+ unless last_pos.nil? or current_pos == last_pos
292
+ drop_count =
293
+ if buffer.length == 1 and not buffer.first[:repeatable]
294
+ offset
295
+ else
296
+ offset - buffer.length
297
+ end
298
+
299
+ buffer.each do |item|
300
+ instructions << Instruction.new(nil, item[:segment_use], 0, drop_count, item[:push])
301
+ end
302
+
303
+ buffer.clear
304
+ end
305
+
306
+ segment_use = child.is_a?(Schema::SegmentUse) ? child : child.entry_segment_use
307
+ push_state = child.is_a?(Schema::SegmentUse) ? nil : LoopState
308
+
309
+ buffer << { segment_use: segment_use, push: push_state, repeatable: is_repeatable }
310
+ last_pos = current_pos
311
+ offset += 1
312
+ end
313
+
314
+ # Flush the buffer one last time
315
+ unless buffer.empty?
316
+ drop_count =
317
+ if buffer.length == 1 and not buffer.first[:repeatable]
318
+ offset
319
+ else
320
+ offset - buffer.length
321
+ end
322
+
323
+ buffer.each do |item|
324
+ instructions << Instruction.new(nil, item[:segment_use], 0, drop_count, item[:push])
325
+ end
326
+ end
327
+
328
+ instructions
329
+ end
330
+
331
+ # Builds a sequence of {Instruction} values that corresponds to the given
332
+ # sequence of `table_defs`
333
+ #
334
+ # @return [Array<Instruction>]
335
+ def tsequence(table_defs, offset = 0)
336
+ instructions = []
337
+ buffer = []
338
+ last = nil
339
+
340
+ table_defs.each do |t|
341
+ unless last.nil? or t.position == last.position
342
+ drop_count =
343
+ if buffer.length == 1 and not last.repeatable?
344
+ offset
345
+ else
346
+ offset - buffer.inject(0){|n,b| n + b.entry_segment_uses.length }
347
+ end
348
+
349
+ buffer.each do |b|
350
+ b.entry_segment_uses.each do |u|
351
+ instructions << Instruction.new(nil, u, 0, drop_count, TableState)
352
+ end
353
+ end
354
+
355
+ buffer.clear
356
+ end
357
+
358
+ last = t
359
+ offset += t.entry_segment_uses.length
360
+ buffer << t
361
+ end
362
+
363
+ unless buffer.empty?
364
+ drop_count =
365
+ if buffer.length == 1 and not last.repeatable?
366
+ offset
367
+ else
368
+ offset - buffer.inject(0){|n,b| n + b.entry_segment_uses.length }
369
+ end
370
+
371
+ buffer.each do |b|
372
+ b.entry_segment_uses.each do |u|
373
+ instructions << Instruction.new(nil, u, 0, drop_count, TableState)
374
+ end
375
+ end
376
+ end
377
+
378
+ instructions
379
+ end
380
+
381
+ # @endgroup
382
+ #########################################################################
383
+ end
384
+ end
385
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class FailureState < AbstractState
7
+ # @return [Reader::Separators]
8
+ attr_reader :separators
9
+
10
+ # @return [Reader::SegmentDict]
11
+ attr_reader :segment_dict
12
+
13
+ # @return [Zipper::AbstractCursor]
14
+ attr_reader :zipper
15
+
16
+ # @return [InstructionTable]
17
+ attr_reader :instructions
18
+
19
+ # @return [Array<FailureState>]
20
+ attr_reader :children
21
+
22
+ def initialize(separators, segment_dict, instructions, zipper, children)
23
+ @separators, @segment_dict, @instructions, @zipper, @children =
24
+ separators, segment_dict, instructions, zipper, children
25
+ end
26
+
27
+ def copy(changes = {})
28
+ FailureState.new \
29
+ changes.fetch(:separators, @separators),
30
+ changes.fetch(:segment_dict, @segment_dict),
31
+ changes.fetch(:instructions, @instructions),
32
+ changes.fetch(:zipper, @zipper),
33
+ changes.fetch(:children, @children)
34
+ end
35
+ end
36
+
37
+ class << FailureState
38
+ # @group Constructors
39
+ #########################################################################
40
+
41
+ # @return [Zipper::AbstractCursor]
42
+ def push(zipper, parent, segment_tok, reason)
43
+ envelope_val = Values::InvalidEnvelopeVal.new([])
44
+ segment_val = Values::InvalidSegmentVal.new(reason, segment_tok, parent.separators)
45
+
46
+ zipper.append_child new(
47
+ parent.separators,
48
+ parent.segment_dict,
49
+ parent.instructions.push([]),
50
+ parent.zipper.append(envelope_val).append_child(segment_val),
51
+ [])
52
+ end
53
+
54
+ def mksegment(segment_tok, parent)
55
+ segment_val = Values::InvalidSegmentVal.new \
56
+ "cannot occur here", segment_tok, parent.separators
57
+
58
+ new(parent.separators,
59
+ parent.segment_dict,
60
+ parent.instructions,
61
+ parent.zipper.append(segment_val),
62
+ [])
63
+ end
64
+
65
+ # @endgroup
66
+ #########################################################################
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class FunctionalGroupState < AbstractState
7
+ # @return [Reader::Separators]
8
+ attr_reader :separators
9
+
10
+ # @return [Reader::SegmentDict]
11
+ attr_reader :segment_dict
12
+
13
+ # @return [InstructionTable]
14
+ attr_reader :instructions
15
+
16
+ # @return [Zipper::AbstractCursor]
17
+ attr_reader :zipper
18
+
19
+ # @return [Array<AbstractState>]
20
+ attr_reader :children
21
+
22
+ # GS01: Functional Identifier Code
23
+ # @return [String]
24
+ attr_reader :gs01
25
+
26
+ # GS08: Version / Release / Industry Identifier Code
27
+ # @return [String]
28
+ attr_reader :gs08
29
+
30
+ def initialize(separators, segment_dict, instructions, zipper, children, gs01, gs08)
31
+ @separators, @segment_dict, @instructions, @zipper, @children, @gs01, @gs08 =
32
+ separators, segment_dict, instructions, zipper, children, gs01, gs08
33
+ end
34
+
35
+ # @return [FunctionalGroupState]
36
+ def copy(changes = {})
37
+ FunctionalGroupState.new \
38
+ changes.fetch(:separators, @separators),
39
+ changes.fetch(:segment_dict, @segment_dict),
40
+ changes.fetch(:instructions, @instructions),
41
+ changes.fetch(:zipper, @zipper),
42
+ changes.fetch(:children, @children),
43
+ changes.fetch(:gs01, @gs01),
44
+ changes.fetch(:gs08, @gs08)
45
+ end
46
+ end
47
+
48
+ class << FunctionalGroupState
49
+ # @group Constructors
50
+ #########################################################################
51
+
52
+ # @return [Zipper::AbstractCursor]
53
+ def push(zipper, parent, segment_tok, segment_use, config)
54
+ # GS08: Version / Release / Industry Identifier Code
55
+ gs08 = segment_tok.element_toks.at(7).try(:value)
56
+ gs08_version = gs08.try(:slice, 0, 6)
57
+
58
+ # GS01: Functional Identifier Code
59
+ gs01 = segment_tok.element_toks.at(0).try(:value)
60
+
61
+ unless config.functional_group.defined_at?(gs08_version)
62
+ reason =
63
+ if config.functional_group.empty?
64
+ Stupidedi::Exceptions::MissingGrammarError::DEFAULT_MESSAGE
65
+ else
66
+ "unknown functional group version #{gs08_version.inspect}"
67
+ end
68
+
69
+ return FailureState.push(zipper, parent, segment_tok, reason)
70
+ end
71
+
72
+ envelope_def = config.functional_group.at(gs08_version)
73
+ envelope_val = envelope_def.empty
74
+ segment_use = envelope_def.entry_segment_use
75
+ segment_val = mksegment(segment_tok, segment_use)
76
+
77
+ zipper.append_child new(
78
+ parent.separators,
79
+ parent.segment_dict.push(envelope_val.segment_dict),
80
+ parent.instructions.push(instructions(envelope_def)),
81
+ parent.zipper.append(envelope_val).append_child(segment_val),
82
+ [], gs01, gs08)
83
+ end
84
+
85
+ # @endgroup
86
+ #########################################################################
87
+
88
+ private
89
+
90
+ # @return [Array<Instruction>]
91
+ def instructions(functional_group_def)
92
+ @__instructions ||= Hash.new
93
+ @__instructions[functional_group_def] ||= begin
94
+ is = sequence(functional_group_def.header_segment_uses.tail)
95
+ is << Instruction.new(:ST, nil, 0, is.length, TransactionSetState)
96
+ is.concat(sequence(functional_group_def.trailer_segment_uses, is.length))
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class InitialState < AbstractState
7
+ # @return [Reader::Separators]
8
+ attr_reader :separators
9
+
10
+ # @return [Reader::SegmentDict]
11
+ attr_reader :segment_dict
12
+
13
+ # @return [InstructionTable]
14
+ attr_reader :instructions
15
+
16
+ # @return [Zipper::AbstractCursor]
17
+ attr_reader :zipper
18
+
19
+ # @return [Array<AbstractState>]
20
+ attr_reader :children
21
+
22
+ def initialize(separators, segment_dict, instructions, zipper, children)
23
+ @separators, @segment_dict, @instructions, @zipper, @children =
24
+ separators, segment_dict, instructions, zipper, children
25
+ end
26
+
27
+ # @return [InitialState]
28
+ def copy(changes = {})
29
+ InitialState.new \
30
+ changes.fetch(:separators, @separators),
31
+ changes.fetch(:segment_dict, @segment_dict),
32
+ changes.fetch(:instructions, @instructions),
33
+ changes.fetch(:zipper, @zipper),
34
+ changes.fetch(:children, @children)
35
+ end
36
+ end
37
+
38
+ class << InitialState
39
+ # @return [InitialState]
40
+ def build(zipper)
41
+ new(
42
+ Reader::Separators.empty,
43
+ Reader::SegmentDict.empty,
44
+
45
+ InstructionTable.build(
46
+ # We initially accept only a single segment. When reading the "ISA"
47
+ # segment, we push a new InterchangeState.
48
+ Instruction.new(:ISA, nil, 0, 0, TransmissionState).cons),
49
+
50
+ # Create a new parse tree with a Transmission as the root, and descend
51
+ # to the placeholder where the first child node will be placed.
52
+ zipper.build(Values::TransmissionVal.new),
53
+ [])
54
+ end
55
+
56
+ # @return [Zipper::AbstractCursor]
57
+ def start(zipper)
58
+ zipper.build(build(zipper))
59
+ end
60
+ end
61
+ end
62
+ end