Module: Ibex::NormalizeNodes

Included in:
Normalizer
Defined in:
lib/ibex/normalize/nodes.rb,
sig/ibex/normalize/nodes.rbs

Overview

Validation and normalization for generated AST node declarations.

Instance Method Summary collapse

Instance Method Details

#normalize_node_annotation(alternative, rhs) ⇒ IR::node_annotation?

RBS:

  • (Frontend::AST::Alternative alternative, Array[String] rhs) -> IR::node_annotation?

Parameters:

Returns:

  • (IR::node_annotation, nil)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/ibex/normalize/nodes.rb', line 9

def normalize_node_annotation(alternative, rhs)
  # @type self: Normalizer
  annotation = alternative.node_annotation
  return unless annotation

  if alternative.action || alternative.items.any?(Frontend::AST::InlineAction)
    fail_at(annotation.loc, "@node cannot be combined with semantic actions")
  end
  unless annotation.name.match?(/\A[A-Z][A-Za-z0-9_]*\z/)
    fail_at(annotation.loc, "@node name #{annotation.name.inspect} must be a Ruby constant identifier")
  end
  validate_node_fields(annotation, rhs)
  previous = @node_shapes[annotation.name]
  if previous && previous != annotation.fields
    fail_at(annotation.loc, "@node #{annotation.name} was already declared with fields (#{previous.join(', ')})")
  end
  @node_shapes[annotation.name] = annotation.fields.dup.freeze
  { name: annotation.name, fields: annotation.fields, loc: annotation.loc.to_h }
end

#validate_node_fields(annotation, rhs) ⇒ void

This method returns an undefined value.

RBS:

  • (Frontend::AST::NodeAnnotation annotation, Array[String] rhs) -> void

Parameters:



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/ibex/normalize/nodes.rb', line 30

def validate_node_fields(annotation, rhs)
  # @type self: Normalizer
  unless annotation.fields.length == rhs.length
    fail_at(
      annotation.loc,
      "@node #{annotation.name} declares #{annotation.fields.length} fields for #{rhs.length} RHS values"
    )
  end
  duplicate = annotation.fields.tally.find { |_name, count| count > 1 }&.first
  fail_at(annotation.loc, "@node field #{duplicate.inspect} is duplicated") if duplicate
  invalid = annotation.fields.find do |field|
    !field.match?(/\A[a-z_][a-zA-Z0-9_]*\z/) || Normalizer::RUBY_KEYWORDS.include?(field)
  end
  fail_at(annotation.loc, "@node field #{invalid.inspect} must be a Ruby local identifier") if invalid
end