Class: Ibex::Codegen::ActionMethodSource

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/codegen/action_method_source.rb,
sig/ibex/codegen/action_method_source.rbs

Overview

Builds semantic method source shared by runtime and static shadow output.

Instance Method Summary collapse

Constructor Details

#initialize(grammar, generated_action_abi: nil) ⇒ ActionMethodSource

Returns a new instance of ActionMethodSource.

RBS:

  • (IR::Grammar grammar, ?generated_action_abi: GeneratedActionABI::Cache?) -> void

Parameters:



15
16
17
18
# File 'lib/ibex/codegen/action_method_source.rb', line 15

def initialize(grammar, generated_action_abi: nil)
  @grammar = grammar
  @generated_action_abi = generated_action_abi || GeneratedActionABI::Cache.new
end

Instance Method Details

#action_parameters(production) ⇒ String

RBS:

  • (IR::Production production) -> String

Parameters:

Returns:

  • (String)


107
108
109
110
111
112
113
114
115
# File 'lib/ibex/codegen/action_method_source.rb', line 107

def action_parameters(production)
  if @generated_action_abi.positional_values?(production)
    parameters = Array.new(production.rhs.length) { |index| "v#{index}" }
    return "(#{parameters.join(', ')})"
  end
  return "(val)" if @generated_action_abi.values_only?(production)

  "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location)"
end

#append_action_body(source, production, action) ⇒ void

This method returns an undefined value.

RBS:

  • (String source, IR::Production production, IR::Action action) -> void

Parameters:



169
170
171
172
173
# File 'lib/ibex/codegen/action_method_source.rb', line 169

def append_action_body(source, production, action)
  source << "result = #{default_value_expression(production)}; " if @grammar.options[:result_var]
  source << semantic_action_code(production, action)
  source << "\nresult" if @grammar.options[:result_var]
end

#append_direct_action_body(lines, production, action) ⇒ void

This method returns an undefined value.

RBS:

  • (Array[String] lines, IR::Production production, IR::Action? action) -> void

Parameters:



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/ibex/codegen/action_method_source.rb', line 176

def append_direct_action_body(lines, production, action)
  unless action
    lines << "  #{default_value_expression(production)}"
    return
  end

  lines << "  result = #{default_value_expression(production)}" if @grammar.options[:result_var]
  semantic_code = semantic_action_code(production, action)
  if column_sensitive?(semantic_code)
    lines << semantic_code
  else
    semantic_code.lines.each { |line| lines << "  #{line.rstrip}" }
  end
  lines << "  result" if @grammar.options[:result_var]
end

#append_direct_parameter_values(lines, production:) ⇒ void

This method returns an undefined value.

RBS:

  • (Array[String] lines, production: IR::Production) -> void

Parameters:



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/ibex/codegen/action_method_source.rb', line 139

def append_direct_parameter_values(lines, production:)
  excluded = if @generated_action_abi.positional_values?(production)
               Array.new(production.rhs.length) { |index| "v#{index}" }
             else
               [] #: Array[String]
             end
  @grammar.parser_parameters.each do |parameter|
    next if excluded.include?(parameter[:name])

    lines << "  #{parameter[:name]} = @#{parameter[:name]}"
  end
end

#append_named_values(source, named_refs) ⇒ void

This method returns an undefined value.

RBS:

  • (String source, Array[IR::named_ref] named_refs) -> void

Parameters:

  • source (String)
  • named_refs (Array[IR::named_ref])


161
162
163
164
165
166
# File 'lib/ibex/codegen/action_method_source.rb', line 161

def append_named_values(source, named_refs)
  return if named_refs.empty?

  names = named_refs.map { |reference| reference[:name] }
  source << "_ibex_named_values = [#{names.join(', ')}]; "
end

#append_parameter_values(source, production: nil) ⇒ void

This method returns an undefined value.

RBS:

  • (String source, ?production: IR::Production?) -> void

Parameters:

  • source (String)
  • production: (IR::Production, nil) (defaults to: nil)


125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/ibex/codegen/action_method_source.rb', line 125

def append_parameter_values(source, production: nil)
  excluded = if production && @generated_action_abi.positional_values?(production)
               Array.new(production.rhs.length) { |index| "v#{index}" }
             else
               [] #: Array[String]
             end
  @grammar.parser_parameters.each do |parameter|
    next if excluded.include?(parameter[:name])

    source << "#{parameter[:name]} = @#{parameter[:name]}; "
  end
end

#column_sensitive?(source) ⇒ Boolean

RBS:

  • (String source) -> bool

Parameters:

  • source (String)

Returns:

  • (Boolean)


95
96
97
98
99
100
101
102
# File 'lib/ibex/codegen/action_method_source.rb', line 95

def column_sensitive?(source)
  return false unless source.include?("<<")

  require "ripper"
  tokens = Object.const_get(:Ripper).__send__(:lex, source)
  # @type var tokens: Array[[[Integer, Integer], Symbol, String, untyped]]
  tokens.any? { |_position, event, _token, _state| event == :on_heredoc_beg }
end

#compiled_action_method_source(production) ⇒ String

RBS:

  • (IR::Production production) -> String

Parameters:

Returns:

  • (String)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ibex/codegen/action_method_source.rb', line 45

def compiled_action_method_source(production)
  action = production.action
  source = "private def _ibex_action_#{production.id}#{action_parameters(production)}; "
  append_parameter_values(source, production: production)
  return "#{source}#{default_value_expression(production)}\nend" unless action

  if action.context_length.positive?
    source << "val = _values.last(#{action.context_length}); "
    source << "_ibex_locations = _ibex_location_stack.last(#{action.context_length}); "
  end
  action.named_refs.each do |reference|
    source << "#{reference[:name]} = #{value_expression(production, reference[:index])}; "
  end
  append_named_values(source, action.named_refs)
  append_action_body(source, production, action)
  source << "\nend"
end

#composed_fragment_method_source(production, step, index) ⇒ String

RBS:

  • (IR::Production production, Hash[Symbol, untyped] step, Integer index) -> String

Parameters:

  • production (IR::Production)
  • step (Hash[Symbol, untyped])
  • index (Integer)

Returns:

  • (String)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ibex/codegen/action_method_source.rb', line 21

def composed_fragment_method_source(production, step, index)
  source = "private def #{composed_fragment_name(production, index)}" \
           "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location); "
  append_parameter_values(source)
  context_length = step.fetch(:context_length)
  if context_length.positive?
    source << "val = _values.last(#{context_length}); "
    source << "_ibex_locations = _ibex_location_stack.last(#{context_length}); "
  end
  named_refs = step.fetch(:named_refs)
  named_refs.each { |reference| source << "#{reference[:name]} = val[#{reference[:index]}]; " }
  append_named_values(source, named_refs)
  source << "result = val[0]; " if step.fetch(:result_var)
  source << composed_semantic_code(step)
  source << "\nresult" if step.fetch(:result_var)
  source << "\nend"
end

#composed_fragment_name(production, index) ⇒ String

RBS:

  • (IR::Production production, Integer index) -> String

Parameters:

Returns:

  • (String)


40
41
42
# File 'lib/ibex/codegen/action_method_source.rb', line 40

def composed_fragment_name(production, index)
  "_ibex_inline_fragment_#{production.id}_#{index}"
end

#composed_semantic_code(step) ⇒ String

RBS:

  • (Hash[Symbol, untyped] step) -> String

Parameters:

  • step (Hash[Symbol, untyped])

Returns:

  • (String)


153
154
155
156
157
158
# File 'lib/ibex/codegen/action_method_source.rb', line 153

def composed_semantic_code(step)
  maximum = [step.fetch(:inputs).length, step.fetch(:context_length)].max
  ActionLocations.new(
    step.fetch(:code), maximum: maximum, location: step.fetch(:loc)
  ).rewrite
end

#default_value_expression(production) ⇒ String

RBS:

  • (IR::Production production) -> String

Parameters:

Returns:

  • (String)


202
203
204
205
206
207
# File 'lib/ibex/codegen/action_method_source.rb', line 202

def default_value_expression(production)
  return "nil" if production.rhs.empty?
  return "v0" if @generated_action_abi.positional_values?(production)

  "val[0]"
end

#direct_action_method_source(production) ⇒ String

RBS:

  • (IR::Production production) -> String

Parameters:

Returns:

  • (String)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/ibex/codegen/action_method_source.rb', line 64

def direct_action_method_source(production)
  action = production.action
  lines = [
    "private def _ibex_action_#{production.id}#{action_parameters(production)}"
  ]
  append_direct_parameter_values(lines, production: production)
  if action&.context_length&.positive?
    lines << "  val = _values.last(#{action.context_length})"
    lines << "  _ibex_locations = _ibex_location_stack.last(#{action.context_length})"
  end
  if action&.named_refs&.any?
    action.named_refs.each do |reference|
      lines << "  #{reference[:name]} = #{value_expression(production, reference[:index])}"
    end
    names = action.named_refs.map { |reference| reference[:name] }
    lines << "  _ibex_named_values = [#{names.join(', ')}]"
  end
  append_direct_action_body(lines, production, action)
  lines << "end"
  lines.join("\n")
end

#semantic_action_code(production, action) ⇒ String

RBS:

  • (IR::Production production, IR::Action action) -> String

Parameters:

Returns:

  • (String)


193
194
195
196
197
198
199
# File 'lib/ibex/codegen/action_method_source.rb', line 193

def semantic_action_code(production, action)
  positional = @generated_action_abi.positional_action_source(production)
  return positional unless positional.nil?

  maximum = action.context_length.positive? ? action.context_length : production.rhs.length
  ActionLocations.new(action.code, maximum: maximum, location: action.location).rewrite
end

#value_expression(production, index) ⇒ String

RBS:

  • (IR::Production production, Integer index) -> String

Parameters:

Returns:

  • (String)


118
119
120
121
122
# File 'lib/ibex/codegen/action_method_source.rb', line 118

def value_expression(production, index)
  return "v#{index}" if @generated_action_abi.positional_values?(production)

  "val[#{index}]"
end

#value_printer_method_source(symbol_id, printer) ⇒ String

RBS:

  • (Integer symbol_id, IR::value_printer printer) -> String

Parameters:

  • symbol_id (Integer)
  • printer (IR::value_printer)

Returns:

  • (String)


87
88
89
90
91
92
# File 'lib/ibex/codegen/action_method_source.rb', line 87

def value_printer_method_source(symbol_id, printer)
  source = "private def _ibex_value_printer_#{symbol_id}(value); "
  append_parameter_values(source)
  source << printer[:code]
  source << "\nend"
end