e = object.new

e.defaults = [:object, :array, :number, :string, :exception, :hash, :regex]

e.init = {
  my.variables = [[:]]
  my.unsets = [[]]
  my.variable_type = [[:]]
  my.next_id = 0
  v = my.variables.last
  defaults.each { d | v[d] = d }
}

e.next_var = {
  w = my
  next_unset || { w.next_temp }
}

e.next_unset = {
  my.unsets.last.pop
}

e.next_temp = {
  "_temp#{my.next_id = my.next_id + 1}"
}

e.new_scope = {
  my.unsets << []
  my.variables << [:]
  my.variable_type << [:]
}

e.pop_scope = {
  my.variables.pop
  my.unsets.pop
  my.variable_type.pop
}

e.new_var = { var |
  my.variables.last[var] = next_temp
}

e.local_var? = { var |
  my.variables.last[var]
}

e.get = { var |
  v = null
  my.variables.reverse_each_while { vars |
    v = vars[var]
    v.null?
  }
  v
}

e.set = { var, val |
  my.variables.last[var] = val
}

e.unset = { var |
  true? var.string? && { var.include? "_temp" }
  {
     my.unsets.last << var
     my.variable_type.last[var] = null
  }
}

e.set_type = { var, type |
  my.variable_type.last[var] = type
}

e.get_type = { var |
  t = null
  my.variable_type.reverse_each_while { types |
    t = types[var]
    t.null?
  }
  t
}

e.do_scope = {
    my.unsets << []
  }

e.endo_scope = {
  my.unsets.pop
}


export e, :env