2 // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
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.
29 namespace Boo
.Lang
.Compiler
.TypeSystem
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
)
45 _codeBuilder
= new BooCodeBuilder(tss
);
48 protected TypeSystemServices TypeSystemServices
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
);
70 type
= new AnonymousCallableType(TypeSystemServices
, signature
);
71 _cache
.Add(signature
, type
);
76 private AnonymousCallableType
GetCachedCallableType(CallableSignature signature
)
78 AnonymousCallableType result
= null;
79 _cache
.TryGetValue(signature
, out 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
));
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
),
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
));
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());
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());
211 public Method
CreateEndInvokeMethod(ICallableType anonymousType
)
213 CallableSignature signature
= anonymousType
.GetSignature();
214 Method method
= CodeBuilder
.CreateRuntimeMethod("EndInvoke", signature
.ReturnType
);
217 foreach (IParameter p
in signature
.Parameters
)
221 method
.Parameters
.Add(
222 CodeBuilder
.CreateParameterDeclaration(++delta
,
228 delta
= method
.Parameters
.Count
;
229 method
.Parameters
.Add(
230 CodeBuilder
.CreateParameterDeclaration(delta
+ 1, "result", TypeSystemServices
.Map(typeof(IAsyncResult
))));
234 Method
CreateInvokeMethod(AnonymousCallableType anonymousType
)
236 CallableSignature signature
= anonymousType
.GetSignature();
237 return CodeBuilder
.CreateRuntimeMethod("Invoke", signature
.ReturnType
, signature
.Parameters
, signature
.AcceptVarArgs
);