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.
Files changed (61) hide show
  1. data/README +164 -0
  2. data/Rakefile +35 -0
  3. data/bin/tt +25 -0
  4. data/doc/contributing_and_planned_features.markdown +103 -0
  5. data/doc/grammar_composition.markdown +65 -0
  6. data/doc/index.markdown +90 -0
  7. data/doc/pitfalls_and_advanced_techniques.markdown +51 -0
  8. data/doc/semantic_interpretation.markdown +189 -0
  9. data/doc/site.rb +110 -0
  10. data/doc/sitegen.rb +60 -0
  11. data/doc/syntactic_recognition.markdown +100 -0
  12. data/doc/using_in_ruby.markdown +21 -0
  13. data/examples/lambda_calculus/arithmetic.rb +551 -0
  14. data/examples/lambda_calculus/arithmetic.treetop +97 -0
  15. data/examples/lambda_calculus/arithmetic_node_classes.rb +7 -0
  16. data/examples/lambda_calculus/arithmetic_test.rb +54 -0
  17. data/examples/lambda_calculus/lambda_calculus +0 -0
  18. data/examples/lambda_calculus/lambda_calculus.rb +718 -0
  19. data/examples/lambda_calculus/lambda_calculus.treetop +132 -0
  20. data/examples/lambda_calculus/lambda_calculus_node_classes.rb +5 -0
  21. data/examples/lambda_calculus/lambda_calculus_test.rb +89 -0
  22. data/examples/lambda_calculus/test_helper.rb +18 -0
  23. data/lib/treetop.rb +8 -0
  24. data/lib/treetop/bootstrap_gen_1_metagrammar.rb +45 -0
  25. data/lib/treetop/compiler.rb +6 -0
  26. data/lib/treetop/compiler/grammar_compiler.rb +40 -0
  27. data/lib/treetop/compiler/lexical_address_space.rb +17 -0
  28. data/lib/treetop/compiler/metagrammar.rb +2887 -0
  29. data/lib/treetop/compiler/metagrammar.treetop +404 -0
  30. data/lib/treetop/compiler/node_classes.rb +19 -0
  31. data/lib/treetop/compiler/node_classes/anything_symbol.rb +18 -0
  32. data/lib/treetop/compiler/node_classes/atomic_expression.rb +14 -0
  33. data/lib/treetop/compiler/node_classes/character_class.rb +19 -0
  34. data/lib/treetop/compiler/node_classes/choice.rb +31 -0
  35. data/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
  36. data/lib/treetop/compiler/node_classes/grammar.rb +28 -0
  37. data/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
  38. data/lib/treetop/compiler/node_classes/nonterminal.rb +13 -0
  39. data/lib/treetop/compiler/node_classes/optional.rb +19 -0
  40. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
  41. data/lib/treetop/compiler/node_classes/parsing_expression.rb +138 -0
  42. data/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
  43. data/lib/treetop/compiler/node_classes/predicate.rb +45 -0
  44. data/lib/treetop/compiler/node_classes/repetition.rb +55 -0
  45. data/lib/treetop/compiler/node_classes/sequence.rb +68 -0
  46. data/lib/treetop/compiler/node_classes/terminal.rb +20 -0
  47. data/lib/treetop/compiler/node_classes/transient_prefix.rb +9 -0
  48. data/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
  49. data/lib/treetop/compiler/ruby_builder.rb +113 -0
  50. data/lib/treetop/ruby_extensions.rb +2 -0
  51. data/lib/treetop/ruby_extensions/string.rb +42 -0
  52. data/lib/treetop/runtime.rb +5 -0
  53. data/lib/treetop/runtime/compiled_parser.rb +87 -0
  54. data/lib/treetop/runtime/interval_skip_list.rb +4 -0
  55. data/lib/treetop/runtime/interval_skip_list/head_node.rb +15 -0
  56. data/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb +200 -0
  57. data/lib/treetop/runtime/interval_skip_list/node.rb +164 -0
  58. data/lib/treetop/runtime/syntax_node.rb +72 -0
  59. data/lib/treetop/runtime/terminal_parse_failure.rb +16 -0
  60. data/lib/treetop/runtime/terminal_syntax_node.rb +17 -0
  61. 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,9 @@
1
+ module Treetop
2
+ module Compiler
3
+ class TransientPrefix < ParsingExpression
4
+ def compile(address, builder, parent_expression)
5
+ parent_expression.prefixed_expression.compile(address, builder)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Treetop
2
+ module Compiler
3
+ class TreetopFile < Runtime::SyntaxNode
4
+ def compile
5
+ (elements.map {|elt| elt.compile}).join
6
+ end
7
+ end
8
+ end
9
+ 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,2 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/ruby_extensions/string"
@@ -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,5 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/runtime/compiled_parser"
3
+ require "#{dir}/runtime/syntax_node"
4
+ require "#{dir}/runtime/terminal_parse_failure"
5
+ require "#{dir}/runtime/interval_skip_list"
@@ -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,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/interval_skip_list/interval_skip_list.rb"
3
+ require "#{dir}/interval_skip_list/head_node.rb"
4
+ require "#{dir}/interval_skip_list/node.rb"
@@ -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