PageRenderTime 34ms CodeModel.GetById 4ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_1_1/Src/IronPython/CodeDom/Parser.cs

#
C# | 299 lines | 201 code | 49 blank | 49 comment | 48 complexity | adb5137c1b7f3fe248406dce0f99c1d2 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public
  6. * License. A copy of the license can be found in the License.html file at the
  7. * root of this distribution. If you cannot locate the Microsoft Public
  8. * License, please send an email to dlr@microsoft.com. By using this source
  9. * code in any fashion, you are agreeing to be bound by the terms of the
  10. * Microsoft Public License.
  11. *
  12. * You must not remove this notice, or any other, from this software.
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Text;
  18. using System.IO;
  19. using System.Reflection;
  20. using System.CodeDom;
  21. using System.CodeDom.Compiler;
  22. using IronPython.Compiler;
  23. using IronPython.Compiler.Ast;
  24. using IronPython.Runtime;
  25. using System.Diagnostics;
  26. namespace IronPython.CodeDom {
  27. class PythonParser : CodeParser, IDisposable {
  28. private List<string> references = new List<string>();
  29. private SystemState state = new SystemState();
  30. public PythonParser(List<string> assemblyReferences) {
  31. if (assemblyReferences.Count == 0) {
  32. references.Add("System.Windows.Forms");
  33. references.Add("System");
  34. references.Add("System.Data");
  35. references.Add("System.Drawing");
  36. references.Add("System.Xml");
  37. references.Add("mscorlib");
  38. } else {
  39. references.AddRange(assemblyReferences);
  40. }
  41. }
  42. /// <summary>
  43. /// Parse an entire file - ideal path as we'll respect
  44. /// PEP-263 encodings and the such...
  45. /// </summary>
  46. public CodeCompileUnit ParseFile(string filename) {
  47. return Parse(Parser.FromFile(state, new CompilerContext(filename)), filename);
  48. }
  49. /// <summary>
  50. /// Parse an arbitrary stream
  51. /// </summary>
  52. public override CodeCompileUnit Parse(System.IO.TextReader codeStream) {
  53. return ParseMergeable(codeStream, null);
  54. }
  55. public CodeCompileUnit ParseMergeable(string text, string filename, IMergeDestination destination){
  56. CodeCompileUnit tree = Parse(Parser.FromString(state, new CompilerContext(), text), filename);
  57. CodeMerger.CacheCode(tree, destination);
  58. return tree;
  59. }
  60. public CodeCompileUnit ParseMergeable(System.IO.TextReader codeStream, IMergeDestination destination) {
  61. // get a better filename if we can
  62. string name = "<unknown>";
  63. StreamReader sw = codeStream as StreamReader;
  64. if (sw != null) {
  65. FileStream fs = sw.BaseStream as FileStream;
  66. if (fs != null) name = fs.Name;
  67. }
  68. //!!! it'd be nice to have Parser.FromStream to get proper decodings here
  69. string codeText = codeStream.ReadToEnd();
  70. CodeCompileUnit tree = Parse(Parser.FromString(state, new CompilerContext(), codeText), name);
  71. if (destination != null) CodeMerger.CacheCode(tree, destination);
  72. else CodeMerger.CacheCode(tree, codeText);
  73. return tree;
  74. }
  75. /// <summary>
  76. /// Parses an arbitrary string of Python code
  77. /// </summary>
  78. public CodeCompileUnit Parse(string text) {
  79. return Parse(Parser.FromString(state, new CompilerContext(), text), "<unknown>");
  80. }
  81. /// <summary>
  82. /// Private helper function for all parsing. Takes in the IronPython Parser
  83. /// object and a filename that's used for error reports
  84. /// </summary>
  85. /// <param name="p"></param>
  86. private CodeCompileUnit Parse(Parser p, string filename) {
  87. Statement s = p.ParseFileInput();
  88. CodeCompileUnit res = new CodeCompileUnit();
  89. CodeNamespace defaultNamespace = new CodeNamespace();
  90. defaultNamespace.UserData["Line"] = 1;
  91. defaultNamespace.UserData["Column"] = 1;
  92. defaultNamespace.UserData["EndLine"] = 1;
  93. defaultNamespace.UserData["EndColumn"] = 1;
  94. //!!! enable AD usage when we're strong named.
  95. //AppDomainSetup ads = new AppDomainSetup();
  96. //ads.ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
  97. //AppDomain ad = AppDomain.CreateDomain("ParserReferenceDomain",null,ads);
  98. try {
  99. RemoteReferences rc = new RemoteReferences();
  100. /*(RemoteReferences)ad.CreateInstanceAndUnwrap(
  101. Assembly.GetExecutingAssembly().FullName,
  102. "IronPython.CodeDom.RemoteReferences");*/
  103. rc.Initialize(references);
  104. CodeWalker cw = new CodeWalker(filename, rc);
  105. s.Walk(cw);
  106. CodeObject co = cw.LastObject;
  107. CodeObjectSuite cos = co as CodeObjectSuite;
  108. if (cos == null) cos = new CodeObjectSuite(new CodeObject[] { co });
  109. // walk the top-level and see if we need to create a fake top-type
  110. // or if we can just stick everything directly into the namespace.
  111. CodeTypeDeclaration topType = null;
  112. for (int i = 0; i < cos.Count; i++) {
  113. topType = CheckTopLevel(cos[i], res, defaultNamespace, topType);
  114. }
  115. // if no namespaces we're added then everything's in our default namespace.
  116. if (res.Namespaces.Count == 0 || defaultNamespace.Types.Count > 0) {
  117. res.Namespaces.Add(defaultNamespace);
  118. }
  119. UpdateTopType(topType, defaultNamespace);
  120. } finally {
  121. //AppDomain.Unload(ad);
  122. }
  123. return res;
  124. }
  125. private static CodeTypeDeclaration CheckTopLevel(CodeObject cur, CodeCompileUnit res, CodeNamespace defaultNamespace, CodeTypeDeclaration topType) {
  126. if (cur is CodeNamespaceImport) {
  127. CodeNamespaceImport adding = cur as CodeNamespaceImport;
  128. foreach (CodeNamespaceImport cni in defaultNamespace.Imports) {
  129. if (cni.Namespace == adding.Namespace) {
  130. cni.UserData["Dupped"] = true;
  131. return topType;
  132. }
  133. }
  134. defaultNamespace.Imports.Add(adding);
  135. } else if (cur is CodeTypeDeclaration) {
  136. CodeTypeDeclaration ctd = cur as CodeTypeDeclaration;
  137. bool fRealClass = false;
  138. if (ctd.BaseTypes.Count == 0) {
  139. foreach (CodeTypeMember mem in ctd.Members) {
  140. if (mem is CodeTypeDeclaration)
  141. continue;
  142. fRealClass = true;
  143. break;
  144. }
  145. } else {
  146. fRealClass = true;
  147. }
  148. if (fRealClass) {
  149. defaultNamespace.Types.Add(ctd);
  150. } else {
  151. // class w/ nested types, transfer the
  152. // type's content to a namespace.
  153. TypeToNamespace(res, defaultNamespace, ctd);
  154. }
  155. } else if (cur is CodeNamespace) {
  156. res.Namespaces.Add(cur as CodeNamespace);
  157. } else if (cur is CodeExpressionStatement) {
  158. ValidateCodeExpression(cur as CodeExpressionStatement);
  159. } else {
  160. if (topType == null) topType = new CodeTypeDeclaration("__top__");
  161. topType.Members.Add((CodeTypeMember)cur);
  162. }
  163. return topType;
  164. }
  165. private static void TypeToNamespace(CodeCompileUnit res, CodeNamespace defaultNamespace, CodeTypeDeclaration ctd) {
  166. CodeNamespace nsRes = new CodeNamespace(ctd.Name);
  167. res.Namespaces.Add(nsRes);
  168. foreach (CodeTypeMember mem in ctd.Members) {
  169. nsRes.Types.Add((CodeTypeDeclaration)mem);
  170. }
  171. CopyLineInfo(ctd, nsRes);
  172. foreach (CodeNamespaceImport cn in defaultNamespace.Imports) {
  173. nsRes.Imports.Add(cn);
  174. }
  175. }
  176. private static void CopyLineInfo(CodeTypeDeclaration ctd, CodeNamespace nsRes) {
  177. nsRes.UserData["PreImport"] = true;
  178. nsRes.UserData["IPCreated"] = ctd.UserData["IPCreated"];
  179. nsRes.UserData["EndLine"] = ctd.UserData["EndLine"];
  180. nsRes.UserData["EndColumn"] = ctd.UserData["EndColumn"];
  181. nsRes.UserData["Column"] = ctd.UserData["Column"];
  182. nsRes.UserData["Line"] = ctd.UserData["Line"];
  183. }
  184. private static void UpdateTopType(CodeTypeDeclaration topType, CodeNamespace defaultNamespace) {
  185. if (topType != null) {
  186. // we had a non-type at the top-level, we need to transfer
  187. // all our types from the default name space to the top-type
  188. for (int i = 0; i < defaultNamespace.Types.Count; i++) {
  189. topType.Members.Insert(i, defaultNamespace.Types[i]);
  190. }
  191. defaultNamespace.Types.Clear();
  192. topType.UserData["IsTopType"] = true;
  193. }
  194. }
  195. private static void ValidateCodeExpression(CodeExpressionStatement ces) {
  196. CodeMethodInvokeExpression invoke = ces.Expression as CodeMethodInvokeExpression;
  197. if (invoke != null) {
  198. CodeFieldReferenceExpression target = invoke.Method.TargetObject as CodeFieldReferenceExpression;
  199. if (target != null) {
  200. if (target.FieldName != "RealEntryPoint") throw new NotImplementedException("arbitrary calls at the top-level");
  201. } else if (invoke.Method.MethodName != "RealEntryPoint") throw new NotImplementedException("arbitrary calls at the top-level");
  202. // otherwise we want to ignore the statement.
  203. } else {
  204. throw new NotImplementedException("arbitrary expressions at the top-level");
  205. }
  206. }
  207. ~PythonParser() {
  208. Dispose(true);
  209. }
  210. #region IDisposable Members
  211. public void Dispose() {
  212. Dispose(false);
  213. }
  214. #endregion
  215. private void Dispose(bool finalizing) {
  216. // if we're finalizing we shouldn't access other managed objects, as
  217. // their finalizers may have already run
  218. if (!finalizing) {
  219. state.Dispose();
  220. }
  221. }
  222. }
  223. class CodeObjectSuite : CodeObject {
  224. List<CodeObject> objects = new List<CodeObject>();
  225. public CodeObjectSuite() {
  226. }
  227. public CodeObjectSuite(CodeObject[] objs) {
  228. objects.AddRange(objs);
  229. }
  230. public int Count {
  231. get {
  232. return objects.Count;
  233. }
  234. }
  235. public CodeObject this[int index] {
  236. get {
  237. return objects[index];
  238. }
  239. set {
  240. objects[index] = value;
  241. }
  242. }
  243. public void Add(CodeObject co) {
  244. objects.Add(co);
  245. }
  246. public void RemoveAt(int index) {
  247. objects.RemoveAt(index);
  248. }
  249. }
  250. }