PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/SourceUnit.cs

https://bitbucket.org/stefanrusek/xronos
C# | 275 lines | 176 code | 47 blank | 52 comment | 19 complexity | 4eb2d209e8ea98ec21bdba367b62d95a MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. using System.Diagnostics;
  22. #if CODEPLEX_40
  23. using System.Linq.Expressions;
  24. using System.Dynamic;
  25. #else
  26. using Microsoft.Linq.Expressions;
  27. using Microsoft.Scripting;
  28. #endif
  29. using Microsoft.Scripting.Runtime;
  30. using Microsoft.Scripting.Utils;
  31. using System.Text;
  32. namespace Microsoft.Scripting {
  33. [DebuggerDisplay("{_path ?? \"<anonymous>\"}")]
  34. public sealed class SourceUnit {
  35. private readonly SourceCodeKind _kind;
  36. private readonly string _path;
  37. private readonly LanguageContext _language;
  38. private readonly TextContentProvider _contentProvider;
  39. // SourceUnit is serializable => updated parse result is transmitted
  40. // back to the host unless the unit is passed by-ref
  41. private ScriptCodeParseResult? _parseResult;
  42. private KeyValuePair<int, int>[] _lineMap;
  43. /// <summary>
  44. /// Identification of the source unit. Assigned by the host.
  45. /// The format and semantics is host dependent (could be a path on file system or URL).
  46. /// Empty string for anonymous source units.
  47. /// </summary>
  48. public string Path {
  49. get { return _path; }
  50. }
  51. public bool HasPath {
  52. get { return _path != null; }
  53. }
  54. public SourceCodeKind Kind {
  55. get { return _kind; }
  56. }
  57. public SymbolDocumentInfo Document {
  58. get {
  59. // _path is valid to be null. In that case we cannot create a valid SymbolDocumentInfo.
  60. return _path == null ? null : Expression.SymbolDocument(_path, _language.LanguageGuid, _language.VendorGuid);
  61. }
  62. }
  63. /// <summary>
  64. /// LanguageContext of the language of the unit.
  65. /// </summary>
  66. public LanguageContext LanguageContext {
  67. get { return _language; }
  68. }
  69. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  70. public ScriptCodeParseResult GetCodeProperties() {
  71. return GetCodeProperties(_language.GetCompilerOptions());
  72. }
  73. public ScriptCodeParseResult GetCodeProperties(CompilerOptions options) {
  74. ContractUtils.RequiresNotNull(options, "options");
  75. _language.CompileSourceCode(this, options, ErrorSink.Null);
  76. return _parseResult ?? ScriptCodeParseResult.Complete;
  77. }
  78. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] // TODO: fix
  79. public ScriptCodeParseResult? CodeProperties {
  80. get { return _parseResult; }
  81. set { _parseResult = value; }
  82. }
  83. public SourceUnit(LanguageContext context, TextContentProvider contentProvider, string path, SourceCodeKind kind) {
  84. Assert.NotNull(context, contentProvider);
  85. Debug.Assert(path == null || path.Length > 0);
  86. Debug.Assert(context.CanCreateSourceCode);
  87. _language = context;
  88. _contentProvider = contentProvider;
  89. _kind = kind;
  90. _path = path;
  91. }
  92. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  93. public SourceCodeReader GetReader() {
  94. return _contentProvider.GetReader();
  95. }
  96. /// <summary>
  97. /// Reads specified range of lines (or less) from the source unit.
  98. /// Line numbers starts with 1.
  99. /// </summary>
  100. public string[] GetCodeLines(int start, int count) {
  101. ContractUtils.Requires(start > 0, "start");
  102. ContractUtils.Requires(count > 0, "count");
  103. List<string> result = new List<string>(count);
  104. using (SourceCodeReader reader = GetReader()) {
  105. reader.SeekLine(start);
  106. while (count > 0) {
  107. string line = reader.ReadLine();
  108. if (line == null) break;
  109. result.Add(line);
  110. count--;
  111. }
  112. }
  113. return result.ToArray();
  114. }
  115. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  116. public string GetCodeLine(int line) {
  117. string[] lines = GetCodeLines(line, 1);
  118. return (lines.Length > 0) ? lines[0] : null;
  119. }
  120. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  121. public string GetCode() {
  122. using (SourceCodeReader reader = GetReader()) {
  123. return reader.ReadToEnd();
  124. }
  125. }
  126. #region Line/File mapping
  127. public SourceLocation MakeLocation(int index, int line, int column) {
  128. return new SourceLocation(index, MapLine(line), column);
  129. }
  130. public SourceLocation MakeLocation(SourceLocation loc) {
  131. return new SourceLocation(loc.Index, MapLine(loc.Line), loc.Column);
  132. }
  133. public int MapLine(int line) {
  134. if (_lineMap != null) {
  135. int match = BinarySearch(_lineMap, line);
  136. int delta = line - _lineMap[match].Key;
  137. line = _lineMap[match].Value + delta;
  138. if (line < 1) {
  139. line = 1; // this is the minimum value
  140. }
  141. }
  142. return line;
  143. }
  144. private static int BinarySearch<T>(KeyValuePair<int, T>[] array, int line) {
  145. int match = Array.BinarySearch(array, new KeyValuePair<int, T>(line, default(T)), new KeyComparer<T>());
  146. if (match < 0) {
  147. // If we couldn't find an exact match for this line number, get the nearest
  148. // matching line number less than this one
  149. match = ~match - 1;
  150. // If our index = -1, it means that this line is before any line numbers that
  151. // we know about. If that's the case, use the first entry in the list
  152. if (match == -1) {
  153. match = 0;
  154. }
  155. }
  156. return match;
  157. }
  158. private class KeyComparer<T1> : IComparer<KeyValuePair<int, T1>> {
  159. public int Compare(KeyValuePair<int, T1> x, KeyValuePair<int, T1> y) {
  160. return x.Key - y.Key;
  161. }
  162. }
  163. #endregion
  164. #region Parsing, Compilation, Execution
  165. public bool EmitDebugSymbols {
  166. get {
  167. return HasPath && LanguageContext.DomainManager.Configuration.DebugMode;
  168. }
  169. }
  170. public ScriptCode Compile() {
  171. return Compile(ErrorSink.Default);
  172. }
  173. public ScriptCode Compile(ErrorSink errorSink) {
  174. return Compile(_language.GetCompilerOptions(), errorSink);
  175. }
  176. /// <summary>
  177. /// Errors are reported to the specified sink.
  178. /// Returns <c>null</c> if the parser cannot compile the code due to error(s).
  179. /// </summary>
  180. public ScriptCode Compile(CompilerOptions options, ErrorSink errorSink) {
  181. ContractUtils.RequiresNotNull(errorSink, "errorSink");
  182. ContractUtils.RequiresNotNull(options, "options");
  183. return _language.CompileSourceCode(this, options, errorSink);
  184. }
  185. /// <summary>
  186. /// Executes against a specified scope.
  187. /// </summary>
  188. public object Execute(Scope scope) {
  189. return Execute(scope, ErrorSink.Default);
  190. }
  191. /// <summary>
  192. /// Executes against a specified scope and reports errors to the given error sink.
  193. /// </summary>
  194. public object Execute(Scope scope, ErrorSink errorSink) {
  195. ContractUtils.RequiresNotNull(scope, "scope");
  196. ScriptCode compiledCode = Compile(_language.GetCompilerOptions(scope), errorSink);
  197. if (compiledCode == null) {
  198. throw new SyntaxErrorException();
  199. }
  200. return compiledCode.Run(scope);
  201. }
  202. /// <summary>
  203. /// Executes in a new scope created by the language.
  204. /// </summary>
  205. public object Execute() {
  206. return Compile().Run();
  207. }
  208. /// <summary>
  209. /// Executes in a new scope created by the language.
  210. /// </summary>
  211. public object Execute(ErrorSink errorSink) {
  212. return Compile(errorSink).Run();
  213. }
  214. /// <summary>
  215. /// Executes in a new scope created by the language.
  216. /// </summary>
  217. public object Execute(CompilerOptions options, ErrorSink errorSink) {
  218. return Compile(options, errorSink).Run();
  219. }
  220. public int ExecuteProgram() {
  221. return _language.ExecuteProgram(this);
  222. }
  223. #endregion
  224. public void SetLineMapping(KeyValuePair<int, int>[] lineMap) {
  225. _lineMap = (lineMap == null || lineMap.Length == 0) ? null : lineMap;
  226. }
  227. }
  228. }