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 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
));
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
),
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
));
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());
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());
196 public Method
CreateEndInvokeMethod(ICallableType anonymousType
)
198 CallableSignature signature
= anonymousType
.GetSignature();
199 Method method
= CodeBuilder
.CreateRuntimeMethod("EndInvoke", signature
.ReturnType
);
202 foreach (IParameter p
in signature
.Parameters
)
206 method
.Parameters
.Add(
207 CodeBuilder
.CreateParameterDeclaration(++delta
,
213 delta
= method
.Parameters
.Count
;
214 method
.Parameters
.Add(
215 CodeBuilder
.CreateParameterDeclaration(delta
+ 1, "result", TypeSystemServices
.Map(typeof(IAsyncResult
))));
219 Method
CreateInvokeMethod(AnonymousCallableType anonymousType
)
221 CallableSignature signature
= anonymousType
.GetSignature();
222 return CodeBuilder
.CreateRuntimeMethod("Invoke", signature
.ReturnType
, signature
.Parameters
, signature
.AcceptVarArgs
);