Class: Ibex::TableArtifact::Builder
- Inherits:
-
Object
- Object
- Ibex::TableArtifact::Builder
- Includes:
- CSTProjection
- Defined in:
- lib/ibex/table_artifact/builder.rb,
sig/ibex/table_artifact/builder.rbs
Overview
Projects validated Automaton IR into an action-free executable sidecar.
Constant Summary collapse
- REPRESENTATIONS =
%i[plain compact].freeze
Instance Method Summary collapse
- #action_slot?(production) ⇒ Boolean
- #action_table(table) ⇒ json_hash
- #automaton_digest ⇒ String
- #build ⇒ Document
- #build_cost(payload) ⇒ json_hash
- #build_payload(source_identity) ⇒ json_hash
- #compact_action_table(table) ⇒ json_hash
- #compact_goto_table(table) ⇒ json_hash
- #effective_cst_trivia(requested) ⇒ Symbol
- #entry_states ⇒ Array[json_hash]
- #goto_table(table) ⇒ json_hash
-
#initialize(automaton, representation: :compact, cst_trivia: nil, omit_action_call: nil) ⇒ Builder
constructor
A new instance of Builder.
- #lookup_cost ⇒ String
- #occupied_cells(table, values_key) ⇒ Integer
- #productions ⇒ Array[json_hash]
- #recognition_cost ⇒ String
- #recovery ⇒ json_hash
- #semantic_actions ⇒ json_hash
- #symbols ⇒ Array[json_hash]
- #table_format ⇒ json_hash
- #tables ⇒ json_hash
- #tokens ⇒ Array[json_hash]
Constructor Details
#initialize(automaton, representation: :compact, cst_trivia: nil, omit_action_call: nil) ⇒ Builder
Returns a new instance of Builder.
21 22 23 24 25 26 27 28 29 30 |
# File 'lib/ibex/table_artifact/builder.rb', line 21 def initialize(automaton, representation: :compact, cst_trivia: nil, omit_action_call: nil) @automaton = automaton @grammar = automaton.grammar @representation = representation.to_sym @cst_trivia = effective_cst_trivia(cst_trivia) @omit_action_call = omit_action_call.nil? ? @grammar..fetch(:omit_action_call) : omit_action_call return if REPRESENTATIONS.include?(@representation) raise ArgumentError, "representation must be :plain or :compact" end |
Instance Method Details
#action_slot?(production) ⇒ Boolean
185 186 187 |
# File 'lib/ibex/table_artifact/builder.rb', line 185 def action_slot?(production) !!(production.node || production.action || !@omit_action_call) end |
#action_table(table) ⇒ json_hash
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/ibex/table_artifact/builder.rb', line 124 def action_table(table) return compact_action_table(table) if table.is_a?(Tables::CompactActions) { "encoding" => "signed-sparse-rows-v1", "rows" => table.map do |row| row.sort.map { |token_id, action| { "token_id" => token_id, "code" => Tables::CompactActions.pack(action) } } end } end |
#automaton_digest ⇒ String
74 75 76 |
# File 'lib/ibex/table_artifact/builder.rb', line 74 def automaton_digest "sha256:#{Digest::SHA256.hexdigest(IR::Serialize.dump(@automaton))}" end |
#build ⇒ Document
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/ibex/table_artifact/builder.rb', line 33 def build source_identity = { "grammar_digest" => @automaton.grammar_digest, "automaton_digest" => automaton_digest } payload = build_payload(source_identity) cost = build_cost(payload) identity = source_identity.merge( "payload_digest" => Serializer.digest(payload), "cst_metadata_digest" => Serializer.digest(payload.fetch("cst")), "recovery_metadata_digest" => Serializer.digest(payload.fetch("recovery")) ) Document.new( "artifact_type" => ARTIFACT_TYPE, "schema_version" => SCHEMA_VERSION, "identity" => identity, "payload" => payload, "cost" => cost ) end |
#build_cost(payload) ⇒ json_hash
211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/ibex/table_artifact/builder.rb', line 211 def build_cost(payload) tables = payload.fetch("tables") #: json_hash action_table = tables.fetch("actions") #: json_hash goto_table = tables.fetch("gotos") #: json_hash { "canonical_payload_bytes" => Serializer.compact(payload).bytesize, "action_cells" => occupied_cells(action_table, "codes"), "goto_cells" => occupied_cells(goto_table, "values"), "lookup_cost" => lookup_cost, "recognition_cost" => recognition_cost, "measurement" => "not-measured", "bounded_by_max_steps" => true } end |
#build_payload(source_identity) ⇒ json_hash
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/ibex/table_artifact/builder.rb', line 57 def build_payload(source_identity) { "table_format" => table_format, "source" => source_identity, "state_count" => @automaton.states.length, "symbols" => symbols, "tokens" => tokens, "entry_states" => entry_states, "tables" => tables, "productions" => productions, "cst" => cst, "recovery" => recovery, "semantic_actions" => semantic_actions } end |
#compact_action_table(table) ⇒ json_hash
136 137 138 139 140 141 142 143 144 145 |
# File 'lib/ibex/table_artifact/builder.rb', line 136 def compact_action_table(table) { "encoding" => "signed-row-displacement-v1", "row_count" => table.row_count, "column_count" => table.column_count, "offsets" => table.offsets, "codes" => table.codes, "checks" => table.checks } end |
#compact_goto_table(table) ⇒ json_hash
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/ibex/table_artifact/builder.rb', line 160 def compact_goto_table(table) { "encoding" => "row-displacement-v1", "row_count" => table.row_count, "dense_width" => table.dense_width, "offsets" => table.offsets, "values" => table.values, "checks" => table.checks } end |
#effective_cst_trivia(requested) ⇒ Symbol
255 256 257 258 259 260 261 262 263 |
# File 'lib/ibex/table_artifact/builder.rb', line 255 def effective_cst_trivia(requested) contract_entry = @grammar.parser_contract&.cst_trivia persisted = contract_entry.value if contract_entry&.explicit if requested && persisted && requested.to_sym != persisted raise ArgumentError, "cst_trivia conflicts with the persisted parser contract" end (requested || persisted || :leading).to_sym end |
#entry_states ⇒ Array[json_hash]
109 110 111 |
# File 'lib/ibex/table_artifact/builder.rb', line 109 def entry_states @automaton.entry_states.map { |name, state| { "name" => name, "state" => state } } end |
#goto_table(table) ⇒ json_hash
148 149 150 151 152 153 154 155 156 157 |
# File 'lib/ibex/table_artifact/builder.rb', line 148 def goto_table(table) return compact_goto_table(table) if table.is_a?(Tables::Compact) { "encoding" => "sparse-rows-v1", "rows" => table.map do |row| row.sort.map { |symbol_id, state| { "symbol_id" => symbol_id, "state" => state } } end } end |
#lookup_cost ⇒ String
238 239 240 241 242 |
# File 'lib/ibex/table_artifact/builder.rb', line 238 def lookup_cost return "O(1) row-displacement probe" if @representation == :compact "O(log row width) binary search" end |
#occupied_cells(table, values_key) ⇒ Integer
227 228 229 230 231 232 233 234 235 |
# File 'lib/ibex/table_artifact/builder.rb', line 227 def occupied_cells(table, values_key) if table.key?("rows") rows = table.fetch("rows") #: Array[json_value] return rows.sum { |row| row.is_a?(Array) ? row.length : 0 } end values = table.fetch(values_key) #: Array[json_value] values.compact.length end |
#productions ⇒ Array[json_hash]
172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/ibex/table_artifact/builder.rb', line 172 def productions @grammar.productions.sort_by(&:id).map do |production| { "id" => production.id, "lhs" => production.lhs, "rhs" => production.rhs, "rhs_length" => production.rhs.length, "action_slot" => action_slot?(production) ? production.id : nil } end end |
#recognition_cost ⇒ String
245 246 247 248 249 250 251 252 |
# File 'lib/ibex/table_artifact/builder.rb', line 245 def recognition_cost prefix = if @representation == :compact "O(input tokens + reductions)" else "O((input tokens + reductions) * log maximum row width)" end "#{prefix}; lexer, recovery search, and semantic actions excluded" end |
#recovery ⇒ json_hash
199 200 201 202 203 204 205 206 207 208 |
# File 'lib/ibex/table_artifact/builder.rb', line 199 def recovery sync_tokens = @grammar.recovery.fetch(:sync_tokens) #: Array[String] on_error_reduce = @grammar.recovery.fetch(:on_error_reduce) #: Array[Array[String]] { "sync_token_ids" => sync_tokens.map { |name| @grammar.symbol(name).id }, "on_error_reduce_symbol_ids" => on_error_reduce.map do |group| group.map { |name| @grammar.symbol(name).id } end } end |
#semantic_actions ⇒ json_hash
190 191 192 193 194 195 196 |
# File 'lib/ibex/table_artifact/builder.rb', line 190 def semantic_actions { "binding" => "opaque-wrapper-production-id-v1", "verified" => false, "slots" => @grammar.productions.select { |production| action_slot?(production) }.map(&:id) } end |
#symbols ⇒ Array[json_hash]
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ibex/table_artifact/builder.rb', line 90 def symbols @grammar.symbols.sort_by(&:id).map do |symbol| { "id" => symbol.id, "name" => symbol.name, "kind" => symbol.kind.to_s, "display_name" => symbol.display_name } end end |
#table_format ⇒ json_hash
79 80 81 82 83 84 85 86 87 |
# File 'lib/ibex/table_artifact/builder.rb', line 79 def table_format { "family" => "ibex-runtime-parser-table", "version" => Runtime::PARSER_TABLE_FORMAT_VERSION, "representation" => @representation.to_s, "action_encoding" => @representation == :compact ? "signed-row-displacement-v1" : "signed-sparse-rows-v1", "goto_encoding" => @representation == :compact ? "row-displacement-v1" : "sparse-rows-v1" } end |
#tables ⇒ json_hash
114 115 116 117 118 119 120 121 |
# File 'lib/ibex/table_artifact/builder.rb', line 114 def tables table_set = Tables.build(@automaton, format: @representation) #: Tables::TableSet { "actions" => action_table(table_set.actions), "gotos" => goto_table(table_set.gotos), "default_actions" => table_set.default_actions.map { |action| Tables::CompactActions.pack(action) } } end |
#tokens ⇒ Array[json_hash]
102 103 104 105 106 |
# File 'lib/ibex/table_artifact/builder.rb', line 102 def tokens @grammar.terminals.sort_by(&:id).map do |symbol| { "id" => symbol.id, "name" => symbol.name, "display_name" => symbol.display_name } end end |