Class: Rubycc::Front::InitializerResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/rubycc/front/initializer_resolver.rb

Overview

Resolves an initializer (6.7.9) against the object's type into a flat list of scalar/string placements plus a completed type. The whole current-object walk lives here — nested braces, brace elision (an aggregate subobject with no braces of its own keeps drawing from the enclosing list), designated initializers ("[i] = ", ".m = ", and chains such as ".a.b = "), the "0" idiom, unions (the first member by default, any member by designator) and transparent designation into an anonymous member — so both the local and the global lowering share one interpretation and neither re-implements it.

What it deliberately leaves out: it never evaluates a scalar's value (that is the caller's, since a constant fold and a run-time store differ), and it never type-checks a scalar against its slot (the caller applies the ordinary assignment conversion). It only diagnoses the structural errors — excess elements, a braced list for a scalar, an unknown member, an out-of-range index and an over-long char-array string — that depend on the shape alone.

Defined Under Namespace

Classes: Cursor

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.char_array?(type) ⇒ Boolean

An array of character type — the one aggregate a string literal may initialize as a whole (6.7.9p14). Any of the three character types qualifies (plain char under either target signedness, signed char, unsigned char), since the literal's bytes are copied in unchanged.

Returns:

  • (Boolean)


99
100
101
# File 'lib/rubycc/front/initializer_resolver.rb', line 99

def self.char_array?(type)
  type.array? && Type.character?(type.element)
end

.resolve(type, initializer, static_storage: false, type_of: nil) ⇒ Object

static_storage says the object being initialized lives in .data/.bss (a file-scope definition or a block-scope static), which is the only place a trailing flexible array member may be initialized.

type_of is how the caller lends this resolver its view of expression types: a callable taking an expression node and answering its Rubycc::Type, or nil when it cannot tell (see #single_expression_init?, which is the only thing that asks). It must not emit code or evaluate anything — the generator passes its #static_type inference, the parser the smaller one it uses for parse-time sizeof. A caller with no type table at all may leave it out, and every subobject then falls to brace elision as it did before the hook existed.



115
116
117
# File 'lib/rubycc/front/initializer_resolver.rb', line 115

def self.resolve(type, initializer, static_storage: false, type_of: nil)
  new.resolve(type, initializer, static_storage: static_storage, type_of: type_of)
end

.structural?(type, init) ⇒ Boolean

Whether init initializes type structurally (needs this resolver) rather than as a plain scalar value: a brace list always does, and so does a bare string literal aimed at a char array. Both the parser (to decide whether to fold or defer) and the generator consult this.

Returns:

  • (Boolean)


90
91
92
93
# File 'lib/rubycc/front/initializer_resolver.rb', line 90

def self.structural?(type, init)
  init.is_a?(AST::InitializerList) ||
    (char_array?(type) && init.is_a?(AST::StringLit))
end

Instance Method Details

#resolve(type, initializer, static_storage: false, type_of: nil) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rubycc/front/initializer_resolver.rb', line 119

def resolve(type, initializer, static_storage: false, type_of: nil)
  @entries = []
  @static_storage = static_storage
  @type_of = type_of
  @flexible_bytes = 0
  # The first expression this run could not type against a struct
  # subobject, if any; #excess_elements_error reports against it.
  @untyped_struct_item = nil
  # Only the object's *own* trailing flexible array member may be
  # initialized; one reached through a nested struct is rejected, so
  # remember which struct owns the one initializer this run may fill.
  @flexible_owner = type.struct? ? type : nil
  final = init_top(type, initializer)
  ResolvedInitializer.new(final, @entries, @flexible_bytes)
end