Module: Ibex::NormalizeExpander

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

Overview

Production and EBNF expansion used by Normalizer.

Instance Method Summary collapse

Instance Method Details

#add_group_production(helper, rhs, item) ⇒ void

This method returns an undefined value.

RBS:

  • (String helper, Array[String] rhs, Frontend::AST::Group item) -> void

Parameters:



164
165
166
167
168
# File 'lib/ibex/normalize/expander.rb', line 164

def add_group_production(helper, rhs, item)
  # @type self: Normalizer
  expression = group_value_expression(rhs.length)
  add_production(helper, rhs, synthetic_action(expression, item.loc), nil, synthetic_origin(:group, item))
end

#add_production(lhs_name, rhs_names, action, precedence_name, origin, documentation = nil, node = nil) ⇒ void

This method returns an undefined value.

RBS:

  • (String lhs_name, Array[String] rhs_names, IR::Action? action, String? precedence_name, Hash[Symbol, untyped] origin, ?String? documentation, ?IR::node_annotation? node) -> void

Parameters:

  • lhs_name (String)
  • rhs_names (Array[String])
  • action (IR::Action, nil)
  • precedence_name (String, nil)
  • origin (Hash[Symbol, untyped])
  • documentation (String, nil) (defaults to: nil)
  • node (IR::node_annotation, nil) (defaults to: nil)


211
212
213
214
215
216
217
218
219
220
# File 'lib/ibex/normalize/expander.rb', line 211

def add_production(lhs_name, rhs_names, action, precedence_name, origin, documentation = nil, node = nil)
  # @type self: Normalizer
  lhs = symbol(lhs_name) || intern(lhs_name, :nonterminal, location: origin[:loc])
  rhs = rhs_names.map { |name| symbol(name)&.id || fail_hash(origin[:loc], "undefined symbol #{name}") }
  precedence = precedence_name && symbol(precedence_name)
  fail_hash(origin[:loc], "undefined precedence symbol #{precedence_name}") if precedence_name && !precedence
  @productions << IR::Production.new(id: @productions.length, lhs: lhs.id, rhs: rhs, action: action,
                                     precedence_override: precedence&.id, origin: origin,
                                     documentation: documentation, expansion: resolved_expansion, node: node)
end

#build_optional(item, base) ⇒ String

RBS:

  • (Frontend::AST::Optional item, String base) -> String

Parameters:

Returns:

  • (String)


87
88
89
90
91
92
93
# File 'lib/ibex/normalize/expander.rb', line 87

def build_optional(item, base)
  # @type self: Normalizer
  helper = new_helper("optional", item.loc)
  add_production(helper, [], synthetic_action("nil", item.loc), nil, synthetic_origin(:optional, item))
  add_production(helper, [base], synthetic_action("val[0]", item.loc), nil, synthetic_origin(:optional, item))
  helper
end

#build_plus(item, base) ⇒ String

RBS:

  • (Frontend::AST::Plus item, String base) -> String

Parameters:

Returns:

  • (String)


120
121
122
123
124
125
126
127
# File 'lib/ibex/normalize/expander.rb', line 120

def build_plus(item, base)
  # @type self: Normalizer
  helper = new_helper("plus", item.loc)
  add_production(helper, [base], synthetic_action("[val[0]]", item.loc), nil, synthetic_origin(:plus, item))
  add_production(helper, [helper, base], synthetic_action("val[0] + [val[1]]", item.loc), nil,
                 synthetic_origin(:plus, item))
  helper
end

#build_separated_list(item, base, separator) ⇒ String

RBS:

  • (Frontend::AST::SeparatedList item, String base, String separator) -> String

Parameters:

Returns:

  • (String)


138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/ibex/normalize/expander.rb', line 138

def build_separated_list(item, base, separator)
  # @type self: Normalizer
  helper = new_helper("separated_list", item.loc)
  unless item.nonempty
    add_production(helper, [], synthetic_action("[]", item.loc), nil, synthetic_origin(:separated_list, item))
  end
  add_production(helper, [base], synthetic_action("[val[0]]", item.loc), nil,
                 synthetic_origin(:separated_list, item))
  add_production(helper, [helper, separator, base], synthetic_action("val[0] + [val[2]]", item.loc), nil,
                 synthetic_origin(:separated_list, item))
  helper
end

#build_star(item, base) ⇒ String

RBS:

  • (Frontend::AST::Star item, String base) -> String

Parameters:

Returns:

  • (String)


103
104
105
106
107
108
109
110
# File 'lib/ibex/normalize/expander.rb', line 103

def build_star(item, base)
  # @type self: Normalizer
  helper = new_helper("star", item.loc)
  add_production(helper, [], synthetic_action("[]", item.loc), nil, synthetic_origin(:star, item))
  add_production(helper, [helper, base], synthetic_action("val[0] + [val[1]]", item.loc), nil,
                 synthetic_origin(:star, item))
  helper
end

#expand_group(item) ⇒ String

RBS:

  • (Frontend::AST::Group item) -> String

Parameters:

Returns:

  • (String)


152
153
154
155
156
157
158
159
160
161
# File 'lib/ibex/normalize/expander.rb', line 152

def expand_group(item)
  # @type self: Normalizer
  reject_group_named_references(item)
  helper = new_helper("group", item.loc)
  item.alternatives.each do |alternative|
    rhs = alternative.map { |child| normalize_item(child) }
    add_group_production(helper, rhs, item)
  end
  helper
end

#expand_inline_action(item, context_length, named_refs) ⇒ String

RBS:

  • (Frontend::AST::InlineAction item, Integer context_length, Array[IR::named_ref] named_refs) -> String

Parameters:

Returns:

  • (String)


70
71
72
73
74
75
76
77
# File 'lib/ibex/normalize/expander.rb', line 70

def expand_inline_action(item, context_length, named_refs)
  # @type self: Normalizer
  helper = new_helper("inline", item.loc)
  action = IR::Action.new(code: item.code, location: item.loc.to_h, named_refs: named_refs.map(&:dup),
                          context_length: context_length)
  add_production(helper, [], action, nil, { kind: :inline_action, loc: item.loc.to_h })
  helper
end

#expand_optional(item) ⇒ String

RBS:

  • (Frontend::AST::Optional item) -> String

Parameters:

Returns:

  • (String)


80
81
82
83
84
# File 'lib/ibex/normalize/expander.rb', line 80

def expand_optional(item)
  # @type self: Normalizer
  base = normalize_item(item.item)
  build_optional(item, base)
end

#expand_plus(item) ⇒ String

RBS:

  • (Frontend::AST::Plus item) -> String

Parameters:

Returns:

  • (String)


113
114
115
116
117
# File 'lib/ibex/normalize/expander.rb', line 113

def expand_plus(item)
  # @type self: Normalizer
  base = normalize_item(item.item)
  build_plus(item, base)
end

#expand_separated_list(item) ⇒ String

RBS:

  • (Frontend::AST::SeparatedList item) -> String

Parameters:

Returns:

  • (String)


130
131
132
133
134
135
# File 'lib/ibex/normalize/expander.rb', line 130

def expand_separated_list(item)
  # @type self: Normalizer
  base = normalize_item(item.item)
  separator = normalize_item(item.separator)
  build_separated_list(item, base, separator)
end

#expand_star(item) ⇒ String

RBS:

  • (Frontend::AST::Star item) -> String

Parameters:

Returns:

  • (String)


96
97
98
99
100
# File 'lib/ibex/normalize/expander.rb', line 96

def expand_star(item)
  # @type self: Normalizer
  base = normalize_item(item.item)
  build_star(item, base)
end

#group_value_expression(length) ⇒ String

RBS:

  • (Integer length) -> String

Parameters:

  • length (Integer)

Returns:

  • (String)


171
172
173
174
175
176
177
# File 'lib/ibex/normalize/expander.rb', line 171

def group_value_expression(length)
  # @type self: Normalizer
  return "nil" if length.zero?
  return "val[0]" if length == 1

  "val"
end

#new_helper(kind, location) ⇒ String

RBS:

  • (String kind, Frontend::Location location) -> String

Parameters:

Returns:

  • (String)


180
181
182
183
184
185
186
# File 'lib/ibex/normalize/expander.rb', line 180

def new_helper(kind, location)
  # @type self: Normalizer
  @helper_sequence += 1
  name = "$#{kind}_#{@helper_sequence}"
  intern(name, :nonterminal, location: location.to_h)
  name
end

#normalize_action(action, named_refs) ⇒ IR::Action?

RBS:

  • (Frontend::AST::InlineAction? action, Array[IR::named_ref] named_refs) -> IR::Action?

Parameters:

Returns:



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

def normalize_action(action, named_refs)
  # @type self: Normalizer
  return nil unless action

  IR::Action.new(code: action.code, location: action.loc.to_h, named_refs: named_refs)
end

#normalize_alternative(rule, alternative) ⇒ void

This method returns an undefined value.

RBS:

  • (Frontend::AST::Rule rule, Frontend::AST::Alternative alternative) -> void

Parameters:



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

def normalize_alternative(rule, alternative)
  # @type self: Normalizer
  rhs = [] #: Array[String]
  named_refs = [] #: Array[IR::named_ref]
  items = normalized_alternative_items(alternative)
  items.each do |item|
    if item.is_a?(Frontend::AST::InlineAction)
      rhs << expand_inline_action(item, rhs.length, named_refs)
      next
    end

    rhs << normalize_item(item)
    add_named_reference(item, named_refs, rhs.length - 1)
  end
  action = normalize_action(alternative.action, named_refs)
  node = normalize_node_annotation(alternative, rhs)
  add_production(rule.lhs, rhs, action, alternative.precedence,
                 { kind: :user, loc: alternative.loc.to_h }, rule.documentation, node)
end

#normalize_item(item) ⇒ String

RBS:

  • (Frontend::AST::item item) -> String

Parameters:

  • item (Frontend::AST::item)

Returns:

  • (String)


56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ibex/normalize/expander.rb', line 56

def normalize_item(item)
  # @type self: Normalizer
  return symbol_for_reference(item).name if item.is_a?(Frontend::AST::SymbolReference)
  return specialize_parameterized_reference(item) if item.is_a?(Frontend::AST::ParameterizedReference)
  return expand_group(item) if item.is_a?(Frontend::AST::Group)
  return expand_optional(item) if item.is_a?(Frontend::AST::Optional)
  return expand_star(item) if item.is_a?(Frontend::AST::Star)
  return expand_plus(item) if item.is_a?(Frontend::AST::Plus)
  return expand_separated_list(item) if item.is_a?(Frontend::AST::SeparatedList)

  fail_at(item.loc, "unsupported nested EBNF expression")
end

#normalize_user_productionsvoid

This method returns an undefined value.

RBS:

  • () -> void



9
10
11
12
13
14
15
16
17
# File 'lib/ibex/normalize/expander.rb', line 9

def normalize_user_productions
  # @type self: Normalizer
  @ast.rules.each do |rule|
    next if parameterized_rule?(rule)

    @current_include_chain = @resolution&.include_chain_for(rule) || []
    rule.alternatives.each { |alternative| normalize_alternative(rule, alternative) }
  end
end

#normalized_alternative_items(alternative) ⇒ Array[Frontend::AST::item]

RBS:

  • (Frontend::AST::Alternative alternative) -> Array[Frontend::AST::item]

Parameters:

Returns:

  • (Array[Frontend::AST::item])


41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/ibex/normalize/expander.rb', line 41

def normalized_alternative_items(alternative)
  # @type self: Normalizer
  explicit = alternative.items.grep(Frontend::AST::Empty)
  if explicit.any?
    fail_at(explicit.first.loc, "%empty must be the only item in an alternative") unless alternative.items.one?
    return []
  end

  if alternative.items.empty? && (@mode.to_sym == :extended || @ast.extended)
    @warnings << { type: :implicit_empty, loc: alternative.loc.to_h }
  end
  alternative.items
end

#synthetic_action(expression, location) ⇒ IR::Action

RBS:

  • (String expression, Frontend::Location location) -> IR::Action

Parameters:

Returns:



189
190
191
192
193
# File 'lib/ibex/normalize/expander.rb', line 189

def synthetic_action(expression, location)
  # @type self: Normalizer
  code = @options[:result_var] ? " result = #{expression} " : " #{expression} "
  IR::Action.new(code: code, location: location.to_h)
end

#synthetic_origin(kind, item) ⇒ Hash[Symbol, untyped]

RBS:

  • (Symbol kind, Frontend::AST::item item) -> Hash[Symbol, untyped]

Parameters:

  • kind (Symbol)
  • item (Frontend::AST::item)

Returns:

  • (Hash[Symbol, untyped])


196
197
198
199
# File 'lib/ibex/normalize/expander.rb', line 196

def synthetic_origin(kind, item)
  # @type self: Normalizer
  { kind: :"#{kind}_expansion", expression: NormalizeExpression.render(item), loc: item.loc.to_h }
end