/Microsoft.Scripting/SourceUnit.cs
C# | 275 lines | 176 code | 47 blank | 52 comment | 19 complexity | 4eb2d209e8ea98ec21bdba367b62d95a MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- using System.Diagnostics;
- #if CODEPLEX_40
- using System.Linq.Expressions;
- using System.Dynamic;
- #else
- using Microsoft.Linq.Expressions;
- using Microsoft.Scripting;
- #endif
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
- using System.Text;
-
- namespace Microsoft.Scripting {
- [DebuggerDisplay("{_path ?? \"<anonymous>\"}")]
- public sealed class SourceUnit {
- private readonly SourceCodeKind _kind;
- private readonly string _path;
- private readonly LanguageContext _language;
- private readonly TextContentProvider _contentProvider;
-
- // SourceUnit is serializable => updated parse result is transmitted
- // back to the host unless the unit is passed by-ref
- private ScriptCodeParseResult? _parseResult;
- private KeyValuePair<int, int>[] _lineMap;
-
- /// <summary>
- /// Identification of the source unit. Assigned by the host.
- /// The format and semantics is host dependent (could be a path on file system or URL).
- /// Empty string for anonymous source units.
- /// </summary>
- public string Path {
- get { return _path; }
- }
-
- public bool HasPath {
- get { return _path != null; }
- }
-
- public SourceCodeKind Kind {
- get { return _kind; }
- }
-
- public SymbolDocumentInfo Document {
- get {
- // _path is valid to be null. In that case we cannot create a valid SymbolDocumentInfo.
- return _path == null ? null : Expression.SymbolDocument(_path, _language.LanguageGuid, _language.VendorGuid);
- }
- }
-
- /// <summary>
- /// LanguageContext of the language of the unit.
- /// </summary>
- public LanguageContext LanguageContext {
- get { return _language; }
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- public ScriptCodeParseResult GetCodeProperties() {
- return GetCodeProperties(_language.GetCompilerOptions());
- }
-
- public ScriptCodeParseResult GetCodeProperties(CompilerOptions options) {
- ContractUtils.RequiresNotNull(options, "options");
-
- _language.CompileSourceCode(this, options, ErrorSink.Null);
- return _parseResult ?? ScriptCodeParseResult.Complete;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] // TODO: fix
- public ScriptCodeParseResult? CodeProperties {
- get { return _parseResult; }
- set { _parseResult = value; }
- }
-
- public SourceUnit(LanguageContext context, TextContentProvider contentProvider, string path, SourceCodeKind kind) {
- Assert.NotNull(context, contentProvider);
- Debug.Assert(path == null || path.Length > 0);
- Debug.Assert(context.CanCreateSourceCode);
-
- _language = context;
- _contentProvider = contentProvider;
- _kind = kind;
- _path = path;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- public SourceCodeReader GetReader() {
- return _contentProvider.GetReader();
- }
-
- /// <summary>
- /// Reads specified range of lines (or less) from the source unit.
- /// Line numbers starts with 1.
- /// </summary>
- public string[] GetCodeLines(int start, int count) {
- ContractUtils.Requires(start > 0, "start");
- ContractUtils.Requires(count > 0, "count");
-
- List<string> result = new List<string>(count);
-
- using (SourceCodeReader reader = GetReader()) {
- reader.SeekLine(start);
- while (count > 0) {
- string line = reader.ReadLine();
- if (line == null) break;
- result.Add(line);
- count--;
- }
- }
-
- return result.ToArray();
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- public string GetCodeLine(int line) {
- string[] lines = GetCodeLines(line, 1);
- return (lines.Length > 0) ? lines[0] : null;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
- public string GetCode() {
- using (SourceCodeReader reader = GetReader()) {
- return reader.ReadToEnd();
- }
- }
-
- #region Line/File mapping
-
- public SourceLocation MakeLocation(int index, int line, int column) {
- return new SourceLocation(index, MapLine(line), column);
- }
- public SourceLocation MakeLocation(SourceLocation loc) {
- return new SourceLocation(loc.Index, MapLine(loc.Line), loc.Column);
- }
-
- public int MapLine(int line) {
- if (_lineMap != null) {
- int match = BinarySearch(_lineMap, line);
- int delta = line - _lineMap[match].Key;
- line = _lineMap[match].Value + delta;
- if (line < 1) {
- line = 1; // this is the minimum value
- }
- }
-
- return line;
- }
-
- private static int BinarySearch<T>(KeyValuePair<int, T>[] array, int line) {
- int match = Array.BinarySearch(array, new KeyValuePair<int, T>(line, default(T)), new KeyComparer<T>());
- if (match < 0) {
- // If we couldn't find an exact match for this line number, get the nearest
- // matching line number less than this one
- match = ~match - 1;
-
- // If our index = -1, it means that this line is before any line numbers that
- // we know about. If that's the case, use the first entry in the list
- if (match == -1) {
- match = 0;
- }
- }
- return match;
- }
-
-
- private class KeyComparer<T1> : IComparer<KeyValuePair<int, T1>> {
- public int Compare(KeyValuePair<int, T1> x, KeyValuePair<int, T1> y) {
- return x.Key - y.Key;
- }
- }
-
- #endregion
-
- #region Parsing, Compilation, Execution
-
- public bool EmitDebugSymbols {
- get {
- return HasPath && LanguageContext.DomainManager.Configuration.DebugMode;
- }
- }
-
- public ScriptCode Compile() {
- return Compile(ErrorSink.Default);
- }
-
- public ScriptCode Compile(ErrorSink errorSink) {
- return Compile(_language.GetCompilerOptions(), errorSink);
- }
-
- /// <summary>
- /// Errors are reported to the specified sink.
- /// Returns <c>null</c> if the parser cannot compile the code due to error(s).
- /// </summary>
- public ScriptCode Compile(CompilerOptions options, ErrorSink errorSink) {
- ContractUtils.RequiresNotNull(errorSink, "errorSink");
- ContractUtils.RequiresNotNull(options, "options");
-
- return _language.CompileSourceCode(this, options, errorSink);
- }
-
- /// <summary>
- /// Executes against a specified scope.
- /// </summary>
- public object Execute(Scope scope) {
- return Execute(scope, ErrorSink.Default);
- }
-
- /// <summary>
- /// Executes against a specified scope and reports errors to the given error sink.
- /// </summary>
- public object Execute(Scope scope, ErrorSink errorSink) {
- ContractUtils.RequiresNotNull(scope, "scope");
-
- ScriptCode compiledCode = Compile(_language.GetCompilerOptions(scope), errorSink);
-
- if (compiledCode == null) {
- throw new SyntaxErrorException();
- }
-
- return compiledCode.Run(scope);
- }
-
- /// <summary>
- /// Executes in a new scope created by the language.
- /// </summary>
- public object Execute() {
- return Compile().Run();
- }
-
- /// <summary>
- /// Executes in a new scope created by the language.
- /// </summary>
- public object Execute(ErrorSink errorSink) {
- return Compile(errorSink).Run();
- }
-
- /// <summary>
- /// Executes in a new scope created by the language.
- /// </summary>
- public object Execute(CompilerOptions options, ErrorSink errorSink) {
- return Compile(options, errorSink).Run();
- }
-
- public int ExecuteProgram() {
- return _language.ExecuteProgram(this);
- }
-
- #endregion
-
- public void SetLineMapping(KeyValuePair<int, int>[] lineMap) {
- _lineMap = (lineMap == null || lineMap.Length == 0) ? null : lineMap;
- }
- }
- }