BOO-988: Added else block to the for and while statements, and include a suite of...
[boo.git] / src / Boo.Lang.Compiler / Steps / BindAndApplyAttributes.cs
blob22fd234579961027c0ce9496f1b17aef0e02e84f
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.Steps
31 using System;
32 using Boo.Lang.Compiler.Ast;
33 using Boo.Lang.Compiler;
34 using Boo.Lang.Compiler.TypeSystem;
35 using Boo.Lang.Compiler.Util;
36 using Reflection = System.Reflection;
38 class ApplyAttributeTask : ITask
40 CompilerContext _context;
42 Boo.Lang.Compiler.Ast.Attribute _attribute;
44 Type _type;
46 Node _targetNode;
48 public ApplyAttributeTask(CompilerContext context, Boo.Lang.Compiler.Ast.Attribute attribute, Type type)
50 _context = context;
51 _attribute = attribute;
52 _type = type;
53 _targetNode = GetTargetNode();
56 private Node GetTargetNode()
58 Module module = _attribute.ParentNode as Module;
59 if (module != null && module.AssemblyAttributes.ContainsNode(_attribute))
61 return module.ParentNode;
63 return _attribute.ParentNode;
66 public void Execute()
68 try
70 IAstAttribute aa = CreateAstAttributeInstance();
71 if (null != aa)
73 aa.Initialize(_context);
74 using (aa)
76 aa.Apply(_targetNode);
80 catch (Exception x)
82 _context.TraceError(x);
83 _context.Errors.Add(CompilerErrorFactory.AttributeApplicationError(x, _attribute, _type));
84 System.Console.WriteLine(x.StackTrace);
88 public IAstAttribute CreateAstAttributeInstance()
90 object[] parameters = _attribute.Arguments.Count > 0 ? _attribute.Arguments.ToArray() : new object[0];
92 IAstAttribute aa = null;
93 try
95 aa = (IAstAttribute)Activator.CreateInstance(_type, parameters);
97 catch (MissingMethodException x)
99 _context.Errors.Add(CompilerErrorFactory.MissingConstructor(x, _attribute, _type, parameters));
100 return null;
103 aa.Attribute = _attribute;
105 if (_attribute.NamedArguments.Count > 0)
107 bool initialized = true;
109 foreach (ExpressionPair p in _attribute.NamedArguments)
111 bool success = SetFieldOrProperty(aa, p);
112 initialized = initialized && success;
115 if (!initialized)
117 return null;
121 return aa;
124 bool SetFieldOrProperty(IAstAttribute aa, ExpressionPair p)
126 ReferenceExpression name = p.First as ReferenceExpression;
127 if (null == name)
129 _context.Errors.Add(CompilerErrorFactory.NamedParameterMustBeIdentifier(p));
130 return false;
132 else
134 Reflection.MemberInfo[] members = _type.FindMembers(
135 Reflection.MemberTypes.Property | Reflection.MemberTypes.Field,
136 Reflection.BindingFlags.Instance | Reflection.BindingFlags.Public,
137 Type.FilterName, name.Name);
138 if (members.Length > 0)
140 if (members.Length > 1)
142 _context.Errors.Add(CompilerErrorFactory.AmbiguousReference(name, members));
143 return false;
145 else
147 Reflection.MemberInfo m = members[0];
148 Reflection.PropertyInfo property = m as Reflection.PropertyInfo;
149 if (null != property)
151 property.SetValue(aa, p.Second, null);
153 else
155 Reflection.FieldInfo field = m as Reflection.FieldInfo;
156 if (null != field)
158 field.SetValue(aa, p.Second);
160 else
162 throw new InvalidOperationException();
167 else
169 _context.Errors.Add(CompilerErrorFactory.NotAPublicFieldOrProperty(name, name.Name, _type.FullName));
170 return false;
173 return true;
177 /// <summary>
178 /// Step 2. Processes AST attributes.
179 /// </summary>
180 public class BindAndApplyAttributes : AbstractNamespaceSensitiveTransformerCompilerStep
183 TaskList _tasks;
185 System.Text.StringBuilder _buffer = new System.Text.StringBuilder();
187 IType _astAttributeInterface;
189 Boo.Lang.List _elements = new Boo.Lang.List();
191 public BindAndApplyAttributes()
193 _tasks = new TaskList();
196 override public void Run()
198 _astAttributeInterface = TypeSystemServices.Map(typeof(IAstAttribute));
200 int step = 0;
201 while (step < Parameters.MaxAttributeSteps)
203 Visit(CompileUnit);
204 if (0 == _tasks.Count)
206 break;
208 _tasks.Flush();
209 ++step;
213 override public void OnModule(Boo.Lang.Compiler.Ast.Module module)
215 EnterNamespace((INamespace)TypeSystemServices.GetEntity(module));
218 Visit(module.Members);
219 Visit(module.Globals);
220 Visit(module.Attributes);
221 Visit(module.AssemblyAttributes);
223 finally
225 LeaveNamespace();
229 void VisitTypeDefinition(TypeDefinition node)
231 Visit(node.Members);
232 Visit(node.Attributes);
235 override public void OnClassDefinition(ClassDefinition node)
237 VisitTypeDefinition(node);
240 override public void OnInterfaceDefinition(InterfaceDefinition node)
242 VisitTypeDefinition(node);
245 override public void OnStructDefinition(StructDefinition node)
247 VisitTypeDefinition(node);
250 override public void OnEnumDefinition(EnumDefinition node)
252 VisitTypeDefinition(node);
255 override public void OnBlock(Block node)
257 // No need to visit blocks
260 override public void OnAttribute(Boo.Lang.Compiler.Ast.Attribute attribute)
262 if (null != attribute.Entity)
264 return;
267 _elements.Clear();
269 if (!NameResolutionService.ResolveQualifiedName(_elements, BuildAttributeName(attribute.Name, true)))
271 if (!NameResolutionService.ResolveQualifiedName(_elements, BuildAttributeName(attribute.Name, false)))
273 NameResolutionService.ResolveQualifiedName(_elements, attribute.Name);
277 if (_elements.Count == 0)
279 string suggestion = NameResolutionService.GetMostSimilarTypeName(BuildAttributeName(attribute.Name, true));
280 if (null == suggestion)
281 suggestion = NameResolutionService.GetMostSimilarTypeName(BuildAttributeName(attribute.Name, false));
283 Error(attribute, CompilerErrorFactory.UnknownAttribute(attribute, attribute.Name, suggestion));
284 return;
287 if (_elements.Count > 1)
289 Error(attribute, CompilerErrorFactory.AmbiguousReference(
290 attribute,
291 attribute.Name,
292 _elements));
293 return;
296 // if _elements.Count == 1
297 IEntity tag = (IEntity)_elements[0];
298 if (EntityType.Type != tag.EntityType)
300 Error(attribute, CompilerErrorFactory.NameNotType(attribute, attribute.Name, null));
301 return;
304 IType attributeType = ((ITypedEntity)tag).Type;
305 if (IsAstAttribute(attributeType))
307 ExternalType externalType = attributeType as ExternalType;
308 if (null == externalType)
310 Error(attribute, CompilerErrorFactory.AstAttributeMustBeExternal(attribute, attributeType.FullName));
312 else
314 ScheduleAttributeApplication(attribute, externalType.ActualType);
316 RemoveCurrentNode();
319 else
321 if (!IsSystemAttribute(attributeType))
323 Error(attribute, CompilerErrorFactory.TypeNotAttribute(attribute, attributeType.FullName));
325 else
327 // remember the attribute's type
328 attribute.Name = attributeType.FullName;
329 attribute.Entity = attributeType;
330 CheckAttributeParameters(attribute);
336 private void CheckAttributeParameters(Boo.Lang.Compiler.Ast.Attribute node)
338 foreach(Expression e in node.Arguments)
340 if (e.NodeType == NodeType.BinaryExpression
341 && ((BinaryExpression)e).Operator == BinaryOperatorType.Assign)
343 Error(node, CompilerErrorFactory.ColonInsteadOfEquals(node));
348 override public void LeaveProperty(Property node)
350 if (node.Name == "self")
352 node.Name = "Item";
354 if (node.Name == "Item" && node.Parameters.Count > 0 && !node.IsStatic)
356 TypeDefinition t = node.ParentNode as TypeDefinition;
357 if (t != null)
359 bool already_has_attribute = false;
360 foreach(Boo.Lang.Compiler.Ast.Attribute a in t.Attributes)
362 if (a.Name.IndexOf("DefaultMember") >= 0)
364 already_has_attribute = true;
365 break;
368 if (!already_has_attribute)
370 Boo.Lang.Compiler.Ast.Attribute att = new Boo.Lang.Compiler.Ast.Attribute(t.LexicalInfo);
371 att.Name = Types.DefaultMemberAttribute.FullName;
372 att.Arguments.Add(new StringLiteralExpression(node.Name));
373 t.Attributes.Add(att);
374 Visit(att);
380 void Error(Boo.Lang.Compiler.Ast.Attribute node, CompilerError error)
382 node.Entity = TypeSystemServices.ErrorEntity;
383 Errors.Add(error);
386 void ScheduleAttributeApplication(Boo.Lang.Compiler.Ast.Attribute attribute, Type type)
388 _tasks.Add(new ApplyAttributeTask(_context, attribute, type));
391 string BuildAttributeName(string name, bool forcePascalNaming)
393 _buffer.Length = 0;
394 if (forcePascalNaming && !Char.IsUpper(name[0]))
396 _buffer.Append(Char.ToUpper(name[0]));
397 _buffer.Append(name.Substring(1));
398 _buffer.Append("Attribute");
400 else
402 _buffer.Append(name);
403 _buffer.Append("Attribute");
405 return _buffer.ToString();
408 bool IsSystemAttribute(IType type)
410 return TypeSystemServices.IsAttribute(type);
413 bool IsAstAttribute(IType type)
415 return _astAttributeInterface.IsAssignableFrom(type);