Esempio n. 1
0
        public static MetaObject TryBind(RubyContext /*!*/ context, GetMemberBinder /*!*/ binder, MetaObject /*!*/ target)
        {
            Assert.NotNull(context, target);
            var metaBuilder       = new MetaObjectBuilder();
            var contextExpression = Ast.Constant(context);

            metaBuilder.AddTargetTypeTest(target.Value, target.Expression, context, contextExpression);

            RubyMemberInfo method = context.ResolveMethod(target.Value, binder.Name, true).InvalidateSitesOnOverride();

            if (method != null && RubyModule.IsMethodVisible(method, false))
            {
                // we need to create a bound member:
                metaBuilder.Result = Ast.Constant(new RubyMethod(target.Value, method, binder.Name));
            }
            else
            {
                // TODO:
                // We need to throw an exception if we don't find method_missing so that our version update optimization works:
                // This limits interop with other languages.
                //
                // class B           CLR type with method 'foo'
                // class C < B       Ruby class
                // x = C.new
                //
                // 1. x.GET("foo") from Ruby
                //    No method found or CLR method found -> fallback to Python
                //    Python might see its method foo or might just fallback to .NET,
                //    in any case it will add rule [1] with restriction on type of C w/o Ruby version check.
                // 2. B.define_method("foo")
                //    This doesn't update C due to the optimization (there is no overridden method foo in C).
                // 3. x.GET("foo") from Ruby
                //    This will not invoke the binder since the rule [1] is still valid.
                //
                object symbol = SymbolTable.StringToId(binder.Name);
                RubyCallAction.BindToMethodMissing(metaBuilder, binder.Name,
                                                   new CallArguments(
                                                       new MetaObject(contextExpression, Restrictions.Empty, context),
                                                       new[] {
                    target,
                    new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol)
                },
                                                       RubyCallSignature.Simple(1)
                                                       ),
                                                   method != null
                                                   );
            }

            // TODO: we should return null if we fail, we need to throw exception for now:
            return(metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects));
        }
Esempio n. 2
0
        protected override Node CreateNode(object data)
        {
            RubyMemberInfo method = _context.ResolveMethod(data, "to_yaml", false).InvalidateSitesOnOverride();

            if (method == _objectToYamlMethod)
            {
                return(_ToYamlNode.Target(_ToYamlNode, _context, data, this));
            }
            else
            {
                // TODO: this doesn't seem right
                // (we're passing the extra argument, but the callee might not take it?)
                return(_ToYaml.Target(_ToYaml, _context, data, this));
            }
        }
Esempio n. 3
0
        public static MetaObject TryBind(RubyContext/*!*/ context, GetMemberBinder/*!*/ binder, MetaObject/*!*/ target) {
            Assert.NotNull(context, target);
            var metaBuilder = new MetaObjectBuilder();
            var contextExpression = Ast.Constant(context);

            metaBuilder.AddTargetTypeTest(target.Value, target.Expression, context, contextExpression);

            RubyMemberInfo method = context.ResolveMethod(target.Value, binder.Name, true).InvalidateSitesOnOverride();
            if (method != null && RubyModule.IsMethodVisible(method, false)) {
                // we need to create a bound member:
                metaBuilder.Result = Ast.Constant(new RubyMethod(target.Value, method, binder.Name));
            } else {
                // TODO:
                // We need to throw an exception if we don't find method_missing so that our version update optimization works: 
                // This limits interop with other languages. 
                //                   
                // class B           CLR type with method 'foo'
                // class C < B       Ruby class
                // x = C.new
                //
                // 1. x.GET("foo") from Ruby
                //    No method found or CLR method found -> fallback to Python
                //    Python might see its method foo or might just fallback to .NET, 
                //    in any case it will add rule [1] with restriction on type of C w/o Ruby version check.
                // 2. B.define_method("foo") 
                //    This doesn't update C due to the optimization (there is no overridden method foo in C).
                // 3. x.GET("foo") from Ruby
                //    This will not invoke the binder since the rule [1] is still valid.
                //
                object symbol = SymbolTable.StringToId(binder.Name);
                RubyCallAction.BindToMethodMissing(metaBuilder, binder.Name,
                    new CallArguments(
                        new MetaObject(contextExpression, Restrictions.Empty, context),
                        new[] { 
                            target,
                            new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol) 
                        },
                        RubyCallSignature.Simple(1)
                    ), 
                    method != null
                );
            }

            // TODO: we should return null if we fail, we need to throw exception for now:
            return metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects);
        }
Esempio n. 4
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++;
                }
            }
Esempio n. 5
0
 public static RubyMethod/*!*/ GetMethod(RubyContext/*!*/ context, object self, [DefaultProtocol, NotNull]string/*!*/ name) {
     RubyMemberInfo info = context.ResolveMethod(self, name, VisibilityContext.AllVisible).Info;
     if (info == null) {
         throw RubyExceptions.CreateUndefinedMethodError(context.GetClassOf(self), name);
     }
     return new RubyMethod(self, info, name);
 }
Esempio n. 6
0
        public static bool RespondTo(RubyContext/*!*/ context, object self, 
            [DefaultProtocol, NotNull]string/*!*/ methodName, [Optional]bool includePrivate) {

            return context.ResolveMethod(self, methodName, includePrivate).Found;
        }
Esempio n. 7
0
        public static bool RespondTo(RubyContext/*!*/ context, object self, 
            [DefaultProtocol, NotNull]string/*!*/ methodName, [DefaultParameterValue(null)]object includePrivate) {

            return context.ResolveMethod(self, methodName, Protocols.IsTrue(includePrivate)).Found;
        }