Class: Yadriggy::RubyTypeChecker
- Inherits:
-
TypeChecker
- Object
- Checker
- TypeChecker
- Yadriggy::RubyTypeChecker
- Defined in:
- lib/yadriggy/ruby_typecheck.rb
Overview
Type checker for Ruby
Direct Known Subclasses
Constant Summary
Constants included from Yadriggy
Instance Method Summary collapse
-
#bind_local_var(env, ast, var_type) ⇒ Object
Helper methods for rules They can be overridden.
-
#clear_references ⇒ Object
Makes the references set empty.
-
#get_call_expr_type(call_ast, type_env, method_name) ⇒ ResultType
Computes the type of Call expression.
-
#get_name_type(name_ast, tenv) ⇒ Object
Gets the type of a given name, which may be a local variable or a free variable.
-
#get_return_type(an_ast, mthd, new_tenv, arg_types) ⇒ ResultType
Type-checks whether the argument types match parameter types.
-
#initialize(syntax = nil) ⇒ RubyTypeChecker
constructor
A new instance of RubyTypeChecker.
- #lookup_builtin(recv_type, method_name) ⇒ Object
- #lookup_ruby_classes(type_env, arg_types, recv_type, method_name) ⇒ Object
-
#references ⇒ Set<Object>
All the constants that the type-checked code has referred to.
- #type_assert_params(params, args, errmsg = '') ⇒ Object
- #type_assert_subsume(expected_type, actual_type, errmsg = '') ⇒ Object
- #type_parameters(an_ast, tenv) ⇒ Object
Methods inherited from TypeChecker
#add_typedef, #check, #error_group, #make_base_env, #type, #type_as, #type_assert, #type_assert_false, #type_assert_later, #type_env, #typecheck, #typedef
Methods inherited from Checker
all_rules, #apply_typing_rule, #ast, #ast_env, #check, #check_all, check_init_class, #check_later, #error, #error_found!, #error_group, find_rule_entry, #make_base_env, #proceed, rule
Methods included from Yadriggy
debug, debug=, define_syntax, reify
Constructor Details
#initialize(syntax = nil) ⇒ RubyTypeChecker
Returns a new instance of RubyTypeChecker.
10 11 12 13 14 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 10 def initialize(syntax=nil) super() @syntax = syntax @referred_objects = Set.new end |
Instance Method Details
#bind_local_var(env, ast, var_type) ⇒ Object
Helper methods for rules They can be overridden.
338 339 340 341 342 343 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 338 def bind_local_var(env, ast, var_type) unless var_type.nil? env.bind_name(ast, LocalVarType.new(var_type.copy(OptionalRole), ast)) @typetable[ast] = var_type end end |
#clear_references ⇒ Object
Makes the references set empty. The references set is a set of constants returned by #references.
25 26 27 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 25 def clear_references @referred_objects = Set.new end |
#get_call_expr_type(call_ast, type_env, method_name) ⇒ ResultType
Computes the type of Call expression. If it finds ‘method_name` in `type_env`, it returns its type recorded in `type_env`.
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 380 def get_call_expr_type(call_ast, type_env, method_name) arg_types = call_ast.args.map {|t| type(t) } type(call_ast.block_arg) type(call_ast.block) if call_ast.receiver.nil? found_t = type_env.bound_name?(method_name) unless found_t.nil? recv_type = DynType else recv_obj = call_ast.get_receiver_object recv_type = if recv_obj.nil? if type_env.context.nil? DynType else RubyClass[type_env.context] # self's type end else InstanceType.new(recv_obj) end end else found_t = nil recv_type = type(call_ast.receiver) end if !found_t.nil? found_t elsif DynType == recv_type || DynType == recv_type.exact_type DynType else lookup_builtin(recv_type, method_name) || lookup_ruby_classes(type_env, arg_types, recv_type, method_name) end end |
#get_name_type(name_ast, tenv) ⇒ Object
Gets the type of a given name, which may be a local variable or a free variable.
75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 75 def get_name_type(name_ast, tenv) type = tenv.bound_name?(name_ast) if type type else v = name_ast.value if v == Undef DynType else InstanceType.new(v) end end end |
#get_return_type(an_ast, mthd, new_tenv, arg_types) ⇒ ResultType
Type-checks whether the argument types match parameter types. It returns a Yadriggy::ResultType.
Override this method to delimit reification. The implementation in this class reifies any method. The method does not have to return a ResultType, which can be used in a later phase to obtain the invoked method. This method is invoked by rule(Call). See rule(Call) for more details.
457 458 459 460 461 462 463 464 465 466 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 457 def get_return_type(an_ast, mthd, new_tenv, arg_types) m_ast = an_ast.root.reify(mthd) type_assert_false(m_ast.nil?, "no source code: for #{mthd}") (@syntax.check(m_ast.tree) || @syntax.raise_error) if @syntax mtype = MethodType.role(type(m_ast.tree, new_tenv)) type_assert(mtype, 'not a method type') type_assert_params(mtype.params, arg_types, 'argument type mismatch') mtype.result end |
#lookup_builtin(recv_type, method_name) ⇒ Object
417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 417 def lookup_builtin(recv_type, method_name) et = recv_type.exact_type if DynType == et nil else mt = typedef(et)&.[](method_name) if mt.nil? nil else MethodType.role(mt)&.result end end end |
#lookup_ruby_classes(type_env, arg_types, recv_type, method_name) ⇒ Object
432 433 434 435 436 437 438 439 440 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 432 def lookup_ruby_classes(type_env, arg_types, recv_type, method_name) begin mth = Type.get_instance_method_object(recv_type, method_name) rescue CheckError => evar error_found!(ast, evar.) end new_tenv = type_env.new_base_tenv(recv_type.exact_type) get_return_type(ast, mth, new_tenv, arg_types) end |
#references ⇒ Set<Object>
Returns all the constants that the type-checked code has referred to. Numbers and classes are excluced.
18 19 20 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 18 def references() @referred_objects end |
#type_assert_params(params, args, errmsg = '') ⇒ Object
345 346 347 348 349 350 351 352 353 354 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 345 def type_assert_params(params, args, errmsg='') unless params == DynType type_assert(params.is_a?(Array), errmsg) type_assert(args.is_a?(Array), errmsg) type_assert(params.length <= args.length, errmsg) # ignore keyword params params.each_with_index do |p, i| type_assert_subsume(p, args[i], errmsg) end end end |
#type_assert_subsume(expected_type, actual_type, errmsg = '') ⇒ Object
356 357 358 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 356 def type_assert_subsume(expected_type, actual_type, errmsg='') type_assert(actual_type <= expected_type, errmsg) end |
#type_parameters(an_ast, tenv) ⇒ Object
360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 360 def type_parameters(an_ast, tenv) an_ast.params.each {|v| bind_local_var(tenv, v, DynType) } an_ast.optionals.each {|v| bind_local_var(tenv, v[0], DynType) } bind_local_var(tenv, an_ast.rest_of_params, DynType) unless an_ast.rest_of_params.nil? an_ast.keywords.each {|v| bind_local_var(tenv, v, DynType) } bind_local_var(tenv, an_ast.rest_of_keywords, DynType) unless an_ast.rest_of_keywords.nil? bind_local_var(tenv, an_ast.block_param, DynType) unless an_ast.block_param.nil? end |