BOO-503: Some love for compiler-generated callable definition names so that they...
[boo.git] / src / Boo.Lang.Compiler / TypeSystem / AnonymousCallablesManager.cs
blob58ff083aaccc682b97a5b1201476e9542b19f415
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 TypeMember enclosing = (sourceNode.GetAncestor(NodeType.ClassDefinition) ?? sourceNode.GetAncestor(NodeType.Module)) as TypeMember;
103 string prefix = "__$";
104 string postfix = "$__";
105 if(enclosing != null)
107 prefix += enclosing.Name + "$";
109 else if (!sourceNode.LexicalInfo.Equals(LexicalInfo.Empty))
111 prefix += System.IO.Path.GetFileNameWithoutExtension(sourceNode.LexicalInfo.FileName) + "$";
113 if(!sourceNode.LexicalInfo.Equals(LexicalInfo.Empty))
115 postfix = "$" + sourceNode.LexicalInfo.Line + "_" + sourceNode.LexicalInfo.Column + postfix;
117 string name = prefix + "callable" + module.Members.Count + postfix;
118 ClassDefinition cd = TypeSystemServices.CreateCallableDefinition(name);
119 cd.Modifiers |= TypeMemberModifiers.Public;
120 cd.LexicalInfo = sourceNode.LexicalInfo;
122 cd.Members.Add(CreateInvokeMethod(anonymousType));
124 Method beginInvoke = CreateBeginInvokeMethod(anonymousType);
125 cd.Members.Add(beginInvoke);
127 cd.Members.Add(CreateEndInvokeMethod(anonymousType));
128 module.Members.Add(cd);
130 CreateCallableTypeBeginInvokeExtensions(anonymousType, beginInvoke);
132 return (IType)cd.Entity;
135 private void CreateCallableTypeBeginInvokeExtensions(AnonymousCallableType anonymousType, Method beginInvoke)
137 ClassDefinition extensions = TypeSystemServices.GetCompilerGeneratedExtensionsClass();
138 extensions.Members.Add(CreateBeginInvokeCallbackOnlyExtension(anonymousType, beginInvoke));
139 extensions.Members.Add(CreateBeginInvokeSimplerExtension(anonymousType, beginInvoke));
142 Method CreateBeginInvokeMethod(ICallableType anonymousType)
144 Method method = CodeBuilder.CreateRuntimeMethod("BeginInvoke", TypeSystemServices.Map(typeof(IAsyncResult)),
145 anonymousType.GetSignature().Parameters, false);
147 int delta = method.Parameters.Count;
148 method.Parameters.Add(
149 CodeBuilder.CreateParameterDeclaration(delta + 1, "callback", TypeSystemServices.Map(typeof(AsyncCallback))));
150 method.Parameters.Add(
151 CodeBuilder.CreateParameterDeclaration(delta + 1, "asyncState", TypeSystemServices.ObjectType));
152 return method;
155 Method CreateBeginInvokeExtension(ICallableType anonymousType, Method beginInvoke, out MethodInvocationExpression mie)
157 InternalMethod beginInvokeEntity = (InternalMethod)beginInvoke.Entity;
159 Method extension = CodeBuilder.CreateMethod("BeginInvoke", TypeSystemServices.Map(typeof(IAsyncResult)),
160 TypeMemberModifiers.Public | TypeMemberModifiers.Static);
161 extension.Attributes.Add(CodeBuilder.CreateAttribute(Types.BooExtensionAttribute));
162 if (MetadataUtil.HasClrExtensions())
164 extension.Attributes.Add(CodeBuilder.CreateAttribute(Types.ClrExtensionAttribute));
167 ParameterDeclaration self = CodeBuilder.CreateParameterDeclaration(0, "self", beginInvokeEntity.DeclaringType);
169 extension.Parameters.Add(self);
170 CodeBuilder.DeclareParameters(extension, 1, anonymousType.GetSignature().Parameters);
172 mie = CodeBuilder.CreateMethodInvocation(
173 CodeBuilder.CreateReference(self),
174 beginInvokeEntity);
176 ParameterDeclarationCollection parameters = extension.Parameters;
177 for (int i = 1; i < parameters.Count; ++i)
179 mie.Arguments.Add(CodeBuilder.CreateReference(parameters[i]));
181 extension.Body.Add(new ReturnStatement(mie));
182 return extension;
185 Method CreateBeginInvokeSimplerExtension(ICallableType anonymousType, Method beginInvoke)
187 MethodInvocationExpression mie;
188 Method overload = CreateBeginInvokeExtension(anonymousType, beginInvoke, out mie);
190 mie.Arguments.Add(CodeBuilder.CreateNullLiteral());
191 mie.Arguments.Add(CodeBuilder.CreateNullLiteral());
193 return overload;
196 Method CreateBeginInvokeCallbackOnlyExtension(ICallableType anonymousType, Method beginInvoke)
198 MethodInvocationExpression mie;
200 Method overload = CreateBeginInvokeExtension(anonymousType, beginInvoke, out mie);
201 ParameterDeclaration callback = CodeBuilder.CreateParameterDeclaration(overload.Parameters.Count,
202 "callback", TypeSystemServices.Map(typeof(AsyncCallback)));
203 overload.Parameters.Add(callback);
205 mie.Arguments.Add(CodeBuilder.CreateReference(callback));
206 mie.Arguments.Add(CodeBuilder.CreateNullLiteral());
208 return overload;
211 public Method CreateEndInvokeMethod(ICallableType anonymousType)
213 CallableSignature signature = anonymousType.GetSignature();
214 Method method = CodeBuilder.CreateRuntimeMethod("EndInvoke", signature.ReturnType);
216 int delta = 1;
217 foreach (IParameter p in signature.Parameters)
219 if (p.IsByRef)
221 method.Parameters.Add(
222 CodeBuilder.CreateParameterDeclaration(++delta,
223 p.Name,
224 p.Type,
225 true));
228 delta = method.Parameters.Count;
229 method.Parameters.Add(
230 CodeBuilder.CreateParameterDeclaration(delta + 1, "result", TypeSystemServices.Map(typeof(IAsyncResult))));
231 return method;
234 Method CreateInvokeMethod(AnonymousCallableType anonymousType)
236 CallableSignature signature = anonymousType.GetSignature();
237 return CodeBuilder.CreateRuntimeMethod("Invoke", signature.ReturnType, signature.Parameters, signature.AcceptVarArgs);