File: syntax_node.rb

package info (click to toggle)
ruby-treetop 1.6.14-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 956 kB
  • sloc: ruby: 8,918; makefile: 5
file content (123 lines) | stat: -rw-r--r-- 3,134 bytes parent folder | download | duplicates (4)
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