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,96 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class InterchangeState < 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 [InterchangeState]
28
+ def copy(changes = {})
29
+ InterchangeState.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 << InterchangeState
39
+ # @group Constructors
40
+ #########################################################################
41
+
42
+ # @return [Zipper::AbstractCursor]
43
+ def push(zipper, parent, segment_tok, segment_use, config)
44
+ # ISA12: Interchange Control Version Number
45
+ version = segment_tok.element_toks.at(11).try(:value)
46
+
47
+ unless config.interchange.defined_at?(version)
48
+ reason =
49
+ if config.interchange.empty?
50
+ Stupidedi::Exceptions::MissingGrammarError::DEFAULT_MESSAGE
51
+ else
52
+ "unknown interchange version #{version.inspect}"
53
+ end
54
+
55
+ return FailureState.push(zipper, parent, segment_tok, reason)
56
+ end
57
+
58
+ # Construct a SegmentVal and InterchangeVal around it
59
+ envelope_def = config.interchange.at(version)
60
+ envelope_val = envelope_def.empty(parent.separators)
61
+ segment_use = envelope_def.entry_segment_use
62
+ segment_val = mksegment(segment_tok, segment_use)
63
+
64
+ separators =
65
+ parent.separators.merge(envelope_def.separators(segment_val))
66
+
67
+ zipper.append_child new(
68
+ separators,
69
+ parent.segment_dict.push(envelope_val.segment_dict),
70
+ parent.instructions.push(instructions(envelope_def)),
71
+ parent.zipper.append(envelope_val).append_child(segment_val),
72
+ [])
73
+ end
74
+
75
+ # @endgroup
76
+ #########################################################################
77
+
78
+ private
79
+
80
+ # @return [Array<Instruction>]
81
+ def instructions(interchange_def)
82
+ @__instructions ||= Hash.new
83
+ @__instructions[interchange_def] ||= begin
84
+ is = if interchange_def.header_segment_uses.head.repeatable?
85
+ sequence(interchange_def.header_segment_uses)
86
+ else
87
+ sequence(interchange_def.header_segment_uses.tail)
88
+ end
89
+
90
+ is << Instruction.new(:GS, nil, 0, is.length, FunctionalGroupState)
91
+ is.concat(sequence(interchange_def.trailer_segment_uses, is.length))
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class LoopState < 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 [LoopState]
28
+ def copy(changes = {})
29
+ LoopState.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 << LoopState
39
+ # @group Constructors
40
+ #########################################################################
41
+
42
+ # @return [Zipper::AbstractCursor]
43
+ def push(zipper, parent, segment_tok, segment_use, config)
44
+ loop_def = segment_use.parent
45
+ loop_val = loop_def.empty
46
+ segment_val = mksegment(segment_tok, segment_use)
47
+
48
+ zipper.append_child new(
49
+ parent.separators,
50
+ parent.segment_dict,
51
+ parent.instructions.push(instructions(loop_def)),
52
+ parent.zipper.append(loop_val).append_child(segment_val),
53
+ [])
54
+ end
55
+
56
+ # @endgroup
57
+ #########################################################################
58
+
59
+ private
60
+
61
+ # @return [Array<Instruction>]
62
+ def instructions(loop_def)
63
+ @__instructions ||= Hash.new
64
+ @__instructions[loop_def] ||= begin
65
+ # When first segment is repeatable, then `successors` should include
66
+ # an {Instruction} for it; but when it's non-repeatable, there should
67
+ # be no successor instruction for that segment.
68
+ skip_first = !loop_def.entry_segment_use.repeatable?
69
+ interleaved_sequence(loop_def.children, 0, skip_first: skip_first)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class TableState < 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 [TableState]
28
+ def copy(changes = {})
29
+ TableState.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 << TableState
39
+ # @group Constructors
40
+ #########################################################################
41
+
42
+ # @return [Zipper::AbstractCursor]
43
+ def push(zipper, parent, segment_tok, segment_use, config)
44
+ case segment_use.parent
45
+ when Schema::TableDef
46
+ table_def = segment_use.parent
47
+ table_val = table_def.empty
48
+ segment_val = mksegment(segment_tok, segment_use)
49
+
50
+ itable = InstructionTable.build(instructions(table_def))
51
+ itable = itable.drop(itable.at(segment_use).drop_count)
52
+
53
+ zipper.append_child new(
54
+ parent.separators,
55
+ parent.segment_dict,
56
+ parent.instructions.push(itable.instructions),
57
+ parent.zipper.append(table_val).append_child(segment_val),
58
+ [])
59
+
60
+ when Schema::LoopDef
61
+ table_def = segment_use.parent.parent
62
+ table_val = table_def.empty
63
+
64
+ itable = InstructionTable.build(instructions(table_def))
65
+ itable = itable.drop(itable.at(segment_use).drop_count)
66
+
67
+ zipper = zipper.append_child new(
68
+ parent.separators,
69
+ parent.segment_dict,
70
+ parent.instructions.push(itable.instructions),
71
+ parent.zipper.append(table_val).dangle.last,
72
+ [])
73
+
74
+ LoopState.push(zipper, zipper.node, segment_tok, segment_use, config)
75
+ end
76
+ end
77
+
78
+ # @endgroup
79
+ #########################################################################
80
+
81
+ private
82
+
83
+ # @return [Array<Instruction>]
84
+ def instructions(table_def)
85
+ @__instructions ||= Hash.new
86
+ @__instructions[table_def] ||= interleaved_sequence(table_def.children)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class TransactionSetState < 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 [TransactionSetState]
28
+ def copy(changes = {})
29
+ TransactionSetState.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 << TransactionSetState
39
+ # @group Constructors
40
+ #########################################################################
41
+
42
+ # @return [TransactionSetState]
43
+ def push(zipper, parent, segment_tok, segment_use, config)
44
+ # GS01: Functional Identifier Code
45
+ gs01 = parent.gs01
46
+
47
+ # ST01: Transaction Set Identifier Code
48
+ st01 = segment_tok.element_toks.at(0).try(:value)
49
+
50
+ # ST03: Implementation Convention Reference
51
+ #
52
+ # The implementation convention reference (ST03) is used by the
53
+ # translation routines of the interchange partners to select the
54
+ # appropriate implementation convention to match the transaction set
55
+ # definition. When used, this implementation convention reference takes
56
+ # precedence over the implementation reference specified in the GS08
57
+ st03 = segment_tok.element_toks.at(2).try(:value)
58
+
59
+ # Fall back to GS08 if ST03 isn't available
60
+ if st03.blank? or st03.is_a?(Symbol)
61
+ # GS08: Version / Release / Industry Identifier Code
62
+ st03 = parent.gs08
63
+ end
64
+
65
+ # Fall back to GS08 if ST03 isn't recognized
66
+ # unless config.transaction_set.defined_at?(st03, gs01, st01)
67
+ # if config.transaction_set.defined_at?(parent.gs08, gs01, st01)
68
+ # st03 = parent.gs08
69
+ # end
70
+ # end
71
+
72
+ unless config.transaction_set.defined_at?(st03, gs01, st01)
73
+ reason =
74
+ if config.transaction_set.empty?
75
+ Stupidedi::Exceptions::MissingGrammarError::DEFAULT_MESSAGE
76
+ else
77
+ context = "#{st03.inspect} #{gs01.inspect} #{st01.inspect}"
78
+ "unknown transaction set #{context}"
79
+ end
80
+
81
+ return FailureState.push(zipper, parent, segment_tok, reason)
82
+ end
83
+
84
+ envelope_def = config.transaction_set.at(st03, gs01, st01)
85
+ envelope_val = envelope_def.empty
86
+ segment_use = envelope_def.entry_segment_use
87
+
88
+ zipper = zipper.append_child \
89
+ TransactionSetState.new(
90
+ parent.separators,
91
+ parent.segment_dict,
92
+ parent.instructions.push(instructions(envelope_def)),
93
+ parent.zipper.append(envelope_val).dangle.last,
94
+ [])
95
+
96
+ TableState.push(zipper, zipper.node, segment_tok, segment_use, config)
97
+ end
98
+
99
+ # @endgroup
100
+ #########################################################################
101
+
102
+ private
103
+
104
+ # @return [Array<Instruction>]
105
+ def instructions(transaction_set_def)
106
+ @__instructions ||= Hash.new
107
+ @__instructions[transaction_set_def] ||= begin
108
+ # When first segment is repeatable, then `successors` should include
109
+ # an {Instruction} for it; but when it's non-repeatable, there should
110
+ # be no successor instruction for that segment.
111
+ if transaction_set_def.table_defs.head.repeatable?
112
+ tsequence(transaction_set_def.table_defs)
113
+ else
114
+ tsequence(transaction_set_def.table_defs.tail)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ class TransmissionState < 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 [TransmissionState]
28
+ def copy(changes = {})
29
+ TransmissionState.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 << TransmissionState
39
+ # @group Constructors
40
+ #########################################################################
41
+
42
+ # @return [Zipper::AbstractCursor]
43
+ def push(zipper, parent, segment_tok, segment_use, config)
44
+ zipper = zipper.append_child new(
45
+ parent.separators,
46
+ parent.segment_dict,
47
+ parent.instructions.push([
48
+ Instruction.new(:ISA, nil, 0, 0, InterchangeState)]),
49
+ parent.zipper.dangle.last,
50
+ [])
51
+
52
+ InterchangeState.push(zipper, zipper.node, segment_tok, segment_use, config)
53
+ end
54
+
55
+ # @endgroup
56
+ #########################################################################
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ using Refinements
4
+
5
+ module Parser
6
+ module Tokenization
7
+ #########################################################################
8
+ # @group Element Constructors
9
+
10
+ # Generates a repeated element (simple or composite)
11
+ #
12
+ # @return [void]
13
+ def repeated(*elements)
14
+ [:repeated, elements, Reader::Position.caller(2)]
15
+ end
16
+
17
+ # Generates a composite element
18
+ #
19
+ # @return [void]
20
+ def composite(*components)
21
+ [:composite, components, Reader::Position.caller(2)]
22
+ end
23
+
24
+ #########################################################################
25
+ # @group Element Placeholders
26
+
27
+ # Generates a blank element
28
+ #
29
+ # @return [void]
30
+ def blank
31
+ [:blank, nil, Reader::Position.caller(2)]
32
+ end
33
+
34
+ # Generates a blank element and asserts that the element's usage
35
+ # requirement is `NOT USED`
36
+ #
37
+ # @see Schema::ElementReq#forbidden?
38
+ #
39
+ # @return [void]
40
+ def not_used
41
+ [:not_used, nil, Reader::Position.caller(2)]
42
+ end
43
+
44
+ # Generates the only possible value an element may have, which may
45
+ # be blank. An exception is thrown if the element's usage requirement
46
+ # is optional, or if there are more than one allowed non-blank values.
47
+ #
48
+ # @see Schema::SimpleElementUse#allowed_values
49
+ # @see Schema::ElementReq#forbidden?
50
+ #
51
+ # @return [void]
52
+ def default
53
+ [:default, nil, Reader::Position.caller(2)]
54
+ end
55
+
56
+ # @endgroup
57
+ #########################################################################
58
+
59
+ private
60
+
61
+ # @return [Reader::SegmentTok]
62
+ def mksegment_tok(segment_dict, id, elements, position)
63
+ id = id.to_sym
64
+ element_toks = []
65
+
66
+ unless segment_dict.defined_at?(id)
67
+ element_idx = "00"
68
+ elements.each do |e_tag, e_val, e_position|
69
+ element_idx = element_idx.succ
70
+
71
+ # If the element is a regular Ruby value "ABC", the way this
72
+ # proc's arguments are assigned would be e_tag = "ABC", and
73
+ # e_val and e_position are nil. If the argument is a placeholder
74
+ # like #blank, #not_used, or #default is used, those methods return
75
+ # a triple that is deconstructed such that e_val is also nil.
76
+ #
77
+ # However, for #composite or #repeated, the triple is deconstructed
78
+ # such that e_val is an Array of other values, and isn't #nil?
79
+ unless e_val.nil?
80
+ raise ArgumentError,
81
+ "#{id}#{element_idx} is assumed to be a simple element"
82
+ end
83
+
84
+ element_toks << mksimple_tok(e_tag, e_position || position)
85
+ end
86
+ else
87
+ segment_def = segment_dict.at(id)
88
+ element_uses = segment_def.element_uses
89
+
90
+ if elements.length > element_uses.length
91
+ raise ArgumentError,
92
+ "#{id} segment has only #{element_uses.length} elements"
93
+ end
94
+
95
+ element_idx = "00"
96
+ elements.zip(element_uses) do |(e_tag, e_val, e_position), e_use|
97
+ element_idx = element_idx.succ
98
+ designator = "#{id}#{element_idx}"
99
+
100
+ if e_use.repeatable?
101
+ # Repeatable composite or non-composite
102
+ unless [:repeated, :blank, :not_used, nil].include?(e_tag)
103
+ raise ArgumentError,
104
+ "#{designator} is a repeatable element"
105
+ end
106
+
107
+ element_toks << mkrepeated_tok(e_val || [], e_use, designator, e_position || position)
108
+ elsif e_use.composite?
109
+ unless [:composite, :not_used, :blank, nil].include?(e_tag)
110
+ raise ArgumentError,
111
+ "#{id}#{element_idx} is a non-repeatable composite element"
112
+ end
113
+
114
+ element_toks << mkcomposite_tok(e_val || [], e_use, designator, e_position || position)
115
+ else
116
+ # The actual value is in e_tag
117
+ unless e_val.nil?
118
+ raise ArgumentError,
119
+ "#{id}#{element_idx} is a non-repeatable simple element"
120
+ end
121
+
122
+ element_toks << mksimple_tok(e_tag, e_position || position)
123
+ end
124
+ end
125
+ end
126
+
127
+ Reader::SegmentTok.new(id, element_toks, position, nil)
128
+ end
129
+
130
+ # @return [Reader::RepeatedElementTok]
131
+ def mkrepeated_tok(elements, element_use, designator, position)
132
+ element_toks = []
133
+
134
+ if element_use.composite?
135
+ elements.each do |e_tag, e_val, e_position|
136
+ unless [:composite, :not_used, :blank, nil].include?(e_tag)
137
+ raise ArgumentError,
138
+ "#{designator} is a composite element"
139
+ end
140
+
141
+ element_toks << mkcomposite_tok(e_val || [], element_use, designator, e_position || position)
142
+ end
143
+ else
144
+ elements.each do |e_tag, e_val, e_position|
145
+ unless e_val.nil?
146
+ raise ArgumentError,
147
+ "#{designator} is a simple element"
148
+ end
149
+
150
+ element_toks << mksimple_tok(e_tag, e_position || position)
151
+ end
152
+ end
153
+
154
+ Reader::RepeatedElementTok.build(element_toks, position)
155
+ end
156
+
157
+ # @return [Reader::CompositeElementTok]
158
+ def mkcomposite_tok(components, composite_use, designator, position)
159
+ component_uses = composite_use.definition.component_uses
160
+
161
+ if components.length > component_uses.length
162
+ raise ArgumentError,
163
+ "#{designator} has only #{component_uses.length} components"
164
+ end
165
+
166
+ component_idx = "0"
167
+ component_toks = []
168
+ component_uses.zip(components) do |c_use, (c_tag, c_val, c_position)|
169
+ component_idx = component_idx.succ
170
+ unless c_val.nil?
171
+ raise ArgumentError,
172
+ "#{designator}-#{component_idx} is a component element"
173
+ end
174
+
175
+ component_toks << mkcomponent_tok(c_tag, c_position || position)
176
+ end
177
+
178
+ Reader::CompositeElementTok.build(component_toks, position, nil)
179
+ end
180
+
181
+ # @return [Reader::ComponentElementTok]
182
+ def mkcomponent_tok(value, position)
183
+ Reader::ComponentElementTok.build(value, position, nil)
184
+ end
185
+
186
+ # @return [Reader::SimpleElementTok]
187
+ def mksimple_tok(value, position)
188
+ Reader::SimpleElementTok.build(value, position, nil)
189
+ end
190
+
191
+ # @endgroup
192
+ #########################################################################
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module Stupidedi
3
+ module Parser
4
+ autoload :ConstraintTable, "stupidedi/parser/constraint_table"
5
+ autoload :Instruction, "stupidedi/parser/instruction"
6
+ autoload :InstructionTable, "stupidedi/parser/instruction_table"
7
+
8
+ autoload :BuilderDsl, "stupidedi/parser/builder_dsl"
9
+ autoload :Generation, "stupidedi/parser/generation"
10
+ autoload :Navigation, "stupidedi/parser/navigation"
11
+ autoload :Tokenization, "stupidedi/parser/tokenization"
12
+ autoload :StateMachine, "stupidedi/parser/state_machine"
13
+ autoload :IdentifierStack, "stupidedi/parser/identifier_stack"
14
+
15
+ autoload :AbstractState, "stupidedi/parser/states/abstract_state"
16
+ autoload :FailureState, "stupidedi/parser/states/failure_state"
17
+ autoload :FunctionalGroupState, "stupidedi/parser/states/functional_group_state"
18
+ autoload :InitialState, "stupidedi/parser/states/initial_state"
19
+ autoload :InterchangeState, "stupidedi/parser/states/interchange_state"
20
+ autoload :LoopState, "stupidedi/parser/states/loop_state"
21
+ autoload :TableState, "stupidedi/parser/states/table_state"
22
+ autoload :TransactionSetState, "stupidedi/parser/states/transaction_set_state"
23
+ autoload :TransmissionState, "stupidedi/parser/states/transmission_state"
24
+ end
25
+
26
+ class << Parser
27
+ # @return [StateMachine]
28
+ def build(*args)
29
+ Parser::StateMachine.build(*args)
30
+ end
31
+ end
32
+ end