PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/w4x/boolangstudio
C# | 479 lines | 400 code | 51 blank | 28 comment | 68 complexity | adb267b193ebecc808d5c39bcb5d5e74 MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2004, 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 Boo.Lang.Compiler.Ast;
  32. using Boo.Lang.Compiler.TypeSystem;
  33. public class InjectCallableConversions : AbstractVisitorCompilerStep
  34. {
  35. IMethod _current;
  36. IType _asyncResultType;
  37. IMethod _asyncResultTypeAsyncDelegateGetter;
  38. Boo.Lang.List _adaptors;
  39. override public void Run()
  40. {
  41. if (0 == Errors.Count)
  42. {
  43. Initialize();
  44. Visit(CompileUnit);
  45. }
  46. }
  47. void Initialize()
  48. {
  49. Type type = typeof(System.Runtime.Remoting.Messaging.AsyncResult);
  50. _asyncResultType = TypeSystemServices.Map(type);
  51. _asyncResultTypeAsyncDelegateGetter = TypeSystemServices.Map(type.GetProperty("AsyncDelegate").GetGetMethod());
  52. _adaptors = new Boo.Lang.List();
  53. }
  54. override public void Dispose()
  55. {
  56. _asyncResultType = null;
  57. _asyncResultTypeAsyncDelegateGetter = null;
  58. _adaptors = null;
  59. base.Dispose();
  60. }
  61. override public void OnMethod(Method node)
  62. {
  63. _current = (IMethod)GetEntity(node);
  64. Visit(node.Body);
  65. }
  66. bool HasReturnType(IMethod method)
  67. {
  68. return TypeSystemServices.VoidType != method.ReturnType;
  69. }
  70. bool IsMethodReference(Expression node)
  71. {
  72. IEntity entity = GetEntity(node);
  73. return EntityType.Method == entity.EntityType;
  74. }
  75. bool IsNotTargetOfMethodInvocation(Expression node)
  76. {
  77. MethodInvocationExpression mie = node.ParentNode as MethodInvocationExpression;
  78. if (null != mie) return mie.Target != node;
  79. return true;
  80. }
  81. bool IsStandaloneMethodReference(Expression node)
  82. {
  83. return
  84. (node is ReferenceExpression) &&
  85. IsMethodReference(node) &&
  86. IsNotTargetOfMethodInvocation(node);
  87. }
  88. override public void LeaveExpressionStatement(ExpressionStatement node)
  89. {
  90. // allow interactive evaluation of closures (see booish)
  91. Expression converted = ConvertExpression(node.Expression);
  92. if (null != converted)
  93. {
  94. node.Expression = converted;
  95. }
  96. }
  97. override public void LeaveReturnStatement(ReturnStatement node)
  98. {
  99. if (HasReturnType(_current))
  100. {
  101. Expression expression = node.Expression;
  102. if (null != expression)
  103. {
  104. Expression newExpression = Convert(_current.ReturnType, expression);
  105. if (null != newExpression)
  106. {
  107. node.Expression = newExpression;
  108. }
  109. }
  110. }
  111. }
  112. override public void LeaveExpressionPair(ExpressionPair pair)
  113. {
  114. Expression converted = ConvertExpression(pair.First);
  115. if (null != converted)
  116. {
  117. pair.First = converted;
  118. }
  119. converted = ConvertExpression(pair.Second);
  120. if (null != converted)
  121. {
  122. pair.Second = converted;
  123. }
  124. }
  125. override public void LeaveListLiteralExpression(ListLiteralExpression node)
  126. {
  127. ConvertExpressions(node.Items);
  128. }
  129. override public void LeaveArrayLiteralExpression(ArrayLiteralExpression node)
  130. {
  131. IType elementType = ((IArrayType)GetExpressionType(node)).GetElementType();
  132. for (int i=0; i<node.Items.Count; ++i)
  133. {
  134. Expression converted = Convert(elementType, node.Items[i]);
  135. if (null != converted)
  136. {
  137. node.Items.ReplaceAt(i, converted);
  138. }
  139. }
  140. }
  141. override public void LeaveMethodInvocationExpression(MethodInvocationExpression node)
  142. {
  143. IParameter[] parameters = null;
  144. IMethod entity = node.Target.Entity as IMethod;
  145. if (null != entity)
  146. {
  147. parameters = entity.GetParameters();
  148. }
  149. else
  150. {
  151. ICallableType type = node.Target.ExpressionType as ICallableType;
  152. if (null == type)
  153. {
  154. return;
  155. }
  156. parameters = type.GetSignature().Parameters;
  157. }
  158. ConvertMethodInvocation(node, parameters);
  159. }
  160. void ConvertMethodInvocation(MethodInvocationExpression node, IParameter[] parameters)
  161. {
  162. ExpressionCollection arguments = node.Arguments;
  163. for (int i=0; i<parameters.Length; ++i)
  164. {
  165. Expression newArgument = Convert(parameters[i].Type, arguments[i]);
  166. if (null != newArgument)
  167. {
  168. arguments.ReplaceAt(i, newArgument);
  169. }
  170. }
  171. }
  172. override public void LeaveMemberReferenceExpression(MemberReferenceExpression node)
  173. {
  174. if (IsEndInvokeOnStandaloneMethodReference(node) &&
  175. AstUtil.IsTargetOfMethodInvocation(node))
  176. {
  177. ReplaceEndInvokeTargetByGetAsyncDelegate((MethodInvocationExpression)node.ParentNode);
  178. }
  179. else
  180. {
  181. Expression newTarget = ConvertExpression(node.Target);
  182. if (null != newTarget)
  183. {
  184. node.Target = newTarget;
  185. }
  186. }
  187. }
  188. override public void LeaveCastExpression(CastExpression node)
  189. {
  190. Expression newExpression = Convert(node.ExpressionType, node.Target);
  191. if (null != newExpression)
  192. {
  193. node.Target = newExpression;
  194. }
  195. }
  196. override public void LeaveTryCastExpression(TryCastExpression node)
  197. {
  198. Expression newExpression = Convert(node.ExpressionType, node.Target);
  199. if (null != newExpression)
  200. {
  201. node.Target = newExpression;
  202. }
  203. }
  204. override public void LeaveBinaryExpression(BinaryExpression node)
  205. {
  206. if (BinaryOperatorType.Assign == node.Operator)
  207. {
  208. Expression newRight = Convert(node.Left.ExpressionType, node.Right);
  209. if (null != newRight)
  210. {
  211. node.Right = newRight;
  212. }
  213. }
  214. }
  215. override public void LeaveGeneratorExpression(GeneratorExpression node)
  216. {
  217. Expression newExpression = Convert(
  218. GetConcreteExpressionType(node.Expression),
  219. node.Expression);
  220. if (null != newExpression)
  221. {
  222. node.Expression = newExpression;
  223. }
  224. }
  225. void ConvertExpressions(ExpressionCollection items)
  226. {
  227. for (int i=0; i<items.Count; ++i)
  228. {
  229. Expression converted = ConvertExpression(items[i]);
  230. if (null != converted)
  231. {
  232. items.ReplaceAt(i, converted);
  233. }
  234. }
  235. }
  236. Expression ConvertExpression(Expression expression)
  237. {
  238. return Convert(expression.ExpressionType, expression);
  239. }
  240. Expression Convert(IType expectedType, Expression argument)
  241. {
  242. if (IsStandaloneMethodReference(argument))
  243. {
  244. if (IsCallableType(expectedType))
  245. {
  246. ICallableType argumentType = (ICallableType)GetExpressionType(argument);
  247. if (argumentType.GetSignature() !=
  248. ((ICallableType)expectedType).GetSignature())
  249. {
  250. return Adapt((ICallableType)expectedType,
  251. CreateDelegate(GetConcreteExpressionType(argument), argument));
  252. }
  253. return CreateDelegate(expectedType, argument);
  254. }
  255. else
  256. {
  257. return CreateDelegate(GetConcreteExpressionType(argument), argument);
  258. }
  259. }
  260. else
  261. {
  262. if (IsCallableType(expectedType))
  263. {
  264. IType argumentType = GetExpressionType(argument);
  265. if (Null.Default != argumentType &&
  266. expectedType != argumentType)
  267. {
  268. return Adapt((ICallableType)expectedType, argument);
  269. }
  270. }
  271. }
  272. return null;
  273. }
  274. Expression Adapt(ICallableType expected, Expression callable)
  275. {
  276. ICallableType actual = GetExpressionType(callable) as ICallableType;
  277. if (null == actual)
  278. {
  279. // TODO: should we adapt System.Object, System.Delegate,
  280. // System.MulticastDelegate and ICallable as well?
  281. return null;
  282. }
  283. ClassDefinition adaptor = GetAdaptor(expected, actual);
  284. Method adapt = (Method)adaptor.Members["Adapt"];
  285. return CodeBuilder.CreateMethodInvocation((IMethod)adapt.Entity, callable);
  286. }
  287. ClassDefinition GetAdaptor(ICallableType to, ICallableType from)
  288. {
  289. ClassDefinition adaptor = FindAdaptor(to, from);
  290. if (null == adaptor)
  291. {
  292. adaptor = CreateAdaptor(to, from);
  293. }
  294. return adaptor;
  295. }
  296. class AdaptorRecord
  297. {
  298. public readonly ICallableType To;
  299. public readonly ICallableType From;
  300. public readonly ClassDefinition Adaptor;
  301. public AdaptorRecord(ICallableType to, ICallableType from, ClassDefinition adaptor)
  302. {
  303. To = to;
  304. From = from;
  305. Adaptor = adaptor;
  306. }
  307. }
  308. ClassDefinition FindAdaptor(ICallableType to, ICallableType from)
  309. {
  310. foreach (AdaptorRecord record in _adaptors)
  311. {
  312. if (from == record.From && to == record.To)
  313. {
  314. return record.Adaptor;
  315. }
  316. }
  317. return null;
  318. }
  319. ClassDefinition CreateAdaptor(ICallableType to, ICallableType from)
  320. {
  321. BooClassBuilder adaptor = CodeBuilder.CreateClass("$adaptor$" + from.Name + "$" + to.Name + "$" + _adaptors.Count);
  322. adaptor.AddBaseType(TypeSystemServices.ObjectType);
  323. adaptor.Modifiers = TypeMemberModifiers.Final|TypeMemberModifiers.Internal;
  324. Field callable = adaptor.AddField("$from", from);
  325. BooMethodBuilder constructor = adaptor.AddConstructor();
  326. ParameterDeclaration param = constructor.AddParameter("from", from);
  327. constructor.Body.Add(
  328. CodeBuilder.CreateSuperConstructorInvocation(TypeSystemServices.ObjectType));
  329. constructor.Body.Add(
  330. CodeBuilder.CreateAssignment(
  331. CodeBuilder.CreateReference(callable),
  332. CodeBuilder.CreateReference(param)));
  333. CallableSignature signature = to.GetSignature();
  334. BooMethodBuilder invoke = adaptor.AddMethod("Invoke", signature.ReturnType);
  335. foreach (IParameter parameter in signature.Parameters)
  336. {
  337. invoke.AddParameter(parameter.Name, parameter.Type, parameter.IsByRef);
  338. }
  339. MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
  340. CodeBuilder.CreateReference(callable),
  341. GetInvokeMethod(from));
  342. int fromParameterCount = from.GetSignature().Parameters.Length;
  343. for (int i=0; i<fromParameterCount; ++i)
  344. {
  345. mie.Arguments.Add(
  346. CodeBuilder.CreateReference(invoke.Parameters[i]));
  347. }
  348. if (signature.ReturnType != TypeSystemServices.VoidType &&
  349. from.GetSignature().ReturnType != TypeSystemServices.VoidType)
  350. {
  351. invoke.Body.Add(new ReturnStatement(mie));
  352. }
  353. else
  354. {
  355. invoke.Body.Add(mie);
  356. }
  357. BooMethodBuilder adapt = adaptor.AddMethod("Adapt", to);
  358. adapt.Modifiers = TypeMemberModifiers.Static|TypeMemberModifiers.Public;
  359. param = adapt.AddParameter("from", from);
  360. adapt.Body.Add(
  361. new ReturnStatement(
  362. CodeBuilder.CreateConstructorInvocation(
  363. to.GetConstructors()[0],
  364. CodeBuilder.CreateConstructorInvocation(
  365. (IConstructor)constructor.Entity,
  366. CodeBuilder.CreateReference(param)),
  367. CodeBuilder.CreateAddressOfExpression(invoke.Entity))));
  368. RegisterAdaptor(to, from, adaptor.ClassDefinition);
  369. return adaptor.ClassDefinition;
  370. }
  371. void RegisterAdaptor(ICallableType to, ICallableType from, ClassDefinition adaptor)
  372. {
  373. _adaptors.Add(new AdaptorRecord(to, from, adaptor));
  374. TypeSystemServices.GetCompilerGeneratedTypesModule().Members.Add(adaptor);
  375. }
  376. bool IsEndInvokeOnStandaloneMethodReference(MemberReferenceExpression node)
  377. {
  378. if (IsStandaloneMethodReference(node.Target))
  379. {
  380. return node.Entity.Name == "EndInvoke";
  381. }
  382. return false;
  383. }
  384. void ReplaceEndInvokeTargetByGetAsyncDelegate(MethodInvocationExpression node)
  385. {
  386. Expression asyncResult = node.Arguments[node.Arguments.Count-1];
  387. MemberReferenceExpression endInvoke = (MemberReferenceExpression)node.Target;
  388. IType callableType = ((IMember)endInvoke.Entity).DeclaringType;
  389. endInvoke.Target = CodeBuilder.CreateCast(callableType,
  390. CodeBuilder.CreateMethodInvocation(
  391. CodeBuilder.CreateCast(_asyncResultType, asyncResult.CloneNode()),
  392. _asyncResultTypeAsyncDelegateGetter));
  393. }
  394. bool IsCallableType(IType type)
  395. {
  396. return type is ICallableType;
  397. }
  398. Expression CreateDelegate(IType type, Expression source)
  399. {
  400. IMethod method = (IMethod)GetEntity(source);
  401. Expression target = null;
  402. if (method.IsStatic)
  403. {
  404. target = CodeBuilder.CreateNullLiteral();
  405. }
  406. else
  407. {
  408. target = ((MemberReferenceExpression)source).Target;
  409. }
  410. return CodeBuilder.CreateConstructorInvocation(GetConcreteType(type).GetConstructors()[0],
  411. target,
  412. CodeBuilder.CreateAddressOfExpression(method));
  413. }
  414. IType GetConcreteType(IType type)
  415. {
  416. AnonymousCallableType anonymous = type as AnonymousCallableType;
  417. if (null == anonymous)
  418. {
  419. return type;
  420. }
  421. return anonymous.ConcreteType;
  422. }
  423. IMethod GetInvokeMethod(ICallableType type)
  424. {
  425. return NameResolutionService.ResolveMethod(type, "Invoke");
  426. }
  427. }
  428. }