PageRenderTime 60ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/Tools/IronStudio/IronPythonToolsCore/PyAnalysis/ProjectState.cs

http://github.com/IronLanguages/main
C# | 731 lines | 559 code | 96 blank | 76 comment | 150 complexity | 096e8a0a6299bdeb940c225e8f644858 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. * ***************************************************************************/
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Reflection;
  20. using System.Threading;
  21. using IronPython.Compiler.Ast;
  22. using IronPython.Hosting;
  23. using IronPython.Modules;
  24. using IronPython.Runtime;
  25. using IronPython.Runtime.Operations;
  26. using IronPython.Runtime.Types;
  27. using Microsoft.IronPythonTools;
  28. using Microsoft.PyAnalysis.Interpreter;
  29. using Microsoft.PyAnalysis.Values;
  30. using Microsoft.Scripting;
  31. using Microsoft.Scripting.Actions;
  32. using Microsoft.Scripting.Hosting;
  33. using Microsoft.Scripting.Hosting.Providers;
  34. using Microsoft.Scripting.Library;
  35. using Microsoft.Scripting.Math;
  36. using Microsoft.Scripting.Runtime;
  37. namespace Microsoft.PyAnalysis {
  38. /// <summary>
  39. /// Connects multiple source files together into one project state for combined analysis
  40. /// </summary>
  41. class ProjectState {
  42. private readonly ScriptEngine _pythonEngine;
  43. private readonly CodeContext _codeContext;
  44. private readonly CodeContext _codeContextCls;
  45. private readonly List<ProjectEntry> _projectEntries;
  46. private readonly Dictionary<string, ModuleReference> _modules;
  47. private readonly Dictionary<string, ModuleInfo> _modulesByFilename;
  48. private readonly Dictionary<string, XamlProjectEntry> _xamlByFilename = new Dictionary<string, XamlProjectEntry>();
  49. private readonly Dictionary<object, object> _itemCache;
  50. private readonly BuiltinModule _builtinModule;
  51. private readonly List<KeyValuePair<Assembly, TopNamespaceTracker>> _references;
  52. internal readonly Namespace _propertyObj, _classmethodObj, _staticmethodObj, _typeObj, _intType, _rangeFunc, _frozensetType;
  53. internal readonly HashSet<Namespace> _objectSet;
  54. internal readonly Namespace _functionType;
  55. internal readonly BuiltinClassInfo _dictType, _listType, _tupleType, _generatorType, _stringType, _boolType, _setType;
  56. internal readonly ConstantInfo _noneInst;
  57. private readonly Queue<AnalysisUnit> _queue;
  58. private readonly DocumentationProvider _docProvider;
  59. private HashSet<string> _assemblyLoadList = new HashSet<string>();
  60. private static object _nullKey = new object();
  61. public ProjectState(ScriptEngine pythonEngine) {
  62. _pythonEngine = pythonEngine;
  63. _projectEntries = new List<ProjectEntry>();
  64. _modules = new Dictionary<string, ModuleReference>();
  65. _modulesByFilename = new Dictionary<string, ModuleInfo>(StringComparer.OrdinalIgnoreCase);
  66. _itemCache = new Dictionary<object, object>();
  67. var pythonContext = HostingHelpers.GetLanguageContext(_pythonEngine) as PythonContext;
  68. _codeContextCls = new ModuleContext(new PythonDictionary(), pythonContext).GlobalContext;
  69. _codeContextCls.ModuleContext.ShowCls = true;
  70. _codeContext = new ModuleContext(
  71. new PythonDictionary(),
  72. HostingHelpers.GetLanguageContext(_pythonEngine) as PythonContext
  73. ).GlobalContext;
  74. InitializeBuiltinModules();
  75. // TODO: Use reflection-only!
  76. _references = new List<KeyValuePair<Assembly, TopNamespaceTracker>>();
  77. AddAssembly(LoadAssemblyInfo(typeof(string).Assembly));
  78. AddAssembly(LoadAssemblyInfo(typeof(Debug).Assembly));
  79. // cached for quick checks to see if we're a call to clr.AddReference
  80. SpecializeFunction("clr", "AddReference", (n, unit, args) => AddReference(n, null));
  81. SpecializeFunction("clr", "AddReferenceByPartialName", (n, unit, args) => AddReference(n, ClrModule.LoadAssemblyByPartialName));
  82. SpecializeFunction("clr", "AddReferenceByName", (n, unit, args) => AddReference(n, null));
  83. SpecializeFunction("clr", "AddReferenceToFile", (n, unit, args) => AddReference(n, (s) => ClrModule.LoadAssemblyFromFile(_codeContext, s)));
  84. SpecializeFunction("clr", "AddReferenceToFileAndPath", (n, unit, args) => AddReference(n, (s) => ClrModule.LoadAssemblyFromFileWithPath(_codeContext, s)));
  85. try {
  86. SpecializeFunction("wpf", "LoadComponent", LoadComponent);
  87. } catch (KeyNotFoundException) {
  88. // IronPython.Wpf.dll isn't available...
  89. }
  90. SpecializeFunction("__builtin__", "range", (n, unit, args) => unit.DeclaringModule.GetOrMakeNodeVariable(n, (nn) => new RangeInfo(ClrModule.GetPythonType(typeof(List)), unit.ProjectState).SelfSet));
  91. SpecializeFunction("__builtin__", "min", ReturnUnionOfInputs);
  92. SpecializeFunction("__builtin__", "max", ReturnUnionOfInputs);
  93. _builtinModule = (BuiltinModule)Modules["__builtin__"].Module;
  94. _propertyObj = GetBuiltin("property");
  95. _classmethodObj = GetBuiltin("classmethod");
  96. _staticmethodObj = GetBuiltin("staticmethod");
  97. _typeObj = GetBuiltin("type");
  98. _intType = GetBuiltin("int");
  99. _stringType = (BuiltinClassInfo)GetBuiltin("str");
  100. _objectSet = new HashSet<Namespace>(new[] { GetBuiltin("object") });
  101. _setType = (BuiltinClassInfo)GetNamespaceFromObjects(TypeCache.Set);
  102. _rangeFunc = GetBuiltin("range");
  103. _frozensetType = GetBuiltin("frozenset");
  104. _functionType = GetNamespaceFromObjects(TypeCache.Function);
  105. _generatorType = (BuiltinClassInfo)GetNamespaceFromObjects(DynamicHelpers.GetPythonTypeFromType(typeof(PythonGenerator)));
  106. _dictType = (BuiltinClassInfo)GetNamespaceFromObjects(TypeCache.Dict);
  107. _boolType = (BuiltinClassInfo)GetNamespaceFromObjects(TypeCache.Boolean);
  108. _noneInst = (ConstantInfo)GetNamespaceFromObjects(new object[] { null });
  109. _listType = (BuiltinClassInfo)GetNamespaceFromObjects(TypeCache.List);
  110. _tupleType = (BuiltinClassInfo)GetNamespaceFromObjects(TypeCache.PythonTuple);
  111. _queue = new Queue<AnalysisUnit>();
  112. _docProvider = CodeContext.LanguageContext.GetService<DocumentationProvider>();
  113. }
  114. /// <summary>
  115. /// Adds a new module of code to the list of available modules and returns a ProjectEntry object.
  116. /// </summary>
  117. /// <param name="moduleName">The name of the module; used to associate with imports</param>
  118. /// <param name="filePath">The path to the file on disk</param>
  119. /// <param name="cookie">An application-specific identifier for the module</param>
  120. /// <returns></returns>
  121. public ProjectEntry AddModule(string moduleName, string filePath, IAnalysisCookie cookie) {
  122. var entry = new ProjectEntry(this, moduleName, filePath, cookie);
  123. _projectEntries.Add(entry);
  124. if (moduleName != null) {
  125. Modules[moduleName] = new ModuleReference(entry.MyScope);
  126. }
  127. if (filePath != null) {
  128. _modulesByFilename[filePath] = entry.MyScope;
  129. }
  130. return entry;
  131. }
  132. public XamlProjectEntry AddXamlFile(string filePath) {
  133. var entry = new XamlProjectEntry(this, filePath);
  134. _xamlByFilename[filePath] = entry;
  135. return entry;
  136. }
  137. /// <summary>
  138. /// Gets a top-level list of all the available modules as a list of MemberResults.
  139. /// </summary>
  140. /// <returns></returns>
  141. public MemberResult[] GetModules() {
  142. var d = new Dictionary<string, HashSet<Namespace>>();
  143. foreach (var keyValue in Modules) {
  144. var modName = keyValue.Key;
  145. var moduleRef = keyValue.Value;
  146. HashSet<Namespace> l;
  147. if (!d.TryGetValue(modName, out l)) {
  148. d[modName] = l = new HashSet<Namespace>();
  149. }
  150. if (moduleRef != null && moduleRef.Module != null) {
  151. // The REPL shows up here with value=None
  152. l.Add(moduleRef.Module);
  153. }
  154. }
  155. foreach (var r in _references) {
  156. foreach (string key in r.Value.GetMemberNames()) {
  157. var value = PythonAssemblyOps.GetBoundMember(_codeContext, r.Key, key);
  158. HashSet<Namespace> l2;
  159. if (!d.TryGetValue(key, out l2)) {
  160. d[key] = l2 = new HashSet<Namespace>();
  161. }
  162. l2.Add(GetNamespaceFromObjects(value));
  163. }
  164. }
  165. var result = new MemberResult[d.Count];
  166. int pos = 0;
  167. foreach (var kvp in d) {
  168. result[pos++] = new MemberResult(kvp.Key, kvp.Value);
  169. }
  170. return result;
  171. }
  172. /// <summary>
  173. /// returns the MemberResults associated with modules in the specified
  174. /// list of names. The list of names is the path through the module, for example
  175. /// ['System', 'Runtime']
  176. /// </summary>
  177. /// <returns></returns>
  178. public MemberResult[] GetModuleMembers(string[] names) {
  179. return GetModuleMembers(names, true);
  180. }
  181. /// <summary>
  182. /// returns the MemberResults associated with modules in the specified
  183. /// list of names. The list of names is the path through the module, for example
  184. /// ['System', 'Runtime']
  185. /// </summary>
  186. /// <returns></returns>
  187. public MemberResult[] GetModuleMembers(string[] names, bool bottom) {
  188. IDictionary<string, ISet<Namespace>> d = null;
  189. var nses = GetReflectedNamespaces(names, bottom);
  190. if (nses == null) {
  191. return new MemberResult[0];
  192. }
  193. var ns = GetNamespaceFromObjects(nses);
  194. if (ns != null) {
  195. d = ns.GetAllMembers(true);
  196. }
  197. ModuleReference moduleRef;
  198. if (Modules.TryGetValue(names[0], out moduleRef) && moduleRef.Module != null) {
  199. var module = moduleRef.Module;
  200. var newDict = new Dictionary<string, ISet<Namespace>>();
  201. if (d != null) {
  202. Update(newDict, d);
  203. }
  204. d = newDict;
  205. var mod = module.SelfSet;
  206. if (bottom) {
  207. for (int i = 1; i < names.Length; i++) {
  208. var next = names[i];
  209. // import Foo.Bar as Baz, we need to get Bar
  210. VariableDef def;
  211. ISet<Namespace> newMod = EmptySet<Namespace>.Instance;
  212. bool madeSet = false;
  213. foreach (var modItem in mod) {
  214. BuiltinModule builtinMod = modItem as BuiltinModule;
  215. if (builtinMod != null) {
  216. ISet<Namespace> builtinValues;
  217. if (builtinMod.VariableDict.TryGetValue(next, out builtinValues)) {
  218. newMod = newMod.Union(builtinValues, ref madeSet);
  219. }
  220. } else {
  221. ModuleInfo userMod = modItem as ModuleInfo;
  222. if (userMod != null && userMod.Scope.Variables.TryGetValue(next, out def)) {
  223. newMod = newMod.Union(def.Types, ref madeSet);
  224. }
  225. }
  226. }
  227. mod = newMod;
  228. if (mod.Count == 0) {
  229. break;
  230. }
  231. }
  232. }
  233. foreach (var modItem in mod) {
  234. Update(d, modItem.GetAllMembers(false));
  235. }
  236. }
  237. MemberResult[] result;
  238. if (d != null) {
  239. result = new MemberResult[d.Count];
  240. int pos = 0;
  241. foreach (var kvp in d) {
  242. result[pos++] = new MemberResult(kvp.Key, kvp.Value);
  243. }
  244. } else {
  245. result = new MemberResult[0];
  246. }
  247. return result;
  248. }
  249. /// <summary>
  250. /// Replaces a built-in function (specified by module name and function name) with a customized
  251. /// delegate which provides specific behavior for handling when that function is called.
  252. ///
  253. /// Currently this just provides a hook when the function is called - it could be expanded
  254. /// to providing the interpretation of when the function is called as well.
  255. /// </summary>
  256. private void SpecializeFunction(string moduleName, string name, Func<CallExpression, AnalysisUnit, ISet<Namespace>[], ISet<Namespace>> dlg) {
  257. var module = Modules[moduleName];
  258. BuiltinModule builtin = module.Module as BuiltinModule;
  259. Debug.Assert(builtin != null);
  260. if (builtin != null) {
  261. foreach (var v in builtin.VariableDict[name]) {
  262. BuiltinFunctionInfo funcInfo = v as BuiltinFunctionInfo;
  263. if (funcInfo != null) {
  264. builtin.VariableDict[name] = new SpecializedBuiltinFunction(this, funcInfo.Function, dlg).SelfSet;
  265. break;
  266. }
  267. }
  268. }
  269. }
  270. public List<ProjectEntry> ProjectEntries {
  271. get { return _projectEntries; }
  272. }
  273. internal Queue<AnalysisUnit> Queue {
  274. get {
  275. return _queue;
  276. }
  277. }
  278. private void InitializeBuiltinModules() {
  279. string installDir = PythonRuntimeHost.GetPythonInstallDir();
  280. if (installDir != null) {
  281. var dllDir = Path.Combine(installDir, "DLLs");
  282. if (Directory.Exists(dllDir)) {
  283. foreach (var assm in Directory.GetFiles(dllDir)) {
  284. try {
  285. _pythonEngine.Runtime.LoadAssembly(Assembly.LoadFile(Path.Combine(dllDir, assm)));
  286. } catch {
  287. }
  288. }
  289. }
  290. }
  291. var names = _pythonEngine.Operations.GetMember<PythonTuple>(_pythonEngine.GetSysModule(), "builtin_module_names");
  292. foreach (string modName in names) {
  293. PythonModule mod = Importer.Import(_codeContextCls, modName, PythonOps.EmptyTuple, 0) as PythonModule;
  294. Debug.Assert(mod != null);
  295. Modules[modName] = new ModuleReference(new BuiltinModule(mod, this, false));
  296. }
  297. }
  298. private KeyValuePair<Assembly, TopNamespaceTracker> LoadAssemblyInfo(Assembly assm) {
  299. var nsTracker = new TopNamespaceTracker(_codeContext.LanguageContext.DomainManager);
  300. nsTracker.LoadAssembly(assm);
  301. return new KeyValuePair<Assembly, TopNamespaceTracker>(assm, nsTracker);
  302. }
  303. private void AddAssembly(KeyValuePair<Assembly, TopNamespaceTracker> assembly) {
  304. _references.Add(assembly);
  305. ThreadPool.QueueUserWorkItem(state => {
  306. // start initializing assemblies on background thread for quick response.
  307. foreach (string key in assembly.Value.GetMemberNames()) {
  308. var value = PythonAssemblyOps.GetBoundMember(_codeContext, assembly.Key, key);
  309. }
  310. });
  311. }
  312. private ISet<Namespace> ReturnUnionOfInputs(CallExpression call, AnalysisUnit unit, ISet<Namespace>[] args) {
  313. ISet<Namespace> res = EmptySet<Namespace>.Instance;
  314. bool madeSet = false;
  315. foreach (var set in args) {
  316. res = res.Union(set, ref madeSet);
  317. }
  318. return res;
  319. }
  320. private ISet<Namespace> LoadComponent(CallExpression node, AnalysisUnit unit, ISet<Namespace>[]args) {
  321. if (args.Length == 2) {
  322. var xaml = args[1];
  323. var self = args[0];
  324. foreach (var arg in xaml) {
  325. string strConst = arg.GetConstantValue() as string;
  326. if (strConst != null) {
  327. // process xaml file, add attributes to self
  328. string xamlPath = Path.Combine(Path.GetDirectoryName(unit.DeclaringModule.ProjectEntry.FilePath), strConst);
  329. XamlProjectEntry xamlProject;
  330. if (_xamlByFilename.TryGetValue(xamlPath, out xamlProject)) {
  331. // TODO: Get existing analysis if it hasn't changed.
  332. var analysis = xamlProject.Analysis;
  333. if (analysis == null) {
  334. xamlProject.Analyze();
  335. analysis = xamlProject.Analysis;
  336. }
  337. xamlProject.AddDependency(unit);
  338. var evalUnit = unit.CopyForEval();
  339. // add named objects to instance
  340. foreach (var keyValue in analysis.NamedObjects) {
  341. var type = keyValue.Value;
  342. if (type.Type.UnderlyingType != null) {
  343. var ns = GetNamespaceFromObjects(DynamicHelpers.GetPythonTypeFromType(type.Type.UnderlyingType));
  344. if (ns is BuiltinClassInfo) {
  345. ns = ((BuiltinClassInfo)ns).Instance;
  346. }
  347. self.SetMember(node, evalUnit, keyValue.Key, ns.SelfSet);
  348. }
  349. // TODO: Better would be if SetMember took something other than a node, then we'd
  350. // track references w/o this extra effort.
  351. foreach (var inst in self) {
  352. InstanceInfo instInfo = inst as InstanceInfo;
  353. if (instInfo != null) {
  354. VariableDef def;
  355. if (instInfo.InstanceAttributes.TryGetValue(keyValue.Key, out def)) {
  356. def.AddAssignment(
  357. new SimpleSrcLocation(type.LineNumber, type.LineOffset, keyValue.Key.Length),
  358. xamlProject
  359. );
  360. }
  361. }
  362. }
  363. }
  364. // add references to event handlers
  365. foreach (var keyValue in analysis.EventHandlers) {
  366. // add reference to methods...
  367. var member = keyValue.Value;
  368. // TODO: Better would be if SetMember took something other than a node, then we'd
  369. // track references w/o this extra effort.
  370. foreach (var inst in self) {
  371. InstanceInfo instInfo = inst as InstanceInfo;
  372. if (instInfo != null) {
  373. ClassInfo ci = instInfo.ClassInfo;
  374. VariableDef def;
  375. if (ci.Scope.Variables.TryGetValue(keyValue.Key, out def)) {
  376. def.AddReference(
  377. new SimpleSrcLocation(member.LineNumber, member.LineOffset, keyValue.Key.Length),
  378. xamlProject
  379. );
  380. }
  381. }
  382. }
  383. }
  384. }
  385. }
  386. }
  387. // load component returns self
  388. return self;
  389. }
  390. return EmptySet<Namespace>.Instance;
  391. }
  392. private ISet<Namespace> AddReference(CallExpression node, Func<string, Assembly> partialLoader) {
  393. // processes a call to clr.AddReference updating project state
  394. // so that it contains the newly loaded assembly.
  395. foreach (var arg in node.Args) {
  396. var cexpr = arg.Expression as ConstantExpression;
  397. if (cexpr == null || !(cexpr.Value is string)) {
  398. // can't process this add reference
  399. continue;
  400. }
  401. // TODO: Should we do a .NET reflection only load rather than
  402. // relying on the CLR module here? That would prevent any code from
  403. // running although at least we don't taint our own modules which
  404. // are loaded with this current code.
  405. var asmName = cexpr.Value as string;
  406. if (asmName != null && _assemblyLoadList.Add(asmName)) {
  407. Assembly asm = null;
  408. try {
  409. if (partialLoader != null) {
  410. asm = partialLoader(asmName);
  411. } else {
  412. try {
  413. asm = ClrModule.LoadAssemblyByName(_codeContext, asmName);
  414. } catch {
  415. asm = ClrModule.LoadAssemblyByPartialName(asmName);
  416. }
  417. }
  418. } catch {
  419. }
  420. AddAssembly(asm);
  421. }
  422. }
  423. return null;
  424. }
  425. public void AddAssembly(Assembly asm) {
  426. if (asm != null && _references.FindIndex(reference => (reference.Key == asm)) == -1) {
  427. // TODO: When do assembly references get removed?
  428. var nsTracker = new TopNamespaceTracker(_codeContext.LanguageContext.DomainManager);
  429. nsTracker.LoadAssembly(asm);
  430. AddAssembly(new KeyValuePair<Assembly, TopNamespaceTracker>(asm, nsTracker));
  431. }
  432. }
  433. /// <summary>
  434. /// Gets a builtin value
  435. /// </summary>
  436. /// <param name="name"></param>
  437. /// <returns></returns>
  438. internal Namespace GetBuiltin(string name) {
  439. return _builtinModule.VariableDict[name].First();
  440. }
  441. internal T GetCached<T>(object key, Func<T> maker) where T : class {
  442. object result;
  443. if (!_itemCache.TryGetValue(key, out result)) {
  444. _itemCache[key] = result = maker();
  445. } else {
  446. Debug.Assert(result is T);
  447. }
  448. return (result as T);
  449. }
  450. internal object[] GetReflectedNamespaces(IList<string> names, bool bottom) {
  451. if (names == null || names.Count == 0) {
  452. return null;
  453. }
  454. var topName = names[0];
  455. if (String.IsNullOrEmpty(topName)) {
  456. // user typed "import."
  457. return null;
  458. }
  459. var builtinRefs = new List<object>();
  460. foreach (var asm in _references) {
  461. object attr = NamespaceTrackerOps.GetCustomMember(_codeContext, asm.Value, topName);
  462. if (attr != null && attr != OperationFailed.Value) {
  463. if (bottom) {
  464. for (int i = 1; i < names.Count; i++) {
  465. if (names[i] != null) {
  466. object nextAttr;
  467. if (!TryGetMember(attr, names[i], out nextAttr) || nextAttr == null) {
  468. attr = null;
  469. break;
  470. }
  471. attr = nextAttr;
  472. }
  473. }
  474. }
  475. if (attr != null) {
  476. builtinRefs.Add(attr);
  477. }
  478. }
  479. }
  480. return builtinRefs.ToArray();
  481. }
  482. internal BuiltinModule BuiltinModule {
  483. get { return _builtinModule; }
  484. }
  485. internal T GetMember<T>(object obj, string name) {
  486. return (T)Builtin.getattr(_codeContext, obj, name);
  487. }
  488. private bool TryGetMember(CodeContext codeContext, object obj, string name, out object value) {
  489. NamespaceTracker nt = obj as NamespaceTracker;
  490. if (nt != null) {
  491. value = NamespaceTrackerOps.GetCustomMember(codeContext, nt, name);
  492. return value != OperationFailed.Value;
  493. }
  494. object result = Builtin.getattr(codeContext, obj, name, this);
  495. if (result == this) {
  496. value = null;
  497. return false;
  498. } else {
  499. value = result;
  500. return true;
  501. }
  502. }
  503. internal bool TryGetMember(object obj, string name, out object value) {
  504. return TryGetMember(_codeContext, obj, name, out value);
  505. }
  506. internal bool TryGetMember(object obj, string name, bool showClr, out object value) {
  507. var cctx = showClr ? _codeContextCls : _codeContext;
  508. return TryGetMember(cctx, obj, name, out value);
  509. }
  510. internal SourceUnit GetSourceUnitForExpression(string expr) {
  511. return StringTextContentProvider.Make(_pythonEngine, expr, SourceCodeKind.Expression);
  512. }
  513. internal CodeContext CodeContext {
  514. get { return _codeContext; }
  515. }
  516. internal CodeContext CodeContextCls {
  517. get { return _codeContextCls; }
  518. }
  519. internal DocumentationProvider DocProvider {
  520. get { return _docProvider; }
  521. }
  522. internal BuiltinInstanceInfo GetInstance(Type type) {
  523. return GetInstance(ClrModule.GetPythonType(type));
  524. }
  525. internal BuiltinInstanceInfo GetInstance(PythonType type) {
  526. return GetBuiltinType(type).Instance;
  527. }
  528. internal BuiltinClassInfo GetBuiltinType(Type type) {
  529. return GetBuiltinType(ClrModule.GetPythonType(type));
  530. }
  531. internal BuiltinClassInfo GetBuiltinType(PythonType type) {
  532. return GetCached(type, () => new BuiltinClassInfo(type, this));
  533. }
  534. internal Namespace GetNamespaceFromObjects(params object[] attrs) {
  535. return GetNamespaceFromObjects((IEnumerable<object>)attrs);
  536. }
  537. internal Namespace GetNamespaceFromObjects(IEnumerable<object> attrs) {
  538. List<Namespace> values = new List<Namespace>();
  539. foreach (var attr in attrs) {
  540. var attrType = (attr != null) ? attr.GetType() : typeof(DynamicNull);
  541. if (attr is PythonType) {
  542. values.Add(GetBuiltinType((PythonType)attr));
  543. } else if (attr is BuiltinFunction) {
  544. var bf = (BuiltinFunction)attr;
  545. if (bf.__self__ == null) {
  546. values.Add(GetCached(attr, () => new BuiltinFunctionInfo(bf, this)));
  547. } else {
  548. values.Add(new BuiltinFunctionInfo(bf, this));
  549. }
  550. } else if (attrType == typeof(BuiltinMethodDescriptor)) {
  551. values.Add(GetCached(attr, () => new BuiltinMethodInfo((BuiltinMethodDescriptor)attr, this)));
  552. } else if (attrType.IsEnum) {
  553. values.Add(GetCached(attr, () => new EnumInstanceInfo(attr, this)));
  554. } else if (attrType == typeof(ReflectedProperty) || attrType == typeof(ReflectedExtensionProperty)) {
  555. values.Add(GetCached(attr, () => new BuiltinPropertyInfo((ReflectedGetterSetter)attr, this)));
  556. } else if (attrType == typeof(ReflectedField)) {
  557. values.Add(GetCached(attr, () => new BuiltinFieldInfo((ReflectedField)attr, this)));
  558. } else if (attrType == typeof(ReflectedEvent)) {
  559. values.Add(GetCached(attr, () => new BuiltinEventInfo((ReflectedEvent)attr, this)));
  560. } else if (attrType == typeof(bool) || attrType == typeof(int) || attrType == typeof(Complex64)
  561. || attrType == typeof(string) || attrType == typeof(long) || attrType == typeof(double) ||
  562. attr == null) {
  563. var varRef = GetConstant(attr);
  564. foreach (var constant in varRef) {
  565. values.Add(constant);
  566. }
  567. } else if (attr is NamespaceTracker || attr is TypeGroup) { // TODO: Need to do better for TypeGroup's.
  568. values.Add(GetCached(attr, () => new ReflectedNamespace(new[] { attr }, this)));
  569. } else {
  570. var pyAattrType = DynamicHelpers.GetPythonType(attr);
  571. values.Add(GetCached(pyAattrType, () => new BuiltinClassInfo(pyAattrType, this)).Instance);
  572. }
  573. }
  574. if (values.Count == 1) {
  575. return values[0];
  576. } else if (values.Count > 1) {
  577. return GetCached(new NamespaceKey(values.ToArray()), () => new ReflectedNamespace(attrs, this));
  578. } else {
  579. return null;
  580. }
  581. }
  582. class NamespaceKey : IEquatable<NamespaceKey> {
  583. private readonly Namespace[] _values;
  584. public NamespaceKey(Namespace[] values) {
  585. _values = values;
  586. }
  587. public override bool Equals(object obj) {
  588. if (!(obj is NamespaceKey)) {
  589. return false;
  590. }
  591. return Equals((NamespaceKey)obj);
  592. }
  593. public override int GetHashCode() {
  594. int res = 0;
  595. foreach (Namespace n in _values) {
  596. res ^= n.GetHashCode();
  597. }
  598. return res;
  599. }
  600. #region IEquatable<NamespaceKey> Members
  601. public bool Equals(NamespaceKey other) {
  602. if (other._values.Length != _values.Length) {
  603. return false;
  604. }
  605. for (int i = 0; i < _values.Length; i++) {
  606. if (_values[i] != other._values[i]) {
  607. return false;
  608. }
  609. }
  610. return true;
  611. }
  612. #endregion
  613. }
  614. internal Dictionary<string, ModuleReference> Modules {
  615. get { return _modules; }
  616. }
  617. internal Dictionary<string, ModuleInfo> ModulesByFilename {
  618. get { return _modulesByFilename; }
  619. }
  620. internal ISet<Namespace> GetConstant(object value) {
  621. object key = value ?? _nullKey;
  622. return GetCached<ISet<Namespace>>(key, () => new ConstantInfo(value, this).SelfSet);
  623. }
  624. internal BuiltinClassInfo MakeGenericType(Type clrType, params Type[] clrIndexTypes) {
  625. var genType = clrType.MakeGenericType(clrIndexTypes);
  626. var pyType = ClrModule.GetPythonType(genType);
  627. return GetCached(pyType, () => new BuiltinClassInfo(pyType, this));
  628. }
  629. private static void Update<K, V>(IDictionary<K, V> dict, IDictionary<K, V> newValues) {
  630. foreach (var kvp in newValues) {
  631. dict[kvp.Key] = kvp.Value;
  632. }
  633. }
  634. }
  635. }