BOO-988: Added else block to the for and while statements, and include a suite of...
[boo.git] / src / Boo.Lang.Compiler / TypeSystem / AnonymousCallablesManager.cs
blobf8c0730769af166d46ff405964b4faa784ae3817
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.
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
29 namespace Boo.Lang.Compiler.TypeSystem
31 using System;
32 using System.Collections.Generic;
33 using Boo.Lang.Compiler.Ast;
34 using Module = Boo.Lang.Compiler.Ast.Module;
36 internal class AnonymousCallablesManager
38 private TypeSystemServices _tss;
39 private IDictionary<CallableSignature, AnonymousCallableType> _cache = new Dictionary<CallableSignature, AnonymousCallableType>();
40 private BooCodeBuilder _codeBuilder;
42 public AnonymousCallablesManager(TypeSystemServices tss)
44 _tss = tss;
45 _codeBuilder = new BooCodeBuilder(tss);
48 protected TypeSystemServices TypeSystemServices
50 get { return _tss; }
53 protected BooCodeBuilder CodeBuilder
55 get { return _codeBuilder; }
58 public AnonymousCallableType GetCallableType(IMethod method)
60 CallableSignature signature = new CallableSignature(method);
61 return GetCallableType(signature);
64 public AnonymousCallableType GetCallableType(CallableSignature signature)
66 AnonymousCallableType type = GetCachedCallableType(signature);
68 if (type == null)
70 type = new AnonymousCallableType(TypeSystemServices, signature);
71 _cache.Add(signature, type);
73 return type;
76 private AnonymousCallableType GetCachedCallableType(CallableSignature signature)
78 AnonymousCallableType result = null;
79 _cache.TryGetValue(signature, out result);
80 return result;
83 public IType GetConcreteCallableType(Node sourceNode, CallableSignature signature)
85 AnonymousCallableType type = GetCallableType(signature);
86 return GetConcreteCallableType(sourceNode, type);
89 public IType GetConcreteCallableType(Node sourceNode, AnonymousCallableType anonymousType)
91 if (null == anonymousType.ConcreteType)
93 anonymousType.ConcreteType = CreateConcreteCallableType(sourceNode, anonymousType);
95 return anonymousType.ConcreteType;
98 private IType CreateConcreteCallableType(Node sourceNode, AnonymousCallableType anonymousType)
100 Module module = TypeSystemServices.GetCompilerGeneratedTypesModule();
102 string name = string.Format("___callable{0}", module.Members.Count);
103 ClassDefinition cd = TypeSystemServices.CreateCallableDefinition(name);
104 cd.Modifiers |= TypeMemberModifiers.Public;
105 cd.LexicalInfo = sourceNode.LexicalInfo;
107 cd.Members.Add(CreateInvokeMethod(anonymousType));
109 Method beginInvoke = CreateBeginInvokeMethod(anonymousType);
110 cd.Members.Add(beginInvoke);
112 cd.Members.Add(CreateEndInvokeMethod(anonymousType));
113 module.Members.Add(cd);
115 CreateCallableTypeBeginInvokeExtensions(anonymousType, beginInvoke);
117 return (IType)cd.Entity;
120 private void CreateCallableTypeBeginInvokeExtensions(AnonymousCallableType anonymousType, Method beginInvoke)
122 ClassDefinition extensions = TypeSystemServices.GetCompilerGeneratedExtensionsClass();
123 extensions.Members.Add(CreateBeginInvokeCallbackOnlyExtension(anonymousType, beginInvoke));
124 extensions.Members.Add(CreateBeginInvokeSimplerExtension(anonymousType, beginInvoke));
127 Method CreateBeginInvokeMethod(ICallableType anonymousType)
129 Method method = CodeBuilder.CreateRuntimeMethod("BeginInvoke", TypeSystemServices.Map(typeof(IAsyncResult)),
130 anonymousType.GetSignature().Parameters, false);
132 int delta = method.Parameters.Count;
133 method.Parameters.Add(
134 CodeBuilder.CreateParameterDeclaration(delta + 1, "callback", TypeSystemServices.Map(typeof(AsyncCallback))));
135 method.Parameters.Add(
136 CodeBuilder.CreateParameterDeclaration(delta + 1, "asyncState", TypeSystemServices.ObjectType));
137 return method;
140 Method CreateBeginInvokeExtension(ICallableType anonymousType, Method beginInvoke, out MethodInvocationExpression mie)
142 InternalMethod beginInvokeEntity = (InternalMethod)beginInvoke.Entity;
144 Method extension = CodeBuilder.CreateMethod("BeginInvoke", TypeSystemServices.Map(typeof(IAsyncResult)),
145 TypeMemberModifiers.Public | TypeMemberModifiers.Static);
146 extension.Attributes.Add(CodeBuilder.CreateAttribute(Types.BooExtensionAttribute));
147 if (MetadataUtil.HasClrExtensions())
149 extension.Attributes.Add(CodeBuilder.CreateAttribute(Types.ClrExtensionAttribute));
152 ParameterDeclaration self = CodeBuilder.CreateParameterDeclaration(0, "self", beginInvokeEntity.DeclaringType);
154 extension.Parameters.Add(self);
155 CodeBuilder.DeclareParameters(extension, 1, anonymousType.GetSignature().Parameters);
157 mie = CodeBuilder.CreateMethodInvocation(
158 CodeBuilder.CreateReference(self),
159 beginInvokeEntity);
161 ParameterDeclarationCollection parameters = extension.Parameters;
162 for (int i = 1; i < parameters.Count; ++i)
164 mie.Arguments.Add(CodeBuilder.CreateReference(parameters[i]));
166 extension.Body.Add(new ReturnStatement(mie));
167 return extension;
170 Method CreateBeginInvokeSimplerExtension(ICallableType anonymousType, Method beginInvoke)
172 MethodInvocationExpression mie;
173 Method overload = CreateBeginInvokeExtension(anonymousType, beginInvoke, out mie);
175 mie.Arguments.Add(CodeBuilder.CreateNullLiteral());
176 mie.Arguments.Add(CodeBuilder.CreateNullLiteral());
178 return overload;
181 Method CreateBeginInvokeCallbackOnlyExtension(ICallableType anonymousType, Method beginInvoke)
183 MethodInvocationExpression mie;
185 Method overload = CreateBeginInvokeExtension(anonymousType, beginInvoke, out mie);
186 ParameterDeclaration callback = CodeBuilder.CreateParameterDeclaration(overload.Parameters.Count,
187 "callback", TypeSystemServices.Map(typeof(AsyncCallback)));
188 overload.Parameters.Add(callback);
190 mie.Arguments.Add(CodeBuilder.CreateReference(callback));
191 mie.Arguments.Add(CodeBuilder.CreateNullLiteral());
193 return overload;
196 public Method CreateEndInvokeMethod(ICallableType anonymousType)
198 CallableSignature signature = anonymousType.GetSignature();
199 Method method = CodeBuilder.CreateRuntimeMethod("EndInvoke", signature.ReturnType);
201 int delta = 1;
202 foreach (IParameter p in signature.Parameters)
204 if (p.IsByRef)
206 method.Parameters.Add(
207 CodeBuilder.CreateParameterDeclaration(++delta,
208 p.Name,
209 p.Type,
210 true));
213 delta = method.Parameters.Count;
214 method.Parameters.Add(
215 CodeBuilder.CreateParameterDeclaration(delta + 1, "result", TypeSystemServices.Map(typeof(IAsyncResult))));
216 return method;
219 Method CreateInvokeMethod(AnonymousCallableType anonymousType)
221 CallableSignature signature = anonymousType.GetSignature();
222 return CodeBuilder.CreateRuntimeMethod("Invoke", signature.ReturnType, signature.Parameters, signature.AcceptVarArgs);