Class: Yadriggy::RubyTypeChecker
- Inherits:
-
TypeChecker
- Object
- Checker
- TypeChecker
- Yadriggy::RubyTypeChecker
- Defined in:
- lib/yadriggy/ruby_typecheck.rb
Overview
Type checker for Ruby.
Most values are typed as DynType but local variables
are identified. So type(ast)
returns
a LocalVarType object if ast
is of a local variable.
A LocalVarType is a Type object that represents not
only the value's type but also the fact that the value
comes from a local variable.
The type of a free variable is the type of the current value of that variable. TypeChecker#type returns an InstanceType object.
This checker also attempts to recursivly trace a call-graph to reify and type-check the ASTs of the called methods.
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.
-
#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_ruby_classes(type_env, arg_types, recv_type, method_name) ⇒ ResultType
Computes the type of the Call expression by searching the receiver class for the called method.
- #type_args_and_block(call_ast) ⇒ Object
- #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, #error_group, #make_base_env, #type, #type?, #type_as, #type_assert, #type_assert_false, #type_assert_later, #type_env, #typecheck, #typedef
Methods inherited from Checker
#ast, #ast_env, #check, #check_all, #check_later, #error!, #error_found!, #error_messages, #errors?, #last_error, #make_base_env, #proceed, rule
Methods included from Yadriggy
debug, debug=, define_syntax, reify, reset_pry
Constructor Details
#initialize(syntax = nil) ⇒ RubyTypeChecker
Returns a new instance of RubyTypeChecker.
21 22 23 24 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 21 def initialize(syntax=nil) super() @syntax = syntax end |
Instance Method Details
#bind_local_var(env, ast, var_type) ⇒ Object
Helper methods for rules They can be overridden.
369 370 371 372 373 374 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 369 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 |
#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
.
411 412 413 414 415 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 411 def get_call_expr_type(call_ast, type_env, method_name) arg_types = call_ast.args.map {|t| type(t) } get_call_expr_type_with_argtypes(call_ast, type_env, method_name, arg_types) 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.
90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 90 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. If its source code is not found, #get_return_type reports an error.
This method #get_return_type 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.
509 510 511 512 513 514 515 516 517 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 509 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_ruby_classes(type_env, arg_types, recv_type, method_name) ⇒ ResultType
Computes the type of the Call expression by searching the receiver class for the called method.
481 482 483 484 485 486 487 488 489 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 481 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 |
#type_args_and_block(call_ast) ⇒ Object
226 227 228 229 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 226 def type_args_and_block(call_ast) call_ast.args.each {|t| type(t) } type(call_ast.block) end |
#type_assert_params(params, args, errmsg = '') ⇒ Object
376 377 378 379 380 381 382 383 384 385 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 376 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
387 388 389 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 387 def type_assert_subsume(expected_type, actual_type, errmsg='') type_assert(actual_type <= expected_type, errmsg) end |
#type_parameters(an_ast, tenv) ⇒ Object
391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/yadriggy/ruby_typecheck.rb', line 391 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 |