PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 0ms 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
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  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. #if !CLR2
  16. using MSA = System.Linq.Expressions;
  17. #else
  18. using MSA = Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections;
  22. using System.Collections.Generic;
  23. using System.Diagnostics;
  24. using System.Dynamic;
  25. using System.Globalization;
  26. using System.IO;
  27. using System.Reflection;
  28. using System.Runtime.CompilerServices;
  29. using System.Runtime.Serialization;
  30. using System.Threading;
  31. using IronRuby.Builtins;
  32. using IronRuby.Compiler;
  33. using IronRuby.Compiler.Generation;
  34. using IronRuby.Runtime.Calls;
  35. using Microsoft.Scripting;
  36. using Microsoft.Scripting.Interpreter;
  37. using Microsoft.Scripting.Math;
  38. using Microsoft.Scripting.Runtime;
  39. using Microsoft.Scripting.Utils;
  40. using IronRuby.Compiler.Ast;
  41. using IronRuby.Runtime.Conversions;
  42. namespace IronRuby.Runtime {
  43. [ReflectionCached, CLSCompliant(false)]
  44. public static partial class RubyOps {
  45. [Emitted]
  46. public static readonly object DefaultArgument = new object();
  47. // Returned by a virtual site if a base call should be performed.
  48. [Emitted]
  49. public static readonly object ForwardToBase = new object();
  50. // an instance of a dummy type that causes any rule based on instance type check to fail
  51. private sealed class _NeedsUpdate {
  52. }
  53. [Emitted]
  54. public static readonly object NeedsUpdate = new _NeedsUpdate();
  55. #region Scopes
  56. [Emitted]
  57. public static MutableTuple GetLocals(RubyScope/*!*/ scope) {
  58. return scope.Locals;
  59. }
  60. [Emitted]
  61. public static MutableTuple GetParentLocals(RubyScope/*!*/ scope) {
  62. return scope.Parent.Locals;
  63. }
  64. [Emitted]
  65. public static RubyScope/*!*/ GetParentScope(RubyScope/*!*/ scope) {
  66. return scope.Parent;
  67. }
  68. [Emitted]
  69. public static Proc GetMethodBlockParameter(RubyScope/*!*/ scope) {
  70. var methodScope = scope.GetInnerMostMethodScope();
  71. return methodScope != null ? methodScope.BlockParameter : null;
  72. }
  73. [Emitted]
  74. public static object GetMethodBlockParameterSelf(RubyScope/*!*/ scope) {
  75. Proc proc = scope.GetInnerMostMethodScope().BlockParameter;
  76. Debug.Assert(proc != null, "CreateBfcForYield is called before this method and it checks non-nullity");
  77. return proc.Self;
  78. }
  79. [Emitted]
  80. public static object GetProcSelf(Proc/*!*/ proc) {
  81. return proc.Self;
  82. }
  83. [Emitted]
  84. public static int GetProcArity(Proc/*!*/ proc) {
  85. return proc.Dispatcher.Arity;
  86. }
  87. [Emitted]
  88. public static void InitializeScope(RubyScope/*!*/ scope, MutableTuple locals, string[] variableNames,
  89. InterpretedFrame interpretedFrame) {
  90. if (!scope.LocalsInitialized) {
  91. scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
  92. }
  93. scope.InterpretedFrame = interpretedFrame;
  94. }
  95. [Emitted]
  96. public static void InitializeScopeNoLocals(RubyScope/*!*/ scope, InterpretedFrame interpretedFrame) {
  97. scope.InterpretedFrame = interpretedFrame;
  98. }
  99. [Emitted]
  100. public static void SetDataConstant(RubyScope/*!*/ scope, string/*!*/ dataPath, int dataOffset) {
  101. Debug.Assert(dataOffset >= 0);
  102. RubyFile dataFile;
  103. RubyContext context = scope.RubyContext;
  104. if (context.DomainManager.Platform.FileExists(dataPath)) {
  105. dataFile = new RubyFile(context, dataPath, IOMode.ReadOnly);
  106. dataFile.Seek(dataOffset, SeekOrigin.Begin);
  107. } else {
  108. dataFile = null;
  109. }
  110. context.ObjectClass.SetConstant("DATA", dataFile);
  111. }
  112. [Emitted]
  113. public static RubyModuleScope/*!*/ CreateModuleScope(MutableTuple locals, string[] variableNames,
  114. RubyScope/*!*/ parent, RubyModule/*!*/ module) {
  115. if (parent.RubyContext != module.Context) {
  116. throw RubyExceptions.CreateTypeError("Cannot open a module `{0}' defined in a foreign runtime #{1}", module.Name, module.Context.RuntimeId);
  117. }
  118. RubyModuleScope scope = new RubyModuleScope(parent, module);
  119. scope.SetDebugName((module.IsClass ? "class" : "module") + " " + module.Name);
  120. scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
  121. return scope;
  122. }
  123. [Emitted]
  124. public static RubyMethodScope/*!*/ CreateMethodScope(MutableTuple locals, string[] variableNames, int visibleParameterCount,
  125. RubyScope/*!*/ parentScope, RubyModule/*!*/ declaringModule, string/*!*/ definitionName,
  126. object selfObject, Proc blockParameter, InterpretedFrame interpretedFrame) {
  127. return new RubyMethodScope(
  128. locals, variableNames ?? ArrayUtils.EmptyStrings, visibleParameterCount,
  129. parentScope, declaringModule, definitionName, selfObject, blockParameter,
  130. interpretedFrame
  131. );
  132. }
  133. [Emitted]
  134. public static RubyScope/*!*/ CreateFileInitializerScope(MutableTuple locals, string[] variableNames, RubyScope/*!*/ parent) {
  135. return new RubyFileInitializerScope(locals, variableNames ?? ArrayUtils.EmptyStrings, parent);
  136. }
  137. [Emitted]
  138. public static RubyBlockScope/*!*/ CreateBlockScope(MutableTuple locals, string[] variableNames,
  139. BlockParam/*!*/ blockParam, object selfObject, InterpretedFrame interpretedFrame) {
  140. return new RubyBlockScope(locals, variableNames ?? ArrayUtils.EmptyStrings, blockParam, selfObject, interpretedFrame);
  141. }
  142. [Emitted]
  143. public static void TraceMethodCall(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
  144. // MRI:
  145. // Reports DeclaringModule even though an aliased method in a sub-module is called.
  146. // Also works for singleton module-function, which shares DeclaringModule with instance module-function.
  147. RubyModule module = scope.DeclaringModule;
  148. scope.RubyContext.ReportTraceEvent("call", scope, module, scope.DefinitionName, fileName, lineNumber);
  149. }
  150. [Emitted]
  151. public static void TraceMethodReturn(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
  152. RubyModule module = scope.DeclaringModule;
  153. scope.RubyContext.ReportTraceEvent("return", scope, module, scope.DefinitionName, fileName, lineNumber);
  154. }
  155. [Emitted]
  156. public static void TraceBlockCall(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
  157. var method = block.Proc.Method;
  158. if (method != null) {
  159. scope.RubyContext.ReportTraceEvent("call", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
  160. }
  161. }
  162. [Emitted]
  163. public static void TraceBlockReturn(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
  164. var method = block.Proc.Method;
  165. if (method != null) {
  166. scope.RubyContext.ReportTraceEvent("return", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
  167. }
  168. }
  169. [Emitted]
  170. public static void PrintInteractiveResult(RubyScope/*!*/ scope, MutableString/*!*/ value) {
  171. var writer = scope.RubyContext.DomainManager.SharedIO.OutputStream;
  172. writer.WriteByte((byte)'=');
  173. writer.WriteByte((byte)'>');
  174. writer.WriteByte((byte)' ');
  175. var bytes = value.ToByteArray();
  176. writer.Write(bytes, 0, bytes.Length);
  177. writer.WriteByte((byte)'\r');
  178. writer.WriteByte((byte)'\n');
  179. }
  180. [Emitted]
  181. public static object GetLocalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
  182. return scope.ResolveLocalVariable(name);
  183. }
  184. [Emitted]
  185. public static object SetLocalVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
  186. return scope.ResolveAndSetLocalVariable(name, value);
  187. }
  188. [Emitted]
  189. public static VersionHandle/*!*/ GetSelfClassVersionHandle(RubyScope/*!*/ scope) {
  190. return scope.SelfImmediateClass.Version;
  191. }
  192. #endregion
  193. #region Context
  194. [Emitted]
  195. public static RubyContext/*!*/ GetContextFromModule(RubyModule/*!*/ module) {
  196. return module.Context;
  197. }
  198. [Emitted]
  199. public static RubyContext/*!*/ GetContextFromIRubyObject(IRubyObject/*!*/ obj) {
  200. return obj.ImmediateClass.Context;
  201. }
  202. [Emitted]
  203. public static RubyContext/*!*/ GetContextFromScope(RubyScope/*!*/ scope) {
  204. return scope.RubyContext;
  205. }
  206. [Emitted]
  207. public static RubyContext/*!*/ GetContextFromMethod(RubyMethod/*!*/ method) {
  208. return method.Info.Context;
  209. }
  210. [Emitted]
  211. public static RubyContext/*!*/ GetContextFromBlockParam(BlockParam/*!*/ block) {
  212. return block.RubyContext;
  213. }
  214. [Emitted]
  215. public static RubyContext/*!*/ GetContextFromProc(Proc/*!*/ proc) {
  216. return proc.LocalScope.RubyContext;
  217. }
  218. [Emitted]
  219. public static RubyScope/*!*/ GetEmptyScope(RubyContext/*!*/ context) {
  220. return context.EmptyScope;
  221. }
  222. [Emitted]
  223. public static Scope/*!*/ GetGlobalScopeFromScope(RubyScope/*!*/ scope) {
  224. return scope.GlobalScope.Scope;
  225. }
  226. #endregion
  227. #region Blocks
  228. [Emitted]
  229. public static Proc InstantiateBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
  230. return (dispatcher.Method != null) ? new Proc(ProcKind.Block, self, scope, dispatcher) : null;
  231. }
  232. [Emitted]
  233. public static Proc InstantiateLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
  234. return (dispatcher.Method != null) ? new Proc(ProcKind.Lambda, self, scope, dispatcher) : null;
  235. }
  236. [Emitted]
  237. public static Proc/*!*/ DefineBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
  238. // DLR closures should not be used:
  239. Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
  240. return new Proc(ProcKind.Block, self, scope, dispatcher.SetMethod(clrMethod));
  241. }
  242. [Emitted]
  243. public static Proc/*!*/ DefineLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
  244. // DLR closures should not be used:
  245. Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
  246. return new Proc(ProcKind.Lambda, self, scope, dispatcher.SetMethod(clrMethod));
  247. }
  248. /// <summary>
  249. /// Used in a method call with a block to reset proc-kind when the call is retried
  250. /// </summary>
  251. [Emitted]
  252. public static void InitializeBlock(Proc/*!*/ proc) {
  253. Assert.NotNull(proc);
  254. proc.Kind = ProcKind.Block;
  255. }
  256. /// <summary>
  257. /// Implements END block - like if it was a call to at_exit { ... } library method.
  258. /// </summary>
  259. [Emitted]
  260. public static void RegisterShutdownHandler(Proc/*!*/ proc) {
  261. proc.LocalScope.RubyContext.RegisterShutdownHandler(proc);
  262. }
  263. #endregion
  264. #region Yield: TODO: generate
  265. [Emitted]
  266. public static object Yield0(Proc procArg, object self, BlockParam/*!*/ blockParam) {
  267. object result;
  268. var proc = blockParam.Proc;
  269. try {
  270. result = proc.Dispatcher.Invoke(blockParam, self, procArg);
  271. } catch(EvalUnwinder evalUnwinder) {
  272. result = blockParam.GetUnwinderResult(evalUnwinder);
  273. }
  274. return result;
  275. }
  276. [Emitted]
  277. public static object Yield1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  278. object result;
  279. var proc = blockParam.Proc;
  280. try {
  281. result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1);
  282. } catch (EvalUnwinder evalUnwinder) {
  283. result = blockParam.GetUnwinderResult(evalUnwinder);
  284. }
  285. return result;
  286. }
  287. // YieldNoAutoSplat1 uses InvokeNoAutoSplat instead of Invoke (used by Call1)
  288. internal static object YieldNoAutoSplat1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  289. object result;
  290. var proc = blockParam.Proc;
  291. try {
  292. result = proc.Dispatcher.InvokeNoAutoSplat(blockParam, self, procArg, arg1);
  293. } catch (EvalUnwinder evalUnwinder) {
  294. result = blockParam.GetUnwinderResult(evalUnwinder);
  295. }
  296. return result;
  297. }
  298. [Emitted]
  299. public static object Yield2(object arg1, object arg2, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  300. object result;
  301. var proc = blockParam.Proc;
  302. try {
  303. result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2);
  304. } catch (EvalUnwinder evalUnwinder) {
  305. result = blockParam.GetUnwinderResult(evalUnwinder);
  306. }
  307. return result;
  308. }
  309. [Emitted]
  310. public static object Yield3(object arg1, object arg2, object arg3, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  311. object result;
  312. var proc = blockParam.Proc;
  313. try {
  314. result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3);
  315. } catch (EvalUnwinder evalUnwinder) {
  316. result = blockParam.GetUnwinderResult(evalUnwinder);
  317. }
  318. return result;
  319. }
  320. [Emitted]
  321. public static object Yield4(object arg1, object arg2, object arg3, object arg4, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  322. object result;
  323. var proc = blockParam.Proc;
  324. try {
  325. result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3, arg4);
  326. } catch (EvalUnwinder evalUnwinder) {
  327. result = blockParam.GetUnwinderResult(evalUnwinder);
  328. }
  329. return result;
  330. }
  331. [Emitted]
  332. public static object YieldN(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  333. Debug.Assert(args.Length > BlockDispatcher.MaxBlockArity);
  334. object result;
  335. var proc = blockParam.Proc;
  336. try {
  337. result = proc.Dispatcher.Invoke(blockParam, self, procArg, args);
  338. } catch (EvalUnwinder evalUnwinder) {
  339. result = blockParam.GetUnwinderResult(evalUnwinder);
  340. }
  341. return result;
  342. }
  343. internal static object Yield(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  344. switch (args.Length) {
  345. case 0: return RubyOps.Yield0(procArg, self, blockParam);
  346. case 1: return RubyOps.Yield1(args[0], procArg, self, blockParam);
  347. case 2: return RubyOps.Yield2(args[0], args[1], procArg, self, blockParam);
  348. case 3: return RubyOps.Yield3(args[0], args[1], args[2], procArg, self, blockParam);
  349. case 4: return RubyOps.Yield4(args[0], args[1], args[2], args[3], procArg, self, blockParam);
  350. default: return RubyOps.YieldN(args, procArg, self, blockParam);
  351. }
  352. }
  353. [Emitted]
  354. public static object YieldSplat0(IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  355. object result;
  356. var proc = blockParam.Proc;
  357. try {
  358. result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, splattee);
  359. } catch (EvalUnwinder evalUnwinder) {
  360. result = blockParam.GetUnwinderResult(evalUnwinder);
  361. }
  362. return result;
  363. }
  364. [Emitted]
  365. public static object YieldSplat1(object arg1, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  366. object result;
  367. var proc = blockParam.Proc;
  368. try {
  369. result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, splattee);
  370. } catch (EvalUnwinder evalUnwinder) {
  371. result = blockParam.GetUnwinderResult(evalUnwinder);
  372. }
  373. return result;
  374. }
  375. [Emitted]
  376. public static object YieldSplat2(object arg1, object arg2, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  377. object result;
  378. var proc = blockParam.Proc;
  379. try {
  380. result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, splattee);
  381. } catch (EvalUnwinder evalUnwinder) {
  382. result = blockParam.GetUnwinderResult(evalUnwinder);
  383. }
  384. return result;
  385. }
  386. [Emitted]
  387. public static object YieldSplat3(object arg1, object arg2, object arg3, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  388. object result;
  389. var proc = blockParam.Proc;
  390. try {
  391. result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, splattee);
  392. } catch (EvalUnwinder evalUnwinder) {
  393. result = blockParam.GetUnwinderResult(evalUnwinder);
  394. }
  395. return result;
  396. }
  397. [Emitted]
  398. public static object YieldSplat4(object arg1, object arg2, object arg3, object arg4, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  399. object result;
  400. var proc = blockParam.Proc;
  401. try {
  402. result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, arg4, splattee);
  403. } catch (EvalUnwinder evalUnwinder) {
  404. result = blockParam.GetUnwinderResult(evalUnwinder);
  405. }
  406. return result;
  407. }
  408. [Emitted]
  409. public static object YieldSplatN(object[]/*!*/ args, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  410. object result;
  411. var proc = blockParam.Proc;
  412. try {
  413. result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, args, splattee);
  414. } catch (EvalUnwinder evalUnwinder) {
  415. result = blockParam.GetUnwinderResult(evalUnwinder);
  416. }
  417. return result;
  418. }
  419. [Emitted]
  420. public static object YieldSplatNRhs(object[]/*!*/ args, IList/*!*/ splattee, object rhs, Proc procArg, object self, BlockParam/*!*/ blockParam) {
  421. object result;
  422. var proc = blockParam.Proc;
  423. try {
  424. result = proc.Dispatcher.InvokeSplatRhs(blockParam, self, procArg, args, splattee, rhs);
  425. } catch (EvalUnwinder evalUnwinder) {
  426. result = blockParam.GetUnwinderResult(evalUnwinder);
  427. }
  428. return result;
  429. }
  430. #endregion
  431. #region Methods
  432. [Emitted] // MethodDeclaration:
  433. public static object DefineMethod(object target, RubyScope/*!*/ scope, RubyMethodBody/*!*/ body) {
  434. Assert.NotNull(body, scope);
  435. RubyModule instanceOwner, singletonOwner;
  436. RubyMemberFlags instanceFlags, singletonFlags;
  437. bool moduleFunction = false;
  438. if (body.HasTarget) {
  439. if (!RubyUtils.CanDefineSingletonMethod(target)) {
  440. throw RubyExceptions.CreateTypeError("can't define singleton method for literals");
  441. }
  442. instanceOwner = null;
  443. instanceFlags = RubyMemberFlags.Invalid;
  444. singletonOwner = scope.RubyContext.GetOrCreateSingletonClass(target);
  445. singletonFlags = RubyMemberFlags.Public;
  446. } else {
  447. var attributesScope = scope.GetMethodAttributesDefinitionScope();
  448. if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) {
  449. // Singleton module-function's scope points to the instance method's RubyMemberInfo.
  450. // This affects:
  451. // 1) super call
  452. // Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function
  453. // was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton.
  454. // Module's singleton is never part of MRO so we are safe.
  455. // 2) trace
  456. // Method call trace reports non-singleton module.
  457. // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug)
  458. // MRI 1.9: instance method owner GetMethodDefinitionOwner
  459. // MRI allows to define m.f. on classes but then doesn't work correctly with it.
  460. instanceOwner = scope.GetMethodDefinitionOwner();
  461. if (instanceOwner.IsClass) {
  462. throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class.");
  463. }
  464. instanceFlags = RubyMemberFlags.Private;
  465. singletonOwner = instanceOwner.GetOrCreateSingletonClass();
  466. singletonFlags = RubyMemberFlags.Public;
  467. moduleFunction = true;
  468. } else {
  469. instanceOwner = scope.GetMethodDefinitionOwner();
  470. instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, body.Name);
  471. singletonOwner = null;
  472. singletonFlags = RubyMemberFlags.Invalid;
  473. }
  474. }
  475. RubyMethodInfo instanceMethod = null, singletonMethod = null;
  476. if (instanceOwner != null) {
  477. SetMethod(scope.RubyContext, instanceMethod =
  478. new RubyMethodInfo(body, scope, instanceOwner, instanceFlags)
  479. );
  480. }
  481. if (singletonOwner != null) {
  482. SetMethod(scope.RubyContext, singletonMethod =
  483. new RubyMethodInfo(body, scope, singletonOwner, singletonFlags)
  484. );
  485. }
  486. // the method's scope saves the result => singleton module-function uses instance-method
  487. var method = instanceMethod ?? singletonMethod;
  488. method.DeclaringModule.MethodAdded(body.Name);
  489. if (moduleFunction) {
  490. Debug.Assert(!method.DeclaringModule.IsClass);
  491. method.DeclaringModule.GetOrCreateSingletonClass().MethodAdded(body.Name);
  492. }
  493. return null;
  494. }
  495. private static void SetMethod(RubyContext/*!*/ callerContext, RubyMethodInfo/*!*/ method) {
  496. var owner = method.DeclaringModule;
  497. // Do not trigger the add-method event just yet, we need to assign the result into closure before executing any user code.
  498. // If the method being defined is "method_added" itself, we would call that method before the info gets assigned to the closure.
  499. owner.SetMethodNoEvent(callerContext, method.DefinitionName, method);
  500. // expose RubyMethod in the scope (the method is bound to the main singleton instance):
  501. if (owner.GlobalScope != null) {
  502. RubyOps.ScopeSetMember(
  503. owner.GlobalScope.Scope,
  504. method.DefinitionName,
  505. new RubyMethod(owner.GlobalScope.MainObject, method, method.DefinitionName)
  506. );
  507. }
  508. }
  509. [Emitted] // AliasStatement:
  510. public static void AliasMethod(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) {
  511. scope.GetMethodDefinitionOwner().AddMethodAlias(newName, oldName);
  512. }
  513. [Emitted] // UndefineMethod:
  514. public static void UndefineMethod(RubyScope/*!*/ scope, string/*!*/ name) {
  515. RubyModule owner = scope.GetMethodDefinitionOwner();
  516. if (!owner.ResolveMethod(name, VisibilityContext.AllVisible).Found) {
  517. throw RubyExceptions.CreateUndefinedMethodError(owner, name);
  518. }
  519. owner.UndefineMethod(name);
  520. }
  521. #endregion
  522. #region Modules
  523. [Emitted]
  524. public static RubyModule/*!*/ DefineGlobalModule(RubyScope/*!*/ scope, string/*!*/ name) {
  525. return DefineModule(scope, scope.Top.TopModuleOrObject, name);
  526. }
  527. [Emitted]
  528. public static RubyModule/*!*/ DefineNestedModule(RubyScope/*!*/ scope, string/*!*/ name) {
  529. return DefineModule(scope, scope.GetInnerMostModuleForConstantLookup(), name);
  530. }
  531. [Emitted]
  532. public static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, object target, string/*!*/ name) {
  533. return DefineModule(scope, RubyUtils.GetModuleFromObject(scope, target), name);
  534. }
  535. // thread-safe:
  536. private static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name) {
  537. Assert.NotNull(scope, owner);
  538. ConstantStorage existing;
  539. if (owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
  540. RubyModule module = existing.Value as RubyModule;
  541. if (module == null || module.IsClass) {
  542. throw RubyExceptions.CreateTypeError(String.Format("{0} is not a module", name));
  543. }
  544. return module;
  545. } else {
  546. // create class/module object:
  547. return owner.Context.DefineModule(owner, name);
  548. }
  549. }
  550. #endregion
  551. #region Classes
  552. [Emitted]
  553. public static RubyClass/*!*/ DefineSingletonClass(RubyScope/*!*/ scope, object obj) {
  554. if (!RubyUtils.HasSingletonClass(obj)) {
  555. throw RubyExceptions.CreateTypeError(String.Format("no virtual class for {0}", scope.RubyContext.GetClassOf(obj).Name));
  556. }
  557. return scope.RubyContext.GetOrCreateSingletonClass(obj);
  558. }
  559. [Emitted]
  560. public static RubyModule/*!*/ DefineGlobalClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
  561. return DefineClass(scope, scope.Top.TopModuleOrObject, name, superClassObject);
  562. }
  563. [Emitted]
  564. public static RubyModule/*!*/ DefineNestedClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
  565. return DefineClass(scope, scope.GetInnerMostModuleForConstantLookup(), name, superClassObject);
  566. }
  567. [Emitted]
  568. public static RubyModule/*!*/ DefineClass(RubyScope/*!*/ scope, object target, string/*!*/ name, object superClassObject) {
  569. return DefineClass(scope, RubyUtils.GetModuleFromObject(scope, target), name, superClassObject);
  570. }
  571. // thread-safe:
  572. private static RubyClass/*!*/ DefineClass(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name, object superClassObject) {
  573. Assert.NotNull(owner);
  574. RubyClass superClass = ToSuperClass(owner.Context, superClassObject);
  575. ConstantStorage existing;
  576. if (owner.IsObjectClass
  577. ? owner.TryResolveConstant(scope.GlobalScope, name, out existing)
  578. : owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
  579. RubyClass cls = existing.Value as RubyClass;
  580. if (cls == null || !cls.IsClass) {
  581. throw RubyExceptions.CreateTypeError("{0} is not a class", name);
  582. }
  583. if (superClassObject != null && !ReferenceEquals(cls.SuperClass, superClass)) {
  584. throw RubyExceptions.CreateTypeError("superclass mismatch for class {0}", name);
  585. }
  586. return cls;
  587. } else {
  588. return owner.Context.DefineClass(owner, name, superClass, null);
  589. }
  590. }
  591. private static RubyClass/*!*/ ToSuperClass(RubyContext/*!*/ ec, object superClassObject) {
  592. if (superClassObject != null) {
  593. RubyClass superClass = superClassObject as RubyClass;
  594. if (superClass == null) {
  595. throw RubyExceptions.CreateTypeError("superclass must be a Class ({0} given)", ec.GetClassOf(superClassObject).Name);
  596. }
  597. if (superClass.IsSingletonClass) {
  598. throw RubyExceptions.CreateTypeError("can't make subclass of virtual class");
  599. }
  600. return superClass;
  601. } else {
  602. return ec.ObjectClass;
  603. }
  604. }
  605. #endregion
  606. #region Constants
  607. /// <summary>
  608. /// A
  609. /// ::A
  610. /// </summary>
  611. [Emitted]
  612. public static object GetUnqualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name, bool isGlobal) {
  613. object result = null;
  614. RubyModule missingConstantOwner;
  615. var context = scope.RubyContext;
  616. using (context.ClassHierarchyLocker()) {
  617. // Thread safety:
  618. // Another thread could have already updated the value, so the site version might be the same as CAV.
  619. // We do the lookup anyways since it is no-op and this only happens rarely.
  620. //
  621. // An important invariant holds here: in any time after initialized for the first time the Value field contains a valid value.
  622. // Threads can read an older value (the previous version) but that is still correct since we don't guarantee immediate
  623. // propagation of the constant write to all readers.
  624. //
  625. // if (site.Version = CAV) {
  626. // <- another thread could increment CAV here - we may return old or new value (both are ok)
  627. // value = site.Value;
  628. // } else {
  629. // <- another thread could get here as well and update the site before we get to update it.
  630. // GetConstant(...)
  631. // }
  632. // Constants might be updated during constant resolution due to autoload.
  633. // Any such updates need to invalidate the cache hence we need to capture the version before resolving the constant.
  634. int newVersion = context.ConstantAccessVersion;
  635. ConstantStorage storage;
  636. if (!isGlobal) {
  637. missingConstantOwner = scope.TryResolveConstantNoLock(scope.GlobalScope, name, out storage);
  638. } else if (context.ObjectClass.TryResolveConstantNoLock(scope.GlobalScope, name, out storage)) {
  639. missingConstantOwner = null;
  640. } else {
  641. missingConstantOwner = context.ObjectClass;
  642. }
  643. object newCacheValue;
  644. if (missingConstantOwner == null) {
  645. if (storage.WeakValue != null) {
  646. result = storage.Value;
  647. newCacheValue = storage.WeakValue;
  648. } else {
  649. result = newCacheValue = storage.Value;
  650. }
  651. } else {
  652. newCacheValue = ConstantSiteCache.WeakMissingConstant;
  653. }
  654. cache.Update(newCacheValue, newVersion);
  655. }
  656. if (missingConstantOwner != null) {
  657. result = missingConstantOwner.ConstantMissing(name);
  658. }
  659. return result;
  660. }
  661. /// <summary>
  662. /// A1::..::AN
  663. /// ::A1::..::AN
  664. /// </summary>
  665. [Emitted]
  666. public static object GetQualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
  667. var globalScope = scope.GlobalScope;
  668. var context = globalScope.Context;
  669. using (context.ClassHierarchyLocker()) {
  670. int newVersion = context.ConstantAccessVersion;
  671. ConstantStorage storage;
  672. bool anyMissing;
  673. RubyModule topModule = isGlobal ? context.ObjectClass : null;
  674. object result = ResolveQualifiedConstant(scope, qualifiedName, topModule, true, out storage, out anyMissing);
  675. // cache result only if no constant was missing:
  676. if (!anyMissing) {
  677. Debug.Assert(result == storage.Value);
  678. cache.Update(storage.WeakValue ?? result, newVersion);
  679. }
  680. return result;
  681. }
  682. }
  683. /// <summary>
  684. /// {expr}::A1::..::AN
  685. /// </summary>
  686. [Emitted]
  687. public static object GetExpressionQualifiedConstant(object target, RubyScope/*!*/ scope, ExpressionQualifiedConstantSiteCache/*!*/ cache,
  688. string/*!*/[]/*!*/ qualifiedName) {
  689. RubyModule module = target as RubyModule;
  690. if (module == null) {
  691. throw RubyUtils.CreateNotModuleException(scope, target);
  692. }
  693. var condition = cache.Condition;
  694. RubyContext context = module.Context;
  695. // Note that the module can be bound to another runtime:
  696. if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
  697. object value = cache.Value;
  698. if (value.GetType() == typeof(WeakReference)) {
  699. return ((WeakReference)value).Target;
  700. } else {
  701. return value;
  702. }
  703. }
  704. using (context.ClassHierarchyLocker()) {
  705. int newVersion = context.ConstantAccessVersion;
  706. ConstantStorage storage;
  707. bool anyMissing;
  708. object result = ResolveQualifiedConstant(scope, qualifiedName, module, true, out storage, out anyMissing);
  709. // cache result only if no constant was missing:
  710. if (!anyMissing) {
  711. Debug.Assert(result == storage.Value);
  712. cache.Update(storage.WeakValue ?? result, newVersion, module);
  713. }
  714. return result;
  715. }
  716. }
  717. /// <summary>
  718. /// defined? A
  719. /// </summary>
  720. [Emitted]
  721. public static bool IsDefinedUnqualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
  722. var context = scope.RubyContext;
  723. using (context.ClassHierarchyLocker()) {
  724. int newVersion = context.ConstantAccessVersion;
  725. ConstantStorage storage;
  726. bool exists = scope.TryResolveConstantNoLock(null, name, out storage) == null;
  727. cache.Update(exists, newVersion);
  728. return exists;
  729. }
  730. }
  731. /// <summary>
  732. /// defined? ::A
  733. /// </summary>
  734. [Emitted]
  735. public static bool IsDefinedGlobalConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
  736. var context = scope.RubyContext;
  737. using (context.ClassHierarchyLocker()) {
  738. int newVersion = context.ConstantAccessVersion;
  739. ConstantStorage storage;
  740. bool exists = context.ObjectClass.TryResolveConstantNoLock(null, name, out storage);
  741. cache.Update(exists, newVersion);
  742. return exists;
  743. }
  744. }
  745. /// <summary>
  746. /// defined? A1::..::AN
  747. /// defined? ::A1::..::AN
  748. /// </summary>
  749. [Emitted]
  750. public static bool IsDefinedQualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache,
  751. string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
  752. var context = scope.RubyContext;
  753. using (context.ClassHierarchyLocker()) {
  754. int newVersion = context.ConstantAccessVersion;
  755. ConstantStorage storage;
  756. bool anyMissing;
  757. RubyModule topModule = isGlobal ? context.ObjectClass : null;
  758. RubyModule owner;
  759. try {
  760. owner = ResolveQualifiedConstant(scope, qualifiedName, topModule, false, out storage, out anyMissing) as RubyModule;
  761. } catch {
  762. // autoload can raise an exception
  763. scope.RubyContext.SetCurrentException(null);
  764. return false;
  765. }
  766. // Note that the owner could be another runtime's module:
  767. bool exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
  768. // cache result only if no constant was missing:
  769. if (!anyMissing) {
  770. cache.Update(exists, newVersion);
  771. }
  772. return exists;
  773. }
  774. }
  775. /// <summary>
  776. /// defined? {expr}::A
  777. /// defined? {expr}::A1::..::AN
  778. /// </summary>
  779. [Emitted]
  780. public static bool IsDefinedExpressionQualifiedConstant(object target, RubyScope/*!*/ scope,
  781. ExpressionQualifiedIsDefinedConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName) {
  782. RubyModule module = target as RubyModule;
  783. if (module == null) {
  784. return false;
  785. }
  786. var condition = cache.Condition;
  787. RubyContext context = module.Context;
  788. // Note that the module can be bound to another runtime:
  789. if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
  790. return cache.Value;
  791. }
  792. using (context.ClassHierarchyLocker()) {
  793. int newVersion = context.ConstantAccessVersion;
  794. ConstantStorage storage;
  795. bool exists;
  796. if (qualifiedName.Length == 1) {
  797. // Note that the owner could be another runtime's module:
  798. exists = module.TryResolveConstant(context, null, qualifiedName[0], out storage);
  799. } else {
  800. bool anyMissing;
  801. RubyModule owner;
  802. try {
  803. owner = ResolveQualifiedConstant(scope, qualifiedName, module, false, out storage, out anyMissing) as RubyModule;
  804. } catch {
  805. // autoload can raise an exception:
  806. return false;
  807. }
  808. // Note that the owner could be another runtime's module:
  809. exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
  810. // cache result only if no constant was missing:
  811. if (anyMissing) {
  812. return exists;
  813. }
  814. }
  815. cache.Update(exists, newVersion, module);
  816. return exists;
  817. }
  818. }
  819. private static object ResolveQualifiedConstant(RubyScope/*!*/ scope, string/*!*/[]/*!*/ qualifiedName, RubyModule topModule, bool isGet,
  820. out ConstantStorage storage, out bool anyMissing) {
  821. Debug.Assert(qualifiedName.Length >= 2 || qualifiedName.Length == 1 && isGet);
  822. RubyContext context = scope.RubyContext;
  823. context.RequiresClassHierarchyLock();
  824. RubyModule missingConstantOwner;
  825. RubyGlobalScope globalScope = scope.GlobalScope;
  826. int nameCount = (isGet) ? qualifiedName.Length : qualifiedName.Length - 1;
  827. string name = qualifiedName[0];
  828. if (topModule == null) {
  829. missingConstantOwner = scope.TryResolveConstantNoLock(globalScope, name, out storage);
  830. } else if (topModule.TryResolveConstant(context, globalScope, name, out storage)) {
  831. missingConstantOwner = null;
  832. } else {
  833. missingConstantOwner = topModule;
  834. }
  835. object result;
  836. if (missingConstantOwner == null) {
  837. result = storage.Value;
  838. anyMissing = false;
  839. } else {
  840. anyMissing = true;
  841. using (context.ClassHierarchyUnlocker()) {
  842. result = missingConstantOwner.ConstantMissing(name);
  843. }
  844. }
  845. for (int i = 1; i < nameCount; i++) {
  846. RubyModule owner = RubyUtils.GetModuleFromObject(scope, result);
  847. // Note that the owner could be another runtime's module:
  848. name = qualifiedName[i];
  849. if (owner.TryResolveConstant(context, globalScope, name, out storage)) {
  850. // Constant write updates constant version in a single runtime only.
  851. // Therefore if the chain mixes modules from different runtimes we cannot cache the result.
  852. if (owner.Context != context) {
  853. anyMissing = true;
  854. }
  855. result = storage.Value;
  856. } else {
  857. anyMissing = true;
  858. using (context.ClassHierarchyUnlocker()) {
  859. result = owner.ConstantMissing(name);
  860. }
  861. }
  862. }
  863. return result;
  864. }
  865. [Emitted]
  866. public static object GetMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
  867. return scope.GetInnerMostModuleForConstantLookup().ConstantMissing(name);
  868. }
  869. [Emitted]
  870. public static object GetGlobalMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
  871. return scope.RubyContext.ObjectClass.ConstantMissing(name);
  872. }
  873. [Emitted] // ConstantVariable:
  874. public static object SetGlobalConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
  875. RubyUtils.SetConstant(scope.RubyContext.ObjectClass, name, value);
  876. return value;
  877. }
  878. [Emitted] // ConstantVariable:
  879. public static object SetUnqualifiedConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
  880. RubyUtils.SetConstant(scope.GetInnerMostModuleForConstantLookup(), name, value);
  881. return value;
  882. }
  883. [Emitted] // ConstantVariable:
  884. public static object SetQualifiedConstant(object value, object target, RubyScope/*!*/ scope, string/*!*/ name) {
  885. RubyUtils.SetConstant(RubyUtils.GetModuleFromObject(scope, target), name, value);
  886. return value;
  887. }
  888. #endregion
  889. // MakeArray*
  890. public const int OptimizedOpCallParamCount = 5;
  891. #region MakeArray
  892. [Emitted]
  893. public static RubyArray/*!*/ MakeArray0() {
  894. return new RubyArray(0);
  895. }
  896. [Emitted]
  897. public static RubyArray/*!*/ MakeArray1(object item1) {
  898. RubyArray result = new RubyArray(1);
  899. result.Add(item1);
  900. return result;
  901. }
  902. [Emitted]
  903. public static RubyArray/*!*/ MakeArray2(object item1, object item2) {
  904. RubyArray result = new RubyArray(2);
  905. result.Add(item1);
  906. result.Add(item2);
  907. return result;
  908. }
  909. [Emitted]
  910. public static RubyArray/*!*/ MakeArray3(object item1, object item2, object item3) {
  911. RubyArray result = new RubyArray(3);
  912. result.Add(item1);
  913. result.Add(item2);
  914. result.Add(item3);
  915. return result;
  916. }
  917. [Emitted]
  918. public static RubyArray/*!*/ MakeArray4(object item1, object item2, object item3, object item4) {
  919. RubyArray result = new RubyArray(4);
  920. result.Add(item1);
  921. result.Add(item2);
  922. result.Add(item3);
  923. result.Add(item4);
  924. return result;
  925. }
  926. [Emitted]
  927. public static RubyArray/*!*/ MakeArray5(object item1, object item2, object item3, object item4, object item5) {
  928. RubyArray result = new RubyArray(5);
  929. result.Add(item1);
  930. result.Add(item2);
  931. result.Add(item3);
  932. result.Add(item4);
  933. result.Add(item5);
  934. return result;
  935. }
  936. [Emitted]
  937. public static RubyArray/*!*/ MakeArrayN(object[]/*!*/ items) {
  938. Debug.Assert(items != null);
  939. var array = new RubyArray(items.Length);
  940. array.AddVector(items, 0, items.Length);
  941. return array;
  942. }
  943. #endregion
  944. #region MakeHash
  945. [Emitted]
  946. public static Hash/*!*/ MakeHash0(RubyScope/*!*/ scope) {
  947. return new Hash(scope.RubyContext.EqualityComparer, 0);
  948. }
  949. [Emitted]
  950. public static Hash/*!*/ MakeHash(RubyScope/*!*/ scope, object[]/*!*/ items) {
  951. return RubyUtils.SetHashElements(scope.RubyContext, new Hash(scope.RubyContext.EqualityComparer, items.Length / 2), items);
  952. }
  953. #endregion
  954. #region Array
  955. [Emitted]
  956. public static RubyArray/*!*/ AddRange(RubyArray/*!*/ array, IList/*!*/ list) {
  957. return array.AddRange(list);
  958. }
  959. [Emitted] // method call:
  960. public static RubyArray/*!*/ AddSubRange(RubyArray/*!*/ result, IList/*!*/ array, int start, int count) {
  961. return result.AddRange(array, start, count);
  962. }
  963. [Emitted]
  964. public static RubyArray/*!*/ AddItem(RubyArray/*!*/ array, object item) {
  965. array.Add(item);
  966. return array;
  967. }
  968. [Emitted]
  969. public static IList/*!*/ SplatAppend(IList/*!*/ array, IList/*!*/ list) {
  970. Utils.AddRange(array, list);
  971. return array;
  972. }
  973. [Emitted]
  974. public static object Splat(IList/*!*/ list) {
  975. if (list.Count <= 1) {
  976. return (list.Count > 0) ? list[0] : null;
  977. }
  978. return list;
  979. }
  980. // 1.8 behavior
  981. [Emitted]
  982. public static object SplatPair(object value, IList/*!*/ list) {
  983. if (list.Count == 0) {
  984. return value;
  985. }
  986. RubyArray result = new RubyArray(list.Count + 1);
  987. result.Add(value);
  988. result.AddRange(list);
  989. return result;
  990. }
  991. [Emitted]
  992. public static IList/*!*/ Unsplat(object splattee) {
  993. var list = splattee as IList;
  994. if (list == null) {
  995. list = new RubyArray(1);
  996. list.Add(splattee);
  997. }
  998. return list;
  999. }
  1000. // CaseExpression
  1001. [Emitted]
  1002. public static bool ExistsUnsplatCompare(CallSite<Func<CallSite, object, object, object>>/*!*/ comparisonSite, object splattee, object value) {
  1003. var list = splattee as IList;
  1004. if (list != null) {
  1005. for (int i = 0; i < list.Count; i++) {
  1006. if (IsTrue(comparisonSite.Target(comparisonSite, list[i], value))) {
  1007. return true;
  1008. }
  1009. }
  1010. return false;
  1011. } else {
  1012. return IsTrue(comparisonSite.Target(comparisonSite, splattee, value));
  1013. }
  1014. }
  1015. // CaseExpression
  1016. [Emitted]
  1017. public static bool ExistsUnsplat(object splattee) {
  1018. var list = splattee as IList;
  1019. if (list != null) {
  1020. for (int i = 0; i < list.Count; i++) {
  1021. if (IsTrue(list[i])) {
  1022. return true;
  1023. }
  1024. }
  1025. return false;
  1026. } else {
  1027. return IsTrue(splattee);
  1028. }
  1029. }
  1030. [Emitted] // parallel assignment:
  1031. public static object GetArrayItem(IList/*!*/ array, int index) {
  1032. Debug.Assert(index >= 0);
  1033. return index < array.Count ? array[index] : null;
  1034. }
  1035. [Emitted] // parallel assignment:
  1036. public static object GetTrailingArrayItem(IList/*!*/ array, int index, int explicitCount) {
  1037. Debug.Assert(index >= 0);
  1038. int i = Math.Max(array.Count, explicitCount) - index;
  1039. return i >= 0 ? array[i] : null;
  1040. }
  1041. [Emitted] // parallel assignment:
  1042. public static RubyArray/*!*/ GetArrayRange(IList/*!*/ array, int startIndex, int explicitCount) {
  1043. int size = array.Count - explicitCount;
  1044. if (size > 0) {
  1045. RubyArray result = new RubyArray(size);
  1046. for (int i = 0; i < size; i++) {
  1047. result.Add(array[startIndex + i]);
  1048. }
  1049. return result;
  1050. } else {
  1051. return new RubyArray();
  1052. }
  1053. }
  1054. #endregion
  1055. #region CLR Vectors (factories mimic Ruby Array factories)
  1056. [Emitted, RubyConstructor]
  1057. public static object/*!*/ CreateVector<TElement>(
  1058. ConversionStorage<TElement>/*!*/ elementConversion,
  1059. ConversionStorage<Union<IList, int>>/*!*/ toAryToInt,
  1060. BlockParam block, RubyClass/*!*/ self, [NotNull]object/*!*/ arrayOrSize) {
  1061. Debug.Assert(typeof(TElement) == self.GetUnderlyingSystemType().GetElementType());
  1062. var site = toAryToInt.GetSite(CompositeConversionAction.Make(self.Context, CompositeConversion.ToAryToInt));
  1063. var union = site.Target(site, arrayOrSize);
  1064. if (union.First != null) {
  1065. // block ignored
  1066. return CreateVectorInternal(elementConversion, union.First);
  1067. } else if (block != null) {
  1068. return PopulateVector(elementConversion, CreateVectorInternal<TElement>(union.Second), block);
  1069. } else {
  1070. return CreateVectorInternal<TElement>(union.Second);
  1071. }
  1072. }
  1073. [Emitted, RubyConstructor]
  1074. public static Array/*!*/ CreateVectorWithValues<TElement>(ConversionStorage<TElement>/*!*/ elementConversion,
  1075. RubyClass/*!*/ self, [DefaultProtocol]int size, [DefaultProtocol]TElement value) {
  1076. Debug.Assert(typeof(TElement) == self.GetUnderlyingSystemType().GetElementType());
  1077. TElement[] result = CreateVectorInternal<TElement>(size);
  1078. for (int i = 0; i < result.Length; i++) {
  1079. result[i] = value;
  1080. }
  1081. return result;
  1082. }
  1083. private static TElement[]/*!*/ CreateVectorInternal<TElement>(int size) {
  1084. if (size < 0) {
  1085. throw RubyExceptions.CreateArgumentError("negative array size");
  1086. }
  1087. return new TElement[size];
  1088. }
  1089. private static Array/*!*/ CreateVectorInternal<TElement>(ConversionStorage<TElement>/*!*/ elementConversion, IList/*!*/ list) {
  1090. var site = elementConversion.GetDefaultConversionSite();
  1091. var result = new TElement[list.Count];
  1092. for (int i = 0; i < result.Length; i++) {
  1093. object item = list[i];
  1094. result[i] = (item is TElement) ? (TElement)item : site.Target(site, item);
  1095. }
  1096. return result;
  1097. }
  1098. private static object PopulateVector<TElement>(ConversionStorage<TElement>/*!*/ elementConversion, TElement[]/*!*/ array, BlockParam/*!*/ block) {
  1099. var site = elementConversion.GetDefaultConversionSite();
  1100. for (int i = 0; i < array.Length; i++) {
  1101. object item;
  1102. if (block.Yield(i, out item)) {
  1103. return item;
  1104. }
  1105. array[i] = site.Target(site, item);
  1106. }
  1107. return array;
  1108. }
  1109. #endregion
  1110. #region Global Variables
  1111. [Emitted]
  1112. public static object GetGlobalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
  1113. object value;
  1114. // no error reported if the variable doesn't exist:
  1115. scope.RubyContext.TryGetGlobalVariable(scope, name, out value);
  1116. return value;
  1117. }
  1118. [Emitted]
  1119. public static bool IsDefinedGlobalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
  1120. GlobalVariable variable;
  1121. return scope.RubyContext.TryGetGlobalVariable(name, out variable) && variable.IsDefined;
  1122. }
  1123. [Emitted]
  1124. public static object SetGlobalVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
  1125. scope.RubyContext.SetGlobalVariable(scope, name, value);
  1126. return value;
  1127. }
  1128. [Emitted]
  1129. public static void AliasGlobalVariable(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) {
  1130. scope.RubyContext.AliasGlobalVariable(newName, oldName);
  1131. }
  1132. #endregion
  1133. #region DLR Scopes
  1134. internal static bool TryGetGlobalScopeConstant(RubyContext/*!*/ context, Scope/*!*/ scope, string/*!*/ name, out object value) {
  1135. string mangled;
  1136. ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
  1137. if (scopeStorage != null) {
  1138. return scopeStorage.TryGetValue(name, false, out value)
  1139. || (mangled = RubyUtils.TryMangleName(name)) != null && scopeStorage.TryGetValue(mangled, false, out value);
  1140. } else {
  1141. return context.Operations.TryGetMember(scope, name, out value)
  1142. || (mangled = RubyUtils.TryMangleName(name)) != null && context.Operations.TryGetMember(scope, mangled, out value);
  1143. }
  1144. }
  1145. // TODO:
  1146. internal static void ScopeSetMember(Scope scope, string name, object value) {
  1147. ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
  1148. if (scopeStorage != null) {
  1149. scopeStorage.SetValue(name, false, value);
  1150. return;
  1151. }
  1152. throw new NotImplementedException();
  1153. }
  1154. // TODO:
  1155. internal static bool ScopeContainsMember(Scope scope, string name) {
  1156. ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
  1157. if (scopeStorage != null) {
  1158. return scopeStorage.HasValue(name, false);
  1159. }
  1160. throw new NotImplementedException();
  1161. }
  1162. // TODO:
  1163. internal static bool ScopeDeleteMember(Scope scope, string name) {
  1164. ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
  1165. if (scopeStorage != null) {
  1166. return scopeStorage.DeleteValue(name, false);
  1167. }
  1168. throw new NotImplementedException();
  1169. }
  1170. // TODO:
  1171. internal static IList<KeyValuePair<string, object>> ScopeGetItems(Scope scope) {
  1172. ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
  1173. if (scopeStorage != null) {
  1174. return scopeStorage.GetItems();
  1175. }
  1176. throw new NotImplementedException();
  1177. }
  1178. #endregion
  1179. #region Regex
  1180. [Emitted] //RegexMatchReference:
  1181. public static MutableString GetCurrentMatchGroup(RubyScope/*!*/ scope, int index) {
  1182. Debug.Assert(index >= 0);
  1183. return scope.GetInnerMostClosureScope().GetCurrentMatchGroup(index);
  1184. }
  1185. [Emitted] //RegexMatchReference:
  1186. public static MatchData GetCurrentMatchData(RubyScope/*!*/ scope) {
  1187. return scope.GetInnerMostClosureScope().CurrentMatch;
  1188. }
  1189. [Emitted] //RegexMatchReference:
  1190. public static MutableString GetCurrentMatchLastGroup(RubyScope/*!*/ scope) {
  1191. return scope.GetInnerMostClosureScope().GetCurrentMatchLastGroup();
  1192. }
  1193. [Emitted] //RegexMatchReference:
  1194. public static MutableString GetCurrentPreMatch(RubyScope/*!*/ scope) {
  1195. return scope.GetInnerMostClosureScope().GetCurrentPreMatch();
  1196. }
  1197. [Emitted] //RegexMatchReference:
  1198. public static MutableString GetCurrentPostMatch(RubyScope/*!*/ scope) {
  1199. return scope.GetInnerMostClosureScope().GetCurrentPostMatch();
  1200. }
  1201. [Emitted] //RegularExpression:
  1202. public static bool MatchLastInputLine(RubyRegex/*!*/ regex, RubyScope/*!*/ scope) {
  1203. var str = scope.GetInnerMostClosureScope().LastInputLine as MutableString;
  1204. return (str != null) ? RubyRegex.SetCurrentMatchData(scope, regex, str) != null : false;
  1205. }
  1206. [Emitted] //MatchExpression:
  1207. public static object MatchString(MutableString str, RubyRegex/*!*/ regex, RubyScope/*!*/ scope) {
  1208. var match = RubyRegex.SetCurrentMatchData(scope, regex, str);
  1209. return (match != null) ? ScriptingRuntimeHelpers.Int32ToObject(match.Index) : null;
  1210. }
  1211. #endregion
  1212. public const char SuffixLiteral = 'L'; // Repr: literal string
  1213. public const char SuffixMutable = 'M'; // non-literal "...#{expr}..."
  1214. /// <summary>
  1215. /// Specialized signatures exist for upto the following number of string parts
  1216. /// </summary>
  1217. public const int MakeStringParamCount = 2;
  1218. #region CreateRegex
  1219. private static RubyRegex/*!*/ CreateRegexWorker(
  1220. RubyRegexOptions options,
  1221. StrongBox<RubyRegex> regexpCache,
  1222. bool isLiteralWithoutSubstitutions,
  1223. Func<RubyRegex> createRegex) {
  1224. try {
  1225. bool once = ((options & RubyRegexOptions.Once) == RubyRegexOptions.Once) || isLiteralWithoutSubstitutions;
  1226. if (once) {
  1227. // Note that the user is responsible for thread synchronization
  1228. if (regexpCache.Value == null) {
  1229. regexpCache.Value = createRegex();
  1230. }
  1231. return regexpCache.Value;
  1232. } else {
  1233. // In the future, we can consider caching the last Regexp. For some regexp literals
  1234. // with substitution, the substition will be the same most of the time
  1235. return createRegex();
  1236. }
  1237. } catch (RegexpError e) {
  1238. if (isLiteralWithoutSubstitutions) {
  1239. // Ideally, this should be thrown during parsing of the source, even if the
  1240. // expression happens to be unreachable at runtime.
  1241. throw new SyntaxError(e.Message);
  1242. } else {
  1243. throw;
  1244. }
  1245. }
  1246. }
  1247. [Emitted]
  1248. public static RubyRegex/*!*/ CreateRegexB(byte[]/*!*/ bytes, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1249. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringB(bytes, encoding), options); };
  1250. return CreateRegexWorker(options, regexpCache, true, createRegex);
  1251. }
  1252. [Emitted]
  1253. public static RubyRegex/*!*/ CreateRegexL(string/*!*/ str1, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1254. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringL(str1, encoding), options); };
  1255. return CreateRegexWorker(options, regexpCache, true, createRegex);
  1256. }
  1257. [Emitted]
  1258. public static RubyRegex/*!*/ CreateRegexM(MutableString str1, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1259. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringM(str1, encoding), options); };
  1260. return CreateRegexWorker(options, regexpCache, false, createRegex);
  1261. }
  1262. [Emitted]
  1263. public static RubyRegex/*!*/ CreateRegexLM(string/*!*/ str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1264. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringLM(str1, str2, encoding), options); };
  1265. return CreateRegexWorker(options, regexpCache, false, createRegex);
  1266. }
  1267. [Emitted]
  1268. public static RubyRegex/*!*/ CreateRegexML(MutableString str1, string/*!*/ str2, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1269. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringML(str1, str2, encoding), options); };
  1270. return CreateRegexWorker(options, regexpCache, false, createRegex);
  1271. }
  1272. [Emitted]
  1273. public static RubyRegex/*!*/ CreateRegexMM(MutableString str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1274. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringMM(str1, str2, encoding), options); };
  1275. return CreateRegexWorker(options, regexpCache, false, createRegex);
  1276. }
  1277. [Emitted]
  1278. public static RubyRegex/*!*/ CreateRegexN(MutableString[]/*!*/ strings, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
  1279. Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringN(strings), options); };
  1280. return CreateRegexWorker(options, regexpCache, false, createRegex);
  1281. }
  1282. #endregion
  1283. #region CreateMutableString
  1284. [Emitted]
  1285. public static MutableString/*!*/ CreateMutableStringB(byte[]/*!*/ bytes, RubyEncoding/*!*/ encoding) {
  1286. return MutableString.CreateBinary(bytes, encoding);
  1287. }
  1288. [Emitted]
  1289. public static MutableString/*!*/ CreateMutableStringL(string/*!*/ str1, RubyEncoding/*!*/ encoding) {
  1290. return MutableString.Create(str1, encoding);
  1291. }
  1292. [Emitted]
  1293. public static MutableString/*!*/ CreateMutableStringM(MutableString str1, RubyEncoding/*!*/ encoding) {
  1294. return MutableString.CreateInternal(str1, encoding);
  1295. }
  1296. [Emitted]
  1297. public static MutableString/*!*/ CreateMutableStringLM(string/*!*/ str1, MutableString str2, RubyEncoding/*!*/ encoding) {
  1298. return MutableString.CreateMutable(str1, encoding).Append(str2);
  1299. }
  1300. [Emitted]
  1301. public static MutableString/*!*/ CreateMutableStringML(MutableString str1, string/*!*/ str2, RubyEncoding/*!*/ encoding) {
  1302. return MutableString.CreateInternal(str1, encoding).Append(str2);
  1303. }
  1304. [Emitted]
  1305. public static MutableString/*!*/ CreateMutableStringMM(MutableString str1, MutableString str2, RubyEncoding/*!*/ encoding) {
  1306. return MutableString.CreateInternal(str1, encoding).Append(str2);
  1307. }
  1308. // TODO: we should emit Append calls directly, and not create an array first
  1309. [Emitted]
  1310. public static MutableString/*!*/ CreateMutableStringN(MutableString/*!*/[]/*!*/ parts) {
  1311. Debug.Assert(parts.Length > 0);
  1312. var result = MutableString.CreateMutable(RubyEncoding.Ascii);
  1313. for (int i = 0; i < parts.Length; i++) {
  1314. result.Append(parts[i]);
  1315. }
  1316. return result;
  1317. }
  1318. #endregion
  1319. #region CreateSymbol
  1320. [Emitted]
  1321. public static RubySymbol/*!*/ CreateSymbolM(MutableString str1, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
  1322. return scope.RubyContext.CreateSymbol(CreateMutableStringM(str1, encoding), false);
  1323. }
  1324. [Emitted]
  1325. public static RubySymbol/*!*/ CreateSymbolLM(string/*!*/ str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
  1326. return scope.RubyContext.CreateSymbol(CreateMutableStringLM(str1, str2, encoding), false);
  1327. }
  1328. [Emitted]
  1329. public static RubySymbol/*!*/ CreateSymbolML(MutableString str1, string/*!*/ str2, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
  1330. return scope.RubyContext.CreateSymbol(CreateMutableStringML(str1, str2, encoding), false);
  1331. }
  1332. [Emitted]
  1333. public static RubySymbol/*!*/ CreateSymbolMM(MutableString str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
  1334. return scope.RubyContext.CreateSymbol(CreateMutableStringMM(str1, str2, encoding), false);
  1335. }
  1336. [Emitted]
  1337. public static RubySymbol/*!*/ CreateSymbolN(MutableString[]/*!*/ strings, RubyScope/*!*/ scope) {
  1338. return scope.RubyContext.CreateSymbol(CreateMutableStringN(strings), false);
  1339. }
  1340. #endregion
  1341. #region Strings, Encodings
  1342. [Emitted]
  1343. public static RubyEncoding/*!*/ CreateEncoding(int codepage) {
  1344. return RubyEncoding.GetRubyEncoding(codepage);
  1345. }
  1346. [Emitted, Obsolete("Internal only")]
  1347. public static byte[]/*!*/ GetMutableStringBytes(MutableString/*!*/ str) {
  1348. int byteCount;
  1349. var result = str.GetByteArray(out byteCount);
  1350. return result;
  1351. }
  1352. #endregion
  1353. #region Booleans
  1354. [Emitted]
  1355. public static bool IsTrue(object obj) {
  1356. return (obj is bool) ? (bool)obj == true : obj != null;
  1357. }
  1358. [Emitted]
  1359. public static bool IsFalse(object obj) {
  1360. return (obj is bool) ? (bool)obj == false : obj == null;
  1361. }
  1362. [Emitted]
  1363. public static object NullIfFalse(object obj) {
  1364. return (obj is bool && !(bool)obj) ? null : obj;
  1365. }
  1366. [Emitted]
  1367. public static object NullIfTrue(object obj) {
  1368. return (obj is bool && !(bool)obj || obj == null) ? DefaultArgument : null;
  1369. }
  1370. #endregion
  1371. #region Exceptions
  1372. //
  1373. // NOTE:
  1374. // Exception Ops go directly to the current exception object. MRI ignores potential aliases.
  1375. //
  1376. /// <summary>
  1377. /// Called in try-filter that wraps the entire body of a block.
  1378. /// We just need to capture stack trace, should not filter out any exception.
  1379. /// </summary>
  1380. [Emitted]
  1381. public static bool FilterBlockException(RubyScope/*!*/ scope, Exception/*!*/ exception) {
  1382. RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
  1383. return false;
  1384. }
  1385. /// <summary>
  1386. /// Called in try-filter that wraps the entire top-level code.
  1387. /// We just need to capture stack trace, should not filter out any exception.
  1388. /// </summary>
  1389. [Emitted]
  1390. public static bool TraceTopLevelCodeFrame(RubyScope/*!*/ scope, Exception/*!*/ exception) {
  1391. RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
  1392. return false;
  1393. }
  1394. // Ruby method exit filter:
  1395. [Emitted]
  1396. public static bool IsMethodUnwinderTargetFrame(RubyScope/*!*/ scope, Exception/*!*/ exception) {
  1397. var unwinder = exception as MethodUnwinder;
  1398. if (unwinder == null) {
  1399. RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
  1400. return false;
  1401. } else {
  1402. return unwinder.TargetFrame == scope.FlowControlScope;
  1403. }
  1404. }
  1405. [Emitted]
  1406. public static object GetMethodUnwinderReturnValue(Exception/*!*/ exception) {
  1407. return ((MethodUnwinder)exception).ReturnValue;
  1408. }
  1409. [Emitted]
  1410. public static void LeaveMethodFrame(RuntimeFlowControl/*!*/ rfc) {
  1411. rfc.LeaveMethod();
  1412. }
  1413. /// <summary>
  1414. /// Filters exceptions raised from EH-body, EH-rescue and EH-else clauses.
  1415. /// </summary>
  1416. [Emitted]
  1417. public static bool CanRescue(RubyScope/*!*/ scope, Exception/*!*/ exception) {
  1418. if (exception is StackUnwinder) {
  1419. return false;
  1420. }
  1421. LocalJumpError lje = exception as LocalJumpError;
  1422. if (lje != null && lje.SkipFrame == scope.FlowControlScope) {
  1423. return false;
  1424. }
  1425. // calls "new" on the exception class if it hasn't been called yet:
  1426. exception = RubyExceptionData.HandleException(scope.RubyContext, exception);
  1427. scope.RubyContext.CurrentException = exception;
  1428. RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
  1429. return true;
  1430. }
  1431. [Emitted]
  1432. public static Exception/*!*/ MarkException(Exception/*!*/ exception) {
  1433. RubyExceptionData.GetInstance(exception).Handled = true;
  1434. return exception;
  1435. }
  1436. [Emitted]
  1437. public static Exception GetCurrentException(RubyScope/*!*/ scope) {
  1438. return scope.RubyContext.CurrentException;
  1439. }
  1440. /// <summary>
  1441. /// Sets $!. Used in EH finally clauses to restore exception stored in oldExceptionVariable local.
  1442. /// </summary>
  1443. [Emitted]
  1444. public static void SetCurrentException(RubyScope/*!*/ scope, Exception exception) {
  1445. scope.RubyContext.CurrentException = exception;
  1446. }
  1447. [Emitted] //RescueClause:
  1448. public static bool CompareException(BinaryOpStorage/*!*/ comparisonStorage, RubyScope/*!*/ scope, object classObject) {
  1449. var context = scope.RubyContext;
  1450. var site = comparisonStorage.GetCallSite("===");
  1451. bool result = IsTrue(site.Target(site, classObject, context.CurrentException));
  1452. if (result) {
  1453. RubyExceptionData.ActiveExceptionHandled(context.CurrentException);
  1454. }
  1455. return result;
  1456. }
  1457. [Emitted] //RescueClause:
  1458. public static bool CompareSplattedExceptions(BinaryOpStorage/*!*/ comparisonStorage, RubyScope/*!*/ scope, IList/*!*/ classObjects) {
  1459. for (int i = 0; i < classObjects.Count; i++) {
  1460. if (CompareException(comparisonStorage, scope, classObjects[i])) {
  1461. return true;
  1462. }
  1463. }
  1464. return false;
  1465. }
  1466. [Emitted] //RescueClause:
  1467. public static bool CompareDefaultException(RubyScope/*!*/ scope) {
  1468. RubyContext ec = scope.RubyContext;
  1469. // MRI doesn't call === here;
  1470. bool result = ec.IsInstanceOf(ec.CurrentException, ec.StandardErrorClass);
  1471. if (result) {
  1472. RubyExceptionData.ActiveExceptionHandled(ec.CurrentException);
  1473. }
  1474. return result;
  1475. }
  1476. [Emitted]
  1477. public static string/*!*/ GetDefaultExceptionMessage(RubyClass/*!*/ exceptionClass) {
  1478. return exceptionClass.Name;
  1479. }
  1480. [Emitted]
  1481. public static ArgumentException/*!*/ CreateArgumentsError(string message) {
  1482. return (ArgumentException)RubyExceptions.CreateArgumentError(message);
  1483. }
  1484. [Emitted]
  1485. public static ArgumentException/*!*/ CreateArgumentsErrorForMissingBlock() {
  1486. return (ArgumentException)RubyExceptions.CreateArgumentError("block not supplied");
  1487. }
  1488. [Emitted]
  1489. public static ArgumentException/*!*/ CreateArgumentsErrorForProc(string className) {
  1490. return (ArgumentException)RubyExceptions.CreateArgumentError(String.Format("wrong type argument {0} (should be callable)", className));
  1491. }
  1492. [Emitted]
  1493. public static ArgumentException/*!*/ MakeWrongNumberOfArgumentsError(int actual, int expected) {
  1494. return new ArgumentException(String.Format("wrong number of arguments ({0} for {1})", actual, expected));
  1495. }
  1496. [Emitted] //SuperCall
  1497. public static Exception/*!*/ MakeTopLevelSuperException() {
  1498. return new MissingMethodException("super called outside of method");
  1499. }
  1500. [Emitted] //SuperCallAction
  1501. public static Exception/*!*/ MakeMissingSuperException(string/*!*/ name) {
  1502. return new MissingMethodException(String.Format("super: no superclass method `{0}'", name));
  1503. }
  1504. [Emitted]
  1505. public static Exception/*!*/ MakeVirtualClassInstantiatedError() {
  1506. return RubyExceptions.CreateTypeError("can't create instance of virtual class");
  1507. }
  1508. [Emitted]
  1509. public static Exception/*!*/ MakeAbstractMethodCalledError(RuntimeMethodHandle/*!*/ method) {
  1510. return new NotImplementedException(String.Format("Abstract method `{0}' not implemented", MethodInfo.GetMethodFromHandle(method)));
  1511. }
  1512. [Emitted]
  1513. public static Exception/*!*/ MakeInvalidArgumentTypesError(string/*!*/ methodName) {
  1514. // TODO:
  1515. return new ArgumentException(String.Format("wrong number or type of arguments for `{0}'", methodName));
  1516. }
  1517. [Emitted]
  1518. public static Exception/*!*/ MakeTypeConversionError(RubyContext/*!*/ context, object value, Type/*!*/ type) {
  1519. return RubyExceptions.CreateTypeConversionError(context.GetClassDisplayName(value), context.GetTypeName(type, true));
  1520. }
  1521. [Emitted]
  1522. public static Exception/*!*/ MakeAmbiguousMatchError(string/*!*/ message) {
  1523. // TODO:
  1524. return new AmbiguousMatchException(message);
  1525. }
  1526. [Emitted]
  1527. public static Exception/*!*/ MakeAllocatorUndefinedError(RubyClass/*!*/ classObj) {
  1528. return RubyExceptions.CreateAllocatorUndefinedError(classObj);
  1529. }
  1530. [Emitted]
  1531. public static Exception/*!*/ MakeNotClrTypeError(RubyClass/*!*/ classObj) {
  1532. return RubyExceptions.CreateNotClrTypeError(classObj);
  1533. }
  1534. [Emitted]
  1535. public static Exception/*!*/ MakeConstructorUndefinedError(RubyClass/*!*/ classObj) {
  1536. return RubyExceptions.CreateTypeError(String.Format("`{0}' doesn't have a visible CLR constructor",
  1537. classObj.Context.GetTypeName(classObj.TypeTracker.Type, true)
  1538. ));
  1539. }
  1540. [Emitted]
  1541. public static Exception/*!*/ MakeMissingDefaultConstructorError(RubyClass/*!*/ classObj, string/*!*/ initializerOwnerName) {
  1542. return RubyExceptions.CreateMissingDefaultConstructorError(classObj, initializerOwnerName);
  1543. }
  1544. [Emitted]
  1545. public static Exception/*!*/ MakePrivateMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
  1546. return RubyExceptions.CreatePrivateMethodCalled(context, target, methodName);
  1547. }
  1548. [Emitted]
  1549. public static Exception/*!*/ MakeProtectedMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
  1550. return RubyExceptions.CreateProtectedMethodCalled(context, target, methodName);
  1551. }
  1552. [Emitted]
  1553. public static Exception/*!*/ MakeClrProtectedMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
  1554. return new MissingMethodException(
  1555. RubyExceptions.FormatMethodMissingMessage(context, target, methodName, "CLR protected method `{0}' called for {1}; " +
  1556. "CLR protected methods can only be called with a receiver whose class is a Ruby subclass of the class declaring the method")
  1557. );
  1558. }
  1559. [Emitted]
  1560. public static Exception/*!*/ MakeClrVirtualMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
  1561. return new MissingMethodException(
  1562. RubyExceptions.FormatMethodMissingMessage(context, target, methodName, "Virtual CLR method `{0}' called via super from {1}; " +
  1563. "Super calls to virtual CLR methods can only be used in a Ruby subclass of the class declaring the method")
  1564. );
  1565. }
  1566. [Emitted]
  1567. public static Exception/*!*/ MakeImplicitSuperInBlockMethodError() {
  1568. return RubyExceptions.CreateRuntimeError("implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.");
  1569. }
  1570. [Emitted]
  1571. public static Exception/*!*/ MakeMissingMethodError(RubyContext/*!*/ context, object self, string/*!*/ methodName) {
  1572. return RubyExceptions.CreateMethodMissing(context, self, methodName);
  1573. }
  1574. [Emitted]
  1575. public static Exception/*!*/ MakeMissingMemberError(string/*!*/ memberName) {
  1576. return new MissingMemberException(String.Format(CultureInfo.InvariantCulture, "undefined member: `{0}'", memberName));
  1577. }
  1578. #endregion
  1579. #region Ranges
  1580. [Emitted]
  1581. public static Range/*!*/ CreateInclusiveRange(object begin, object end, RubyScope/*!*/ scope, BinaryOpStorage/*!*/ comparisonStorage) {
  1582. return new Range(comparisonStorage, scope.RubyContext, begin, end, false);
  1583. }
  1584. [Emitted]
  1585. public static Range/*!*/ CreateExclusiveRange(object begin, object end, RubyScope/*!*/ scope, BinaryOpStorage/*!*/ comparisonStorage) {
  1586. return new Range(comparisonStorage, scope.RubyContext, begin, end, true);
  1587. }
  1588. [Emitted]
  1589. public static Range/*!*/ CreateInclusiveIntegerRange(int begin, int end) {
  1590. return new Range(begin, end, false);
  1591. }
  1592. [Emitted]
  1593. public static Range/*!*/ CreateExclusiveIntegerRange(int begin, int end) {
  1594. return new Range(begin, end, true);
  1595. }
  1596. #endregion
  1597. #region Dynamic Operations
  1598. // allocator for struct instances:
  1599. [Emitted]
  1600. public static RubyStruct/*!*/ AllocateStructInstance(RubyClass/*!*/ self) {
  1601. return RubyStruct.Create(self);
  1602. }
  1603. // factory for struct instances:
  1604. [Emitted]
  1605. public static RubyStruct/*!*/ CreateStructInstance(RubyClass/*!*/ self, [NotNull]params object[]/*!*/ items) {
  1606. var result = RubyStruct.Create(self);
  1607. result.SetValues(items);
  1608. return result;
  1609. }
  1610. [Emitted]
  1611. public static DynamicMetaObject/*!*/ GetMetaObject(IRubyObject/*!*/ obj, MSA.Expression/*!*/ parameter) {
  1612. return new RubyObject.Meta(parameter, BindingRestrictions.Empty, obj);
  1613. }
  1614. [Emitted]
  1615. public static RubyMethod/*!*/ CreateBoundMember(object target, RubyMemberInfo/*!*/ info, string/*!*/ name) {
  1616. return new RubyMethod(target, info, name);
  1617. }
  1618. [Emitted]
  1619. public static RubyMethod/*!*/ CreateBoundMissingMember(object target, RubyMemberInfo/*!*/ info, string/*!*/ name) {
  1620. return new RubyMethod.Curried(target, info, name);
  1621. }
  1622. [Emitted]
  1623. public static bool IsClrSingletonRuleValid(RubyContext/*!*/ context, object/*!*/ target, int expectedVersion) {
  1624. RubyInstanceData data;
  1625. RubyClass immediate;
  1626. // TODO: optimize this (we can have a hashtable of singletons per class: Weak(object) => Struct { ImmediateClass, InstanceVariables, Flags }):
  1627. return context.TryGetClrTypeInstanceData(target, out data) && (immediate = data.ImmediateClass) != null && immediate.IsSingletonClass
  1628. && immediate.Version.Method == expectedVersion;
  1629. }
  1630. [Emitted]
  1631. public static bool IsClrNonSingletonRuleValid(RubyContext/*!*/ context, object/*!*/ target, VersionHandle/*!*/ versionHandle, int expectedVersion) {
  1632. RubyInstanceData data;
  1633. RubyClass immediate;
  1634. return versionHandle.Method == expectedVersion
  1635. // TODO: optimize this (we can have a hashtable of singletons per class: Weak(object) => Struct { ImmediateClass, InstanceVariables, Flags }):
  1636. && !(context.TryGetClrTypeInstanceData(target, out data) && (immediate = data.ImmediateClass) != null && immediate.IsSingletonClass);
  1637. }
  1638. // super call condition
  1639. [Emitted]
  1640. public static object GetSuperCallTarget(RubyScope/*!*/ scope, int targetId) {
  1641. while (true) {
  1642. switch (scope.Kind) {
  1643. case ScopeKind.Method:
  1644. return targetId == 0 ? scope.SelfObject : NeedsUpdate;
  1645. case ScopeKind.BlockMethod:
  1646. return targetId == ((RubyBlockScope)scope).BlockFlowControl.Proc.Method.Id ? scope.SelfObject : NeedsUpdate;
  1647. case ScopeKind.TopLevel:
  1648. // This method is only called if there was method or block-method scope in lexical scope chain.
  1649. // Once there is it cannot be undone. It can only be shadowed by a block scope that became block-method scope, or
  1650. // a block-method scope's target-id can be changed.
  1651. throw Assert.Unreachable;
  1652. }
  1653. scope = scope.Parent;
  1654. }
  1655. }
  1656. // super call condition
  1657. [Emitted]
  1658. public static bool IsSuperOutOfMethodScope(RubyScope/*!*/ scope) {
  1659. while (true) {
  1660. switch (scope.Kind) {
  1661. case ScopeKind.Method:
  1662. case ScopeKind.BlockMethod:
  1663. return false;
  1664. case ScopeKind.TopLevel:
  1665. return true;
  1666. }
  1667. scope = scope.Parent;
  1668. }
  1669. }
  1670. #endregion
  1671. #region Conversions
  1672. [Emitted] // ProtocolConversionAction
  1673. public static Proc/*!*/ ToProcValidator(string/*!*/ className, object obj) {
  1674. Proc result = obj as Proc;
  1675. if (result == null) {
  1676. throw RubyExceptions.CreateReturnTypeError(className, "to_proc", "Proc");
  1677. }
  1678. return result;
  1679. }
  1680. // Used for implicit conversions from System.String to MutableString (to_str conversion like).
  1681. [Emitted]
  1682. public static MutableString/*!*/ StringToMutableString(string/*!*/ str) {
  1683. return MutableString.Create(str, RubyEncoding.UTF8);
  1684. }
  1685. // Used for implicit conversions from System.Object to MutableString (to_s conversion like).
  1686. [Emitted]
  1687. public static MutableString/*!*/ ObjectToMutableString(object/*!*/ value) {
  1688. return (value != null) ? MutableString.Create(value.ToString(), RubyEncoding.UTF8) : MutableString.FrozenEmpty;
  1689. }
  1690. [Emitted] // ProtocolConversionAction
  1691. public static MutableString/*!*/ ToStringValidator(string/*!*/ className, object obj) {
  1692. MutableString result = obj as MutableString;
  1693. if (result == null) {
  1694. throw RubyExceptions.CreateReturnTypeError(className, "to_str", "String");
  1695. }
  1696. return result;
  1697. }
  1698. [Emitted] // ProtocolConversionAction
  1699. public static string/*!*/ ToSymbolValidator(string/*!*/ className, object obj) {
  1700. var str = obj as MutableString;
  1701. if (str == null) {
  1702. throw RubyExceptions.CreateReturnTypeError(className, "to_str", "String");
  1703. }
  1704. return str.ConvertToString();
  1705. }
  1706. [Emitted] // ProtocolConversionAction
  1707. public static string/*!*/ ConvertSymbolToClrString(RubySymbol/*!*/ value) {
  1708. return value.ToString();
  1709. }
  1710. [Emitted] // ProtocolConversionAction
  1711. public static string/*!*/ ConvertRubySymbolToClrString(RubyContext/*!*/ context, int value) {
  1712. context.ReportWarning("do not use Fixnums as Symbols");
  1713. RubySymbol result = context.FindSymbol(value);
  1714. if (result != null) {
  1715. return result.ToString();
  1716. } else {
  1717. throw RubyExceptions.CreateArgumentError(String.Format("{0} is not a symbol", value));
  1718. }
  1719. }
  1720. [Emitted] // ProtocolConversionAction
  1721. public static string/*!*/ ConvertMutableStringToClrString(MutableString/*!*/ value) {
  1722. return value.ConvertToString();
  1723. }
  1724. [Emitted] // ProtocolConversionAction
  1725. public static MutableString/*!*/ ConvertSymbolToMutableString(RubySymbol/*!*/ value) {
  1726. // TODO: this is used for DefaultProtocol conversions; we might avoid clonning in some (many?) cases
  1727. return value.String.Clone();
  1728. }
  1729. [Emitted] // ProtocolConversionAction
  1730. public static RubyRegex/*!*/ ToRegexValidator(string/*!*/ className, object obj) {
  1731. return new RubyRegex(RubyRegex.Escape(ToStringValidator(className, obj)), RubyRegexOptions.NONE);
  1732. }
  1733. [Emitted] // ProtocolConversionAction
  1734. public static IList/*!*/ ToArrayValidator(string/*!*/ className, object obj) {
  1735. var result = obj as IList;
  1736. if (result == null) {
  1737. throw RubyExceptions.CreateReturnTypeError(className, "to_ary", "Array");
  1738. }
  1739. return result;
  1740. }
  1741. [Emitted] // ProtocolConversionAction
  1742. public static IList/*!*/ ToAValidator(string/*!*/ className, object obj) {
  1743. var result = obj as IList;
  1744. if (result == null) {
  1745. throw RubyExceptions.CreateReturnTypeError(className, "to_a", "Array");
  1746. }
  1747. return result;
  1748. }
  1749. [Emitted] // ProtocolConversionAction
  1750. public static IDictionary<object, object>/*!*/ ToHashValidator(string/*!*/ className, object obj) {
  1751. var result = obj as IDictionary<object, object>;
  1752. if (result == null) {
  1753. throw RubyExceptions.CreateReturnTypeError(className, "to_hash", "Hash");
  1754. }
  1755. return result;
  1756. }
  1757. private static int ToIntValidator(string/*!*/ className, string/*!*/ targetType, object obj) {
  1758. if (obj is int) {
  1759. return (int)obj;
  1760. }
  1761. var bignum = obj as BigInteger;
  1762. if ((object)bignum != null) {
  1763. int fixnum;
  1764. if (bignum.AsInt32(out fixnum)) {
  1765. return fixnum;
  1766. }
  1767. throw RubyExceptions.CreateRangeError("bignum too big to convert into {0}", targetType);
  1768. }
  1769. throw RubyExceptions.CreateReturnTypeError(className, "to_int", "Integer");
  1770. }
  1771. [Emitted] // ProtocolConversionAction
  1772. public static int ToFixnumValidator(string/*!*/ className, object obj) {
  1773. return ToIntValidator(className, "Fixnum", obj);
  1774. }
  1775. [Emitted] // ProtocolConversionAction
  1776. public static Byte ToByteValidator(string/*!*/ className, object obj) {
  1777. return Converter.ToByte(ToIntValidator(className, "System::Byte", obj));
  1778. }
  1779. [Emitted] // ProtocolConversionAction
  1780. public static SByte ToSByteValidator(string/*!*/ className, object obj) {
  1781. return Converter.ToSByte(ToIntValidator(className, "System::SByte", obj));
  1782. }
  1783. [Emitted] // ProtocolConversionAction
  1784. public static Int16 ToInt16Validator(string/*!*/ className, object obj) {
  1785. return Converter.ToInt16(ToIntValidator(className, "System::Int16", obj));
  1786. }
  1787. [Emitted] // ProtocolConversionAction
  1788. public static UInt16 ToUInt16Validator(string/*!*/ className, object obj) {
  1789. return Converter.ToUInt16(ToIntValidator(className, "System::UInt16", obj));
  1790. }
  1791. [Emitted] // ProtocolConversionAction
  1792. public static UInt32 ToUInt32Validator(string/*!*/ className, object obj) {
  1793. if (obj is int) {
  1794. return Converter.ToUInt32((int)obj);
  1795. }
  1796. var bignum = obj as BigInteger;
  1797. if ((object)bignum != null) {
  1798. return Converter.ToUInt32(bignum);
  1799. }
  1800. throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
  1801. }
  1802. [Emitted] // ProtocolConversionAction
  1803. public static Int64 ToInt64Validator(string/*!*/ className, object obj) {
  1804. if (obj is int) {
  1805. return (int)obj;
  1806. }
  1807. var bignum = obj as BigInteger;
  1808. if ((object)bignum != null) {
  1809. return Converter.ToInt64(bignum);
  1810. }
  1811. throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
  1812. }
  1813. [Emitted] // ProtocolConversionAction
  1814. public static UInt64 ToUInt64Validator(string/*!*/ className, object obj) {
  1815. if (obj is int) {
  1816. return Converter.ToUInt64((int)obj);
  1817. }
  1818. var bignum = obj as BigInteger;
  1819. if ((object)bignum != null) {
  1820. return Converter.ToUInt64(bignum);
  1821. }
  1822. throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
  1823. }
  1824. [Emitted] // ProtocolConversionAction
  1825. public static BigInteger ToBignumValidator(string/*!*/ className, object obj) {
  1826. if (obj is int) {
  1827. return (int)obj;
  1828. }
  1829. var bignum = obj as BigInteger;
  1830. if ((object)bignum != null) {
  1831. return bignum;
  1832. }
  1833. throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
  1834. }
  1835. [Emitted] // ProtocolConversionAction
  1836. public static IntegerValue ToIntegerValidator(string/*!*/ className, object obj) {
  1837. if (obj is int) {
  1838. return new IntegerValue((int)obj);
  1839. }
  1840. var bignum = obj as BigInteger;
  1841. if ((object)bignum != null) {
  1842. return new IntegerValue(bignum);
  1843. }
  1844. throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
  1845. }
  1846. [Emitted] // ProtocolConversionAction
  1847. public static double ToDoubleValidator(string/*!*/ className, object obj) {
  1848. if (obj is double) {
  1849. return (double)obj;
  1850. }
  1851. if (obj is float) {
  1852. return (double)(float)obj;
  1853. }
  1854. throw RubyExceptions.CreateReturnTypeError(className, "to_f", "Float");
  1855. }
  1856. [Emitted] // ProtocolConversionAction
  1857. public static float ToSingleValidator(string/*!*/ className, object obj) {
  1858. if (obj is double) {
  1859. return (float)(double)obj;
  1860. }
  1861. if (obj is float) {
  1862. return (float)obj;
  1863. }
  1864. throw RubyExceptions.CreateReturnTypeError(className, "to_f", "System::Single");
  1865. }
  1866. [Emitted]
  1867. public static double ConvertBignumToFloat(BigInteger/*!*/ value) {
  1868. double result;
  1869. return value.TryToFloat64(out result) ? result : (value.IsNegative() ? Double.NegativeInfinity : Double.PositiveInfinity);
  1870. }
  1871. [Emitted]
  1872. public static double ConvertMutableStringToFloat(RubyContext/*!*/ context, MutableString/*!*/ value) {
  1873. return ConvertStringToFloat(context, value.ConvertToString());
  1874. }
  1875. [Emitted]
  1876. public static double ConvertStringToFloat(RubyContext/*!*/ context, string/*!*/ value) {
  1877. double result;
  1878. bool complete;
  1879. if (Tokenizer.TryParseDouble(value, out result, out complete) && complete) {
  1880. return result;
  1881. }
  1882. throw RubyExceptions.InvalidValueForType(context, value, "Float");
  1883. }
  1884. [Emitted] // ProtocolConversionAction
  1885. public static Exception/*!*/ CreateTypeConversionError(string/*!*/ fromType, string/*!*/ toType) {
  1886. return RubyExceptions.CreateTypeConversionError(fromType, toType);
  1887. }
  1888. [Emitted] // ConvertToFixnumAction
  1889. public static int ConvertBignumToFixnum(BigInteger/*!*/ bignum) {
  1890. int fixnum;
  1891. if (bignum.AsInt32(out fixnum)) {
  1892. return fixnum;
  1893. }
  1894. throw RubyExceptions.CreateRangeError("bignum too big to convert into Fixnum");
  1895. }
  1896. [Emitted] // ConvertDoubleToFixnum
  1897. public static int ConvertDoubleToFixnum(double value) {
  1898. try {
  1899. return checked((int)value);
  1900. } catch (OverflowException) {
  1901. throw RubyExceptions.CreateRangeError(String.Format("float {0} out of range of Fixnum", value));
  1902. }
  1903. }
  1904. [Emitted] // ConvertToSAction
  1905. public static MutableString/*!*/ ToSDefaultConversion(RubyContext/*!*/ context, object target, object converted) {
  1906. return converted as MutableString ?? RubyUtils.ObjectToMutableString(context, target);
  1907. }
  1908. #endregion
  1909. #region Instance variable support
  1910. [Emitted]
  1911. public static object GetInstanceVariable(RubyScope/*!*/ scope, object self, string/*!*/ name) {
  1912. RubyInstanceData data = scope.RubyContext.TryGetInstanceData(self);
  1913. return (data != null) ? data.GetInstanceVariable(name) : null;
  1914. }
  1915. [Emitted]
  1916. public static bool IsDefinedInstanceVariable(RubyScope/*!*/ scope, object self, string/*!*/ name) {
  1917. RubyInstanceData data = scope.RubyContext.TryGetInstanceData(self);
  1918. if (data == null) return false;
  1919. object value;
  1920. return data.TryGetInstanceVariable(name, out value);
  1921. }
  1922. [Emitted]
  1923. public static object SetInstanceVariable(object self, object value, RubyScope/*!*/ scope, string/*!*/ name) {
  1924. scope.RubyContext.SetInstanceVariable(self, name, value);
  1925. return value;
  1926. }
  1927. #endregion
  1928. #region Class Variables
  1929. [Emitted]
  1930. public static object GetClassVariable(RubyScope/*!*/ scope, string/*!*/ name) {
  1931. // owner is the first module in scope:
  1932. RubyModule owner = scope.GetInnerMostModuleForClassVariableLookup();
  1933. return GetClassVariableInternal(owner, name);
  1934. }
  1935. private static object GetClassVariableInternal(RubyModule/*!*/ module, string/*!*/ name) {
  1936. object value;
  1937. if (module.TryResolveClassVariable(name, out value) == null) {
  1938. throw RubyExceptions.CreateNameError(String.Format("uninitialized class variable {0} in {1}", name, module.Name));
  1939. }
  1940. return value;
  1941. }
  1942. [Emitted]
  1943. public static object TryGetClassVariable(RubyScope/*!*/ scope, string/*!*/ name) {
  1944. object value;
  1945. // owner is the first module in scope:
  1946. scope.GetInnerMostModuleForClassVariableLookup().TryResolveClassVariable(name, out value);
  1947. return value;
  1948. }
  1949. [Emitted]
  1950. public static bool IsDefinedClassVariable(RubyScope/*!*/ scope, string/*!*/ name) {
  1951. // owner is the first module in scope:
  1952. RubyModule owner = scope.GetInnerMostModuleForClassVariableLookup();
  1953. object value;
  1954. return owner.TryResolveClassVariable(name, out value) != null;
  1955. }
  1956. [Emitted]
  1957. public static object SetClassVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
  1958. return SetClassVariableInternal(scope.GetInnerMostModuleForClassVariableLookup(), name, value);
  1959. }
  1960. private static object SetClassVariableInternal(RubyModule/*!*/ lexicalOwner, string/*!*/ name, object value) {
  1961. object oldValue;
  1962. RubyModule owner = lexicalOwner.TryResolveClassVariable(name, out oldValue);
  1963. (owner ?? lexicalOwner).SetClassVariable(name, value);
  1964. return value;
  1965. }
  1966. #endregion
  1967. #region Ruby Types
  1968. [Emitted]
  1969. public static string/*!*/ ObjectToString(IRubyObject/*!*/ obj) {
  1970. return RubyUtils.ObjectToMutableString(obj).ToString();
  1971. }
  1972. [Emitted] //RubyTypeBuilder
  1973. public static RubyInstanceData/*!*/ GetInstanceData(ref RubyInstanceData/*!*/ instanceData) {
  1974. if (instanceData == null) {
  1975. Interlocked.CompareExchange(ref instanceData, new RubyInstanceData(), null);
  1976. }
  1977. return instanceData;
  1978. }
  1979. [Emitted]
  1980. public static bool IsObjectFrozen(RubyInstanceData instanceData) {
  1981. return instanceData != null && instanceData.IsFrozen;
  1982. }
  1983. [Emitted]
  1984. public static bool IsObjectTainted(RubyInstanceData instanceData) {
  1985. return instanceData != null && instanceData.IsTainted;
  1986. }
  1987. [Emitted]
  1988. public static bool IsObjectUntrusted(RubyInstanceData instanceData) {
  1989. return instanceData != null && instanceData.IsUntrusted;
  1990. }
  1991. [Emitted]
  1992. public static void FreezeObject(ref RubyInstanceData instanceData) {
  1993. RubyOps.GetInstanceData(ref instanceData).Freeze();
  1994. }
  1995. [Emitted]
  1996. public static void SetObjectTaint(ref RubyInstanceData instanceData, bool value) {
  1997. RubyOps.GetInstanceData(ref instanceData).IsTainted = value;
  1998. }
  1999. [Emitted]
  2000. public static void SetObjectTrustiness(ref RubyInstanceData instanceData, bool untrusted) {
  2001. RubyOps.GetInstanceData(ref instanceData).IsUntrusted = untrusted;
  2002. }
  2003. #if !SILVERLIGHT // serialization
  2004. [Emitted(UseReflection = true)] //RubyTypeBuilder
  2005. public static void DeserializeObject(out RubyInstanceData/*!*/ instanceData, out RubyClass/*!*/ immediateClass, SerializationInfo/*!*/ info) {
  2006. immediateClass = (RubyClass)info.GetValue(RubyUtils.SerializationInfoClassKey, typeof(RubyClass));
  2007. RubyInstanceData newInstanceData = null;
  2008. foreach (SerializationEntry entry in info) {
  2009. if (entry.Name.StartsWith("@", StringComparison.Ordinal)) {
  2010. if (newInstanceData == null) {
  2011. newInstanceData = new RubyInstanceData();
  2012. }
  2013. newInstanceData.SetInstanceVariable(entry.Name, entry.Value);
  2014. }
  2015. }
  2016. instanceData = newInstanceData;
  2017. }
  2018. [Emitted(UseReflection = true)] //RubyTypeBuilder
  2019. public static void SerializeObject(RubyInstanceData instanceData, RubyClass/*!*/ immediateClass, SerializationInfo/*!*/ info) {
  2020. info.AddValue(RubyUtils.SerializationInfoClassKey, immediateClass, typeof(RubyClass));
  2021. if (instanceData != null) {
  2022. string[] instanceNames = instanceData.GetInstanceVariableNames();
  2023. foreach (string name in instanceNames) {
  2024. object value;
  2025. if (!instanceData.TryGetInstanceVariable(name, out value)) {
  2026. value = null;
  2027. }
  2028. info.AddValue(name, value, typeof(object));
  2029. }
  2030. }
  2031. }
  2032. #endif
  2033. #endregion
  2034. #region Delegates, Events
  2035. /// <summary>
  2036. /// Hooks up an event to call a proc at hand.
  2037. /// EventInfo is passed in as object since it is an internal type.
  2038. /// </summary>
  2039. [Emitted]
  2040. public static Proc/*!*/ HookupEvent(RubyEventInfo/*!*/ eventInfo, object/*!*/ target, Proc/*!*/ proc) {
  2041. eventInfo.Tracker.AddHandler(target, proc, eventInfo.Context.DelegateCreator);
  2042. return proc;
  2043. }
  2044. [Emitted]
  2045. public static RubyEvent/*!*/ CreateEvent(RubyEventInfo/*!*/ eventInfo, object/*!*/ target, string/*!*/ name) {
  2046. return new RubyEvent(target, eventInfo, name);
  2047. }
  2048. [Emitted]
  2049. public static Delegate/*!*/ CreateDelegateFromProc(Type/*!*/ type, Proc proc) {
  2050. if (proc == null) {
  2051. throw RubyExceptions.NoBlockGiven();
  2052. }
  2053. BlockParam bp = CreateBfcForProcCall(proc);
  2054. return proc.LocalScope.RubyContext.DelegateCreator.GetDelegate(bp, type);
  2055. }
  2056. [Emitted]
  2057. public static Delegate/*!*/ CreateDelegateFromMethod(Type/*!*/ type, RubyMethod/*!*/ method) {
  2058. return method.Info.Context.DelegateCreator.GetDelegate(method, type);
  2059. }
  2060. #endregion
  2061. #region Tuples
  2062. // Instance variable storages needs MT<n> to be a subclass of MT<m> for all n > m.
  2063. // This property is not true if we used DynamicNull as a generic argument for arities that are not powers of 2 like MutableTuple.MakeTupleType does.
  2064. // We make this property true for all simple tuples, thus instance variable storages can only use tuples of size <= 128.
  2065. internal static Type/*!*/ MakeObjectTupleType(int fieldCount) {
  2066. if (fieldCount <= MutableTuple.MaxSize) {
  2067. if (fieldCount <= 1) {
  2068. return typeof(MutableTuple<object>);
  2069. } else if (fieldCount <= 2) {
  2070. return typeof(MutableTuple<object, object>);
  2071. } else if (fieldCount <= 4) {
  2072. return typeof(MutableTuple<object, object, object, object>);
  2073. } else if (fieldCount <= 8) {
  2074. return typeof(MutableTuple<object, object, object, object, object, object, object, object>);
  2075. } else if (fieldCount <= 16) {
  2076. return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
  2077. } else if (fieldCount <= 32) {
  2078. return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
  2079. } else if (fieldCount <= 64) {
  2080. return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
  2081. } else {
  2082. return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
  2083. }
  2084. }
  2085. Type[] types = new Type[fieldCount];
  2086. for (int i = 0; i < types.Length; i++) {
  2087. types[i] = typeof(object);
  2088. }
  2089. return MutableTuple.MakeTupleType(types);
  2090. }
  2091. internal static MutableTuple/*!*/ CreateObjectTuple(int fieldCount) {
  2092. Debug.Assert(fieldCount <= MutableTuple.MaxSize);
  2093. if (fieldCount <= 1) {
  2094. return new MutableTuple<object>();
  2095. } else if (fieldCount <= 2) {
  2096. return new MutableTuple<object, object>();
  2097. } else if (fieldCount <= 4) {
  2098. return new MutableTuple<object, object, object, object>();
  2099. } else if (fieldCount <= 8) {
  2100. return new MutableTuple<object, object, object, object, object, object, object, object>();
  2101. } else if (fieldCount <= 16) {
  2102. return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
  2103. } else if (fieldCount <= 32) {
  2104. return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
  2105. } else if (fieldCount <= 64) {
  2106. return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
  2107. } else {
  2108. return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
  2109. }
  2110. }
  2111. #endregion
  2112. [Emitted]
  2113. public static void X(string marker) {
  2114. }
  2115. [Emitted]
  2116. public static object CreateDefaultInstance() {
  2117. // nop (stub)
  2118. return null;
  2119. }
  2120. }
  2121. }