summaryrefslogtreecommitdiff
path: root/tool/lrama/lib/lrama/grammar/rule.rb
blob: 0e06edc80d620868b5ed6dca2d48496583212fcb (plain)
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
module Lrama
  class Grammar
    # _rhs holds original RHS element. Use rhs to refer to Symbol.
    class Rule < Struct.new(:id, :_lhs, :lhs, :lhs_tag, :_rhs, :rhs, :token_code, :position_in_original_rule_rhs, :nullable, :precedence_sym, :lineno, keyword_init: true)
      attr_accessor :original_rule

      def ==(other)
        self.class == other.class &&
        self.lhs == other.lhs &&
        self.lhs_tag == other.lhs_tag &&
        self.rhs == other.rhs &&
        self.token_code == other.token_code &&
        self.position_in_original_rule_rhs == other.position_in_original_rule_rhs &&
        self.nullable == other.nullable &&
        self.precedence_sym == other.precedence_sym &&
        self.lineno == other.lineno
      end

      # TODO: Change this to display_name
      def to_s
        l = lhs.id.s_value
        r = empty_rule? ? "ε" : rhs.map {|r| r.id.s_value }.join(" ")

        "#{l} -> #{r}"
      end

      # Used by #user_actions
      def as_comment
        l = lhs.id.s_value
        r = empty_rule? ? "%empty" : rhs.map(&:display_name).join(" ")

        "#{l}: #{r}"
      end

      def with_actions
        "#{to_s} {#{token_code&.s_value}}"
      end

      # opt_nl: ε     <-- empty_rule
      #       | '\n'  <-- not empty_rule
      def empty_rule?
        rhs.empty?
      end

      def precedence
        precedence_sym&.precedence
      end

      def initial_rule?
        id == 0
      end

      def translated_code
        return nil unless token_code

        Code::RuleAction.new(type: :rule_action, token_code: token_code, rule: self).translated_code
      end
    end
  end
end