PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

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

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