mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
1916 lines
54 KiB
Ruby
1916 lines
54 KiB
Ruby
# TODO: Finish adding some layer structure to the core library. This file is a
|
|
# complete mess at the moment.
|
|
#
|
|
# A proper layered structure for the core library would enable and encourage
|
|
# composition and make visible where pieces are loosely or tightly coupled. A
|
|
# reasonable layer for something as complex as the Ruby core library would be:
|
|
#
|
|
# 1. Simple values like Fixnum, Bignum, Float;
|
|
# 2. Basic data structures like Tuple, ByteArray, Array, Hash;
|
|
# 3. More complicated values like String, Regexp, Complex, Rational;
|
|
# 4. Fairly simple system-dependent facilities like IO, File, Process;
|
|
# 5. Even more complex facilities like FFI;
|
|
# 6. Something like Socket that composes multiple lower layers;
|
|
# 7. A complex facility like CodeLoader or RubyGems.
|
|
|
|
|
|
# The virtual concatenation file of the files given on command line (or
|
|
# from $stdin if no files were given.) Usable like an IO.
|
|
ARGF = Rubinius::ARGFClass.new
|
|
|
|
class Module
|
|
def alias_method(new_name, current_name)
|
|
new_name = Rubinius::Type.coerce_to_symbol(new_name)
|
|
current_name = Rubinius::Type.coerce_to_symbol(current_name)
|
|
mod, entry = lookup_method(current_name, true, false)
|
|
|
|
if entry
|
|
Rubinius::VM.reset_method_cache self, new_name
|
|
|
|
method_visibility = visibility_for_aliased_method(new_name, entry.visibility)
|
|
|
|
# If we're aliasing a method we contain, just reference it directly, no
|
|
# need for the alias wrapper
|
|
#
|
|
# The 'and entry.get_method' is there to force us to use the alias code
|
|
# when the original method exists only to change the visibility of a
|
|
# parent method.
|
|
if mod == self and entry.get_method
|
|
@method_table.store new_name, entry.method_id, entry.method,
|
|
entry.scope, entry.serial, method_visibility
|
|
else
|
|
@method_table.alias new_name, method_visibility, current_name,
|
|
entry.get_method, mod
|
|
end
|
|
|
|
if ai = Rubinius::Type.singleton_class_object(self)
|
|
Rubinius.privately do
|
|
ai.singleton_method_added new_name
|
|
end
|
|
else
|
|
method_added new_name
|
|
end
|
|
|
|
self
|
|
else
|
|
if ai = Rubinius::Type.singleton_class_object(self)
|
|
raise NameError, "Unable to find '#{current_name}' for object #{ai.inspect}"
|
|
else
|
|
thing = Rubinius::Type.object_kind_of?(self, Class) ? "class" : "module"
|
|
raise NameError, "undefined method `#{current_name}' for #{thing} `#{self.name}'"
|
|
end
|
|
end
|
|
end
|
|
private :alias_method
|
|
|
|
def const_set(name, value)
|
|
name = Rubinius::Type.coerce_to_constant_name name
|
|
Rubinius.check_frozen
|
|
|
|
if Rubinius::Type.object_kind_of? value, Module
|
|
Rubinius::Type.set_module_name value, name, self
|
|
|
|
if Object.equal? self
|
|
value.constant_table.each do |n, c, _|
|
|
if Rubinius::Type.object_kind_of? c, Module and !c.name
|
|
Rubinius::Type.set_module_name c, n, value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
@constant_table.store(name, value, :public)
|
|
Rubinius.inc_global_serial
|
|
|
|
return value
|
|
end
|
|
|
|
def module_function(*args)
|
|
if kind_of? Class
|
|
raise TypeError, "invalid receiver class #{__class__}, expected Module"
|
|
end
|
|
|
|
if args.empty?
|
|
vs = Rubinius::VariableScope.of_sender
|
|
vs.method_visibility = :module
|
|
else
|
|
sc = Rubinius::Type.object_singleton_class(self)
|
|
args.each do |meth|
|
|
method_name = Rubinius::Type.coerce_to_symbol meth
|
|
|
|
Rubinius::VM.reset_method_cache sc, method_name
|
|
|
|
mod, entry = lookup_method(method_name)
|
|
sc.method_table.store method_name, entry.method_id, entry.method,
|
|
entry.scope, entry.serial, :public
|
|
set_visibility method_name, :private
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
private :module_function
|
|
|
|
def public(*args)
|
|
if args.empty?
|
|
vs = Rubinius::VariableScope.of_sender
|
|
vs.method_visibility = nil
|
|
else
|
|
args.each { |meth| set_visibility(meth, :public) }
|
|
end
|
|
|
|
self
|
|
end
|
|
private :public
|
|
|
|
def private(*args)
|
|
if args.empty?
|
|
vs = Rubinius::VariableScope.of_sender
|
|
vs.method_visibility = :private
|
|
else
|
|
args.each { |meth| set_visibility(meth, :private) }
|
|
end
|
|
|
|
self
|
|
end
|
|
private :private
|
|
|
|
def protected(*args)
|
|
if args.empty?
|
|
vs = Rubinius::VariableScope.of_sender
|
|
vs.method_visibility = :protected
|
|
else
|
|
args.each { |meth| set_visibility(meth, :protected) }
|
|
end
|
|
|
|
self
|
|
end
|
|
private :protected
|
|
|
|
def private_class_method(*args)
|
|
args.each do |meth|
|
|
set_class_visibility(meth, :private)
|
|
end
|
|
self
|
|
end
|
|
|
|
def public_class_method(*args)
|
|
args.each do |meth|
|
|
set_class_visibility(meth, :public)
|
|
end
|
|
self
|
|
end
|
|
|
|
# Invokes <code>Module#append_features</code> and
|
|
# <code>Module#included</code> on each argument, passing in self.
|
|
#
|
|
def include(*modules)
|
|
modules.reverse_each do |mod|
|
|
if !mod.kind_of?(Module) or mod.kind_of?(Class)
|
|
raise TypeError, "wrong argument type #{mod.class} (expected Module)"
|
|
end
|
|
|
|
Rubinius.privately do
|
|
mod.append_features self
|
|
end
|
|
|
|
Rubinius.privately do
|
|
mod.included self
|
|
end
|
|
end
|
|
self
|
|
end
|
|
|
|
# Add all constants, instance methods and module variables
|
|
# of this Module and all Modules that this one includes to +klass+
|
|
#
|
|
# This method is aliased as append_features as the default implementation
|
|
# for that method. Kernel#extend calls this method directly through
|
|
# Module#extend_object, because Kernel#extend should not use append_features.
|
|
def include_into(klass)
|
|
unless klass.kind_of? Module
|
|
raise TypeError, "invalid argument class #{klass.class}, expected Module"
|
|
end
|
|
|
|
if kind_of? Class
|
|
raise TypeError, "invalid receiver class #{__class__}, expected Module"
|
|
end
|
|
|
|
Rubinius::Type.include_modules_from(self, klass.origin)
|
|
Rubinius::Type.infect(klass, self)
|
|
|
|
self
|
|
end
|
|
|
|
# Called when this Module is being included in another Module.
|
|
# This may be overridden for custom behaviour. The default
|
|
# is to add constants, instance methods and module variables
|
|
# of this Module and all Modules that this one includes to +klass+.
|
|
#
|
|
# See also #include.
|
|
#
|
|
alias_method :append_features, :include_into
|
|
private :append_features
|
|
|
|
def attr_reader(*names)
|
|
vis = Rubinius::VariableScope.of_sender.method_visibility
|
|
|
|
names.each { |name| Rubinius.add_reader name, self, vis }
|
|
|
|
return nil
|
|
end
|
|
private :attr_reader
|
|
|
|
def attr_writer(*names)
|
|
vis = Rubinius::VariableScope.of_sender.method_visibility
|
|
|
|
names.each { |name| Rubinius::add_writer name, self, vis }
|
|
|
|
return nil
|
|
end
|
|
private :attr_writer
|
|
|
|
def attr_accessor(*names)
|
|
vis = Rubinius::VariableScope.of_sender.method_visibility
|
|
|
|
names.each do |name|
|
|
Rubinius.add_reader name, self, vis
|
|
Rubinius.add_writer name, self, vis
|
|
end
|
|
|
|
return nil
|
|
end
|
|
private :attr_accessor
|
|
|
|
def undef_method(*names)
|
|
return self if names.empty?
|
|
names.map!{ |name| Rubinius::Type.coerce_to_symbol name }
|
|
Rubinius.check_frozen
|
|
|
|
names.each do |name|
|
|
# Will raise a NameError if the method doesn't exist.
|
|
instance_method name
|
|
undef_method! name
|
|
end
|
|
|
|
self
|
|
end
|
|
private :undef_method
|
|
|
|
# Like undef_method, but doesn't even check that the method exists. Used
|
|
# mainly to implement rb_undef_method.
|
|
def undef_method!(name)
|
|
Rubinius.check_frozen
|
|
name = Rubinius::Type.coerce_to_symbol(name)
|
|
|
|
Rubinius::VM.reset_method_cache self, name
|
|
|
|
@method_table.store name, nil, nil, nil, 0, :undef
|
|
|
|
if obj = Rubinius::Type.singleton_class_object(self)
|
|
Rubinius.privately do
|
|
obj.singleton_method_undefined(name)
|
|
end
|
|
else
|
|
method_undefined(name)
|
|
end
|
|
|
|
name
|
|
end
|
|
|
|
def remove_method(*names)
|
|
names.each do |name|
|
|
name = Rubinius::Type.coerce_to_symbol(name)
|
|
Rubinius.check_frozen
|
|
|
|
unless @method_table.lookup(name)
|
|
raise NameError.new("method `#{name}' not defined in #{self.name}", name)
|
|
end
|
|
|
|
Rubinius::VM.reset_method_cache self, name
|
|
@method_table.delete name
|
|
|
|
if obj = Rubinius::Type.singleton_class_object(self)
|
|
Rubinius.privately do
|
|
obj.singleton_method_removed(name)
|
|
end
|
|
else
|
|
method_removed(name)
|
|
end
|
|
end
|
|
|
|
self
|
|
end
|
|
private :remove_method
|
|
|
|
def name
|
|
Rubinius::Type.module_name self
|
|
end
|
|
|
|
def to_s
|
|
Rubinius::Type.module_inspect self
|
|
end
|
|
|
|
def inspect
|
|
to_s
|
|
end
|
|
end
|
|
|
|
module Rubinius
|
|
Config = Configuration.new
|
|
Globals = GlobalVariables.new
|
|
|
|
@add_method_hook = Rubinius::Hook.new
|
|
|
|
def self.open_class(name, sup, scope)
|
|
if scope
|
|
under = scope.module
|
|
else
|
|
under = Object
|
|
end
|
|
|
|
open_class_under name, sup, under
|
|
end
|
|
|
|
def self.open_class_under(name, sup, mod)
|
|
unless Type.object_kind_of? mod, Module
|
|
raise TypeError, "'#{mod.inspect}' is not a class/module"
|
|
end
|
|
|
|
tbl = mod.constant_table
|
|
if !tbl.has_name?(name)
|
|
# Create the class
|
|
sup = Object unless sup
|
|
obj = Class.new sup, name, mod
|
|
else
|
|
entry = tbl.lookup(name)
|
|
obj = entry.constant
|
|
if Type.object_kind_of? obj, Autoload
|
|
obj = begin
|
|
obj.call(mod, true)
|
|
rescue NameError # Constant not found in loaded file
|
|
nil
|
|
end
|
|
|
|
# nil is returned if the autoload was abort, usually because
|
|
# the file to be required has already been loaded. In which case
|
|
# act like the autoload wasn't there.
|
|
unless obj
|
|
supr = sup ? sup : Object
|
|
obj = Class.new supr, name, mod
|
|
end
|
|
end
|
|
|
|
if Type.object_kind_of? obj, Class
|
|
if sup and obj.superclass != sup
|
|
raise TypeError, "Superclass mismatch: #{obj.superclass} != #{sup}"
|
|
end
|
|
else
|
|
raise TypeError, "#{name} is not a class"
|
|
end
|
|
end
|
|
|
|
return obj
|
|
end
|
|
|
|
def self.open_module(name, scope)
|
|
if scope
|
|
under = scope.module
|
|
else
|
|
under = Object
|
|
end
|
|
|
|
open_module_under name, under
|
|
end
|
|
|
|
def self.open_module_under(name, mod)
|
|
unless Type.object_kind_of? mod, Module
|
|
raise TypeError, "'#{mod.inspect}' is not a class/module"
|
|
end
|
|
|
|
tbl = mod.constant_table
|
|
found = tbl.has_name?(name)
|
|
|
|
# Object has special behavior, we check it's included
|
|
# modules also
|
|
if !found and mod.equal? Object
|
|
check = mod.direct_superclass
|
|
|
|
while check
|
|
tbl = check.constant_table
|
|
found = tbl.has_name?(name)
|
|
break if found
|
|
check = check.direct_superclass
|
|
end
|
|
end
|
|
|
|
if !found
|
|
# Create the module
|
|
obj = Module.new
|
|
mod.const_set name, obj
|
|
else
|
|
entry = tbl.lookup(name)
|
|
obj = entry.constant
|
|
|
|
if Type.object_kind_of? obj, Autoload
|
|
obj = obj.call(mod, true)
|
|
|
|
# See comment above about autoload returning nil
|
|
unless obj
|
|
obj = Module.new
|
|
mod.const_set name, obj
|
|
end
|
|
end
|
|
|
|
if Type.object_kind_of?(obj, Class) || !Type.object_kind_of?(obj, Module)
|
|
raise TypeError, "#{name} is not a module, but a #{obj.class}"
|
|
end
|
|
end
|
|
return obj
|
|
end
|
|
|
|
def self.add_function(name, executable, lexical_scope)
|
|
scope = lexical_scope
|
|
while scope.parent
|
|
scope = scope.parent
|
|
end
|
|
|
|
unless scope.functions.kind_of? Rubinius::LookupTable
|
|
scope.functions = Rubinius::LookupTable.new
|
|
end
|
|
|
|
scope.functions[name] = executable
|
|
end
|
|
|
|
def self.add_defn_method(name, executable, lexical_scope, vis)
|
|
# TODO: puts serial on MethodTable entry
|
|
unless Type.object_kind_of? executable, String
|
|
executable.serial = 1
|
|
if executable.respond_to? :scope=
|
|
# If we're adding a method inside ane eval, dup it so that
|
|
# we don't share the CompiledCode with the eval, since
|
|
# we're going to mutate it.
|
|
if lexical_scope and script = lexical_scope.current_script
|
|
if script.eval?
|
|
executable = executable.dup
|
|
end
|
|
end
|
|
executable.scope = lexical_scope
|
|
end
|
|
end
|
|
|
|
mod = lexical_scope.for_method_definition
|
|
|
|
if ai = Type.singleton_class_object(mod)
|
|
if Type.object_kind_of? ai, Numeric
|
|
|
|
# Such a weird protocol. If :singleton_method_added exists, allow this.
|
|
# le sigh.
|
|
unless Type.object_respond_to? ai, :singleton_method_added
|
|
raise TypeError, "Unable to define singleton methods on Numerics"
|
|
end
|
|
end
|
|
end
|
|
|
|
add_method name, executable, mod, lexical_scope, 1, vis
|
|
name
|
|
end
|
|
|
|
# Must be AFTER add_method, because otherwise we'll run this attach_method to add
|
|
# add_method itself and fail.
|
|
def self.attach_method(name, executable, lexical_scope, recv)
|
|
# TODO: puts serial on MethodTable entry
|
|
unless Type.object_kind_of? executable, String
|
|
executable.serial = 1
|
|
if executable.respond_to? :scope=
|
|
# If we're adding a method inside ane eval, dup it so that
|
|
# we don't share the CompiledCode with the eval, since
|
|
# we're going to mutate it.
|
|
if lexical_scope and script = lexical_scope.current_script
|
|
if script.eval?
|
|
executable = executable.dup
|
|
end
|
|
end
|
|
executable.scope = lexical_scope
|
|
end
|
|
end
|
|
|
|
mod = Rubinius::Type.object_singleton_class recv
|
|
|
|
add_method name, executable, mod, lexical_scope, 1, :public
|
|
name
|
|
end
|
|
|
|
def self.add_reader(name, mod, vis)
|
|
normalized = Rubinius::Type.coerce_to_symbol(name)
|
|
add_method normalized, AccessVariable.get_ivar(normalized), mod, nil, 0, vis
|
|
end
|
|
|
|
def self.add_writer(name, mod, vis)
|
|
normalized = Rubinius::Type.coerce_to_symbol(name)
|
|
writer_name = "#{normalized}=".to_sym
|
|
add_method writer_name, AccessVariable.set_ivar(normalized), mod, nil, 0, vis
|
|
end
|
|
|
|
class << self
|
|
attr_reader :add_method_hook
|
|
end
|
|
|
|
module CAPI
|
|
INTEGER_PACK_MSWORD_FIRST = 0x01
|
|
INTEGER_PACK_LSWORD_FIRST = 0x02
|
|
INTEGER_PACK_MSBYTE_FIRST = 0x10
|
|
INTEGER_PACK_LSBYTE_FIRST = 0x20
|
|
INTEGER_PACK_NATIVE_BYTE_ORDER = 0x40
|
|
INTEGER_PACK_2COMP = 0x80
|
|
INTEGER_PACK_FORCE_BIGNUM = 0x100
|
|
INTEGER_PACK_NEGATIVE = 0x200
|
|
|
|
INTEGER_PACK_LITTLE_ENDIAN = INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_LSBYTE_FIRST
|
|
INTEGER_PACK_BIG_ENDIAN = INTEGER_PACK_MSWORD_FIRST|INTEGER_PACK_MSBYTE_FIRST
|
|
|
|
INTEGER_PACK_DIGITS = [
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
]
|
|
end
|
|
|
|
module CType
|
|
Printed = Rubinius::Tuple.new 256
|
|
i = 0
|
|
while i < 256
|
|
Printed[i] = toprint(i)
|
|
i += 1
|
|
end
|
|
|
|
Lowered = Rubinius::Tuple.new 256
|
|
|
|
i = 0
|
|
while i < 256
|
|
Lowered[i] = tolower(i).chr
|
|
i += 1
|
|
end
|
|
end
|
|
|
|
module FFI
|
|
# Shorthand for the current process, i.e. all code that
|
|
# the process image itself contains. In addition to the
|
|
# Rubinius codebase, this also includes libc etc.
|
|
#
|
|
# Use this constant instead of nil directly.
|
|
#
|
|
CURRENT_PROCESS = nil
|
|
|
|
TypeDefs = Rubinius::LookupTable.new
|
|
|
|
# Converts a char
|
|
add_typedef TYPE_CHAR, :char
|
|
|
|
# Converts an unsigned char
|
|
add_typedef TYPE_UCHAR, :uchar
|
|
|
|
# The C++ boolean type
|
|
add_typedef TYPE_BOOL, :bool
|
|
|
|
# Converts a short
|
|
add_typedef TYPE_SHORT, :short
|
|
|
|
# Converts an unsigned short
|
|
add_typedef TYPE_USHORT, :ushort
|
|
add_typedef TYPE_USHORT, :mode_t
|
|
add_typedef TYPE_USHORT, :nlink_t
|
|
|
|
# Converts an int
|
|
add_typedef TYPE_INT, :int
|
|
add_typedef TYPE_INT, :dev_t
|
|
add_typedef TYPE_INT, :blksize_t
|
|
add_typedef TYPE_INT, :time_t
|
|
|
|
# Converts an unsigned int
|
|
add_typedef TYPE_UINT, :uint
|
|
add_typedef TYPE_UINT, :uid_t
|
|
add_typedef TYPE_UINT, :gid_t
|
|
add_typedef TYPE_UINT, :id_t
|
|
|
|
# Converts a long
|
|
add_typedef TYPE_LONG, :long
|
|
add_typedef TYPE_LONG, :ssize_t
|
|
|
|
# Converts an unsigned long
|
|
add_typedef TYPE_ULONG, :ulong
|
|
|
|
# Converts a size_t
|
|
add_typedef TYPE_ULONG, :size_t
|
|
|
|
# Converts a long long
|
|
add_typedef TYPE_LL, :long_long
|
|
add_typedef TYPE_LL, :blkcnt_t
|
|
add_typedef TYPE_LL, :off_t
|
|
|
|
# Converts an unsigned long long
|
|
add_typedef TYPE_ULL, :ulong_long
|
|
add_typedef TYPE_ULL, :ino64_t
|
|
|
|
# Converts a float
|
|
add_typedef TYPE_FLOAT, :float
|
|
|
|
# Converts a double
|
|
add_typedef TYPE_DOUBLE, :double
|
|
|
|
# Converts a pointer to opaque data
|
|
add_typedef TYPE_PTR, :pointer
|
|
|
|
# For when a function has no return value
|
|
add_typedef TYPE_VOID, :void
|
|
|
|
# Converts NULL-terminated C strings
|
|
add_typedef TYPE_STRING, :string
|
|
|
|
# Use strptr when you need to free the result of some operation.
|
|
add_typedef TYPE_STRPTR, :strptr
|
|
add_typedef TYPE_STRPTR, :string_and_pointer
|
|
|
|
# Use for a C struct with a char [] embedded inside.
|
|
add_typedef TYPE_CHARARR, :char_array
|
|
|
|
# A set of unambigious integer types
|
|
add_typedef TYPE_CHAR, :int8
|
|
add_typedef TYPE_UCHAR, :uint8
|
|
add_typedef TYPE_SHORT, :int16
|
|
add_typedef TYPE_USHORT, :uint16
|
|
add_typedef TYPE_INT, :int32
|
|
add_typedef TYPE_UINT, :uint32
|
|
|
|
# Converts a varargs argument
|
|
add_typedef TYPE_VARARGS, :varargs
|
|
|
|
if Rubinius::L64
|
|
add_typedef TYPE_LONG, :int64
|
|
add_typedef TYPE_ULONG, :uint64
|
|
else
|
|
add_typedef TYPE_LL, :int64
|
|
add_typedef TYPE_ULL, :uint64
|
|
end
|
|
|
|
TypeSizes = Rubinius::LookupTable.new
|
|
TypeSizes[1] = :char
|
|
TypeSizes[2] = :short
|
|
TypeSizes[4] = :int
|
|
TypeSizes[8] = Rubinius::L64 ? :long : :long_long
|
|
|
|
# Load all the platform dependent types
|
|
|
|
Rubinius::Config.section("rbx.platform.typedef.") do |key, value|
|
|
add_typedef(find_type(value.to_sym), key.substring(21, key.length).to_sym)
|
|
end
|
|
|
|
class DynamicLibrary
|
|
extend FFI::Library
|
|
|
|
# Bootstrap dlsym, dlopen, and dlerror
|
|
pointer_as_function :find_symbol, FFI::Pointer::DLSYM, [:pointer, :string], :pointer
|
|
pointer_as_function :open_library, FFI::Pointer::DLOPEN, [:string, :int], :pointer
|
|
pointer_as_function :last_error, FFI::Pointer::DLERROR, [], :string
|
|
|
|
if Rubinius.windows?
|
|
RTLD_LAZY = 0
|
|
RTLD_NOW = 0
|
|
RTLD_GLOBAL = 0
|
|
RTLD_LOCAL = 0
|
|
else
|
|
RTLD_LAZY = Rubinius::Config['rbx.platform.dlopen.RTLD_LAZY']
|
|
RTLD_NOW = Rubinius::Config['rbx.platform.dlopen.RTLD_NOW']
|
|
RTLD_GLOBAL = Rubinius::Config['rbx.platform.dlopen.RTLD_GLOBAL']
|
|
RTLD_LOCAL = Rubinius::Config['rbx.platform.dlopen.RTLD_LOCAL']
|
|
end
|
|
|
|
class << self
|
|
alias_method :open, :new
|
|
end
|
|
|
|
def initialize(name, flags=nil)
|
|
# Accept nil and check for ruby-ffi API compat
|
|
flags ||= RTLD_LAZY | RTLD_GLOBAL
|
|
|
|
unless name
|
|
@name = "[current process]"
|
|
@handle = FFI::Pointer::CURRENT_PROCESS
|
|
return
|
|
end
|
|
|
|
@name = name
|
|
@handle = DynamicLibrary.open_library name, flags
|
|
|
|
unless @handle
|
|
orig_error = last_error
|
|
|
|
libnames = FFI::LIB_SUFFIXES.map {|suffix| "#{name}.#{suffix}" }
|
|
libnames << "lib#{name}"
|
|
libnames += FFI::LIB_SUFFIXES.map {|suffix| "lib#{name}.#{suffix}" }
|
|
|
|
libnames.detect do |libname|
|
|
@name = libname
|
|
@handle = DynamicLibrary.open_library libname, flags
|
|
end
|
|
end
|
|
|
|
unless @handle
|
|
orig_error = orig_error.split("\n").first
|
|
# API Compat. LoadError is wrong here.
|
|
raise LoadError, "Could not open library #{name} - #{orig_error}"
|
|
end
|
|
end
|
|
|
|
private :initialize
|
|
|
|
attr_reader :name
|
|
|
|
def find_symbol(name)
|
|
ptr = DynamicLibrary.find_symbol @handle, name
|
|
return nil unless ptr
|
|
# defined in core/pointer.rb
|
|
FFI::DynamicLibrary::Symbol.new(self, ptr, name)
|
|
end
|
|
|
|
alias_method :find_function, :find_symbol
|
|
alias_method :find_variable, :find_symbol
|
|
|
|
def last_error
|
|
DynamicLibrary.last_error
|
|
end
|
|
|
|
CURRENT_PROCESS = DynamicLibrary.new(nil)
|
|
end
|
|
|
|
module Platform
|
|
ARCH = Rubinius::CPU
|
|
|
|
# ruby-ffi compatible
|
|
LONG_SIZE = Rubinius::SIZEOF_LONG * 8
|
|
ADDRESS_SIZE = Rubinius::WORDSIZE
|
|
|
|
case
|
|
when Rubinius.windows?
|
|
LIBSUFFIX = "dll"
|
|
IS_WINDOWS = true
|
|
OS = 'windows'
|
|
when Rubinius.darwin?
|
|
LIBSUFFIX = "dylib"
|
|
IS_WINDOWS = false
|
|
OS = 'darwin'
|
|
else
|
|
LIBSUFFIX = "so"
|
|
IS_WINDOWS = false
|
|
OS = 'linux'
|
|
end
|
|
|
|
module File
|
|
SEPARATOR = '/'
|
|
ALT_SEPARATOR = nil
|
|
PATH_SEPARATOR = ':'
|
|
end
|
|
|
|
module Math
|
|
extend FFI::Library
|
|
|
|
attach_function :fabs, [:double], :double
|
|
attach_function :atan2, [:double, :double], :double
|
|
attach_function :cos, [:double], :double
|
|
attach_function :sin, [:double], :double
|
|
attach_function :tan, [:double], :double
|
|
attach_function :acos, [:double], :double
|
|
attach_function :asin, [:double], :double
|
|
attach_function :atan, [:double], :double
|
|
attach_function :cosh, [:double], :double
|
|
attach_function :sinh, [:double], :double
|
|
attach_function :tanh, [:double], :double
|
|
attach_function :acosh, [:double], :double
|
|
attach_function :asinh, [:double], :double
|
|
attach_function :atanh, [:double], :double
|
|
attach_function :exp, [:double], :double
|
|
attach_function :log, [:double], :double
|
|
attach_function :log10, [:double], :double
|
|
attach_function :sqrt, [:double], :double
|
|
attach_function :frexp, [:double, :pointer], :double
|
|
attach_function :ldexp, [:double, :int], :double
|
|
attach_function :hypot, [:double, :double], :double
|
|
attach_function :erf, [:double], :double
|
|
attach_function :erfc, [:double], :double
|
|
attach_function :cbrt, [:double], :double
|
|
attach_function :tgamma, [:double], :double
|
|
attach_function :lgamma_r, [:double, :pointer], :double
|
|
|
|
# Rubinius-specific, used in Marshal
|
|
attach_function :modf, [:double, :pointer], :double
|
|
|
|
# TODO: we need a way to determine whether a function
|
|
# is defined for a particular platform.
|
|
#
|
|
# attach_function :log2, [:double], :double
|
|
def self.log2(x)
|
|
log10(x) / log10(2.0)
|
|
end
|
|
end
|
|
|
|
module POSIX
|
|
extend FFI::Library
|
|
|
|
# errors
|
|
attach_function :errno, 'ffi_errno', [], :int
|
|
attach_function :errno=, 'ffi_set_errno', [:int], :void
|
|
|
|
# memory
|
|
attach_function :malloc, [:size_t], :pointer
|
|
attach_function :realloc, [:pointer, :size_t], :pointer
|
|
attach_function :free, [:pointer], :void
|
|
attach_function :memset, [:pointer, :int, :size_t], :pointer
|
|
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
|
|
|
|
# file system
|
|
attach_function :access, [:string, :int], :int
|
|
attach_function :chmod, [:string, :mode_t], :int
|
|
attach_function :fchmod, [:int, :mode_t], :int
|
|
attach_function :lchmod, [:string, :mode_t], :int
|
|
attach_function :chown, [:string, :uid_t, :gid_t], :int
|
|
attach_function :fchown, [:int, :uid_t, :gid_t], :int
|
|
attach_function :lchown, [:string, :uid_t, :gid_t], :int
|
|
attach_function :unlink, [:string], :int
|
|
attach_function :getcwd, [:string, :size_t], :string
|
|
attach_function :umask, [:mode_t], :int
|
|
attach_function :link, [:string, :string], :int
|
|
attach_function :symlink, [:string, :string], :int
|
|
attach_function :readlink, [:string, :pointer, :size_t], :ssize_t
|
|
attach_function :rename, [:string, :string], :int
|
|
attach_function :utimes, [:string, :pointer], :int
|
|
attach_function :mkfifo, [:string, :mode_t], :int
|
|
|
|
# directories
|
|
attach_function :chdir, [:string], :int
|
|
attach_function :mkdir, [:string, :mode_t], :int
|
|
attach_function :rmdir, [:string], :int
|
|
attach_function :chroot, [:string], :int
|
|
|
|
# File/IO
|
|
attach_function :fcntl, [:int, :int, :long], :int
|
|
attach_function :ioctl, [:int, :ulong, :long], :int
|
|
attach_function :fsync, [:int], :int
|
|
attach_function :dup, [:int], :int
|
|
attach_function :dup2, [:int, :int], :int
|
|
attach_function :open, [:string, :int, :mode_t], :int
|
|
attach_function :close, [:int], :int
|
|
attach_function :lseek, [:int, :off_t, :int], :off_t
|
|
attach_function :read, [:int, :pointer, :size_t], :ssize_t
|
|
attach_function :ftruncate, [:int, :off_t], :int
|
|
attach_function :truncate, [:string, :off_t], :int
|
|
attach_function :write, [:int, :pointer, :size_t], :ssize_t
|
|
attach_function :select, [:int, :pointer, :pointer, :pointer, :pointer], :int
|
|
|
|
# Other I/O
|
|
attach_function :pipe, [:pointer], :int
|
|
attach_function :mmap, [:pointer, :size_t, :int, :int, :int, :off_t], :pointer
|
|
attach_function :msync, [:pointer, :size_t, :int], :int
|
|
attach_function :munmap, [:pointer, :size_t], :int
|
|
attach_function :getpagesize, [], :int
|
|
attach_function :shutdown, [:int, :int], :int
|
|
attach_function :posix_fadvise, [:int, :off_t, :off_t, :int], :int
|
|
|
|
# inspecting
|
|
attach_function :isatty, [:int], :int
|
|
attach_function :ttyname, [:int], :string
|
|
|
|
# locking
|
|
attach_function :flock, [:int, :int], :int
|
|
|
|
# UID/GID
|
|
attach_function :getuid, [], :uid_t
|
|
attach_function :getgid, [], :gid_t
|
|
attach_function :geteuid, [], :uid_t
|
|
attach_function :getegid, [], :gid_t
|
|
|
|
attach_function :setgid, [:gid_t], :int
|
|
attach_function :setuid, [:uid_t], :int
|
|
attach_function :setegid, [:gid_t], :int
|
|
attach_function :seteuid, [:uid_t], :int
|
|
|
|
attach_function :setregid, [:gid_t, :gid_t], :int
|
|
attach_function :setreuid, [:uid_t, :uid_t], :int
|
|
|
|
attach_function :setresgid, [:gid_t, :gid_t, :gid_t], :int
|
|
attach_function :setresuid, [:uid_t, :uid_t, :uid_t], :int
|
|
|
|
attach_function :getpriority, [:int, :id_t], :int
|
|
attach_function :setpriority, [:int, :id_t, :int], :int
|
|
|
|
attach_function :getgroups, [:int, :pointer], :int
|
|
attach_function :setgroups, [:int, :pointer], :int
|
|
attach_function :initgroups, [:string, :gid_t], :int
|
|
|
|
attach_function :setrlimit, [:int, :pointer], :int
|
|
attach_function :getrlimit, [:int, :pointer], :int
|
|
|
|
# password and group file access
|
|
attach_function :getpwnam, [:string], :pointer
|
|
attach_function :getpwuid, [:uid_t], :pointer
|
|
attach_function :setpwent, [], :void
|
|
attach_function :getpwent, [], :pointer
|
|
attach_function :endpwent, [], :void
|
|
|
|
attach_function :getgrnam, [:string], :pointer
|
|
attach_function :getgrgid, [:gid_t], :pointer
|
|
attach_function :setgrent, [], :void
|
|
attach_function :getgrent, [], :pointer
|
|
attach_function :endgrent, [], :void
|
|
|
|
# processes and signals
|
|
attach_function :kill, [:pid_t, :int], :int
|
|
attach_function :getpgid, [:pid_t], :pid_t
|
|
attach_function :setpgid, [:pid_t, :pid_t], :int
|
|
attach_function :getpid, [], :pid_t
|
|
attach_function :getppid, [], :pid_t
|
|
attach_function :getpgrp, [], :pid_t
|
|
attach_function :setsid, [], :pid_t
|
|
|
|
# related to stat()
|
|
attach_function :major, 'ffi_major', [:dev_t], :dev_t
|
|
attach_function :minor, 'ffi_minor', [:dev_t], :dev_t
|
|
|
|
# time
|
|
attach_function :gettimeofday, [:pointer, :pointer], :int
|
|
|
|
#--
|
|
# Internal class for accessing timevals
|
|
#++
|
|
class TimeVal < FFI::Struct
|
|
config 'rbx.platform.timeval', :tv_sec, :tv_usec
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
module EnvironmentAccess
|
|
extend FFI::Library
|
|
|
|
attach_function :getenv, [:string], :string
|
|
attach_function :putenv, [:string], :int
|
|
attach_function :setenv, [:string, :string, :int], :int
|
|
attach_function :unsetenv, [:string], :int
|
|
attach_function :environ, 'ffi_environ', [], :pointer
|
|
end
|
|
|
|
class EnvironmentVariables
|
|
include EnvironmentAccess
|
|
end
|
|
|
|
::ENV = EnvironmentVariables.new
|
|
|
|
module Metrics
|
|
class Data
|
|
MetricsHash = Hash.new
|
|
end
|
|
end
|
|
|
|
class Stat
|
|
S_IRUSR = Rubinius::Config['rbx.platform.file.S_IRUSR']
|
|
S_IWUSR = Rubinius::Config['rbx.platform.file.S_IWUSR']
|
|
S_IXUSR = Rubinius::Config['rbx.platform.file.S_IXUSR']
|
|
S_IRGRP = Rubinius::Config['rbx.platform.file.S_IRGRP']
|
|
S_IWGRP = Rubinius::Config['rbx.platform.file.S_IWGRP']
|
|
S_IXGRP = Rubinius::Config['rbx.platform.file.S_IXGRP']
|
|
S_IROTH = Rubinius::Config['rbx.platform.file.S_IROTH']
|
|
S_IWOTH = Rubinius::Config['rbx.platform.file.S_IWOTH']
|
|
S_IXOTH = Rubinius::Config['rbx.platform.file.S_IXOTH']
|
|
|
|
S_IRUGO = S_IRUSR | S_IRGRP | S_IROTH
|
|
S_IWUGO = S_IWUSR | S_IWGRP | S_IWOTH
|
|
S_IXUGO = S_IXUSR | S_IXGRP | S_IXOTH
|
|
|
|
S_IFMT = Rubinius::Config['rbx.platform.file.S_IFMT']
|
|
S_IFIFO = Rubinius::Config['rbx.platform.file.S_IFIFO']
|
|
S_IFCHR = Rubinius::Config['rbx.platform.file.S_IFCHR']
|
|
S_IFDIR = Rubinius::Config['rbx.platform.file.S_IFDIR']
|
|
S_IFBLK = Rubinius::Config['rbx.platform.file.S_IFBLK']
|
|
S_IFREG = Rubinius::Config['rbx.platform.file.S_IFREG']
|
|
S_IFLNK = Rubinius::Config['rbx.platform.file.S_IFLNK']
|
|
S_IFSOCK = Rubinius::Config['rbx.platform.file.S_IFSOCK']
|
|
S_IFWHT = Rubinius::Config['rbx.platform.file.S_IFWHT']
|
|
S_ISUID = Rubinius::Config['rbx.platform.file.S_ISUID']
|
|
S_ISGID = Rubinius::Config['rbx.platform.file.S_ISGID']
|
|
S_ISVTX = Rubinius::Config['rbx.platform.file.S_ISVTX']
|
|
end
|
|
end
|
|
|
|
code = Class.method_table.lookup(:new).get_method
|
|
code.serial = Rubinius::CompiledCode::KernelMethodSerial
|
|
|
|
class Class
|
|
undef_method :append_features
|
|
undef_method :extend_object
|
|
undef_method :module_function
|
|
undef_method :prepend_features
|
|
end
|
|
|
|
class Complex < Numeric
|
|
I = Complex(0, 1)
|
|
end
|
|
|
|
class NilClass
|
|
include ImmediateValue
|
|
end
|
|
|
|
class FalseClass
|
|
include ImmediateValue
|
|
end
|
|
|
|
class TrueClass
|
|
include ImmediateValue
|
|
end
|
|
|
|
class Symbol
|
|
include ImmediateValue
|
|
end
|
|
|
|
class Fixnum
|
|
include ImmediateValue
|
|
end
|
|
|
|
# Default Ruby Record Separator
|
|
# Used in this file and by various methods that need to ignore $/
|
|
DEFAULT_RECORD_SEPARATOR = "\n"
|
|
|
|
class Dir
|
|
# This seems silly, I know. But we do this to make Dir more resistent to people
|
|
# screwing with ::File later (ie, fakefs)
|
|
PrivateFile = ::File
|
|
|
|
FFI = Rubinius::FFI
|
|
|
|
module Glob
|
|
total = Rubinius::Config['glob.cache']
|
|
|
|
case total
|
|
when Fixnum
|
|
if total == 0
|
|
@glob_cache = nil
|
|
else
|
|
@glob_cache = Rubinius::LRUCache.new(total)
|
|
end
|
|
when false
|
|
@glob_cache = nil
|
|
else
|
|
@glob_cache = Rubinius::LRUCache.new(50)
|
|
end
|
|
end
|
|
end
|
|
|
|
class Encoding
|
|
class Converter
|
|
class TranscodingPath
|
|
@paths = {}
|
|
@load_cache = true
|
|
@cache_valid = false
|
|
@transcoders_count = TranscodingMap.size
|
|
end
|
|
end
|
|
end
|
|
|
|
module Errno
|
|
FFI = Rubinius::FFI
|
|
end
|
|
|
|
class File < IO
|
|
# these will be necessary when we run on Windows
|
|
DOSISH = false # !!(RUBY_PLATFORM =~ /mswin/)
|
|
CASEFOLD_FILESYSTEM = DOSISH
|
|
FNM_SYSCASE = CASEFOLD_FILESYSTEM ? FNM_CASEFOLD : 0
|
|
|
|
module Constants
|
|
F_GETFL = Rubinius::Config['rbx.platform.fcntl.F_GETFL']
|
|
F_SETFL = Rubinius::Config['rbx.platform.fcntl.F_SETFL']
|
|
|
|
# O_ACCMODE is /undocumented/ for fcntl() on some platforms
|
|
ACCMODE = Rubinius::Config['rbx.platform.fcntl.O_ACCMODE']
|
|
O_ACCMODE = Rubinius::Config['rbx.platform.fcntl.O_ACCMODE']
|
|
|
|
F_GETFD = Rubinius::Config['rbx.platform.fcntl.F_GETFD']
|
|
F_SETFD = Rubinius::Config['rbx.platform.fcntl.F_SETFD']
|
|
FD_CLOEXEC = Rubinius::Config['rbx.platform.fcntl.FD_CLOEXEC']
|
|
O_CLOEXEC = Rubinius::Config['rbx.platform.file.O_CLOEXEC']
|
|
O_NONBLOCK = Rubinius::Config['rbx.platform.file.O_NONBLOCK']
|
|
|
|
RDONLY = Rubinius::Config['rbx.platform.file.O_RDONLY']
|
|
WRONLY = Rubinius::Config['rbx.platform.file.O_WRONLY']
|
|
RDWR = Rubinius::Config['rbx.platform.file.O_RDWR']
|
|
|
|
CREAT = Rubinius::Config['rbx.platform.file.O_CREAT']
|
|
EXCL = Rubinius::Config['rbx.platform.file.O_EXCL']
|
|
NOCTTY = Rubinius::Config['rbx.platform.file.O_NOCTTY']
|
|
TRUNC = Rubinius::Config['rbx.platform.file.O_TRUNC']
|
|
APPEND = Rubinius::Config['rbx.platform.file.O_APPEND']
|
|
NONBLOCK = Rubinius::Config['rbx.platform.file.O_NONBLOCK']
|
|
SYNC = Rubinius::Config['rbx.platform.file.O_SYNC']
|
|
|
|
# TODO: these flags should probably be imported from Platform
|
|
LOCK_SH = 0x01
|
|
LOCK_EX = 0x02
|
|
LOCK_NB = 0x04
|
|
LOCK_UN = 0x08
|
|
BINARY = 0x04
|
|
|
|
# TODO: "OK" constants aren't in File::Constants in MRI
|
|
F_OK = 0 # test for existence of file
|
|
X_OK = 1 # test for execute or search permission
|
|
W_OK = 2 # test for write permission
|
|
R_OK = 4 # test for read permission
|
|
|
|
FNM_NOESCAPE = 0x01
|
|
FNM_PATHNAME = 0x02
|
|
FNM_DOTMATCH = 0x04
|
|
FNM_CASEFOLD = 0x08
|
|
FNM_EXTGLOB = 0x10
|
|
FNM_SYSCASE = File::FNM_SYSCASE
|
|
|
|
if Rubinius.windows?
|
|
NULL = 'NUL'
|
|
else
|
|
NULL = '/dev/null'
|
|
end
|
|
end
|
|
|
|
Stat = Rubinius::Stat
|
|
|
|
class Stat
|
|
@module_name = :"File::Stat"
|
|
|
|
def world_readable?
|
|
if mode & S_IROTH == S_IROTH
|
|
tmp = mode & (S_IRUGO | S_IWUGO | S_IXUGO)
|
|
return Rubinius::Type.coerce_to tmp, Fixnum, :to_int
|
|
end
|
|
end
|
|
|
|
def world_writable?
|
|
if mode & S_IWOTH == S_IWOTH
|
|
tmp = mode & (S_IRUGO | S_IWUGO | S_IXUGO)
|
|
return Rubinius::Type.coerce_to tmp, Fixnum, :to_int
|
|
end
|
|
end
|
|
end
|
|
|
|
FFI = Rubinius::FFI
|
|
|
|
SEPARATOR = FFI::Platform::File::SEPARATOR
|
|
Separator = FFI::Platform::File::SEPARATOR
|
|
ALT_SEPARATOR = FFI::Platform::File::ALT_SEPARATOR
|
|
PATH_SEPARATOR = FFI::Platform::File::PATH_SEPARATOR
|
|
POSIX = FFI::Platform::POSIX
|
|
end
|
|
|
|
class Float
|
|
FFI = Rubinius::FFI
|
|
end
|
|
|
|
class IO
|
|
include File::Constants
|
|
|
|
FFI = Rubinius::FFI
|
|
|
|
SEEK_SET = Rubinius::Config['rbx.platform.io.SEEK_SET']
|
|
SEEK_CUR = Rubinius::Config['rbx.platform.io.SEEK_CUR']
|
|
SEEK_END = Rubinius::Config['rbx.platform.io.SEEK_END']
|
|
|
|
# Not available on all platforms, so these constants may be nil
|
|
POSIX_FADV_NORMAL = Rubinius::Config['rbx.platform.advise.POSIX_FADV_NORMAL']
|
|
POSIX_FADV_SEQUENTIAL = Rubinius::Config['rbx.platform.advise.POSIX_FADV_SEQUENTIAL']
|
|
POSIX_FADV_RANDOM = Rubinius::Config['rbx.platform.advise.POSIX_FADV_RANDOM']
|
|
POSIX_FADV_WILLNEED = Rubinius::Config['rbx.platform.advise.POSIX_FADV_WILLNEED']
|
|
POSIX_FADV_DONTNEED = Rubinius::Config['rbx.platform.advise.POSIX_FADV_DONTNEED']
|
|
POSIX_FADV_NOREUSE = Rubinius::Config['rbx.platform.advise.POSIX_FADV_NOREUSE']
|
|
|
|
class FileDescriptor
|
|
@@max_descriptors = Rubinius::AtomicReference.new(2)
|
|
|
|
include File::Constants
|
|
|
|
O_RDONLY = Rubinius::Config['rbx.platform.file.O_RDONLY']
|
|
O_WRONLY = Rubinius::Config['rbx.platform.file.O_WRONLY']
|
|
O_RDWR = Rubinius::Config['rbx.platform.file.O_RDWR']
|
|
end
|
|
|
|
class Select
|
|
FD_SETSIZE = Rubinius::Config['rbx.platform.select.FD_SETSIZE']
|
|
end
|
|
end
|
|
|
|
class NilClass
|
|
include ImmediateValue
|
|
end
|
|
|
|
class FalseClass
|
|
include ImmediateValue
|
|
end
|
|
|
|
class TrueClass
|
|
include ImmediateValue
|
|
end
|
|
|
|
class Symbol
|
|
include ImmediateValue
|
|
end
|
|
|
|
class Fixnum
|
|
include ImmediateValue
|
|
end
|
|
|
|
module Rubinius
|
|
class Mirror
|
|
module Process
|
|
class Execute
|
|
# Mapping of string open modes to integer oflag versions.
|
|
OFLAGS = {
|
|
"r" => ::File::RDONLY,
|
|
"r+" => ::File::RDWR | ::File::CREAT,
|
|
"w" => ::File::WRONLY | ::File::CREAT | ::File::TRUNC,
|
|
"w+" => ::File::RDWR | ::File::CREAT | ::File::TRUNC,
|
|
"a" => ::File::WRONLY | ::File::APPEND | ::File::CREAT,
|
|
"a+" => ::File::RDWR | ::File::APPEND | ::File::CREAT
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
class Regexp
|
|
IGNORECASE = 1
|
|
EXTENDED = 2
|
|
MULTILINE = 4
|
|
FIXEDENCODING = 16
|
|
NOENCODING = 32
|
|
DONT_CAPTURE_GROUP = 128
|
|
CAPTURE_GROUP = 256
|
|
|
|
KCODE_NONE = (1 << 9)
|
|
KCODE_EUC = (2 << 9)
|
|
KCODE_SJIS = (3 << 9)
|
|
KCODE_UTF8 = (4 << 9)
|
|
KCODE_MASK = KCODE_NONE | KCODE_EUC | KCODE_SJIS | KCODE_UTF8
|
|
|
|
OPTION_MASK = IGNORECASE | EXTENDED | MULTILINE | FIXEDENCODING | NOENCODING | DONT_CAPTURE_GROUP | CAPTURE_GROUP
|
|
|
|
ESCAPE_TABLE = Rubinius::Tuple.new(256)
|
|
|
|
# Seed it with direct replacements
|
|
i = 0
|
|
while i < 256
|
|
ESCAPE_TABLE[i] = i.chr
|
|
i += 1
|
|
end
|
|
|
|
# The character literals (?x) are Fixnums in 1.8 and Strings in 1.9
|
|
# so we use literal values instead so this is 1.8/1.9 compatible.
|
|
ESCAPE_TABLE[9] = '\\t'
|
|
ESCAPE_TABLE[10] = '\\n'
|
|
ESCAPE_TABLE[11] = '\\v'
|
|
ESCAPE_TABLE[12] = '\\f'
|
|
ESCAPE_TABLE[13] = '\\r'
|
|
ESCAPE_TABLE[32] = '\\ '
|
|
ESCAPE_TABLE[35] = '\\#'
|
|
ESCAPE_TABLE[36] = '\\$'
|
|
ESCAPE_TABLE[40] = '\\('
|
|
ESCAPE_TABLE[41] = '\\)'
|
|
ESCAPE_TABLE[42] = '\\*'
|
|
ESCAPE_TABLE[43] = '\\+'
|
|
ESCAPE_TABLE[45] = '\\-'
|
|
ESCAPE_TABLE[46] = '\\.'
|
|
ESCAPE_TABLE[63] = '\\?'
|
|
ESCAPE_TABLE[91] = '\\['
|
|
ESCAPE_TABLE[92] = '\\\\'
|
|
ESCAPE_TABLE[93] = '\\]'
|
|
ESCAPE_TABLE[94] = '\\^'
|
|
ESCAPE_TABLE[123] = '\\{'
|
|
ESCAPE_TABLE[124] = '\\|'
|
|
ESCAPE_TABLE[125] = '\\}'
|
|
|
|
class SourceParser
|
|
class Part
|
|
OPTIONS_MAP = {
|
|
'm' => Regexp::MULTILINE,
|
|
'i' => Regexp::IGNORECASE,
|
|
'x' => Regexp::EXTENDED
|
|
}
|
|
end
|
|
|
|
PossibleOptions = [[MULTILINE, "m"], [IGNORECASE, "i"], [EXTENDED, "x"]]
|
|
end
|
|
end
|
|
|
|
class String
|
|
class Rationalizer
|
|
SPACE = "\\s*"
|
|
DIGITS = "(?:[0-9](?:_[0-9]|[0-9])*)"
|
|
NUMERATOR = "(?:#{DIGITS}?\\.)?#{DIGITS}(?:[eE][-+]?#{DIGITS})?"
|
|
DENOMINATOR = DIGITS
|
|
RATIONAL = "\\A#{SPACE}([-+])?(#{NUMERATOR})(?:\\/(#{DENOMINATOR}))?#{SPACE}"
|
|
PATTERN = Regexp.new RATIONAL
|
|
end
|
|
|
|
class Complexifier
|
|
SPACE = Rationalizer::SPACE
|
|
NUMERATOR = Rationalizer::NUMERATOR
|
|
DENOMINATOR = Rationalizer::DENOMINATOR
|
|
NUMBER = "[-+]?#{NUMERATOR}(?:\\/#{DENOMINATOR})?"
|
|
NUMBERNOS = "#{NUMERATOR}(?:\\/#{DENOMINATOR})?"
|
|
PATTERN0 = Regexp.new "\\A#{SPACE}(#{NUMBER})@(#{NUMBER})#{SPACE}"
|
|
PATTERN1 = Regexp.new "\\A#{SPACE}([-+])?(#{NUMBER})?[iIjJ]#{SPACE}"
|
|
PATTERN2 = Regexp.new "\\A#{SPACE}(#{NUMBER})(([-+])(#{NUMBERNOS})?[iIjJ])?#{SPACE}"
|
|
end
|
|
end
|
|
|
|
module Signal
|
|
Names = {
|
|
"EXIT" => 0
|
|
}
|
|
|
|
Numbers = {
|
|
0 => "EXIT"
|
|
}
|
|
|
|
@handlers = {}
|
|
|
|
Rubinius::Config.section 'rbx.platform.signal.' do |key, value|
|
|
name = key[23, key.length]
|
|
number = value.to_i
|
|
Names[name] = number
|
|
Numbers[number] = name
|
|
end
|
|
|
|
# special case of signal.c
|
|
if Names["CHLD"]
|
|
Names["CLD"] = Names["CHLD"]
|
|
end
|
|
end
|
|
|
|
class Integer < Numeric
|
|
alias_method :magnitude, :abs
|
|
end
|
|
|
|
module Kernel
|
|
def extend(*modules)
|
|
raise ArgumentError, "wrong number of arguments (0 for 1+)" if modules.empty?
|
|
Rubinius.check_frozen
|
|
|
|
modules.reverse_each do |mod|
|
|
Rubinius.privately do
|
|
mod.extend_object self
|
|
end
|
|
|
|
Rubinius.privately do
|
|
mod.extended self
|
|
end
|
|
end
|
|
self
|
|
end
|
|
|
|
alias_method :__extend__, :extend
|
|
|
|
def method_missing(meth, *args)
|
|
cls = NoMethodError
|
|
|
|
case Rubinius.method_missing_reason
|
|
when :private
|
|
msg = "private method `#{meth}' called"
|
|
when :protected
|
|
msg = "protected method `#{meth}' called"
|
|
when :super
|
|
msg = "no superclass method `#{meth}'"
|
|
when :vcall
|
|
msg = "undefined local variable or method `#{meth}'"
|
|
cls = NameError
|
|
else
|
|
msg = "undefined method `#{meth}'"
|
|
end
|
|
|
|
object_class = Rubinius::Type.object_class(self)
|
|
|
|
if Rubinius::Type.object_kind_of?(self, Module)
|
|
msg << " on #{self} (#{object_class})"
|
|
|
|
# A separate case for nil, because people like to patch methods to
|
|
# nil, so we can't call methods on it reliably.
|
|
elsif nil.equal?(self)
|
|
msg << " on nil:NilClass"
|
|
|
|
if $rbx_show_nil_location
|
|
m = Rubinius::Mirror::Object.reflect self
|
|
code_id = m.nil_code_id
|
|
|
|
# TODO: implement in CodeDB
|
|
code = nil
|
|
|
|
ObjectSpace.each_object(Rubinius::CompiledCode).each do |c|
|
|
code = c if c.code_id.start_with? code_id
|
|
end
|
|
|
|
|
|
if code
|
|
ip = m.nil_ip
|
|
msg << " originating in '#{code.name}' at #{code.file}:#{code.line_from_ip(ip)}+#{ip}"
|
|
end
|
|
end
|
|
|
|
msg << "."
|
|
elsif ImmediateValue === self
|
|
msg << " on #{self}:#{object_class}."
|
|
else
|
|
msg << " on an instance of #{object_class}."
|
|
end
|
|
|
|
Kernel.raise(cls.new(msg, meth, args, receiver: self))
|
|
end
|
|
|
|
private :method_missing
|
|
|
|
def raise(exc=undefined, msg=undefined, ctx=nil, cause: nil)
|
|
if undefined.equal? exc
|
|
exc = $!
|
|
exc = RuntimeError.new("No current exception") unless exc
|
|
exc.cause = cause unless exc.cause or exc == cause
|
|
else
|
|
if exc.respond_to? :exception
|
|
if undefined.equal? msg
|
|
exc = exc.exception
|
|
else
|
|
exc = exc.exception msg
|
|
end
|
|
raise ::TypeError, 'exception class/object expected' unless exc.kind_of?(::Exception)
|
|
elsif exc.kind_of? String
|
|
exc = ::RuntimeError.exception exc
|
|
else
|
|
raise ::TypeError, 'exception class/object expected'
|
|
end
|
|
|
|
exc.cause = cause unless exc.cause or exc == cause
|
|
exc.cause = $! unless exc.cause or exc == $!
|
|
end
|
|
|
|
if ctx.kind_of? Array
|
|
exc.set_backtrace ctx
|
|
else
|
|
exc.capture_backtrace!(2) unless exc.backtrace?
|
|
end
|
|
|
|
if $DEBUG and $VERBOSE != nil
|
|
if loc = exc.locations and loc[1]
|
|
pos = loc[1].position
|
|
else
|
|
pos = Rubinius::VM.backtrace(1)[0].position
|
|
end
|
|
|
|
STDERR.puts "Exception: `#{exc.class}' #{pos} - #{exc.message}"
|
|
end
|
|
|
|
Rubinius.raise_exception exc
|
|
end
|
|
module_function :raise
|
|
|
|
alias_method :fail, :raise
|
|
module_function :fail
|
|
|
|
def to_s
|
|
Rubinius::Type.infect("#<#{self.class}:0x#{self.__id__.to_s(16)}>", self)
|
|
end
|
|
|
|
# Add in $! in as a hook, to just do $!. This is for accesses to $!
|
|
# that the compiler can't see.
|
|
Rubinius::Globals.set_hook(:$!) { $! }
|
|
|
|
get = proc do
|
|
# We raise an exception here because Regexp.last_match won't work
|
|
raise TypeError, "Unable to handle $~ in this context"
|
|
end
|
|
set = proc do |key, val|
|
|
if val.nil? || val.kind_of?(MatchData)
|
|
Rubinius.invoke_primitive :regexp_set_last_match, val
|
|
else
|
|
raise TypeError, "Cannot assign #{val.class}, expexted nil or instance MatchData."
|
|
end
|
|
end
|
|
Rubinius::Globals.set_hook(:$~, get, set)
|
|
|
|
Rubinius::Globals.set_hook(:$*) { ARGV }
|
|
|
|
Rubinius::Globals.set_hook(:$@) { $! ? $!.backtrace : nil }
|
|
|
|
Rubinius::Globals.set_hook(:$$) { Process.pid }
|
|
|
|
prc = proc { ARGF.filename }
|
|
Rubinius::Globals.set_hook(:$FILENAME, prc, :raise_readonly)
|
|
|
|
write_filter = proc do |key, io|
|
|
unless io.respond_to? :write
|
|
raise ::TypeError, "#{key} must have write method, #{io.class} given"
|
|
end
|
|
io
|
|
end
|
|
|
|
get = proc { |key| Thread.current[:$_] }
|
|
set = proc { |key, val| Thread.current[:$_] = val }
|
|
Rubinius::Globals.set_hook(:$_, get, set)
|
|
|
|
Rubinius::Globals.add_alias :$stdout, :$>
|
|
Rubinius::Globals.set_filter(:$stdout, write_filter)
|
|
Rubinius::Globals.set_filter(:$stderr, write_filter)
|
|
|
|
get = proc do
|
|
warn "$KCODE is unused in Ruby 1.9 and later"
|
|
nil
|
|
end
|
|
|
|
set = proc do |key, io|
|
|
warn "$KCODE is unused in Ruby 1.9 and later, changes are ignored"
|
|
nil
|
|
end
|
|
|
|
Rubinius::Globals.set_hook(:$KCODE, get, set)
|
|
|
|
set = proc do |key, val|
|
|
val = Rubinius::Type.coerce_to val, String, :to_str
|
|
Rubinius.invoke_primitive :vm_set_process_title, val
|
|
end
|
|
Rubinius::Globals.set_hook(:$0, :[], set)
|
|
|
|
set = proc { |key, val| STDERR.puts("WARNING: $SAFE is not supported on Rubinius."); val }
|
|
Rubinius::Globals.set_hook(:$SAFE, :[], set)
|
|
|
|
# Alias $0 $PROGRAM_NAME
|
|
Rubinius::Globals.add_alias(:$0, :$PROGRAM_NAME)
|
|
|
|
Rubinius::Globals.read_only :$:, :$LOAD_PATH, :$-I
|
|
Rubinius::Globals.read_only :$", :$LOADED_FEATURES
|
|
Rubinius::Globals.read_only :$<
|
|
|
|
Rubinius::Globals[:$-a] = false
|
|
Rubinius::Globals[:$-l] = false
|
|
Rubinius::Globals[:$-p] = false
|
|
Rubinius::Globals.read_only :$-a, :$-l, :$-p
|
|
|
|
Rubinius::Globals.add_alias :$DEBUG, :$-d
|
|
Rubinius::Globals.add_alias :$VERBOSE, :$-v
|
|
Rubinius::Globals.add_alias :$VERBOSE, :$-w
|
|
|
|
set_string = proc do |key, value|
|
|
unless value.nil? or value.kind_of? String
|
|
raise TypeError, "value of #{key} must be a String"
|
|
end
|
|
|
|
Rubinius::Globals.set! key, value
|
|
end
|
|
|
|
Rubinius::Globals.set_filter :$/, set_string
|
|
Rubinius::Globals.add_alias :$/, :$-0
|
|
|
|
Rubinius::Globals.set_filter :$,, set_string
|
|
end
|
|
|
|
module Math
|
|
FFI = Rubinius::FFI
|
|
|
|
# Constants
|
|
PI = 3.14159_26535_89793_23846
|
|
E = 2.71828_18284_59045_23536
|
|
|
|
FactorialTable = [
|
|
1.0,
|
|
1.0,
|
|
2.0,
|
|
6.0,
|
|
24.0,
|
|
120.0,
|
|
720.0,
|
|
5040.0,
|
|
40320.0,
|
|
362880.0,
|
|
3628800.0,
|
|
39916800.0,
|
|
479001600.0,
|
|
6227020800.0,
|
|
87178291200.0,
|
|
1307674368000.0,
|
|
20922789888000.0,
|
|
355687428096000.0,
|
|
6402373705728000.0,
|
|
121645100408832000.0,
|
|
2432902008176640000.0,
|
|
51090942171709440000.0,
|
|
1124000727777607680000.0
|
|
]
|
|
|
|
if Errno.const_defined? :EDOM
|
|
DomainError = Errno::EDOM
|
|
elsif Errno.const_defined? :ERANGE
|
|
DomainError = Errno::ERANGE
|
|
else
|
|
class DomainError < SystemCallError
|
|
end
|
|
end
|
|
end
|
|
|
|
module Process
|
|
module Constants
|
|
EXIT_SUCCESS = Rubinius::Config['rbx.platform.process.EXIT_SUCCESS'] || 0
|
|
EXIT_FAILURE = Rubinius::Config['rbx.platform.process.EXIT_FAILURE'] || 1
|
|
|
|
PRIO_PGRP = Rubinius::Config['rbx.platform.process.PRIO_PGRP']
|
|
PRIO_PROCESS = Rubinius::Config['rbx.platform.process.PRIO_PROCESS']
|
|
PRIO_USER = Rubinius::Config['rbx.platform.process.PRIO_USER']
|
|
|
|
RLIM_INFINITY = Rubinius::Config['rbx.platform.process.RLIM_INFINITY']
|
|
RLIM_SAVED_MAX = Rubinius::Config['rbx.platform.process.RLIM_SAVED_MAX']
|
|
RLIM_SAVED_CUR = Rubinius::Config['rbx.platform.process.RLIM_SAVED_CUR']
|
|
|
|
RLIMIT_AS = Rubinius::Config['rbx.platform.process.RLIMIT_AS']
|
|
RLIMIT_CORE = Rubinius::Config['rbx.platform.process.RLIMIT_CORE']
|
|
RLIMIT_CPU = Rubinius::Config['rbx.platform.process.RLIMIT_CPU']
|
|
RLIMIT_DATA = Rubinius::Config['rbx.platform.process.RLIMIT_DATA']
|
|
RLIMIT_FSIZE = Rubinius::Config['rbx.platform.process.RLIMIT_FSIZE']
|
|
RLIMIT_MEMLOCK = Rubinius::Config['rbx.platform.process.RLIMIT_MEMLOCK']
|
|
RLIMIT_NOFILE = Rubinius::Config['rbx.platform.process.RLIMIT_NOFILE']
|
|
RLIMIT_NPROC = Rubinius::Config['rbx.platform.process.RLIMIT_NPROC']
|
|
RLIMIT_RSS = Rubinius::Config['rbx.platform.process.RLIMIT_RSS']
|
|
RLIMIT_SBSIZE = Rubinius::Config['rbx.platform.process.RLIMIT_SBSIZE']
|
|
RLIMIT_STACK = Rubinius::Config['rbx.platform.process.RLIMIT_STACK']
|
|
|
|
RLIMIT_RTPRIO = Rubinius::Config['rbx.platform.process.RLIMIT_RTPRIO']
|
|
RLIMIT_RTTIME = Rubinius::Config['rbx.platform.process.RLIMIT_RTTIME']
|
|
RLIMIT_SIGPENDING = Rubinius::Config['rbx.platform.process.RLIMIT_SIGPENDING']
|
|
RLIMIT_MSGQUEUE = Rubinius::Config['rbx.platform.process.RLIMIT_MSGQUEUE']
|
|
RLIMIT_NICE = Rubinius::Config['rbx.platform.process.RLIMIT_NICE']
|
|
|
|
WNOHANG = 1
|
|
WUNTRACED = 2
|
|
end
|
|
include Constants
|
|
|
|
FFI = Rubinius::FFI
|
|
|
|
class Rlimit < FFI::Struct
|
|
config "rbx.platform.rlimit", :rlim_cur, :rlim_max
|
|
end
|
|
|
|
Rubinius::Globals.read_only :$?
|
|
Rubinius::Globals.set_hook(:$?) { Thread.current[:$?] }
|
|
end
|
|
|
|
|
|
STDIN = Rubinius::IOUtility.redefine_io(0, :read_only)
|
|
STDOUT = Rubinius::IOUtility.redefine_io(1, :write_only)
|
|
STDERR = Rubinius::IOUtility.redefine_io(2, :write_only)
|
|
|
|
Rubinius::Globals.set!(:$stdin, STDIN)
|
|
Rubinius::Globals.set!(:$stdout, STDOUT)
|
|
Rubinius::Globals.set!(:$stderr, STDERR)
|
|
|
|
module Rubinius
|
|
begin
|
|
is_tty = STDIN.tty?
|
|
rescue IOError
|
|
is_tty = false
|
|
end
|
|
|
|
Terminal = is_tty
|
|
AtExit = []
|
|
|
|
class Sprinter
|
|
total = Rubinius::Config['printf.cache']
|
|
|
|
case total
|
|
when Fixnum
|
|
if total == 0
|
|
@cache = nil
|
|
else
|
|
@cache = Rubinius::LRUCache.new(total)
|
|
end
|
|
when false
|
|
@cache = nil
|
|
else
|
|
@cache = Rubinius::LRUCache.new(50)
|
|
end
|
|
|
|
class Builder
|
|
RADIX = { 'u' => 10, 'x' => 16, 'X' => 16, 'o' => 8, 'b' => 2, 'B' => 2 }
|
|
PREFIX = { 'o' => '0', 'x' => '0x', 'X' => '0X', 'b' => '0b', 'B' => '0B' }
|
|
|
|
AtomMap = Rubinius::LookupTable.new
|
|
|
|
AtomMap[?c] = CharAtom
|
|
AtomMap[?s] = StringAtom
|
|
AtomMap[?p] = InspectAtom
|
|
AtomMap[?e] = FloatAtom
|
|
AtomMap[?E] = FloatAtom
|
|
AtomMap[?g] = FloatAtom
|
|
AtomMap[?G] = FloatAtom
|
|
AtomMap[?f] = FloatAtom
|
|
AtomMap[?d] = IntegerAtom
|
|
AtomMap[?i] = IntegerAtom
|
|
AtomMap[?u] = IntegerAtom
|
|
AtomMap[?b] = ExtIntegerAtom
|
|
AtomMap[?B] = ExtIntegerAtom
|
|
AtomMap[?x] = ExtIntegerAtom
|
|
AtomMap[?X] = ExtIntegerAtom
|
|
AtomMap[?o] = ExtIntegerAtom
|
|
|
|
RE = /
|
|
([^%]+|%(?:[\n\0]|\z)) # 1
|
|
|
|
|
%
|
|
( # 2
|
|
(<[^>]+>)? # 3
|
|
([0# +-]*) # 4
|
|
(?:([0-9]+)\$)? # 5
|
|
([0# +-]*) # 6
|
|
(?:
|
|
(\*(?:([0-9]+)\$)?|([1-9][0-9]*))? # 7 8 9
|
|
(?:\.(\*(?:([0-9]+)\$)?|([0-9][0-9]*))?)? # 10 11 12
|
|
)
|
|
(?:([0-9]+)\$)? # 13
|
|
([BbcdEefGgiopsuXx]) # 14
|
|
)
|
|
|
|
|
(%)(?:%|[-+0-9# *.$]+\$[0-9.]*\z) # 15
|
|
|
|
|
(%{[^}]+}) #16
|
|
|
|
|
(%) # 17
|
|
/x
|
|
end
|
|
end
|
|
end
|
|
|
|
class Struct
|
|
Struct.new 'Tms', :utime, :stime, :cutime, :cstime, :tutime, :tstime
|
|
|
|
class Tms
|
|
def initialize(utime=nil, stime=nil, cutime=nil, cstime=nil,
|
|
tutime=nil, tstime=nil)
|
|
@utime = utime
|
|
@stime = stime
|
|
@cutime = cutime
|
|
@cstime = cstime
|
|
@tutime = tutime
|
|
@tstime = tstime
|
|
end
|
|
|
|
private :initialize
|
|
end
|
|
|
|
def self._specialize(attrs)
|
|
# Because people are crazy, they subclass Struct directly, ie.
|
|
# class Craptastic < Struct
|
|
#
|
|
# NOT
|
|
#
|
|
# class Fine < Struct.new(:x, :y)
|
|
#
|
|
# When they do this craptastic act, they'll sometimes define their
|
|
# own #initialize and super into Struct#initialize.
|
|
#
|
|
# When they do this and then do Craptastic.new(:x, :y), this code
|
|
# will accidentally shadow their #initialize. So for now, only run
|
|
# the specialize if we're trying new Struct's directly from Struct itself,
|
|
# not a craptastic Struct subclass.
|
|
|
|
return unless superclass.equal? Struct
|
|
|
|
# To allow for optimization, we generate code with normal ivar
|
|
# references for all attributes whose names can be written as
|
|
# tIVAR tokens. For example, of the following struct attributes
|
|
#
|
|
# Struct.new(:a, :@b, :c?, :'d-e')
|
|
#
|
|
# only the first, :a, can be written as a valid tIVAR token:
|
|
#
|
|
# * :a can be written as @a
|
|
# * :@b becomes @@b and would be interpreted as a tCVAR
|
|
# * :c? becomes @c? and be interpreted as the beginning of
|
|
# a ternary expression
|
|
# * :'d-e' becomes @d-e and would be interpreted as a method
|
|
# invocation
|
|
#
|
|
# Attribute names that cannot be written as tIVAR tokens will
|
|
# fall back to using #instance_variable_(get|set).
|
|
|
|
args, assigns, hashes, vars = [], [], [], []
|
|
|
|
attrs.each_with_index do |name, i|
|
|
name = "@#{name}"
|
|
|
|
if name =~ /^@[a-z_]\w*$/i
|
|
assigns << "#{name} = a#{i}"
|
|
vars << name
|
|
else
|
|
assigns << "instance_variable_set(:#{name.inspect}, a#{i})"
|
|
vars << "instance_variable_get(:#{name.inspect})"
|
|
end
|
|
|
|
args << "a#{i} = nil"
|
|
hashes << "#{vars[-1]}.hash"
|
|
end
|
|
|
|
code = <<-CODE
|
|
def initialize(#{args.join(", ")})
|
|
#{assigns.join(';')}
|
|
self
|
|
end
|
|
|
|
private :initialize
|
|
|
|
def hash
|
|
hash = #{hashes.size}
|
|
|
|
return hash if Thread.detect_outermost_recursion(self) do
|
|
hash = hash ^ #{hashes.join(' ^ ')}
|
|
end
|
|
|
|
hash
|
|
end
|
|
|
|
def to_a
|
|
[#{vars.join(', ')}]
|
|
end
|
|
|
|
def length
|
|
#{vars.size}
|
|
end
|
|
CODE
|
|
|
|
begin
|
|
mod = Module.new do
|
|
module_eval code
|
|
end
|
|
include mod
|
|
rescue SyntaxError
|
|
# SyntaxError means that something is wrong with the
|
|
# specialization code. Just eat the error and don't specialize.
|
|
end
|
|
end
|
|
end
|
|
|
|
class Thread
|
|
MUTEX_FOR_THREAD_EXCLUSIVE = Mutex.new
|
|
|
|
Thread.initialize_main_thread(Thread.current)
|
|
ThreadGroup::Default.add Thread.current
|
|
|
|
sm = Rubinius::Mirror.reflect Rubinius.signal_thread
|
|
sm.group = ThreadGroup::Default
|
|
end
|
|
|
|
class Time
|
|
MonthValue = {
|
|
'JAN' => 1, 'FEB' => 2, 'MAR' => 3, 'APR' => 4, 'MAY' => 5, 'JUN' => 6,
|
|
'JUL' => 7, 'AUG' => 8, 'SEP' => 9, 'OCT' =>10, 'NOV' =>11, 'DEC' =>12
|
|
}
|
|
end
|
|
|
|
class Random
|
|
DEFAULT = new
|
|
end
|
|
|
|
module Rubinius
|
|
class Prediction
|
|
def valid?
|
|
Rubinius.primitive :prediction_valid_p
|
|
raise PrimitiveFailure, "Rubinius::Prediction#valid? primitive failed"
|
|
end
|
|
end
|
|
|
|
class CodeDB
|
|
class << self
|
|
undef :new
|
|
end
|
|
end
|
|
|
|
module FFI
|
|
module Library
|
|
# Once the core library is loaded, we want to raise an error if
|
|
# attempting to attach to a non-existent function.
|
|
def ffi_function_missing(name, *args)
|
|
raise FFI::NotFoundError, "Unable to find foreign function '#{name}'"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|