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,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Zipper
|
|
6
|
+
class DanglingCursor < AbstractCursor
|
|
7
|
+
# @return [AbstractCursor]
|
|
8
|
+
attr_reader :parent
|
|
9
|
+
|
|
10
|
+
def initialize(parent)
|
|
11
|
+
@parent = parent
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# (see AbstractCursor#node)
|
|
15
|
+
def node
|
|
16
|
+
raise Exceptions::ZipperError,
|
|
17
|
+
"DanglingCursor#node should not be called"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# (see AbstractCursor#path)
|
|
21
|
+
def path
|
|
22
|
+
Hole.new([], @parent.path.parent, [])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @group Querying the Tree Location
|
|
26
|
+
#########################################################################
|
|
27
|
+
|
|
28
|
+
# (see AbstractCursor#leaf?)
|
|
29
|
+
def leaf?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# (see AbstractCursor#root?)
|
|
34
|
+
def root?
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# (see AbstractCursor#depth)
|
|
39
|
+
def depth
|
|
40
|
+
@parent.depth + 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# (see AbstractCursor#first?)
|
|
44
|
+
def first?
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# (see AbstractCursor#last?)
|
|
49
|
+
def last?
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @group Traversing the Tree
|
|
54
|
+
#########################################################################
|
|
55
|
+
|
|
56
|
+
# @return [AbstractCursor]
|
|
57
|
+
def up
|
|
58
|
+
@parent
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# (see AbstractCursor#next)
|
|
62
|
+
def next
|
|
63
|
+
raise Exceptions::ZipperError,
|
|
64
|
+
"cannot move to next after last node"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# (see AbstractCursor#prev)
|
|
68
|
+
def prev
|
|
69
|
+
raise Exceptions::ZipperError,
|
|
70
|
+
"cannot move to prev before first node"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# (see AbstractCursor#first)
|
|
74
|
+
def first
|
|
75
|
+
self
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# (see AbstractCursor#last)
|
|
79
|
+
def last
|
|
80
|
+
self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @group Editing the Tree
|
|
84
|
+
#########################################################################
|
|
85
|
+
|
|
86
|
+
# (see AbstractCursor#replace)
|
|
87
|
+
def replace(node)
|
|
88
|
+
@parent.append_child(node)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
alias prepend replace
|
|
92
|
+
alias append replace
|
|
93
|
+
|
|
94
|
+
# (see AbstractCursor#delete)
|
|
95
|
+
def delete
|
|
96
|
+
self
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# @endgroup
|
|
100
|
+
#########################################################################
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Zipper
|
|
6
|
+
class EditedCursor < AbstractCursor
|
|
7
|
+
# (see AbstractCursor#node)
|
|
8
|
+
attr_reader :node
|
|
9
|
+
|
|
10
|
+
# @return [Hole]
|
|
11
|
+
attr_reader :path
|
|
12
|
+
|
|
13
|
+
# @return [AbstractCursor]
|
|
14
|
+
attr_reader :parent
|
|
15
|
+
|
|
16
|
+
def initialize(node, path, parent)
|
|
17
|
+
@node, @path, @parent =
|
|
18
|
+
node, path, parent
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @group Querying the Tree Location
|
|
22
|
+
#########################################################################
|
|
23
|
+
|
|
24
|
+
# (see AbstractCursor#leaf?)
|
|
25
|
+
def leaf?
|
|
26
|
+
@node.leaf? or @node.children.empty?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# (see AbstractCursor#root?)
|
|
30
|
+
def root?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @group Traversing the Tree
|
|
35
|
+
#########################################################################
|
|
36
|
+
|
|
37
|
+
# (see AbstractCursor#up)
|
|
38
|
+
# @return [AbstractCursor]
|
|
39
|
+
def up
|
|
40
|
+
node =
|
|
41
|
+
@parent.node.copy(:children =>
|
|
42
|
+
@path.left.reverse.concat(@node.cons(@path.right)))
|
|
43
|
+
|
|
44
|
+
if parent.root?
|
|
45
|
+
RootCursor.new(node)
|
|
46
|
+
else
|
|
47
|
+
EditedCursor.new(node, @path.parent, @parent.parent)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# (see AbstractCursor#next)
|
|
52
|
+
# @return [EditedCursor]
|
|
53
|
+
def next
|
|
54
|
+
if last?
|
|
55
|
+
raise Exceptions::ZipperError,
|
|
56
|
+
"cannot move to next after last node"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
head, *tail = @path.right
|
|
60
|
+
|
|
61
|
+
EditedCursor.new(head,
|
|
62
|
+
Hole.new(@node.cons(@path.left), @path.parent, tail), @parent)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# (see AbstractCursor#prev)
|
|
66
|
+
# @return [EditedCursor]
|
|
67
|
+
def prev
|
|
68
|
+
if first?
|
|
69
|
+
raise Exceptions::ZipperError,
|
|
70
|
+
"cannot move to prev before first node"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
head, *tail = @path.left
|
|
74
|
+
|
|
75
|
+
EditedCursor.new(head,
|
|
76
|
+
Hole.new(tail, @path.parent, @node.cons(@path.right)), @parent)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# (see AbstractCursor#first)
|
|
80
|
+
# @return [EditedCursor]
|
|
81
|
+
def first
|
|
82
|
+
if first?
|
|
83
|
+
return self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
right = @path.left.init.reverse.concat(@node.cons(@path.right))
|
|
87
|
+
|
|
88
|
+
EditedCursor.new(@path.left.last,
|
|
89
|
+
Hole.new([], @path.parent, right), @parent)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# (see AbstractCursor#last)
|
|
93
|
+
# @return [EditedCursor]
|
|
94
|
+
def last
|
|
95
|
+
if last?
|
|
96
|
+
return self
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
left = @node.cons(@path.right.init.reverse).concat(@path.left)
|
|
100
|
+
|
|
101
|
+
EditedCursor.new(@path.right.last,
|
|
102
|
+
Hole.new(left, @path.parent, []), @parent)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @group Editing the Tree
|
|
106
|
+
#########################################################################
|
|
107
|
+
|
|
108
|
+
# (see AbstractCursor#last)
|
|
109
|
+
# @return [EditedCursor]
|
|
110
|
+
def append(node)
|
|
111
|
+
EditedCursor.new(node,
|
|
112
|
+
Hole.new(@node.cons(@path.left), @path.parent, @path.right), @parent)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# (see AbstractCursor#last)
|
|
116
|
+
# @return [EditedCursor]
|
|
117
|
+
def prepend(node)
|
|
118
|
+
EditedCursor.new(node,
|
|
119
|
+
Hole.new(@path.left, @path.parent, @node.cons(@path.right)), @parent)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# (see AbstractCursor#last)
|
|
123
|
+
# @return [EditedCursor]
|
|
124
|
+
def replace(node)
|
|
125
|
+
EditedCursor.new(node, @path, @parent)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# (see AbstractCursor#last)
|
|
129
|
+
# @return [EditedCursor]
|
|
130
|
+
def delete
|
|
131
|
+
if not last?
|
|
132
|
+
# Move to `next`
|
|
133
|
+
head, *tail = @path.right
|
|
134
|
+
|
|
135
|
+
EditedCursor.new(head,
|
|
136
|
+
Hole.new(@path.left, @path.parent, tail), @parent)
|
|
137
|
+
elsif not first?
|
|
138
|
+
# Move to `prev`
|
|
139
|
+
head, *tail = @path.left
|
|
140
|
+
|
|
141
|
+
EditedCursor.new(head,
|
|
142
|
+
Hole.new(tail, @path.parent, @path.right), @parent)
|
|
143
|
+
else
|
|
144
|
+
# Deleting the only child
|
|
145
|
+
parent =
|
|
146
|
+
@parent.node.copy(:children =>
|
|
147
|
+
@path.left.reverse.concat(@path.right))
|
|
148
|
+
|
|
149
|
+
EditedCursor.new(parent, @path.parent, @parent.parent).dangle
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @endgroup
|
|
154
|
+
#########################################################################
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Zipper
|
|
6
|
+
class MemoizedCursor < AbstractCursor
|
|
7
|
+
# @return [#leaf?, #children, #copy]
|
|
8
|
+
attr_reader :node
|
|
9
|
+
|
|
10
|
+
# @return [Hole]
|
|
11
|
+
attr_reader :path
|
|
12
|
+
|
|
13
|
+
# @private
|
|
14
|
+
# @return [AbstractCursor]
|
|
15
|
+
attr_reader :parent
|
|
16
|
+
|
|
17
|
+
def initialize(node, path, parent)
|
|
18
|
+
@node, @path, @parent =
|
|
19
|
+
node, path, parent
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @group Querying the Tree Location
|
|
23
|
+
#########################################################################
|
|
24
|
+
|
|
25
|
+
# (see AbstractCursor#leaf?)
|
|
26
|
+
def leaf?
|
|
27
|
+
@node.leaf? or @node.children.empty?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# (see AbstractCursor#root?)
|
|
31
|
+
def root?
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @group Traversing the Tree
|
|
36
|
+
#########################################################################
|
|
37
|
+
|
|
38
|
+
# @return [AbstractCursor]
|
|
39
|
+
def up
|
|
40
|
+
@parent
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [MemoizedCursor]
|
|
44
|
+
def next
|
|
45
|
+
@__next ||= begin
|
|
46
|
+
if last?
|
|
47
|
+
raise Exceptions::ZipperError,
|
|
48
|
+
"cannot move to next after last node"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
head, *tail = @path.right
|
|
52
|
+
|
|
53
|
+
MemoizedCursor.new(head,
|
|
54
|
+
Hole.new(@node.cons(@path.left), @path.parent, tail), @parent)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [MemoizedCursor]
|
|
59
|
+
def prev
|
|
60
|
+
@__prev ||= begin
|
|
61
|
+
if first?
|
|
62
|
+
raise Exceptions::ZipperError,
|
|
63
|
+
"cannot move to prev before first node"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
head, *tail = @path.left
|
|
67
|
+
|
|
68
|
+
MemoizedCursor.new(head,
|
|
69
|
+
Hole.new(tail, @path.parent, @node.cons(@path.right)), @parent)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @return [MemoizedCursor]
|
|
74
|
+
def first
|
|
75
|
+
@parent.down
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @return [MemoizedCursor]
|
|
79
|
+
def last
|
|
80
|
+
current = self
|
|
81
|
+
current = current.next until current.last?
|
|
82
|
+
current
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @group Editing the Tree
|
|
86
|
+
#########################################################################
|
|
87
|
+
|
|
88
|
+
# @return [EditedCursor]
|
|
89
|
+
def append(node)
|
|
90
|
+
EditedCursor.new(node,
|
|
91
|
+
Hole.new(@node.cons(@path.left), @path.parent, @path.right), @parent)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [EditedCursor]
|
|
95
|
+
def prepend
|
|
96
|
+
EditedCursor.new(node,
|
|
97
|
+
Hole.new(@path.left, @path.parent, @node.cons(@path.right)), @parent)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @return [EditedCursor]
|
|
101
|
+
def replace(node)
|
|
102
|
+
EditedCursor.new(node, @path, @parent)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @return [EditedCursor]
|
|
106
|
+
def delete
|
|
107
|
+
if not last?
|
|
108
|
+
# Move to `next`
|
|
109
|
+
head, *tail = @path.right
|
|
110
|
+
|
|
111
|
+
EditedCursor.new(head,
|
|
112
|
+
Hole.new(@path.left, @path.parent, tail), @parent)
|
|
113
|
+
elsif not first?
|
|
114
|
+
# Move to `prev`
|
|
115
|
+
head, *tail = @path.left
|
|
116
|
+
|
|
117
|
+
EditedCursor.new(head,
|
|
118
|
+
Hole.new(tail, @path.parent, @path.right), @parent)
|
|
119
|
+
else
|
|
120
|
+
# Deleting the only child
|
|
121
|
+
parent =
|
|
122
|
+
@parent.node.copy(:children =>
|
|
123
|
+
@path.left.reverse.concat(@path.right))
|
|
124
|
+
|
|
125
|
+
EditedCursor.new(parent, @path.parent, @parent.parent).dangle
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @endgroup
|
|
130
|
+
#########################################################################
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Zipper
|
|
6
|
+
class AbstractPath
|
|
7
|
+
abstract :root?
|
|
8
|
+
|
|
9
|
+
# @return [AbstractPath]
|
|
10
|
+
abstract :parent
|
|
11
|
+
|
|
12
|
+
# Contains the node's leftward siblings, sorted nearest to furthest
|
|
13
|
+
#
|
|
14
|
+
# @return [Array<#leaf?, #children, #copy>]
|
|
15
|
+
abstract :left
|
|
16
|
+
|
|
17
|
+
# Contains the node's rightward siblings, sorted nearest to furthest
|
|
18
|
+
#
|
|
19
|
+
# @return [Array<#leaf?, #children, #copy>]
|
|
20
|
+
abstract :right
|
|
21
|
+
|
|
22
|
+
# True when the node has no rightward siblings
|
|
23
|
+
abstract :last?
|
|
24
|
+
|
|
25
|
+
# True when the node has no leftward siblings
|
|
26
|
+
abstract :first?
|
|
27
|
+
|
|
28
|
+
# Distance from the root node
|
|
29
|
+
#
|
|
30
|
+
# @return [Integer]
|
|
31
|
+
abstract :depth
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @private
|
|
35
|
+
Root = Class.new(AbstractPath) do
|
|
36
|
+
def root?
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @return self
|
|
41
|
+
def parent
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# (see AbstractPath#left)
|
|
46
|
+
def left
|
|
47
|
+
[]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# (see AbstractPath#right)
|
|
51
|
+
def right
|
|
52
|
+
[]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# (see AbstractPath#last?)
|
|
56
|
+
# @return true
|
|
57
|
+
def last?
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# (see AbstractPath#first?)
|
|
62
|
+
# @return true
|
|
63
|
+
def first?
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# (see AbstractPath#depth)
|
|
68
|
+
def depth
|
|
69
|
+
0
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def position
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @return [String]
|
|
77
|
+
def inspect
|
|
78
|
+
"root"
|
|
79
|
+
end
|
|
80
|
+
end.new
|
|
81
|
+
|
|
82
|
+
class Hole < AbstractPath
|
|
83
|
+
# (see AbstractPath#right)
|
|
84
|
+
attr_reader :left
|
|
85
|
+
|
|
86
|
+
# @return [AbstractPath]
|
|
87
|
+
attr_reader :parent
|
|
88
|
+
|
|
89
|
+
# (see AbstractPath#left)
|
|
90
|
+
attr_reader :right
|
|
91
|
+
|
|
92
|
+
def initialize(left, parent, right)
|
|
93
|
+
@left, @parent, @right =
|
|
94
|
+
left, parent, right
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def root?
|
|
98
|
+
false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# (see AbstractPath#last?)
|
|
102
|
+
def last?
|
|
103
|
+
@right.empty?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# (see AbstractPath#first?)
|
|
107
|
+
def first?
|
|
108
|
+
@left.empty?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# (see AbstractPath#depth)
|
|
112
|
+
def depth
|
|
113
|
+
1 + @parent.depth
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def position
|
|
117
|
+
@left.length
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @return [String]
|
|
121
|
+
def inspect
|
|
122
|
+
"#{@parent.inspect}/#{@left.length}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @return [Boolean]
|
|
126
|
+
def ==(other)
|
|
127
|
+
depth == other.depth and
|
|
128
|
+
position == other.position
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Stupidedi
|
|
3
|
+
using Refinements
|
|
4
|
+
|
|
5
|
+
module Zipper
|
|
6
|
+
class RootCursor < AbstractCursor
|
|
7
|
+
# @return [AbstractNode]
|
|
8
|
+
attr_reader :node
|
|
9
|
+
|
|
10
|
+
# @return [AbstractPath]
|
|
11
|
+
attr_reader :path
|
|
12
|
+
|
|
13
|
+
def initialize(node)
|
|
14
|
+
@node, @path =
|
|
15
|
+
node, Root
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @group Querying the Tree Location
|
|
19
|
+
#########################################################################
|
|
20
|
+
|
|
21
|
+
# (see AbstractCursor#depth)
|
|
22
|
+
def depth
|
|
23
|
+
0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# (see AbstractCursor#first?)
|
|
27
|
+
def first?
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# (see AbstractCursor#last?)
|
|
32
|
+
def last?
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# (see AbstractCursor#leaf?)
|
|
37
|
+
def leaf?
|
|
38
|
+
@node.leaf? or @node.children.empty?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# (see AbstractCursor#root?)
|
|
42
|
+
def root?
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @group Traversing the Tree
|
|
47
|
+
#########################################################################
|
|
48
|
+
|
|
49
|
+
# (see AbstractCursor#first)
|
|
50
|
+
def first
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# (see AbstractCursor#last)
|
|
55
|
+
def last
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# (see AbstractCursor#next)
|
|
60
|
+
# @return [void]
|
|
61
|
+
def next
|
|
62
|
+
raise Exceptions::ZipperError,
|
|
63
|
+
"root node has no siblings"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# (see AbstractCursor#prev)
|
|
67
|
+
# @return [void]
|
|
68
|
+
def prev
|
|
69
|
+
raise Exceptions::ZipperError,
|
|
70
|
+
"root node has no siblings"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# (see AbstractCursor#root)
|
|
74
|
+
# @return [RootCursor]
|
|
75
|
+
def root
|
|
76
|
+
self
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# (see AbstractCursor#up)
|
|
80
|
+
# @return [void]
|
|
81
|
+
def up
|
|
82
|
+
raise Exceptions::ZipperError,
|
|
83
|
+
"root node has no parent"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @group Editing the Tree
|
|
87
|
+
#########################################################################
|
|
88
|
+
|
|
89
|
+
# (see AbstractCursor#append)
|
|
90
|
+
# @return [void]
|
|
91
|
+
def append(node)
|
|
92
|
+
raise Exceptions::ZipperError,
|
|
93
|
+
"root node has no siblings"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# (see AbstractCursor#prepend)
|
|
97
|
+
# @return [void]
|
|
98
|
+
def prepend(node)
|
|
99
|
+
raise Exceptions::ZipperError,
|
|
100
|
+
"root node has no siblings"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# (see AbstractCursor#replace)
|
|
104
|
+
# @return [RootCursor]
|
|
105
|
+
def replace(node)
|
|
106
|
+
RootCursor.new(node)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# (see AbstractCursor#delete)
|
|
110
|
+
# @return [void]
|
|
111
|
+
def delete
|
|
112
|
+
raise Exceptions::ZipperError,
|
|
113
|
+
"cannot delete root node"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @endgroup
|
|
117
|
+
#########################################################################
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|