File: sequence.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 (75 lines) | stat: -rw-r--r-- 2,557 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
module Treetop
  module Compiler    
    class Sequence < ParsingExpression
      def compile(address, builder, parent_expression = nil)
        super
        begin_comment(self)
        use_vars :result, :start_index, :accumulator
        compile_sequence_elements(sequence_elements)
        builder.if__ "#{accumulator_var}.last" do
          assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})"
          extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name
          extend_result_with_inline_module parent_expression
        end
        builder.else_ do
          reset_index
          assign_failure start_index_var
        end
        end_comment(self)
      end
      
      def node_class_name
        node_class_declarations.node_class_name || 'SyntaxNode'
      end
      
      def compile_sequence_elements(elements)
        obtain_new_subexpression_address
        elements.first.compile(subexpression_address, builder)
        accumulate_subexpression_result
        if elements.size > 1
          builder.if_ subexpression_success? do
            compile_sequence_elements(elements[1..-1])
          end
        end
      end
      
      def sequence_element_accessor_module
        @sequence_element_accessor_module ||= SequenceElementAccessorModule.new(sequence_elements)
      end
      
      def sequence_element_accessor_module_name
        sequence_element_accessor_module.module_name
      end

      def expected
        '"<a sequence>"'
      end
    end
    
    class SequenceElementAccessorModule
      include InlineModuleMixin   
      attr_reader :sequence_elements
      
      def initialize(sequence_elements)
        @sequence_elements = sequence_elements
      end
      
      def compile(idx, builder, rule)
        super
        builder.module_declaration(module_name) do
          elements_by_name = sequence_elements.inject({}){|h,e| (h[e.label_name.to_s] ||= []) << e; h}
          sequence_elements.each_with_index do |element, index|
            if element.label_name
              repetitions = elements_by_name[element.label_name.to_s]
              label_name = element.label_name + (repetitions.size > 1 ? (repetitions.index(element)+1).to_s : "")
              builder.method_declaration(label_name) do
                builder << "elements[#{index}]"
              end
              builder.newline unless index == sequence_elements.size - 1
            end
          end
        end
      end
    end
  end
end