PageRenderTime 4384ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 1ms

/src/Milo.Compilation/Steps/BindTypeMembers.cs

http://milo.googlecode.com/
C# | 398 lines | 301 code | 43 blank | 54 comment | 24 complexity | 5078dfa7fd488584ca7c4e7193e55978 MD5 | raw file
  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. using System;
  29. #region license
  30. // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
  31. // All rights reserved.
  32. //
  33. // Redistribution and use in source and binary forms, with or without modification,
  34. // are permitted provided that the following conditions are met:
  35. //
  36. // * Redistributions of source code must retain the above copyright notice,
  37. // this list of conditions and the following disclaimer.
  38. // * Redistributions in binary form must reproduce the above copyright notice,
  39. // this list of conditions and the following disclaimer in the documentation
  40. // and/or other materials provided with the distribution.
  41. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  42. // contributors may be used to endorse or promote products derived from this
  43. // software without specific prior written permission.
  44. //
  45. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  46. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  47. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  48. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  49. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  50. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  51. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  52. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  53. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  54. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  55. #endregion
  56. namespace Milo.Compilation.Steps
  57. {
  58. using Milo.Ast;
  59. using Milo.Compilation.TypeSystem;
  60. public class BindTypeMembers : AbstractVisitorCompilerStep
  61. {
  62. Boo.Lang.List _parameters = new Boo.Lang.List();
  63. Boo.Lang.List _events = new Boo.Lang.List();
  64. IMethod _delegate_Combine;
  65. IMethod _delegate_Remove;
  66. public BindTypeMembers()
  67. {
  68. }
  69. override public void OnMethod(Method node)
  70. {
  71. // The method itself has been bound earlier during BindMethods, so
  72. // we just have to remember to bind its parameters
  73. _parameters.Add(node);
  74. Visit(node.ExplicitInfo);
  75. }
  76. void BindAllParameters()
  77. {
  78. foreach (INodeWithParameters node in _parameters)
  79. {
  80. TypeMember member = (TypeMember)node;
  81. NameResolutionService.Restore((INamespace)TypeSystemServices.GetEntity(member.DeclaringType));
  82. CodeBuilder.BindParameterDeclarations(member.IsStatic, node);
  83. }
  84. }
  85. override public void OnConstructor(Constructor node)
  86. {
  87. if (null == node.Entity)
  88. {
  89. node.Entity = new InternalConstructor(TypeSystemServices, node);
  90. }
  91. _parameters.Add(node);
  92. }
  93. override public void OnField(Field node)
  94. {
  95. if (null == node.Entity)
  96. {
  97. node.Entity = new InternalField(node);
  98. }
  99. }
  100. override public void OnProperty(Property node)
  101. {
  102. if (null == node.Entity)
  103. {
  104. node.Entity = new InternalProperty(TypeSystemServices, node);
  105. }
  106. _parameters.Add(node);
  107. Visit(node.Getter);
  108. Visit(node.Setter);
  109. Visit(node.ExplicitInfo);
  110. }
  111. override public void OnExplicitMemberInfo(ExplicitMemberInfo node)
  112. {
  113. Visit(node.InterfaceType);
  114. }
  115. override public void OnEvent(Event node)
  116. {
  117. _events.Add(node);
  118. }
  119. void BindAllEvents()
  120. {
  121. foreach (Event node in _events)
  122. {
  123. BindEvent(node);
  124. }
  125. }
  126. void BindEvent(Event node)
  127. {
  128. if (null == node.Entity)
  129. {
  130. node.Entity = new InternalEvent(TypeSystemServices, node);
  131. }
  132. IType type = GetType(node.Type);
  133. IType declaringType = GetType(node.DeclaringType);
  134. bool typeIsCallable = type is ICallableType;
  135. if (!typeIsCallable)
  136. {
  137. Errors.Add(
  138. CompilerErrorFactory.EventTypeIsNotCallable(node.Type,
  139. type.ToString()));
  140. }
  141. if (declaringType.IsInterface)
  142. {
  143. BindInterfaceEvent(node);
  144. }
  145. else
  146. {
  147. BindClassEvent(node, type, typeIsCallable);
  148. }
  149. }
  150. private void BindInterfaceEvent(Event node)
  151. {
  152. // TODO: Add checks to ensure Add/Remove/Raise are
  153. // null before doing this.
  154. node.Add = CreateInterfaceEventAddMethod(node);
  155. node.Remove = CreateInterfaceEventRemoveMethod(node);
  156. }
  157. private void BindClassEvent (Event node, IType type, bool typeIsCallable)
  158. {
  159. Field backingField = CodeBuilder.CreateField("___" + node.Name, type);
  160. if (node.IsTransient)
  161. {
  162. backingField.Modifiers |= TypeMemberModifiers.Transient;
  163. }
  164. if (node.IsStatic)
  165. {
  166. backingField.Modifiers |= TypeMemberModifiers.Static;
  167. }
  168. node.DeclaringType.Members.Add(backingField);
  169. ((InternalEvent)node.Entity).BackingField = (InternalField)backingField.Entity;
  170. if (null == node.Add)
  171. {
  172. node.Add = CreateEventAddMethod(node, backingField);
  173. }
  174. else
  175. {
  176. Visit(node.Add);
  177. }
  178. if (null == node.Remove)
  179. {
  180. node.Remove = CreateEventRemoveMethod(node, backingField);
  181. }
  182. else
  183. {
  184. Visit(node.Remove);
  185. }
  186. if (null == node.Raise)
  187. {
  188. if (typeIsCallable)
  189. {
  190. node.Raise = CreateEventRaiseMethod(node, backingField);
  191. }
  192. }
  193. else
  194. {
  195. Visit(node.Raise);
  196. }
  197. }
  198. override public void OnClassDefinition(ClassDefinition node)
  199. {
  200. Visit(node.Members);
  201. }
  202. override public void OnModule(Module node)
  203. {
  204. Visit(node.Members);
  205. }
  206. override public void Run()
  207. {
  208. NameResolutionService.Reset();
  209. Visit(CompileUnit.Modules);
  210. BindAllParameters();
  211. BindAllEvents();
  212. }
  213. override public void Dispose()
  214. {
  215. _parameters.Clear();
  216. _events.Clear();
  217. base.Dispose();
  218. }
  219. IMethod Delegate_Combine
  220. {
  221. get
  222. {
  223. InitializeDelegateMethods();
  224. return _delegate_Combine;
  225. }
  226. }
  227. IMethod Delegate_Remove
  228. {
  229. get
  230. {
  231. InitializeDelegateMethods();
  232. return _delegate_Remove;
  233. }
  234. }
  235. void InitializeDelegateMethods()
  236. {
  237. if (null != _delegate_Combine)
  238. {
  239. return;
  240. }
  241. Type delegateType = Types.Delegate;
  242. Type[] delegates = new Type[] { delegateType, delegateType };
  243. _delegate_Combine = TypeSystemServices.Map(delegateType.GetMethod("Combine", delegates));
  244. _delegate_Remove = TypeSystemServices.Map(delegateType.GetMethod("Remove", delegates));
  245. }
  246. Method CreateInterfaceEventMethod(Event node, string prefix)
  247. {
  248. Method method = CodeBuilder.CreateMethod(prefix + node.Name,
  249. TypeSystemServices.VoidType,
  250. TypeMemberModifiers.Public | TypeMemberModifiers.Virtual | TypeMemberModifiers.Abstract);
  251. method.Parameters.Add(
  252. CodeBuilder.CreateParameterDeclaration(
  253. CodeBuilder.GetFirstParameterIndex(node),
  254. "handler",
  255. GetType(node.Type)));
  256. return method;
  257. }
  258. Method CreateInterfaceEventAddMethod(Event node)
  259. {
  260. return CreateInterfaceEventMethod(node, "add_");
  261. }
  262. Method CreateInterfaceEventRemoveMethod(Event node)
  263. {
  264. return CreateInterfaceEventMethod(node, "remove_");
  265. }
  266. Method CreateEventMethod(Event node, string prefix)
  267. {
  268. Method method = CodeBuilder.CreateMethod(prefix + node.Name,
  269. TypeSystemServices.VoidType,
  270. node.Modifiers);
  271. method.Parameters.Add(
  272. CodeBuilder.CreateParameterDeclaration(
  273. CodeBuilder.GetFirstParameterIndex(node),
  274. "handler",
  275. GetType(node.Type)));
  276. return method;
  277. }
  278. Method CreateEventAddMethod(Event node, Field backingField)
  279. {
  280. Method m = CreateEventMethod(node, "add_");
  281. m.Body.Add(
  282. CodeBuilder.CreateAssignment(
  283. CodeBuilder.CreateReference(backingField),
  284. CodeBuilder.CreateMethodInvocation(
  285. Delegate_Combine,
  286. CodeBuilder.CreateReference(backingField),
  287. CodeBuilder.CreateReference(m.Parameters[0]))));
  288. return m;
  289. }
  290. Method CreateEventRemoveMethod(Event node, Field backingField)
  291. {
  292. Method m = CreateEventMethod(node, "remove_");
  293. m.Body.Add(
  294. CodeBuilder.CreateAssignment(
  295. CodeBuilder.CreateReference(backingField),
  296. CodeBuilder.CreateMethodInvocation(
  297. Delegate_Remove,
  298. CodeBuilder.CreateReference(backingField),
  299. CodeBuilder.CreateReference(m.Parameters[0]))));
  300. return m;
  301. }
  302. TypeMemberModifiers RemoveAccessiblityModifiers(TypeMemberModifiers modifiers)
  303. {
  304. TypeMemberModifiers mask = TypeMemberModifiers.Public |
  305. TypeMemberModifiers.Protected |
  306. TypeMemberModifiers.Private |
  307. TypeMemberModifiers.Internal;
  308. return modifiers & ~mask ;
  309. }
  310. Method CreateEventRaiseMethod(Event node, Field backingField)
  311. {
  312. TypeMemberModifiers modifiers = RemoveAccessiblityModifiers(node.Modifiers);
  313. if (node.IsPrivate)
  314. {
  315. modifiers |= TypeMemberModifiers.Private;
  316. }
  317. else
  318. {
  319. modifiers |= TypeMemberModifiers.Protected | TypeMemberModifiers.Internal;
  320. }
  321. Method method = CodeBuilder.CreateMethod("raise_" + node.Name,
  322. TypeSystemServices.VoidType,
  323. modifiers);
  324. ICallableType type = GetEntity(node.Type) as ICallableType;
  325. if (null != type)
  326. {
  327. int index = CodeBuilder.GetFirstParameterIndex(node);
  328. foreach (IParameter parameter in type.GetSignature().Parameters)
  329. {
  330. method.Parameters.Add(
  331. CodeBuilder.CreateParameterDeclaration(
  332. index,
  333. parameter.Name,
  334. parameter.Type,
  335. parameter.IsByRef));
  336. ++index;
  337. }
  338. }
  339. MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
  340. CodeBuilder.CreateReference(backingField),
  341. NameResolutionService.ResolveMethod(GetType(backingField.Type), "Invoke"));
  342. foreach (ParameterDeclaration parameter in method.Parameters)
  343. {
  344. mie.Arguments.Add(CodeBuilder.CreateReference(parameter));
  345. }
  346. IfStatement stmt = new IfStatement(node.LexicalInfo);
  347. stmt.Condition = CodeBuilder.CreateNotNullTest(
  348. CodeBuilder.CreateReference(backingField));
  349. stmt.TrueBlock = new Block();
  350. stmt.TrueBlock.Add(mie);
  351. method.Body.Add(stmt);
  352. return method;
  353. }
  354. }
  355. }