mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
810 lines
19 KiB
Ruby
810 lines
19 KiB
Ruby
# 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
|
|
"<unknown>"
|
|
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 <code>Symbol</code> corresponding to <i>self</i>, creating the
|
|
# symbol if it did not previously exist. See <code>Symbol#id2name</code>.
|
|
#
|
|
# "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
|
|
# <code>:xxx</code> 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
|
|
"#<IncludedModule #{@module.to_s}>"
|
|
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
|