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)


129
130
131
# File 'lib/ibex/codegen/ruby_actions.rb', line 129

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

#action_method_sourceActionMethodSource

RBS:

  • () -> ActionMethodSource

Returns:



139
140
141
142
143
# File 'lib/ibex/codegen/ruby_actions.rb', line 139

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:



118
119
120
121
122
123
124
125
126
# File 'lib/ibex/codegen/ruby_actions.rb', line 118

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:



110
111
112
113
114
115
# File 'lib/ibex/codegen/ruby_actions.rb', line 110

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, IR::action_composition_step step, Integer index) -> void

Parameters:

  • lines (Array[String])
  • production (IR::Production)
  • step (IR::action_composition_step)
  • index (Integer)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 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]})"
  else
    code = step.fetch(:code) #: String
    if action_method_source.column_sensitive?(code)
      lines << source
    else
      source.lines.each { |line| lines << "  #{line.rstrip}" }
    end
  end
  lines << ""
end

#append_composed_orchestrator(lines, production, plan) ⇒ void

This method returns an undefined value.

RBS:

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

Parameters:

  • lines (Array[String])
  • production (IR::Production)
  • plan (IR::action_composition_plan)


74
75
76
77
78
79
80
81
82
83
84
# File 'lib/ibex/codegen/ruby_actions.rb', line 74

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, IR::action_composition_step step, Integer index) -> void

Parameters:

  • lines (Array[String])
  • production (IR::Production)
  • step (IR::action_composition_step)
  • index (Integer)


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

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)


134
135
136
# File 'lib/ibex/codegen/ruby_actions.rb', line 134

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)


69
70
71
# File 'lib/ibex/codegen/ruby_actions.rb', line 69

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