Class: Stone::AST::PropertyAccess

Inherits:
Expression show all
Defined in:
lib/stone/ast/property_access.rb

Defined Under Namespace

Classes: TypeDispatchBuilder

Constant Summary collapse

TYPE_PROPERTIES =
%w[as_String record? primitive? kind size fields].freeze
FIELD_LIST_PROPERTIES =
%w[first name type rest].freeze
TYPE_PROPERTY_GENERATORS =
{
  "as_String" => :generate_type_as_string, "size" => :generate_type_size,
  "kind" => :generate_type_kind, "record?" => :generate_type_record_check,
  "primitive?" => :generate_type_primitive_check, "fields" => :generate_type_fields
}.freeze
FIELD_LIST_PROPERTY_GENERATORS =
{
  "name" => :generate_field_list_name, "type" => :generate_field_list_type,
  "rest" => :generate_field_list_rest
}.freeze

Instance Attribute Summary collapse

Attributes inherited from Stone::AST

#children, #name

Instance Method Summary collapse

Constructor Details

#initialize(receiver, property) ⇒ PropertyAccess



15
16
17
18
19
# File 'lib/stone/ast/property_access.rb', line 15

def initialize(receiver, property)
  @receiver = receiver
  @property = property
  @name = :property_access
end

Instance Attribute Details

#propertyObject (readonly)

Returns the value of attribute property.



13
14
15
# File 'lib/stone/ast/property_access.rb', line 13

def property
  @property
end

#receiverObject (readonly)

Returns the value of attribute receiver.



13
14
15
# File 'lib/stone/ast/property_access.rb', line 13

def receiver
  @receiver
end

Instance Method Details

#extract_union_type_tag(builder, mod, scope) ⇒ Object

Extract the type tag from a union field (for Type.of() support)



497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/stone/ast/property_access.rb', line 497

def extract_union_type_tag(builder, mod, scope)
  record_type_name = get_record_type_name(mod)
  record_def = lookup_record_definition(mod, record_type_name)
  field_index = get_field_index(record_def, record_type_name)

  # Evaluate the receiver to get the record struct
  receiver_value = @receiver.to_llir(builder, mod, scope)

  # If receiver is a pointer (recursive field), load the struct first
  if receiver_value.type.kind == :pointer
    struct_type = record_def.llvm_type(mod)
    receiver_value = builder.load2(struct_type, receiver_value, "loaded_struct")
  end

  # Extract the union struct from the record
  union_value = builder.extract_value(receiver_value, field_index, "#{@property}_union")

  # Extract the type tag (index 0) from the union struct
  builder.extract_value(union_value, 0, "union_type_tag")
end

#get_record_type_name(mod) ⇒ Object



529
530
531
532
533
534
535
536
537
538
539
# File 'lib/stone/ast/property_access.rb', line 529

def get_record_type_name(mod)
  case @receiver
  when Reference
    mod.record_instance_type(@receiver.identifier)
  when FunctionCall
    @receiver.function_name
  when PropertyAccess
    # Receiver is a PropertyAccess - get the field type it returns
    get_receiver_field_type(mod)
  end
end

#returns_string_field?(mod) ⇒ Boolean



518
519
520
521
522
523
524
525
526
527
# File 'lib/stone/ast/property_access.rb', line 518

def returns_string_field?(mod)
  return false unless record_field_access?(mod)

  record_type_name = get_record_type_name(mod)
  record_def = mod.record_types[record_type_name]
  return false unless record_def

  field_def = record_def.fields.find { |f| f[:name] == @property }
  field_def && field_def[:type_name] == "String"
end

#to_llir(builder, mod, scope = Stone::Scope.top_level) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/stone/ast/property_access.rb', line 31

def to_llir(builder, mod, scope = Stone::Scope.top_level)
  # 1. Check if this is a record field access (highest priority)
  return access_record_field(builder, mod, scope) if record_field_access?(mod)

  # 2. Check if receiver is a union containing record(s) - enables chained access like o.value.x
  return access_field_on_union_record(builder, mod, scope) if receiver_is_union_with_record?(mod)

  # Resolve the receiver type for subsequent checks
  receiver_type = resolve_node_type(@receiver, mod)

  # Try different property access strategies
  handle_type_property(builder, mod, scope, receiver_type) ||
    handle_field_list_property(builder, mod, scope, receiver_type) ||
    handle_byte_count(mod) ||
    handle_computed_property(builder, mod, scope, receiver_type) ||
    fail_property_not_found(receiver_type)
end

#type(context = nil) ⇒ Object



21
22
23
24
25
26
27
28
29
# File 'lib/stone/ast/property_access.rb', line 21

def type(context = nil)
  receiver_type = @receiver.type(context)
  return nil unless receiver_type

  return_type = receiver_type.property_return_type(@property)
  fail Stone::PropertyError, "Property '#{@property}' not found for type '#{receiver_type.name}'" unless return_type

  return_type
end

#union_field_access?(mod) ⇒ Boolean

Check if this property access is on a union-typed field (for Type.of() support)



485
486
487
488
489
490
491
492
493
494
# File 'lib/stone/ast/property_access.rb', line 485

def union_field_access?(mod)
  return false unless record_field_access?(mod)

  record_type_name = get_record_type_name(mod)
  record_def = mod.record_types[record_type_name]
  return false unless record_def

  field_annotation = record_def.field_type_annotation(@property)
  Stone::AST::FieldHelpers.union_annotation?(field_annotation)
end