BOO-999
[boo.git] / src / Boo.Lang.Compiler / Steps / BindTypeMembers.cs
blobf68d8d96c28b29f815a64197d64afacfd58c2ff3
1 #region license
2 // Copyright (c) 2003, 2004, 2005 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.
16 //
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
30 using System;
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);
99 Visit(node.Getter);
100 Visit(node.Setter);
101 Visit(node.ExplicitInfo);
104 override public void OnExplicitMemberInfo(ExplicitMemberInfo node)
106 Visit(node.InterfaceType);
109 override public void OnEvent(Event node)
111 _events.Add(node);
114 void BindAllEvents()
116 foreach (Event node in _events)
118 BindEvent(node);
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;
132 if (!typeIsCallable)
134 Errors.Add(
135 CompilerErrorFactory.EventTypeIsNotCallable(node.Type,
136 type.ToString()));
139 if (declaringType.IsInterface)
141 BindInterfaceEvent(node);
143 else
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;
164 if (node.IsStatic)
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);
176 else
178 Visit(node.Add);
181 if (null == node.Remove)
183 node.Remove = CreateEventRemoveMethod(node, backingField);
185 else
187 Visit(node.Remove);
190 if (null == node.Raise)
192 if (typeIsCallable)
194 node.Raise = CreateEventRaiseMethod(node, backingField);
197 else
199 Visit(node.Raise);
203 override public void OnClassDefinition(ClassDefinition node)
205 Visit(node.Members);
208 override public void OnModule(Module node)
210 Visit(node.Members);
213 override public void Run()
215 NameResolutionService.Reset();
216 Visit(CompileUnit.Modules);
217 BindAllParameters();
218 BindAllEvents();
221 override public void Dispose()
223 _parameters.Clear();
224 _events.Clear();
225 base.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)
250 return;
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),
266 "handler",
267 GetType(node.Type)));
268 return method;
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,
285 node.Modifiers);
286 method.Parameters.Add(
287 CodeBuilder.CreateParameterDeclaration(
288 CodeBuilder.GetFirstParameterIndex(node),
289 "handler",
290 GetType(node.Type)));
291 return method;
294 Method CreateEventAddMethod(Event node, Field backingField)
296 Method m = CreateEventMethod(node, "add_");
297 m.Body.Add(
298 CodeBuilder.CreateAssignment(
299 CodeBuilder.CreateReference(backingField),
300 CodeBuilder.CreateMethodInvocation(
301 Delegate_Combine,
302 CodeBuilder.CreateReference(backingField),
303 CodeBuilder.CreateReference(m.Parameters[0]))));
304 return m;
307 Method CreateEventRemoveMethod(Event node, Field backingField)
309 Method m = CreateEventMethod(node, "remove_");
310 m.Body.Add(
311 CodeBuilder.CreateAssignment(
312 CodeBuilder.CreateReference(backingField),
313 CodeBuilder.CreateMethodInvocation(
314 Delegate_Remove,
315 CodeBuilder.CreateReference(backingField),
316 CodeBuilder.CreateReference(m.Parameters[0]))));
317 return m;
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);
332 if (node.IsPrivate)
334 modifiers |= TypeMemberModifiers.Private;
336 else
338 modifiers |= TypeMemberModifiers.Protected | TypeMemberModifiers.Internal;
341 Method method = CodeBuilder.CreateMethod("raise_" + node.Name,
342 TypeSystemServices.VoidType,
343 modifiers);
345 ICallableType type = GetEntity(node.Type) as ICallableType;
346 if (null != type)
348 int index = CodeBuilder.GetFirstParameterIndex(node);
349 foreach (IParameter parameter in type.GetSignature().Parameters)
351 method.Parameters.Add(
352 CodeBuilder.CreateParameterDeclaration(
353 index,
354 parameter.Name,
355 parameter.Type,
356 parameter.IsByRef));
357 ++index;
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);
375 return method;