Class: RDL::Typecheck::Env

Inherits:
Object
  • Object
show all
Defined in:
lib/rdl/typecheck.rb

Overview

Local variable environment tracks the types of local variables, and whether they’re “fixed,” i.e., whether they should be treated flow-insensitively

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = nil) ⇒ Env

+ params +

is a map from Symbols to Types. This initial variable mapping

is added to the Env, and these initial mappings are fixed. If params is nil, initial Env is empty.



54
55
56
57
58
59
60
61
# File 'lib/rdl/typecheck.rb', line 54

def initialize(params = nil)
  @env = Hash.new
  unless params.nil?
    params.each_pair { |var, typ|
      @env[var] = {type: typ, fixed: true}
    }
  end
end

Instance Attribute Details

#envObject

Returns the value of attribute env.



49
50
51
# File 'lib/rdl/typecheck.rb', line 49

def env
  @env
end

Class Method Details

.join(e, *envs) ⇒ Object

+ envs +

is Array<Env>

any elts of envs that are nil are discarded returns new Env where every key is mapped to the union of its bindings in the envs any fixed binding in any env must be fixed in all envs and at the same type

Raises:

  • (RuntimeError)


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rdl/typecheck.rb', line 107

def self.join(e, *envs)
  raise RuntimeError, "Expecting AST, got #{e.class}" unless e.is_a? AST::Node
  env = Env.new
  envs.delete(nil)
  return env if envs.empty?
  return envs[0] if envs.size == 1
  first = envs[0]
  rest = envs[1..-1]
  first.env.each_pair { |var, h|
    first_typ = h[:type]
    if h[:fixed]
      error :inconsistent_var_type, [var.to_s], e unless rest.all? { |other| (other.fixed? var) || (not (other.has_key? var)) }
      neq = []
      rest.each { |other|
        other_typ = other[var]
        neq << other_typ unless first_typ == other_typ
      }
      error :inconsistent_var_type_type, [var.to_s, (first_typ + neq).map { |t| t.to_s }.join(' and ')], e unless neq.empty?
      env.env[var] = {type: h[:type], fixed: true}
    else
      typ = RDL::Type::UnionType.new(first_typ, *rest.map { |other| ((other.has_key? var) && other[var]) || RDL::Globals.types[:nil] })
      typ = typ.canonical
      env.env[var] = {type: typ, fixed: false}
    end
  }
  return env
end

Instance Method Details

#==(other) ⇒ Object



91
92
93
94
# File 'lib/rdl/typecheck.rb', line 91

def ==(other)
  return false unless other.is_a? Env
  return @env == other.env
end

#[](var) ⇒ Object

+ var +

is a Symbol



64
65
66
# File 'lib/rdl/typecheck.rb', line 64

def [](var)
  return @env[var][:type]
end

#bind(var, typ, force: false) ⇒ Object

force should only be used with care! currently only used when type is being refined to a subtype in a lexical scope

Raises:

  • (RuntimeError)


69
70
71
72
73
74
# File 'lib/rdl/typecheck.rb', line 69

def bind(var, typ, force: false)
  raise RuntimeError, "Can't update variable with fixed type" if !force && @env[var] && @env[var][:fixed]
  result = Env.new
  result.env = @env.merge(var => {type: typ, fixed: false})
  return result
end

#fix(var, typ) ⇒ Object

Raises:

  • (RuntimeError)


80
81
82
83
84
85
# File 'lib/rdl/typecheck.rb', line 80

def fix(var, typ)
  raise RuntimeError, "Can't fix type of already-bound variable" if @env[var]
  result = Env.new
  result.env = @env.merge(var => {type: typ, fixed: true})
  return result
end

#fixed?(var) ⇒ Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/rdl/typecheck.rb', line 87

def fixed?(var)
  return @env[var] && @env[var][:fixed]
end

#has_key?(var) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/rdl/typecheck.rb', line 76

def has_key?(var)
  return @env.has_key?(var)
end

#merge(other) ⇒ Object

merges bindings in self with bindings in other, preferring bindings in other if there is a common key



97
98
99
100
101
# File 'lib/rdl/typecheck.rb', line 97

def merge(other)
  result = Env.new
  result.env = @env.merge(other.env)
  return result
end