PageRenderTime 81ms CodeModel.GetById 29ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 1ms

/IronPython_Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs

#
C# | 2570 lines | 1954 code | 449 blank | 167 comment | 303 complexity | 59b560ffd38a41d8fd908eeb89bd675a MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* ****************************************************************************
   2 *
   3 * Copyright (c) Microsoft Corporation. 
   4 *
   5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
   6 * copy of the license can be found in the License.html file at the root of this distribution. If 
   7 * you cannot locate the  Apache License, Version 2.0, please send an email to 
   8 * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
   9 * by the terms of the Apache License, Version 2.0.
  10 *
  11 * You must not remove this notice, or any other, from this software.
  12 *
  13 *
  14 * ***************************************************************************/
  15
  16#if !CLR2
  17using MSA = System.Linq.Expressions;
  18#else
  19using MSA = Microsoft.Scripting.Ast;
  20#endif
  21
  22using System;
  23using System.Collections;
  24using System.Collections.Generic;
  25using System.Diagnostics;
  26using System.Dynamic;
  27using System.Globalization;
  28using System.IO;
  29using System.Reflection;
  30using System.Runtime.CompilerServices;
  31using System.Runtime.Serialization;
  32using System.Threading;
  33using IronRuby.Builtins;
  34using IronRuby.Compiler;
  35using IronRuby.Compiler.Generation;
  36using IronRuby.Runtime.Calls;
  37using Microsoft.Scripting;
  38using Microsoft.Scripting.Interpreter;
  39using Microsoft.Scripting.Math;
  40using Microsoft.Scripting.Runtime;
  41using Microsoft.Scripting.Utils;
  42using IronRuby.Compiler.Ast;
  43using IronRuby.Runtime.Conversions;
  44
  45namespace IronRuby.Runtime {
  46    [ReflectionCached, CLSCompliant(false)]
  47    public static partial class RubyOps {
  48        [Emitted]
  49        public static readonly object DefaultArgument = new object();
  50        
  51        // Returned by a virtual site if a base call should be performed.
  52        [Emitted]
  53        public static readonly object ForwardToBase = new object();
  54
  55        // an instance of a dummy type that causes any rule based on instance type check to fail
  56        private sealed class _NeedsUpdate {
  57        }
  58
  59        [Emitted]
  60        public static readonly object NeedsUpdate = new _NeedsUpdate();
  61
  62        #region Scopes
  63
  64        [Emitted]
  65        public static MutableTuple GetLocals(RubyScope/*!*/ scope) {
  66            return scope.Locals;
  67        }
  68
  69        [Emitted]
  70        public static MutableTuple GetParentLocals(RubyScope/*!*/ scope) {
  71            return scope.Parent.Locals;
  72        }
  73
  74        [Emitted]
  75        public static RubyScope/*!*/ GetParentScope(RubyScope/*!*/ scope) {
  76            return scope.Parent;
  77        }
  78
  79        [Emitted]
  80        public static Proc GetMethodBlockParameter(RubyScope/*!*/ scope) {
  81            var methodScope = scope.GetInnerMostMethodScope();
  82            return methodScope != null ? methodScope.BlockParameter : null;
  83        }
  84
  85        [Emitted]
  86        public static object GetMethodBlockParameterSelf(RubyScope/*!*/ scope) {
  87            Proc proc = scope.GetInnerMostMethodScope().BlockParameter;
  88            Debug.Assert(proc != null, "CreateBfcForYield is called before this method and it checks non-nullity");
  89            return proc.Self;
  90        }
  91
  92        [Emitted]
  93        public static object GetProcSelf(Proc/*!*/ proc) {
  94            return proc.Self;
  95        }
  96
  97        [Emitted]
  98        public static int GetProcArity(Proc/*!*/ proc) {
  99            return proc.Dispatcher.Arity;
 100        }
 101
 102        [Emitted]
 103        public static void InitializeScope(RubyScope/*!*/ scope, MutableTuple locals, string[] variableNames, 
 104            InterpretedFrame interpretedFrame) {
 105
 106            if (!scope.LocalsInitialized) {
 107                scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
 108            }
 109            scope.InterpretedFrame = interpretedFrame;
 110        }
 111        
 112        [Emitted]
 113        public static void InitializeScopeNoLocals(RubyScope/*!*/ scope, InterpretedFrame interpretedFrame) {
 114            scope.InterpretedFrame = interpretedFrame;
 115        }
 116
 117        [Emitted]
 118        public static void SetDataConstant(RubyScope/*!*/ scope, string/*!*/ dataPath, int dataOffset) {
 119            Debug.Assert(dataOffset >= 0);
 120            RubyFile dataFile;
 121            RubyContext context = scope.RubyContext;
 122            if (context.DomainManager.Platform.FileExists(dataPath)) {
 123                dataFile = new RubyFile(context, dataPath, IOMode.ReadOnly);
 124                dataFile.Seek(dataOffset, SeekOrigin.Begin);
 125            } else {
 126                dataFile = null;
 127            }
 128
 129            context.ObjectClass.SetConstant("DATA", dataFile);
 130        }
 131
 132        [Emitted]
 133        public static RubyModuleScope/*!*/ CreateModuleScope(MutableTuple locals, string[] variableNames, 
 134            RubyScope/*!*/ parent, RubyModule/*!*/ module) {
 135
 136            if (parent.RubyContext != module.Context) {
 137                throw RubyExceptions.CreateTypeError("Cannot open a module `{0}' defined in a foreign runtime #{1}", module.Name, module.Context.RuntimeId);
 138            }
 139
 140            RubyModuleScope scope = new RubyModuleScope(parent, module);
 141            scope.SetDebugName((module.IsClass ? "class" : "module") + " " + module.Name);
 142            scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
 143            return scope;
 144        }
 145
 146        [Emitted]
 147        public static RubyMethodScope/*!*/ CreateMethodScope(MutableTuple locals, string[] variableNames, int visibleParameterCount,
 148            RubyScope/*!*/ parentScope, RubyModule/*!*/ declaringModule, string/*!*/ definitionName, 
 149            object selfObject, Proc blockParameter, InterpretedFrame interpretedFrame) {
 150
 151            return new RubyMethodScope(
 152                locals, variableNames ?? ArrayUtils.EmptyStrings, visibleParameterCount,
 153                parentScope, declaringModule, definitionName, selfObject, blockParameter,
 154                interpretedFrame
 155            );            
 156        }
 157
 158        [Emitted]
 159        public static RubyScope/*!*/ CreateFileInitializerScope(MutableTuple locals, string[] variableNames, RubyScope/*!*/ parent) {
 160            return new RubyFileInitializerScope(locals, variableNames ?? ArrayUtils.EmptyStrings, parent);
 161        }
 162
 163        [Emitted]
 164        public static RubyBlockScope/*!*/ CreateBlockScope(MutableTuple locals, string[] variableNames, 
 165            BlockParam/*!*/ blockParam, object selfObject, InterpretedFrame interpretedFrame) {
 166
 167            return new RubyBlockScope(locals, variableNames ?? ArrayUtils.EmptyStrings, blockParam, selfObject, interpretedFrame);
 168        }
 169
 170        [Emitted]
 171        public static void TraceMethodCall(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
 172            // MRI: 
 173            // Reports DeclaringModule even though an aliased method in a sub-module is called.
 174            // Also works for singleton module-function, which shares DeclaringModule with instance module-function.
 175            RubyModule module = scope.DeclaringModule;
 176            scope.RubyContext.ReportTraceEvent("call", scope, module, scope.DefinitionName, fileName, lineNumber);
 177        }
 178
 179        [Emitted]
 180        public static void TraceMethodReturn(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
 181            RubyModule module = scope.DeclaringModule;
 182            scope.RubyContext.ReportTraceEvent("return", scope, module, scope.DefinitionName, fileName, lineNumber);
 183        }
 184
 185        [Emitted]
 186        public static void TraceBlockCall(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
 187            var method = block.Proc.Method;
 188            if (method != null) {
 189                scope.RubyContext.ReportTraceEvent("call", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
 190            }
 191        }
 192
 193        [Emitted]
 194        public static void TraceBlockReturn(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
 195            var method = block.Proc.Method;
 196            if (method != null) {
 197                scope.RubyContext.ReportTraceEvent("return", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
 198            }
 199        }
 200
 201        [Emitted]
 202        public static void PrintInteractiveResult(RubyScope/*!*/ scope, MutableString/*!*/ value) {
 203            var writer = scope.RubyContext.DomainManager.SharedIO.OutputStream;
 204            writer.WriteByte((byte)'=');
 205            writer.WriteByte((byte)'>');
 206            writer.WriteByte((byte)' ');
 207            var bytes = value.ToByteArray();
 208            writer.Write(bytes, 0, bytes.Length);
 209            writer.WriteByte((byte)'\r');
 210            writer.WriteByte((byte)'\n');
 211        }
 212
 213        [Emitted]
 214        public static object GetLocalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
 215            return scope.ResolveLocalVariable(name);
 216        }
 217
 218        [Emitted]
 219        public static object SetLocalVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
 220            return scope.ResolveAndSetLocalVariable(name, value);
 221        }
 222
 223        [Emitted]
 224        public static VersionHandle/*!*/ GetSelfClassVersionHandle(RubyScope/*!*/ scope) {
 225            return scope.SelfImmediateClass.Version;
 226        }
 227
 228        #endregion
 229
 230        #region Context
 231
 232        [Emitted]
 233        public static RubyContext/*!*/ GetContextFromModule(RubyModule/*!*/ module) {
 234            return module.Context;
 235        }
 236        
 237        [Emitted]
 238        public static RubyContext/*!*/ GetContextFromIRubyObject(IRubyObject/*!*/ obj) {
 239            return obj.ImmediateClass.Context;
 240        }
 241        
 242        [Emitted]
 243        public static RubyContext/*!*/ GetContextFromScope(RubyScope/*!*/ scope) {
 244            return scope.RubyContext;
 245        }
 246
 247        [Emitted]
 248        public static RubyContext/*!*/ GetContextFromMethod(RubyMethod/*!*/ method) {
 249            return method.Info.Context;
 250        }
 251
 252        [Emitted]
 253        public static RubyContext/*!*/ GetContextFromBlockParam(BlockParam/*!*/ block) {
 254            return block.RubyContext;
 255        }
 256
 257        [Emitted]
 258        public static RubyContext/*!*/ GetContextFromProc(Proc/*!*/ proc) {
 259            return proc.LocalScope.RubyContext;
 260        }
 261
 262        [Emitted]
 263        public static RubyScope/*!*/ GetEmptyScope(RubyContext/*!*/ context) {
 264            return context.EmptyScope;
 265        }
 266
 267        [Emitted]
 268        public static Scope/*!*/ GetGlobalScopeFromScope(RubyScope/*!*/ scope) {
 269            return scope.GlobalScope.Scope;
 270        }
 271
 272        #endregion
 273
 274        #region Blocks
 275
 276        [Emitted]
 277        public static Proc InstantiateBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
 278            return (dispatcher.Method != null) ? new Proc(ProcKind.Block, self, scope, dispatcher) : null;
 279        }
 280        [Emitted]
 281        public static Proc InstantiateLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
 282            return (dispatcher.Method != null) ? new Proc(ProcKind.Lambda, self, scope, dispatcher) : null;
 283        }
 284
 285        [Emitted]
 286        public static Proc/*!*/ DefineBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
 287            // DLR closures should not be used:
 288            Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
 289            return new Proc(ProcKind.Block, self, scope, dispatcher.SetMethod(clrMethod));
 290        }
 291
 292        [Emitted]
 293        public static Proc/*!*/ DefineLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
 294            // DLR closures should not be used:
 295            Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
 296            return new Proc(ProcKind.Lambda, self, scope, dispatcher.SetMethod(clrMethod));
 297        }
 298
 299        /// <summary>
 300        /// Used in a method call with a block to reset proc-kind when the call is retried
 301        /// </summary>
 302        [Emitted]
 303        public static void InitializeBlock(Proc/*!*/ proc) {
 304            Assert.NotNull(proc);
 305            proc.Kind = ProcKind.Block;
 306        }
 307
 308        /// <summary>
 309        /// Implements END block - like if it was a call to at_exit { ... } library method.
 310        /// </summary>
 311        [Emitted]
 312        public static void RegisterShutdownHandler(Proc/*!*/ proc) {
 313            proc.LocalScope.RubyContext.RegisterShutdownHandler(proc);
 314        }
 315
 316        #endregion
 317
 318        #region Yield: TODO: generate
 319
 320        [Emitted] 
 321        public static object Yield0(Proc procArg, object self, BlockParam/*!*/ blockParam) {
 322            object result;
 323            var proc = blockParam.Proc;
 324            try {
 325                result = proc.Dispatcher.Invoke(blockParam, self, procArg);
 326            } catch(EvalUnwinder evalUnwinder) {
 327                result = blockParam.GetUnwinderResult(evalUnwinder);
 328            }
 329
 330            return result;
 331        }
 332
 333        [Emitted]
 334        public static object Yield1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 335            object result;
 336            var proc = blockParam.Proc;
 337            try {
 338                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1);
 339            } catch (EvalUnwinder evalUnwinder) {
 340                result = blockParam.GetUnwinderResult(evalUnwinder);
 341            }
 342
 343            return result;
 344        }
 345
 346        // YieldNoAutoSplat1 uses InvokeNoAutoSplat instead of Invoke (used by Call1)
 347        internal static object YieldNoAutoSplat1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 348            object result;
 349            var proc = blockParam.Proc;
 350            try {
 351                result = proc.Dispatcher.InvokeNoAutoSplat(blockParam, self, procArg, arg1);
 352            } catch (EvalUnwinder evalUnwinder) {
 353                result = blockParam.GetUnwinderResult(evalUnwinder);
 354            }
 355
 356            return result;
 357        }
 358
 359        [Emitted]
 360        public static object Yield2(object arg1, object arg2, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 361            object result;
 362            var proc = blockParam.Proc;
 363            try {
 364                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2);
 365            } catch (EvalUnwinder evalUnwinder) {
 366                result = blockParam.GetUnwinderResult(evalUnwinder);
 367            }
 368
 369            return result;
 370        }
 371
 372        [Emitted]
 373        public static object Yield3(object arg1, object arg2, object arg3, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 374            object result;
 375            var proc = blockParam.Proc;
 376            try {
 377                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3);
 378            } catch (EvalUnwinder evalUnwinder) {
 379                result = blockParam.GetUnwinderResult(evalUnwinder);
 380            }
 381
 382            return result;
 383        }
 384
 385        [Emitted]
 386        public static object Yield4(object arg1, object arg2, object arg3, object arg4, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 387            object result;
 388            var proc = blockParam.Proc;
 389            try {
 390                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3, arg4);
 391            } catch (EvalUnwinder evalUnwinder) {
 392                result = blockParam.GetUnwinderResult(evalUnwinder);
 393            }
 394
 395            return result;
 396        }
 397
 398        [Emitted]
 399        public static object YieldN(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 400            Debug.Assert(args.Length > BlockDispatcher.MaxBlockArity);
 401
 402            object result;
 403            var proc = blockParam.Proc;
 404            try {
 405                result = proc.Dispatcher.Invoke(blockParam, self, procArg, args);
 406            } catch (EvalUnwinder evalUnwinder) {
 407                result = blockParam.GetUnwinderResult(evalUnwinder);
 408            }
 409
 410            return result;
 411        }
 412
 413        internal static object Yield(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 414            switch (args.Length) {
 415                case 0: return RubyOps.Yield0(procArg, self, blockParam);
 416                case 1: return RubyOps.Yield1(args[0], procArg, self, blockParam);
 417                case 2: return RubyOps.Yield2(args[0], args[1], procArg, self, blockParam);
 418                case 3: return RubyOps.Yield3(args[0], args[1], args[2], procArg, self, blockParam);
 419                case 4: return RubyOps.Yield4(args[0], args[1], args[2], args[3], procArg, self, blockParam);
 420                default: return RubyOps.YieldN(args, procArg, self, blockParam); 
 421            }
 422        }
 423
 424        [Emitted]
 425        public static object YieldSplat0(IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 426            object result;
 427            var proc = blockParam.Proc;
 428            try {
 429                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, splattee);
 430            } catch (EvalUnwinder evalUnwinder) {
 431                result = blockParam.GetUnwinderResult(evalUnwinder);
 432            }
 433
 434            return result;
 435        }
 436
 437        [Emitted]
 438        public static object YieldSplat1(object arg1, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 439            object result;
 440            var proc = blockParam.Proc;
 441            try {
 442                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, splattee);
 443            } catch (EvalUnwinder evalUnwinder) {
 444                result = blockParam.GetUnwinderResult(evalUnwinder);
 445            }
 446
 447            return result;
 448        }
 449
 450        [Emitted]
 451        public static object YieldSplat2(object arg1, object arg2, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 452            object result;
 453            var proc = blockParam.Proc;
 454            try {
 455                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, splattee);
 456            } catch (EvalUnwinder evalUnwinder) {
 457                result = blockParam.GetUnwinderResult(evalUnwinder);
 458            }
 459
 460            return result;
 461        }
 462
 463        [Emitted]
 464        public static object YieldSplat3(object arg1, object arg2, object arg3, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 465            object result;
 466            var proc = blockParam.Proc;
 467            try {
 468                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, splattee);
 469            } catch (EvalUnwinder evalUnwinder) {
 470                result = blockParam.GetUnwinderResult(evalUnwinder);
 471            }
 472
 473            return result;
 474        }
 475
 476        [Emitted]
 477        public static object YieldSplat4(object arg1, object arg2, object arg3, object arg4, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 478            object result;
 479            var proc = blockParam.Proc;
 480            try {
 481                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, arg4, splattee);
 482            } catch (EvalUnwinder evalUnwinder) {
 483                result = blockParam.GetUnwinderResult(evalUnwinder);
 484            }
 485
 486            return result;
 487        }
 488
 489        [Emitted]
 490        public static object YieldSplatN(object[]/*!*/ args, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 491            object result;
 492            var proc = blockParam.Proc;
 493            try {
 494                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, args, splattee);
 495            } catch (EvalUnwinder evalUnwinder) {
 496                result = blockParam.GetUnwinderResult(evalUnwinder);
 497            }
 498
 499            return result;
 500        }
 501
 502        [Emitted]
 503        public static object YieldSplatNRhs(object[]/*!*/ args, IList/*!*/ splattee, object rhs, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 504            object result;
 505            var proc = blockParam.Proc;
 506            try {
 507                result = proc.Dispatcher.InvokeSplatRhs(blockParam, self, procArg, args, splattee, rhs);
 508            } catch (EvalUnwinder evalUnwinder) {
 509                result = blockParam.GetUnwinderResult(evalUnwinder);
 510            }
 511
 512            return result;
 513        }
 514
 515        #endregion
 516
 517        #region Methods
 518
 519        [Emitted] // MethodDeclaration:
 520        public static object DefineMethod(object target, RubyScope/*!*/ scope, RubyMethodBody/*!*/ body) {
 521            Assert.NotNull(body, scope);
 522
 523            RubyModule instanceOwner, singletonOwner;
 524            RubyMemberFlags instanceFlags, singletonFlags;
 525            bool moduleFunction = false;
 526
 527            if (body.HasTarget) {
 528                if (!RubyUtils.CanDefineSingletonMethod(target)) {
 529                    throw RubyExceptions.CreateTypeError("can't define singleton method for literals");
 530                }
 531
 532                instanceOwner = null;
 533                instanceFlags = RubyMemberFlags.Invalid;
 534                singletonOwner = scope.RubyContext.GetOrCreateSingletonClass(target);
 535                singletonFlags = RubyMemberFlags.Public;
 536            } else {
 537                var attributesScope = scope.GetMethodAttributesDefinitionScope();
 538                if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) {
 539                    // Singleton module-function's scope points to the instance method's RubyMemberInfo.
 540                    // This affects:
 541                    // 1) super call
 542                    //    Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function
 543                    //    was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton.
 544                    //    Module's singleton is never part of MRO so we are safe.
 545                    // 2) trace
 546                    //    Method call trace reports non-singleton module.
 547
 548                    // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug)
 549                    // MRI 1.9: instance method owner GetMethodDefinitionOwner
 550                    // MRI allows to define m.f. on classes but then doesn't work correctly with it.
 551                    instanceOwner = scope.GetMethodDefinitionOwner();
 552                    if (instanceOwner.IsClass) {
 553                        throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class.");
 554                    }
 555
 556                    instanceFlags = RubyMemberFlags.Private;
 557                    singletonOwner = instanceOwner.GetOrCreateSingletonClass();
 558                    singletonFlags = RubyMemberFlags.Public;
 559                    moduleFunction = true;
 560                } else {
 561                    instanceOwner = scope.GetMethodDefinitionOwner();
 562                    instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, body.Name);
 563                    singletonOwner = null;
 564                    singletonFlags = RubyMemberFlags.Invalid;
 565                }
 566            }
 567            
 568            RubyMethodInfo instanceMethod = null, singletonMethod = null;
 569
 570            if (instanceOwner != null) {
 571                SetMethod(scope.RubyContext, instanceMethod =
 572                    new RubyMethodInfo(body, scope, instanceOwner, instanceFlags)
 573                );
 574            }
 575
 576            if (singletonOwner != null) {
 577                SetMethod(scope.RubyContext, singletonMethod =
 578                    new RubyMethodInfo(body, scope, singletonOwner, singletonFlags)
 579                );
 580            }
 581
 582            // the method's scope saves the result => singleton module-function uses instance-method
 583            var method = instanceMethod ?? singletonMethod;
 584
 585            method.DeclaringModule.MethodAdded(body.Name);
 586
 587            if (moduleFunction) {
 588                Debug.Assert(!method.DeclaringModule.IsClass);
 589                method.DeclaringModule.GetOrCreateSingletonClass().MethodAdded(body.Name);
 590            }
 591
 592            return null;
 593        }
 594
 595        private static void SetMethod(RubyContext/*!*/ callerContext, RubyMethodInfo/*!*/ method) {
 596            var owner = method.DeclaringModule;
 597
 598            // Do not trigger the add-method event just yet, we need to assign the result into closure before executing any user code.
 599            // If the method being defined is "method_added" itself, we would call that method before the info gets assigned to the closure.
 600            owner.SetMethodNoEvent(callerContext, method.DefinitionName, method);
 601
 602            // expose RubyMethod in the scope (the method is bound to the main singleton instance):
 603            if (owner.GlobalScope != null) {
 604                RubyOps.ScopeSetMember(
 605                    owner.GlobalScope.Scope,
 606                    method.DefinitionName,
 607                    new RubyMethod(owner.GlobalScope.MainObject, method, method.DefinitionName)
 608                );
 609            }
 610        }
 611
 612        [Emitted] // AliasStatement:
 613        public static void AliasMethod(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) {
 614            scope.GetMethodDefinitionOwner().AddMethodAlias(newName, oldName);
 615        }
 616
 617        [Emitted] // UndefineMethod:
 618        public static void UndefineMethod(RubyScope/*!*/ scope, string/*!*/ name) {
 619            RubyModule owner = scope.GetMethodDefinitionOwner();
 620
 621            if (!owner.ResolveMethod(name, VisibilityContext.AllVisible).Found) {
 622                throw RubyExceptions.CreateUndefinedMethodError(owner, name);
 623            }
 624            owner.UndefineMethod(name);
 625        }
 626
 627        #endregion
 628
 629        #region Modules
 630
 631        [Emitted]
 632        public static RubyModule/*!*/ DefineGlobalModule(RubyScope/*!*/ scope, string/*!*/ name) {
 633            return DefineModule(scope, scope.Top.TopModuleOrObject, name);
 634        }
 635
 636        [Emitted]
 637        public static RubyModule/*!*/ DefineNestedModule(RubyScope/*!*/ scope, string/*!*/ name) {
 638            return DefineModule(scope, scope.GetInnerMostModuleForConstantLookup(), name);
 639        }
 640
 641        [Emitted]
 642        public static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, object target, string/*!*/ name) {
 643            return DefineModule(scope, RubyUtils.GetModuleFromObject(scope, target), name);
 644        }
 645
 646        // thread-safe:
 647        private static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name) {
 648            Assert.NotNull(scope, owner);
 649
 650            ConstantStorage existing;
 651            if (owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
 652                RubyModule module = existing.Value as RubyModule;
 653                if (module == null || module.IsClass) {
 654                    throw RubyExceptions.CreateTypeError(String.Format("{0} is not a module", name));
 655                }
 656                return module;
 657            } else {
 658                // create class/module object:
 659                return owner.Context.DefineModule(owner, name);
 660            }
 661        }
 662
 663        #endregion
 664
 665        #region Classes
 666
 667        [Emitted]
 668        public static RubyClass/*!*/ DefineSingletonClass(RubyScope/*!*/ scope, object obj) {
 669            if (!RubyUtils.HasSingletonClass(obj)) {
 670                throw RubyExceptions.CreateTypeError(String.Format("no virtual class for {0}", scope.RubyContext.GetClassOf(obj).Name));
 671            }
 672            return scope.RubyContext.GetOrCreateSingletonClass(obj);
 673        }
 674
 675        [Emitted] 
 676        public static RubyModule/*!*/ DefineGlobalClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
 677            return DefineClass(scope, scope.Top.TopModuleOrObject, name, superClassObject);
 678        }
 679
 680        [Emitted]
 681        public static RubyModule/*!*/ DefineNestedClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
 682            return DefineClass(scope, scope.GetInnerMostModuleForConstantLookup(), name, superClassObject);
 683        }
 684
 685        [Emitted]
 686        public static RubyModule/*!*/ DefineClass(RubyScope/*!*/ scope, object target, string/*!*/ name, object superClassObject) {
 687            return DefineClass(scope, RubyUtils.GetModuleFromObject(scope, target), name, superClassObject);
 688        }
 689
 690        // thread-safe:
 691        private static RubyClass/*!*/ DefineClass(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name, object superClassObject) {
 692            Assert.NotNull(owner);
 693            RubyClass superClass = ToSuperClass(owner.Context, superClassObject);
 694
 695            ConstantStorage existing;
 696            if (owner.IsObjectClass
 697                ? owner.TryResolveConstant(scope.GlobalScope, name, out existing)
 698                : owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
 699
 700                RubyClass cls = existing.Value as RubyClass;
 701                if (cls == null || !cls.IsClass) {
 702                    throw RubyExceptions.CreateTypeError("{0} is not a class", name);
 703                }
 704
 705                if (superClassObject != null && !ReferenceEquals(cls.SuperClass, superClass)) {
 706                    throw RubyExceptions.CreateTypeError("superclass mismatch for class {0}", name);
 707                }
 708                return cls;
 709            } else {
 710                return owner.Context.DefineClass(owner, name, superClass, null);
 711            }
 712        }
 713
 714        private static RubyClass/*!*/ ToSuperClass(RubyContext/*!*/ ec, object superClassObject) {
 715            if (superClassObject != null) {
 716                RubyClass superClass = superClassObject as RubyClass;
 717                if (superClass == null) {
 718                    throw RubyExceptions.CreateTypeError("superclass must be a Class ({0} given)", ec.GetClassOf(superClassObject).Name);
 719                }
 720
 721                if (superClass.IsSingletonClass) {
 722                    throw RubyExceptions.CreateTypeError("can't make subclass of virtual class");
 723                }
 724
 725                return superClass;
 726            } else {
 727                return ec.ObjectClass;
 728            }
 729        }
 730
 731        #endregion
 732
 733        #region Constants
 734
 735        /// <summary>
 736        /// A
 737        /// ::A
 738        /// </summary>
 739        [Emitted]
 740        public static object GetUnqualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name, bool isGlobal) {
 741            object result = null;
 742            RubyModule missingConstantOwner;
 743            var context = scope.RubyContext;
 744            using (context.ClassHierarchyLocker()) {
 745                // Thread safety:
 746                // Another thread could have already updated the value, so the site version might be the same as CAV.
 747                // We do the lookup anyways since it is no-op and this only happens rarely.
 748                //
 749                // An important invariant holds here: in any time after initialized for the first time the Value field contains a valid value.
 750                // Threads can read an older value (the previous version) but that is still correct since we don't guarantee immediate
 751                // propagation of the constant write to all readers.
 752                // 
 753                // if (site.Version = CAV) {
 754                //   <- another thread could increment CAV here - we may return old or new value (both are ok)
 755                //   value = site.Value;
 756                // } else {
 757                //   <- another thread could get here as well and update the site before we get to update it.
 758                //   GetConstant(...)
 759                // }
 760
 761                // Constants might be updated during constant resolution due to autoload. 
 762                // Any such updates need to invalidate the cache hence we need to capture the version before resolving the constant.
 763                int newVersion = context.ConstantAccessVersion;
 764
 765                ConstantStorage storage;
 766                if (!isGlobal) {
 767                    missingConstantOwner = scope.TryResolveConstantNoLock(scope.GlobalScope, name, out storage);
 768                } else if (context.ObjectClass.TryResolveConstantNoLock(scope.GlobalScope, name, out storage)) {
 769                    missingConstantOwner = null;
 770                } else {
 771                    missingConstantOwner = context.ObjectClass;
 772                }
 773
 774                object newCacheValue;
 775                if (missingConstantOwner == null) {
 776                    if (storage.WeakValue != null) {
 777                        result = storage.Value;
 778                        newCacheValue = storage.WeakValue;
 779                    } else {
 780                        result = newCacheValue = storage.Value;
 781                    }
 782                } else {
 783                    newCacheValue = ConstantSiteCache.WeakMissingConstant;
 784                }
 785
 786                cache.Update(newCacheValue, newVersion);
 787            }
 788
 789            if (missingConstantOwner != null) {
 790                result = missingConstantOwner.ConstantMissing(name);
 791            }
 792
 793            return result;
 794        }
 795
 796        /// <summary>
 797        /// A1::..::AN
 798        /// ::A1::..::AN
 799        /// </summary>
 800        [Emitted]
 801        public static object GetQualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
 802            var globalScope = scope.GlobalScope;
 803            var context = globalScope.Context;
 804
 805            using (context.ClassHierarchyLocker()) {
 806                int newVersion = context.ConstantAccessVersion;
 807                
 808                ConstantStorage storage;
 809                bool anyMissing;
 810                RubyModule topModule = isGlobal ? context.ObjectClass : null;
 811                object result = ResolveQualifiedConstant(scope, qualifiedName, topModule, true, out storage, out anyMissing);
 812
 813                // cache result only if no constant was missing:
 814                if (!anyMissing) {
 815                    Debug.Assert(result == storage.Value);
 816                    cache.Update(storage.WeakValue ?? result, newVersion);
 817                }
 818
 819                return result;
 820            }
 821        }
 822
 823        /// <summary>
 824        /// {expr}::A1::..::AN
 825        /// </summary>
 826        [Emitted]
 827        public static object GetExpressionQualifiedConstant(object target, RubyScope/*!*/ scope, ExpressionQualifiedConstantSiteCache/*!*/ cache,
 828            string/*!*/[]/*!*/ qualifiedName) {
 829            RubyModule module = target as RubyModule;
 830            if (module == null) {
 831                throw RubyUtils.CreateNotModuleException(scope, target);
 832            }
 833
 834            var condition = cache.Condition;
 835            RubyContext context = module.Context;
 836
 837            // Note that the module can be bound to another runtime:
 838            if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
 839                object value = cache.Value;
 840                if (value.GetType() == typeof(WeakReference)) {
 841                    return ((WeakReference)value).Target;
 842                } else {
 843                    return value;
 844                }
 845            }
 846
 847            using (context.ClassHierarchyLocker()) {
 848                int newVersion = context.ConstantAccessVersion;
 849                
 850                ConstantStorage storage;
 851                bool anyMissing;
 852                object result = ResolveQualifiedConstant(scope, qualifiedName, module, true, out storage, out anyMissing);
 853
 854                // cache result only if no constant was missing:
 855                if (!anyMissing) {
 856                    Debug.Assert(result == storage.Value);
 857                    cache.Update(storage.WeakValue ?? result, newVersion, module);
 858                }
 859
 860                return result;
 861            }
 862        }
 863
 864        /// <summary>
 865        /// defined? A
 866        /// </summary>
 867        [Emitted]
 868        public static bool IsDefinedUnqualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
 869            var context = scope.RubyContext;
 870            using (context.ClassHierarchyLocker()) {
 871                int newVersion = context.ConstantAccessVersion;
 872                
 873                ConstantStorage storage;
 874                bool exists = scope.TryResolveConstantNoLock(null, name, out storage) == null;
 875                cache.Update(exists, newVersion);
 876                return exists;
 877            }
 878        }
 879
 880        /// <summary>
 881        /// defined? ::A
 882        /// </summary>
 883        [Emitted]
 884        public static bool IsDefinedGlobalConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
 885            var context = scope.RubyContext;
 886            using (context.ClassHierarchyLocker()) {
 887                int newVersion = context.ConstantAccessVersion;
 888
 889                ConstantStorage storage;
 890                bool exists = context.ObjectClass.TryResolveConstantNoLock(null, name, out storage);
 891                cache.Update(exists, newVersion);
 892                return exists;
 893            }
 894        }
 895
 896        /// <summary>
 897        /// defined? A1::..::AN
 898        /// defined? ::A1::..::AN
 899        /// </summary>
 900        [Emitted]
 901        public static bool IsDefinedQualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache,
 902            string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
 903
 904            var context = scope.RubyContext;
 905            using (context.ClassHierarchyLocker()) {
 906                int newVersion = context.ConstantAccessVersion;
 907
 908                ConstantStorage storage;
 909                bool anyMissing;
 910                RubyModule topModule = isGlobal ? context.ObjectClass : null;
 911                RubyModule owner;
 912                try {
 913                    owner = ResolveQualifiedConstant(scope, qualifiedName, topModule, false, out storage, out anyMissing) as RubyModule;
 914                } catch {
 915                    // autoload can raise an exception
 916                    scope.RubyContext.SetCurrentException(null);
 917                    return false;
 918                }
 919                
 920                // Note that the owner could be another runtime's module:
 921                bool exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
 922                
 923                // cache result only if no constant was missing:
 924                if (!anyMissing) {
 925                    cache.Update(exists, newVersion);
 926                }
 927
 928                return exists;
 929            }
 930        }
 931
 932        /// <summary>
 933        /// defined? {expr}::A
 934        /// defined? {expr}::A1::..::AN
 935        /// </summary>
 936        [Emitted]
 937        public static bool IsDefinedExpressionQualifiedConstant(object target, RubyScope/*!*/ scope,
 938            ExpressionQualifiedIsDefinedConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName) {
 939
 940            RubyModule module = target as RubyModule;
 941            if (module == null) {
 942                return false;
 943            }
 944
 945            var condition = cache.Condition;
 946            RubyContext context = module.Context;
 947
 948            // Note that the module can be bound to another runtime:
 949            if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
 950                return cache.Value;
 951            }
 952
 953            using (context.ClassHierarchyLocker()) {
 954                int newVersion = context.ConstantAccessVersion;
 955
 956                ConstantStorage storage;
 957                bool exists;
 958                if (qualifiedName.Length == 1) {
 959                    // Note that the owner could be another runtime's module:
 960                    exists = module.TryResolveConstant(context, null, qualifiedName[0], out storage);
 961                } else {
 962                    bool anyMissing;
 963                    RubyModule owner;
 964                    try {
 965                        owner = ResolveQualifiedConstant(scope, qualifiedName, module, false, out storage, out anyMissing) as RubyModule;
 966                    } catch {
 967                        // autoload can raise an exception:
 968                        return false;
 969                    }
 970
 971                    // Note that the owner could be another runtime's module:
 972                    exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
 973
 974                    // cache result only if no constant was missing:
 975                    if (anyMissing) {
 976                        return exists;
 977                    } 
 978                }
 979
 980                cache.Update(exists, newVersion, module);
 981                return exists;
 982            }
 983        }
 984
 985        private static object ResolveQualifiedConstant(RubyScope/*!*/ scope, string/*!*/[]/*!*/ qualifiedName, RubyModule topModule, bool isGet,
 986            out ConstantStorage storage, out bool anyMissing) {
 987
 988            Debug.Assert(qualifiedName.Length >= 2 || qualifiedName.Length == 1 && isGet);
 989            RubyContext context = scope.RubyContext;
 990            context.RequiresClassHierarchyLock();
 991
 992            RubyModule missingConstantOwner;
 993            RubyGlobalScope globalScope = scope.GlobalScope;
 994            int nameCount = (isGet) ? qualifiedName.Length : qualifiedName.Length - 1;
 995
 996            string name = qualifiedName[0];
 997            if (topModule == null) {
 998                missingConstantOwner = scope.TryResolveConstantNoLock(globalScope, name, out storage);
 999            } else if (topModule.TryResolveConstant(context, globalScope, name, out storage)) {
1000                missingConstantOwner = null;
1001            } else {
1002                missingConstantOwner = topModule;
1003            }
1004
1005            object result;
1006            if (missingConstantOwner == null) {
1007                result = storage.Value;
1008                anyMissing = false;
1009            } else {
1010                anyMissing = true;
1011                using (context.ClassHierarchyUnlocker()) {
1012                    result = missingConstantOwner.ConstantMissing(name);
1013                }
1014            }
1015
1016            for (int i = 1; i < nameCount; i++) {
1017                RubyModule owner = RubyUtils.GetModuleFromObject(scope, result);
1018                // Note that the owner could be another runtime's module:
1019                name = qualifiedName[i];
1020                if (owner.TryResolveConstant(context, globalScope, name, out storage)) {
1021                    
1022                    // Constant write updates constant version in a single runtime only. 
1023                    // Therefore if the chain mixes modules from different runtimes we cannot cache the result.
1024                    if (owner.Context != context) {
1025                        anyMissing = true;
1026                    }
1027                    
1028                    result = storage.Value;
1029                } else {
1030                    anyMissing = true;
1031                    using (context.ClassHierarchyUnlocker()) {
1032                        result = owner.ConstantMissing(name);
1033                    }
1034                }
1035            }
1036
1037            return result;
1038        }
1039
1040        [Emitted]
1041        public static object GetMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
1042            return scope.GetInnerMostModuleForConstantLookup().ConstantMissing(name);
1043        }
1044
1045        [Emitted]
1046        public static object GetGlobalMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
1047            return scope.RubyContext.ObjectClass.ConstantMissing(name);
1048        }
1049
1050
1051        [Emitted] // ConstantVariable:
1052        public static object SetGlobalConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
1053            RubyUtils.SetConstant(scope.RubyContext.ObjectClass, name, value);
1054            return value;
1055        }
1056
1057        [Emitted] // ConstantVariable:
1058        public static object SetUnqualifiedConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
1059            RubyUtils.SetConstant(scope.GetInnerMostModuleForConstantLookup(), name, value);
1060            return value;
1061        }
1062
1063        [Emitted] // ConstantVariable:
1064        public static object SetQualifiedConstant(object value, object target, RubyScope/*!*/ scope, string/*!*/ name) {
1065            RubyUtils.SetConstant(RubyUtils.GetModuleFromObject(scope, target), name, value);
1066            return value;
1067        }
1068
1069        #endregion
1070
1071        // MakeArray*
1072        public const int OptimizedOpCallParamCount = 5;
1073        
1074        #region MakeArray
1075        
1076        [Emitted]
1077        public static RubyArray/*!*/ MakeArray0() {
1078            return new RubyArray(0);
1079        }
1080
1081        [Emitted]
1082        public static RubyArray/*!*/ MakeArray1(object item1) {
1083            RubyArray result = new RubyArray(1);
1084            result.Add(item1);
1085            return result;
1086        }
1087
1088        [Emitted]
1089        public static RubyArray/*!*/ MakeArray2(object item1, object item2) {
1090            RubyArray result = new RubyArray(2);
1091            result.Add(item1);
1092            result.Add(item2);
1093            return result;
1094        }
1095
1096        [Emitted]
1097        public static RubyArray/*!*/ MakeArray3(object item1, object item2, object item3) {
1098            RubyArray result = new RubyArray(3);
1099            result.Add(item1);
1100            result.Add(item2);
1101            result.Add(item3);
1102            return result;
1103        }
1104
1105        [Emitted]
1106        public static RubyArray/*!*/ MakeArray4(object item1, object item2, object item3, object item4) {
1107            RubyArray result = new RubyArray(4);
1108            result.Add(item1);
1109            result.Add(item2);
1110            result.Add(item3);
1111            result.Add(item4);
1112            return result;
1113        }
1114
1115        [Emitted]
1116        public static RubyArray/*!*/ MakeArray5(object item1, object item2, object item3, object item4, object item5) {
1117            RubyArray result = new RubyArray(5);
1118            result.Add(item1);
1119            result.Add(item2);
1120            result.Add(item3);
1121            result.Add(item4);
1122            result.Add(item5);
1123            return result;
1124        }
1125
1126        [Emitted]
1127        public static RubyArray/*!*/ MakeArrayN(object[]/*!*/ items) {
1128            Debug.Assert(items != null);
1129            var array = new RubyArray(items.Length);
1130            array.AddVector(items, 0, items.Length);
1131            return array;
1132        }
1133
1134        #endregion
1135
1136        #region MakeHash
1137
1138        [Emitted]
1139        public static Hash/*!*/ MakeHash0(RubyScope/*!*/ scope) {
1140            return new Hash(scope.RubyContext.EqualityComparer, 0);
1141        }
1142        
1143        [Emitted]
1144        public static Hash/*!*/ MakeHash(RubyScope/*!*/ scope, object[]/*!*/ items) {
1145            return RubyUtils.SetHashElements(scope.RubyContext, new Hash(scope.RubyContext.EqualityComparer, items.Length / 2), items);
1146        }
1147
1148        #endregion
1149
1150        #region Array
1151
1152        [Emitted]
1153        public static RubyArray/*!*/ AddRange(RubyArray/*!*/ array, IList/*!*/ list) {
1154            return array.AddRange(list);
1155        }
1156
1157        [Emitted] // method call:
1158        public static RubyArray/*!*/ AddSubRange(RubyArray/*!*/ result, IList/*!*/ array, int start, int count) {
1159            return result.AddRange(array, start, count);
1160        }
1161
1162        [Emitted]
1163        public static RubyArray/*!*/ AddItem(RubyArray/*!*/ array, object item) {
1164            array.Add(item);
1165            return array;
1166        }
1167
1168        [Emitted]
1169        public static IList/*!*/ SplatAppend(IList/*!*/ array, IList/*!*/ list) {
1170            Utils.AddRange(array, list);
1171            return array;
1172        }
1173
1174        [Emitted]
1175        public static object Splat(IList/*!*/ list) {
1176            if (list.Count <= 1) {
1177                return (list.Count > 0) ? list[0] : null;
1178            }
1179
1180            return list;
1181        }
1182
1183        // 1.8 behavior
1184        [Emitted]
1185        public static object SplatPair(object value, IList/*!*/ list) {
1186            if (list.Count == 0) {
1187                return value;
1188            }
1189
1190            RubyArray result = new RubyArray(list.Count + 1);
1191            result.Add(value);
1192            result.AddRange(list);
1193            return result;
1194        }
1195
1196        [Emitted]
1197        public static IList/*!*/ Unsplat(object splattee) {
1198            var list = splattee as IList;
1199            if (list == null) {
1200                list = new RubyArray(1);
1201                list.Add(splattee);
1202            }
1203            return list;
1204        }
1205
1206        // CaseExpression
1207        [Emitted]
1208        public static bool ExistsUnsplatCompare(CallSite<Func<CallSite, obje

Large files files are truncated, but you can click here to view the full file