class Yadriggy::C::ClangTypeChecker

Attributes

instance_variables[R]

@return [Set<IvarObj>] accessed instance variables.

local_vars_table[R]

@return [Hash<Def,Hash<Symbol,Type>>] a map from functions to their

local variables.

Public Class Methods

new(syntax=nil) click to toggle source
Calls superclass method
# File lib/yadriggy/c/ctypecheck.rb, line 59
def initialize(syntax=nil)
  super(syntax || C::syntax)
  @local_vars_table = {}
  @instance_variables = Set.new
end

Public Instance Methods

binary_cexpr_type(op, t1, t2) click to toggle source

@api private

# File lib/yadriggy/c/ctypecheck.rb, line 208
def binary_cexpr_type(op, t1, t2)
  case op
  when :+, :-, :*, :/
    if t1 <= RubyClass::Float || t2 <= RubyClass::Float
      return RubyClass::Float
    elsif t1 <= Float32Type || t2 <= Float32Type
      return Float32Type
    else
      return RubyClass::Integer
    end
  when :%
    type_assert(t1 <= RubyClass::Integer &&
                t2 <= RubyClass::Integer, 'bad operand type')
    return RubyClass::Integer
  when :<, :>, :<=, :>=, :==, :'&&', :'||'
    return RubyClass::Boolean
  else
    type_assert(false, "bad operator: #{ast.op}")
  end
end
check_duplicate(name, t) click to toggle source

@api private

# File lib/yadriggy/c/ctypecheck.rb, line 139
def check_duplicate(name, t)
  old_type = type_env.bound_name?(name)
  type_assert(old_type.nil? || old_type == t,
              "incompatible or duplicate declaration: #{name}")
end
declare_type(name, name_ast, t) click to toggle source

@api private

# File lib/yadriggy/c/ctypecheck.rb, line 120
def declare_type(name, name_ast, t)
  if name == 'return' || name == 'foreign'
    type_assert(valid_type?(t) || t == Void,
                "bad return type: #{t.name}")
    check_duplicate(name, t)
    type_env.bind_name(name.to_sym, t)
  elsif name == 'native'
    type_assert(t.is_a?(String), 'bad native argument. not String.')
    type_assert(type_env.bound_name?(:native).nil?,
                'duplicate declaration: native')
    type_env.bind_name(:native, InstanceType.new(t))
  else
    type_assert(valid_type?(t), "bad parameter type: #{name}")
    check_duplicate(name, t)
    bind_local_var(type_env, name_ast, t, false)
  end
end
is_subsumed_by?(sub_type, super_type) click to toggle source
# File lib/yadriggy/c/ctypecheck.rb, line 78
def is_subsumed_by?(sub_type, super_type)
  (valid_var_type?(sub_type) && valid_var_type?(super_type)) ||
    sub_type <= super_type
end
method_with_block?(name) click to toggle source

Specifies the names of methods with a block.

@param [String] name a method name. @see CodeGen#call_with_block @see typecheck_call_with_block

# File lib/yadriggy/c/ctypecheck.rb, line 321
def method_with_block?(name)
  name == 'times'
end
typecheck_call_with_block(call_ast) click to toggle source
# File lib/yadriggy/c/ctypecheck.rb, line 325
def typecheck_call_with_block(call_ast)
  type_assert(ast.name.name == 'times',
              "no such method: #{ast.name.name}")
  type_assert(type(ast.receiver) == RubyClass::Integer,
              'the receiver must be an integer')
  type_assert(ast.block.params.size == 1,
              "wrong number of block parameters")
  type_as(ast.block.params[0], RubyClass::Integer)
  tenv = type_env.new_tenv
  tenv.bind_name(ast.block.params[0], RubyClass::Integer)
  tenv.bind_name(:return, Void)
  type(ast.block, tenv)
  Void
end
typedecl_type(type_expr) click to toggle source

@api private @param [ASTnode] type_expr

# File lib/yadriggy/c/ctypecheck.rb, line 101
def typedecl_type(type_expr)
  if type_expr.is_a?(Call)
    type_assert(type_expr.args.size == 1, 'bad array type')
    etype = RubyClass[type_expr.args[0].value]
    type_assert(etype != Undef, 'cannot resolve a type name')
    type_assert(valid_var_type?(etype), "bad array type: #{etype}")
    ArrayType.new(etype)
  else
    rt = type_expr.value
    type_assert(rt != Undef, 'cannot resolve a type name')
    if rt.is_a?(Module) && rt <= FFIArray
      ArrayType.new(RubyClass[rt.element_type])
    else
      RubyClass[rt]
    end
  end
end
valid_type?(t) click to toggle source
# File lib/yadriggy/c/ctypecheck.rb, line 74
def valid_type?(t)
  valid_var_type?(t) || ArrayType.role(t)
end
valid_var_type?(t) click to toggle source
# File lib/yadriggy/c/ctypecheck.rb, line 65
def valid_var_type?(t)
  if t.is_a?(Type)
    et = t.exact_type
    et == Integer || et == Float || et == String || et == Float32
  else
    false
  end
end

Private Instance Methods

def_block_rule(is_block, new_tenv) click to toggle source
# File lib/yadriggy/c/ctypecheck.rb, line 360
def def_block_rule(is_block, new_tenv)
  type_block(ast, new_tenv)

  ptypes = ast.params.map { |v| new_tenv.bound_name?(v.name) }
  ptypes.each_with_index do |t, i|
    type_assert(t, "missing parameter type: #{ast.params[i].name}")
  end
  result_t = new_tenv.bound_name?(:return)
  result_t = new_tenv.bound_name?(:foreign) if result_t.nil?
  type_assert(result_t, 'no return type specified')

  mtype = MethodType.new(ast, ptypes, result_t)
  type_env.bind_name(ast.name.name, mtype.result) unless is_block

  code = new_tenv.bound_name?(:native)
  if code
    ins_t = InstanceType.role(code)
    type_assert(ins_t, 'bad native declaration')
    return NativeMethodType.new(mtype, ins_t.object)
  end

  foreign_value = new_tenv.bound_name?(:foreign)
  if foreign_value && !is_block
    mtype2 = MethodType.new(nil, DynType, result_t)
    return ForeignMethodType.new(mtype2)
  end

  type_assert_later_unless(is_block) do
    body_t = type(ast.body, new_tenv)
    wt = WithReturnType.role(body_t)
    if result_t == Void
      type_assert(wt.nil? || body_t == Void, 'non-void return statement')
    else
      type_assert(wt, 'no return statement')
      type_assert(is_subsumed_by?(result_t, body_t), 'bad result type')
    end

    local_vars = {}
    new_tenv.each do |name, type|
      lvt = LocalVarType.role(type)
      local_vars[name] = type unless lvt.nil?
    end
    ast.params.each do |p|
      local_vars.delete(p.name.to_sym)
    end

    @local_vars_table[ast] = local_vars
  end
  mtype
end
type_assert_later_unless(value) { || ... } click to toggle source
# File lib/yadriggy/c/ctypecheck.rb, line 411
def type_assert_later_unless(value, &proc)
  unless value
    check_later(&proc)
  else
    yield
  end
end
type_block(block_ast, new_env) click to toggle source

Do typing the given block according to typedecl.

# File lib/yadriggy/c/ctypecheck.rb, line 421
def type_block(block_ast, new_env)
  expr0 = nil
  expr1 = nil
  if block_ast.body.is_a?(Exprs)
    size = block_ast.body.expressions.size
    expr0 = block_ast.body.expressions[0] if size > 0
    expr1 = block_ast.body.expressions[1] if size > 1
  else
    expr0 = block_ast.body
  end

  if expr0&.usertype == :return_type
    new_env.bind_name(:return, type(expr0))
  end

  if expr0&.usertype == :typedecl
    type(expr0, new_env)
  elsif expr1&.usertype == :typedecl
    type(expr1, new_env)
  end

  unless new_env.bound_name?(:return) || new_env.bound_name?(:foreign)
    new_env.bind_name(:return, Void)
  end
end