# This is the beginning of loading Ruby code. At this point, the VM is # bootstrapped and the fundamental data structures, primitive functions and # the basic classes and objects are available. # # The classes, modules, and methods defined here provide basic functionality # needed to load the bootstrap directory. By the end of this file, the # following methods are available: # # attr_reader :sym # attr_writer :sym # attr_accessor :sym # # private :sym # protected :sym # # module_function :sym # # These forms should be used in the rest of the core library. In core/zed.rb, # more complete forms of these methods are provided for user code. # # NOTE: The order of these definitions is important. Do not # change it without consultation. class NilClass def nil? true end def ! true end def !=(other) other.nil? ? false : true end def ==(other) other.nil? ? true : false end # alias_method is not available yet def equal?(other) other.nil? ? true : false end end # This class encapsulates primitives that involve the VM itself rather than # something in Ruby-land. # # See core/vm.rb # class Rubinius::VM # Write given string to stderr. # # Used to support error reporting where IO is not reliable yet. # def self.write_error(str) Rubinius.primitive :vm_write_error raise PrimitiveFailure, "Rubinius::VM.write_error primitive failed" end # Prints Ruby backtrace at point of call. # def self.show_backtrace Rubinius.primitive :vm_show_backtrace raise PrimitiveFailure, "Rubinius::VM.show_backtrace primitive failed" end # Reset the method cache globally for given method name. # def self.reset_method_cache(mod, sym) Rubinius.primitive :vm_reset_method_cache raise PrimitiveFailure, "Rubinius::VM.reset_method_cache primitive failed" end end class Object # Prints basic information about the object to stdout. # def __show__ Rubinius.primitive :object_show "" end end class Class # Allocate memory for an instance of the class without initialization. # # The object returned is valid to use, but its #initialize method has not # been called. In almost all cases, .new is the correct method to use # instead. # # See .new # def allocate Rubinius.primitive :class_allocate raise RuntimeError, "Class#allocate primitive failed on #{self.inspect}" end # Allocate and initialize an instance of the class. # # Default implementation: merely allocates the instance, and then calls the # #initialize method on the object with the given arguments and block, if # provided. # # See .allocate # def new(*args) obj = allocate() Rubinius.asm(args, obj) do |args, obj| run obj run args push_block send_with_splat :initialize, 0, true # no pop here, as .asm blocks imply a pop as they're not # allowed to leak a stack value end obj end end module Kernel def nil? false end # Return the Class object this object is an instance of. # # Note that this method must always be called with an explicit receiver, # since class by itself is a keyword. # def class Rubinius.primitive :object_class raise PrimitiveFailure, "Kernel#class primitive failed." end # Return the class object of self. # # This is the same as #class, but named to always be available. def __class__ Rubinius.primitive :object_class raise PrimitiveFailure, "Kernel#class primitive failed." end # String representation of an object. # # By default, the representation is the name of the object's class preceded # by a # to indicate the object is an instance thereof. # def to_s "#<#{self.class.name}>" end # :internal: # # Lowest-level implementation of raise, used internally by core library code # until a more sophisticated version is loaded. # # Redefined later. # def raise(cls, str="", junk=nil) Rubinius::VM.write_error "Fatal error loading core library:\n " Rubinius::VM.write_error str Rubinius::VM.write_error "\n" Rubinius::VM.show_backtrace Process.exit! 1 end # Returns true if the given Class is either the class or superclass of the # object or, when given a Module, if the Module has been included in # object's class or one of its superclasses. Returns false otherwise. # # If the argument is not a Class or Module, a TypeError is raised. # def kind_of?(cls) Rubinius.primitive :object_kind_of raise TypeError, "Kernel#kind_of? requires a Class or Module argument" end # Hook method invoked when object is sent a message it cannot handle. # # The default implementation will merely raise a NoMethodError with # information about the message. # # This method may be overridden, and is often used to provide dynamic # behaviour. An overriding version should call super if it fails to resolve # the message. This practice ensures that the default version will be called # if all else fails. # def method_missing(meth, *args) raise NoMethodError, "Unable to send '#{meth}' on '#{self}' (#{self.class})" end # :internal: # # Backend method for Object#dup and Object#clone. # # Redefined in core/kernel.rb # def initialize_copy(other) end # Generic shallow copy of object. # # Copies instance variables, but does not recursively copy the objects they # reference. Copies taintedness. # # In contrast to .clone, .dup can be considered as creating a new object of # the same class and populating it with data from the object. # # If class-specific behaviour is desired, the class should define # #initialize_copy and implement the behaviour there. #initialize_copy will # automatically be called on the new object - the copy - with the original # object as argument if defined. # def dup copy = Rubinius::Type.object_class(self).allocate Rubinius.invoke_primitive :object_copy_object, copy, self Rubinius::Type.object_initialize_dup self, copy copy end # Direct shallow copy of object. # # Copies instance variables, but does not recursively copy the objects they # reference. Copies taintedness and frozenness. # # In contrast to .dup, .clone can be considered to actually clone the # existing object, including its internal state and any singleton methods. # # If class-specific behaviour is desired, the class should define # #initialize_copy and implement the behaviour there. #initialize_copy will # automatically be called on the new object - the copy - with the original # object as argument if defined. # def clone # Do not implement in terms of dup. It breaks rails. # copy = Rubinius::Type.object_class(self).allocate Rubinius.invoke_primitive :object_copy_object, copy, self Rubinius.invoke_primitive :object_copy_singleton_class, copy, self Rubinius::Type.object_initialize_clone self, copy copy.freeze if frozen? copy end end # Module for internals. # # See core/rubinius.rb # module Rubinius class Mirror def self.subject=(klass) @subject = klass end def self.subject @subject end end module Runtime def self.dup_as_array(obj) Rubinius.primitive :array_dup_as_array raise PrimitiveFailure, "Rubinius::Runtime.dup_as_array primitive failed" end end # Executable abstraction for accessors. # class AccessVariable # Specialised allocation. # def self.allocate Rubinius.primitive :accessvariable_allocate raise PrimitiveFailure, "AccessVariable.allocate primitive failed" end # Set up the executable. # # Name of variable provided without leading @, the second parameter should # be true if the attr is writable. # def initialize(variable, write) @primitive = nil @serial = 0 @name = "@#{variable}".to_sym @write = write end # Get the arity for this reader or writr # def arity @write ? 1 : 0 end # Create a getter for named instance var, without leading @. # def self.get_ivar(name) new(name, false) end # Create a setter for named instance var, without leading @. # def self.set_ivar(name) new(name, true) end end # Simplified lookup table. # # See core/lookup_table.rb. # class LookupTable # Retrieve value for given key. # def [](key) Rubinius.primitive :lookuptable_aref raise PrimitiveFailure, "LookupTable#[] primitive failed" end # Store value under key. # def []=(key, val) Rubinius.primitive :lookuptable_store raise PrimitiveFailure, "LookupTable#[]= primitive failed" end end # Constant table for storing methods. # # See core/constant_table.rb # class ConstantTable # Perform lookup for constant name. # def lookup(name) Rubinius.primitive :constant_table_lookup raise PrimitiveFailure, "ConstantTable#lookup primitive failed" end # Store Constant under name, with given visibility. # def store(name, constant, visibility) Rubinius.primitive :constant_table_store raise PrimitiveFailure, "ConstantTable#store primitive failed" end end # Lookup table for storing methods. # # See core/method_table.rb # class MethodTable # Perform lookup for method name. # def lookup(name) Rubinius.primitive :methodtable_lookup raise PrimitiveFailure, "MethodTable#lookup primitive failed" end # Store Executable under name, with given visibility. # def store(name, method_id, exec, scope, serial, visibility) Rubinius.primitive :methodtable_store raise PrimitiveFailure, "MethodTable#store primitive failed" end # Make an alias from +original_name+ in +original_mod+ to +name+ with # visibility +vis+ def alias(name, visibility, original_name, original_exec, original_mod) Rubinius.primitive :methodtable_alias raise PrimitiveFailure, "MethodTable#alias primitive failed" end end end class Symbol # Produce String representation of this Symbol. # def to_s Rubinius.primitive :symbol_to_s raise PrimitiveFailure, "Symbol#to_s primitive failed" end # For completeness, returns self. # def to_sym self end end class String # Returns the Symbol corresponding to self, creating the # symbol if it did not previously exist. See Symbol#id2name. # # "Koala".intern #=> :Koala # s = 'cat'.to_sym #=> :cat # s == :cat #=> true # s = '@cat'.to_sym #=> :@cat # s == :@cat #=> true # # This can also be used to create symbols that cannot be represented using the # :xxx notation. # # 'cat and dog'.to_sym #=> :"cat and dog" #-- # TODO: Add taintedness-check #++ def to_sym Rubinius.primitive :symbol_lookup raise PrimitiveFailure, "String#to_sym primitive failed: #{self.dump}" end # For completeness, returns self. # def to_s self end end module Process # Terminate with given status code. # def self.exit(code=0) case code when true code = 0 when false code = 1 else code = Rubinius::Type.coerce_to code, Integer, :to_int end raise SystemExit.new(code) end def self.exit!(code=1) Rubinius.primitive :vm_exit case code when true exit! 0 when false exit! 1 else exit! Rubinius::Type.coerce_to(code, Integer, :to_int) end end end class Module def method_table ; @method_table ; end def constant_table ; @constant_table ; end def name ; @module_name.to_s ; end def origin ; @origin ; end # Specialised allocator. # def self.allocate Rubinius.primitive :module_allocate raise PrimitiveFailure, "Module.allocate primitive failed" end # :internal: # # Hook called when a constant cannot be located. # # Default implementation 'raises', but we don't use #raise to prevent # infinite recursion. # # Redefined in core/module.rb # def const_missing(name) Rubinius::VM.write_error "Missing or uninitialized constant: #{name.to_s}" end # Set Module's direct superclass. # # The corresponding 'getter' #superclass method is defined in class.rb, # because it is more complex than a mere accessor # def superclass=(other) Rubinius.check_frozen @superclass = other end # Module's stored superclass. # # This may be either an included Module or an inherited Class. # def direct_superclass @superclass end # :internal: # # Perform actual work for including a Module in this one. # # Redefined in core/module.rb. # def append_features(mod) im = Rubinius::IncludedModule.new(self) im.attach_to mod end # Hook method called on Module when another Module is .include'd into it. # # Override for module-specific behaviour. # def included(mod); end # :internal: # # Basic version of .include used while loading core library code. # # Redefined in core/module.rb. # def include(mod) mod.append_features(self) Rubinius.privately do mod.included self end self end # :internal: # # Basic version used while loading core library code. # # Redefined in core/module.rb. # def attr_reader(name) Rubinius::VM.reset_method_cache self, name meth = Rubinius::AccessVariable.get_ivar name @method_table.store name, nil, meth, nil, 0, :public nil end def attr_reader_specific(name, method_name) Rubinius::VM.reset_method_cache self, method_name meth = Rubinius::AccessVariable.get_ivar name @method_table.store method_name, nil, meth, nil, 0, :public nil end # :internal: # # Basic version used while loading core library code. # # Redefined in core/module.rb. # def attr_writer(name) meth = Rubinius::AccessVariable.set_ivar name writer_name = "#{name}=".to_sym Rubinius::VM.reset_method_cache self, writer_name @method_table.store writer_name, nil, meth, nil, 0, :public nil end # :internal: # # Basic version used while loading core library code. # # Redefined in core/module.rb. # def attr_accessor(name) attr_reader(name) attr_writer(name) nil end # :internal: # # Basic version used while loading core library code. Cannot be used as a # toggle, and only takes a single method name. # # Redefined in core/module.rb. # def public(name) if entry = @method_table.lookup(name) entry.visibility = :public end end # :internal: # # Basic version used while loading core library code. Cannot be used as a # toggle, and only takes a single method name. # # Redefined in core/module.rb. # def private(name) if entry = @method_table.lookup(name) entry.visibility = :private end end # :internal: # # Basic version used while loading core library code. Cannot be used as a # toggle, and only takes a single method name. # # Redefined in core/module.rb. # def protected(name) if entry = @method_table.lookup(name) entry.visibility = :protected end end # :internal: # # Basic version used while loading core library code. Creates a copy of # current method and stores it under the new name. The two are independent. # # Redefined in core/module.rb. # def alias_method(new_name, current_name) Rubinius::VM.reset_method_cache self, new_name # If we're aliasing a method we contain, just reference it directly, no # need for the alias wrapper if entry = @method_table.lookup(current_name) @method_table.store new_name, entry.method_id, entry.get_method, entry.scope, entry.serial, entry.visibility else mod = direct_superclass() while mod entry = mod.method_table.lookup(current_name) break if entry mod = mod.direct_superclass end unless entry raise NoMethodError, "No method '#{current_name}' to alias to '#{new_name}'" end @method_table.alias new_name, entry.visibility, current_name, entry.get_method, mod end end # :internal: # # Basic version used while loading core library code. Only takes a single # method name. # # Redefined in core/module.rb. # def module_function(name) if entry = @method_table.lookup(name) sc = class << self; self; end Rubinius::VM.reset_method_cache sc, name sc.method_table.store name, entry.method_id, entry.method, entry.scope, entry.serial, :public private name end end def custom_call_site(name) if entry = @method_table.lookup(name) entry.get_method.custom_call_site end end def undef_method(name) Rubinius::VM.reset_method_cache self, name @method_table.store name, nil, nil, nil, 0, :undef name end end module Rubinius class AccessVariable attr_reader :name end # Visibility handling for MethodTables. # # See core/method_table.rb # class MethodTable::Bucket attr_accessor :visibility attr_accessor :method_id attr_accessor :method attr_accessor :scope attr_accessor :serial def get_method Rubinius.primitive :methodtable_bucket_get_method raise PrimitiveFailure, "MethodTable::Bucket#get_method primitive failed" end def public? @visibility == :public end def private? @visibility == :private end def protected? @visibility == :protected end end # :internal: # # Internal representation of a Module's inclusion in another. # # Abstracts the injection of the included Module into the ancestor hierarchy # for method- and constant lookup in a roughly transparent fashion. # # This class is known to the VM. # class IncludedModule < Module attr_reader :superclass attr_reader :module # :internal: # # Specialised allocator. # def self.allocate Rubinius.primitive :included_module_allocate raise PrimitiveFailure, "IncludedModule.allocate primitive failed" end # :internal: # # Created referencing the Module that is being included. # def initialize(mod) @method_table = mod.method_table @constant_table = mod.constant_table @module = mod end def module @module end # :internal: # # Inject self inbetween class and its previous direct superclass. # def attach_to(cls) @superclass = cls.direct_superclass cls.superclass = self self end # :internal: # # Name of the included Module. # def name @module.name end # :internal: # # String representation of the included Module. # def to_s @module.to_s end def inspect "#" end # Returns true if +other+ is the same object as self or if +other+ is the # module this IncludedModule is for. # def ==(other) if other.kind_of? IncludedModule super || other.module == @module else super || other == @module end end end end class Object include Kernel end module Enumerable; end class Integer; end class IO; end class Numeric; end class String; end