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
.Steps
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
;
48 public ApplyAttributeTask(CompilerContext context
, Boo
.Lang
.Compiler
.Ast
.Attribute attribute
, Type type
)
51 _attribute
= attribute
;
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
;
70 IAstAttribute aa
= CreateAstAttributeInstance();
73 aa
.Initialize(_context
);
76 aa
.Apply(_targetNode
);
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;
95 aa
= (IAstAttribute
)Activator
.CreateInstance(_type
, parameters
);
97 catch (MissingMethodException x
)
99 _context
.Errors
.Add(CompilerErrorFactory
.MissingConstructor(x
, _attribute
, _type
, parameters
));
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
;
124 bool SetFieldOrProperty(IAstAttribute aa
, ExpressionPair p
)
126 ReferenceExpression name
= p
.First
as ReferenceExpression
;
129 _context
.Errors
.Add(CompilerErrorFactory
.NamedParameterMustBeIdentifier(p
));
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
));
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);
155 Reflection
.FieldInfo field
= m
as Reflection
.FieldInfo
;
158 field
.SetValue(aa
, p
.Second
);
162 throw new InvalidOperationException();
169 _context
.Errors
.Add(CompilerErrorFactory
.NotAPublicFieldOrProperty(name
, name
.Name
, _type
.FullName
));
178 /// Step 2. Processes AST attributes.
180 public class BindAndApplyAttributes
: AbstractNamespaceSensitiveTransformerCompilerStep
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
));
201 while (step
< Parameters
.MaxAttributeSteps
)
204 if (0 == _tasks
.Count
)
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
);
229 void VisitTypeDefinition(TypeDefinition node
)
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
)
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
));
287 if (_elements
.Count
> 1)
289 Error(attribute
, CompilerErrorFactory
.AmbiguousReference(
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));
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
));
314 ScheduleAttributeApplication(attribute
, externalType
.ActualType
);
321 if (!IsSystemAttribute(attributeType
))
323 Error(attribute
, CompilerErrorFactory
.TypeNotAttribute(attribute
, attributeType
.FullName
));
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")
354 if (node
.Name
== "Item" && node
.Parameters
.Count
> 0 && !node
.IsStatic
)
356 TypeDefinition t
= node
.ParentNode
as TypeDefinition
;
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;
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
);
380 void Error(Boo
.Lang
.Compiler
.Ast
.Attribute node
, CompilerError error
)
382 node
.Entity
= TypeSystemServices
.ErrorEntity
;
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
)
394 if (forcePascalNaming
&& !Char
.IsUpper(name
[0]))
396 _buffer
.Append(Char
.ToUpper(name
[0]));
397 _buffer
.Append(name
.Substring(1));
398 _buffer
.Append("Attribute");
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
);