cognita-treetop 1.2.4
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.
- data/README +164 -0
- data/Rakefile +35 -0
- data/bin/tt +25 -0
- data/doc/contributing_and_planned_features.markdown +103 -0
- data/doc/grammar_composition.markdown +65 -0
- data/doc/index.markdown +90 -0
- data/doc/pitfalls_and_advanced_techniques.markdown +51 -0
- data/doc/semantic_interpretation.markdown +189 -0
- data/doc/site.rb +110 -0
- data/doc/sitegen.rb +60 -0
- data/doc/syntactic_recognition.markdown +100 -0
- data/doc/using_in_ruby.markdown +21 -0
- data/examples/lambda_calculus/arithmetic.rb +551 -0
- data/examples/lambda_calculus/arithmetic.treetop +97 -0
- data/examples/lambda_calculus/arithmetic_node_classes.rb +7 -0
- data/examples/lambda_calculus/arithmetic_test.rb +54 -0
- data/examples/lambda_calculus/lambda_calculus +0 -0
- data/examples/lambda_calculus/lambda_calculus.rb +718 -0
- data/examples/lambda_calculus/lambda_calculus.treetop +132 -0
- data/examples/lambda_calculus/lambda_calculus_node_classes.rb +5 -0
- data/examples/lambda_calculus/lambda_calculus_test.rb +89 -0
- data/examples/lambda_calculus/test_helper.rb +18 -0
- data/lib/treetop.rb +8 -0
- data/lib/treetop/bootstrap_gen_1_metagrammar.rb +45 -0
- data/lib/treetop/compiler.rb +6 -0
- data/lib/treetop/compiler/grammar_compiler.rb +40 -0
- data/lib/treetop/compiler/lexical_address_space.rb +17 -0
- data/lib/treetop/compiler/metagrammar.rb +2887 -0
- data/lib/treetop/compiler/metagrammar.treetop +404 -0
- data/lib/treetop/compiler/node_classes.rb +19 -0
- data/lib/treetop/compiler/node_classes/anything_symbol.rb +18 -0
- data/lib/treetop/compiler/node_classes/atomic_expression.rb +14 -0
- data/lib/treetop/compiler/node_classes/character_class.rb +19 -0
- data/lib/treetop/compiler/node_classes/choice.rb +31 -0
- data/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
- data/lib/treetop/compiler/node_classes/grammar.rb +28 -0
- data/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
- data/lib/treetop/compiler/node_classes/nonterminal.rb +13 -0
- data/lib/treetop/compiler/node_classes/optional.rb +19 -0
- data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
- data/lib/treetop/compiler/node_classes/parsing_expression.rb +138 -0
- data/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
- data/lib/treetop/compiler/node_classes/predicate.rb +45 -0
- data/lib/treetop/compiler/node_classes/repetition.rb +55 -0
- data/lib/treetop/compiler/node_classes/sequence.rb +68 -0
- data/lib/treetop/compiler/node_classes/terminal.rb +20 -0
- data/lib/treetop/compiler/node_classes/transient_prefix.rb +9 -0
- data/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
- data/lib/treetop/compiler/ruby_builder.rb +113 -0
- data/lib/treetop/ruby_extensions.rb +2 -0
- data/lib/treetop/ruby_extensions/string.rb +42 -0
- data/lib/treetop/runtime.rb +5 -0
- data/lib/treetop/runtime/compiled_parser.rb +87 -0
- data/lib/treetop/runtime/interval_skip_list.rb +4 -0
- data/lib/treetop/runtime/interval_skip_list/head_node.rb +15 -0
- data/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb +200 -0
- data/lib/treetop/runtime/interval_skip_list/node.rb +164 -0
- data/lib/treetop/runtime/syntax_node.rb +72 -0
- data/lib/treetop/runtime/terminal_parse_failure.rb +16 -0
- data/lib/treetop/runtime/terminal_syntax_node.rb +17 -0
- metadata +119 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
module Treetop
|
2
|
+
module Compiler
|
3
|
+
class Sequence < ParsingExpression
|
4
|
+
def compile(address, builder, parent_expression = nil)
|
5
|
+
super
|
6
|
+
begin_comment(self)
|
7
|
+
use_vars :result, :start_index, :accumulator
|
8
|
+
compile_sequence_elements(sequence_elements)
|
9
|
+
builder.if__ "#{accumulator_var}.last" do
|
10
|
+
assign_result "(#{node_class_name}).new(input, #{start_index_var}...index, #{accumulator_var})"
|
11
|
+
extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name
|
12
|
+
extend_result_with_inline_module
|
13
|
+
end
|
14
|
+
builder.else_ do
|
15
|
+
reset_index
|
16
|
+
assign_failure start_index_var
|
17
|
+
end
|
18
|
+
end_comment(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def node_class_name
|
22
|
+
node_class_declarations.node_class_name || 'SyntaxNode'
|
23
|
+
end
|
24
|
+
|
25
|
+
def compile_sequence_elements(elements)
|
26
|
+
obtain_new_subexpression_address
|
27
|
+
elements.first.compile(subexpression_address, builder)
|
28
|
+
accumulate_subexpression_result
|
29
|
+
if elements.size > 1
|
30
|
+
builder.if_ subexpression_success? do
|
31
|
+
compile_sequence_elements(elements[1..-1])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def sequence_element_accessor_module
|
37
|
+
@sequence_element_accessor_module ||= SequenceElementAccessorModule.new(sequence_elements)
|
38
|
+
end
|
39
|
+
|
40
|
+
def sequence_element_accessor_module_name
|
41
|
+
sequence_element_accessor_module.module_name
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class SequenceElementAccessorModule
|
46
|
+
include InlineModuleMixin
|
47
|
+
attr_reader :sequence_elements
|
48
|
+
|
49
|
+
def initialize(sequence_elements)
|
50
|
+
@sequence_elements = sequence_elements
|
51
|
+
end
|
52
|
+
|
53
|
+
def compile(index, rule, builder)
|
54
|
+
super
|
55
|
+
builder.module_declaration(module_name) do
|
56
|
+
sequence_elements.each_with_index do |element, index|
|
57
|
+
if element.label_name
|
58
|
+
builder.method_declaration(element.label_name) do
|
59
|
+
builder << "elements[#{index}]"
|
60
|
+
end
|
61
|
+
builder.newline unless index == sequence_elements.size - 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Treetop
|
2
|
+
module Compiler
|
3
|
+
class Terminal < AtomicExpression
|
4
|
+
def compile(address, builder, parent_expression = nil)
|
5
|
+
super
|
6
|
+
string_length = eval(text_value).length
|
7
|
+
|
8
|
+
builder.if__ "input.index(#{text_value}, index) == index" do
|
9
|
+
assign_result "(#{node_class_name}).new(input, index...(index + #{string_length}))"
|
10
|
+
extend_result_with_inline_module
|
11
|
+
builder << "@index += #{string_length}"
|
12
|
+
end
|
13
|
+
builder.else_ do
|
14
|
+
builder << "terminal_parse_failure(#{text_value})"
|
15
|
+
assign_result 'nil'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Treetop
|
2
|
+
module Compiler
|
3
|
+
class RubyBuilder
|
4
|
+
|
5
|
+
attr_reader :level, :address_space, :ruby
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@level = 0
|
9
|
+
@address_space = LexicalAddressSpace.new
|
10
|
+
@ruby = ""
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(ruby_line)
|
14
|
+
return if ruby_line.blank?
|
15
|
+
ruby << ruby_line.tabto(level) << "\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def newline
|
19
|
+
ruby << "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def indented(depth = 2)
|
23
|
+
self.in(depth)
|
24
|
+
yield
|
25
|
+
self.out(depth)
|
26
|
+
end
|
27
|
+
|
28
|
+
def class_declaration(name, &block)
|
29
|
+
self << "class #{name}"
|
30
|
+
indented(&block)
|
31
|
+
self << "end"
|
32
|
+
end
|
33
|
+
|
34
|
+
def module_declaration(name, &block)
|
35
|
+
self << "module #{name}"
|
36
|
+
indented(&block)
|
37
|
+
self << "end"
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_declaration(name, &block)
|
41
|
+
self << "def #{name}"
|
42
|
+
indented(&block)
|
43
|
+
self << "end"
|
44
|
+
end
|
45
|
+
|
46
|
+
def assign(left, right)
|
47
|
+
if left.instance_of? Array
|
48
|
+
self << "#{left.join(', ')} = #{right.join(', ')}"
|
49
|
+
else
|
50
|
+
self << "#{left} = #{right}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def extend(var, module_name)
|
55
|
+
self << "#{var}.extend(#{module_name})"
|
56
|
+
end
|
57
|
+
|
58
|
+
def accumulate(left, right)
|
59
|
+
self << "#{left} << #{right}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def if__(condition, &block)
|
63
|
+
self << "if #{condition}"
|
64
|
+
indented(&block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def if_(condition, &block)
|
68
|
+
if__(condition, &block)
|
69
|
+
self << 'end'
|
70
|
+
end
|
71
|
+
|
72
|
+
def else_(&block)
|
73
|
+
self << 'else'
|
74
|
+
indented(&block)
|
75
|
+
self << 'end'
|
76
|
+
end
|
77
|
+
|
78
|
+
def loop(&block)
|
79
|
+
self << 'loop do'
|
80
|
+
indented(&block)
|
81
|
+
self << 'end'
|
82
|
+
end
|
83
|
+
|
84
|
+
def break
|
85
|
+
self << 'break'
|
86
|
+
end
|
87
|
+
|
88
|
+
def in(depth = 2)
|
89
|
+
@level += depth
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
def out(depth = 2)
|
94
|
+
@level -= depth
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def next_address
|
99
|
+
address_space.next_address
|
100
|
+
end
|
101
|
+
|
102
|
+
def reset_addresses
|
103
|
+
address_space.reset_addresses
|
104
|
+
end
|
105
|
+
|
106
|
+
protected
|
107
|
+
|
108
|
+
def indent
|
109
|
+
" " * level
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class String
|
2
|
+
def column_of(index)
|
3
|
+
return 1 if index == 0
|
4
|
+
newline_index = rindex("\n", index - 1)
|
5
|
+
if newline_index
|
6
|
+
index - newline_index
|
7
|
+
else
|
8
|
+
index + 1
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def line_of(index)
|
13
|
+
self[0...index].count("\n") + 1
|
14
|
+
end
|
15
|
+
|
16
|
+
unless method_defined?(:blank?)
|
17
|
+
def blank?
|
18
|
+
self == ""
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# The following methods are lifted from Facets 2.0.2
|
23
|
+
def tabto(n)
|
24
|
+
if self =~ /^( *)\S/
|
25
|
+
indent(n - $1.length)
|
26
|
+
else
|
27
|
+
self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def indent(n)
|
32
|
+
if n >= 0
|
33
|
+
gsub(/^/, ' ' * n)
|
34
|
+
else
|
35
|
+
gsub(/^ {0,#{-n}}/, "")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def treetop_camelize
|
40
|
+
to_s.gsub(/\/(.?)/){ "::" + $1.upcase }.gsub(/(^|_)(.)/){ $2.upcase }
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Treetop
|
2
|
+
module Runtime
|
3
|
+
class CompiledParser
|
4
|
+
include Treetop::Runtime
|
5
|
+
|
6
|
+
attr_reader :input, :index, :terminal_failures, :max_terminal_failure_index
|
7
|
+
attr_writer :root
|
8
|
+
attr_accessor :consume_all_input
|
9
|
+
alias :consume_all_input? :consume_all_input
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
self.consume_all_input = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(input, options = {})
|
16
|
+
prepare_to_parse(input)
|
17
|
+
@index = options[:index] if options[:index]
|
18
|
+
result = send("_nt_#{root}")
|
19
|
+
return nil if (consume_all_input? && index != input.size)
|
20
|
+
return result
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure_index
|
24
|
+
max_terminal_failure_index
|
25
|
+
end
|
26
|
+
|
27
|
+
def failure_line
|
28
|
+
terminal_failures && input.line_of(failure_index)
|
29
|
+
end
|
30
|
+
|
31
|
+
def failure_column
|
32
|
+
terminal_failures && input.column_of(failure_index)
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure_reason
|
36
|
+
return nil unless (tf = terminal_failures) && tf.size > 0
|
37
|
+
"Expected " +
|
38
|
+
(tf.size == 1 ?
|
39
|
+
tf[0].expected_string :
|
40
|
+
"one of #{tf.map{|f| f.expected_string}.uniq*', '}"
|
41
|
+
) +
|
42
|
+
" at line #{failure_line}, column #{failure_column} (byte #{failure_index+1})" +
|
43
|
+
" after #{input[index...failure_index]}"
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
attr_reader :node_cache, :input_length
|
50
|
+
attr_writer :index
|
51
|
+
|
52
|
+
def prepare_to_parse(input)
|
53
|
+
@input = input
|
54
|
+
@input_length = input.length
|
55
|
+
reset_index
|
56
|
+
@node_cache = Hash.new {|hash, key| hash[key] = Hash.new}
|
57
|
+
@terminal_failures = []
|
58
|
+
@max_terminal_failure_index = 0
|
59
|
+
end
|
60
|
+
|
61
|
+
def reset_index
|
62
|
+
@index = 0
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_anything(node_class = SyntaxNode, inline_module = nil)
|
66
|
+
if index < input.length
|
67
|
+
result = node_class.new(input, index...(index + 1))
|
68
|
+
result.extend(inline_module) if inline_module
|
69
|
+
@index += 1
|
70
|
+
result
|
71
|
+
else
|
72
|
+
terminal_parse_failure("any character")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def terminal_parse_failure(expected_string)
|
77
|
+
return nil if index < max_terminal_failure_index
|
78
|
+
if index > max_terminal_failure_index
|
79
|
+
@max_terminal_failure_index = index
|
80
|
+
@terminal_failures = []
|
81
|
+
end
|
82
|
+
terminal_failures << TerminalParseFailure.new(index, expected_string)
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class IntervalSkipList
|
2
|
+
class HeadNode
|
3
|
+
attr_reader :height, :forward, :forward_markers
|
4
|
+
|
5
|
+
def initialize(height)
|
6
|
+
@height = height
|
7
|
+
@forward = Array.new(height, nil)
|
8
|
+
@forward_markers = Array.new(height) {|i| []}
|
9
|
+
end
|
10
|
+
|
11
|
+
def top_level
|
12
|
+
height - 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
class IntervalSkipList
|
2
|
+
attr_reader :probability
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@head = HeadNode.new(max_height)
|
6
|
+
@ranges = {}
|
7
|
+
@probability = 0.5
|
8
|
+
end
|
9
|
+
|
10
|
+
def max_height
|
11
|
+
3
|
12
|
+
end
|
13
|
+
|
14
|
+
def empty?
|
15
|
+
head.forward[0].nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def expire(range, length_change)
|
19
|
+
expired_markers, first_node_after_range = overlapping(range)
|
20
|
+
expired_markers.each { |marker| delete(marker) }
|
21
|
+
first_node_after_range.propagate_length_change(length_change)
|
22
|
+
end
|
23
|
+
|
24
|
+
def overlapping(range)
|
25
|
+
markers, first_node = containing_with_node(range.first)
|
26
|
+
|
27
|
+
cur_node = first_node
|
28
|
+
begin
|
29
|
+
markers.concat(cur_node.forward_markers.flatten)
|
30
|
+
cur_node = cur_node.forward[0]
|
31
|
+
end while cur_node.key < range.last
|
32
|
+
|
33
|
+
return markers.uniq, cur_node
|
34
|
+
end
|
35
|
+
|
36
|
+
def containing(n)
|
37
|
+
containing_with_node(n).first
|
38
|
+
end
|
39
|
+
|
40
|
+
def insert(range, marker)
|
41
|
+
ranges[marker] = range
|
42
|
+
first_node = insert_node(range.first)
|
43
|
+
first_node.endpoint_of.push(marker)
|
44
|
+
last_node = insert_node(range.last)
|
45
|
+
last_node.endpoint_of.push(marker)
|
46
|
+
|
47
|
+
cur_node = first_node
|
48
|
+
cur_level = first_node.top_level
|
49
|
+
while next_node_at_level_inside_range?(cur_node, cur_level, range)
|
50
|
+
while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
|
51
|
+
cur_level += 1
|
52
|
+
end
|
53
|
+
cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
|
54
|
+
end
|
55
|
+
|
56
|
+
while node_inside_range?(cur_node, range)
|
57
|
+
while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
|
58
|
+
cur_level -= 1
|
59
|
+
end
|
60
|
+
cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def delete(marker)
|
65
|
+
range = ranges[marker]
|
66
|
+
path_to_first_node = make_path
|
67
|
+
first_node = find(range.first, path_to_first_node)
|
68
|
+
|
69
|
+
cur_node = first_node
|
70
|
+
cur_level = first_node.top_level
|
71
|
+
while next_node_at_level_inside_range?(cur_node, cur_level, range)
|
72
|
+
while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
|
73
|
+
cur_level += 1
|
74
|
+
end
|
75
|
+
cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
|
76
|
+
end
|
77
|
+
|
78
|
+
while node_inside_range?(cur_node, range)
|
79
|
+
while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
|
80
|
+
cur_level -= 1
|
81
|
+
end
|
82
|
+
cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
|
83
|
+
end
|
84
|
+
last_node = cur_node
|
85
|
+
|
86
|
+
first_node.endpoint_of.delete(marker)
|
87
|
+
if first_node.endpoint_of.empty?
|
88
|
+
first_node.delete(path_to_first_node)
|
89
|
+
end
|
90
|
+
|
91
|
+
last_node.endpoint_of.delete(marker)
|
92
|
+
if last_node.endpoint_of.empty?
|
93
|
+
path_to_last_node = make_path
|
94
|
+
find(range.last, path_to_last_node)
|
95
|
+
last_node.delete(path_to_last_node)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
attr_reader :head, :ranges
|
101
|
+
|
102
|
+
def insert_node(key)
|
103
|
+
path = make_path
|
104
|
+
found_node = find(key, path)
|
105
|
+
if found_node && found_node.key == key
|
106
|
+
return found_node
|
107
|
+
else
|
108
|
+
return Node.new(key, next_node_height, path)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def containing_with_node(n)
|
113
|
+
containing = []
|
114
|
+
cur_node = head
|
115
|
+
(max_height - 1).downto(0) do |cur_level|
|
116
|
+
while (next_node = cur_node.forward[cur_level]) && next_node.key <= n
|
117
|
+
cur_node = next_node
|
118
|
+
if cur_node.key == n
|
119
|
+
return containing + (cur_node.markers - cur_node.endpoint_of), cur_node
|
120
|
+
end
|
121
|
+
end
|
122
|
+
containing.concat(cur_node.forward_markers[cur_level])
|
123
|
+
end
|
124
|
+
|
125
|
+
return containing, cur_node
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete_node(key)
|
129
|
+
path = make_path
|
130
|
+
found_node = find(key, path)
|
131
|
+
found_node.delete(path) if found_node.key == key
|
132
|
+
end
|
133
|
+
|
134
|
+
def find(key, path)
|
135
|
+
cur_node = head
|
136
|
+
(max_height - 1).downto(0) do |cur_level|
|
137
|
+
while (next_node = cur_node.forward[cur_level]) && next_node.key < key
|
138
|
+
cur_node = next_node
|
139
|
+
end
|
140
|
+
path[cur_level] = cur_node
|
141
|
+
end
|
142
|
+
cur_node.forward[0]
|
143
|
+
end
|
144
|
+
|
145
|
+
def make_path
|
146
|
+
Array.new(max_height, nil)
|
147
|
+
end
|
148
|
+
|
149
|
+
def next_node_height
|
150
|
+
height = 1
|
151
|
+
while rand < probability && height < max_height
|
152
|
+
height += 1
|
153
|
+
end
|
154
|
+
height
|
155
|
+
end
|
156
|
+
|
157
|
+
def can_ascend_from?(node, level)
|
158
|
+
level < node.top_level
|
159
|
+
end
|
160
|
+
|
161
|
+
def can_descend_from?(level)
|
162
|
+
level > 0
|
163
|
+
end
|
164
|
+
|
165
|
+
def node_inside_range?(node, range)
|
166
|
+
node.key < range.last
|
167
|
+
end
|
168
|
+
|
169
|
+
def next_node_at_level_inside_range?(node, level, range)
|
170
|
+
node.forward[level] && node.forward[level].key <= range.last
|
171
|
+
end
|
172
|
+
|
173
|
+
def next_node_at_level_outside_range?(node, level, range)
|
174
|
+
(node.forward[level].nil? || node.forward[level].key > range.last)
|
175
|
+
end
|
176
|
+
|
177
|
+
def mark_forward_path_at_level(node, level, marker)
|
178
|
+
node.forward_markers[level].push(marker)
|
179
|
+
next_node = node.forward[level]
|
180
|
+
next_node.markers.push(marker)
|
181
|
+
node = next_node
|
182
|
+
end
|
183
|
+
|
184
|
+
def unmark_forward_path_at_level(node, level, marker)
|
185
|
+
node.forward_markers[level].delete(marker)
|
186
|
+
next_node = node.forward[level]
|
187
|
+
next_node.markers.delete(marker)
|
188
|
+
node = next_node
|
189
|
+
end
|
190
|
+
|
191
|
+
def nodes
|
192
|
+
nodes = []
|
193
|
+
cur_node = head.forward[0]
|
194
|
+
until cur_node.nil?
|
195
|
+
nodes << cur_node
|
196
|
+
cur_node = cur_node.forward[0]
|
197
|
+
end
|
198
|
+
nodes
|
199
|
+
end
|
200
|
+
end
|