Class: Ibex::Codegen::CSTMetadata
- Inherits:
-
Object
- Object
- Ibex::Codegen::CSTMetadata
- Defined in:
- lib/ibex/codegen/cst_metadata.rb,
sig/ibex/codegen/cst_metadata.rbs
Overview
Builds the deterministic kind space embedded in CST-aware parser tables.
Constant Summary collapse
- TRIVIA_KINDS =
%w[ whitespace newline line_comment block_comment custom_skip skipped_tokens ].freeze
- SYNTHETIC_KINDS =
%w[ lexical_error_token missing_token error_node source_file synthetic_root ].freeze
Instance Method Summary collapse
- #append_kinds(names, additions) ⇒ Hash[String, Integer]
- #append_named_kinds(names) ⇒ Hash[String, Integer]
-
#build ⇒ metadata
Return table-ready CST metadata with stable insertion order.
- #field_slot(index, symbol_id) ⇒ field_slot
- #half_open_range(ids) ⇒ Array[Integer]
-
#initialize(grammar, trivia_policy: :leading) ⇒ CSTMetadata
constructor
A new instance of CSTMetadata.
- #named_nonterminals(named) ⇒ Hash[Integer, Integer]
- #normalize_trivia_policy(policy) ⇒ Symbol
- #repetition_extraction(symbol_id) ⇒ Symbol?
- #slot_metadata(named) ⇒ Hash[Integer, slot]
Constructor Details
#initialize(grammar, trivia_policy: :leading) ⇒ CSTMetadata
Returns a new instance of CSTMetadata.
49 50 51 52 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 49 def initialize(grammar, trivia_policy: :leading) @grammar = grammar @trivia_policy = normalize_trivia_policy(trivia_policy) end |
Instance Method Details
#append_kinds(names, additions) ⇒ Hash[String, Integer]
97 98 99 100 101 102 103 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 97 def append_kinds(names, additions) additions.to_h do |name| kind = names.length names << name.freeze [name.freeze, kind] end end |
#append_named_kinds(names) ⇒ Hash[String, Integer]
91 92 93 94 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 91 def append_named_kinds(names) node_names = @grammar.productions.filter_map { |production| production.node&.fetch(:name) }.uniq.sort append_kinds(names, node_names) end |
#build ⇒ metadata
Return table-ready CST metadata with stable insertion order.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 56 def build names = @grammar.symbols.sort_by(&:id).map(&:name) named = append_named_kinds(names) trivia = append_kinds(names, TRIVIA_KINDS) synthetic = append_kinds(names, SYNTHETIC_KINDS) terminals = @grammar.terminals.map(&:id) nonterminals = @grammar.nonterminals.map(&:id) kinds = { names: names.freeze, terminal_range: half_open_range(terminals), nonterminal_range: half_open_range(nonterminals), named: named.freeze, named_nonterminals: named_nonterminals(named).freeze, trivia: trivia.freeze, synthetic: synthetic.freeze }.freeze #: kinds = { # rubocop:disable Style/RedundantAssignment -- preserves the exact record type for Steep. version: 1, trivia_policy: @trivia_policy, kinds: kinds, slots: (named).freeze }.freeze #: metadata end |
#field_slot(index, symbol_id) ⇒ field_slot
151 152 153 154 155 156 157 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 151 def field_slot(index, symbol_id) extraction = repetition_extraction(symbol_id) return index unless extraction value = { index: index, extraction: extraction } #: field_slot value.freeze end |
#half_open_range(ids) ⇒ Array[Integer]
106 107 108 109 110 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 106 def half_open_range(ids) return [0, 0].freeze if ids.empty? [ids.min, ids.max + 1].freeze end |
#named_nonterminals(named) ⇒ Hash[Integer, Integer]
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 113 def named_nonterminals(named) result = {} #: Hash[Integer, Integer] @grammar.productions.each do |production| node = production.node next unless node kind = named.fetch(node.fetch(:name)) current = result[kind] if current && current != production.lhs raise ArgumentError, "@node #{node.fetch(:name)} spans multiple nonterminals" end result[kind] = production.lhs end result end |
#normalize_trivia_policy(policy) ⇒ Symbol
82 83 84 85 86 87 88 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 82 def normalize_trivia_policy(policy) normalized = policy.to_sym normalized = :leading if normalized == :attach return normalized if %i[leading balanced drop].include?(normalized) raise ArgumentError, "cst_trivia must be :leading, :balanced, or :drop" end |
#repetition_extraction(symbol_id) ⇒ Symbol?
160 161 162 163 164 165 166 167 168 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 160 def repetition_extraction(symbol_id) origins = @grammar.productions .select { |production| production.lhs == symbol_id } .map { |production| production.origin.fetch(:kind) }.uniq return :separated_list if origins == [:separated_list_expansion] return :repetition if (origins - %i[star_expansion plus_expansion]).empty? && !origins.empty? nil end |
#slot_metadata(named) ⇒ Hash[Integer, slot]
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/ibex/codegen/cst_metadata.rb', line 131 def (named) @grammar.productions.filter_map do |production| node = production.node next unless node fields = node.fetch(:fields).each_with_index.to_h do |name, index| [name, field_slot(index, production.rhs.fetch(index))] end.freeze [ production.id, { node_kind: named.fetch(node.fetch(:name)), node_name: node.fetch(:name), fields: fields }.freeze ] end.to_h end |