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,292 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class BuilderDsl
7
+ include Inspect
8
+ include Tokenization
9
+
10
+ # @private
11
+ SEGMENT_ID = /^[A-Z][A-Z0-9]{1,2}$/
12
+
13
+ # @return [StateMachine]
14
+ attr_reader :machine
15
+
16
+ # @return [Boolean]
17
+ attr_writer :strict
18
+
19
+ # @return [DslReader]
20
+ attr_reader :reader
21
+
22
+ def_delegators :@machine, :pretty_print, :segment, :element, :zipper, :successors, :empty?, :first?, :last?, :deterministic?
23
+
24
+ def initialize(machine, strict = true)
25
+ @machine = machine
26
+ @strict = strict
27
+ @reader = DslReader.new(Reader::Separators.empty,
28
+ Reader::SegmentDict.empty)
29
+ end
30
+
31
+ def respond_to_missing?(name, include_private = false)
32
+ SEGMENT_ID =~ name.to_s || super
33
+ end
34
+
35
+ def strict?
36
+ @strict
37
+ end
38
+
39
+ # @return [BuilderDsl]
40
+ def segment!(name, position, *elements)
41
+ segment_tok = mksegment_tok(@reader.segment_dict, name, elements, position)
42
+ machine, reader = @machine.insert(segment_tok, @strict, @reader)
43
+
44
+ if @strict
45
+ unless machine.deterministic?
46
+ matches = machine.active.map do |m|
47
+ segment_def = m.node.zipper.node.definition
48
+ "#{segment_def.id} #{segment_def.name}"
49
+ end.join(", ")
50
+
51
+ raise Exceptions::ParseError,
52
+ "non-deterministic machine state: #{matches}"
53
+ end
54
+
55
+ # Validate the new segment (recursively, including its children)
56
+ machine.active.each{|m| critique(m.node.zipper) }
57
+
58
+ # We want to detect when we've ended a syntax node (or more), like
59
+ # starting a new interchange will end all previously "open" syntax
60
+ # nodes. So we compare the state before adding `segment_tok` to the
61
+ # corresponding state after we've added `segment_tok`.
62
+
63
+ machine.prev.tap do |prev|
64
+ prev.active.zip(machine.active) do |p, q|
65
+ # If the new state `q` is a descendent of `p`, we know that `p`
66
+ # and all of its ancestors are unterminated. However, if `q` is
67
+ # not a descendent of `p`, but is a descendent of one of `p`s
68
+ # descendents, then `p` and perhaps some of its ancestors were
69
+ # terminated when the state transitioned to `q`.
70
+ qancestors = Set.new
71
+
72
+ # Operate on the syntax tree (instead of the state tree)
73
+ q = q.node.zipper
74
+ p = p.node.zipper
75
+
76
+ while q.respond_to?(:parent)
77
+ qancestors << q.parent
78
+ q = q.parent
79
+ end
80
+
81
+ while p.respond_to?(:parent)
82
+ break if qancestors.include?(p)
83
+
84
+ # Now that we're sure that this syntax node (loop, table, etc)
85
+ # is done being constructed, we can perform more validations.
86
+ critique(p)
87
+ p = p.parent
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ @machine = machine
94
+ @reader = reader
95
+
96
+ self
97
+ end
98
+
99
+ private
100
+
101
+ def method_missing(name, *args)
102
+ if SEGMENT_ID =~ name.to_s
103
+ segment!(name, Reader::Position.caller(2), *args)
104
+ else
105
+ super
106
+ end
107
+ end
108
+
109
+ # The `zipper` argument should be a _completed_ syntax node, meaning all
110
+ # children have already been added. This is invariably true for segments,
111
+ # because the {StateMachine} does not accept smaller units of syntax.
112
+ def critique(zipper, recursive = false, position = false)
113
+ if zipper.node.simple? or zipper.node.component?
114
+ if zipper.node.invalid?
115
+ raise Exceptions::ParseError,
116
+ "invalid #{zipper.node.descriptor} at #{zipper.node.position.inspect}"
117
+ elsif zipper.node.blank?
118
+ if zipper.node.usage.required?
119
+ raise Exceptions::ParseError,
120
+ "required #{zipper.node.descriptor} is blank at #{zipper.node.position.inspect}"
121
+ end
122
+ elsif zipper.node.usage.forbidden?
123
+ raise Exceptions::ParseError,
124
+ "forbidden #{zipper.node.descriptor} is present at #{zipper.node.position.inspect}"
125
+ elsif not zipper.node.allowed?
126
+ raise Exceptions::ParseError,
127
+ "value #{zipper.node.to_s} is not allowed in #{zipper.node.descriptor} at #{zipper.node.position.inspect}"
128
+ elsif zipper.node.too_long?
129
+ raise Exceptions::ParseError,
130
+ "value is too long in #{zipper.node.descriptor} at #{zipper.node.position.inspect}"
131
+ elsif zipper.node.too_short?
132
+ raise Exceptions::ParseError,
133
+ "value is too short in #{zipper.node.descriptor} at #{zipper.node.position.inspect}"
134
+ end
135
+
136
+ elsif zipper.node.composite?
137
+ if zipper.node.blank?
138
+ if zipper.node.usage.required?
139
+ # GH-194: Normally the position of a composit element is the
140
+ # position of it's first child; but an empty composit element
141
+ # doesn't have children. So the closest position is of the parent
142
+ raise Exceptions::ParseError,
143
+ "required #{zipper.node.descriptor} is blank at #{zipper.parent.node.position.inspect}"
144
+ end
145
+ elsif zipper.node.usage.forbidden?
146
+ raise Exceptions::ParseError,
147
+ "forbidden #{zipper.node.descriptor} is present at #{zipper.node.position.inspect}"
148
+ else
149
+ if zipper.node.present?
150
+ zipper.children.each_with_index do |z, i|
151
+ critique(z)
152
+ end
153
+
154
+ d = zipper.node.definition
155
+ d.syntax_notes.each do |s|
156
+ unless s.satisfied?(zipper)
157
+ raise Exceptions::ParseError,
158
+ "for #{zipper.node.descriptor}, #{s.reason(zipper)} at #{zipper.node.position.inspect}"
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ elsif zipper.node.repeated?
165
+ unless zipper.node.usage.repeat_count.include?(zipper.node.children.length)
166
+ raise Exceptions::ParseError,
167
+ "repeating #{zipper.node.descriptor} occurs too many times at #{zipper.node.position.inspect}"
168
+ end
169
+
170
+ zipper.children.each{|z| critique(z) }
171
+
172
+ elsif zipper.node.segment?
173
+ if zipper.node.invalid?
174
+ if zipper.up.node.invalid?
175
+ # parent is an InvalidEnvelopeVal
176
+ raise Exceptions::ParseError,
177
+ "#{zipper.first.node.reason} at #{zipper.first.node.position.inspect}"
178
+ else
179
+ raise Exceptions::ParseError,
180
+ "#{zipper.node.descriptor} at #{zipper.node.position.inspect}"
181
+ end
182
+ else
183
+ zipper.children.each_with_index do |z, i|
184
+ critique(z)
185
+ end
186
+
187
+ d = zipper.node.definition
188
+ d.syntax_notes.each do |s|
189
+ raise Exceptions::ParseError,
190
+ "for #{zipper.node.descriptor}, #{s.reason(zipper)} at #{zipper.node.position.inspect}" \
191
+ unless s.satisfied?(zipper)
192
+ end
193
+ end
194
+
195
+ elsif zipper.node.loop?
196
+ critique_occurences zipper, recursive
197
+
198
+ elsif zipper.node.table?
199
+ critique_occurences zipper, recursive
200
+
201
+ elsif zipper.node.transaction_set?
202
+ critique_occurences zipper, recursive
203
+
204
+ elsif zipper.node.functional_group?
205
+ critique_occurences zipper, recursive
206
+
207
+ elsif zipper.node.interchange?
208
+ critique_occurences zipper, recursive
209
+
210
+ elsif zipper.node.transmission?
211
+ if recursive
212
+ zipper.children.each_with_index do |z, i|
213
+ critique(z, recursive)
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ def critique_occurences(zipper, recursive)
220
+ occurences = Hash.new{|h,k| h[k] = 0 }
221
+
222
+ zipper.children.each do |child|
223
+ if child.node.respond_to?(:usage)
224
+ occurences[child.node.usage] += 1
225
+ elsif child.node.invalid?
226
+ raise Exceptions::ParseError,
227
+ "#{child.node.descriptor} at #{child.node.position.inspect}"
228
+ else
229
+ occurences[child.node.definition] += 1
230
+ end
231
+
232
+ if recursive
233
+ critique(child, "", recursive)
234
+ end
235
+ end
236
+
237
+ zipper.node.definition.children.each do |child|
238
+ bound = child.repeat_count
239
+ count = occurences.at(child)
240
+
241
+ if count.zero? and child.required?
242
+ raise Exceptions::ParseError,
243
+ "required #{child.descriptor} is missing from #{zipper.node.descriptor} at #{zipper.node.position.inspect}"
244
+ elsif bound < count
245
+ raise Exceptions::ParseError,
246
+ "#{child.descriptor} occurs too many times in #{zipper.node.descriptor} at #{zipper.node.position.inspect}"
247
+ end
248
+ end
249
+ end
250
+
251
+ # @endgroup
252
+ #########################################################################
253
+ end
254
+
255
+ class << BuilderDsl
256
+ # @group Constructors
257
+ #########################################################################
258
+
259
+ # @return [BuilderDsl]
260
+ def build(config, strict = true)
261
+ new(StateMachine.build(config), strict)
262
+ end
263
+
264
+ # @endgroup
265
+ #########################################################################
266
+ end
267
+
268
+ # @private
269
+ class DslReader
270
+ # @return [Reader::Separators]
271
+ attr_reader :separators
272
+
273
+ # @return [Reader::SegmentDict]
274
+ attr_reader :segment_dict
275
+
276
+ def initialize(separators, segment_dict)
277
+ @separators, @segment_dict = separators, segment_dict
278
+ end
279
+
280
+ # @return [DslReader]
281
+ def copy(changes = {})
282
+ @separators = changes.fetch(:separators, @separators)
283
+ @segment_dict = changes.fetch(:segment_dict, @segment_dict)
284
+ self
285
+ end
286
+
287
+ def stream?
288
+ false
289
+ end
290
+ end
291
+ end
292
+ end