Ejemplo n.º 1
0
        public static object DeepCopy(RubyContext /*!*/ context, object obj)
        {
            using (IDisposable handle = _infiniteCopyTracker.TrackObject(obj)) {
                if (handle == null)
                {
                    return(RubyExceptions.CreateArgumentError("unable to deep copy recursive structure"));
                }
                else
                {
                    RubyContext ec = RubyUtils.GetExecutionContext(context);

                    if (RubyUtils.IsRubyValueType(obj))
                    {
                        return(obj);
                    }

                    object copy;

                    // TODO: special case class objects:
                    RubyClass classObject = obj as RubyClass;
                    if (classObject != null)
                    {
                        copy = classObject.Duplicate();
                    }
                    else
                    {
                        copy = RubySites.Allocate(context, ec.GetClassOf(obj));
                    }

                    SymbolId[]       names   = ec.GetInstanceVariableNames(obj);
                    RubyInstanceData newVars = (names.Length > 0) ? ec.GetInstanceData(copy) : null;
                    foreach (SymbolId name in names)
                    {
                        object value;
                        if (!ec.TryGetInstanceVariable(obj, name, out value))
                        {
                            value = null;
                        }
                        else
                        {
                            value = DeepCopy(context, value);
                        }
                        newVars.SetInstanceVariable(name, value);
                    }

                    if (classObject == null)
                    {
                        // do any special copying needed for library types
                        // TODO: we still need to implement copy semantics for .NET types in general
                        IDuplicable duplicable = copy as IDuplicable;
                        if (duplicable != null)
                        {
                            duplicable.InitializeFrom(obj);
                        }
                    }
                    return(copy);
                }
            }
        }
Ejemplo n.º 2
0
            private void WriteAnObject(object obj)
            {
                if (_recursionLimit == 0)
                {
                    throw RubyExceptions.CreateArgumentError("exceed depth limit");
                }
                if (_recursionLimit > 0)
                {
                    _recursionLimit--;
                }

                if (obj is int)
                {
                    int value = (int)obj;
                    if (value < -(1 << 30) || value >= (1 << 30))
                    {
                        obj = (BigInteger)value;
                    }
                }

                // TODO: use RubyUtils.IsRubyValueType?
                RubySymbol sym;

                if (obj == null)
                {
                    _writer.Write((byte)'0');
                }
                else if (obj is bool)
                {
                    _writer.Write((byte)((bool)obj ? 'T' : 'F'));
                }
                else if (obj is int)
                {
                    WriteFixnum((int)obj);
                }
                else if ((sym = obj as RubySymbol) != null)
                {
                    // TODO (encoding):
                    WriteSymbol(sym.ToString(), sym.Encoding);
                }
                else
                {
                    int objectRef;
                    if (_objects.TryGetValue(obj, out objectRef))
                    {
                        _writer.Write((byte)'@');
                        WriteInt32(objectRef);
                    }
                    else
                    {
                        objectRef     = _objects.Count;
                        _objects[obj] = objectRef;

                        // TODO: replace with a table-driven implementation
                        // TODO: visibility?
                        bool implementsDump        = _context.ResolveMethod(obj, "_dump", VisibilityContext.AllVisible).Found;
                        bool implementsMarshalDump = _context.ResolveMethod(obj, "marshal_dump", VisibilityContext.AllVisible).Found;

                        bool     writeInstanceData = false;
                        string[] instanceNames     = null;

                        if (!implementsDump && !implementsMarshalDump)
                        {
                            // Neither "_dump" nor "marshal_dump" writes instance vars separately
                            instanceNames = _context.GetInstanceVariableNames(obj);
                            if (instanceNames.Length > 0)
                            {
                                _writer.Write((byte)'I');
                                writeInstanceData = true;
                            }
                        }

                        if (!implementsDump || implementsMarshalDump)
                        {
                            // "_dump" doesn't write "extend" info but "marshal_dump" does
                            RubyClass theClass = _context.GetImmediateClassOf(obj);
                            if (theClass.IsSingletonClass)
                            {
                                foreach (var mixin in theClass.GetMixins())
                                {
                                    _writer.Write((byte)'e');
                                    WriteModuleName(mixin);
                                }
                            }
                        }

                        if (obj is double)
                        {
                            WriteFloat((double)obj);
                        }
                        else if (obj is float)
                        {
                            WriteFloat((double)(float)obj);
                        }
                        else if (obj is BigInteger)
                        {
                            WriteBignum((BigInteger)obj);
                        }
                        else if (implementsMarshalDump)
                        {
                            WriteUsingMarshalDump(obj);
                        }
                        else if (implementsDump)
                        {
                            WriteUsingDump(obj);
                        }
                        else if (obj is MutableString)
                        {
                            WriteString((MutableString)obj);
                        }
                        else if (obj is RubyArray)
                        {
                            WriteArray((RubyArray)obj);
                        }
                        else if (obj is Hash)
                        {
                            WriteHash((Hash)obj);
                        }
                        else if (obj is RubyRegex)
                        {
                            WriteRegex((RubyRegex)obj);
                        }
                        else if (obj is RubyClass)
                        {
                            WriteClass((RubyClass)obj);
                        }
                        else if (obj is RubyModule)
                        {
                            WriteModule((RubyModule)obj);
                        }
                        else if (obj is RubyStruct)
                        {
                            WriteStruct((RubyStruct)obj);
                        }
                        else if (obj is Range)
                        {
                            WriteRange((Range)obj);
                        }
                        else
                        {
                            if (writeInstanceData)
                            {
                                // Overwrite the "I"; we always have instance data
                                _writer.BaseStream.Seek(-1, SeekOrigin.Current);
                            }
                            else
                            {
                                writeInstanceData = true;
                            }
                            WriteObject(obj);
                        }

                        if (writeInstanceData)
                        {
                            WriteInt32(instanceNames.Length);
                            var encoding = _context.GetIdentifierEncoding();
                            foreach (string name in instanceNames)
                            {
                                object value;
                                if (!_context.TryGetInstanceVariable(obj, name, out value))
                                {
                                    value = null;
                                }
                                // TODO (encoding):
                                WriteSymbol(name, encoding);
                                WriteAnObject(value);
                            }
                        }
                    }
                }
                if (_recursionLimit >= 0)
                {
                    _recursionLimit++;
                }
            }
Ejemplo n.º 3
0
        public static RubyArray/*!*/ InstanceVariables(RubyContext/*!*/ context, object self) {
            string[] names = context.GetInstanceVariableNames(self);

            RubyArray result = new RubyArray(names.Length);
            foreach (string name in names) {
                result.Add(MutableString.Create(name));
            }
            return result;
        }
Ejemplo n.º 4
0
 public static RubyArray /*!*/ ToYamlProperties(RubyContext /*!*/ context, object self)
 {
     string[] names = context.GetInstanceVariableNames(self);
     Array.Sort(names);
     return(context.StringifyIdentifiers(names));
 }
Ejemplo n.º 5
0
 public static RubyArray/*!*/ GetInstanceVariableNames(RubyContext/*!*/ context, object self) {
     return context.StringifyIdentifiers(context.GetInstanceVariableNames(self));
 }
Ejemplo n.º 6
0
 public static RubyArray ToYamlProperties(RubyContext/*!*/ context, object self)
 {
     string[] names = context.GetInstanceVariableNames(self);
     Array.Sort(names);
     return context.StringifyIdentifiers(names);
 }