Module: MilkTea::CompileTime::MethodFolding
- Included in:
- Lowering::Resolve, SemanticAnalyzer::Checker
- Defined in:
- lib/milk_tea/core/compile_time/method_folding.rb
Overview
Compile-time folding for const-method calls and the resolution helpers
behind them. Included by both the semantic checker and the lowering
engine so the folding behavior lives in one place instead of two
near-identical copies. Each includer supplies a small set of comptime_*
adapters for the phase-specific lookups (ctx maps, scope/env evaluation,
and the BlockContext factory).
Instance Method Summary collapse
- #comptime_call_return_type(call_expr, ctx) ⇒ Object
- #comptime_const_function_return?(func) ⇒ Boolean
- #comptime_const_method_body(binding, arguments, scopes:, receiver_value:, arg_evaluator: nil) ⇒ Object
- #comptime_expression_type(expression, scopes:) ⇒ Object
- #comptime_folded_value?(value) ⇒ Boolean
- #comptime_imported_value_type(import_name, member) ⇒ Object
- #comptime_member_receiver_value(receiver, ctx) ⇒ Object
- #comptime_method_binding(member_access, ctx) ⇒ Object
- #comptime_method_binding_for_receiver(receiver_type, member) ⇒ Object
- #comptime_methods_map_for_binding(type, keys) ⇒ Object
- #comptime_receiver_type(receiver, ctx) ⇒ Object
- #comptime_struct_field_names(type_name) ⇒ Object
Instance Method Details
#comptime_call_return_type(call_expr, ctx) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 72 def comptime_call_return_type(call_expr, ctx) case call_expr.callee when AST::MemberAccess binding = comptime_method_binding(call_expr.callee, ctx) return binding.body_return_type if binding when AST::Identifier func = comptime_const_function(call_expr.callee.name) return func.body_return_type if comptime_const_function_return?(func) when AST::Specialization callee_name = call_expr.callee.callee.is_a?(AST::Identifier) ? call_expr.callee.callee.name : nil if callee_name func = comptime_const_function(callee_name) return func.body_return_type if comptime_const_function_return?(func) end end nil end |
#comptime_const_function_return?(func) ⇒ Boolean
115 116 117 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 115 def comptime_const_function_return?(func) func && func.respond_to?(:ast) && func.ast.respond_to?(:const) && func.ast.const end |
#comptime_const_method_body(binding, arguments, scopes:, receiver_value:, arg_evaluator: nil) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 119 def comptime_const_method_body(binding, arguments, scopes:, receiver_value:, arg_evaluator: nil) method = binding.ast return nil unless method.respond_to?(:body) && method.body return nil if binding.type_params.any? return nil unless method.params.length == arguments.length initial_vars = {} if binding.type.receiver_type return nil unless comptime_folded_value?(receiver_value) initial_vars["this"] = receiver_value end method.params.each_with_index do |param, idx| arg_value = if arg_evaluator arg_evaluator.call(arguments[idx].value) else comptime_eval(arguments[idx].value, scopes) end return nil unless arg_value initial_vars[param.name] = arg_value end variable_types = binding.body_params.each_with_object({}) do |param, acc| acc[param.name] = param.type end block_context = comptime_block_context(initial_vars, variable_types) result = block_context.evaluate_block(method.body, scopes: nil) result.is_a?(CompileTime::ReturnOutcome) ? result.value : result rescue CompileTime::Error => e comptime_raise_error(e) end |
#comptime_expression_type(expression, scopes:) ⇒ Object
90 91 92 93 94 95 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 90 def comptime_expression_type(expression, scopes:) case expression when AST::Call, AST::Specialization comptime_call_return_type(expression, scopes) end end |
#comptime_folded_value?(value) ⇒ Boolean
108 109 110 111 112 113 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 108 def comptime_folded_value?(value) return false if value.nil? return false if value.is_a?(Types::Base) true end |
#comptime_imported_value_type(import_name, member) ⇒ Object
153 154 155 156 157 158 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 153 def comptime_imported_value_type(import_name, member) imported_module = @ctx.imports.fetch(import_name, nil) return nil unless imported_module imported_module.values[member]&.type end |
#comptime_member_receiver_value(receiver, ctx) ⇒ Object
66 67 68 69 70 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 66 def comptime_member_receiver_value(receiver, ctx) return nil if resolve_type_expression(receiver) comptime_eval(receiver, ctx) end |
#comptime_method_binding(member_access, ctx) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 31 def comptime_method_binding(member_access, ctx) member = member_access.member keys = ["static:#{member}", member] if (type = resolve_type_expression(member_access.receiver)) && (binding = comptime_methods_map_for_binding(type, keys)) return binding end receiver_type = comptime_receiver_type(member_access.receiver, ctx) return nil unless receiver_type comptime_methods_map_for_binding(receiver_type, keys) end |
#comptime_method_binding_for_receiver(receiver_type, member) ⇒ Object
46 47 48 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 46 def comptime_method_binding_for_receiver(receiver_type, member) comptime_methods_map_for_binding(receiver_type, ["static:#{member}", member]) end |
#comptime_methods_map_for_binding(type, keys) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 12 def comptime_methods_map_for_binding(type, keys) dispatch_type = type.respond_to?(:definition) ? type.definition : type method_map = comptime_methods_map.fetch(dispatch_type, nil) method_map ||= comptime_methods_map_by_to_s(dispatch_type) return nil unless method_map keys.each do |key| binding = method_map[key] next unless binding ast = binding.ast next unless ast.respond_to?(:const) && ast.const && ast.body next unless binding.type_params.empty? return binding end nil end |
#comptime_receiver_type(receiver, ctx) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 50 def comptime_receiver_type(receiver, ctx) case receiver when AST::Identifier type = comptime_scoped_value_type(receiver.name, ctx) return type if type comptime_value_type(receiver.name) when AST::MemberAccess return nil unless receiver.receiver.is_a?(AST::Identifier) comptime_imported_value_type(receiver.receiver.name, receiver.member) when AST::Call, AST::Specialization comptime_call_return_type(receiver, ctx) end end |
#comptime_struct_field_names(type_name) ⇒ Object
97 98 99 100 101 102 103 104 105 106 |
# File 'lib/milk_tea/core/compile_time/method_folding.rb', line 97 def comptime_struct_field_names(type_name) parts = type_name.is_a?(Array) ? type_name.map(&:to_s) : [type_name.to_s] return nil if parts.empty? type = resolve_type_expression(::MilkTea::AST.build_chain_from_parts(parts)) return nil unless type return nil unless type.respond_to?(:fields) && type.fields type.fields.keys end |