Class: MilkTea::ModuleBinder

Inherits:
Object
  • Object
show all
Defined in:
lib/milk_tea/core/module_binder.rb

Instance Method Summary collapse

Instance Method Details

#exported_declaration?(analysis, declaration) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
67
68
69
# File 'lib/milk_tea/core/module_binder.rb', line 64

def exported_declaration?(analysis, declaration)
  return true if analysis.module_kind == :raw_module
  return false unless declaration.respond_to?(:visibility)

  declaration.visibility == :public
end

#exported_interface_binding?(interface, analysis, exported_interfaces) ⇒ Boolean

Returns:

  • (Boolean)


133
134
135
136
137
# File 'lib/milk_tea/core/module_binder.rb', line 133

def exported_interface_binding?(interface, analysis, exported_interfaces)
  return true if exported_interfaces.value?(interface)

  imported_interface_binding?(interface, analysis.imports)
end

#exported_interface_implementations(analysis, exported_types, exported_interfaces) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/milk_tea/core/module_binder.rb', line 98

def exported_interface_implementations(analysis, exported_types, exported_interfaces)
  implemented_interfaces = {}
  private_implemented_interfaces = {}

  analysis.implemented_interfaces.each do |receiver_type, interfaces|
    public_interfaces = []
    hidden_interfaces = []

    interfaces.each do |interface|
      visible = exported_method_receiver?(receiver_type, analysis, exported_types) &&
        exported_interface_binding?(interface, analysis, exported_interfaces) &&
        exported_interface_methods?(receiver_type, interface, analysis, exported_types)
      if visible
        public_interfaces << interface
      else
        hidden_interfaces << interface
      end
    end

    implemented_interfaces[receiver_type] = public_interfaces.freeze unless public_interfaces.empty?
    private_implemented_interfaces[receiver_type] = hidden_interfaces.freeze unless hidden_interfaces.empty?
  end

  [implemented_interfaces.freeze, private_implemented_interfaces.freeze]
end

#exported_interface_methods?(receiver_type, interface, analysis, exported_types) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
127
128
129
130
131
# File 'lib/milk_tea/core/module_binder.rb', line 124

def exported_interface_methods?(receiver_type, interface, analysis, exported_types)
  return false unless exported_method_receiver?(receiver_type, analysis, exported_types)

  interface.methods.each_key.all? do |method_name|
    binding = analysis.methods.fetch(receiver_type, {})[method_name]
    binding && binding.ast.respond_to?(:visibility) && binding.ast.visibility == :public
  end
end

#exported_method_receiver?(receiver_type, analysis, exported_types) ⇒ Boolean

Returns:

  • (Boolean)


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/milk_tea/core/module_binder.rb', line 139

def exported_method_receiver?(receiver_type, analysis, exported_types)
  return true if receiver_type.is_a?(Types::StringView)
  return true if receiver_type.is_a?(Types::Primitive)
  return true if receiver_type.is_a?(Types::Vector)
  return true if receiver_type.is_a?(Types::Matrix)
  return true if receiver_type.is_a?(Types::Quaternion)
  return true if receiver_type.is_a?(Types::SoA)
  return true if receiver_type.is_a?(Types::Simd)
  return true if receiver_type.is_a?(Types::Span)
  return true if receiver_type.is_a?(Types::Task)
  return true if receiver_type.is_a?(Types::Dyn)
  return true if exported_types.value?(receiver_type)
  return true if imported_receiver_type?(receiver_type, analysis.imports)
  return exported_method_receiver?(receiver_type.base, analysis, exported_types) if receiver_type.is_a?(Types::Nullable)
  return receiver_type.arguments.all? { |argument| exported_method_receiver_argument?(argument, analysis, exported_types) } if receiver_type.is_a?(Types::GenericInstance)
  return exported_types.value?(receiver_type.definition) || imported_receiver_type?(receiver_type.definition, analysis.imports) if receiver_type.is_a?(Types::VariantInstance)

  receiver_type.is_a?(Types::StructInstance) &&
    (exported_types.value?(receiver_type.definition) || imported_receiver_type?(receiver_type.definition, analysis.imports))
end

#exported_method_receiver_argument?(argument, analysis, exported_types) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
163
164
165
# File 'lib/milk_tea/core/module_binder.rb', line 160

def exported_method_receiver_argument?(argument, analysis, exported_types)
  return true if argument.is_a?(Types::LiteralTypeArg)
  return true if argument.is_a?(Types::TypeVar)

  exported_method_receiver?(argument, analysis, exported_types)
end

#exported_methods(analysis, exported_types) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/milk_tea/core/module_binder.rb', line 71

def exported_methods(analysis, exported_types)
  methods = {}
  private_methods = {}

  analysis.methods.each do |receiver_type, bindings|
    public_bindings = {}
    hidden_bindings = {}

    bindings.each do |name, binding|
      visible = binding.ast.respond_to?(:visibility) &&
        binding.ast.visibility == :public &&
        exported_method_receiver?(receiver_type, analysis, exported_types)

      if visible
        public_bindings[name] = binding
      else
        hidden_bindings[name] = binding
      end
    end

    methods[receiver_type] = public_bindings unless public_bindings.empty?
    private_methods[receiver_type] = hidden_bindings unless hidden_bindings.empty?
  end

  [methods, private_methods]
end

#imported_interface_binding?(interface, imports) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
178
179
180
181
# File 'lib/milk_tea/core/module_binder.rb', line 175

def imported_interface_binding?(interface, imports)
  imports.each_value do |module_binding|
    return true if module_binding.interfaces.value?(interface)
  end

  false
end

#imported_receiver_type?(receiver_type, imports) ⇒ Boolean

Returns:

  • (Boolean)


167
168
169
170
171
172
173
# File 'lib/milk_tea/core/module_binder.rb', line 167

def imported_receiver_type?(receiver_type, imports)
  imports.each_value do |module_binding|
    return true if module_binding.types.value?(receiver_type)
  end

  false
end

#module_binding(analysis) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/milk_tea/core/module_binder.rb', line 5

def module_binding(analysis)
  types = {}
  type_declarations = {}
  interfaces = {}
  attributes = {}
  private_types = {}
  private_interfaces = {}
  private_attributes = {}
  values = {}
  private_values = {}
  functions = {}
  private_functions = {}

  analysis.ast.declarations.each do |declaration|
    case declaration
    when AST::StructDecl, AST::UnionDecl, AST::VariantDecl, AST::EnumDecl, AST::FlagsDecl, AST::OpaqueDecl, AST::TypeAliasDecl
      type_declarations[declaration.name] = declaration
      target = exported_declaration?(analysis, declaration) ? types : private_types
      target[declaration.name] = analysis.types.fetch(declaration.name)
    when AST::InterfaceDecl
      target = exported_declaration?(analysis, declaration) ? interfaces : private_interfaces
      target[declaration.name] = analysis.interfaces.fetch(declaration.name)
    when AST::AttributeDecl
      target = exported_declaration?(analysis, declaration) ? attributes : private_attributes
      target[declaration.name] = analysis.attributes.fetch(declaration.name)
    when AST::ConstDecl, AST::VarDecl, AST::EventDecl
      target = exported_declaration?(analysis, declaration) ? values : private_values
      target[declaration.name] = analysis.values.fetch(declaration.name)
    when AST::FunctionDef, AST::ExternFunctionDecl, AST::ForeignFunctionDecl
      target = exported_declaration?(analysis, declaration) ? functions : private_functions
      target[declaration.name] = analysis.functions.fetch(declaration.name)
    end
  end

  methods, private_methods = exported_methods(analysis, types)
  implemented_interfaces, private_implemented_interfaces = exported_interface_implementations(analysis, types, interfaces)

  ModuleBinding.new(
    name: analysis.module_name,
    types:,
    type_declarations:,
    interfaces:,
    attributes:,
    attribute_applications: analysis.attribute_applications,
    values:,
    functions:,
    methods:,
    implemented_interfaces:,
    imports: analysis.imports,
    private_types:,
    private_interfaces:,
    private_attributes:,
    private_values:,
    private_functions:,
    private_methods:,
    private_implemented_interfaces:,
  )
end