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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +319 -0
- data/LICENSE +26 -0
- data/README.md +308 -0
- data/Rakefile +33 -0
- data/bin/tediparse +102 -0
- data/doc/Defining.md +97 -0
- data/doc/Generating-Grammars.md +241 -0
- data/doc/Generating.md +332 -0
- data/doc/Navigating.md +670 -0
- data/doc/Parsing.md +133 -0
- data/doc/README.md +51 -0
- data/doc/Serializing.md +100 -0
- data/doc/Tokenizing.md +136 -0
- data/doc/Validating.md +140 -0
- data/lib/ruby/array.rb +226 -0
- data/lib/ruby/blank.rb +52 -0
- data/lib/ruby/exception.rb +14 -0
- data/lib/ruby/hash.rb +14 -0
- data/lib/ruby/module.rb +60 -0
- data/lib/ruby/object.rb +56 -0
- data/lib/ruby/string.rb +89 -0
- data/lib/ruby/to_d.rb +82 -0
- data/lib/ruby/to_date.rb +26 -0
- data/lib/ruby/to_time.rb +21 -0
- data/lib/ruby/try.rb +46 -0
- data/lib/stupidedi/builder.rb +6 -0
- data/lib/stupidedi/color.rb +94 -0
- data/lib/stupidedi/config/code_list_config.rb +45 -0
- data/lib/stupidedi/config/functional_group_config.rb +72 -0
- data/lib/stupidedi/config/interchange_config.rb +86 -0
- data/lib/stupidedi/config/transaction_set_config.rb +73 -0
- data/lib/stupidedi/config.rb +100 -0
- data/lib/stupidedi/either.rb +286 -0
- data/lib/stupidedi/exceptions/invalid_element_error.rb +7 -0
- data/lib/stupidedi/exceptions/invalid_schema_error.rb +7 -0
- data/lib/stupidedi/exceptions/missing_grammar_error.rb +50 -0
- data/lib/stupidedi/exceptions/output_error.rb +7 -0
- data/lib/stupidedi/exceptions/parse_error.rb +7 -0
- data/lib/stupidedi/exceptions/stupidedi_error.rb +7 -0
- data/lib/stupidedi/exceptions/tokenize_error.rb +7 -0
- data/lib/stupidedi/exceptions/zipper_error.rb +7 -0
- data/lib/stupidedi/exceptions.rb +13 -0
- data/lib/stupidedi/inspect.rb +26 -0
- data/lib/stupidedi/interchanges/element_types/separator_val.rb +79 -0
- data/lib/stupidedi/interchanges/element_types/special_val.rb +48 -0
- data/lib/stupidedi/interchanges/element_types.rb +11 -0
- data/lib/stupidedi/interchanges.rb +21 -0
- data/lib/stupidedi/parser/builder_dsl.rb +292 -0
- data/lib/stupidedi/parser/constraint_table.rb +566 -0
- data/lib/stupidedi/parser/generation.rb +147 -0
- data/lib/stupidedi/parser/identifier_stack.rb +248 -0
- data/lib/stupidedi/parser/instruction.rb +112 -0
- data/lib/stupidedi/parser/instruction_table.rb +222 -0
- data/lib/stupidedi/parser/navigation.rb +786 -0
- data/lib/stupidedi/parser/state_machine.rb +62 -0
- data/lib/stupidedi/parser/states/abstract_state.rb +385 -0
- data/lib/stupidedi/parser/states/failure_state.rb +69 -0
- data/lib/stupidedi/parser/states/functional_group_state.rb +101 -0
- data/lib/stupidedi/parser/states/initial_state.rb +62 -0
- data/lib/stupidedi/parser/states/interchange_state.rb +96 -0
- data/lib/stupidedi/parser/states/loop_state.rb +74 -0
- data/lib/stupidedi/parser/states/table_state.rb +90 -0
- data/lib/stupidedi/parser/states/transaction_set_state.rb +120 -0
- data/lib/stupidedi/parser/states/transmission_state.rb +59 -0
- data/lib/stupidedi/parser/tokenization.rb +195 -0
- data/lib/stupidedi/parser.rb +32 -0
- data/lib/stupidedi/reader/input/abstract_input.rb +137 -0
- data/lib/stupidedi/reader/input/delegated_input.rb +112 -0
- data/lib/stupidedi/reader/input/file_input.rb +157 -0
- data/lib/stupidedi/reader/input.rb +31 -0
- data/lib/stupidedi/reader/position.rb +78 -0
- data/lib/stupidedi/reader/result.rb +172 -0
- data/lib/stupidedi/reader/segment_dict.rb +176 -0
- data/lib/stupidedi/reader/separators.rb +90 -0
- data/lib/stupidedi/reader/stream_reader.rb +173 -0
- data/lib/stupidedi/reader/token_reader.rb +465 -0
- data/lib/stupidedi/reader/tokens/component_element_tok.rb +71 -0
- data/lib/stupidedi/reader/tokens/composite_element_tok.rb +85 -0
- data/lib/stupidedi/reader/tokens/repeated_element_tok.rb +74 -0
- data/lib/stupidedi/reader/tokens/segment_tok.rb +74 -0
- data/lib/stupidedi/reader/tokens/simple_element_tok.rb +76 -0
- data/lib/stupidedi/reader.rb +121 -0
- data/lib/stupidedi/schema/abstract_def.rb +76 -0
- data/lib/stupidedi/schema/abstract_element_def.rb +35 -0
- data/lib/stupidedi/schema/abstract_element_use.rb +47 -0
- data/lib/stupidedi/schema/abstract_use.rb +79 -0
- data/lib/stupidedi/schema/code_list.rb +99 -0
- data/lib/stupidedi/schema/component_element_use.rb +76 -0
- data/lib/stupidedi/schema/composite_element_def.rb +103 -0
- data/lib/stupidedi/schema/composite_element_use.rb +78 -0
- data/lib/stupidedi/schema/element_req.rb +57 -0
- data/lib/stupidedi/schema/functional_group_def.rb +124 -0
- data/lib/stupidedi/schema/generation/definition_generator.rb +139 -0
- data/lib/stupidedi/schema/generation/element_generator.rb +221 -0
- data/lib/stupidedi/schema/generation/flat_file_reader.rb +551 -0
- data/lib/stupidedi/schema/generation/functional_group_generator.rb +64 -0
- data/lib/stupidedi/schema/generation/interchange_generator.rb +145 -0
- data/lib/stupidedi/schema/generation/master_loader_generator.rb +121 -0
- data/lib/stupidedi/schema/generation/models.rb +85 -0
- data/lib/stupidedi/schema/generation/module_loader_generator.rb +64 -0
- data/lib/stupidedi/schema/generation/registration_generator.rb +230 -0
- data/lib/stupidedi/schema/generation/runner.rb +161 -0
- data/lib/stupidedi/schema/generation/segment_generator.rb +130 -0
- data/lib/stupidedi/schema/generation/support.rb +78 -0
- data/lib/stupidedi/schema/generation/support_modules_generator.rb +126 -0
- data/lib/stupidedi/schema/generation/version_modules.rb +35 -0
- data/lib/stupidedi/schema/generation.rb +94 -0
- data/lib/stupidedi/schema/interchange_def.rb +103 -0
- data/lib/stupidedi/schema/loop_def.rb +156 -0
- data/lib/stupidedi/schema/repeat_count.rb +86 -0
- data/lib/stupidedi/schema/segment_def.rb +122 -0
- data/lib/stupidedi/schema/segment_req.rb +46 -0
- data/lib/stupidedi/schema/segment_use.rb +99 -0
- data/lib/stupidedi/schema/simple_element_def.rb +51 -0
- data/lib/stupidedi/schema/simple_element_use.rb +83 -0
- data/lib/stupidedi/schema/syntax_note.rb +52 -0
- data/lib/stupidedi/schema/table_def.rb +178 -0
- data/lib/stupidedi/schema/transaction_set_def.rb +125 -0
- data/lib/stupidedi/schema.rb +30 -0
- data/lib/stupidedi/sets.rb +42 -0
- data/lib/stupidedi/transaction_sets/builder/dsl.rb +192 -0
- data/lib/stupidedi/transaction_sets/builder.rb +188 -0
- data/lib/stupidedi/transaction_sets/common/implementations/element_reqs.rb +37 -0
- data/lib/stupidedi/transaction_sets/common/implementations/segment_reqs.rb +31 -0
- data/lib/stupidedi/transaction_sets/common/implementations.rb +11 -0
- data/lib/stupidedi/transaction_sets/common.rb +8 -0
- data/lib/stupidedi/transaction_sets/validation/ambiguity.rb +395 -0
- data/lib/stupidedi/transaction_sets/validation/implementation.rb +12 -0
- data/lib/stupidedi/transaction_sets/validation.rb +9 -0
- data/lib/stupidedi/transaction_sets.rb +25 -0
- data/lib/stupidedi/values/abstract_element_val.rb +19 -0
- data/lib/stupidedi/values/abstract_val.rb +133 -0
- data/lib/stupidedi/values/composite_element_val.rb +102 -0
- data/lib/stupidedi/values/functional_group_val.rb +105 -0
- data/lib/stupidedi/values/interchange_val.rb +102 -0
- data/lib/stupidedi/values/invalid_envelope_val.rb +61 -0
- data/lib/stupidedi/values/invalid_segment_val.rb +89 -0
- data/lib/stupidedi/values/loop_val.rb +73 -0
- data/lib/stupidedi/values/repeated_element_val.rb +113 -0
- data/lib/stupidedi/values/segment_val.rb +105 -0
- data/lib/stupidedi/values/segment_val_group.rb +20 -0
- data/lib/stupidedi/values/simple_element_val.rb +80 -0
- data/lib/stupidedi/values/table_val.rb +69 -0
- data/lib/stupidedi/values/transaction_set_val.rb +69 -0
- data/lib/stupidedi/values/transmission_val.rb +56 -0
- data/lib/stupidedi/values.rb +22 -0
- data/lib/stupidedi/version.rb +4 -0
- data/lib/stupidedi/versions/common/element_reqs.rb +13 -0
- data/lib/stupidedi/versions/common/element_types/an.rb +386 -0
- data/lib/stupidedi/versions/common/element_types/dt.rb +572 -0
- data/lib/stupidedi/versions/common/element_types/id.rb +304 -0
- data/lib/stupidedi/versions/common/element_types/nn.rb +312 -0
- data/lib/stupidedi/versions/common/element_types/operators.rb +128 -0
- data/lib/stupidedi/versions/common/element_types/r.rb +342 -0
- data/lib/stupidedi/versions/common/element_types/simple_element.rb +73 -0
- data/lib/stupidedi/versions/common/element_types/tm.rb +347 -0
- data/lib/stupidedi/versions/common/element_types.rb +29 -0
- data/lib/stupidedi/versions/common/segment_reqs.rb +15 -0
- data/lib/stupidedi/versions/common/syntax_notes.rb +172 -0
- data/lib/stupidedi/versions/common.rb +11 -0
- data/lib/stupidedi/versions.rb +25 -0
- data/lib/stupidedi/writer/claredi.rb +178 -0
- data/lib/stupidedi/writer/default.rb +119 -0
- data/lib/stupidedi/writer.rb +7 -0
- data/lib/stupidedi/zipper/abstract_cursor.rb +351 -0
- data/lib/stupidedi/zipper/dangling_cursor.rb +103 -0
- data/lib/stupidedi/zipper/edited_cursor.rb +157 -0
- data/lib/stupidedi/zipper/memoized_cursor.rb +133 -0
- data/lib/stupidedi/zipper/path.rb +132 -0
- data/lib/stupidedi/zipper/root_cursor.rb +120 -0
- data/lib/stupidedi/zipper/stack_cursor.rb +107 -0
- data/lib/stupidedi/zipper.rb +45 -0
- data/lib/stupidedi.rb +69 -0
- data/lib/tediparse.rb +1 -0
- 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
|