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,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Parser
|
|
6
|
+
module Generation
|
|
7
|
+
# Consumes all input from `reader` and returns the updated
|
|
8
|
+
# {StateMachine} along with the result of the last attempt
|
|
9
|
+
# to read a segment.
|
|
10
|
+
#
|
|
11
|
+
# The `nondeterminism` argument specifies a limit on how many
|
|
12
|
+
# parse trees can be built simultaneously due to ambiguity in
|
|
13
|
+
# the input and/or specification. This prevents runaway memory
|
|
14
|
+
# CPU consumption (see GH-129), and will return a {Reader::Result.failure}
|
|
15
|
+
# once exceeded.
|
|
16
|
+
#
|
|
17
|
+
# The default value is 1, resulting in an error if any input
|
|
18
|
+
# is ambiguous.
|
|
19
|
+
#
|
|
20
|
+
# NOTE: The error is detected *after* the resources are already
|
|
21
|
+
# been consumed. The extra parse trees are returned (in memory)
|
|
22
|
+
# via the {StateMachine} to aide diagnosis.
|
|
23
|
+
#
|
|
24
|
+
# @return [(StateMachine, Reader::Result)]
|
|
25
|
+
def read(reader, options = {})
|
|
26
|
+
limit = options.fetch(:nondeterminism, 1)
|
|
27
|
+
machine = self
|
|
28
|
+
reader_e = reader.read_segment
|
|
29
|
+
|
|
30
|
+
while reader_e.defined?
|
|
31
|
+
reader_e = reader_e.flatmap do |segment_tok, reader_|
|
|
32
|
+
machine, reader__ =
|
|
33
|
+
machine.insert(segment_tok, false, reader_)
|
|
34
|
+
|
|
35
|
+
if machine.active.length <= limit
|
|
36
|
+
reader__.read_segment
|
|
37
|
+
else
|
|
38
|
+
matches = machine.active.map do |m|
|
|
39
|
+
if segment_use = m.node.zipper.node.usage
|
|
40
|
+
"SegmentUse(#{segment_use.position}, #{segment_use.id},
|
|
41
|
+
#{segment_use.requirement.inspect}, #{segment_use.repeat_count.inspect})".join
|
|
42
|
+
else
|
|
43
|
+
m.node.zipper.node.inspect
|
|
44
|
+
end
|
|
45
|
+
end.join(", ")
|
|
46
|
+
|
|
47
|
+
return machine,
|
|
48
|
+
Reader::Result.failure("too much non-determinism: #{matches}", reader__.input, true)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
return machine, reader_e
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @return [(StateMachine, Reader::TokenReader)]
|
|
57
|
+
def insert(segment_tok, strict, reader)
|
|
58
|
+
active = @active.flat_map do |zipper|
|
|
59
|
+
state = zipper.node
|
|
60
|
+
instructions = state.instructions.matches(segment_tok, strict, :insert, state)
|
|
61
|
+
|
|
62
|
+
if instructions.empty?
|
|
63
|
+
zipper.append(FailureState.mksegment(segment_tok, state)).cons
|
|
64
|
+
else
|
|
65
|
+
instructions.map do |op|
|
|
66
|
+
successor = execute(op, zipper, reader, segment_tok)
|
|
67
|
+
reader = update_reader(op, reader, successor)
|
|
68
|
+
successor
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return StateMachine.new(@config, active), reader
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Three things change together when executing an {Instruction}:
|
|
77
|
+
#
|
|
78
|
+
# 1. The stack of instruction tables that indicates where a segment
|
|
79
|
+
# would be located if it existed, or was added to the parse tree
|
|
80
|
+
#
|
|
81
|
+
# 2. The parse tree, to which we add the new syntax nodes using a
|
|
82
|
+
# zipper.
|
|
83
|
+
#
|
|
84
|
+
# 3. The corresponding tree of states, which tie together the first
|
|
85
|
+
# two and are also updated using a zipper
|
|
86
|
+
#
|
|
87
|
+
# @return [AbstractCursor<StateMachine>]
|
|
88
|
+
def execute(op, zipper, reader, segment_tok)
|
|
89
|
+
table = zipper.node.instructions # 1.
|
|
90
|
+
value = zipper.node.zipper # 2.
|
|
91
|
+
state = zipper # 3.
|
|
92
|
+
|
|
93
|
+
op.pop_count.times do
|
|
94
|
+
value = value.up
|
|
95
|
+
state = state.up
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if op.push.nil?
|
|
99
|
+
# This instruction doesn't create a child node in the parse tree,
|
|
100
|
+
# but it might move us forward to a sibling or upward to an uncle
|
|
101
|
+
segment = AbstractState.mksegment(segment_tok, op.segment_use)
|
|
102
|
+
value = value.append(segment)
|
|
103
|
+
|
|
104
|
+
# If we're moving upward, pop off the current table(s). If we're
|
|
105
|
+
# moving forward, shift off the previous instructions. Important
|
|
106
|
+
# that these are done in order.
|
|
107
|
+
instructions = table.pop(op.pop_count).drop(op.drop_count)
|
|
108
|
+
|
|
109
|
+
# Create a new AbstractState node that has a new InstructionTable
|
|
110
|
+
# and also points to a new AbstractVal tree (with the new segment)
|
|
111
|
+
state.append(state.node.copy(
|
|
112
|
+
:zipper => value,
|
|
113
|
+
:instructions => instructions))
|
|
114
|
+
else
|
|
115
|
+
# Make a new sibling or uncle that will be the parent to the child
|
|
116
|
+
parent = state.node.copy \
|
|
117
|
+
:zipper => value,
|
|
118
|
+
:children => [],
|
|
119
|
+
:separators => reader.try(&:separators),
|
|
120
|
+
:segment_dict => reader.try(&:segment_dict),
|
|
121
|
+
:instructions => table.pop(op.pop_count).drop(op.drop_count)
|
|
122
|
+
|
|
123
|
+
# Note, `state` is a cursor pointing at a state, while `parent`
|
|
124
|
+
# is an actual state
|
|
125
|
+
state = state.append(parent) unless state.root?
|
|
126
|
+
|
|
127
|
+
# Note, eg, op.push == TableState; op.push.push == TableState.push
|
|
128
|
+
op.push.push(state, parent, segment_tok, op.segment_use, @config)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def update_reader(op, reader, successor)
|
|
133
|
+
# We might be moving up or down past the interchange or functional
|
|
134
|
+
# group envelope, which control the set of separators and the set
|
|
135
|
+
# of all possible segments
|
|
136
|
+
unless op.push.nil? and (op.pop_count.zero? or reader.stream?)
|
|
137
|
+
unless reader.separators.eql?(successor.node.separators) \
|
|
138
|
+
and reader.segment_dict.eql?(successor.node.segment_dict)
|
|
139
|
+
reader.copy \
|
|
140
|
+
:separators => successor.node.separators,
|
|
141
|
+
:segment_dict => successor.node.segment_dict
|
|
142
|
+
end
|
|
143
|
+
end || reader
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Parser
|
|
6
|
+
# @todo: Documentation
|
|
7
|
+
#
|
|
8
|
+
class IdentifierStack
|
|
9
|
+
def initialize(start)
|
|
10
|
+
@state = Empty.new(Sequence.new(start))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Returns a new interchange control number (ISA13, IEA02)
|
|
14
|
+
#
|
|
15
|
+
# @return [String]
|
|
16
|
+
def isa(*args)
|
|
17
|
+
@state = @state.isa(*args)
|
|
18
|
+
@state.id
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns a new functional Group Control Number (GS06, GE02)
|
|
22
|
+
#
|
|
23
|
+
# @return [String]
|
|
24
|
+
def gs(*args)
|
|
25
|
+
@state = @state.gs(*args)
|
|
26
|
+
@state.id
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns a new Transaction Set Control Number (ST02)
|
|
30
|
+
#
|
|
31
|
+
# @return [String]
|
|
32
|
+
def st(*args)
|
|
33
|
+
@state = @state.st(*args)
|
|
34
|
+
@state.id
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns a new Hierarchical ID Number (HL01)
|
|
38
|
+
#
|
|
39
|
+
# @return [String]
|
|
40
|
+
def hl(*args)
|
|
41
|
+
@state = @state.hl(*args)
|
|
42
|
+
@state.id
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns the last identifier created
|
|
46
|
+
def pop
|
|
47
|
+
@state.id.tap { @state = @state.pop }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def pop_isa
|
|
51
|
+
@state.id.tap { @state = @state.pop_isa }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def pop_gs
|
|
55
|
+
@state.id.tap { @state = @state.pop_gs }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def pop_st
|
|
59
|
+
@state.id.tap { @state = @state.pop_st }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def pop_hl
|
|
63
|
+
@state.id.tap { @state = @state.pop_hl }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def respond_to?(name)
|
|
67
|
+
@state.respond_to?(name)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def method_missing(name, *args)
|
|
71
|
+
@state.__send__(name, *args)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#########################################################################
|
|
75
|
+
# State Representations
|
|
76
|
+
|
|
77
|
+
class Sequence
|
|
78
|
+
def initialize(start)
|
|
79
|
+
@value = start
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def succ!
|
|
83
|
+
self.tap { @value += 1 }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def value
|
|
87
|
+
@value
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class Empty
|
|
92
|
+
def initialize(sequence)
|
|
93
|
+
@count, @sequence = 0, sequence
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def isa
|
|
97
|
+
ISA.new(self, @sequence).tap { @count += 1; @sequence.succ! }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Returns number of interchanges (@note this is not needed by X12)
|
|
101
|
+
#
|
|
102
|
+
# @return [Integer]
|
|
103
|
+
def count
|
|
104
|
+
@count
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class ISA
|
|
109
|
+
attr_reader :id
|
|
110
|
+
|
|
111
|
+
def initialize(parent, sequence)
|
|
112
|
+
@count, @parent, @sequence, @id = 0, parent, sequence, sequence.value
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def gs(start = nil)
|
|
116
|
+
sequence = start.try{|n| Sequence.new(n) } || @sequence
|
|
117
|
+
GS.new(self, sequence).tap { @count += 1; sequence.succ! }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Number of Transaction Sets Included (IEA01)
|
|
121
|
+
#
|
|
122
|
+
# @return [Integer]
|
|
123
|
+
def count
|
|
124
|
+
@count
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def pop_isa
|
|
128
|
+
@parent
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def pop
|
|
132
|
+
warn "DEPRECATION WARNING: IdentifierStack#pop is deprecated, use pop_isa (when removing an ISA identifier from the stack)"
|
|
133
|
+
pop_isa
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class GS
|
|
138
|
+
attr_reader :id
|
|
139
|
+
|
|
140
|
+
def initialize(parent, sequence)
|
|
141
|
+
@count, @parent, @sequence, @id = 0, parent, sequence, sequence.value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def st(start = nil)
|
|
145
|
+
sequence = start.try{|n| Sequence.new(n) } || @sequence
|
|
146
|
+
ST.new(self, sequence).tap { @count += 1; sequence.succ! }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Number of Transaction Sets Included (GE01)
|
|
150
|
+
#
|
|
151
|
+
# @return [Integer]
|
|
152
|
+
def count
|
|
153
|
+
@count
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def pop_gs
|
|
157
|
+
@parent
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def pop
|
|
161
|
+
warn "DEPRECATION WARNING: IdentifierStack#pop is deprecated, use pop_gs (when removing an GS identifier from the stack)"
|
|
162
|
+
pop_gs
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
class ST
|
|
167
|
+
def initialize(parent, sequence)
|
|
168
|
+
@parent, @id = parent, sequence.value
|
|
169
|
+
@hl_sequence = Sequence.new(0)
|
|
170
|
+
@lx_sequence = Sequence.new(0)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def id
|
|
174
|
+
"%04d" % @id
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def hl
|
|
178
|
+
HL.new(self, @hl_sequence.succ!, @lx_sequence)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def lx
|
|
182
|
+
@lx_sequence.succ!.value
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Number of Included Segments (SE01)
|
|
186
|
+
#
|
|
187
|
+
# @return [Integer]
|
|
188
|
+
def count(builder)
|
|
189
|
+
m = Either.success(builder.machine)
|
|
190
|
+
|
|
191
|
+
while m.defined?
|
|
192
|
+
if m.flatmap(&:segment).map{|s| s.node.id == :ST }.fetch(false)
|
|
193
|
+
return m.flatmap{|n| n.distance(builder.machine) }.fetch(0) + 2
|
|
194
|
+
else
|
|
195
|
+
m = m.flatmap(&:parent)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def pop_st
|
|
201
|
+
@parent
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def pop
|
|
205
|
+
warn "DEPRECATION WARNING: IdentifierStack#pop is deprecated, use pop_st (when removing an ST identifier from the stack)"
|
|
206
|
+
pop_st
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
class HL
|
|
211
|
+
attr_reader :id
|
|
212
|
+
|
|
213
|
+
def initialize(parent, hl_sequence, lx_sequence)
|
|
214
|
+
@parent, @id, @hl_sequence, @lx_sequence =
|
|
215
|
+
parent, hl_sequence.value, hl_sequence, lx_sequence
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def hl
|
|
219
|
+
HL.new(self, @hl_sequence.succ!, @lx_sequence)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def lx
|
|
223
|
+
@lx_sequence.succ!.value
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Parent HL number (HL02)
|
|
227
|
+
#
|
|
228
|
+
# @return [Integer]
|
|
229
|
+
def parent_hl
|
|
230
|
+
if @parent.is_a?(HL)
|
|
231
|
+
@parent.id
|
|
232
|
+
else
|
|
233
|
+
raise RuntimeError, "this HL*#{@id} does not have a parent HL"
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def pop_hl
|
|
238
|
+
@parent
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def pop
|
|
242
|
+
warn "DEPRECATION WARNING: IdentifierStack#pop is deprecated, use pop_ht (when removing an HL identifier from the stack)"
|
|
243
|
+
pop_hl
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Parser
|
|
6
|
+
class Instruction
|
|
7
|
+
include Inspect
|
|
8
|
+
|
|
9
|
+
# The segment identifier to which this {Instruction} applies
|
|
10
|
+
#
|
|
11
|
+
# @return [Symbol]
|
|
12
|
+
attr_reader :segment_id
|
|
13
|
+
|
|
14
|
+
# The segment use contains helpful information about the context of the
|
|
15
|
+
# segment within a definition tree (eg the parent structure's definition).
|
|
16
|
+
# It also enumerates the allowed values for segment qualifiers, which is
|
|
17
|
+
# used to minimize non-determinism.
|
|
18
|
+
#
|
|
19
|
+
# @return [Schema::SegmentUse]
|
|
20
|
+
attr_reader :segment_use
|
|
21
|
+
|
|
22
|
+
# This indicates the number of levels to ascend and terminate within the
|
|
23
|
+
# tree before storing the segment.
|
|
24
|
+
#
|
|
25
|
+
# @return [Integer]
|
|
26
|
+
attr_reader :pop_count
|
|
27
|
+
|
|
28
|
+
# This controls the allowed order in which structures may occur, by
|
|
29
|
+
# indicating the number of instructions to remove from the beginning of
|
|
30
|
+
# the instruction table.
|
|
31
|
+
#
|
|
32
|
+
# Repeatable structures have a value that ensures that their instruction
|
|
33
|
+
# remains in the successor table.
|
|
34
|
+
#
|
|
35
|
+
# Sibling structures that have the same position (as defined by their
|
|
36
|
+
# {Schema::SegmentUse}) will have equal drop_count values such that all of
|
|
37
|
+
# the sibling instructions remain in the successor table when any one of
|
|
38
|
+
# them is executed.
|
|
39
|
+
#
|
|
40
|
+
# @return [Integer]
|
|
41
|
+
attr_reader :drop_count
|
|
42
|
+
|
|
43
|
+
# This indicates that a child node should be added to the tree, which
|
|
44
|
+
# will then contain the segment.
|
|
45
|
+
#
|
|
46
|
+
# When a segment indicates the start of a child structure, the class
|
|
47
|
+
# indicated by this attribute is expected to respond to `push` by
|
|
48
|
+
# creating a new {AbstractState}.
|
|
49
|
+
#
|
|
50
|
+
# @return [Zipper::AbstractCursor]
|
|
51
|
+
attr_reader :push
|
|
52
|
+
|
|
53
|
+
def initialize(segment_id, segment_use, pop, drop, push)
|
|
54
|
+
@segment_id, @segment_use, @pop_count, @drop_count, @push =
|
|
55
|
+
segment_id || segment_use.definition.id, segment_use, pop, drop, push
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def hash
|
|
59
|
+
[Instruction, state].hash
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [Instruction]
|
|
63
|
+
def copy(changes = {})
|
|
64
|
+
Instruction.new \
|
|
65
|
+
changes.fetch(:segment_id, @segment_id),
|
|
66
|
+
changes.fetch(:segment_use, @segment_use),
|
|
67
|
+
changes.fetch(:pop_count, @pop_count),
|
|
68
|
+
changes.fetch(:drop_count, @drop_count),
|
|
69
|
+
changes.fetch(:push, @push)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [void]
|
|
73
|
+
def pretty_print(q)
|
|
74
|
+
id = "% 3s" % @segment_id.to_s
|
|
75
|
+
|
|
76
|
+
unless @segment_use.nil?
|
|
77
|
+
width = 18
|
|
78
|
+
name = @segment_use.definition.name
|
|
79
|
+
|
|
80
|
+
# Truncate the segment name to `width` characters
|
|
81
|
+
if name.length > width - 2
|
|
82
|
+
id = id + ": #{name.slice(0, width - 2)}.."
|
|
83
|
+
else
|
|
84
|
+
id = id + ": #{name.ljust(width)}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
q.text "Instruction[#{"% 3s" % id}]"
|
|
89
|
+
|
|
90
|
+
q.group(6, "(", ")") do
|
|
91
|
+
q.breakable ""
|
|
92
|
+
|
|
93
|
+
unless @segment_use.nil?
|
|
94
|
+
q.text "position: #{@segment_use.position},"
|
|
95
|
+
q.breakable
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
q.text "pop: #{@pop_count},"
|
|
99
|
+
q.breakable
|
|
100
|
+
|
|
101
|
+
q.text "drop: #{@drop_count}"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def state
|
|
108
|
+
[@segment_id, @segment_use, @pop_count, @drop_count, @push].hash
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|