Module: Ibex::Codegen::RubySyntax

Included in:
Ruby
Defined in:
lib/ibex/codegen/ruby_syntax.rb,
sig/ibex/codegen/ruby_syntax.rbs

Overview

Generates typed Red syntax views from @node metadata.

Instance Method Summary collapse

Instance Method Details

#append_repetition_accessors(lines, fields) ⇒ void

This method returns an undefined value.

RBS:

  • (Array[String] lines, Hash[String, CSTMetadata::field_slot] fields) -> void

Parameters:

  • lines (Array[String])
  • fields (Hash[String, CSTMetadata::field_slot])


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/ibex/codegen/ruby_syntax.rb', line 73

def append_repetition_accessors(lines, fields)
  repeated = fields.select { |_field, slot| slot.is_a?(Hash) && slot[:extraction] }
  repeated.each do |field, slot|
    typed_slot = slot #: Hash[Symbol, untyped]
    index = typed_slot.fetch(:index) #: Integer
    separated = typed_slot.fetch(:extraction) == :separated_list
    lines << "      def each_#{field}_element = list_items(#{index}, separated: #{separated})"
    next unless separated

    method = "each_#{field}_separator"
    lines << "      def #{method} = list_items(#{index}, separated: true, separators: true)"
  end
  return unless repeated.one?

  field, slot = repeated.first
  typed_slot = slot #: Hash[Symbol, untyped]
  lines << "      alias each_element each_#{field}_element"
  return unless typed_slot.fetch(:extraction) == :separated_list

  lines << "      alias each_separator each_#{field}_separator"
end

#append_syntax(lines) ⇒ void

This method returns an undefined value.

RBS:

  • (Array[String] lines) -> void

Parameters:

  • lines (Array[String])


14
15
16
17
18
19
20
21
22
# File 'lib/ibex/codegen/ruby_syntax.rb', line 14

def append_syntax(lines)
  # @type self: Ruby
  definitions = syntax_node_definitions
  return if definitions.empty? || !cst?

  lines << "  module Syntax"
  definitions.each_value { |definition| append_syntax_node(lines, definition) }
  lines.push("  end", "")
end

#append_syntax_node(lines, definition) ⇒ void

This method returns an undefined value.

RBS:

  • (Array[String] lines, syntax_definition definition) -> void

Parameters:

  • lines (Array[String])
  • definition (syntax_definition)


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ibex/codegen/ruby_syntax.rb', line 56

def append_syntax_node(lines, definition)
  name = definition.fetch(:name)
  fields = definition.fetch(:fields)
  lines.push(
    "    class #{name} < Ibex::Runtime::CST::TypedNode",
    "      KIND = #{definition.fetch(:kind)}",
    "      def self.cast(node) = node.kind == KIND ? new(node) : nil"
  )
  fields.each do |field, slot|
    index = slot.is_a?(Hash) ? slot.fetch(:index) : slot
    lines << "      def #{field} = child_at_slot(#{index})"
  end
  append_repetition_accessors(lines, fields)
  lines.push("    end", "")
end

#merge_syntax_fields(left, right) ⇒ Hash[String, CSTMetadata::field_slot]

RBS:

  • (Hash[String, CSTMetadata::field_slot] left, Hash[String, CSTMetadata::field_slot] right) -> Hash[String, CSTMetadata::field_slot]

Parameters:

  • left (Hash[String, CSTMetadata::field_slot])
  • right (Hash[String, CSTMetadata::field_slot])

Returns:

  • (Hash[String, CSTMetadata::field_slot])


44
45
46
47
48
49
50
51
52
53
# File 'lib/ibex/codegen/ruby_syntax.rb', line 44

def merge_syntax_fields(left, right)
  left.to_h do |name, left_slot|
    right_slot = right.fetch(name)
    left_index = left_slot.is_a?(Hash) ? left_slot.fetch(:index) : left_slot
    right_index = right_slot.is_a?(Hash) ? right_slot.fetch(:index) : right_slot
    raise Ibex::Error, "inconsistent CST slot for #{name}" unless left_index == right_index

    [name, left_slot == right_slot ? left_slot : left_index]
  end.freeze
end

#syntax_node_definitionsHash[String, syntax_definition]

RBS:

  • () -> Hash[String, syntax_definition]

Returns:

  • (Hash[String, syntax_definition])


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ibex/codegen/ruby_syntax.rb', line 25

def syntax_node_definitions
  # @type self: Ruby
   =  #: CSTMetadata::metadata
  slots = .fetch(:slots)
  definitions = {} #: Hash[String, syntax_definition]
  @grammar.productions.each do |production|
    node = production.node
    next unless node

    slot = slots.fetch(production.id)
    name = node.fetch(:name)
    previous = definitions[name]
    fields = previous ? merge_syntax_fields(previous.fetch(:fields), slot.fetch(:fields)) : slot.fetch(:fields)
    definitions[name] = { name: name, kind: slot.fetch(:node_kind), fields: fields }.freeze
  end
  definitions
end