2 // Copyright (c) 2003, 2004, 2005 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.
32 namespace Boo
.Lang
.Compiler
.Steps
34 using Boo
.Lang
.Compiler
.Ast
;
35 using Boo
.Lang
.Compiler
.TypeSystem
;
37 public class BindTypeMembers
: AbstractVisitorCompilerStep
39 Boo
.Lang
.List _parameters
= new Boo
.Lang
.List();
40 Boo
.Lang
.List _events
= new Boo
.Lang
.List();
41 IMethod _delegate_Combine
;
42 IMethod _delegate_Remove
;
44 public BindTypeMembers()
48 override public void OnMethod(Method node
)
50 // The method itself has been bound earlier during BindMethods, so
51 // we just have to remember to bind its parameters
52 _parameters
.Add(node
);
53 Visit(node
.ExplicitInfo
);
56 void BindAllParameters()
58 foreach (INodeWithParameters node
in _parameters
)
60 TypeMember member
= (TypeMember
)node
;
61 NameResolutionService
.Restore((INamespace
)TypeSystemServices
.GetEntity(member
.DeclaringType
));
62 CodeBuilder
.BindParameterDeclarations(member
.IsStatic
, node
);
63 if (member
.IsPrivate
&& !member
.IsSynthetic
)
65 member
.Annotate("PrivateMemberNeverUsed", null);
70 override public void OnConstructor(Constructor node
)
72 if (null == node
.Entity
)
74 node
.Entity
= new InternalConstructor(TypeSystemServices
, node
);
76 _parameters
.Add(node
);
79 override public void OnField(Field node
)
81 if (null == node
.Entity
)
83 node
.Entity
= new InternalField(node
);
84 if (node
.IsPrivate
&& !node
.IsSynthetic
)
86 node
.Annotate("PrivateMemberNeverUsed", null);
91 override public void OnProperty(Property node
)
93 if (null == node
.Entity
)
95 node
.Entity
= new InternalProperty(TypeSystemServices
, node
);
97 _parameters
.Add(node
);
101 Visit(node
.ExplicitInfo
);
104 override public void OnExplicitMemberInfo(ExplicitMemberInfo node
)
106 Visit(node
.InterfaceType
);
109 override public void OnEvent(Event node
)
116 foreach (Event node
in _events
)
122 void BindEvent(Event node
)
124 if (null == node
.Entity
)
126 node
.Entity
= new InternalEvent(TypeSystemServices
, node
);
129 IType type
= GetType(node
.Type
);
130 IType declaringType
= GetType(node
.DeclaringType
);
131 bool typeIsCallable
= type
is ICallableType
;
135 CompilerErrorFactory
.EventTypeIsNotCallable(node
.Type
,
139 if (declaringType
.IsInterface
)
141 BindInterfaceEvent(node
);
145 BindClassEvent(node
, type
, typeIsCallable
);
149 private void BindInterfaceEvent(Event node
)
151 // TODO: Add checks to ensure Add/Remove/Raise are
152 // null before doing this.
153 node
.Add
= CreateInterfaceEventAddMethod(node
);
154 node
.Remove
= CreateInterfaceEventRemoveMethod(node
);
157 private void BindClassEvent(Event node
, IType type
, bool typeIsCallable
)
159 Field backingField
= CodeBuilder
.CreateField("___" + node
.Name
, type
);
160 if (node
.IsTransient
)
162 backingField
.Modifiers
|= TypeMemberModifiers
.Transient
;
166 backingField
.Modifiers
|= TypeMemberModifiers
.Static
;
168 node
.DeclaringType
.Members
.Add(backingField
);
170 ((InternalEvent
)node
.Entity
).BackingField
= (InternalField
)backingField
.Entity
;
172 if (null == node
.Add
)
174 node
.Add
= CreateEventAddMethod(node
, backingField
);
181 if (null == node
.Remove
)
183 node
.Remove
= CreateEventRemoveMethod(node
, backingField
);
190 if (null == node
.Raise
)
194 node
.Raise
= CreateEventRaiseMethod(node
, backingField
);
203 override public void OnClassDefinition(ClassDefinition node
)
208 override public void OnModule(Module node
)
213 override public void Run()
215 NameResolutionService
.Reset();
216 Visit(CompileUnit
.Modules
);
221 override public void Dispose()
228 IMethod Delegate_Combine
232 InitializeDelegateMethods();
233 return _delegate_Combine
;
237 IMethod Delegate_Remove
241 InitializeDelegateMethods();
242 return _delegate_Remove
;
246 void InitializeDelegateMethods()
248 if (null != _delegate_Combine
)
252 Type delegateType
= Types
.Delegate
;
253 Type
[] delegates
= new Type
[] { delegateType, delegateType }
;
254 _delegate_Combine
= TypeSystemServices
.Map(delegateType
.GetMethod("Combine", delegates
));
255 _delegate_Remove
= TypeSystemServices
.Map(delegateType
.GetMethod("Remove", delegates
));
258 Method
CreateInterfaceEventMethod(Event node
, string prefix
)
260 Method method
= CodeBuilder
.CreateMethod(prefix
+ node
.Name
,
261 TypeSystemServices
.VoidType
,
262 TypeMemberModifiers
.Public
| TypeMemberModifiers
.Virtual
| TypeMemberModifiers
.Abstract
);
263 method
.Parameters
.Add(
264 CodeBuilder
.CreateParameterDeclaration(
265 CodeBuilder
.GetFirstParameterIndex(node
),
267 GetType(node
.Type
)));
271 Method
CreateInterfaceEventAddMethod(Event node
)
273 return CreateInterfaceEventMethod(node
, "add_");
276 Method
CreateInterfaceEventRemoveMethod(Event node
)
278 return CreateInterfaceEventMethod(node
, "remove_");
281 Method
CreateEventMethod(Event node
, string prefix
)
283 Method method
= CodeBuilder
.CreateMethod(prefix
+ node
.Name
,
284 TypeSystemServices
.VoidType
,
286 method
.Parameters
.Add(
287 CodeBuilder
.CreateParameterDeclaration(
288 CodeBuilder
.GetFirstParameterIndex(node
),
290 GetType(node
.Type
)));
294 Method
CreateEventAddMethod(Event node
, Field backingField
)
296 Method m
= CreateEventMethod(node
, "add_");
298 CodeBuilder
.CreateAssignment(
299 CodeBuilder
.CreateReference(backingField
),
300 CodeBuilder
.CreateMethodInvocation(
302 CodeBuilder
.CreateReference(backingField
),
303 CodeBuilder
.CreateReference(m
.Parameters
[0]))));
307 Method
CreateEventRemoveMethod(Event node
, Field backingField
)
309 Method m
= CreateEventMethod(node
, "remove_");
311 CodeBuilder
.CreateAssignment(
312 CodeBuilder
.CreateReference(backingField
),
313 CodeBuilder
.CreateMethodInvocation(
315 CodeBuilder
.CreateReference(backingField
),
316 CodeBuilder
.CreateReference(m
.Parameters
[0]))));
320 TypeMemberModifiers
RemoveAccessiblityModifiers(TypeMemberModifiers modifiers
)
322 TypeMemberModifiers mask
= TypeMemberModifiers
.Public
|
323 TypeMemberModifiers
.Protected
|
324 TypeMemberModifiers
.Private
|
325 TypeMemberModifiers
.Internal
;
326 return modifiers
& ~mask
;
329 Method
CreateEventRaiseMethod(Event node
, Field backingField
)
331 TypeMemberModifiers modifiers
= RemoveAccessiblityModifiers(node
.Modifiers
);
334 modifiers
|= TypeMemberModifiers
.Private
;
338 modifiers
|= TypeMemberModifiers
.Protected
| TypeMemberModifiers
.Internal
;
341 Method method
= CodeBuilder
.CreateMethod("raise_" + node
.Name
,
342 TypeSystemServices
.VoidType
,
345 ICallableType type
= GetEntity(node
.Type
) as ICallableType
;
348 int index
= CodeBuilder
.GetFirstParameterIndex(node
);
349 foreach (IParameter parameter
in type
.GetSignature().Parameters
)
351 method
.Parameters
.Add(
352 CodeBuilder
.CreateParameterDeclaration(
361 MethodInvocationExpression mie
= CodeBuilder
.CreateMethodInvocation(
362 CodeBuilder
.CreateReference(backingField
),
363 NameResolutionService
.ResolveMethod(GetType(backingField
.Type
), "Invoke"));
364 foreach (ParameterDeclaration parameter
in method
.Parameters
)
366 mie
.Arguments
.Add(CodeBuilder
.CreateReference(parameter
));
369 IfStatement stmt
= new IfStatement(node
.LexicalInfo
);
370 stmt
.Condition
= CodeBuilder
.CreateNotNullTest(
371 CodeBuilder
.CreateReference(backingField
));
372 stmt
.TrueBlock
= new Block();
373 stmt
.TrueBlock
.Add(mie
);
374 method
.Body
.Add(stmt
);