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