forked from nathansobo/treetop
/
syntax_node.rb
123 lines (106 loc) · 3.06 KB
/
syntax_node.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
module Treetop
module Runtime
class SyntaxNode
attr_reader :input, :interval
attr_accessor :parent
def initialize(input, interval, elements = nil)
@input = input
@interval = interval
if (@elements = elements)
@elements.each { |e| e.equal?(true) or e.parent = self }
end
end
def elements
return @elements if terminal?
# replace the character class placeholders in the sequence (lazy instantiation)
last_element = nil
@comprehensive_elements ||= @elements.map do |element|
if element == true
index = last_element ? last_element.interval.last : interval.first
element = SyntaxNode.new(input, index...(index + 1))
element.parent = self
end
last_element = element
end
@comprehensive_elements
end
def terminal?
@elements.nil?
end
def nonterminal?
!terminal?
end
def text_value
input[interval]
end
def empty?
interval.first == interval.last && interval.exclude_end?
end
def <=>(other)
self.interval.first <=> other.interval.first
end
def extension_modules
local_extensions =
class <<self
included_modules-Object.included_modules
end
if local_extensions.size > 0
local_extensions
else
[] # There weren't any; must be a literal node
end
end
def inspect_self(indent="")
em = extension_modules
interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods
im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : ""
tv = text_value
tv = "...#{tv[-20..-1]}" if tv.size > 20
indent +
self.class.to_s.sub(/.*:/,'') +
em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
" offset=#{interval.first}" +
", #{tv.inspect}" +
im
end
def inspect_children(indent="")
return '' unless elements && elements.size > 0
":" +
elements.map do |e|
begin
"\n"+e.inspect(indent+" ")
rescue # Defend against inspect not taking a parameter
"\n"+indent+" "+e.inspect
end
end.
join("")
end
def inspect(indent="")
inspect_self(indent) +
inspect_children(indent)
end
@@dot_id_counter = 0
def dot_id
@dot_id ||= @@dot_id_counter += 1
end
def write_dot(io)
io.puts "node#{dot_id} [label=\"'#{text_value}'\"];"
if nonterminal? then
elements.each do
|x|
io.puts "node#{dot_id} -> node#{x.dot_id};"
x.write_dot(io)
end
end
end
def write_dot_file(fname)
File.open(fname + ".dot","w") do
|file|
file.puts "digraph G {"
write_dot(file)
file.puts "}"
end
end
end
end
end