treetop 1.2.0 → 1.2.1
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/Rakefile +1 -1
- data/doc/contributing_and_planned_features.markdown +3 -11
- data/doc/index.markdown +65 -4
- data/doc/semantic_interpretation.markdown +3 -1
- data/doc/site.rb +79 -10
- data/doc/site/contribute.html +118 -0
- data/doc/{images/middle_backgound.png → site/images/bottom_background.png} +0 -0
- data/doc/{images → site/images}/middle_background.png +0 -0
- data/doc/{images → site/images}/paren_language_output.png +0 -0
- data/doc/site/images/pivotal.gif +0 -0
- data/doc/site/images/top_background.png +0 -0
- data/doc/site/index.html +102 -0
- data/doc/site/pitfalls_and_advanced_techniques.html +68 -0
- data/doc/site/screen.css +129 -0
- data/doc/site/semantic_interpretation.html +214 -0
- data/doc/site/syntactic_recognition.html +142 -0
- data/doc/site/using_in_ruby.html +34 -0
- data/doc/sitegen.rb +60 -0
- data/doc/syntactic_recognition.markdown +11 -14
- data/doc/using_in_ruby.markdown +7 -3
- data/lib/treetop/compiler/metagrammar.rb +2 -2
- data/lib/treetop/compiler/metagrammar.treetop +3 -3
- data/lib/treetop/compiler/node_classes.rb +1 -0
- data/lib/treetop/compiler/node_classes/character_class.rb +5 -1
- data/lib/treetop/compiler/node_classes/predicate.rb +1 -1
- data/lib/treetop/compiler/node_classes/transient_prefix.rb +9 -0
- data/lib/treetop/runtime.rb +2 -1
- 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 +40 -40
- metadata +23 -10
- data/doc/images/bottom_background.png +0 -0
- data/doc/images/top_background.png +0 -0
- data/doc/screen.css +0 -52
- data/doc/site.html +0 -34
@@ -0,0 +1,164 @@
|
|
1
|
+
class IntervalSkipList
|
2
|
+
class Node < HeadNode
|
3
|
+
attr_accessor :key
|
4
|
+
attr_reader :markers, :endpoint_of
|
5
|
+
|
6
|
+
def initialize(key, height, path)
|
7
|
+
super(height)
|
8
|
+
@key = key
|
9
|
+
@markers = []
|
10
|
+
@endpoint_of = []
|
11
|
+
update_forward_pointers(path)
|
12
|
+
promote_markers(path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def all_forward_markers
|
16
|
+
markers.flatten
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(path)
|
20
|
+
0.upto(top_level) do |i|
|
21
|
+
path[i].forward[i] = forward[i]
|
22
|
+
end
|
23
|
+
demote_markers(path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def propagate_length_change(length_change)
|
27
|
+
cur_node = self
|
28
|
+
while cur_node do
|
29
|
+
cur_node.key += length_change
|
30
|
+
cur_node = cur_node.forward[0]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def update_forward_pointers(path)
|
37
|
+
0.upto(top_level) do |i|
|
38
|
+
forward[i] = path[i].forward[i]
|
39
|
+
path[i].forward[i] = self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def promote_markers(path)
|
44
|
+
promoted = []
|
45
|
+
new_promoted = []
|
46
|
+
0.upto(top_level) do |i|
|
47
|
+
incoming_markers = path[i].forward_markers[i]
|
48
|
+
markers.concat(incoming_markers)
|
49
|
+
|
50
|
+
incoming_markers.each do |marker|
|
51
|
+
if can_be_promoted_higher?(marker, i)
|
52
|
+
new_promoted.push(marker)
|
53
|
+
forward[i].delete_marker_from_path(marker, i, forward[i+1])
|
54
|
+
else
|
55
|
+
forward_markers[i].push(marker)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
promoted.each do |marker|
|
60
|
+
if can_be_promoted_higher?(marker, i)
|
61
|
+
new_promoted.push(marker)
|
62
|
+
forward[i].delete_marker_from_path(marker, i, forward[i+1])
|
63
|
+
else
|
64
|
+
forward_markers[i].push(marker)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
promoted = new_promoted
|
69
|
+
new_promoted = []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def can_be_promoted_higher?(marker, level)
|
75
|
+
level < top_level && forward[level + 1] && forward[level + 1].markers.include?(marker)
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete_marker_from_path(marker, level, terminus)
|
79
|
+
cur_node = self
|
80
|
+
until cur_node == terminus
|
81
|
+
cur_node.forward_markers[level].delete(marker)
|
82
|
+
cur_node.markers.delete(marker)
|
83
|
+
cur_node = cur_node.forward[level]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def demote_markers(path)
|
88
|
+
demote_inbound_markers(path)
|
89
|
+
demote_outbound_markers(path)
|
90
|
+
end
|
91
|
+
|
92
|
+
def demote_inbound_markers(path)
|
93
|
+
demoted = []
|
94
|
+
new_demoted = []
|
95
|
+
|
96
|
+
top_level.downto(0) do |i|
|
97
|
+
incoming_markers = path[i].forward_markers[i].dup
|
98
|
+
incoming_markers.each do |marker|
|
99
|
+
unless forward_node_with_marker_at_or_above_level?(marker, i)
|
100
|
+
path[i].forward_markers[i].delete(marker)
|
101
|
+
new_demoted.push(marker)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
demoted.each do |marker|
|
106
|
+
path[i + 1].place_marker_on_inbound_path(marker, i, path[i])
|
107
|
+
|
108
|
+
if forward[i].markers.include?(marker)
|
109
|
+
path[i].forward_markers[i].push(marker)
|
110
|
+
else
|
111
|
+
new_demoted.push(marker)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
demoted = new_demoted
|
116
|
+
new_demoted = []
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def demote_outbound_markers(path)
|
121
|
+
demoted = []
|
122
|
+
new_demoted = []
|
123
|
+
|
124
|
+
top_level.downto(0) do |i|
|
125
|
+
forward_markers[i].each do |marker|
|
126
|
+
new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker)
|
127
|
+
end
|
128
|
+
|
129
|
+
demoted.each do |marker|
|
130
|
+
forward[i].place_marker_on_outbound_path(marker, i, forward[i + 1])
|
131
|
+
new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker)
|
132
|
+
end
|
133
|
+
|
134
|
+
demoted = new_demoted
|
135
|
+
new_demoted = []
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def forward_node_with_marker_at_or_above_level?(marker, level)
|
140
|
+
level.upto(top_level) do |i|
|
141
|
+
return true if forward[i].markers.include?(marker)
|
142
|
+
end
|
143
|
+
false
|
144
|
+
end
|
145
|
+
|
146
|
+
def place_marker_on_outbound_path(marker, level, terminus)
|
147
|
+
cur_node = self
|
148
|
+
until cur_node == terminus
|
149
|
+
cur_node.forward_markers[level].push(marker)
|
150
|
+
cur_node.markers.push(marker)
|
151
|
+
cur_node = cur_node.forward[level]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def place_marker_on_inbound_path(marker, level, terminus)
|
156
|
+
cur_node = self
|
157
|
+
until cur_node == terminus
|
158
|
+
cur_node.forward_markers[level].push(marker)
|
159
|
+
cur_node = cur_node.forward[level]
|
160
|
+
cur_node.markers.push(marker)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -1,12 +1,17 @@
|
|
1
1
|
module Treetop
|
2
2
|
module Runtime
|
3
3
|
class SyntaxNode
|
4
|
-
attr_reader :input, :interval
|
4
|
+
attr_reader :input, :interval, :elements
|
5
|
+
attr_accessor :parent
|
5
6
|
|
6
7
|
def initialize(input, interval, elements = nil)
|
7
8
|
@input = input
|
8
9
|
@interval = interval
|
9
|
-
@elements = elements
|
10
|
+
if @elements = elements
|
11
|
+
elements.each do |element|
|
12
|
+
element.parent = self
|
13
|
+
end
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
def terminal?
|
@@ -17,56 +22,51 @@ module Treetop
|
|
17
22
|
!terminal?
|
18
23
|
end
|
19
24
|
|
20
|
-
def elements
|
21
|
-
@elements
|
22
|
-
end
|
23
|
-
|
24
25
|
def text_value
|
25
26
|
input[interval]
|
26
27
|
end
|
27
28
|
|
28
29
|
def empty?
|
29
|
-
|
30
|
+
interval.first == interval.last && interval.exclude_end?
|
30
31
|
end
|
31
32
|
|
32
33
|
def extension_modules
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
local_extensions =
|
35
|
+
class <<self
|
36
|
+
included_modules-Object.included_modules
|
37
|
+
end
|
38
|
+
if local_extensions.size > 0
|
39
|
+
local_extensions
|
40
|
+
else
|
41
|
+
[] # There weren't any; must be a literal node
|
42
|
+
end
|
42
43
|
end
|
43
44
|
|
44
45
|
def inspect(indent="")
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
indent +
|
52
|
-
self.class.to_s.sub(/.*:/,'') +
|
53
|
-
em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
|
54
|
-
" offset=#{interval.first}" +
|
55
|
-
", #{tv.inspect}" +
|
56
|
-
im +
|
57
|
-
(elements && elements.size > 0 ?
|
58
|
-
":" +
|
59
|
-
(@elements||[]).map{|e|
|
60
|
-
begin
|
61
|
-
"\n"+e.inspect(indent+" ")
|
62
|
-
rescue # Defend against inspect not taking a parameter
|
63
|
-
"\n"+indent+" "+e.inspect
|
64
|
-
end
|
65
|
-
}.join("") :
|
66
|
-
""
|
67
|
-
)
|
46
|
+
em = extension_modules
|
47
|
+
interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods
|
48
|
+
im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : ""
|
49
|
+
tv = text_value
|
50
|
+
tv = "...#{tv[-20..-1]}" if tv.size > 20
|
68
51
|
|
52
|
+
indent +
|
53
|
+
self.class.to_s.sub(/.*:/,'') +
|
54
|
+
em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
|
55
|
+
" offset=#{interval.first}" +
|
56
|
+
", #{tv.inspect}" +
|
57
|
+
im +
|
58
|
+
(elements && elements.size > 0 ?
|
59
|
+
":" +
|
60
|
+
(@elements||[]).map{|e|
|
61
|
+
begin
|
62
|
+
"\n"+e.inspect(indent+" ")
|
63
|
+
rescue # Defend against inspect not taking a parameter
|
64
|
+
"\n"+indent+" "+e.inspect
|
65
|
+
end
|
66
|
+
}.join("") :
|
67
|
+
""
|
68
|
+
)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
72
|
-
end
|
72
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: treetop
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.2.
|
7
|
-
date: 2008-01
|
6
|
+
version: 1.2.1
|
7
|
+
date: 2008-02-01 00:00:00 -08:00
|
8
8
|
summary: A Ruby-based text parsing and interpretation DSL
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -63,31 +63,44 @@ files:
|
|
63
63
|
- lib/treetop/compiler/node_classes/repetition.rb
|
64
64
|
- lib/treetop/compiler/node_classes/sequence.rb
|
65
65
|
- lib/treetop/compiler/node_classes/terminal.rb
|
66
|
+
- lib/treetop/compiler/node_classes/transient_prefix.rb
|
66
67
|
- lib/treetop/compiler/node_classes/treetop_file.rb
|
67
68
|
- lib/treetop/ruby_extensions/string.rb
|
68
69
|
- lib/treetop/runtime/compiled_parser.rb
|
70
|
+
- lib/treetop/runtime/interval_skip_list
|
71
|
+
- lib/treetop/runtime/interval_skip_list.rb
|
69
72
|
- lib/treetop/runtime/node_cache.rb
|
70
73
|
- lib/treetop/runtime/parse_cache.rb
|
71
74
|
- lib/treetop/runtime/syntax_node.rb
|
72
75
|
- lib/treetop/runtime/terminal_parse_failure.rb
|
73
76
|
- lib/treetop/runtime/terminal_syntax_node.rb
|
77
|
+
- lib/treetop/runtime/interval_skip_list/head_node.rb
|
78
|
+
- lib/treetop/runtime/interval_skip_list/interval_skip_list.rb
|
79
|
+
- lib/treetop/runtime/interval_skip_list/node.rb
|
74
80
|
- bin/tt
|
75
81
|
- doc/contributing_and_planned_features.markdown
|
76
82
|
- doc/grammar_composition.markdown
|
77
|
-
- doc/images
|
78
83
|
- doc/index.markdown
|
79
84
|
- doc/pitfalls_and_advanced_techniques.markdown
|
80
|
-
- doc/screen.css
|
81
85
|
- doc/semantic_interpretation.markdown
|
82
|
-
- doc/site
|
86
|
+
- doc/site
|
83
87
|
- doc/site.rb
|
88
|
+
- doc/sitegen.rb
|
84
89
|
- doc/syntactic_recognition.markdown
|
85
90
|
- doc/using_in_ruby.markdown
|
86
|
-
- doc/
|
87
|
-
- doc/images
|
88
|
-
- doc/
|
89
|
-
- doc/
|
90
|
-
- doc/
|
91
|
+
- doc/site/contribute.html
|
92
|
+
- doc/site/images
|
93
|
+
- doc/site/index.html
|
94
|
+
- doc/site/pitfalls_and_advanced_techniques.html
|
95
|
+
- doc/site/screen.css
|
96
|
+
- doc/site/semantic_interpretation.html
|
97
|
+
- doc/site/syntactic_recognition.html
|
98
|
+
- doc/site/using_in_ruby.html
|
99
|
+
- doc/site/images/bottom_background.png
|
100
|
+
- doc/site/images/middle_background.png
|
101
|
+
- doc/site/images/paren_language_output.png
|
102
|
+
- doc/site/images/pivotal.gif
|
103
|
+
- doc/site/images/top_background.png
|
91
104
|
- examples/lambda_calculus
|
92
105
|
- examples/lambda_calculus/arithmetic.rb
|
93
106
|
- examples/lambda_calculus/arithmetic.treetop
|
Binary file
|
Binary file
|
data/doc/screen.css
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
body {
|
2
|
-
margin: 0;
|
3
|
-
padding: 0;
|
4
|
-
background: #666666;
|
5
|
-
font-family: "Lucida Grande", Geneva, Arial, Verdana, sans-serif;
|
6
|
-
color: #333333;
|
7
|
-
}
|
8
|
-
|
9
|
-
div {
|
10
|
-
margin: 0;
|
11
|
-
background-position: center;
|
12
|
-
background-repeat: none;
|
13
|
-
}
|
14
|
-
|
15
|
-
h1 {
|
16
|
-
font-size: 120%;
|
17
|
-
margin-top: 1.5em;
|
18
|
-
margin-bottom: .5em;
|
19
|
-
}
|
20
|
-
|
21
|
-
div#top {
|
22
|
-
background-image: url("images/top_background.png");
|
23
|
-
height: 200px;
|
24
|
-
width: 100%;
|
25
|
-
}
|
26
|
-
|
27
|
-
div#middle {
|
28
|
-
padding-top: 10px;
|
29
|
-
background-image: url("images/middle_background.png");
|
30
|
-
background-repeat: repeat-y;
|
31
|
-
}
|
32
|
-
|
33
|
-
div#bottom {
|
34
|
-
background-image: url("images/bottom_background.png");
|
35
|
-
height: 42px;
|
36
|
-
margin-bottom: 30px;
|
37
|
-
}
|
38
|
-
|
39
|
-
div#content {
|
40
|
-
width: 481px;
|
41
|
-
margin: 0 auto 0 auto;
|
42
|
-
padding: 0 60px 25px 60px;
|
43
|
-
}
|
44
|
-
|
45
|
-
p {
|
46
|
-
line-height: 150%;
|
47
|
-
}
|
48
|
-
|
49
|
-
p.intro_text {
|
50
|
-
color: #C45900;
|
51
|
-
font-size: 115%;
|
52
|
-
}
|
data/doc/site.html
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
<html><head><link type="text/css" href="./screen.css" rel="stylesheet"></link></head><body><div id="top"></div><div id="middle"><div id="content"><p class="intro_text">
|
2
|
-
|
3
|
-
Treetop is a language for describing languages. Combining the elegance of Ruby with cutting-edge <em>parsing expression grammars</em>, it helps you analyze syntax with revolutionarily ease.
|
4
|
-
|
5
|
-
</p>
|
6
|
-
|
7
|
-
<h1>Intuitive Grammar Specifications</h1>
|
8
|
-
|
9
|
-
<p>Treetop's packrat parsers use <em>memoization</em> to make the backtracking possible in linear time. This cuts the gordian knot of grammar design. There's no need to look ahead and no need to lex. Worry about the structure of the language, not the idiosyncrasies of the parser.</p>
|
10
|
-
|
11
|
-
<h1>Syntax-Oriented Programming</h1>
|
12
|
-
|
13
|
-
<p>Rather than implementing semantic actions that construct parse trees, define methods on the trees that Treetop automatically constructs–and write this code directly inside the grammar.</p>
|
14
|
-
|
15
|
-
<h1>Reusable, Composable Language Descriptions</h1>
|
16
|
-
|
17
|
-
<p>Break grammars into modules and compose them via Ruby's mixin semantics. Or combine grammars written by others in novel ways. Or extend existing grammars with your own syntactic constructs by overriding rules with access to a <code>super</code> keyword. Compositionally means your investment of time into grammar writing is secure–you can always extend and reuse your code.</p>
|
18
|
-
|
19
|
-
<h1>Acknowledgements</h1>
|
20
|
-
|
21
|
-
<p>First, thank you to my employer Rob Mee of Pivotal Labs for funding a substantial portion of Treetop's development. He gets it.</p>
|
22
|
-
|
23
|
-
<p>I'd also like to thank:</p>
|
24
|
-
|
25
|
-
<ul>
|
26
|
-
<li>Damon McCormick for several hours of pair programming.</li>
|
27
|
-
<li>Nick Kallen for lots of well-considered feedback and a few afternoons of programming.</li>
|
28
|
-
<li>Brian Takita for a night of pair programming.</li>
|
29
|
-
<li>Eliot Miranda for urging me rewrite as a compiler right away rather than putting it off.</li>
|
30
|
-
<li>Ryan Davis and Eric Hodel for hurting my code.</li>
|
31
|
-
<li>Dav Yaginuma for kicking me into action on my idea.</li>
|
32
|
-
<li>Bryan Ford for his seminal work on Packrat Parsers.</li>
|
33
|
-
<li>The editors of Lambda the Ultimate, where I discovered parsing expression grammars.</li>
|
34
|
-
</ul></div></div><div id="bottom"></div></body></html>
|