PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Dependencies/boo/src/Boo.Lang.Compiler/TypeSystem/NameResolutionService.cs

https://github.com/w4x/boolangstudio
C# | 634 lines | 519 code | 82 blank | 33 comment | 148 complexity | 3ae8c6802c248d0212dd61767fa3e807 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.TypeSystem
  29. {
  30. using System;
  31. using System.Collections;
  32. using Boo.Lang.Compiler.Ast;
  33. using System.Reflection;
  34. using System.Collections.Generic;
  35. public class NameResolutionService
  36. {
  37. public static readonly char[] DotArray = new char[] { '.' };
  38. protected CompilerContext _context;
  39. protected INamespace _current;
  40. protected INamespace _global = NullNamespace.Default;
  41. protected List _buffer = new List();
  42. protected List _innerBuffer = new List();
  43. public NameResolutionService(CompilerContext context)
  44. {
  45. if (null == context) throw new ArgumentNullException("context");
  46. _context = context;
  47. }
  48. public INamespace GlobalNamespace
  49. {
  50. get { return _global; }
  51. set
  52. {
  53. if (null == value)
  54. {
  55. throw new ArgumentNullException("GlobalNamespace");
  56. }
  57. _global = value;
  58. }
  59. }
  60. public void EnterNamespace(INamespace ns)
  61. {
  62. if (null == ns) throw new ArgumentNullException("ns");
  63. _current = ns;
  64. }
  65. public INamespace CurrentNamespace
  66. {
  67. get { return _current; }
  68. }
  69. public void Reset()
  70. {
  71. EnterNamespace(_global);
  72. }
  73. public void Restore(INamespace saved)
  74. {
  75. if (null == saved) throw new ArgumentNullException("saved");
  76. _current = saved;
  77. }
  78. public void LeaveNamespace()
  79. {
  80. _current = _current.ParentNamespace;
  81. }
  82. public IEntity Resolve(string name)
  83. {
  84. return Resolve(name, EntityType.Any);
  85. }
  86. public IEntity Resolve(string name, EntityType flags)
  87. {
  88. _buffer.Clear();
  89. Resolve(_buffer, name, flags);
  90. return GetEntityFromBuffer();
  91. }
  92. public bool Resolve(List targetList, string name)
  93. {
  94. return Resolve(targetList, name, EntityType.Any);
  95. }
  96. public bool Resolve(List targetList, string name, EntityType flags)
  97. {
  98. IEntity entity = _context.TypeSystemServices.ResolvePrimitive(name);
  99. if (null != entity)
  100. {
  101. targetList.Add(entity);
  102. return true;
  103. }
  104. INamespace ns = _current;
  105. while (null != ns)
  106. {
  107. if (ns.Resolve(targetList, name, flags))
  108. {
  109. return true;
  110. }
  111. ns = ns.ParentNamespace;
  112. }
  113. return false;
  114. }
  115. public IEntity ResolveExtension(INamespace ns, string name)
  116. {
  117. IType type = ns as IType;
  118. if (null == type) return null;
  119. INamespace current = _current;
  120. while (null != current)
  121. {
  122. IEntity found = ResolveExtensionForType(current, type, name);
  123. if (null != found) return found;
  124. current = current.ParentNamespace;
  125. }
  126. return null;
  127. }
  128. class IsNotExtensionOf
  129. {
  130. private IType _type;
  131. public IsNotExtensionOf(IType type)
  132. {
  133. _type = type;
  134. }
  135. public bool Match(object item)
  136. {
  137. IExtensionEnabled e = item as IExtensionEnabled;
  138. if (e == null) return true;
  139. if (!e.IsExtension) return true;
  140. IParameter[] parameters = e.GetParameters();
  141. if (parameters.Length == 0) return true;
  142. return !parameters[0].Type.IsAssignableFrom(_type);
  143. }
  144. }
  145. private IEntity ResolveExtensionForType(INamespace ns, IType type, string name)
  146. {
  147. _buffer.Clear();
  148. if (!ns.Resolve(_buffer, name, EntityType.Method|EntityType.Property)) return null;
  149. _buffer.RemoveAll(new Predicate(new IsNotExtensionOf(type).Match));
  150. return GetEntityFromBuffer();
  151. }
  152. public IEntity ResolveQualifiedName(string name)
  153. {
  154. _buffer.Clear();
  155. ResolveQualifiedName(_buffer, name);
  156. return GetEntityFromBuffer();
  157. }
  158. public bool ResolveQualifiedName(List targetList, string name)
  159. {
  160. return ResolveQualifiedName(targetList, name, EntityType.Any);
  161. }
  162. public bool ResolveQualifiedName(List targetList, string name, EntityType flags)
  163. {
  164. if (!IsQualifiedName(name))
  165. {
  166. return Resolve(targetList, name, flags);
  167. }
  168. string[] parts = name.Split(DotArray);
  169. string topLevel = parts[0];
  170. _innerBuffer.Clear();
  171. if (Resolve(_innerBuffer, topLevel) && 1 == _innerBuffer.Count)
  172. {
  173. INamespace ns = _innerBuffer[0] as INamespace;
  174. if (null != ns)
  175. {
  176. int last = parts.Length-1;
  177. for (int i=1; i<last; ++i)
  178. {
  179. _innerBuffer.Clear();
  180. if (!ns.Resolve(_innerBuffer, parts[i], EntityType.Any) ||
  181. 1 != _innerBuffer.Count)
  182. {
  183. return false;
  184. }
  185. ns = _innerBuffer[0] as INamespace;
  186. if (null == ns)
  187. {
  188. return false;
  189. }
  190. }
  191. return ns.Resolve(targetList, parts[last], flags);
  192. }
  193. }
  194. return false;
  195. }
  196. public void ResolveTypeReference(TypeReference node)
  197. {
  198. if (null != node.Entity) return;
  199. switch (node.NodeType)
  200. {
  201. case NodeType.ArrayTypeReference:
  202. ResolveArrayTypeReference((ArrayTypeReference) node);
  203. break;
  204. case NodeType.CallableTypeReference:
  205. //not needed? (late resolution)
  206. //ResolveCallableTypeReference((CallableTypeReference) node);
  207. break;
  208. default:
  209. ResolveSimpleTypeReference((SimpleTypeReference) node);
  210. break;
  211. }
  212. }
  213. public void ResolveArrayTypeReference(ArrayTypeReference node)
  214. {
  215. if (null != node.Entity) return;
  216. ResolveTypeReference(node.ElementType);
  217. IType elementType = TypeSystemServices.GetType(node.ElementType);
  218. if (TypeSystemServices.IsError(elementType))
  219. {
  220. node.Entity = TypeSystemServices.ErrorEntity;
  221. }
  222. else
  223. {
  224. int rank = null == node.Rank ? 1 : (int)node.Rank.Value;
  225. node.Entity = _context.TypeSystemServices.GetArrayType(elementType, rank);
  226. }
  227. }
  228. private void ResolveTypeReferenceCollection(TypeReferenceCollection collection)
  229. {
  230. foreach (TypeReference tr in collection)
  231. {
  232. ResolveTypeReference(tr);
  233. }
  234. }
  235. public void ResolveSimpleTypeReference(SimpleTypeReference node)
  236. {
  237. if (null != node.Entity) return;
  238. IEntity entity = ResolveTypeName(node);
  239. if (null == entity)
  240. {
  241. node.Entity = NameNotType(node);
  242. return;
  243. }
  244. if (EntityType.Type != entity.EntityType)
  245. {
  246. if (EntityType.Ambiguous == entity.EntityType)
  247. {
  248. entity = AmbiguousReference(node, (Ambiguous)entity);
  249. }
  250. else
  251. {
  252. entity = NameNotType(node);
  253. }
  254. }
  255. else
  256. {
  257. GenericTypeReference gtr = node as GenericTypeReference;
  258. if (null != gtr)
  259. {
  260. ResolveTypeReferenceCollection(gtr.GenericArguments);
  261. entity = ResolveGenericTypeReference(gtr, entity);
  262. }
  263. GenericTypeDefinitionReference gtdr = node as GenericTypeDefinitionReference;
  264. if (null != gtdr)
  265. {
  266. IType type = (IType)entity;
  267. if (gtdr.GenericPlaceholders != type.GenericInfo.GenericParameters.Length)
  268. {
  269. entity = GenericArgumentsCountMismatch(gtdr, type);
  270. }
  271. }
  272. node.Name = entity.FullName;
  273. }
  274. node.Entity = entity;
  275. }
  276. private IEntity ResolveTypeName(SimpleTypeReference node)
  277. {
  278. _buffer.Clear();
  279. if (IsQualifiedName(node.Name))
  280. {
  281. ResolveQualifiedName(_buffer, node.Name);
  282. }
  283. else
  284. {
  285. Resolve(_buffer, node.Name, EntityType.Type);
  286. }
  287. // Remove from the buffer types that do not match requested generity
  288. FilterGenericTypes(_buffer, node);
  289. return GetEntityFromBuffer();
  290. }
  291. public IType ResolveGenericTypeReference(GenericTypeReference gtr, IEntity definition)
  292. {
  293. ResolveTypeReferenceCollection(gtr.GenericArguments);
  294. return (IType)_context.TypeSystemServices.GenericsServices.ConstructEntity(definition, gtr, gtr.GenericArguments);
  295. }
  296. public IEntity ResolveGenericReferenceExpression(GenericReferenceExpression gre, IEntity definition)
  297. {
  298. ResolveTypeReferenceCollection(gre.GenericArguments);
  299. return _context.TypeSystemServices.GenericsServices.ConstructEntity(definition, gre, gre.GenericArguments);
  300. }
  301. private void FilterGenericTypes(List types, SimpleTypeReference node)
  302. {
  303. bool genericRequested = (node is GenericTypeReference || node is GenericTypeDefinitionReference);
  304. for (int i = 0; i < types.Count; i++)
  305. {
  306. IType type = types[i] as IType;
  307. if (type == null) continue;
  308. // Remove type from list of matches if it doesn't match requested generity
  309. if (type.GenericInfo != null ^ genericRequested)
  310. {
  311. types.RemoveAt(i);
  312. i--;
  313. }
  314. }
  315. }
  316. private IEntity NameNotType(SimpleTypeReference node)
  317. {
  318. string suggestion = GetMostSimilarTypeName(node.Name);
  319. _context.Errors.Add(CompilerErrorFactory.NameNotType(node, node.ToCodeString(), suggestion));
  320. return TypeSystemServices.ErrorEntity;
  321. }
  322. private IEntity AmbiguousReference(SimpleTypeReference node, Ambiguous entity)
  323. {
  324. _context.Errors.Add(CompilerErrorFactory.AmbiguousReference(node, node.Name, entity.Entities));
  325. return TypeSystemServices.ErrorEntity;
  326. }
  327. private IEntity GenericArgumentsCountMismatch(TypeReference node, IType type)
  328. {
  329. _context.Errors.Add(CompilerErrorFactory.GenericDefinitionArgumentCount(node, type.FullName, type.GenericInfo.GenericParameters.Length));
  330. return TypeSystemServices.ErrorEntity;
  331. }
  332. public static IField ResolveField(IType type, string name)
  333. {
  334. return (IField)ResolveMember(type, name, EntityType.Field);
  335. }
  336. public static IMethod ResolveMethod(IType type, string name)
  337. {
  338. return (IMethod)ResolveMember(type, name, EntityType.Method);
  339. }
  340. public static IProperty ResolveProperty(IType type, string name)
  341. {
  342. return (IProperty)ResolveMember(type, name, EntityType.Property);
  343. }
  344. public static IEntity ResolveMember(IType type, string name, EntityType elementType)
  345. {
  346. foreach (IEntity member in type.GetMembers())
  347. {
  348. if (elementType == member.EntityType && name == member.Name)
  349. {
  350. return member;
  351. }
  352. }
  353. return null;
  354. }
  355. public IEntity Resolve(INamespace ns, string name, EntityType elementType)
  356. {
  357. _buffer.Clear();
  358. ns.Resolve(_buffer, name, elementType);
  359. return GetEntityFromList(_buffer);
  360. }
  361. public IEntity Resolve(INamespace ns, string name)
  362. {
  363. return Resolve(ns, name, EntityType.Any);
  364. }
  365. IEntity GetEntityFromBuffer()
  366. {
  367. return GetEntityFromList(_buffer);
  368. }
  369. public static IEntity GetEntityFromList(IList list)
  370. {
  371. IEntity element = null;
  372. if (list.Count > 0)
  373. {
  374. if (list.Count > 1)
  375. {
  376. element = new Ambiguous(list);
  377. }
  378. else
  379. {
  380. element = (IEntity)list[0];
  381. }
  382. list.Clear();
  383. }
  384. return element;
  385. }
  386. static bool IsQualifiedName(string name)
  387. {
  388. return name.IndexOf('.') > 0;
  389. }
  390. public static bool IsFlagSet(EntityType flags, EntityType flag)
  391. {
  392. return flag == (flags & flag);
  393. }
  394. public void OrganizeAssemblyTypes(Assembly asm)
  395. {
  396. CatalogPublicTypes(asm.GetTypes());
  397. }
  398. private void CatalogPublicTypes(Type[] types)
  399. {
  400. string lastNs = "!!not a namespace!!";
  401. NamespaceEntity lastNsEntity = null;
  402. foreach (Type type in types)
  403. {
  404. if (!type.IsPublic) continue;
  405. string ns = type.Namespace ?? string.Empty;
  406. //retrieve the namespace only if we don't have it handy already
  407. //usually we'll have it since GetExportedTypes() seems to export
  408. //types in a sorted fashion.
  409. if (ns != lastNs)
  410. {
  411. lastNs = ns;
  412. lastNsEntity = GetNamespace(ns);
  413. lastNsEntity.Add(type);
  414. }
  415. else
  416. {
  417. lastNsEntity.Add(type);
  418. }
  419. }
  420. }
  421. public NamespaceEntity GetNamespace(string ns)
  422. {
  423. string[] namespaceHierarchy = ns.Split('.');
  424. string topLevelName = namespaceHierarchy[0];
  425. NamespaceEntity topLevel = GetTopLevelNamespace(topLevelName);
  426. NamespaceEntity current = topLevel;
  427. for (int i=1; i<namespaceHierarchy.Length; ++i)
  428. {
  429. current = current.GetChildNamespace(namespaceHierarchy[i]);
  430. }
  431. return current;
  432. }
  433. NamespaceEntity GetTopLevelNamespace(string topLevelName)
  434. {
  435. GlobalNamespace globalNS = GetGlobalNamespace();
  436. if (globalNS == null) return null;
  437. NamespaceEntity entity = (NamespaceEntity)globalNS.GetChild(topLevelName);
  438. if (null == entity)
  439. {
  440. entity = new NamespaceEntity(null, _context.TypeSystemServices, topLevelName);
  441. globalNS.SetChild(topLevelName, entity);
  442. }
  443. return entity;
  444. }
  445. GlobalNamespace GetGlobalNamespace()
  446. {
  447. INamespace ns = _global;
  448. GlobalNamespace globals = ns as GlobalNamespace;
  449. while (globals == null && ns != null)
  450. {
  451. ns = ns.ParentNamespace;
  452. globals = ns as GlobalNamespace;
  453. }
  454. return globals;
  455. }
  456. private static void FlattenChildNamespaces(List<INamespace> list, INamespace ns)
  457. {
  458. foreach (IEntity ent in ns.GetMembers())
  459. {
  460. if (EntityType.Namespace != ent.EntityType) continue;
  461. list.Add((INamespace) ent);
  462. FlattenChildNamespaces(list, (INamespace) ent);
  463. }
  464. }
  465. public string GetMostSimilarTypeName(string name)
  466. {
  467. string[] nsHierarchy = name.Split('.');
  468. int nshLen = nsHierarchy.Length;
  469. string suggestion = null;
  470. if (nshLen > 1)
  471. {
  472. INamespace ns = null;
  473. INamespace prevNs = null;
  474. for (int i = 1; i < nshLen; i++)
  475. {
  476. string currentNsName = string.Join(".", nsHierarchy, 0, i);
  477. ns = ResolveQualifiedName(currentNsName) as INamespace;
  478. if (null == ns)
  479. {
  480. nsHierarchy[i-1] = GetMostSimilarMemberName(prevNs, nsHierarchy[i-1], EntityType.Namespace);
  481. if (null == nsHierarchy[i-1]) break;
  482. i--; continue; //reloop to resolve step
  483. }
  484. prevNs = ns;
  485. }
  486. suggestion = GetMostSimilarMemberName(ns, nsHierarchy[nshLen-1], EntityType.Type);
  487. if (null != suggestion)
  488. {
  489. nsHierarchy[nshLen-1] = suggestion;
  490. return string.Join(".", nsHierarchy);
  491. }
  492. }
  493. List<INamespace> nsList = new List<INamespace>();
  494. FlattenChildNamespaces(nsList, GetGlobalNamespace());
  495. nsList.Reverse();//most recently added namespaces first
  496. foreach (INamespace nse in nsList)
  497. {
  498. suggestion = GetMostSimilarMemberName(nse, nsHierarchy[nshLen-1], EntityType.Type);
  499. if (null != suggestion) return nse.ToString()+"."+suggestion;
  500. }
  501. return GetMostSimilarMemberName(GetGlobalNamespace(), nsHierarchy[nshLen-1], EntityType.Type);
  502. }
  503. public string GetMostSimilarMemberName(INamespace ns, string name, EntityType elementType)
  504. {
  505. if (null == ns) return null;
  506. string expectedSoundex = ToSoundex(name);
  507. string lastMemberName = null;
  508. foreach (IEntity member in ns.GetMembers())
  509. {
  510. if (EntityType.Any != elementType && elementType != member.EntityType)
  511. continue;
  512. if (lastMemberName == member.Name)
  513. continue;//no need to check this name again
  514. //TODO: try Levenshtein distance or Metaphone instead of Soundex.
  515. if (expectedSoundex == ToSoundex(member.Name))
  516. {
  517. return member.Name;
  518. }
  519. lastMemberName = member.Name;
  520. }
  521. return null;
  522. }
  523. private static string ToSoundex(string s)
  524. {
  525. if (s.Length < 2) return null;
  526. char[] code = "?0000".ToCharArray();
  527. string ws = s.ToLowerInvariant();
  528. int wsLen = ws.Length;
  529. char lastChar = ' ';
  530. int lastCharPos = 1;
  531. code[0] = ws[0];
  532. for (int i = 1; i < wsLen; i++)
  533. {
  534. char wsc = ws[i];
  535. char c = ' ';
  536. if (wsc == 'b' || wsc == 'f' || wsc == 'p' || wsc == 'v') c = '1';
  537. if (wsc == 'c' || wsc == 'g' || wsc == 'j' || wsc == 'k' || wsc == 'q' || wsc == 's' || wsc == 'x' || wsc == 'z') c = '2';
  538. if (wsc == 'd' || wsc == 't') c = '3';
  539. if (wsc == 'l') c = '4';
  540. if (wsc == 'm' || wsc == 'n') c = '5';
  541. if (wsc == 'r') c = '6';
  542. if (c == lastChar) continue;
  543. lastChar = c;
  544. if (c == ' ') continue;
  545. code[lastCharPos] = c;
  546. lastCharPos++;
  547. if (lastCharPos > 4) break;
  548. }
  549. return new string(code);
  550. }
  551. }
  552. }