Module: Ibex::NormalizeDiagnostics
- Included in:
- Normalizer
- Defined in:
- lib/ibex/normalize/diagnostics.rb,
sig/ibex/normalize/diagnostics.rbs
Overview
Static grammar diagnostics used by Normalizer.
Instance Method Summary collapse
- #productive_terminal?(grammar_symbol) ⇒ Boolean
- #productive_terminal_ids ⇒ Hash[Integer, true]
- #reachable_symbol_ids ⇒ Hash[Integer, true]
- #validate_grammar ⇒ void
- #validate_symbol_metadata ⇒ void
- #warn_duplicate_productions ⇒ void
- #warn_empty_language ⇒ void
- #warn_unreachable_nonterminals ⇒ void
- #warn_unreachable_terminals ⇒ void
- #warn_unused_precedence ⇒ void
- #warn_unused_terminals ⇒ void
Instance Method Details
#productive_terminal?(grammar_symbol) ⇒ Boolean
164 165 166 167 |
# File 'lib/ibex/normalize/diagnostics.rb', line 164 def productive_terminal?(grammar_symbol) # @type self: Normalizer grammar_symbol.terminal? && !grammar_symbol.reserved end |
#productive_terminal_ids ⇒ Hash[Integer, true]
157 158 159 160 161 |
# File 'lib/ibex/normalize/diagnostics.rb', line 157 def productive_terminal_ids # @type self: Normalizer symbols = @symbols #: Array[IR::GrammarSymbol] symbols.select { |grammar_symbol| productive_terminal?(grammar_symbol) }.to_h { |symbol| [symbol.id, true] } end |
#reachable_symbol_ids ⇒ Hash[Integer, true]
66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/ibex/normalize/diagnostics.rb', line 66 def reachable_symbol_ids # @type self: Normalizer start_names = @start_names #: Array[String] productions = @productions #: Array[IR::Production] starts = start_names.map { |name| required_symbol(name).id } reachable = starts.to_h { |id| [id, true] } #: Hash[Integer, true] loop do before = reachable.length productions.select { |production| reachable.key?(production.lhs) }.each do |production| production.rhs.each { |id| reachable[id] = true } end return reachable if reachable.length == before end end |
#validate_grammar ⇒ void
This method returns an undefined value.
9 10 11 12 13 14 15 16 17 18 |
# File 'lib/ibex/normalize/diagnostics.rb', line 9 def validate_grammar # @type self: Normalizer warn_duplicate_productions warn_unreachable_nonterminals warn_unreachable_terminals warn_unused_terminals warn_unused_precedence warn_empty_language end |
#validate_symbol_metadata ⇒ void
This method returns an undefined value.
21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/ibex/normalize/diagnostics.rb', line 21 def # @type self: Normalizer display_locations = @display_name_locations #: Hash[String, IR::location] semantic_locations = @semantic_type_locations #: Hash[String, IR::location] inline_rule_names = @inline_rule_names #: Set[String] { display: display_locations, type: semantic_locations }.each do |label, locations| locations.each do |name, location| fail_hash(location, "#{label} declaration references undefined symbol #{name}") unless symbol(name) || parameter_template?(name) || (label == :type && inline_rule_names.include?(name)) end end end |
#warn_duplicate_productions ⇒ void
This method returns an undefined value.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/ibex/normalize/diagnostics.rb', line 35 def warn_duplicate_productions # @type self: Normalizer productions = @productions #: Array[IR::Production] warnings = @warnings #: Array[IR::grammar_warning] seen = {} #: Hash[[Integer, Array[Integer]], Integer] productions.each do |production| signature = [production.lhs, production.rhs] #: [Integer, Array[Integer]] if seen.key?(signature) location = production.origin[:loc] #: IR::location? warnings << { type: :duplicate_production, production: production.id, original: seen[signature], loc: location } else seen[signature] = production.id end end end |
#warn_empty_language ⇒ void
This method returns an undefined value.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/ibex/normalize/diagnostics.rb', line 135 def warn_empty_language # @type self: Normalizer productions = @productions #: Array[IR::Production] start_names = @start_names #: Array[String] warnings = @warnings #: Array[IR::grammar_warning] productive = productive_terminal_ids loop do before = productive.length productions.each do |production| productive[production.lhs] = true if production.rhs.all? { |id| productive.key?(id) } end break if productive.length == before end start_names.each do |name| next if productive.key?(required_symbol(name).id) start_symbol = required_symbol(name) warnings << { type: :empty_language, symbol: name, loc: start_symbol.location } end end |
#warn_unreachable_nonterminals ⇒ void
This method returns an undefined value.
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/ibex/normalize/diagnostics.rb', line 53 def warn_unreachable_nonterminals # @type self: Normalizer symbols = @symbols #: Array[IR::GrammarSymbol] warnings = @warnings #: Array[IR::grammar_warning] reachable = reachable_symbol_ids symbols.select(&:nonterminal?).each do |grammar_symbol| next if reachable.key?(grammar_symbol.id) || grammar_symbol.name.start_with?("$") warnings << { type: :unreachable_nonterminal, symbol: grammar_symbol.name, loc: grammar_symbol.location } end end |
#warn_unreachable_terminals ⇒ void
This method returns an undefined value.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/ibex/normalize/diagnostics.rb', line 97 def warn_unreachable_terminals # @type self: Normalizer productions = @productions #: Array[IR::Production] declared_tokens = @declared_tokens #: Hash[String, IR::location] warnings = @warnings #: Array[IR::grammar_warning] reachable = reachable_symbol_ids used = productions.flat_map(&:rhs).to_h { |id| [id, true] } #: Hash[Integer, true] declared_tokens.each_key do |name| grammar_symbol = required_symbol(name) next unless used.key?(grammar_symbol.id) next if reachable.key?(grammar_symbol.id) warnings << { type: :unreachable_terminal, symbol: name, loc: declared_tokens[name] } end end |
#warn_unused_precedence ⇒ void
This method returns an undefined value.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/ibex/normalize/diagnostics.rb', line 114 def warn_unused_precedence # @type self: Normalizer productions = @productions #: Array[IR::Production] precedence = @precedence #: Hash[String, IR::precedence] precedence_locations = @precedence_locations #: Hash[String, IR::location] warnings = @warnings #: Array[IR::grammar_warning] referenced = {} # @type var referenced: Hash[Integer, true] productions.each do |production| symbol_ids = referenced production.rhs.each { |id| symbol_ids[id] = true } symbol_ids[production.precedence_override] = true if production.precedence_override end precedence.each_key do |name| grammar_symbol = required_symbol(name) next if referenced.key?(grammar_symbol.id) warnings << { type: :unused_precedence, symbol: name, loc: precedence_locations[name] } end end |
#warn_unused_terminals ⇒ void
This method returns an undefined value.
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/ibex/normalize/diagnostics.rb', line 82 def warn_unused_terminals # @type self: Normalizer productions = @productions #: Array[IR::Production] symbols = @symbols #: Array[IR::GrammarSymbol] precedence = @precedence #: Hash[String, IR::precedence] warnings = @warnings #: Array[IR::grammar_warning] used = productions.flat_map(&:rhs).to_h { |id| [id, true] } #: Hash[Integer, true] symbols.select(&:terminal?).each do |grammar_symbol| next if grammar_symbol.reserved || used.key?(grammar_symbol.id) || precedence.key?(grammar_symbol.name) warnings << { type: :unused_terminal, symbol: grammar_symbol.name, loc: grammar_symbol.location } end end |