core/lexical_scope.rb
##
# A linked list that details the static, lexical scope the method was created
# in.
#
# TODO: document
module Rubinius
class LexicalScope
def self.of_sender
Rubinius.primitive :lexical_scope_of_sender
raise PrimitiveFailure, "primitive failed"
end
def class_variable_get(sym)
Rubinius.primitive :lexical_scope_cvar_get
raise NameError, "Invalid class variable name '#{sym}'"
end
def class_variable_set(sym, val)
Rubinius.primitive :lexical_scope_cvar_set
raise NameError, "Invalid class variable name '#{sym}'"
end
def class_variable_defined?(sym)
Rubinius.primitive :lexical_scope_cvar_defined
raise NameError, "Invalid class variable name '#{sym}'"
end
def class_variable_get_or_set(sym, val)
Rubinius.primitive :lexical_scope_cvar_get_or_set
raise NameError, "Invalid class variable name '#{sym}'"
end
#
# @todo Verify the recursion here does not cause problems. --rue
#
def initialize(mod, par = nil)
@module = mod
@parent = par
end
private :initialize
# Source code of this scope.
attr_accessor :script
# The function map for this scope references its top-most parent's map
attr_accessor :functions
# Module or class this lexical scope enclosed into.
attr_reader :module
# Constant scope object this scope enclosed into.
attr_reader :parent
# Module or class representing the 'current class'. MRI manipulates
# this outside of the lexical scope and uses it for undef and method
# definition.
attr_accessor :current_module
# Set to indicate that no methods may be add to this scope
attr_accessor :disabled_for_methods
# Lazy initialized hash map used for flip-flops
attr_accessor :flip_flops
def const_defined?(name, search_parents=true)
scope = self
while scope and scope.module != Object
return true if scope.module.const_defined?(name)
scope = scope.parent
end
return Object.const_defined?(name)
end
def inspect
current = " current=#{@current_module}" if @current_module
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} parent=#{@parent.inspect} module=#{@module}#{current}>"
end
def to_s
inspect
end
# Indicates if this is a toplevel/default scope
def top_level?
!@parent
end
# Use the same info as the current LexicalScope, but set current_module to
# +mod+. Chains off the current LexicalScope.
def using_current_as(mod)
if top_level?
# Don't chain up if this is a toplevel, create a new one.
cs = dup
else
cs = LexicalScope.new @module, self
end
cs.current_module = mod
return cs
end
def using_disabled_scope
cs = using_current_as(@module)
cs.disabled_for_methods = true
return cs
end
def for_method_definition
if @disabled_for_methods
raise TypeError, "unable to create methods in this scope"
end
return @current_module if @current_module
return @module
end
def alias_method(name, original)
Rubinius.privately do
for_method_definition.alias_method name, original
end
end
def __undef_method__(name)
Rubinius.privately do
for_method_definition.undef_method name
end
end
def active_path
script = current_script
if script
if path = script.file_path
return path.dup
end
end
return "__unknown__.rb"
end
def absolute_active_path
script = current_script
if script
if path = script.data_path
return path.dup
end
end
return nil
end
def data_path
script = current_script
if script and script.main?
if path = script.data_path
return path.dup
end
end
return nil
end
def current_script
scope = self
while scope and !scope.script
scope = scope.parent
end
return scope && scope.script
end
def const_set(name, value)
@module.const_set name, value
end
end
end