Module: Ibex::Codegen::GeneratedActionABI

Defined in:
lib/ibex/codegen/generated_action_abi.rb

Overview

Selects the smallest generated semantic-action ABI that preserves the action's declared inputs. rubocop:disable Metrics/ModuleLength -- ABI proof and source rewriting must evolve together.

Defined Under Namespace

Classes: Cache

Class Method Summary collapse

Class Method Details

.borrowed_values?(production, analysis: self) ⇒ Boolean

The direct runtime can share one reduction-values array with an action and a hook installed by that action only when the action cannot mutate or retain the array itself. Element reads and parallel assignment copy values out without exposing the container.

Returns:

  • (Boolean)


86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/ibex/codegen/generated_action_abi.rb', line 86

def borrowed_values?(production, analysis: self)
  return false unless analysis.values_only?(production)

  action = production.action
  return false unless action

  maximum = production.rhs.length
  source = ActionLocations.new(action.code, maximum: maximum, location: action.location).rewrite
  return true if simple_indexed_values_action?(source)

  require "ripper"
  syntax = Object.const_get(:Ripper).__send__(:sexp, source)
  !syntax.nil? && read_only_value_references?(syntax)
end

.positional_action_source(production, analysis: self) ⇒ Object

Return semantic source rewritten for zero-to-four positional RHS arguments, or nil when the values container remains observable.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/ibex/codegen/generated_action_abi.rb', line 104

def positional_action_source(production, analysis: self)
  return nil unless analysis.values_only?(production)
  return nil unless production.rhs.length <= 4

  action = production.action
  return "" unless action
  return nil unless analysis.borrowed_values?(production)

  parameters = Array.new(production.rhs.length) { |index| "v#{index}" }
  return nil if action.named_refs.any? { |reference| parameters.include?(reference[:name]) }

  maximum = production.rhs.length
  source = ActionLocations.new(action.code, maximum: maximum, location: action.location).rewrite
  simple = fast_positional_action_source(source, parameters)
  return simple unless simple.nil?

  require "ripper"
  tokens = Object.const_get(:Ripper).__send__(:lex, source)
  return nil unless tokens.map { |_position, _event, token, _state| token }.join == source

  rewrite_positional_values(tokens, parameters)
end

.positional_values?(production) ⇒ Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/ibex/codegen/generated_action_abi.rb', line 137

def positional_values?(production)
  !positional_action_source(production).nil?
end

.values_only?(production) ⇒ Boolean

Returns:

  • (Boolean)


69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ibex/codegen/generated_action_abi.rb', line 69

def values_only?(production)
  return false if production.action&.composition

  action = production.action
  return true unless action
  return false if action.context_length.positive?

  maximum = production.rhs.length
  locations = ActionLocations.new(action.code, maximum: maximum, location: action.location)
  !locations.references? && !references_legacy_parameter?(action.code)
end