PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Dependencies/boo/src/Boo.Lang.Compiler/Steps/GeneratorExpressionProcessor.cs

https://github.com/w4x/boolangstudio
C# | 359 lines | 258 code | 58 blank | 43 comment | 28 complexity | 7cb8efb9faef335e2900e56d55fbfeee MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without modification,
  6. // are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  14. // contributors may be used to endorse or promote products derived from this
  15. // software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  21. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #endregion
  28. namespace Boo.Lang.Compiler.Steps
  29. {
  30. using System;
  31. using System.Collections;
  32. using Boo.Lang.Compiler;
  33. using Boo.Lang.Compiler.Ast;
  34. using Boo.Lang.Compiler.TypeSystem;
  35. class GeneratorExpressionProcessor : AbstractCompilerComponent
  36. {
  37. GeneratorExpression _generator;
  38. BooClassBuilder _enumerable;
  39. BooClassBuilder _enumerator;
  40. Field _current;
  41. Field _enumeratorField;
  42. ForeignReferenceCollector _collector;
  43. IType _sourceItemType;
  44. IType _sourceEnumeratorType;
  45. IType _sourceEnumerableType;
  46. IType _resultItemType;
  47. IType _resultEnumeratorType;
  48. public GeneratorExpressionProcessor(CompilerContext context,
  49. ForeignReferenceCollector collector,
  50. GeneratorExpression node)
  51. {
  52. _collector = collector;
  53. _generator = node;
  54. Initialize(context);
  55. }
  56. public void Run()
  57. {
  58. RemoveReferencedDeclarations();
  59. CreateAnonymousGeneratorType();
  60. }
  61. void RemoveReferencedDeclarations()
  62. {
  63. Hash referencedEntities = _collector.ReferencedEntities;
  64. foreach (Declaration d in _generator.Declarations)
  65. {
  66. referencedEntities.Remove(d.Entity);
  67. }
  68. }
  69. void CreateAnonymousGeneratorType()
  70. {
  71. _enumerable = (BooClassBuilder)_generator["GeneratorClassBuilder"];
  72. // Set up some important types
  73. _sourceItemType = TypeSystemServices.ObjectType;
  74. _sourceEnumeratorType = TypeSystemServices.IEnumeratorType;
  75. _sourceEnumerableType = TypeSystemServices.IEnumerableType;
  76. _resultItemType = (IType)_generator["GeneratorItemType"];
  77. _resultEnumeratorType = TypeSystemServices.IEnumeratorGenericType.GenericInfo.ConstructType(_resultItemType);
  78. _enumerator = _collector.CreateSkeletonClass("Enumerator",_generator.LexicalInfo);
  79. // use a generic enumerator for the source type if possible
  80. _sourceItemType = TypeSystemServices.GetGenericEnumerableItemType(_generator.Iterator.ExpressionType);
  81. if (_sourceItemType != null && _sourceItemType != TypeSystemServices.ObjectType)
  82. {
  83. _sourceEnumerableType = TypeSystemServices.IEnumerableGenericType.GenericInfo.ConstructType(_sourceItemType);
  84. _sourceEnumeratorType = TypeSystemServices.IEnumeratorGenericType.GenericInfo.ConstructType(_sourceItemType);
  85. }
  86. else
  87. {
  88. _sourceItemType = TypeSystemServices.ObjectType;
  89. }
  90. // Add base types
  91. _enumerator.AddBaseType(_resultEnumeratorType);
  92. _enumerator.AddBaseType(TypeSystemServices.Map(typeof(ICloneable)));
  93. _enumerator.AddBaseType(TypeSystemServices.Map(typeof(IDisposable)));
  94. // Add fields
  95. _enumeratorField = _enumerator.AddField("$$enumerator", _sourceEnumeratorType);
  96. _current = _enumerator.AddField("$$current", _resultItemType);
  97. // Add methods
  98. CreateReset();
  99. CreateCurrent();
  100. CreateMoveNext();
  101. CreateClone();
  102. CreateDispose();
  103. EnumeratorConstructorMustCallReset();
  104. _collector.AdjustReferences();
  105. _collector.DeclareFieldsAndConstructor(_enumerable);
  106. CreateGetEnumerator();
  107. _enumerable.ClassDefinition.Members.Add(_enumerator.ClassDefinition);
  108. }
  109. public MethodInvocationExpression CreateEnumerableConstructorInvocation()
  110. {
  111. return _collector.CreateConstructorInvocationWithReferencedEntities(
  112. _enumerable.Entity);
  113. }
  114. void EnumeratorConstructorMustCallReset()
  115. {
  116. Constructor constructor = _enumerator.ClassDefinition.GetConstructor(0);
  117. constructor.Body.Add(CreateMethodInvocation(_enumerator.ClassDefinition, "Reset"));
  118. }
  119. IMethod GetMemberwiseCloneMethod()
  120. {
  121. return TypeSystemServices.Map(
  122. typeof(object).GetMethod("MemberwiseClone",
  123. System.Reflection.BindingFlags.NonPublic|System.Reflection.BindingFlags.Instance));
  124. }
  125. MethodInvocationExpression CreateMethodInvocation(ClassDefinition cd, string name)
  126. {
  127. IMethod method = (IMethod)((Method)cd.Members[name]).Entity;
  128. return CodeBuilder.CreateMethodInvocation(
  129. CodeBuilder.CreateSelfReference(method.DeclaringType),
  130. method);
  131. }
  132. void CreateCurrent()
  133. {
  134. Property property = _enumerator.AddReadOnlyProperty("Current", TypeSystemServices.ObjectType);
  135. property.Getter.Modifiers |= TypeMemberModifiers.Virtual;
  136. property.Getter.Body.Add(
  137. new ReturnStatement(
  138. CodeBuilder.CreateReference(_current)));
  139. // If item type is object, we're done
  140. if (_resultItemType == TypeSystemServices.ObjectType) return;
  141. // Since enumerator is generic, this object-typed property should be the
  142. // explicit interface implementation for the non-generic IEnumerator interface
  143. property.ExplicitInfo = new ExplicitMemberInfo();
  144. property.ExplicitInfo.InterfaceType =
  145. (SimpleTypeReference)CodeBuilder.CreateTypeReference(TypeSystemServices.IEnumeratorType);
  146. // ...and now we create a typed property for the generic IEnumerator<> interface
  147. Property typedProperty = _enumerator.AddReadOnlyProperty("Current", _resultItemType);
  148. typedProperty.Getter.Modifiers |= TypeMemberModifiers.Virtual;
  149. typedProperty.Getter.Body.Add(
  150. new ReturnStatement(
  151. CodeBuilder.CreateReference(_current)));
  152. }
  153. void CreateGetEnumerator()
  154. {
  155. BooMethodBuilder method = (BooMethodBuilder)_generator["GetEnumeratorBuilder"];
  156. MethodInvocationExpression mie = CodeBuilder.CreateConstructorInvocation(_enumerator.ClassDefinition);
  157. foreach (TypeMember member in _enumerable.ClassDefinition.Members)
  158. {
  159. if (NodeType.Field == member.NodeType)
  160. {
  161. IField field = (IField)member.Entity;
  162. mie.Arguments.Add(CodeBuilder.CreateMemberReference(field));
  163. }
  164. }
  165. method.Body.Add(new ReturnStatement(mie));
  166. }
  167. void CreateClone()
  168. {
  169. BooMethodBuilder method = _enumerator.AddVirtualMethod("Clone", TypeSystemServices.ObjectType);
  170. method.Body.Add(
  171. new ReturnStatement(
  172. CodeBuilder.CreateMethodInvocation(
  173. CodeBuilder.CreateSelfReference(_enumerator.Entity),
  174. GetMemberwiseCloneMethod())));
  175. }
  176. void CreateReset()
  177. {
  178. // Find GetEnumerator method on the source type
  179. IMethod getEnumerator = (IMethod)GetMember(_sourceEnumerableType, "GetEnumerator", EntityType.Method);
  180. // Build Reset method that calls GetEnumerator on the source
  181. BooMethodBuilder method = _enumerator.AddVirtualMethod("Reset", TypeSystemServices.VoidType);
  182. method.Body.Add(
  183. CodeBuilder.CreateAssignment(
  184. CodeBuilder.CreateReference((InternalField)_enumeratorField.Entity),
  185. CodeBuilder.CreateMethodInvocation(_generator.Iterator, getEnumerator)));
  186. }
  187. void CreateMoveNext()
  188. {
  189. BooMethodBuilder method = _enumerator.AddVirtualMethod("MoveNext", TypeSystemServices.BoolType);
  190. Expression moveNext = CodeBuilder.CreateMethodInvocation(
  191. CodeBuilder.CreateReference((InternalField)_enumeratorField.Entity),
  192. TypeSystemServices.Map(Types.IEnumerator.GetMethod("MoveNext")));
  193. Expression current = CodeBuilder.CreateMethodInvocation(
  194. CodeBuilder.CreateReference((InternalField)_enumeratorField.Entity),
  195. ((IProperty)GetMember(_sourceEnumeratorType, "Current", EntityType.Property)).GetGetMethod());
  196. Statement filter = null;
  197. Statement stmt = null;
  198. Block outerBlock = null;
  199. Block innerBlock = null;
  200. if (null == _generator.Filter)
  201. {
  202. IfStatement istmt = new IfStatement(moveNext, new Block(), null);
  203. outerBlock = innerBlock = istmt.TrueBlock;
  204. stmt = istmt;
  205. }
  206. else
  207. {
  208. WhileStatement wstmt = new WhileStatement(moveNext);
  209. outerBlock = wstmt.Block;
  210. if (StatementModifierType.If == _generator.Filter.Type)
  211. {
  212. IfStatement ifstmt = new IfStatement(_generator.Filter.Condition, new Block(), null);
  213. innerBlock = ifstmt.TrueBlock;
  214. filter = ifstmt;
  215. }
  216. else
  217. {
  218. UnlessStatement ustmt = new UnlessStatement(_generator.Filter.Condition);
  219. innerBlock = ustmt.Block;
  220. filter = ustmt;
  221. }
  222. stmt = wstmt;
  223. }
  224. DeclarationCollection declarations = _generator.Declarations;
  225. if (declarations.Count > 1)
  226. {
  227. NormalizeIterationStatements.UnpackExpression(CodeBuilder,
  228. method.Method,
  229. outerBlock,
  230. current,
  231. declarations);
  232. foreach (Declaration declaration in declarations)
  233. {
  234. method.Locals.Add(((InternalLocal)declaration.Entity).Local);
  235. }
  236. }
  237. else
  238. {
  239. InternalLocal local = (InternalLocal)declarations[0].Entity;
  240. method.Locals.Add(local.Local);
  241. outerBlock.Add(CodeBuilder.CreateAssignment(
  242. CodeBuilder.CreateReference(local),
  243. current));
  244. }
  245. if (null != filter)
  246. {
  247. outerBlock.Add(filter);
  248. }
  249. innerBlock.Add(CodeBuilder.CreateAssignment(
  250. CodeBuilder.CreateReference((InternalField)_current.Entity),
  251. _generator.Expression));
  252. innerBlock.Add(new ReturnStatement(new BoolLiteralExpression(true)));
  253. method.Body.Add(stmt);
  254. method.Body.Add(new ReturnStatement(new BoolLiteralExpression(false)));
  255. }
  256. private void CreateDispose()
  257. {
  258. BooMethodBuilder dispose = _enumerator.AddVirtualMethod("Dispose", TypeSystemServices.VoidType);
  259. if (TypeSystemServices.Map(typeof(IDisposable)).IsAssignableFrom(_sourceEnumeratorType))
  260. {
  261. dispose.Body.Add(CodeBuilder.CreateMethodInvocation(
  262. CodeBuilder.CreateReference(_enumeratorField),
  263. typeof(IDisposable).GetMethod("Dispose")));
  264. }
  265. }
  266. /// <summary>
  267. /// Gets the member of the specified type with the specified name, assuming there is only one.
  268. /// </summary>
  269. private IEntity GetMember(IType type, string name, EntityType entityType)
  270. {
  271. // For external types we can use GetMethod or GetProperty to optimize things a little
  272. ExternalType external = type as ExternalType;
  273. if (external != null)
  274. {
  275. if (entityType == EntityType.Property)
  276. {
  277. return TypeSystemServices.Map(
  278. ((ExternalType)type).ActualType.GetProperty(name));
  279. }
  280. else if (entityType == EntityType.Method)
  281. {
  282. return TypeSystemServices.Map(
  283. ((ExternalType)type).ActualType.GetMethod(name));
  284. }
  285. }
  286. // For constructed types which aren't external we can use the GenericMapping to
  287. // (maybe) optimize things a little
  288. if (type.ConstructedInfo != null)
  289. {
  290. return ((GenericConstructedType)type).GenericMapping.Map(
  291. GetMember(type.ConstructedInfo.GenericDefinition, name, entityType));
  292. }
  293. // For other cases we just scan through the members collection
  294. return Array.Find<IEntity>(
  295. type.GetMembers(),
  296. delegate(IEntity e) {
  297. return entityType == e.EntityType && e.Name == name;
  298. });
  299. }
  300. }
  301. }