-
Notifications
You must be signed in to change notification settings - Fork 95
/
export.rb
153 lines (123 loc) · 2.8 KB
/
export.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Allows exporting parslet grammars to other lingos.
module Parslet::Atoms
class Base
def accept(visitor)
raise NotImplementedError, "No visit method on #{self.class.name}."
end
end
class Str
def accept(visitor)
visitor.str(str)
end
end
class Entity
def accept(visitor)
visitor.entity(name, context, block)
end
end
class Named
def accept(visitor)
visitor.named(name, parslet)
end
end
class Sequence
def accept(visitor)
visitor.sequence(parslets)
end
end
class Repetition
def accept(visitor)
visitor.repetition(min, max, parslet)
end
end
class Alternative
def accept(visitor)
visitor.alternative(alternatives)
end
end
class Lookahead
def accept(visitor)
visitor.lookahead(positive, bound_parslet)
end
end
class Re
def accept(visitor)
visitor.re(match)
end
end
end
require 'set'
class Parslet::Parser
class GrammarPrintVisitor
attr_reader :output
def initialize
@output = ''
@open = Hash.new
end
def str(str)
output << "'#{str.inspect[1..-2]}'"
end
def entity(name, context, block)
@open[name] = [context, block]
output << name.to_s
end
def named(name, parslet)
parslet.accept(self)
end
def sequence(parslets)
output << '('
parslets.each do |parslet|
parslet.accept(self)
output << ' ' unless parslet == parslets.last
end
output << ')'
end
def repetition(min, max, parslet)
parslet.accept(self)
output << "{#{min}, #{max}}"
end
def alternative(alternatives)
alternatives.each do |parslet|
parslet.accept(self)
output << " / " unless parslet == alternatives.last
end
end
def lookahead(positive, bound_parslet)
output << (positive ? '&' : '!')
bound_parslet.accept(self)
end
def re(match)
output << match.inspect
end
def rules
@output = ''
seen = Set.new
loop do
remaining = @open.keys - seen.to_a
break if remaining.empty?
name = remaining.first
context, block = @open[name]
seen << name
output << " rule #{name}\n"
output << " "
context.instance_eval(&block).accept(self)
output << "\n"
output << " end\n"
end
output
end
end
# Exports this parser as a string in Treetop lingo. The resulting Treetop
# grammar will not have any actions.
#
def to_treetop
visitor = GrammarPrintVisitor.new
root.accept(visitor)
"grammar Test\n" <<
" rule root\n" <<
" " << visitor.output << "\n" <<
" end\n" <<
visitor.rules <<
"end\n"
end
end