Module: Ibex::Codegen::RubyActions

Includes:
RubyAST
Included in:
Ruby
Defined in:
lib/ibex/codegen/ruby_actions.rb,
sig/ibex/codegen/ruby_actions.rbs

Overview

Semantic-action method generation shared by direct and source-mapped Ruby output.

Instance Method Summary collapse

Methods included from RubyAST

#append_ast, #append_listener, #append_listener_dispatch, #append_visit_children, #append_visitor, #ast_method_name, #ast_node_action_source, #ast_node_definitions

Instance Method Details

#action_method?(production) ⇒ Boolean

RBS:

  • (IR::Production production) -> bool

Parameters:

Returns:

  • (Boolean)


126
127
128
# File 'lib/ibex/codegen/ruby_actions.rb', line 126

def action_method?(production)
  !!(production.node || production.action || !@omit_action_call)
end

#action_method_sourceActionMethodSource

RBS:

  • () -> ActionMethodSource

Returns:



136
137
138
139
140
# File 'lib/ibex/codegen/ruby_actions.rb', line 136

def action_method_source
  @action_method_source ||= ActionMethodSource.new(
    @grammar, generated_action_abi: @generated_action_abi
  )
end

#append_action_method(lines, production) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:



115
116
117
118
119
120
121
122
123
# File 'lib/ibex/codegen/ruby_actions.rb', line 115

def append_action_method(lines, production)
  source = action_method_source.direct_action_method_source(production)
  if production.action && action_method_source.column_sensitive?(production.action.code)
    lines << source
  else
    source.lines.each { |line| lines << "  #{line.rstrip}" }
  end
  lines << ""
end

#append_actions(lines) ⇒ void

This method returns an undefined value.

RBS:

  • (Array[String] lines) -> void

Parameters:

  • lines (Array[String])


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

def append_actions(lines)
  @grammar.productions.each do |production|
    next unless action_method?(production)

    if production.node
      source = ast_node_action_source(production)
      source.lines.each { |line| lines << "  #{line.rstrip}" }
      lines << ""
    elsif composed_action?(production)
      append_composed_action_method(lines, production)
    elsif production.action && @line_convert
      append_compiled_action_method(lines, production)
    else
      append_action_method(lines, production)
    end
  end
end

#append_compiled_action_method(lines, production) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:



107
108
109
110
111
112
# File 'lib/ibex/codegen/ruby_actions.rb', line 107

def append_compiled_action_method(lines, production)
  action = production.action || raise(Ibex::Error, "missing semantic action")
  source = action_method_source.compiled_action_method_source(production)
  lines << "  class_eval(#{source.dump}, #{action.location[:file].inspect}, #{action.location[:line]})"
  lines << ""
end

#append_composed_action_method(lines, production) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:



41
42
43
44
45
46
47
48
49
# File 'lib/ibex/codegen/ruby_actions.rb', line 41

def append_composed_action_method(lines, production)
  action = production.action || raise(Ibex::Error, "missing composed semantic action")
  plan = action.composition&.dig(:plan) || raise(Ibex::Error, "missing action composition plan")
  steps = plan.fetch(:steps)
  steps.each_with_index do |step, index|
    append_composed_fragment_method(lines, production, step, index) if step[:code]
  end
  append_composed_orchestrator(lines, production, plan)
end

#append_composed_fragment_method(lines, production, step, index) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:

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


52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/ibex/codegen/ruby_actions.rb', line 52

def append_composed_fragment_method(lines, production, step, index)
  source = action_method_source.composed_fragment_method_source(production, step, index)
  if @line_convert
    location = step.fetch(:loc)
    lines << "  class_eval(#{source.dump}, #{location[:file].inspect}, #{location[:line]})"
  elsif action_method_source.column_sensitive?(step.fetch(:code))
    lines << source
  else
    source.lines.each { |line| lines << "  #{line.rstrip}" }
  end
  lines << ""
end

#append_composed_orchestrator(lines, production, plan) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:

  • lines (Array[String])
  • production (IR::Production)
  • plan (Hash[Symbol, untyped])


71
72
73
74
75
76
77
78
79
80
81
# File 'lib/ibex/codegen/ruby_actions.rb', line 71

def append_composed_orchestrator(lines, production, plan)
  lines << "  private def _ibex_action_#{production.id}" \
           "(val, _values, _ibex_locations, _ibex_location_stack, _ibex_location, " \
           "_ibex_lookahead_location)"
  lines << "    _ibex_composed_values = val.dup"
  lines << "    _ibex_composed_locations = _ibex_locations.dup"
  plan.fetch(:steps).each_with_index do |step, index|
    append_composed_step(lines, production, step, index)
  end
  lines.push("    _ibex_composed_values.last", "  end", "")
end

#append_composed_step(lines, production, step, index) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:

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


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/ibex/codegen/ruby_actions.rb', line 84

def append_composed_step(lines, production, step, index)
  inputs = step.fetch(:inputs)
  lines << "    _ibex_step_values = _ibex_composed_values.values_at(#{inputs.join(', ')})"
  lines << "    _ibex_step_locations = _ibex_composed_locations.values_at(#{inputs.join(', ')})"
  lookahead = step[:lookahead]
  boundary = lookahead ? "_ibex_locations[#{lookahead}]" : "_ibex_lookahead_location"
  lines << "    _ibex_step_location = Ibex::Runtime::LocationSpan.for_reduction(" \
           "_ibex_step_locations, lookahead: #{boundary})"
  result = if step[:code]
             stack_inputs = step.fetch(:stack_inputs)
             "#{composed_fragment_name(production, index)}(" \
               "_ibex_step_values, _values + _ibex_composed_values.values_at(#{stack_inputs.join(', ')}), " \
               "_ibex_step_locations, _ibex_location_stack + " \
               "_ibex_composed_locations.values_at(#{stack_inputs.join(', ')}), _ibex_step_location)"
           else
             "_ibex_step_values[0]"
           end
  lines << "    _ibex_composed_values << #{result}"
  lines << "    _ibex_composed_locations << _ibex_step_location"
  lines << "    return _ibex_composed_values.last if @accept_requested || @semantic_error"
end

#composed_action?(production) ⇒ Boolean

RBS:

  • (IR::Production production) -> bool

Parameters:

Returns:

  • (Boolean)


131
132
133
# File 'lib/ibex/codegen/ruby_actions.rb', line 131

def composed_action?(production)
  production.action&.composition&.dig(:plan, :version) == 1
end

#composed_fragment_name(production, index) ⇒ String

RBS:

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

Parameters:

Returns:

  • (String)


66
67
68
# File 'lib/ibex/codegen/ruby_actions.rb', line 66

def composed_fragment_name(production, index)
  action_method_source.composed_fragment_name(production, index)
end