Class: TRuby::ASTTypeInferrer

Inherits:
Object
  • Object
show all
Defined in:
lib/t_ruby/ast_type_inferrer.rb

Overview

ASTTypeInferrer - TypeScript 스타일 정적 타입 추론 엔진IR 노드를 순회하면서 타입을 추론하고 캐싱

Constant Summary collapse

LITERAL_TYPE_MAP =

리터럴 타입 매핑

{
  string: "String",
  integer: "Integer",
  float: "Float",
  boolean: "bool",
  symbol: "Symbol",
  nil: "nil",
  array: "Array[untyped]",
  hash: "Hash[untyped, untyped]",
}.freeze
ARITHMETIC_OPS =

산술 연산자 규칙 (피연산자 타입 → 결과 타입)

%w[+ - * / % **].freeze
COMPARISON_OPS =
%w[== != < > <= >= <=>].freeze
LOGICAL_OPS =
%w[&& ||].freeze
BUILTIN_METHODS =

내장 메서드 반환 타입

{
  # String 메서드
  %w[String upcase] => "String",
  %w[String downcase] => "String",
  %w[String capitalize] => "String",
  %w[String reverse] => "String",
  %w[String strip] => "String",
  %w[String chomp] => "String",
  %w[String chop] => "String",
  %w[String gsub] => "String",
  %w[String sub] => "String",
  %w[String tr] => "String",
  %w[String to_s] => "String",
  %w[String to_str] => "String",
  %w[String to_sym] => "Symbol",
  %w[String to_i] => "Integer",
  %w[String to_f] => "Float",
  %w[String length] => "Integer",
  %w[String size] => "Integer",
  %w[String bytesize] => "Integer",
  %w[String empty?] => "bool",
  %w[String include?] => "bool",
  %w[String start_with?] => "bool",
  %w[String end_with?] => "bool",
  %w[String match?] => "bool",
  %w[String split] => "Array[String]",
  %w[String chars] => "Array[String]",
  %w[String bytes] => "Array[Integer]",
  %w[String lines] => "Array[String]",

  # Integer 메서드
  %w[Integer to_s] => "String",
  %w[Integer to_i] => "Integer",
  %w[Integer to_f] => "Float",
  %w[Integer abs] => "Integer",
  %w[Integer even?] => "bool",
  %w[Integer odd?] => "bool",
  %w[Integer zero?] => "bool",
  %w[Integer positive?] => "bool",
  %w[Integer negative?] => "bool",
  %w[Integer times] => "Integer",
  %w[Integer upto] => "Enumerator[Integer]",
  %w[Integer downto] => "Enumerator[Integer]",

  # Float 메서드
  %w[Float to_s] => "String",
  %w[Float to_i] => "Integer",
  %w[Float to_f] => "Float",
  %w[Float abs] => "Float",
  %w[Float ceil] => "Integer",
  %w[Float floor] => "Integer",
  %w[Float round] => "Integer",
  %w[Float truncate] => "Integer",
  %w[Float nan?] => "bool",
  %w[Float infinite?] => "Integer?",
  %w[Float finite?] => "bool",
  %w[Float zero?] => "bool",
  %w[Float positive?] => "bool",
  %w[Float negative?] => "bool",

  # Array 메서드
  %w[Array length] => "Integer",
  %w[Array size] => "Integer",
  %w[Array count] => "Integer",
  %w[Array empty?] => "bool",
  %w[Array any?] => "bool",
  %w[Array all?] => "bool",
  %w[Array none?] => "bool",
  %w[Array include?] => "bool",
  %w[Array reverse] => "Array[untyped]",
  %w[Array sort] => "Array[untyped]",
  %w[Array uniq] => "Array[untyped]",
  %w[Array compact] => "Array[untyped]",
  %w[Array flatten] => "Array[untyped]",
  %w[Array join] => "String",
  %w[Array to_s] => "String",
  %w[Array to_a] => "Array[untyped]",

  # Hash 메서드
  %w[Hash length] => "Integer",
  %w[Hash size] => "Integer",
  %w[Hash empty?] => "bool",
  %w[Hash key?] => "bool",
  %w[Hash has_key?] => "bool",
  %w[Hash value?] => "bool",
  %w[Hash has_value?] => "bool",
  %w[Hash include?] => "bool",
  %w[Hash keys] => "Array[untyped]",
  %w[Hash values] => "Array[untyped]",
  %w[Hash to_s] => "String",
  %w[Hash to_a] => "Array[untyped]",
  %w[Hash to_h] => "Hash[untyped, untyped]",

  # Object 메서드 (모든 타입에 적용)
  %w[Object to_s] => "String",
  %w[Object inspect] => "String",
  %w[Object class] => "Class",
  %w[Object is_a?] => "bool",
  %w[Object kind_of?] => "bool",
  %w[Object instance_of?] => "bool",
  %w[Object respond_to?] => "bool",
  %w[Object nil?] => "bool",
  %w[Object frozen?] => "bool",
  %w[Object dup] => "untyped",
  %w[Object clone] => "untyped",
  %w[Object freeze] => "self",
  %w[Object tap] => "self",
  %w[Object then] => "untyped",
  %w[Object yield_self] => "untyped",

  # Symbol 메서드
  %w[Symbol to_s] => "String",
  %w[Symbol to_sym] => "Symbol",
  %w[Symbol length] => "Integer",
  %w[Symbol size] => "Integer",
  %w[Symbol empty?] => "bool",
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeASTTypeInferrer

Returns a new instance of ASTTypeInferrer.



145
146
147
# File 'lib/t_ruby/ast_type_inferrer.rb', line 145

def initialize
  @type_cache = {} # 노드 → 타입 캐시 (TypeScript의 지연 평가)
end

Instance Attribute Details

#type_cacheObject (readonly)

Returns the value of attribute type_cache.



143
144
145
# File 'lib/t_ruby/ast_type_inferrer.rb', line 143

def type_cache
  @type_cache
end

Instance Method Details

#infer_expression(node, env) ⇒ String, ...

표현식 타입 추론

Parameters:

Returns:



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/t_ruby/ast_type_inferrer.rb', line 153

def infer_expression(node, env)
  # 캐시 확인 (지연 평가)
  cache_key = node.object_id
  return @type_cache[cache_key] if @type_cache.key?(cache_key)

  type = case node
         when IR::Literal
           infer_literal(node)
         when IR::VariableRef
           infer_variable_ref(node, env)
         when IR::BinaryOp
           infer_binary_op(node, env)
         when IR::UnaryOp
           infer_unary_op(node, env)
         when IR::MethodCall
           infer_method_call(node, env)
         when IR::ArrayLiteral
           infer_array_literal(node, env)
         when IR::HashLiteral
           infer_hash_literal(node, env)
         when IR::Assignment
           infer_assignment(node, env)
         when IR::Conditional
           infer_conditional(node, env)
         when IR::Block
           infer_block(node, env)
         when IR::Return
           infer_return(node, env)
         when IR::RawCode
           "untyped"
         else
           "untyped"
         end

  @type_cache[cache_key] = type
  type
end

#infer_method_return_type(method_node, class_env = nil) ⇒ String, ...

메서드 반환 타입 추론

Parameters:

  • method_node (IR::MethodDef)

    메서드 정의 IR

  • class_env (TypeEnv, nil) (defaults to: nil)

    클래스 타입 환경

Returns:



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/t_ruby/ast_type_inferrer.rb', line 195

def infer_method_return_type(method_node, class_env = nil)
  return nil unless method_node.body

  # 메서드 스코프 생성
  env = TypeEnv.new(class_env)

  # 파라미터 타입 등록
  method_node.params.each do |param|
    param_type = param.type_annotation&.to_rbs || "untyped"
    env.define(param.name, param_type)
  end

  # 본문에서 반환 타입 수집
  return_types, terminated = collect_return_types(method_node.body, env)

  # 암묵적 반환값 추론 (마지막 표현식) - 종료되지 않은 경우만
  unless terminated
    implicit_return = infer_implicit_return(method_node.body, env)
    return_types << implicit_return if implicit_return
  end

  # 타입 통합
  unify_types(return_types)
end