Example #1
0
 def __init__(self, space, name, superclass):
     self.name = name
     self.klass = None
     self.superclass = superclass
     self.version = VersionTag()
     self.methods_w = {}
     self.constants_w = {}
     self.class_variables = CellDict()
     self.instance_variables = CellDict()
     self.lexical_scope = None
     self.included_modules = []
     self.descendants = []
Example #2
0
 def __init__(self, space, name, superclass):
     self.name = name
     self.klass = None
     self.superclass = superclass
     self.version = VersionTag()
     self.methods_w = {}
     self.constants_w = {}
     self.class_variables = CellDict()
     self.instance_variables = CellDict()
     self.lexical_scope = None
     self.included_modules = []
     self.descendants = []
Example #3
0
class W_ModuleObject(W_RootObject):
    _immutable_fields_ = [
        "version?", "included_modules?[*]", "lexical_scope?", "klass?"
    ]

    classdef = ClassDef("Module", W_RootObject.classdef)

    def __init__(self, space, name, superclass):
        self.name = name
        self.klass = None
        self.superclass = superclass
        self.version = VersionTag()
        self.methods_w = {}
        self.constants_w = {}
        self.class_variables = CellDict()
        self.instance_variables = CellDict()
        self.lexical_scope = None
        self.included_modules = []
        self.descendants = []

    def __deepcopy__(self, memo):
        obj = super(W_ModuleObject, self).__deepcopy__(memo)
        obj.name = self.name
        obj.klass = copy.deepcopy(self.klass, memo)
        obj.superclass = copy.deepcopy(self.superclass, memo)
        obj.version = copy.deepcopy(self.version, memo)
        obj.methods_w = copy.deepcopy(self.methods_w, memo)
        obj.constants_w = copy.deepcopy(self.constants_w, memo)
        obj.class_variables = copy.deepcopy(self.class_variables, memo)
        obj.instance_variables = copy.deepcopy(self.instance_variables, memo)
        obj.lexical_scope = copy.deepcopy(self.lexical_scope, memo)
        obj.included_modules = copy.deepcopy(self.included_modules, memo)
        obj.descendants = copy.deepcopy(self.descendants, memo)
        return obj

    def getclass(self, space):
        if self.klass is not None:
            return self.klass
        return W_RootObject.getclass(self, space)

    def getsingletonclass(self, space):
        if self.klass is None:
            self.klass = space.newclass("#<Class:%s>" % self.name,
                                        space.w_module,
                                        is_singleton=True)
        return self.klass

    def mutated(self):
        self.version = VersionTag()

    def define_method(self, space, name, method):
        self.mutated()
        self.methods_w[name] = method

    @jit.unroll_safe
    def find_method(self, space, name):
        method = self._find_method_pure(space, name, self.version)
        if method is None:
            for module in self.included_modules:
                method = module.find_method(space, name)
                if method is not None:
                    return method
        return method

    @jit.unroll_safe
    def find_method_super(self, space, name):
        for module in self.included_modules:
            method = module.find_method(space, name)
            if method is not None:
                return method
        return None

    @jit.elidable
    def _find_method_pure(self, space, method, version):
        return self.methods_w.get(method, None)

    def set_lexical_scope(self, space, w_mod):
        self.lexical_scope = w_mod

    def set_const(self, space, name, w_obj):
        self.mutated()
        self.constants_w[name] = w_obj

    def find_const(self, space, name):
        res = self._find_const_pure(name, self.version)
        if res is None and self.lexical_scope is not None:
            res = self.lexical_scope.find_lexical_const(space, name)
        if res is None and self.superclass is not None:
            res = self.superclass.find_inherited_const(space, name)
        return res

    def find_lexical_const(self, space, name):
        res = self._find_const_pure(name, self.version)
        if res is None and self.lexical_scope is not None:
            return self.lexical_scope.find_lexical_const(space, name)
        return res

    def find_inherited_const(self, space, name):
        res = self._find_const_pure(name, self.version)
        if res is None and self.superclass is not None:
            return self.superclass.find_inherited_const(space, name)
        return res

    def find_local_const(self, space, name):
        return self._find_const_pure(name, self.version)

    @jit.elidable
    def _find_const_pure(self, name, version):
        return self.constants_w.get(name, None)

    @jit.unroll_safe
    def set_class_var(self, space, name, w_obj):
        ancestors = self.ancestors()
        for idx in xrange(len(ancestors) - 1, -1, -1):
            module = ancestors[idx]
            assert isinstance(module, W_ModuleObject)
            w_res = module.class_variables.get(name)
            if w_res is not None or module is self:
                module.class_variables.set(name, w_obj)
                if module is self:
                    for descendant in self.descendants:
                        descendant.remove_class_var(space, name)

    @jit.unroll_safe
    def find_class_var(self, space, name):
        w_res = self.class_variables.get(name)
        if w_res is None:
            ancestors = self.ancestors()
            for idx in xrange(1, len(ancestors)):
                module = ancestors[idx]
                assert isinstance(module, W_ModuleObject)
                w_res = module.class_variables.get(name)
                if w_res is not None:
                    break
        return w_res

    @jit.unroll_safe
    def remove_class_var(self, space, name):
        self.class_variables.delete(name)
        for descendant in self.descendants:
            descendant.remove_class_var(space, name)

    def set_instance_var(self, space, name, w_value):
        return self.instance_variables.set(name, w_value)

    def find_instance_var(self, space, name):
        return self.instance_variables.get(name) or space.w_nil

    def ancestors(self, include_singleton=True, include_self=True):
        if include_self:
            return [self] + self.included_modules
        else:
            return self.included_modules[:]

    def is_ancestor_of(self, w_cls):
        if self is w_cls or self in w_cls.included_modules:
            return True
        elif w_cls.superclass is not None:
            return self.is_ancestor_of(w_cls.superclass)
        else:
            return False

    def include_module(self, space, w_mod):
        assert isinstance(w_mod, W_ModuleObject)
        if w_mod not in self.ancestors():
            self.included_modules = [w_mod] + self.included_modules
            w_mod.included(space, self)

    def included(self, space, w_mod):
        self.descendants.append(w_mod)
        space.send(self, space.newsymbol("included"), [w_mod])

    def inherited(self, space, w_mod):
        self.descendants.append(w_mod)
        if not space.bootstrap:
            space.send(self, space.newsymbol("inherited"), [w_mod])

    def set_visibility(self, space, names_w, visibility):
        names = [space.symbol_w(w_name) for w_name in names_w]
        if names:
            for name in names:
                self.set_method_visibility(space, name, visibility)
        else:
            self.set_default_visibility(space, visibility)

    def set_default_visibility(self, space, visibility):
        pass

    def set_method_visibility(self, space, name, visibility):
        pass

    @classdef.method("to_s")
    def method_to_s(self, space):
        return space.newstr_fromstr(self.name)

    @classdef.method("include")
    def method_include(self, space, w_mod):
        space.send(w_mod, space.newsymbol("append_features"), [self])

    @classdef.method("append_features")
    def method_append_features(self, space, w_mod):
        ancestors = self.ancestors()
        for idx in xrange(len(ancestors) - 1, -1, -1):
            w_mod.include_module(space, ancestors[idx])

    @classdef.method("attr_accessor")
    def method_attr_accessor(self, space, args_w):
        self.method_attr_reader(space, args_w)
        for w_arg in args_w:
            varname = space.symbol_w(w_arg)
            self.define_method(space, varname + "=",
                               AttributeWriter("@" + varname))

    @classdef.method("attr_reader")
    def method_attr_reader(self, space, args_w):
        for w_arg in args_w:
            varname = space.symbol_w(w_arg)
            self.define_method(space, varname, AttributeReader("@" + varname))

    @classdef.method("module_function", name="symbol")
    def method_module_function(self, space, name):
        self.attach_method(space, name,
                           self._find_method_pure(space, name, self.version))

    @classdef.method("private_class_method")
    def method_private_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, space.newsymbol("private"), [w_name])

    @classdef.method("public_class_method")
    def method_public_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, space.newsymbol("public"), [w_name])

    @classdef.method("alias_method", new_name="symbol", old_name="symbol")
    def method_alias_method(self, space, new_name, old_name):
        self.define_method(space, new_name, self.find_method(space, old_name))

    @classdef.method("ancestors")
    def method_ancestors(self, space):
        return space.newarray(self.ancestors(include_singleton=False))

    @classdef.method("inherited")
    def method_inherited(self, space, w_mod):
        pass

    @classdef.method("included")
    def method_included(self, space, w_mod):
        pass

    @classdef.method("name")
    def method_name(self, space):
        return space.newstr_fromstr(self.name)

    @classdef.method("private")
    def method_private(self, space, args_w):
        self.set_visibility(space, args_w, "private")

    @classdef.method("public")
    def method_public(self, space, args_w):
        self.set_visibility(space, args_w, "public")

    @classdef.method("protected")
    def method_protected(self, space, args_w):
        self.set_visibility(space, args_w, "protected")

    @classdef.method("constants")
    def method_constants(self, space):
        return space.newarray([space.newsymbol(n) for n in self.constants_w])

    @classdef.method("const_missing", name="symbol")
    def method_const_missing(self, space, name):
        raise space.error(space.w_NameError,
                          "uninitialized constant %s" % name)

    @classdef.method("class_eval", string="str", filename="str")
    @classdef.method("module_eval", string="str", filename="str")
    def method_module_eval(self,
                           space,
                           string=None,
                           filename=None,
                           w_lineno=None,
                           block=None):
        if string is not None:
            if filename is None:
                filename = "module_eval"
            if w_lineno is not None:
                lineno = space.int_w(w_lineno)
            else:
                lineno = 1
            return space.execute(string, self, self, filename, lineno)
        else:
            space.invoke_block(block.copy(w_self=self, w_scope=self), [])

    @classdef.method("const_defined?", const="str", inherit="bool")
    def method_const_definedp(self, space, const, inherit=True):
        if inherit:
            return space.newbool(
                self.find_inherited_const(space, const) is not None)
        else:
            return space.newbool(
                self._find_const_pure(const, self.version) is not None)

    @classdef.method("method_defined?", name="str")
    def method_method_definedp(self, space, name):
        return space.newbool(self.find_method(space, name) is not None)

    @classdef.method("===")
    def method_eqeqeq(self, space, w_obj):
        return space.newbool(self.is_ancestor_of(space.getclass(w_obj)))
Example #4
0
    def __init__(self):
        self.cache = SpaceCache(self)
        self.symbol_cache = {}
        self._executioncontext = None
        self.globals = CellDict()
        self.bootstrap = True
        self.exit_handlers_w = []

        self.w_true = W_TrueObject(self)
        self.w_false = W_FalseObject(self)
        self.w_nil = W_NilObject(self)

        # Force the setup of a few key classes
        self.w_basicobject = self.getclassfor(W_BaseObject)
        self.w_object = self.getclassfor(W_Object)
        self.w_class = self.getclassfor(W_ClassObject)
        self.w_array = self.getclassfor(W_ArrayObject)
        self.w_proc = self.getclassfor(W_ProcObject)
        self.w_fixnum = self.getclassfor(W_FixnumObject)
        self.w_module = self.getclassfor(W_ModuleObject)
        self.w_string = self.getclassfor(W_StringObject)
        self.w_NoMethodError = self.getclassfor(W_NoMethodError)
        self.w_ArgumentError = self.getclassfor(W_ArgumentError)
        self.w_NameError = self.getclassfor(W_NameError)
        self.w_NotImplementedError = self.getclassfor(W_NotImplementedError)
        self.w_IndexError = self.getclassfor(W_IndexError)
        self.w_LoadError = self.getclassfor(W_LoadError)
        self.w_RangeError = self.getclassfor(W_RangeError)
        self.w_RuntimeError = self.getclassfor(W_RuntimeError)
        self.w_StopIteration = self.getclassfor(W_StopIteration)
        self.w_SyntaxError = self.getclassfor(W_SyntaxError)
        self.w_SystemCallError = self.getclassfor(W_SystemCallError)
        self.w_SystemExit = self.getclassfor(W_SystemExit)
        self.w_TypeError = self.getclassfor(W_TypeError)
        self.w_ZeroDivisionError = self.getclassfor(W_ZeroDivisionError)
        self.w_kernel = self.getmoduleobject(Kernel.moduledef)

        self.w_topaz = self.getmoduleobject(Topaz.moduledef)

        for w_cls in [
            self.w_basicobject, self.w_object, self.w_array, self.w_proc,
            self.w_fixnum, self.w_string, self.w_class, self.w_module,

            self.w_NoMethodError, self.w_ArgumentError, self.w_TypeError,
            self.w_ZeroDivisionError, self.w_SystemExit, self.w_RangeError,
            self.w_RuntimeError, self.w_SystemCallError, self.w_LoadError,
            self.w_StopIteration, self.w_SyntaxError,

            self.w_kernel, self.w_topaz,

            self.getclassfor(W_NilObject),
            self.getclassfor(W_TrueObject),
            self.getclassfor(W_FalseObject),
            self.getclassfor(W_SymbolObject),
            self.getclassfor(W_NumericObject),
            self.getclassfor(W_HashObject),
            self.getclassfor(W_RangeObject),
            self.getclassfor(W_IOObject),
            self.getclassfor(W_FileObject),
            self.getclassfor(W_Dir),
            self.getclassfor(W_EncodingObject),
            self.getclassfor(W_RandomObject),
            self.getclassfor(W_ThreadObject),
            self.getclassfor(W_TimeObject),

            self.getclassfor(W_ExceptionObject),
            self.getclassfor(W_StandardError),

            self.getmoduleobject(Comparable.moduledef),
            self.getmoduleobject(Enumerable.moduledef),
            self.getmoduleobject(Math.moduledef),
            self.getmoduleobject(Process.moduledef),
        ]:
            self.set_const(
                self.w_object,
                self.str_w(self.send(w_cls, self.newsymbol("name"))),
                w_cls
            )

        for w_cls in [
            self.getclassfor(W_EnvObject), self.getclassfor(W_HashIterator),
        ]:
            self.set_const(
                self.w_topaz,
                self.str_w(self.send(w_cls, self.newsymbol("name"))),
                w_cls
            )

        self.w_top_self = W_Object(self, self.w_object)

        # This is bootstrap. We have to delay sending until true, false and nil
        # are defined
        self.send(self.w_object, self.newsymbol("include"), [self.w_kernel])
        self.bootstrap = False

        w_load_path = self.newarray([
            self.newstr_fromstr(
                os.path.join(os.path.dirname(__file__), os.path.pardir, "lib-ruby")
            )
        ])
        self.globals.set("$LOAD_PATH", w_load_path)
        self.globals.set("$:", w_load_path)

        w_loaded_features = self.newarray([])
        self.globals.set("$LOADED_FEATURES", w_loaded_features)
        self.globals.set('$"', w_loaded_features)
Example #5
0
class ObjectSpace(object):
    def __init__(self):
        self.cache = SpaceCache(self)
        self.symbol_cache = {}
        self._executioncontext = None
        self.globals = CellDict()
        self.bootstrap = True
        self.exit_handlers_w = []

        self.w_true = W_TrueObject(self)
        self.w_false = W_FalseObject(self)
        self.w_nil = W_NilObject(self)

        # Force the setup of a few key classes
        self.w_basicobject = self.getclassfor(W_BaseObject)
        self.w_object = self.getclassfor(W_Object)
        self.w_class = self.getclassfor(W_ClassObject)
        self.w_array = self.getclassfor(W_ArrayObject)
        self.w_proc = self.getclassfor(W_ProcObject)
        self.w_fixnum = self.getclassfor(W_FixnumObject)
        self.w_module = self.getclassfor(W_ModuleObject)
        self.w_string = self.getclassfor(W_StringObject)
        self.w_NoMethodError = self.getclassfor(W_NoMethodError)
        self.w_ArgumentError = self.getclassfor(W_ArgumentError)
        self.w_NameError = self.getclassfor(W_NameError)
        self.w_NotImplementedError = self.getclassfor(W_NotImplementedError)
        self.w_IndexError = self.getclassfor(W_IndexError)
        self.w_LoadError = self.getclassfor(W_LoadError)
        self.w_RangeError = self.getclassfor(W_RangeError)
        self.w_RuntimeError = self.getclassfor(W_RuntimeError)
        self.w_StopIteration = self.getclassfor(W_StopIteration)
        self.w_SyntaxError = self.getclassfor(W_SyntaxError)
        self.w_SystemCallError = self.getclassfor(W_SystemCallError)
        self.w_SystemExit = self.getclassfor(W_SystemExit)
        self.w_TypeError = self.getclassfor(W_TypeError)
        self.w_ZeroDivisionError = self.getclassfor(W_ZeroDivisionError)
        self.w_kernel = self.getmoduleobject(Kernel.moduledef)

        self.w_topaz = self.getmoduleobject(Topaz.moduledef)

        for w_cls in [
            self.w_basicobject, self.w_object, self.w_array, self.w_proc,
            self.w_fixnum, self.w_string, self.w_class, self.w_module,

            self.w_NoMethodError, self.w_ArgumentError, self.w_TypeError,
            self.w_ZeroDivisionError, self.w_SystemExit, self.w_RangeError,
            self.w_RuntimeError, self.w_SystemCallError, self.w_LoadError,
            self.w_StopIteration, self.w_SyntaxError,

            self.w_kernel, self.w_topaz,

            self.getclassfor(W_NilObject),
            self.getclassfor(W_TrueObject),
            self.getclassfor(W_FalseObject),
            self.getclassfor(W_SymbolObject),
            self.getclassfor(W_NumericObject),
            self.getclassfor(W_HashObject),
            self.getclassfor(W_RangeObject),
            self.getclassfor(W_IOObject),
            self.getclassfor(W_FileObject),
            self.getclassfor(W_Dir),
            self.getclassfor(W_EncodingObject),
            self.getclassfor(W_RandomObject),
            self.getclassfor(W_ThreadObject),
            self.getclassfor(W_TimeObject),

            self.getclassfor(W_ExceptionObject),
            self.getclassfor(W_StandardError),

            self.getmoduleobject(Comparable.moduledef),
            self.getmoduleobject(Enumerable.moduledef),
            self.getmoduleobject(Math.moduledef),
            self.getmoduleobject(Process.moduledef),
        ]:
            self.set_const(
                self.w_object,
                self.str_w(self.send(w_cls, self.newsymbol("name"))),
                w_cls
            )

        for w_cls in [
            self.getclassfor(W_EnvObject), self.getclassfor(W_HashIterator),
        ]:
            self.set_const(
                self.w_topaz,
                self.str_w(self.send(w_cls, self.newsymbol("name"))),
                w_cls
            )

        self.w_top_self = W_Object(self, self.w_object)

        # This is bootstrap. We have to delay sending until true, false and nil
        # are defined
        self.send(self.w_object, self.newsymbol("include"), [self.w_kernel])
        self.bootstrap = False

        w_load_path = self.newarray([
            self.newstr_fromstr(
                os.path.join(os.path.dirname(__file__), os.path.pardir, "lib-ruby")
            )
        ])
        self.globals.set("$LOAD_PATH", w_load_path)
        self.globals.set("$:", w_load_path)

        w_loaded_features = self.newarray([])
        self.globals.set("$LOADED_FEATURES", w_loaded_features)
        self.globals.set('$"', w_loaded_features)

    def _freeze_(self):
        return True

    @specialize.memo()
    def fromcache(self, key):
        return self.cache.getorbuild(key)

    # Methods for dealing with source code.

    def parse(self, source, initial_lineno=1, symtable=None):
        if symtable is None:
            symtable = SymbolTable()
        parser = Parser(Lexer(source, initial_lineno=initial_lineno, symtable=symtable))
        try:
            return parser.parse().getast()
        except ParsingError as e:
            raise self.error(self.w_SyntaxError, "line %d" % e.getsourcepos().lineno)
        except LexerError as e:
            raise self.error(self.w_SyntaxError, "line %d" % e.pos.lineno)

    def compile(self, source, filepath, initial_lineno=1):
        symtable = SymbolTable()
        astnode = self.parse(source, initial_lineno=initial_lineno, symtable=symtable)
        ctx = CompilerContext(self, "<main>", symtable, filepath)
        with ctx.set_lineno(initial_lineno):
            astnode.compile(ctx)
        return ctx.create_bytecode([], [], None, None)

    def execute(self, source, w_self=None, w_scope=None, filepath="-e", initial_lineno=1):
        bc = self.compile(source, filepath, initial_lineno=initial_lineno)
        frame = self.create_frame(bc, w_self=w_self, w_scope=w_scope)
        with self.getexecutioncontext().visit_frame(frame):
            return self.execute_frame(frame, bc)

    @jit.loop_invariant
    def getexecutioncontext(self):
        # When we have threads this should become a thread local.
        if self._executioncontext is None:
            self._executioncontext = ExecutionContext(self)
        return self._executioncontext

    def create_frame(self, bc, w_self=None, w_scope=None, block=None,
        parent_interp=None):

        if w_self is None:
            w_self = self.w_top_self
        if w_scope is None:
            w_scope = self.w_object
        return Frame(jit.promote(bc), w_self, w_scope, block, parent_interp)

    def execute_frame(self, frame, bc):
        return Interpreter().interpret(self, frame, bc)

    # Methods for allocating new objects.

    def newbool(self, boolvalue):
        if boolvalue:
            return self.w_true
        else:
            return self.w_false

    def newint(self, intvalue):
        return W_FixnumObject(self, intvalue)

    def newfloat(self, floatvalue):
        return W_FloatObject(self, floatvalue)

    @jit.elidable
    def newsymbol(self, symbol):
        try:
            w_sym = self.symbol_cache[symbol]
        except KeyError:
            w_sym = self.symbol_cache[symbol] = W_SymbolObject(self, symbol)
        return w_sym

    def newstr_fromchars(self, chars):
        return W_StringObject.newstr_fromchars(self, chars)

    def newstr_fromstr(self, strvalue):
        return W_StringObject.newstr_fromstr(self, strvalue)

    def newarray(self, items_w):
        return W_ArrayObject(self, items_w)

    def newhash(self):
        return W_HashObject(self)

    def newrange(self, w_start, w_end, exclusive):
        return W_RangeObject(self, w_start, w_end, exclusive)

    def newregexp(self, regexp):
        return W_RegexpObject(self, regexp)

    def newmodule(self, name):
        return W_ModuleObject(self, name, self.w_object)

    def newclass(self, name, superclass, is_singleton=False):
        return W_ClassObject(self, name, superclass, is_singleton=is_singleton)

    def newfunction(self, w_name, w_code):
        name = self.symbol_w(w_name)
        assert isinstance(w_code, W_CodeObject)
        return W_UserFunction(name, w_code)

    def newproc(self, block, is_lambda=False):
        return W_ProcObject(self, block, is_lambda)

    def int_w(self, w_obj):
        return w_obj.int_w(self)

    def float_w(self, w_obj):
        return w_obj.float_w(self)

    def symbol_w(self, w_obj):
        return w_obj.symbol_w(self)

    def str_w(self, w_obj):
        """Unpacks a string object as an rstr."""
        return w_obj.str_w(self)

    def listview(self, w_obj):
        return w_obj.listview(self)

    # Methods for implementing the language semantics.

    def is_true(self, w_obj):
        return w_obj.is_true(self)

    def getclass(self, w_receiver):
        return w_receiver.getclass(self)

    def getsingletonclass(self, w_receiver):
        return w_receiver.getsingletonclass(self)

    def getscope(self, w_receiver):
        if isinstance(w_receiver, W_ModuleObject):
            return w_receiver
        else:
            return self.getclass(w_receiver)

    @jit.unroll_safe
    def getnonsingletonclass(self, w_receiver):
        cls = self.getclass(w_receiver)
        while cls.is_singleton:
            cls = cls.superclass
        return cls

    def getclassfor(self, cls):
        return self.getclassobject(cls.classdef)

    def getclassobject(self, classdef):
        return self.fromcache(ClassCache).getorbuild(classdef)

    def getmoduleobject(self, moduledef):
        return self.fromcache(ModuleCache).getorbuild(moduledef)

    def find_const(self, w_module, name):
        w_obj = w_module.find_const(self, name)
        if w_obj is None:
            w_obj = self.send(w_module, self.newsymbol("const_missing"), [self.newsymbol(name)])
        return w_obj

    def set_const(self, module, name, w_value):
        module.set_const(self, name, w_value)

    def set_lexical_scope(self, module, scope):
        module.set_lexical_scope(self, scope)

    def find_instance_var(self, w_obj, name):
        w_res = w_obj.find_instance_var(self, name)
        return w_res if w_res is not None else self.w_nil

    def set_instance_var(self, w_obj, name, w_value):
        w_obj.set_instance_var(self, name, w_value)

    def find_class_var(self, w_module, name):
        return w_module.find_class_var(self, name)

    def set_class_var(self, w_module, name, w_value):
        w_module.set_class_var(self, name, w_value)

    def send(self, w_receiver, w_method, args_w=None, block=None):
        if args_w is None:
            args_w = []
        name = self.symbol_w(w_method)

        w_cls = self.getclass(w_receiver)
        raw_method = w_cls.find_method(self, name)
        return self._send_raw(w_method, raw_method, w_receiver, w_cls, args_w, block)

    def send_super(self, w_cls, w_receiver, w_method, args_w, block=None):
        name = self.symbol_w(w_method)
        raw_method = w_cls.find_method_super(self, name)
        return self._send_raw(w_method, raw_method, w_receiver, w_cls, args_w, block)

    def _send_raw(self, w_method, raw_method, w_receiver, w_cls, args_w, block):
        if raw_method is None:
            method_missing = w_cls.find_method(self, "method_missing")
            assert method_missing is not None
            args_w.insert(0, w_method)
            return method_missing.call(self, w_receiver, args_w, block)
        return raw_method.call(self, w_receiver, args_w, block)

    def respond_to(self, w_receiver, w_method):
        name = self.symbol_w(w_method)
        w_cls = self.getclass(w_receiver)
        raw_method = w_cls.find_method(self, name)
        return raw_method is not None

    @jit.unroll_safe
    def invoke_block(self, block, args_w):
        bc = block.bytecode
        frame = self.create_frame(
            bc, w_self=block.w_self, w_scope=block.w_scope, block=block.block,
            parent_interp=block.parent_interp,
        )
        if (len(args_w) == 1 and
            isinstance(args_w[0], W_ArrayObject) and len(bc.arg_locs) >= 2):
            w_arg = args_w[0]
            assert isinstance(w_arg, W_ArrayObject)
            args_w = w_arg.items_w
        if len(bc.arg_locs) != 0:
            frame.handle_block_args(self, bc, args_w, None)
        assert len(block.cells) == len(bc.freevars)
        for idx, cell in enumerate(block.cells):
            frame.cells[len(bc.cellvars) + idx] = cell

        with self.getexecutioncontext().visit_frame(frame):
            return self.execute_frame(frame, bc)

    def error(self, w_type, msg="", optargs=None):
        if not optargs:
            optargs = []
        w_new_sym = self.newsymbol("new")
        args_w = [self.newstr_fromstr(msg)] + optargs
        w_exc = self.send(w_type, w_new_sym, args_w)
        assert isinstance(w_exc, W_ExceptionObject)
        return RubyError(w_exc)

    def hash_w(self, w_obj):
        return self.int_w(self.send(w_obj, self.newsymbol("hash")))

    def eq_w(self, w_obj1, w_obj2):
        return self.is_true(self.send(w_obj1, self.newsymbol("=="), [w_obj2]))

    def register_exit_handler(self, w_proc):
        self.exit_handlers_w.append(w_proc)

    def run_exit_handlers(self):
        while self.exit_handlers_w:
            w_proc = self.exit_handlers_w.pop()
            try:
                self.send(w_proc, self.newsymbol("call"))
            except RubyError as e:
                print_traceback(self, e.w_value)

    def subscript_access(self, length, w_idx, w_count):
        inclusive = False
        as_range = False
        end = 0

        if isinstance(w_idx, W_RangeObject) and not w_count:
            start = self.int_w(self.convert_type(w_idx.w_start, self.w_fixnum, "to_int"))
            end = self.int_w(self.convert_type(w_idx.w_end, self.w_fixnum, "to_int"))
            inclusive = not w_idx.exclusive
            as_range = True
        else:
            start = self.int_w(self.convert_type(w_idx, self.w_fixnum, "to_int"))
            if w_count:
                end = self.int_w(self.convert_type(w_count, self.w_fixnum, "to_int"))
                if end >= 0:
                    as_range = True

        if start < 0:
            start += length
        if as_range:
            if w_count:
                end += start
            if end < 0:
                end += length
            if inclusive:
                end += 1
            if end < start:
                end = start
            elif end > length:
                end = length

        nil = ((not as_range and start >= length) or
            start < 0 or end < 0 or (start > 0 and start > length))
        return (start, end, as_range, nil)

    def convert_type(self, w_obj, w_cls, method, raise_error=True):
        if w_obj.is_kind_of(self, w_cls):
            return w_obj

        try:
            w_res = self.send(w_obj, self.newsymbol(method))
        except RubyError:
            src_cls = self.getclass(w_obj).name
            raise self.error(
                self.w_TypeError, "can't convert %s into %s" % (src_cls, w_cls.name)
            )

        if not w_res or w_res is self.w_nil and not raise_error:
            return self.w_nil
        elif not w_res.is_kind_of(self, w_cls):
            src_cls = self.getclass(w_obj).name
            res_cls = self.getclass(w_res).name
            raise self.error(self.w_TypeError,
                "can't convert %s to %s (%s#%s gives %s)" % (
                    src_cls, w_cls.name, src_cls, method, res_cls
                )
            )
        else:
            return w_res
Example #6
0
    def __init__(self):
        self.cache = SpaceCache(self)
        self.symbol_cache = {}
        self._executioncontext = None
        self.globals = CellDict()
        self.bootstrap = True
        self.exit_handlers_w = []

        self.w_true = W_TrueObject(self)
        self.w_false = W_FalseObject(self)
        self.w_nil = W_NilObject(self)

        # Force the setup of a few key classes
        self.w_basicobject = self.getclassfor(W_BaseObject)
        self.w_object = self.getclassfor(W_Object)
        self.w_class = self.getclassfor(W_ClassObject)
        self.w_array = self.getclassfor(W_ArrayObject)
        self.w_proc = self.getclassfor(W_ProcObject)
        self.w_fixnum = self.getclassfor(W_FixnumObject)
        self.w_module = self.getclassfor(W_ModuleObject)
        self.w_string = self.getclassfor(W_StringObject)
        self.w_NoMethodError = self.getclassfor(W_NoMethodError)
        self.w_ArgumentError = self.getclassfor(W_ArgumentError)
        self.w_NameError = self.getclassfor(W_NameError)
        self.w_NotImplementedError = self.getclassfor(W_NotImplementedError)
        self.w_IndexError = self.getclassfor(W_IndexError)
        self.w_LoadError = self.getclassfor(W_LoadError)
        self.w_RangeError = self.getclassfor(W_RangeError)
        self.w_RuntimeError = self.getclassfor(W_RuntimeError)
        self.w_StopIteration = self.getclassfor(W_StopIteration)
        self.w_SyntaxError = self.getclassfor(W_SyntaxError)
        self.w_SystemCallError = self.getclassfor(W_SystemCallError)
        self.w_SystemExit = self.getclassfor(W_SystemExit)
        self.w_TypeError = self.getclassfor(W_TypeError)
        self.w_ZeroDivisionError = self.getclassfor(W_ZeroDivisionError)
        self.w_kernel = self.getmoduleobject(Kernel.moduledef)

        self.w_topaz = self.getmoduleobject(Topaz.moduledef)

        for w_cls in [
                self.w_basicobject,
                self.w_object,
                self.w_array,
                self.w_proc,
                self.w_fixnum,
                self.w_string,
                self.w_class,
                self.w_module,
                self.w_NoMethodError,
                self.w_ArgumentError,
                self.w_TypeError,
                self.w_ZeroDivisionError,
                self.w_SystemExit,
                self.w_RangeError,
                self.w_RuntimeError,
                self.w_SystemCallError,
                self.w_LoadError,
                self.w_StopIteration,
                self.w_SyntaxError,
                self.w_kernel,
                self.w_topaz,
                self.getclassfor(W_NilObject),
                self.getclassfor(W_TrueObject),
                self.getclassfor(W_FalseObject),
                self.getclassfor(W_SymbolObject),
                self.getclassfor(W_NumericObject),
                self.getclassfor(W_HashObject),
                self.getclassfor(W_RangeObject),
                self.getclassfor(W_IOObject),
                self.getclassfor(W_FileObject),
                self.getclassfor(W_Dir),
                self.getclassfor(W_EncodingObject),
                self.getclassfor(W_RandomObject),
                self.getclassfor(W_ThreadObject),
                self.getclassfor(W_TimeObject),
                self.getclassfor(W_ExceptionObject),
                self.getclassfor(W_StandardError),
                self.getmoduleobject(Comparable.moduledef),
                self.getmoduleobject(Enumerable.moduledef),
                self.getmoduleobject(Math.moduledef),
                self.getmoduleobject(Process.moduledef),
        ]:
            self.set_const(
                self.w_object,
                self.str_w(self.send(w_cls, self.newsymbol("name"))), w_cls)

        for w_cls in [
                self.getclassfor(W_EnvObject),
                self.getclassfor(W_HashIterator),
        ]:
            self.set_const(
                self.w_topaz,
                self.str_w(self.send(w_cls, self.newsymbol("name"))), w_cls)

        self.w_top_self = W_Object(self, self.w_object)

        # This is bootstrap. We have to delay sending until true, false and nil
        # are defined
        self.send(self.w_object, self.newsymbol("include"), [self.w_kernel])
        self.bootstrap = False

        w_load_path = self.newarray([
            self.newstr_fromstr(
                os.path.join(os.path.dirname(__file__), os.path.pardir,
                             "lib-ruby"))
        ])
        self.globals.set("$LOAD_PATH", w_load_path)
        self.globals.set("$:", w_load_path)

        w_loaded_features = self.newarray([])
        self.globals.set("$LOADED_FEATURES", w_loaded_features)
        self.globals.set('$"', w_loaded_features)
Example #7
0
class ObjectSpace(object):
    def __init__(self):
        self.cache = SpaceCache(self)
        self.symbol_cache = {}
        self._executioncontext = None
        self.globals = CellDict()
        self.bootstrap = True
        self.exit_handlers_w = []

        self.w_true = W_TrueObject(self)
        self.w_false = W_FalseObject(self)
        self.w_nil = W_NilObject(self)

        # Force the setup of a few key classes
        self.w_basicobject = self.getclassfor(W_BaseObject)
        self.w_object = self.getclassfor(W_Object)
        self.w_class = self.getclassfor(W_ClassObject)
        self.w_array = self.getclassfor(W_ArrayObject)
        self.w_proc = self.getclassfor(W_ProcObject)
        self.w_fixnum = self.getclassfor(W_FixnumObject)
        self.w_module = self.getclassfor(W_ModuleObject)
        self.w_string = self.getclassfor(W_StringObject)
        self.w_NoMethodError = self.getclassfor(W_NoMethodError)
        self.w_ArgumentError = self.getclassfor(W_ArgumentError)
        self.w_NameError = self.getclassfor(W_NameError)
        self.w_NotImplementedError = self.getclassfor(W_NotImplementedError)
        self.w_IndexError = self.getclassfor(W_IndexError)
        self.w_LoadError = self.getclassfor(W_LoadError)
        self.w_RangeError = self.getclassfor(W_RangeError)
        self.w_RuntimeError = self.getclassfor(W_RuntimeError)
        self.w_StopIteration = self.getclassfor(W_StopIteration)
        self.w_SyntaxError = self.getclassfor(W_SyntaxError)
        self.w_SystemCallError = self.getclassfor(W_SystemCallError)
        self.w_SystemExit = self.getclassfor(W_SystemExit)
        self.w_TypeError = self.getclassfor(W_TypeError)
        self.w_ZeroDivisionError = self.getclassfor(W_ZeroDivisionError)
        self.w_kernel = self.getmoduleobject(Kernel.moduledef)

        self.w_topaz = self.getmoduleobject(Topaz.moduledef)

        for w_cls in [
                self.w_basicobject,
                self.w_object,
                self.w_array,
                self.w_proc,
                self.w_fixnum,
                self.w_string,
                self.w_class,
                self.w_module,
                self.w_NoMethodError,
                self.w_ArgumentError,
                self.w_TypeError,
                self.w_ZeroDivisionError,
                self.w_SystemExit,
                self.w_RangeError,
                self.w_RuntimeError,
                self.w_SystemCallError,
                self.w_LoadError,
                self.w_StopIteration,
                self.w_SyntaxError,
                self.w_kernel,
                self.w_topaz,
                self.getclassfor(W_NilObject),
                self.getclassfor(W_TrueObject),
                self.getclassfor(W_FalseObject),
                self.getclassfor(W_SymbolObject),
                self.getclassfor(W_NumericObject),
                self.getclassfor(W_HashObject),
                self.getclassfor(W_RangeObject),
                self.getclassfor(W_IOObject),
                self.getclassfor(W_FileObject),
                self.getclassfor(W_Dir),
                self.getclassfor(W_EncodingObject),
                self.getclassfor(W_RandomObject),
                self.getclassfor(W_ThreadObject),
                self.getclassfor(W_TimeObject),
                self.getclassfor(W_ExceptionObject),
                self.getclassfor(W_StandardError),
                self.getmoduleobject(Comparable.moduledef),
                self.getmoduleobject(Enumerable.moduledef),
                self.getmoduleobject(Math.moduledef),
                self.getmoduleobject(Process.moduledef),
        ]:
            self.set_const(
                self.w_object,
                self.str_w(self.send(w_cls, self.newsymbol("name"))), w_cls)

        for w_cls in [
                self.getclassfor(W_EnvObject),
                self.getclassfor(W_HashIterator),
        ]:
            self.set_const(
                self.w_topaz,
                self.str_w(self.send(w_cls, self.newsymbol("name"))), w_cls)

        self.w_top_self = W_Object(self, self.w_object)

        # This is bootstrap. We have to delay sending until true, false and nil
        # are defined
        self.send(self.w_object, self.newsymbol("include"), [self.w_kernel])
        self.bootstrap = False

        w_load_path = self.newarray([
            self.newstr_fromstr(
                os.path.join(os.path.dirname(__file__), os.path.pardir,
                             "lib-ruby"))
        ])
        self.globals.set("$LOAD_PATH", w_load_path)
        self.globals.set("$:", w_load_path)

        w_loaded_features = self.newarray([])
        self.globals.set("$LOADED_FEATURES", w_loaded_features)
        self.globals.set('$"', w_loaded_features)

    def _freeze_(self):
        return True

    @specialize.memo()
    def fromcache(self, key):
        return self.cache.getorbuild(key)

    # Methods for dealing with source code.

    def parse(self, source, initial_lineno=1, symtable=None):
        if symtable is None:
            symtable = SymbolTable()
        parser = Parser(
            Lexer(source, initial_lineno=initial_lineno, symtable=symtable))
        try:
            return parser.parse().getast()
        except ParsingError as e:
            raise self.error(self.w_SyntaxError,
                             "line %d" % e.getsourcepos().lineno)
        except LexerError as e:
            raise self.error(self.w_SyntaxError, "line %d" % e.pos.lineno)

    def compile(self, source, filepath, initial_lineno=1):
        symtable = SymbolTable()
        astnode = self.parse(source,
                             initial_lineno=initial_lineno,
                             symtable=symtable)
        ctx = CompilerContext(self, "<main>", symtable, filepath)
        with ctx.set_lineno(initial_lineno):
            astnode.compile(ctx)
        return ctx.create_bytecode([], [], None, None)

    def execute(self,
                source,
                w_self=None,
                w_scope=None,
                filepath="-e",
                initial_lineno=1):
        bc = self.compile(source, filepath, initial_lineno=initial_lineno)
        frame = self.create_frame(bc, w_self=w_self, w_scope=w_scope)
        with self.getexecutioncontext().visit_frame(frame):
            return self.execute_frame(frame, bc)

    @jit.loop_invariant
    def getexecutioncontext(self):
        # When we have threads this should become a thread local.
        if self._executioncontext is None:
            self._executioncontext = ExecutionContext(self)
        return self._executioncontext

    def create_frame(self,
                     bc,
                     w_self=None,
                     w_scope=None,
                     block=None,
                     parent_interp=None):

        if w_self is None:
            w_self = self.w_top_self
        if w_scope is None:
            w_scope = self.w_object
        return Frame(jit.promote(bc), w_self, w_scope, block, parent_interp)

    def execute_frame(self, frame, bc):
        return Interpreter().interpret(self, frame, bc)

    # Methods for allocating new objects.

    def newbool(self, boolvalue):
        if boolvalue:
            return self.w_true
        else:
            return self.w_false

    def newint(self, intvalue):
        return W_FixnumObject(self, intvalue)

    def newfloat(self, floatvalue):
        return W_FloatObject(self, floatvalue)

    @jit.elidable
    def newsymbol(self, symbol):
        try:
            w_sym = self.symbol_cache[symbol]
        except KeyError:
            w_sym = self.symbol_cache[symbol] = W_SymbolObject(self, symbol)
        return w_sym

    def newstr_fromchars(self, chars):
        return W_StringObject.newstr_fromchars(self, chars)

    def newstr_fromstr(self, strvalue):
        return W_StringObject.newstr_fromstr(self, strvalue)

    def newarray(self, items_w):
        return W_ArrayObject(self, items_w)

    def newhash(self):
        return W_HashObject(self)

    def newrange(self, w_start, w_end, exclusive):
        return W_RangeObject(self, w_start, w_end, exclusive)

    def newregexp(self, regexp):
        return W_RegexpObject(self, regexp)

    def newmodule(self, name):
        return W_ModuleObject(self, name, self.w_object)

    def newclass(self, name, superclass, is_singleton=False):
        return W_ClassObject(self, name, superclass, is_singleton=is_singleton)

    def newfunction(self, w_name, w_code):
        name = self.symbol_w(w_name)
        assert isinstance(w_code, W_CodeObject)
        return W_UserFunction(name, w_code)

    def newproc(self, block, is_lambda=False):
        return W_ProcObject(self, block, is_lambda)

    def int_w(self, w_obj):
        return w_obj.int_w(self)

    def float_w(self, w_obj):
        return w_obj.float_w(self)

    def symbol_w(self, w_obj):
        return w_obj.symbol_w(self)

    def str_w(self, w_obj):
        """Unpacks a string object as an rstr."""
        return w_obj.str_w(self)

    def listview(self, w_obj):
        return w_obj.listview(self)

    # Methods for implementing the language semantics.

    def is_true(self, w_obj):
        return w_obj.is_true(self)

    def getclass(self, w_receiver):
        return w_receiver.getclass(self)

    def getsingletonclass(self, w_receiver):
        return w_receiver.getsingletonclass(self)

    def getscope(self, w_receiver):
        if isinstance(w_receiver, W_ModuleObject):
            return w_receiver
        else:
            return self.getclass(w_receiver)

    @jit.unroll_safe
    def getnonsingletonclass(self, w_receiver):
        cls = self.getclass(w_receiver)
        while cls.is_singleton:
            cls = cls.superclass
        return cls

    def getclassfor(self, cls):
        return self.getclassobject(cls.classdef)

    def getclassobject(self, classdef):
        return self.fromcache(ClassCache).getorbuild(classdef)

    def getmoduleobject(self, moduledef):
        return self.fromcache(ModuleCache).getorbuild(moduledef)

    def find_const(self, w_module, name):
        w_obj = w_module.find_const(self, name)
        if w_obj is None:
            w_obj = self.send(w_module, self.newsymbol("const_missing"),
                              [self.newsymbol(name)])
        return w_obj

    def set_const(self, module, name, w_value):
        module.set_const(self, name, w_value)

    def set_lexical_scope(self, module, scope):
        module.set_lexical_scope(self, scope)

    def find_instance_var(self, w_obj, name):
        w_res = w_obj.find_instance_var(self, name)
        return w_res if w_res is not None else self.w_nil

    def set_instance_var(self, w_obj, name, w_value):
        w_obj.set_instance_var(self, name, w_value)

    def find_class_var(self, w_module, name):
        return w_module.find_class_var(self, name)

    def set_class_var(self, w_module, name, w_value):
        w_module.set_class_var(self, name, w_value)

    def send(self, w_receiver, w_method, args_w=None, block=None):
        if args_w is None:
            args_w = []
        name = self.symbol_w(w_method)

        w_cls = self.getclass(w_receiver)
        raw_method = w_cls.find_method(self, name)
        return self._send_raw(w_method, raw_method, w_receiver, w_cls, args_w,
                              block)

    def send_super(self, w_cls, w_receiver, w_method, args_w, block=None):
        name = self.symbol_w(w_method)
        raw_method = w_cls.find_method_super(self, name)
        return self._send_raw(w_method, raw_method, w_receiver, w_cls, args_w,
                              block)

    def _send_raw(self, w_method, raw_method, w_receiver, w_cls, args_w,
                  block):
        if raw_method is None:
            method_missing = w_cls.find_method(self, "method_missing")
            assert method_missing is not None
            args_w.insert(0, w_method)
            return method_missing.call(self, w_receiver, args_w, block)
        return raw_method.call(self, w_receiver, args_w, block)

    def respond_to(self, w_receiver, w_method):
        name = self.symbol_w(w_method)
        w_cls = self.getclass(w_receiver)
        raw_method = w_cls.find_method(self, name)
        return raw_method is not None

    @jit.unroll_safe
    def invoke_block(self, block, args_w):
        bc = block.bytecode
        frame = self.create_frame(
            bc,
            w_self=block.w_self,
            w_scope=block.w_scope,
            block=block.block,
            parent_interp=block.parent_interp,
        )
        if (len(args_w) == 1 and isinstance(args_w[0], W_ArrayObject)
                and len(bc.arg_locs) >= 2):
            w_arg = args_w[0]
            assert isinstance(w_arg, W_ArrayObject)
            args_w = w_arg.items_w
        if len(bc.arg_locs) != 0:
            frame.handle_block_args(self, bc, args_w, None)
        assert len(block.cells) == len(bc.freevars)
        for idx, cell in enumerate(block.cells):
            frame.cells[len(bc.cellvars) + idx] = cell

        with self.getexecutioncontext().visit_frame(frame):
            return self.execute_frame(frame, bc)

    def error(self, w_type, msg="", optargs=None):
        if not optargs:
            optargs = []
        w_new_sym = self.newsymbol("new")
        args_w = [self.newstr_fromstr(msg)] + optargs
        w_exc = self.send(w_type, w_new_sym, args_w)
        assert isinstance(w_exc, W_ExceptionObject)
        return RubyError(w_exc)

    def hash_w(self, w_obj):
        return self.int_w(self.send(w_obj, self.newsymbol("hash")))

    def eq_w(self, w_obj1, w_obj2):
        return self.is_true(self.send(w_obj1, self.newsymbol("=="), [w_obj2]))

    def register_exit_handler(self, w_proc):
        self.exit_handlers_w.append(w_proc)

    def run_exit_handlers(self):
        while self.exit_handlers_w:
            w_proc = self.exit_handlers_w.pop()
            try:
                self.send(w_proc, self.newsymbol("call"))
            except RubyError as e:
                print_traceback(self, e.w_value)

    def subscript_access(self, length, w_idx, w_count):
        inclusive = False
        as_range = False
        end = 0

        if isinstance(w_idx, W_RangeObject) and not w_count:
            start = self.int_w(
                self.convert_type(w_idx.w_start, self.w_fixnum, "to_int"))
            end = self.int_w(
                self.convert_type(w_idx.w_end, self.w_fixnum, "to_int"))
            inclusive = not w_idx.exclusive
            as_range = True
        else:
            start = self.int_w(
                self.convert_type(w_idx, self.w_fixnum, "to_int"))
            if w_count:
                end = self.int_w(
                    self.convert_type(w_count, self.w_fixnum, "to_int"))
                if end >= 0:
                    as_range = True

        if start < 0:
            start += length
        if as_range:
            if w_count:
                end += start
            if end < 0:
                end += length
            if inclusive:
                end += 1
            if end < start:
                end = start
            elif end > length:
                end = length

        nil = ((not as_range and start >= length) or start < 0 or end < 0
               or (start > 0 and start > length))
        return (start, end, as_range, nil)

    def convert_type(self, w_obj, w_cls, method, raise_error=True):
        if w_obj.is_kind_of(self, w_cls):
            return w_obj

        try:
            w_res = self.send(w_obj, self.newsymbol(method))
        except RubyError:
            src_cls = self.getclass(w_obj).name
            raise self.error(
                self.w_TypeError,
                "can't convert %s into %s" % (src_cls, w_cls.name))

        if not w_res or w_res is self.w_nil and not raise_error:
            return self.w_nil
        elif not w_res.is_kind_of(self, w_cls):
            src_cls = self.getclass(w_obj).name
            res_cls = self.getclass(w_res).name
            raise self.error(
                self.w_TypeError, "can't convert %s to %s (%s#%s gives %s)" %
                (src_cls, w_cls.name, src_cls, method, res_cls))
        else:
            return w_res
Example #8
0
class W_ModuleObject(W_RootObject):
    _immutable_fields_ = [
        "version?", "included_modules?[*]", "lexical_scope?", "klass?"
    ]

    classdef = ClassDef("Module", W_RootObject.classdef)

    def __init__(self, space, name, superclass):
        self.name = name
        self.klass = None
        self.superclass = superclass
        self.version = VersionTag()
        self.methods_w = {}
        self.constants_w = {}
        self.class_variables = CellDict()
        self.instance_variables = CellDict()
        self.lexical_scope = None
        self.included_modules = []
        self.descendants = []

    def __deepcopy__(self, memo):
        obj = super(W_ModuleObject, self).__deepcopy__(memo)
        obj.name = self.name
        obj.klass = copy.deepcopy(self.klass, memo)
        obj.superclass = copy.deepcopy(self.superclass, memo)
        obj.version = copy.deepcopy(self.version, memo)
        obj.methods_w = copy.deepcopy(self.methods_w, memo)
        obj.constants_w = copy.deepcopy(self.constants_w, memo)
        obj.class_variables = copy.deepcopy(self.class_variables, memo)
        obj.instance_variables = copy.deepcopy(self.instance_variables, memo)
        obj.lexical_scope = copy.deepcopy(self.lexical_scope, memo)
        obj.included_modules = copy.deepcopy(self.included_modules, memo)
        obj.descendants = copy.deepcopy(self.descendants, memo)
        return obj

    def getclass(self, space):
        if self.klass is not None:
            return self.klass
        return W_RootObject.getclass(self, space)

    def getsingletonclass(self, space):
        if self.klass is None:
            self.klass = space.newclass(
                "#<Class:%s>" % self.name, space.w_module, is_singleton=True
            )
        return self.klass

    def mutated(self):
        self.version = VersionTag()

    def define_method(self, space, name, method):
        self.mutated()
        self.methods_w[name] = method

    @jit.unroll_safe
    def find_method(self, space, name):
        method = self._find_method_pure(space, name, self.version)
        if method is None:
            for module in self.included_modules:
                method = module.find_method(space, name)
                if method is not None:
                    return method
        return method

    @jit.unroll_safe
    def find_method_super(self, space, name):
        for module in self.included_modules:
            method = module.find_method(space, name)
            if method is not None:
                return method
        return None

    @jit.elidable
    def _find_method_pure(self, space, method, version):
        return self.methods_w.get(method, None)

    def set_lexical_scope(self, space, w_mod):
        self.lexical_scope = w_mod

    def set_const(self, space, name, w_obj):
        self.mutated()
        self.constants_w[name] = w_obj

    def find_const(self, space, name):
        res = self._find_const_pure(name, self.version)
        if res is None and self.lexical_scope is not None:
            res = self.lexical_scope.find_lexical_const(space, name)
        if res is None and self.superclass is not None:
            res = self.superclass.find_inherited_const(space, name)
        return res

    def find_lexical_const(self, space, name):
        res = self._find_const_pure(name, self.version)
        if res is None and self.lexical_scope is not None:
            return self.lexical_scope.find_lexical_const(space, name)
        return res

    def find_inherited_const(self, space, name):
        res = self._find_const_pure(name, self.version)
        if res is None and self.superclass is not None:
            return self.superclass.find_inherited_const(space, name)
        return res

    def find_local_const(self, space, name):
        return self._find_const_pure(name, self.version)

    @jit.elidable
    def _find_const_pure(self, name, version):
        return self.constants_w.get(name, None)

    @jit.unroll_safe
    def set_class_var(self, space, name, w_obj):
        ancestors = self.ancestors()
        for idx in xrange(len(ancestors) - 1, -1, -1):
            module = ancestors[idx]
            assert isinstance(module, W_ModuleObject)
            w_res = module.class_variables.get(name)
            if w_res is not None or module is self:
                module.class_variables.set(name, w_obj)
                if module is self:
                    for descendant in self.descendants:
                        descendant.remove_class_var(space, name)

    @jit.unroll_safe
    def find_class_var(self, space, name):
        w_res = self.class_variables.get(name)
        if w_res is None:
            ancestors = self.ancestors()
            for idx in xrange(1, len(ancestors)):
                module = ancestors[idx]
                assert isinstance(module, W_ModuleObject)
                w_res = module.class_variables.get(name)
                if w_res is not None:
                    break
        return w_res

    @jit.unroll_safe
    def remove_class_var(self, space, name):
        self.class_variables.delete(name)
        for descendant in self.descendants:
            descendant.remove_class_var(space, name)

    def set_instance_var(self, space, name, w_value):
        return self.instance_variables.set(name, w_value)

    def find_instance_var(self, space, name):
        return self.instance_variables.get(name) or space.w_nil

    def ancestors(self, include_singleton=True, include_self=True):
        if include_self:
            return [self] + self.included_modules
        else:
            return self.included_modules[:]

    def is_ancestor_of(self, w_cls):
        if self is w_cls or self in w_cls.included_modules:
            return True
        elif w_cls.superclass is not None:
            return self.is_ancestor_of(w_cls.superclass)
        else:
            return False

    def include_module(self, space, w_mod):
        assert isinstance(w_mod, W_ModuleObject)
        if w_mod not in self.ancestors():
            self.included_modules = [w_mod] + self.included_modules
            w_mod.included(space, self)

    def included(self, space, w_mod):
        self.descendants.append(w_mod)
        space.send(self, space.newsymbol("included"), [w_mod])

    def inherited(self, space, w_mod):
        self.descendants.append(w_mod)
        if not space.bootstrap:
            space.send(self, space.newsymbol("inherited"), [w_mod])

    def set_visibility(self, space, names_w, visibility):
        names = [space.symbol_w(w_name) for w_name in names_w]
        if names:
            for name in names:
                self.set_method_visibility(space, name, visibility)
        else:
            self.set_default_visibility(space, visibility)

    def set_default_visibility(self, space, visibility):
        pass

    def set_method_visibility(self, space, name, visibility):
        pass

    @classdef.method("to_s")
    def method_to_s(self, space):
        return space.newstr_fromstr(self.name)

    @classdef.method("include")
    def method_include(self, space, w_mod):
        space.send(w_mod, space.newsymbol("append_features"), [self])

    @classdef.method("append_features")
    def method_append_features(self, space, w_mod):
        ancestors = self.ancestors()
        for idx in xrange(len(ancestors) - 1, -1, -1):
            w_mod.include_module(space, ancestors[idx])

    @classdef.method("attr_accessor")
    def method_attr_accessor(self, space, args_w):
        self.method_attr_reader(space, args_w)
        for w_arg in args_w:
            varname = space.symbol_w(w_arg)
            self.define_method(space, varname + "=", AttributeWriter("@" + varname))

    @classdef.method("attr_reader")
    def method_attr_reader(self, space, args_w):
        for w_arg in args_w:
            varname = space.symbol_w(w_arg)
            self.define_method(space, varname, AttributeReader("@" + varname))

    @classdef.method("module_function", name="symbol")
    def method_module_function(self, space, name):
        self.attach_method(space, name, self._find_method_pure(space, name, self.version))

    @classdef.method("private_class_method")
    def method_private_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, space.newsymbol("private"), [w_name])

    @classdef.method("public_class_method")
    def method_public_class_method(self, space, w_name):
        w_cls = self.getsingletonclass(space)
        return space.send(w_cls, space.newsymbol("public"), [w_name])

    @classdef.method("alias_method", new_name="symbol", old_name="symbol")
    def method_alias_method(self, space, new_name, old_name):
        self.define_method(space, new_name, self.find_method(space, old_name))

    @classdef.method("ancestors")
    def method_ancestors(self, space):
        return space.newarray(self.ancestors(include_singleton=False))

    @classdef.method("inherited")
    def method_inherited(self, space, w_mod):
        pass

    @classdef.method("included")
    def method_included(self, space, w_mod):
        pass

    @classdef.method("name")
    def method_name(self, space):
        return space.newstr_fromstr(self.name)

    @classdef.method("private")
    def method_private(self, space, args_w):
        self.set_visibility(space, args_w, "private")

    @classdef.method("public")
    def method_public(self, space, args_w):
        self.set_visibility(space, args_w, "public")

    @classdef.method("protected")
    def method_protected(self, space, args_w):
        self.set_visibility(space, args_w, "protected")

    @classdef.method("constants")
    def method_constants(self, space):
        return space.newarray([space.newsymbol(n) for n in self.constants_w])

    @classdef.method("const_missing", name="symbol")
    def method_const_missing(self, space, name):
        raise space.error(space.w_NameError, "uninitialized constant %s" % name)

    @classdef.method("class_eval", string="str", filename="str")
    @classdef.method("module_eval", string="str", filename="str")
    def method_module_eval(self, space, string=None, filename=None, w_lineno=None, block=None):
        if string is not None:
            if filename is None:
                filename = "module_eval"
            if w_lineno is not None:
                lineno = space.int_w(w_lineno)
            else:
                lineno = 1
            return space.execute(string, self, self, filename, lineno)
        else:
            space.invoke_block(block.copy(w_self=self, w_scope=self), [])

    @classdef.method("const_defined?", const="str", inherit="bool")
    def method_const_definedp(self, space, const, inherit=True):
        if inherit:
            return space.newbool(self.find_inherited_const(space, const) is not None)
        else:
            return space.newbool(self._find_const_pure(const, self.version) is not None)

    @classdef.method("method_defined?", name="str")
    def method_method_definedp(self, space, name):
        return space.newbool(self.find_method(space, name) is not None)

    @classdef.method("===")
    def method_eqeqeq(self, space, w_obj):
        return space.newbool(self.is_ancestor_of(space.getclass(w_obj)))