PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Boo.Lang.Compiler/Steps/BindAndApplyAttributes.cs

https://github.com/boo/boo-lang
C# | 398 lines | 320 code | 47 blank | 31 comment | 41 complexity | 331186a350a06f18e74200032ba6f482 MD5 | raw file
Possible License(s): GPL-2.0
  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.
  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
  28. namespace Boo.Lang.Compiler.Steps
  29. {
  30. using System;
  31. using Boo.Lang.Compiler.Ast;
  32. using Boo.Lang.Compiler;
  33. using Boo.Lang.Compiler.TypeSystem;
  34. using Boo.Lang.Compiler.Util;
  35. using Reflection = System.Reflection;
  36. class ApplyAttributeTask : ITask
  37. {
  38. CompilerContext _context;
  39. Boo.Lang.Compiler.Ast.Attribute _attribute;
  40. Type _type;
  41. Node _targetNode;
  42. public ApplyAttributeTask(CompilerContext context, Boo.Lang.Compiler.Ast.Attribute attribute, Type type)
  43. {
  44. _context = context;
  45. _attribute = attribute;
  46. _type = type;
  47. _targetNode = GetTargetNode();
  48. }
  49. private Node GetTargetNode()
  50. {
  51. Module module = _attribute.ParentNode as Module;
  52. if (module != null && module.AssemblyAttributes.ContainsNode(_attribute))
  53. {
  54. return module.ParentNode;
  55. }
  56. return _attribute.ParentNode;
  57. }
  58. public void Execute()
  59. {
  60. try
  61. {
  62. IAstAttribute aa = CreateAstAttributeInstance();
  63. if (null != aa)
  64. {
  65. aa.Initialize(_context);
  66. using (aa)
  67. {
  68. aa.Apply(_targetNode);
  69. }
  70. }
  71. }
  72. catch (Exception x)
  73. {
  74. _context.TraceError(x);
  75. _context.Errors.Add(CompilerErrorFactory.AttributeApplicationError(x, _attribute, _type));
  76. System.Console.WriteLine(x.StackTrace);
  77. }
  78. }
  79. public IAstAttribute CreateAstAttributeInstance()
  80. {
  81. object[] parameters = _attribute.Arguments.Count > 0 ? _attribute.Arguments.ToArray() : new object[0];
  82. IAstAttribute aa = null;
  83. try
  84. {
  85. aa = (IAstAttribute)Activator.CreateInstance(_type, parameters);
  86. }
  87. catch (MissingMethodException x)
  88. {
  89. _context.Errors.Add(CompilerErrorFactory.MissingConstructor(x, _attribute, _type, parameters));
  90. return null;
  91. }
  92. aa.Attribute = _attribute;
  93. if (_attribute.NamedArguments.Count > 0)
  94. {
  95. bool initialized = true;
  96. foreach (ExpressionPair p in _attribute.NamedArguments)
  97. {
  98. bool success = SetFieldOrProperty(aa, p);
  99. initialized = initialized && success;
  100. }
  101. if (!initialized)
  102. {
  103. return null;
  104. }
  105. }
  106. return aa;
  107. }
  108. bool SetFieldOrProperty(IAstAttribute aa, ExpressionPair p)
  109. {
  110. ReferenceExpression name = p.First as ReferenceExpression;
  111. if (null == name)
  112. {
  113. _context.Errors.Add(CompilerErrorFactory.NamedParameterMustBeIdentifier(p));
  114. return false;
  115. }
  116. else
  117. {
  118. Reflection.MemberInfo[] members = _type.FindMembers(
  119. Reflection.MemberTypes.Property | Reflection.MemberTypes.Field,
  120. Reflection.BindingFlags.Instance | Reflection.BindingFlags.Public,
  121. Type.FilterName, name.Name);
  122. if (members.Length > 0)
  123. {
  124. if (members.Length > 1)
  125. {
  126. _context.Errors.Add(CompilerErrorFactory.AmbiguousReference(name, members));
  127. return false;
  128. }
  129. else
  130. {
  131. Reflection.MemberInfo m = members[0];
  132. Reflection.PropertyInfo property = m as Reflection.PropertyInfo;
  133. if (null != property)
  134. {
  135. property.SetValue(aa, p.Second, null);
  136. }
  137. else
  138. {
  139. Reflection.FieldInfo field = m as Reflection.FieldInfo;
  140. if (null != field)
  141. {
  142. field.SetValue(aa, p.Second);
  143. }
  144. else
  145. {
  146. throw new InvalidOperationException();
  147. }
  148. }
  149. }
  150. }
  151. else
  152. {
  153. _context.Errors.Add(CompilerErrorFactory.NotAPublicFieldOrProperty(name, name.Name, _type.FullName));
  154. return false;
  155. }
  156. }
  157. return true;
  158. }
  159. }
  160. /// <summary>
  161. /// Step 2. Processes AST attributes.
  162. /// </summary>
  163. public class BindAndApplyAttributes : AbstractNamespaceSensitiveTransformerCompilerStep
  164. {
  165. TaskList _tasks;
  166. System.Text.StringBuilder _buffer = new System.Text.StringBuilder();
  167. IType _astAttributeInterface;
  168. Boo.Lang.List _elements = new Boo.Lang.List();
  169. public BindAndApplyAttributes()
  170. {
  171. _tasks = new TaskList();
  172. }
  173. public override void Initialize(CompilerContext context)
  174. {
  175. base.Initialize(context);
  176. _astAttributeInterface = TypeSystemServices.Map(typeof(IAstAttribute));
  177. }
  178. override public void Run()
  179. {
  180. int iteration = 0;
  181. while (iteration < Parameters.MaxExpansionIterations)
  182. {
  183. if (!BindAndApply())
  184. {
  185. break;
  186. }
  187. ++iteration;
  188. }
  189. }
  190. public bool BindAndApply()
  191. {
  192. Visit(CompileUnit);
  193. if (_tasks.Count == 0)
  194. {
  195. return false;
  196. }
  197. _tasks.Flush();
  198. return true;
  199. }
  200. override public void OnModule(Boo.Lang.Compiler.Ast.Module module)
  201. {
  202. EnterNamespace((INamespace)TypeSystemServices.GetEntity(module));
  203. try
  204. {
  205. Visit(module.Members);
  206. Visit(module.Globals);
  207. Visit(module.Attributes);
  208. Visit(module.AssemblyAttributes);
  209. }
  210. finally
  211. {
  212. LeaveNamespace();
  213. }
  214. }
  215. void VisitTypeDefinition(TypeDefinition node)
  216. {
  217. Visit(node.Members);
  218. Visit(node.Attributes);
  219. }
  220. override public void OnClassDefinition(ClassDefinition node)
  221. {
  222. VisitTypeDefinition(node);
  223. }
  224. override public void OnInterfaceDefinition(InterfaceDefinition node)
  225. {
  226. VisitTypeDefinition(node);
  227. }
  228. override public void OnStructDefinition(StructDefinition node)
  229. {
  230. VisitTypeDefinition(node);
  231. }
  232. override public void OnEnumDefinition(EnumDefinition node)
  233. {
  234. VisitTypeDefinition(node);
  235. }
  236. override public void OnBlock(Block node)
  237. {
  238. // No need to visit blocks
  239. }
  240. override public void OnAttribute(Boo.Lang.Compiler.Ast.Attribute attribute)
  241. {
  242. if (null != attribute.Entity)
  243. {
  244. return;
  245. }
  246. _elements.Clear();
  247. if (!NameResolutionService.ResolveQualifiedName(_elements, BuildAttributeName(attribute.Name, true)))
  248. {
  249. if (!NameResolutionService.ResolveQualifiedName(_elements, BuildAttributeName(attribute.Name, false)))
  250. {
  251. NameResolutionService.ResolveQualifiedName(_elements, attribute.Name);
  252. }
  253. }
  254. if (_elements.Count == 0)
  255. {
  256. string suggestion = NameResolutionService.GetMostSimilarTypeName(BuildAttributeName(attribute.Name, true));
  257. if (null == suggestion)
  258. suggestion = NameResolutionService.GetMostSimilarTypeName(BuildAttributeName(attribute.Name, false));
  259. Error(attribute, CompilerErrorFactory.UnknownAttribute(attribute, attribute.Name, suggestion));
  260. return;
  261. }
  262. if (_elements.Count > 1)
  263. {
  264. Error(attribute, CompilerErrorFactory.AmbiguousReference(
  265. attribute,
  266. attribute.Name,
  267. _elements));
  268. return;
  269. }
  270. // if _elements.Count == 1
  271. IEntity tag = (IEntity)_elements[0];
  272. if (EntityType.Type != tag.EntityType)
  273. {
  274. Error(attribute, CompilerErrorFactory.NameNotType(attribute, attribute.Name, null));
  275. return;
  276. }
  277. IType attributeType = ((ITypedEntity)tag).Type;
  278. if (IsAstAttribute(attributeType))
  279. {
  280. ExternalType externalType = attributeType as ExternalType;
  281. if (null == externalType)
  282. {
  283. Error(attribute, CompilerErrorFactory.AstAttributeMustBeExternal(attribute, attributeType.FullName));
  284. }
  285. else
  286. {
  287. ScheduleAttributeApplication(attribute, externalType.ActualType);
  288. RemoveCurrentNode();
  289. }
  290. }
  291. else
  292. {
  293. if (!IsSystemAttribute(attributeType))
  294. {
  295. Error(attribute, CompilerErrorFactory.TypeNotAttribute(attribute, attributeType.FullName));
  296. }
  297. else
  298. {
  299. // remember the attribute's type
  300. attribute.Name = attributeType.FullName;
  301. attribute.Entity = attributeType;
  302. CheckAttributeParameters(attribute);
  303. }
  304. }
  305. }
  306. private void CheckAttributeParameters(Boo.Lang.Compiler.Ast.Attribute node)
  307. {
  308. foreach(Expression e in node.Arguments)
  309. {
  310. if (e.NodeType == NodeType.BinaryExpression
  311. && ((BinaryExpression)e).Operator == BinaryOperatorType.Assign)
  312. {
  313. Error(node, CompilerErrorFactory.ColonInsteadOfEquals(node));
  314. }
  315. }
  316. }
  317. void Error(Boo.Lang.Compiler.Ast.Attribute node, CompilerError error)
  318. {
  319. node.Entity = TypeSystemServices.ErrorEntity;
  320. Errors.Add(error);
  321. }
  322. void ScheduleAttributeApplication(Boo.Lang.Compiler.Ast.Attribute attribute, Type type)
  323. {
  324. _tasks.Add(new ApplyAttributeTask(_context, attribute, type));
  325. }
  326. string BuildAttributeName(string name, bool forcePascalNaming)
  327. {
  328. _buffer.Length = 0;
  329. if (forcePascalNaming && !Char.IsUpper(name[0]))
  330. {
  331. _buffer.Append(Char.ToUpper(name[0]));
  332. _buffer.Append(name.Substring(1));
  333. _buffer.Append("Attribute");
  334. }
  335. else
  336. {
  337. _buffer.Append(name);
  338. _buffer.Append("Attribute");
  339. }
  340. return _buffer.ToString();
  341. }
  342. bool IsSystemAttribute(IType type)
  343. {
  344. return TypeSystemServices.IsAttribute(type);
  345. }
  346. bool IsAstAttribute(IType type)
  347. {
  348. return _astAttributeInterface.IsAssignableFrom(type);
  349. }
  350. }
  351. }