PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/Ruby/ClassInitGenerator/Libraries/LibraryDef.cs

http://github.com/IronLanguages/main
C# | 1404 lines | 1077 code | 248 blank | 79 comment | 316 complexity | 0d05e555f28800311620da17ecc08960 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

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

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.CodeDom.Compiler;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.Reflection;
  21. using System.Runtime.InteropServices;
  22. using System.Text;
  23. using IronRuby;
  24. using IronRuby.Builtins;
  25. using IronRuby.Runtime;
  26. using IronRuby.Runtime.Calls;
  27. using Microsoft.Scripting.Utils;
  28. internal class LibraryDef {
  29. private bool Builtins { get { return _namespace == typeof(RubyClass).Namespace; } }
  30. public static readonly string/*!*/ TypeAction = "Action";
  31. public static readonly string/*!*/ TypeFunction = "Func";
  32. public static readonly string/*!*/ TypeDelegate = TypeName(typeof(Delegate));
  33. public static readonly string/*!*/ TypeRubyModule = TypeName(typeof(RubyModule));
  34. public static readonly string/*!*/ TypeRubyClass = TypeName(typeof(RubyClass));
  35. public static readonly string/*!*/ TypeActionOfRubyModule = TypeName(typeof(Action<RubyModule>));
  36. public static readonly string/*!*/ TypeLibraryInitializer = TypeName(typeof(LibraryInitializer));
  37. public static readonly string/*!*/ TypeRubyLibraryAttribute = TypeName(typeof(RubyLibraryAttribute));
  38. // TODO: store defs into LibraryDef
  39. private IDictionary<Type, ModuleDef> _moduleDefs = new SortedDictionary<Type, ModuleDef>(new TypeComparer()); // sorted to improve diff quality
  40. private IDictionary<Type, ModuleDef> _traits = new Dictionary<Type, ModuleDef>();
  41. private Dictionary<Type, string> _moduleRefs = new Dictionary<Type, string>();
  42. private Dictionary<Type, string> _classRefs = new Dictionary<Type, string>();
  43. public readonly string/*!*/ _namespace;
  44. public readonly string/*!*/ _initializerName;
  45. public bool AnyErrors;
  46. private IndentedTextWriter _output;
  47. #region Definitions
  48. public LibraryDef(string/*!*/ ns) {
  49. _namespace = ns;
  50. _initializerName = LibraryInitializer.GetTypeName(ns);
  51. }
  52. private class TypeRef {
  53. public ModuleDef Definition;
  54. public Type Type;
  55. public string RefName;
  56. public TypeRef(Type type) {
  57. Type = type;
  58. RefName = null;
  59. Definition = null;
  60. }
  61. public TypeRef(ModuleDef def, Type type, string refName) {
  62. Type = type;
  63. RefName = refName;
  64. Definition = def;
  65. }
  66. }
  67. private struct MixinRef {
  68. public readonly TypeRef/*!*/ Module;
  69. public readonly bool Copy;
  70. public MixinRef(TypeRef/*!*/ module, bool copy) {
  71. Module = module;
  72. Copy = copy;
  73. }
  74. }
  75. private enum ModuleKind {
  76. Module,
  77. Singleton,
  78. Class
  79. }
  80. private enum HiddenMethod {
  81. ClrInvisible,
  82. Undefined
  83. }
  84. private class ModuleDef {
  85. // Full Ruby name (e.g. "IronRuby::Clr::String")
  86. public string/*!*/ QualifiedName;
  87. // Name of the constant defined within declaring module (e.g. "String")
  88. public string/*!*/ SimpleName;
  89. // Full Ruby name with '::' replaced by '__' (e.g. "IronRuby__Clr__String").
  90. public string/*!*/ Id;
  91. // The trait only extends an existing CLR type, it doesn't define/reopen a Ruby module.
  92. public bool IsExtension;
  93. // Defines an Exception class.
  94. public bool IsException;
  95. // Aliases for the module (constants defined in the declaring type).
  96. public List<string>/*!*/ Aliases = new List<string>();
  97. // The type declaring Ruby methods:
  98. public Type/*!*/ Trait;
  99. // Type type being extended by trait (same as Trait for non-extension classes):
  100. public Type/*!*/ Extends;
  101. // If non-null, the declaring Ruby module is specified here and is different from the declaring CLR type.
  102. // Target declaration must be within the same library.
  103. public Type DefineIn;
  104. public IDictionary<string, MethodDef>/*!*/ InstanceMethods = new SortedDictionary<string, MethodDef>();
  105. public IDictionary<string, MethodDef>/*!*/ ClassMethods = new SortedDictionary<string, MethodDef>();
  106. public IDictionary<string, ConstantDef>/*!*/ Constants = new SortedDictionary<string, ConstantDef>();
  107. public IDictionary<string, HiddenMethod>/*!*/ HiddenInstanceMethods = new SortedDictionary<string, HiddenMethod>();
  108. public IDictionary<string, HiddenMethod>/*!*/ HiddenClassMethods = new SortedDictionary<string, HiddenMethod>();
  109. // { new_name -> old_name }
  110. public IDictionary<string, string>/*!*/ ClassMethodAliases = new SortedDictionary<string, string>();
  111. public IDictionary<string, string>/*!*/ InstanceMethodAliases = new SortedDictionary<string, string>();
  112. public List<MethodInfo>/*!*/ Factories = new List<MethodInfo>();
  113. public List<MixinRef>/*!*/ Mixins = new List<MixinRef>();
  114. public ModuleKind Kind;
  115. public bool HasCopyInclusions;
  116. public TypeRef Super; // non-null for all classes except for object
  117. // Non-null for modules nested in other Ruby modules.
  118. // Doesn't influence dependency, constants for nested types are defined after all classes have been defined.
  119. public ModuleDef DeclaringModule;
  120. public string DeclaringTypeRef;
  121. // Whether the module is defined on Object, so we need to set a constant on Object.
  122. public bool IsGlobal;
  123. // Variable name where definition is stored.
  124. public string Reference;
  125. public string Definition;
  126. public string BuildConfig;
  127. public RubyCompatibility Compatibility;
  128. public ModuleRestrictions Restrictions;
  129. private int _dependencyOrder;
  130. /// <summary>
  131. /// Indicates the order that things should be generated so mixins/subclasses are always definied before
  132. /// they are referenced. Each module gets the value of the max of all the types it refers to
  133. /// plus one.
  134. /// </summary>
  135. public int DependencyOrder {
  136. get {
  137. if (_dependencyOrder == 0) {
  138. if (Super != null && Super.Definition != null) {
  139. _dependencyOrder = System.Math.Max(Super.Definition.DependencyOrder, _dependencyOrder);
  140. }
  141. foreach (MixinRef mixin in Mixins) {
  142. if (mixin.Module.Definition != null) {
  143. _dependencyOrder = System.Math.Max(mixin.Module.Definition.DependencyOrder, _dependencyOrder);
  144. }
  145. }
  146. _dependencyOrder += 1;
  147. }
  148. return _dependencyOrder;
  149. }
  150. }
  151. public bool IsPrimitive {
  152. get {
  153. return !IsExtension && (
  154. QualifiedName == RubyClass.MainSingletonName
  155. || Extends == typeof(BasicObject)
  156. || Extends == typeof(Kernel)
  157. || Extends == typeof(Object)
  158. || Extends == typeof(RubyClass)
  159. || Extends == typeof(RubyModule)
  160. );
  161. }
  162. }
  163. public bool HasInstanceInitializer {
  164. get {
  165. return InstanceMethods.Count > 0 || HiddenInstanceMethods.Count > 0 || InstanceMethodAliases.Count > 0
  166. || HasCopyInclusions || IsPrimitive;
  167. }
  168. }
  169. public bool HasConstantsInitializer {
  170. get { return Constants.Count > 0 || HasCopyInclusions; }
  171. }
  172. public bool HasClassInitializer {
  173. get {
  174. return ClassMethods.Count > 0 || HiddenClassMethods.Count > 0 || ClassMethodAliases.Count > 0
  175. || HasCopyInclusions || IsPrimitive;
  176. }
  177. }
  178. public const string/*!*/ BasicObjectClassRef = "Context.BasicObjectClass";
  179. public const string/*!*/ ObjectClassRef = "Context.ObjectClass";
  180. public const string/*!*/ KernelModuleRef = "Context.KernelModule";
  181. public const string/*!*/ ModuleClassRef = "Context.ModuleClass";
  182. public const string/*!*/ ClassClassRef = "Context.ClassClass";
  183. internal string GetReference(ref int defVariableId) {
  184. if (Reference == null) {
  185. if (Extends == typeof(BasicObject)) {
  186. Reference = BasicObjectClassRef;
  187. } else if (Extends == typeof(Object)) {
  188. Reference = ObjectClassRef;
  189. } else if (Extends == typeof(Kernel)) {
  190. Reference = KernelModuleRef;
  191. } else if (Extends == typeof(RubyModule)) {
  192. Reference = ModuleClassRef;
  193. } else if (Extends == typeof(RubyClass)) {
  194. Reference = ClassClassRef;
  195. } else {
  196. Definition = Reference = "def" + defVariableId++;
  197. }
  198. }
  199. return Reference;
  200. }
  201. public override string/*!*/ ToString() {
  202. return QualifiedName;
  203. }
  204. internal string/*!*/ GetInitializerDelegates() {
  205. return
  206. (HasInstanceInitializer ? "Load" + Id + "_Instance" : "null") + ", " +
  207. (HasClassInitializer ? "Load" + Id + "_Class" : "null") + ", " +
  208. (HasConstantsInitializer ? "Load" + Id + "_Constants" : "null");
  209. }
  210. internal string/*!*/ GetModuleRestrictions() {
  211. return "0x" + Restrictions.ToString("X");
  212. }
  213. }
  214. private class MethodDef {
  215. public string/*!*/ Name;
  216. public List<MethodInfo>/*!*/ Overloads = new List<MethodInfo>();
  217. public string BuildConfig;
  218. public RubyCompatibility Compatibility;
  219. public RubyMethodAttributes/*!*/ Attributes;
  220. public bool IsRuleGenerator {
  221. get {
  222. return Overloads.Count == 1 && Overloads[0].ReturnType == typeof(RuleGenerator) && Overloads[0].GetParameters().Length == 0;
  223. }
  224. }
  225. public override string/*!*/ ToString() {
  226. return Name;
  227. }
  228. }
  229. private class ConstantDef {
  230. public readonly string/*!*/ Name;
  231. public readonly MemberInfo/*!*/ Member;
  232. public readonly string/*!*/ BuildConfig;
  233. public ConstantDef(string/*!*/ name, MemberInfo/*!*/ member, string/*!*/ buildConfig) {
  234. Name = name;
  235. Member = member;
  236. BuildConfig = buildConfig;
  237. }
  238. }
  239. #endregion
  240. private void WriteRubyCompatibilityCheck(RubyCompatibility compatibility) {
  241. if (compatibility != RubyCompatibility.Default) {
  242. _output.WriteLine("if (Context.RubyOptions.Compatibility >= RubyCompatibility.{0}) {{", compatibility.ToString());
  243. }
  244. }
  245. private void WriteRubyCompatibilityCheckEnd(RubyCompatibility compatibility) {
  246. if (compatibility != RubyCompatibility.Default) {
  247. _output.WriteLine("}");
  248. }
  249. }
  250. #region Reflection
  251. public void ReflectTypes(Type[]/*!*/ allTypes) {
  252. foreach (Type trait in allTypes) {
  253. if (trait.Namespace == null || !trait.Namespace.StartsWith(_namespace)) {
  254. continue;
  255. }
  256. object[] attrs;
  257. try {
  258. attrs = trait.GetCustomAttributes(typeof(RubyModuleAttribute), false);
  259. } catch (Exception e) {
  260. LogError("{0}: Invalid attribute value on type: {1}", trait.FullName, e.Message);
  261. continue;
  262. }
  263. foreach (RubyModuleAttribute module in attrs) {
  264. ModuleDef def = new ModuleDef();
  265. RubySingletonAttribute singleton = module as RubySingletonAttribute;
  266. RubyClassAttribute cls = module as RubyClassAttribute;
  267. if (cls != null) {
  268. def.Kind = ModuleKind.Class;
  269. def.IsException = module is RubyExceptionAttribute;
  270. } else if (singleton != null) {
  271. def.Kind = ModuleKind.Singleton;
  272. if (module.Extends != null) {
  273. LogError("{0}: Singleton cannot Extend a type", trait.FullName);
  274. module.Extends = null;
  275. }
  276. } else {
  277. def.Kind = ModuleKind.Module;
  278. }
  279. if (trait == module.Extends) {
  280. LogError("Module cannot extend itself: {0}", trait);
  281. continue;
  282. }
  283. if (module.Extends != null && module.Name == null) {
  284. // extends a CLR type or an existing Ruby library class/module:
  285. def.IsExtension = true;
  286. def.SimpleName = module.Extends.Name.Replace(ReflectionUtils.GenericArityDelimiter, '_');
  287. def.QualifiedName = null;
  288. def.DeclaringModule = null;
  289. def.IsGlobal = false;
  290. } else {
  291. def.IsExtension = false;
  292. def.SimpleName = module.Name ?? trait.Name;
  293. def.QualifiedName = null; // to be filled in later
  294. def.DeclaringModule = null; // to be corrected later for nested modules
  295. def.IsGlobal = true; // to be corrected later for nested modules
  296. }
  297. def.Trait = trait;
  298. def.Extends = (module.Extends != null) ? module.Extends : trait;
  299. def.DefineIn = module.DefineIn;
  300. def.BuildConfig = module.BuildConfig;
  301. def.Compatibility = module.Compatibility;
  302. def.Restrictions = module.GetRestrictions(Builtins);
  303. def.Super = null;
  304. if (cls != null && def.Extends != typeof(BasicObject) && !def.Extends.IsInterface) {
  305. if (cls != null && cls.Inherits != null) {
  306. def.Super = new TypeRef(cls.Inherits);
  307. } else if (!def.IsExtension) {
  308. def.Super = new TypeRef(def.Extends.BaseType);
  309. }
  310. }
  311. def.HasCopyInclusions = false;
  312. foreach (IncludesAttribute includes in trait.GetCustomAttributes(typeof(IncludesAttribute), false)) {
  313. foreach (Type type in includes.Types) {
  314. def.Mixins.Add(new MixinRef(new TypeRef(type), includes.Copy));
  315. }
  316. def.HasCopyInclusions |= includes.Copy;
  317. }
  318. _moduleDefs.Add(def.Extends, def);
  319. _traits.Add(def.Trait, def);
  320. // added Ruby methods and constants:
  321. ReflectMethods(def);
  322. ReflectFieldConstants(def);
  323. ReflectAliases(def);
  324. // hidden CLR methods:
  325. foreach (HideMethodAttribute method in trait.GetCustomAttributes(typeof(HideMethodAttribute), false)) {
  326. var dict = (method.IsStatic) ? def.HiddenClassMethods : def.HiddenInstanceMethods;
  327. if (dict.ContainsKey(method.Name)) {
  328. LogError("Method {0} is already hidden/removed", method.Name);
  329. } else {
  330. dict.Add(method.Name, HiddenMethod.ClrInvisible);
  331. }
  332. }
  333. // undefined methods:
  334. foreach (UndefineMethodAttribute method in trait.GetCustomAttributes(typeof(UndefineMethodAttribute), false)) {
  335. var dict = (method.IsStatic) ? def.HiddenClassMethods : def.HiddenInstanceMethods;
  336. if (dict.ContainsKey(method.Name)) {
  337. LogError("Method {0} is already hidden/removed", method.Name);
  338. } else {
  339. dict.Add(method.Name, HiddenMethod.Undefined);
  340. }
  341. }
  342. // aliased methods:
  343. foreach (AliasMethodAttribute method in trait.GetCustomAttributes(typeof(AliasMethodAttribute), false)) {
  344. var aliasDict = (method.IsStatic) ? def.ClassMethodAliases : def.InstanceMethodAliases;
  345. var hiddenDict = (method.IsStatic) ? def.HiddenClassMethods : def.HiddenInstanceMethods;
  346. if (hiddenDict.ContainsKey(method.NewName)) {
  347. LogError("Cannot alias hidden/removed method {0}", method.NewName);
  348. } else if (aliasDict.ContainsKey(method.NewName)) {
  349. LogError("Duplicate method alias {0} {1}", method.NewName, method.OldName);
  350. } else {
  351. aliasDict.Add(method.NewName, method.OldName);
  352. }
  353. }
  354. }
  355. }
  356. int defVariableId = 1;
  357. // declaring modules, build configurations:
  358. foreach (ModuleDef def in _moduleDefs.Values) {
  359. if (!def.IsExtension) {
  360. if (def.Extends.IsGenericTypeDefinition) {
  361. LogError("Only extension modules or classes can be generic type definitions '{0}'", def.QualifiedName);
  362. }
  363. // finds the inner most Ruby module def containing this module def:
  364. ModuleDef declaringDef = GetDeclaringModuleDef(def);
  365. if (declaringDef != null) {
  366. def.DeclaringModule = declaringDef;
  367. def.IsGlobal = false;
  368. // inherits build config:
  369. if (declaringDef.BuildConfig != null) {
  370. if (def.BuildConfig != null) {
  371. def.BuildConfig = declaringDef.BuildConfig + " && " + def.BuildConfig;
  372. } else {
  373. def.BuildConfig = declaringDef.BuildConfig;
  374. }
  375. }
  376. if (declaringDef.Compatibility != RubyCompatibility.Default) {
  377. def.Compatibility = (RubyCompatibility)Math.Max((int)declaringDef.Compatibility, (int)def.Compatibility);
  378. }
  379. // we will need a reference for setting the constant:
  380. def.DeclaringTypeRef = declaringDef.GetReference(ref defVariableId);
  381. def.GetReference(ref defVariableId);
  382. }
  383. }
  384. if (def.Kind == ModuleKind.Singleton) {
  385. // we need to refer to the singleton object returned from singelton factory:
  386. def.GetReference(ref defVariableId);
  387. }
  388. }
  389. // qualified names, ids:
  390. foreach (ModuleDef def in _moduleDefs.Values) {
  391. SetQualifiedName(def);
  392. if (def.Kind == ModuleKind.Singleton) {
  393. def.Id = "__Singleton_" + def.QualifiedName;
  394. } else {
  395. def.Id = def.QualifiedName.Replace(':', '_');
  396. }
  397. }
  398. // wire-up supers and mixins:
  399. foreach (ModuleDef def in _moduleDefs.Values) {
  400. if (def.Super != null) {
  401. ModuleDef superDef;
  402. if (_moduleDefs.TryGetValue(def.Super.Type, out superDef)) {
  403. // define inheritance relationship:
  404. def.Super.Definition = superDef;
  405. def.Super.RefName = superDef.GetReference(ref defVariableId);
  406. } else {
  407. // define a class ref-variable for the type of the super class:
  408. def.Super.RefName = MakeClassReference(def.Super.Type);
  409. }
  410. } else if (!def.IsExtension && def.Kind == ModuleKind.Class && def.Extends != typeof(BasicObject)) {
  411. LogError("Missing super type for type '{0}'", def.QualifiedName);
  412. }
  413. // wire-up mixins:
  414. foreach (MixinRef mixin in def.Mixins) {
  415. ModuleDef mixinDef;
  416. if (_moduleDefs.TryGetValue(mixin.Module.Type, out mixinDef)) {
  417. // define mixin relationship:
  418. mixin.Module.Definition = mixinDef;
  419. if (!mixin.Copy) {
  420. mixin.Module.RefName = mixinDef.GetReference(ref defVariableId);
  421. }
  422. } else if (!mixin.Copy) {
  423. // define a module ref-variable for the type of the mixin:
  424. mixin.Module.RefName = MakeModuleReference(mixin.Module.Type);
  425. } else {
  426. LogError("Cannot copy-include a mixin not defined in this library ('{0}' includes '{1}')",
  427. def.QualifiedName, mixin.Module.Type
  428. );
  429. }
  430. }
  431. }
  432. // TODO: checks
  433. // - loops in copy-inclusion
  434. }
  435. private void SetQualifiedName(ModuleDef/*!*/ def) {
  436. if (def.QualifiedName == null) {
  437. if (def.IsExtension) {
  438. def.QualifiedName = RubyContext.GetQualifiedNameNoLock(def.Extends, null, true);
  439. } else if (def.DeclaringModule == null) {
  440. def.QualifiedName = def.SimpleName;
  441. } else {
  442. SetQualifiedName(def.DeclaringModule);
  443. def.QualifiedName = def.DeclaringModule.QualifiedName + "::" + def.SimpleName;
  444. }
  445. }
  446. }
  447. private ModuleDef GetDeclaringModuleDef(ModuleDef/*!*/ def) {
  448. ModuleDef declaringDef;
  449. if (def.DefineIn != null) {
  450. if (_traits.TryGetValue(def.DefineIn, out declaringDef)) {
  451. return declaringDef;
  452. }
  453. LogError("Declaring type specified by DeclareIn parameter '{0}' is not Ruby module definition or is in different library", def.DefineIn);
  454. }
  455. Type declaringType = def.Trait.DeclaringType;
  456. while (declaringType != null) {
  457. if (_traits.TryGetValue(declaringType, out declaringDef)) {
  458. return declaringDef;
  459. } else {
  460. declaringType = declaringType.DeclaringType;
  461. }
  462. }
  463. return null;
  464. }
  465. private string/*!*/ MakeModuleReference(Type/*!*/ typeRef) {
  466. string refVariable;
  467. if (!_moduleRefs.TryGetValue(typeRef, out refVariable)) {
  468. refVariable = "moduleRef" + _moduleRefs.Count;
  469. _moduleRefs.Add(typeRef, refVariable);
  470. }
  471. return refVariable;
  472. }
  473. private string/*!*/ MakeClassReference(Type/*!*/ typeRef) {
  474. string refVariable;
  475. if (!_classRefs.TryGetValue(typeRef, out refVariable)) {
  476. refVariable = "classRef" + _classRefs.Count;
  477. _classRefs.Add(typeRef, refVariable);
  478. }
  479. return refVariable;
  480. }
  481. private void ReflectMethods(ModuleDef/*!*/ moduleDef) {
  482. Debug.Assert(moduleDef.Trait != null);
  483. BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
  484. foreach (MethodInfo method in moduleDef.Trait.GetMethods(flags)) {
  485. object[] attrs = method.GetCustomAttributes(typeof(RubyMethodAttribute), false);
  486. if (attrs.Length > 0) {
  487. if (!RequireStatic(method)) continue;
  488. foreach (RubyMethodAttribute attr in attrs) {
  489. MethodDef def;
  490. IDictionary<string, MethodDef> methods =
  491. ((attr.MethodAttributes & RubyMethodAttributes.Instance) != 0) ? moduleDef.InstanceMethods : moduleDef.ClassMethods;
  492. if (!methods.TryGetValue(attr.Name, out def)) {
  493. def = new MethodDef();
  494. def.Name = attr.Name;
  495. def.Attributes = attr.MethodAttributes;
  496. if (Builtins) {
  497. def.Attributes |= RubyMethodAttributes.NoEvent;
  498. }
  499. def.BuildConfig = attr.BuildConfig;
  500. def.Compatibility = attr.Compatibility;
  501. methods.Add(attr.Name, def);
  502. }
  503. def.Overloads.Add(method);
  504. }
  505. }
  506. if (method.IsDefined(typeof(RubyConstructorAttribute), false)) {
  507. if (!RequireStatic(method)) continue;
  508. moduleDef.Factories.Add(method);
  509. }
  510. if (method.IsDefined(typeof(RubyConstantAttribute), false)) {
  511. if (!RequireStatic(method)) continue;
  512. var parameters = method.GetParameters();
  513. if (parameters.Length != 1 || !parameters[0].ParameterType.IsAssignableFrom(typeof(RubyModule)) ||
  514. parameters[0].Attributes != ParameterAttributes.None) {
  515. LogError("Method that defines a constant must take a single parameter of type RubyModule: '{0}'",
  516. ReflectionUtils.FormatSignature(new StringBuilder(), method));
  517. }
  518. ReflectConstants(moduleDef, method);
  519. }
  520. }
  521. VerifyMethods(moduleDef);
  522. }
  523. private void VerifyMethods(ModuleDef/*!*/ moduleDef) {
  524. foreach (var methodDef in moduleDef.InstanceMethods.Values) {
  525. VerifyMethod(moduleDef, methodDef.Overloads, methodDef, true);
  526. }
  527. foreach (var methodDef in moduleDef.ClassMethods.Values) {
  528. VerifyMethod(moduleDef, methodDef.Overloads, methodDef, false);
  529. }
  530. VerifyFactory(moduleDef, moduleDef.Factories);
  531. }
  532. private void VerifyFactory(ModuleDef/*!*/ moduleDef, IList<MethodInfo>/*!*/ overloads) {
  533. VerifyMethod(moduleDef, overloads, null, false);
  534. }
  535. private void VerifyMethod(ModuleDef/*!*/ moduleDef, IList<MethodInfo>/*!*/ overloads, MethodDef methodDef, bool isInstance) {
  536. foreach (var overload in overloads) {
  537. var parameterInfos = overload.GetParameters();
  538. if (overload.ReturnType == typeof(RuleGenerator)) {
  539. if (parameterInfos.Length != 0) {
  540. LogMethodError("RuleGenerator must be parameterless", methodDef, overload);
  541. }
  542. if (overloads.Count != 1) {
  543. LogMethodError("RuleGenerator must have no overloads", methodDef, overload);
  544. }
  545. } else {
  546. bool hasContext = false;
  547. bool hasBlock = false;
  548. bool hasSelf = false;
  549. int storageCount = 0;
  550. for (int i = 0; i < parameterInfos.Length; i++) {
  551. if (parameterInfos[i].ParameterType.IsByRef) {
  552. LogMethodError("has ref/out parameter", methodDef, overload);
  553. }
  554. var type = parameterInfos[i].ParameterType;
  555. if (type.IsSubclassOf(typeof(RubyCallSiteStorage))) {
  556. if (hasSelf || hasContext || hasBlock) {
  557. LogMethodError("RubyCallSiteStorage must precede all other parameters", methodDef, overload);
  558. }
  559. storageCount++;
  560. } else if (type == typeof(RubyContext) || type == typeof(RubyScope)) {
  561. if (hasContext) {
  562. LogMethodError("has multiple context parameters", methodDef, overload);
  563. }
  564. if (i - storageCount != 0) {
  565. LogMethodError("Context parameter must be the first parameter following optional RubyCallSiteStorage", methodDef, overload);
  566. }
  567. hasContext = true;
  568. } else if (type == typeof(BlockParam)) {
  569. if (hasBlock) {
  570. LogMethodError("has multiple block parameters.", methodDef, overload);
  571. }
  572. // TODO: sites
  573. if (hasContext && i - storageCount != 1) {
  574. LogMethodError("Block parameter must be the first parameter after context parameter", methodDef, overload);
  575. }
  576. if (!hasContext && i - storageCount != 0) {
  577. LogMethodError("Block parameter must be the first parameter following optional RubyCallSiteStorage", methodDef, overload);
  578. }
  579. // TODO: we should detect a call to the BlockParam.Yield:
  580. //if (overload.ReturnType != typeof(object)) {
  581. // LogMethodWarning("A method that yields to a block must return Object.", methodDef, overload);
  582. //}
  583. hasBlock = true;
  584. } else if (!hasSelf) {
  585. // self
  586. if (isInstance) {
  587. Debug.Assert(methodDef != null);
  588. // TODO:
  589. //if (parameterInfos[i].Name != "self") {
  590. // LogMethodWarning("Self parameter should be named 'self'.", methodDef, overload);
  591. //}
  592. } else {
  593. Type requiredType;
  594. switch (moduleDef.Kind) {
  595. case ModuleKind.Module: requiredType = typeof(RubyModule); break;
  596. case ModuleKind.Singleton:
  597. case ModuleKind.Class: requiredType = typeof(RubyClass); break;
  598. default: throw Assert.Unreachable;
  599. }
  600. if (!type.IsAssignableFrom(requiredType)) {
  601. LogMethodError("Invalid type of self parameter: it must be assignable from '{0}'.", methodDef, overload, requiredType);
  602. }
  603. if (parameterInfos[i].Name != "self") {
  604. LogMethodError("Self parameter should be named 'self'.", methodDef, overload);
  605. }
  606. }
  607. hasSelf = true;
  608. }
  609. }
  610. if (!hasSelf) {
  611. LogMethodError("Missing self parameter", methodDef, overload);
  612. }
  613. }
  614. }
  615. }
  616. private void ReflectFieldConstants(ModuleDef/*!*/ moduleDef) {
  617. Debug.Assert(moduleDef.Trait != null);
  618. BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
  619. foreach (FieldInfo field in moduleDef.Trait.GetFields(flags)) {
  620. ReflectConstants(moduleDef, field);
  621. }
  622. }
  623. private void ReflectConstants(ModuleDef/*!*/ moduleDef, MemberInfo/*!*/ member) {
  624. Debug.Assert(member is MethodInfo || member is FieldInfo);
  625. foreach (RubyConstantAttribute attr in member.GetCustomAttributes(typeof(RubyConstantAttribute), false)) {
  626. string name = attr.Name ?? member.Name;
  627. ConstantDef existing;
  628. if (moduleDef.Constants.TryGetValue(name, out existing)) {
  629. LogError("Constant '{0}' defined by multiple members: '{1}' and '{2}'", name, existing.Member.Name, member.Name);
  630. continue;
  631. }
  632. if (String.IsNullOrEmpty(name) || name[0] < 'A' && name[0] > 'Z') {
  633. LogError("Invalid constant name: '{0}' ({1}::{2})", name, existing.Member.DeclaringType.FullName, existing.Member.Name);
  634. continue;
  635. }
  636. Debug.Assert(attr.Compatibility == RubyCompatibility.Default);
  637. moduleDef.Constants.Add(name, new ConstantDef(name, member, attr.BuildConfig));
  638. }
  639. }
  640. private void ReflectAliases(ModuleDef/*!*/ moduleDef) {
  641. // TODO: check for duplicates (in general in the scope of dll)
  642. foreach (RubyConstantAttribute attr in moduleDef.Trait.GetCustomAttributes(typeof(RubyConstantAttribute), false)) {
  643. if (attr.Name == null) {
  644. LogError("Constant alias for module/class must have a name (type '{0}')", moduleDef.Trait.FullName);
  645. }
  646. if (moduleDef.Aliases.IndexOf(attr.Name) != -1) {
  647. LogError("Duplicate module/class alias '{0}' (type '{1}')", attr.Name, moduleDef.Trait.FullName);
  648. }
  649. moduleDef.Aliases.Add(attr.Name);
  650. }
  651. }
  652. #endregion
  653. private bool RequireStatic(MethodBase/*!*/ method) {
  654. if (!method.IsStatic) {
  655. Console.Error.WriteLine("Instance methods not supported (method '{0}.{1}')", TypeName(method.DeclaringType), method.Name);
  656. AnyErrors = true;
  657. return false;
  658. }
  659. return true;
  660. }
  661. private void LogError(string/*!*/ message, params object[] args) {
  662. Console.Error.Write("Error: ");
  663. Console.Error.WriteLine(message, args);
  664. AnyErrors = true;
  665. }
  666. private void LogWarning(string/*!*/ message, params object[] args) {
  667. Console.Error.Write("Warning: ");
  668. Console.Error.WriteLine(message, args);
  669. }
  670. private void LogMethodError(string/*!*/ message, MethodDef methodDef, MethodBase/*!*/ overload, params object[] args) {
  671. string methodName = (methodDef != null) ? "method \"" + methodDef.Name + '"' : "factory";
  672. Console.Error.WriteLine("Error: {0}: {1}", methodName, String.Format(message, args));
  673. Console.Error.WriteLine(" overload: {0}", ReflectionUtils.FormatSignature(new StringBuilder(), overload));
  674. AnyErrors = true;
  675. }
  676. private void LogMethodWarning(string/*!*/ message, MethodDef methodDef, MethodBase/*!*/ overload, params object[] args) {
  677. string methodName = (methodDef != null) ? "method \"" + methodDef.Name + '"' : "factory";
  678. Console.Error.WriteLine("Warning: {0}: {1}", methodName, String.Format(message, args));
  679. Console.Error.WriteLine(" overload: {0}", ReflectionUtils.FormatSignature(new StringBuilder(), overload));
  680. }
  681. #region Code Generation
  682. public void GenerateCode(IndentedTextWriter/*!*/ output) {
  683. _output = output;
  684. _output.WriteLine("namespace {0} {{", _namespace);
  685. _output.Indent++;
  686. _output.WriteLine("using System;");
  687. _output.WriteLine("using Microsoft.Scripting.Utils;");
  688. _output.WriteLine("using System.Runtime.InteropServices;");
  689. _output.WriteLine();
  690. _output.WriteLine("public sealed class {0} : {1} {{", _initializerName, TypeLibraryInitializer);
  691. _output.Indent++;
  692. _output.WriteLine("protected override void LoadModules() {");
  693. _output.Indent++;
  694. GenerateModuleRegistrations();
  695. _output.Indent--;
  696. _output.WriteLine("}");
  697. _output.WriteLine();
  698. GenerateTraitInitializations(_moduleDefs);
  699. GenerateExceptionFactories(_moduleDefs);
  700. _output.Indent--;
  701. _output.WriteLine("}");
  702. _output.Indent--;
  703. _output.WriteLine("}");
  704. _output.WriteLine();
  705. }
  706. private void GenerateModuleRegistrations() {
  707. // primitives:
  708. if (Builtins) {
  709. _output.WriteLine("Context.RegisterPrimitives(");
  710. _output.Indent++;
  711. _output.WriteLine("Load{0}_Instance,", RubyClass.MainSingletonName);
  712. _output.WriteLine(_moduleDefs[typeof(BasicObject)].GetInitializerDelegates() + ",");
  713. _output.WriteLine(_moduleDefs[typeof(Kernel)].GetInitializerDelegates() + ",");
  714. _output.WriteLine(_moduleDefs[typeof(Object)].GetInitializerDelegates() + ",");
  715. _output.WriteLine(_moduleDefs[typeof(RubyModule)].GetInitializerDelegates() + ",");
  716. _output.WriteLine(_moduleDefs[typeof(RubyClass)].GetInitializerDelegates());
  717. _output.Indent--;
  718. _output.WriteLine(");");
  719. }
  720. // generate references:
  721. foreach (KeyValuePair<Type, string> moduleRef in _moduleRefs) {
  722. _output.WriteLine("{0} {1} = GetModule(typeof({2}));", TypeRubyModule, moduleRef.Value, TypeName(moduleRef.Key));
  723. }
  724. foreach (KeyValuePair<Type, string> classRef in _classRefs) {
  725. _output.WriteLine("{0} {1} = GetClass(typeof({2}));", TypeRubyClass, classRef.Value, TypeName(classRef.Key));
  726. }
  727. _output.WriteLine();
  728. _output.WriteLine();
  729. // We need to generate these in proper dependency order
  730. // also, we want the sort to be stable to improve the
  731. // quality of the resulting diff of the generated code.
  732. ModuleDef[] worklist = new ModuleDef[_moduleDefs.Count];
  733. _moduleDefs.Values.CopyTo(worklist, 0);
  734. Array.Sort(worklist, delegate(ModuleDef x, ModuleDef y) {
  735. // if the dependency order is the same, fall back to the type name
  736. if (x.DependencyOrder == y.DependencyOrder) {
  737. return x.QualifiedName.CompareTo(y.QualifiedName);
  738. }
  739. return x.DependencyOrder - y.DependencyOrder;
  740. });
  741. // classes:
  742. foreach (ModuleDef def in worklist) {
  743. GenerateModuleRegistration(def);
  744. }
  745. // add constants for non-global nested modules, adds aliases:
  746. foreach (ModuleDef def in worklist) {
  747. if (def.IsGlobal && def.Aliases.Count > 0 || def.DeclaringTypeRef != null) {
  748. if (def.BuildConfig != null) {
  749. _output.WriteLine("#if " + def.BuildConfig);
  750. }
  751. WriteRubyCompatibilityCheck(def.Compatibility);
  752. if (def.IsGlobal) {
  753. GenerateAliases(def, ModuleDef.ObjectClassRef);
  754. } else if (def.DeclaringTypeRef != null) {
  755. GenerateAliases(def, def.DeclaringTypeRef);
  756. GenerateSetConstant(def.DeclaringTypeRef, def.SimpleName, def.Reference);
  757. }
  758. WriteRubyCompatibilityCheckEnd(def.Compatibility);
  759. if (def.BuildConfig != null) {
  760. _output.WriteLine("#endif");
  761. }
  762. }
  763. }
  764. }
  765. private void GenerateSetConstant(string/*!*/ owner, string/*!*/ name, string/*!*/ expression) {
  766. _output.WriteLine("Set{3}Constant({0}, \"{1}\", {2});", owner, name, expression, Builtins ? "Builtin" : null);
  767. }
  768. private void GenerateAliases(ModuleDef/*!*/ def, string/*!*/ ownerRef) {
  769. foreach (string alias in def.Aliases) {
  770. GenerateSetConstant(ownerRef, alias, def.Reference);
  771. }
  772. }
  773. private void GenerateModuleRegistration(ModuleDef/*!*/ def) {
  774. if (def.IsPrimitive) {
  775. _output.WriteLine("// Skipped primitive: {0}", def.QualifiedName);
  776. return;
  777. }
  778. if (def.BuildConfig != null) {
  779. _output.WriteLine("#if " + def.BuildConfig);
  780. }
  781. WriteRubyCompatibilityCheck(def.Compatibility);
  782. switch (def.Kind) {
  783. case ModuleKind.Class:
  784. if (def.Definition != null) {
  785. _output.Write("{0} {1} = ", TypeRubyClass, def.Definition);
  786. }
  787. if (Builtins && !def.IsExtension) {
  788. if (def.QualifiedName == "NilClass") {
  789. _output.Write("Context.NilClass = ");
  790. } else if (def.QualifiedName == "TrueClass") {
  791. _output.Write("Context.TrueClass = ");
  792. } else if (def.QualifiedName == "FalseClass") {
  793. _output.Write("Context.FalseClass = ");
  794. } else if (def.QualifiedName == "Exception") {
  795. _output.Write("Context.ExceptionClass = ");
  796. } else if (def.QualifiedName == "StandardError") {
  797. _output.Write("Context.StandardErrorClass = ");
  798. }
  799. }
  800. #if TODO
  801. string extensionType = "null";
  802. if (def.Trait != def.Extends) {
  803. extensionType = string.Format("typeof({0})", TypeName(def.Trait));
  804. }
  805. pass: extensionType,
  806. #endif
  807. if (def.IsExtension) {
  808. _output.Write("ExtendClass(typeof({0}), {1}, {2}, {3}, ",
  809. TypeName(def.Extends),
  810. def.GetModuleRestrictions(),
  811. def.Super != null ? def.Super.RefName : "null",
  812. def.GetInitializerDelegates()
  813. );
  814. } else {
  815. _output.Write("Define{0}Class(\"{1}\", typeof({2}), {3}, {4}, {5}, ",
  816. def.IsGlobal ? "Global" : "",
  817. def.QualifiedName,
  818. TypeName(def.Extends),
  819. def.GetModuleRestrictions(),
  820. def.Super.RefName,
  821. def.GetInitializerDelegates()
  822. );
  823. }
  824. GenerateInclusions(def, true);
  825. if (def.Factories.Count > 0) {
  826. _output.WriteLine(", ");
  827. GenerateDelegatesListCreation(def.Factories);
  828. } else if (def.IsException) {
  829. _output.WriteLine(", ");
  830. GenerateExceptionFactoryDelegateList(def);
  831. }
  832. _output.WriteLine(");");
  833. break;
  834. case ModuleKind.Module:
  835. if (def.Definition != null) {
  836. _output.Write("{0} {1} = ", TypeRubyModule, def.Definition);
  837. }
  838. if (def.IsExtension) {
  839. _output.Write("ExtendModule(typeof({0}), {1}, {2}, ",
  840. TypeName(def.Extends),
  841. def.GetModuleRestrictions(),
  842. def.GetInitializerDelegates()
  843. );
  844. } else {
  845. _output.Write("Define{0}Module(\"{1}\", typeof({2}), {3}, {4}, ",
  846. def.IsGlobal ? "Global" : "",
  847. def.QualifiedName,
  848. TypeName(def.Extends),
  849. def.GetModuleRestrictions(),
  850. def.GetInitializerDelegates()
  851. );
  852. }
  853. GenerateInclusions(def, false);
  854. _output.WriteLine(");");
  855. break;
  856. case ModuleKind.Singleton:
  857. if (def.Definition != null) {
  858. _output.Write("object {0} = ", def.Definition);
  859. }
  860. _output.Write("DefineSingleton({0}, ", def.GetInitializerDelegates());
  861. GenerateInclusions(def, false);
  862. _output.WriteLine(");");
  863. break;
  864. default:
  865. throw Assert.Unreachable;
  866. }
  867. WriteRubyCompatibilityCheckEnd(def.Compatibility);
  868. if (def.BuildConfig != null) {
  869. _output.WriteLine("#endif");
  870. }
  871. }
  872. private void GenerateInclusions(ModuleDef/*!*/ def, bool makeArray) {
  873. List<string> mixinRefs = new List<string>();
  874. AddMixinRefsRecursive(mixinRefs, def);
  875. if (mixinRefs.Count > 0) {
  876. if (makeArray) {
  877. _output.Write("new {0}[] {{", TypeRubyModule);
  878. }
  879. bool first = true;
  880. foreach (string mixinRef in mixinRefs) {
  881. if (first) {
  882. first = false;
  883. } else {
  884. _output.Write(", ");
  885. }
  886. _output.Write(mixinRef);
  887. }
  888. if (makeArray) {
  889. _output.Write("}");
  890. }
  891. } else {
  892. _output.Write("{0}.EmptyArray", TypeRubyModule);
  893. }
  894. }
  895. private void AddMixinRefsRecursive(List<string>/*!*/ mixinRefs, ModuleDef/*!*/ def) {
  896. foreach (MixinRef mixin in def.Mixins) {
  897. if (mixin.Copy) {
  898. AddMixinRefsRecursive(mixinRefs, mixin.Module.Definition);
  899. } else {
  900. mixinRefs.Add(mixin.Module.RefName);
  901. }
  902. }
  903. }
  904. private void GenerateTraitInitializations(IDictionary<Type, ModuleDef>/*!*/ traitDefs) {
  905. // Sort the items before we generate them to improve diff quality
  906. ModuleDef[] worklist = new ModuleDef[traitDefs.Count];
  907. traitDefs.Values.CopyTo(worklist, 0);
  908. Array.Sort(worklist, (x, y) => x.QualifiedName.CompareTo(y.QualifiedName));
  909. foreach (ModuleDef moduleDef in worklist) {
  910. GenerateTraitInitialization(moduleDef);
  911. }
  912. }
  913. private void GenerateTraitInitialization(ModuleDef/*!*/ moduleDef) {
  914. GenerateConstantsInitialization(moduleDef);
  915. GenerateTraitInitialization(moduleDef, true);
  916. GenerateTraitInitialization(moduleDef, false);
  917. }
  918. private void GenerateTraitInitialization(ModuleDef/*!*/ moduleDef, bool isInstance) {
  919. if (isInstance ? moduleDef.HasInstanceInitializer : moduleDef.HasClassInitializer) {
  920. if (moduleDef.BuildConfig != null) {
  921. _output.WriteLine("#if " + moduleDef.BuildConfig);
  922. }
  923. _output.WriteLine("private static void Load{0}_{2}({1}/*!*/ module) {{", moduleDef.Id, TypeRubyModule, isInstance ? "Instance" : "Class");
  924. _output.Indent++;
  925. GenerateIncludedTraitLoaders(moduleDef, isInstance);
  926. GenerateHiddenMethods(isInstance ? moduleDef.HiddenInstanceMethods : moduleDef.HiddenClassMethods);
  927. GenerateMethods(moduleDef.Trait, isInstance ? moduleDef.InstanceMethods : moduleDef.ClassMethods);
  928. GenerateMethodAliases(isInstance ? moduleDef.InstanceMethodAliases : moduleDef.ClassMethodAliases);
  929. _output.Indent--;
  930. _output.WriteLine("}");
  931. if (moduleDef.BuildConfig != null) {
  932. _output.WriteLine("#endif");
  933. }
  934. _output.WriteLine();
  935. }
  936. }
  937. private void GenerateConstantsInitialization(ModuleDef/*!*/ moduleDef) {
  938. if (moduleDef.HasConstantsInitializer) {
  939. if (moduleDef.BuildConfig != null) {
  940. _output.WriteLine("#if " + moduleDef.BuildConfig);
  941. }
  942. WriteRubyCompatibilityCheck(moduleDef.Compatibility);
  943. _output.WriteLine("private static void Load{0}_Constants({1}/*!*/ module) {{", moduleDef.Id, TypeRubyModule);
  944. _output.Indent++;
  945. GenerateIncludedConstantLoaders(moduleDef);
  946. GenerateConstants(moduleDef);
  947. _output.Indent--;
  948. _output.WriteLine("}");
  949. WriteRubyCompatibilityCheckEnd(moduleDef.Compatibility);
  950. if (moduleDef.BuildConfig != null) {
  951. _output.WriteLine("#endif");
  952. }
  953. _output.WriteLine();
  954. }
  955. }
  956. private void GenerateConstants(ModuleDef/*!*/ moduleDef) {
  957. // add constants on module
  958. foreach (var constantDef in moduleDef.Constants.Values) {
  959. if (constantDef.BuildConfig != null) {
  960. _output.WriteLine("#if " + constantDef.BuildConfig);
  961. }
  962. GenerateSetConstant("module", constantDef.Name, String.Format("{0}.{1}{2}",
  963. TypeName(constantDef.Member.DeclaringType),
  964. constantDef.Member.Name,
  965. constantDef.Member is MethodInfo ? "(module)" : null
  966. ));
  967. if (constantDef.BuildConfig != null) {
  968. _output.WriteLine("#endif");
  969. }
  970. }
  971. _output.WriteLine();
  972. }
  973. private void GenerateIncludedTraitLoaders(ModuleDef/*!*/ moduleDef, bool isInstance) {
  974. foreach (MixinRef mixin in moduleDef.Mixins) {
  975. ModuleDef def = mixin.Module.Definition;
  976. if (mixin.Copy && (isInstance ? def.HasInstanceInitializer : def.HasClassInitializer)) {
  977. _output.WriteLine("Load{0}_{1}(module);", mixin.Module.Definition.Id, isInstance ? "Instance" : "Class");
  978. }
  979. }
  980. }
  981. private void GenerateIncludedConstantLoaders(ModuleDef/*!*/ moduleDef) {
  982. foreach (MixinRef mixin in moduleDef.Mixins) {
  983. ModuleDef def = mixin.Module.Definition;
  984. if (mixin.Copy && def.HasConstantsInitializer) {
  985. _output.WriteLine("Load{0}_Constants(module);", mixin.Module.Definition.Id);
  986. }
  987. }
  988. }
  989. private void GenerateHiddenMethods(IDictionary<string, HiddenMethod>/*!*/ methods) {
  990. foreach (KeyValuePair<string, HiddenMethod> entry in methods) {
  991. if (entry.Value == HiddenMethod.Undefined) {
  992. _output.WriteLine("module.{0}(\"{1}\");",
  993. Builtins ? "UndefineMethodNoEvent" : "UndefineMethod",
  994. entry.Key
  995. );
  996. } else {
  997. _output.WriteLine("module.HideMethod(\"{0}\");", entry.Key);
  998. }
  999. }
  1000. }
  1001. private void GenerateMethodAliases(IDictionary<string, string>/*!*/ aliases) {
  1002. foreach (var alias in aliases) {
  1003. _output.WriteLine("module.AddMethodAlias(\"{0}\", \"{1}\");", alias.Key, alias.Value);
  1004. }
  1005. }
  1006. private void GenerateMethods(Type/*!*/ type, IDictionary<string, MethodDef>/*!*…

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