提交 f1702c92 编写于 作者: K Kevin Halverson

Merge pull request #4346 from KevinH-MS/Directives

#load directives...
......@@ -230,6 +230,8 @@
<Compile Include="Compilation\AttributeSemanticModel.cs" />
<Compile Include="Compilation\AwaitExpressionInfo.cs" />
<Compile Include="Compilation\BuiltInOperators.cs" />
<Compile Include="Compilation\SyntaxAndDeclarationManager.cs" />
<Compile Include="Compilation\SyntaxAndDeclarationManager.LazyState.cs" />
<Compile Include="Compilation\CSharpCompilerDiagnosticAnalyzer.cs" />
<Compile Include="Compilation\CSharpCompilation.cs" />
<Compile Include="Compilation\CSharpCompilationReference.cs" />
......
......@@ -351,6 +351,12 @@ internal static bool HasReferenceDirectives(this SyntaxTree tree)
return csharpTree != null && csharpTree.HasReferenceDirectives;
}
internal static bool HasReferenceOrLoadDirectives(this SyntaxTree tree)
{
var csharpTree = tree as CSharpSyntaxTree;
return csharpTree != null && csharpTree.HasReferenceOrLoadDirectives;
}
internal static bool IsAnyPreprocessorSymbolDefined(this SyntaxTree tree, ImmutableArray<string> conditionalSymbols)
{
var csharpTree = tree as CSharpSyntaxTree;
......
......@@ -61,6 +61,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot have a previousSubmission when not a submission..
/// </summary>
internal static string CannotHavePreviousSubmission {
get {
return ResourceManager.GetString("CannotHavePreviousSubmission", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Can&apos;t reference compilation of type &apos;{0}&apos; from {1} compilation..
/// </summary>
......@@ -88,6 +97,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Could not find file..
/// </summary>
internal static string CouldNotFindFile {
get {
return ResourceManager.GetString("CouldNotFindFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to element is expected.
/// </summary>
......@@ -5362,6 +5380,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to #load is only allowed in scripts.
/// </summary>
internal static string ERR_LoadDirectiveOnlyAllowedInScripts {
get {
return ResourceManager.GetString("ERR_LoadDirectiveOnlyAllowedInScripts", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Local &apos;{0}&apos; or its members cannot have their address taken and be used inside an anonymous method or lambda expression.
/// </summary>
......@@ -7027,6 +7054,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use #load after first token in file.
/// </summary>
internal static string ERR_PPLoadFollowsToken {
get {
return ResourceManager.GetString("ERR_PPLoadFollowsToken", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use #r after first token in file.
/// </summary>
......@@ -9674,6 +9710,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to SyntaxTree &apos;{0}&apos; resulted from a #load directive and cannot be removed or replaced directly..
/// </summary>
internal static string SyntaxTreeFromLoadNoRemoveReplace {
get {
return ResourceManager.GetString("SyntaxTreeFromLoadNoRemoveReplace", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SyntaxTree &apos;{0}&apos; not found to remove.
/// </summary>
......@@ -9746,24 +9791,6 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to trees[{0}].
/// </summary>
internal static string Trees0 {
get {
return ResourceManager.GetString("Trees0", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to trees[{0}] must have root node with SyntaxKind.CompilationUnit..
/// </summary>
internal static string TreesMustHaveRootNode {
get {
return ResourceManager.GetString("TreesMustHaveRootNode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type argument cannot be null.
/// </summary>
......
......@@ -4161,15 +4161,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="CantReferenceCompilationOf" xml:space="preserve">
<value>Can't reference compilation of type '{0}' from {1} compilation.</value>
</data>
<data name="TreesMustHaveRootNode" xml:space="preserve">
<value>trees[{0}] must have root node with SyntaxKind.CompilationUnit.</value>
</data>
<data name="SyntaxTreeAlreadyPresent" xml:space="preserve">
<value>Syntax tree already present</value>
</data>
<data name="Trees0" xml:space="preserve">
<value>trees[{0}]</value>
</data>
<data name="SubmissionCanOnlyInclude" xml:space="preserve">
<value>Submission can only include script code.</value>
</data>
......@@ -4641,4 +4635,20 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_DebugEntryPointNotSourceMethodDefinition" xml:space="preserve">
<value>Debug entry point must be a definition of a method declared in the current compilation.</value>
</data>
<data name="ERR_LoadDirectiveOnlyAllowedInScripts" xml:space="preserve">
<value>#load is only allowed in scripts</value>
</data>
<data name="ERR_PPLoadFollowsToken" xml:space="preserve">
<value>Cannot use #load after first token in file</value>
</data>
<data name="CouldNotFindFile" xml:space="preserve">
<value>Could not find file.</value>
<comment>File path referenced in source (#load) could not be resolved.</comment>
</data>
<data name="CannotHavePreviousSubmission" xml:space="preserve">
<value>Cannot have a previousSubmission when not a submission.</value>
</data>
<data name="SyntaxTreeFromLoadNoRemoveReplace" xml:space="preserve">
<value>SyntaxTree '{0}' resulted from a #load directive and cannot be removed or replaced directly.</value>
</data>
</root>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class SyntaxAndDeclarationManager : CommonSyntaxAndDeclarationManager
{
internal sealed class State
{
internal readonly ImmutableArray<SyntaxTree> SyntaxTrees; // In ordinal order.
internal readonly ImmutableDictionary<SyntaxTree, int> OrdinalMap; // Inverse of syntaxTrees array (i.e. maps tree to index)
internal readonly ImmutableDictionary<SyntaxTree, ImmutableArray<LoadDirective>> LoadDirectiveMap;
internal readonly ImmutableDictionary<string, SyntaxTree> LoadedSyntaxTreeMap;
internal readonly ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> RootNamespaces;
internal readonly DeclarationTable DeclarationTable;
internal State(
ImmutableArray<SyntaxTree> syntaxTrees,
ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap,
ImmutableDictionary<SyntaxTree, ImmutableArray<LoadDirective>> loadDirectiveMap,
ImmutableDictionary<string, SyntaxTree> loadedSyntaxTreeMap,
ImmutableDictionary<SyntaxTree, Lazy<RootSingleNamespaceDeclaration>> rootNamespaces,
DeclarationTable declarationTable)
{
Debug.Assert(syntaxTrees.All(tree => syntaxTrees[syntaxTreeOrdinalMap[tree]] == tree));
Debug.Assert(syntaxTrees.SetEquals(rootNamespaces.Keys.AsImmutable(), EqualityComparer<SyntaxTree>.Default));
this.SyntaxTrees = syntaxTrees;
this.OrdinalMap = syntaxTreeOrdinalMap;
this.LoadDirectiveMap = loadDirectiveMap;
this.LoadedSyntaxTreeMap = loadedSyntaxTreeMap;
this.RootNamespaces = rootNamespaces;
this.DeclarationTable = declarationTable;
}
}
}
}
......@@ -1312,5 +1312,7 @@ internal enum ErrorCode
WRN_AlignmentMagnitude = 8094,
ERR_ConstantStringTooLong = 8095,
ERR_DebugEntryPointNotSourceMethodDefinition = 8096,
ERR_LoadDirectiveOnlyAllowedInScripts = 8097,
ERR_PPLoadFollowsToken = 8098,
}
}
......@@ -37,8 +37,8 @@ internal DirectiveParser(Lexer lexer, DirectiveStack context)
// 1) #error, #warning, #line, and #pragma have no effect and produce no diagnostics.
// 2) #if, #else, #elif, #endif, #region, and #endregion must still nest correctly.
// 3) #define and #undef produce diagnostics but have no effect.
// #reference is new, but it does not require nesting behavior, so we'll ignore its
// diagnostics (as in (1) above).
// #reference, #load and #! are new, but they do not require nesting behavior, so we'll
// ignore their diagnostics (as in (1) above).
SyntaxKind contextualKind = this.CurrentToken.ContextualKind;
switch (contextualKind)
......@@ -89,6 +89,10 @@ internal DirectiveParser(Lexer lexer, DirectiveStack context)
result = this.ParseReferenceDirective(hash, this.EatContextualToken(contextualKind), isActive, isAfterFirstTokenInFile && !isAfterNonWhitespaceOnLine);
break;
case SyntaxKind.LoadKeyword:
result = this.ParseLoadDirective(hash, this.EatContextualToken(contextualKind), isActive, isAfterFirstTokenInFile && !isAfterNonWhitespaceOnLine);
break;
default:
var id = this.EatToken(SyntaxKind.IdentifierToken, false);
var end = this.ParseEndOfDirective(ignoreErrors: true);
......@@ -359,13 +363,32 @@ private DirectiveTriviaSyntax ParseReferenceDirective(SyntaxToken hash, SyntaxTo
}
}
SyntaxToken file = this.EatToken(SyntaxKind.StringLiteralToken, ErrorCode.ERR_ExpectedPPFile, reportError: isActive);
var end = this.ParseEndOfDirective(ignoreErrors: file.IsMissing || !isActive, afterPragma: false, afterLineNumber: false, afterReference: true);
var end = this.ParseEndOfDirective(ignoreErrors: file.IsMissing || !isActive);
return SyntaxFactory.ReferenceDirectiveTrivia(hash, keyword, file, end, isActive);
}
private DirectiveTriviaSyntax ParseLoadDirective(SyntaxToken hash, SyntaxToken keyword, bool isActive, bool isFollowingToken)
{
if (isActive)
{
if (Options.Kind == SourceCodeKind.Regular)
{
keyword = this.AddError(keyword, ErrorCode.ERR_LoadDirectiveOnlyAllowedInScripts);
}
else if (isFollowingToken)
{
keyword = this.AddError(keyword, ErrorCode.ERR_PPLoadFollowsToken);
}
}
SyntaxToken file = this.EatToken(SyntaxKind.StringLiteralToken, ErrorCode.ERR_ExpectedPPFile, reportError: isActive);
var end = this.ParseEndOfDirective(ignoreErrors: file.IsMissing || !isActive);
return SyntaxFactory.LoadDirectiveTrivia(hash, keyword, file, end, isActive);
}
private DirectiveTriviaSyntax ParsePragmaDirective(SyntaxToken hash, SyntaxToken pragma, bool isActive)
{
pragma = CheckFeatureAvailability(pragma, MessageID.IDS_FeaturePragma);
......@@ -512,7 +535,7 @@ private SyntaxToken ParseEndOfDirectiveWithOptionalPreprocessingMessage()
return endOfDirective;
}
private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = false, bool afterLineNumber = false, bool afterReference = false)
private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = false, bool afterLineNumber = false)
{
var skippedTokens = new SyntaxListBuilder<SyntaxToken>();
......@@ -524,7 +547,7 @@ private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = fa
if (!ignoreErrors)
{
ErrorCode errorCode = ErrorCode.ERR_EndOfPPLineExpected;
var errorCode = ErrorCode.ERR_EndOfPPLineExpected;
if (afterPragma)
{
errorCode = ErrorCode.WRN_EndOfPPLineExpected;
......@@ -533,10 +556,6 @@ private SyntaxToken ParseEndOfDirective(bool ignoreErrors, bool afterPragma = fa
{
errorCode = ErrorCode.ERR_MissingPPFile;
}
else if (afterReference)
{
errorCode = ErrorCode.ERR_ExpectedPPFile;
}
skippedTokens.Add(this.AddError(this.EatToken().WithoutDiagnosticsGreen(), errorCode));
}
......
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxToken
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxTriviaList
Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.WithKind(Microsoft.CodeAnalysis.SourceCodeKind kind) -> Microsoft.CodeAnalysis.CSharp.CSharpParseOptions
Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax.GetLoadDirectives() -> System.Collections.Generic.IList<Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax>
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.File.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.LoadKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken loadKeyword, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithFile(Microsoft.CodeAnalysis.SyntaxToken file) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithIsActive(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.WithLoadKeyword(Microsoft.CodeAnalysis.SyntaxToken loadKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
Microsoft.CodeAnalysis.CSharp.SyntaxKind.LoadDirectiveTrivia = 8923 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.LoadKeyword = 8485 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.ShebangCommentTrivia = 8922 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
override Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.CommonWithKind(Microsoft.CodeAnalysis.SourceCodeKind kind) -> Microsoft.CodeAnalysis.ParseOptions
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken
override Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax.IsActive.get -> bool
static Microsoft.CodeAnalysis.CSharp.CSharpCommandLineParser.Interactive.get -> Microsoft.CodeAnalysis.CSharp.CSharpCommandLineParser
static Microsoft.CodeAnalysis.CSharp.CSharpCompilation.CreateSubmission(string assemblyName, Microsoft.CodeAnalysis.SyntaxTree syntaxTree = null, System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.MetadataReference> references = null, Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions options = null, Microsoft.CodeAnalysis.Compilation previousSubmission = null, System.Type returnType = null, System.Type hostObjectType = null) -> Microsoft.CodeAnalysis.CSharp.CSharpCompilation
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation = " ", string eol = "\r\n", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxToken
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation, bool elasticTrivia) -> Microsoft.CodeAnalysis.SyntaxToken
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation = " ", string eol = "\r\n", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxTriviaList
static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation, bool elasticTrivia) -> Microsoft.CodeAnalysis.SyntaxTriviaList
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxToken token, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxToken
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxExtensions.NormalizeWhitespace(this Microsoft.CodeAnalysis.SyntaxTriviaList list, string indentation = " ", bool elasticTrivia = false) -> Microsoft.CodeAnalysis.SyntaxTriviaList
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LoadDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken file, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LoadDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken loadKeyword, Microsoft.CodeAnalysis.SyntaxToken file, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitLoadDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.LoadDirectiveTriviaSyntax node) -> TResult
\ No newline at end of file
......@@ -110,6 +110,22 @@ internal bool HasReferenceDirectives
}
}
internal bool HasReferenceOrLoadDirectives
{
get
{
Debug.Assert(this.HasCompilationUnitRoot);
if (Options.Kind == SourceCodeKind.Interactive || Options.Kind == SourceCodeKind.Script)
{
var compilationUnitRoot = this.GetCompilationUnitRoot();
return compilationUnitRoot.GetReferenceDirectives().Count > 0 || compilationUnitRoot.GetLoadDirectives().Count > 0;
}
return false;
}
}
#region Preprocessor Symbols
private bool _hasDirectives;
private InternalSyntax.DirectiveStack _directives;
......
......@@ -25,6 +25,16 @@ internal IList<ReferenceDirectiveTriviaSyntax> GetReferenceDirectives(Func<Refer
return firstToken.GetDirectives<ReferenceDirectiveTriviaSyntax>(filter);
}
/// <summary>
/// Returns #load directives specified in the compilation.
/// </summary>
public IList<LoadDirectiveTriviaSyntax> GetLoadDirectives()
{
// #load directives are always on the first token of the compilation unit.
var firstToken = (SyntaxNodeOrToken)this.GetFirstToken(includeZeroWidth: true);
return firstToken.GetDirectives<LoadDirectiveTriviaSyntax>(filter: null);
}
internal Syntax.InternalSyntax.DirectiveStack GetConditionalDirectivesStack()
{
IEnumerable<DirectiveTriviaSyntax> directives = this.GetDirectives(filter: IsActiveConditionalDirective);
......
......@@ -3979,4 +3979,20 @@
</Field>
<Field Name="IsActive" Type="bool" Override="true"/>
</Node>
<Node Name="LoadDirectiveTriviaSyntax" Base="DirectiveTriviaSyntax">
<Kind Name="LoadDirectiveTrivia"/>
<Field Name="HashToken" Type="SyntaxToken" Override="true">
<Kind Name="HashToken"/>
</Field>
<Field Name="LoadKeyword" Type="SyntaxToken">
<Kind Name="LoadKeyword"/>
</Field>
<Field Name="File" Type="SyntaxToken">
<Kind Name="StringLiteralToken"/>
</Field>
<Field Name="EndOfDirectiveToken" Type="SyntaxToken" Override="true">
<Kind Name="EndOfDirectiveToken"/>
</Field>
<Field Name="IsActive" Type="bool" Override="true"/>
</Node>
</Tree>
......@@ -209,6 +209,7 @@ public enum SyntaxKind : ushort
DisableKeyword = 8479,
RestoreKeyword = 8480,
ReferenceKeyword = 8481,
LoadKeyword = 8485,
InterpolatedStringStartToken = 8482, // $"
InterpolatedStringEndToken = 8483, // "
......@@ -530,5 +531,6 @@ public enum SyntaxKind : ushort
InterpolationFormatClause = 8921,
ShebangCommentTrivia = 8922,
LoadDirectiveTrivia = 8923,
}
}
......@@ -87,6 +87,7 @@ public static bool IsPreprocessorKeyword(SyntaxKind kind)
case SyntaxKind.DisableKeyword:
case SyntaxKind.RestoreKeyword:
case SyntaxKind.ReferenceKeyword:
case SyntaxKind.LoadKeyword:
return true;
default:
return false;
......@@ -193,6 +194,7 @@ public static bool IsAnyToken(SyntaxKind kind)
case SyntaxKind.InterpolatedVerbatimStringStartToken:
case SyntaxKind.InterpolatedStringTextToken:
case SyntaxKind.InterpolatedStringEndToken:
case SyntaxKind.LoadKeyword:
return true;
default:
return false;
......@@ -1020,6 +1022,8 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)
return SyntaxKind.RestoreKeyword;
case "r":
return SyntaxKind.ReferenceKeyword;
case "load":
return SyntaxKind.LoadKeyword;
default:
return SyntaxKind.None;
}
......@@ -1496,6 +1500,8 @@ public static string GetText(SyntaxKind kind)
return "restore";
case SyntaxKind.ReferenceKeyword:
return "r";
case SyntaxKind.LoadKeyword:
return "load";
// contextual keywords
case SyntaxKind.YieldKeyword:
......
......@@ -68,6 +68,7 @@
<Compile Include="Compilation\GetSemanticInfoTests.cs" />
<Compile Include="Compilation\GetUnusedImportDirectivesTests.cs" />
<Compile Include="Compilation\IndexedProperties_BindingTests.cs" />
<Compile Include="Compilation\LoadDirectiveTests.cs" />
<Compile Include="Compilation\QueryClauseInfoTests.cs" />
<Compile Include="Compilation\ReferenceManagerTests.cs" />
<Compile Include="Compilation\SemanticModelAPITests.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class LoadDirectiveTests : CSharpTestBase
{
[Fact]
void EmptyFile()
{
var code = "#load \"\"";
var compilation = CreateCompilation(code);
Assert.Single(compilation.SyntaxTrees);
compilation.GetDiagnostics().Verify(
// error CS1504: Source file '' could not be opened -- Could not find file.
Diagnostic(ErrorCode.ERR_NoSourceFile, "\"\"").WithArguments("", CSharpResources.CouldNotFindFile).WithLocation(1, 7));
}
[Fact]
void MissingFile()
{
var code = "#load \"missing\"";
var compilation = CreateCompilation(code);
Assert.Single(compilation.SyntaxTrees);
compilation.GetDiagnostics().Verify(
// error CS1504: Source file 'missing' could not be opened -- Could not find file.
Diagnostic(ErrorCode.ERR_NoSourceFile, "\"missing\"").WithArguments("missing", CSharpResources.CouldNotFindFile).WithLocation(1, 7));
}
[Fact]
void FileWithErrors()
{
var code = "#load \"a.csx\"";
var resolver = CreateResolver(
Script("a.csx", @"
#load ""b.csx""
asdf();"));
var compilation = CreateCompilation(code, resolver);
Assert.Equal(2, compilation.SyntaxTrees.Length);
compilation.GetParseDiagnostics().Verify(
// a.csx(2,27): error CS1504: Source file 'b.csx' could not be opened -- Could not find file.
// #load "b.csx";
Diagnostic(ErrorCode.ERR_NoSourceFile, @"""b.csx""").WithArguments("b.csx", "Could not find file.").WithLocation(2, 27));
compilation.GetDiagnostics().Verify(
// a.csx(2,27): error CS1504: Source file 'b.csx' could not be opened -- Could not find file.
// #load "b.csx";
Diagnostic(ErrorCode.ERR_NoSourceFile, @"""b.csx""").WithArguments("b.csx", "Could not find file.").WithLocation(2, 27),
// a.csx(3,21): error CS0103: The name 'asdf' does not exist in the current context
// asdf();
Diagnostic(ErrorCode.ERR_NameNotInContext, "asdf").WithArguments("asdf").WithLocation(3, 21));
}
private static CSharpCompilation CreateCompilation(string code, SourceReferenceResolver sourceReferenceResolver = null)
{
var options = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
sourceReferenceResolver: sourceReferenceResolver ?? TestSourceReferenceResolver.Default);
var parseOptions = new CSharpParseOptions(kind: SourceCodeKind.Interactive);
return CreateCompilationWithMscorlib(code, options: options, parseOptions: parseOptions);
}
private static SourceReferenceResolver CreateResolver(params KeyValuePair<string, string>[] scripts)
{
var sources = new Dictionary<string, string>();
foreach (var script in scripts)
{
sources.Add(script.Key, script.Value);
}
return new TestSourceReferenceResolver(sources);
}
private static KeyValuePair<string, string> Script(string path, string source)
{
return new KeyValuePair<string, string>(path, source);
}
private class TestSourceReferenceResolver : SourceReferenceResolver
{
private readonly IDictionary<string, string> _sources;
public static TestSourceReferenceResolver Default { get; } = new TestSourceReferenceResolver();
public TestSourceReferenceResolver(IDictionary<string, string> sources = null)
{
_sources = sources;
}
public override string NormalizePath(string path, string baseFilePath)
{
return path;
}
public override string ResolveReference(string path, string baseFilePath)
{
return ((_sources != null) && _sources.ContainsKey(path)) ? path : null;
}
public override Stream OpenRead(string resolvedPath)
{
if (_sources != null)
{
return new MemoryStream(Encoding.UTF8.GetBytes(_sources[resolvedPath]));
}
else
{
throw new IOException();
}
}
public override bool Equals(object other)
{
return this.Equals(other);
}
public override int GetHashCode()
{
return this.GetHashCode();
}
}
}
}
......@@ -4,13 +4,12 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
//test
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
#region Local types for verification
......@@ -3810,5 +3809,67 @@ public void TestReferenceWithVariousFileNameFormats()
}
#endregion
#region #load
[Fact]
public void TestLoad()
{
var text = "#load \"bogus\"";
var node = Parse(text, SourceCodeKind.Script);
TestRoundTripping(node, text);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
Text = "bogus"
});
}
[Fact]
public void TestLoadWithoutFile()
{
var text = "#load";
var node = Parse(text, SourceCodeKind.Interactive);
TestRoundTripping(node, text, disallowErrors: false);
VerifyErrorCode(node, (int)ErrorCode.ERR_ExpectedPPFile);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
});
Assert.True(node.GetLoadDirectives().Single().File.IsMissing);
}
[Fact]
public void TestLoadWithSemicolon()
{
var text = "#load \"\";";
var node = Parse(text, SourceCodeKind.Interactive);
TestRoundTripping(node, text, disallowErrors: false);
VerifyErrorCode(node, (int)ErrorCode.ERR_EndOfPPLineExpected);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
Text = ""
});
}
[Fact]
public void TestLoadWithComment()
{
var text = "#load \"bogus\" // comment";
var node = Parse(text, SourceCodeKind.Script);
TestRoundTripping(node, text);
VerifyDirectivesSpecial(node, new DirectiveInfo
{
Kind = SyntaxKind.LoadDirectiveTrivia,
Status = NodeStatus.IsActive,
Text = "bogus"
});
}
#endregion
}
}
......@@ -135,6 +135,8 @@
<Compile Include="CommandLine\ErrorLogger.WellKnownStrings.cs" />
<Compile Include="CommandLine\TouchedFileLogger.cs" />
<Compile Include="Compilation.EmitStreamProvider.cs" />
<Compile Include="Compilation\LoadDirective.cs" />
<Compile Include="Compilation\CommonSyntaxAndDeclarationManager.cs" />
<Compile Include="Compilation\SymbolFilter.cs" />
<Compile Include="CompilerPathUtilities.cs" />
<Compile Include="DiagnosticAnalyzer\AnalysisResult.cs" />
......
......@@ -150,40 +150,46 @@ internal SourceText ReadFileContent(CommandLineSourceFile file, IList<Diagnostic
/// <returns>File content or null on failure.</returns>
internal SourceText ReadFileContent(CommandLineSourceFile file, IList<DiagnosticInfo> diagnostics, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, out string normalizedFilePath)
{
var filePath = file.Path;
try
{
// PERF: Using a very small buffer size for the FileStream opens up an optimization within EncodedStringText where
// we read the entire FileStream into a byte array in one shot. For files that are actually smaller than the buffer
// size, FileStream.Read still allocates the internal buffer.
using (var data = PortableShim.FileStream.Create(file.Path, PortableShim.FileMode.Open, PortableShim.FileAccess.Read, PortableShim.FileShare.ReadWrite, bufferSize: 1, options: PortableShim.FileOptions.None))
{
normalizedFilePath = (string)PortableShim.FileStream.Name.GetValue(data);
return EncodedStringText.Create(data, encoding, checksumAlgorithm);
}
return ReadFileContentHelper(filePath, encoding, checksumAlgorithm, out normalizedFilePath);
}
catch (Exception e)
{
diagnostics.Add(ToFileReadDiagnostics(e, file));
diagnostics.Add(ToFileReadDiagnostics(this.MessageProvider, e, filePath));
normalizedFilePath = null;
return null;
}
}
private DiagnosticInfo ToFileReadDiagnostics(Exception e, CommandLineSourceFile file)
internal static SourceText ReadFileContentHelper(string filePath, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, out string normalizedFilePath)
{
// PERF: Using a very small buffer size for the FileStream opens up an optimization within EncodedStringText where
// we read the entire FileStream into a byte array in one shot. For files that are actually smaller than the buffer
// size, FileStream.Read still allocates the internal buffer.
using (var data = PortableShim.FileStream.Create(filePath, PortableShim.FileMode.Open, PortableShim.FileAccess.Read, PortableShim.FileShare.ReadWrite, bufferSize: 1, options: PortableShim.FileOptions.None))
{
normalizedFilePath = (string)PortableShim.FileStream.Name.GetValue(data);
return EncodedStringText.Create(data, encoding, checksumAlgorithm);
}
}
internal static DiagnosticInfo ToFileReadDiagnostics(CommonMessageProvider messageProvider, Exception e, string filePath)
{
DiagnosticInfo diagnosticInfo;
if (e is FileNotFoundException || e.GetType().Name == "DirectoryNotFoundException")
{
diagnosticInfo = new DiagnosticInfo(MessageProvider, MessageProvider.ERR_FileNotFound, file.Path);
diagnosticInfo = new DiagnosticInfo(messageProvider, messageProvider.ERR_FileNotFound, filePath);
}
else if (e is InvalidDataException)
{
diagnosticInfo = new DiagnosticInfo(MessageProvider, MessageProvider.ERR_BinaryFile, file.Path);
diagnosticInfo = new DiagnosticInfo(messageProvider, messageProvider.ERR_BinaryFile, filePath);
}
else
{
diagnosticInfo = new DiagnosticInfo(MessageProvider, MessageProvider.ERR_NoSourceFile, file.Path, e.Message);
diagnosticInfo = new DiagnosticInfo(messageProvider, messageProvider.ERR_NoSourceFile, filePath, e.Message);
}
return diagnosticInfo;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis
{
internal abstract class CommonSyntaxAndDeclarationManager
{
internal readonly ImmutableArray<SyntaxTree> ExternalSyntaxTrees;
internal readonly string ScriptClassName;
internal readonly SourceReferenceResolver Resolver;
internal readonly CommonMessageProvider MessageProvider;
internal readonly bool IsSubmission;
private ImmutableDictionary<SyntaxTree, ImmutableArray<Diagnostic>> _syntaxTreeLoadDirectiveMap;
// This ImmutableDictionary will use default (case-sensitive) comparison
// for its keys. It is the responsibility of the SourceReferenceResolver
// to normalize the paths it resolves in a way that is appropriate for the
// platforms that the host supports.
private ImmutableDictionary<string, SyntaxTree> _resolvedFilePathSyntaxTreeMap;
public CommonSyntaxAndDeclarationManager(
ImmutableArray<SyntaxTree> externalSyntaxTrees,
string scriptClassName,
SourceReferenceResolver resolver,
CommonMessageProvider messageProvider,
bool isSubmission)
{
this.ExternalSyntaxTrees = externalSyntaxTrees;
this.ScriptClassName = scriptClassName ?? "";
this.Resolver = resolver; // TODO: What if SourceReferenceResolver is null?
this.MessageProvider = messageProvider;
this.IsSubmission = isSubmission;
}
}
}
......@@ -32,9 +32,6 @@ namespace Microsoft.CodeAnalysis
/// </summary>
public abstract partial class Compilation
{
// Inverse of syntaxTrees array (i.e. maps tree to index)
internal readonly ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap;
/// <summary>
/// Returns true if this is a case sensitive compilation, false otherwise. Case sensitivity
/// affects compilation features such as name lookup as well as choosing what names to emit
......@@ -58,17 +55,17 @@ public abstract partial class Compilation
internal Compilation(
string name,
ImmutableArray<MetadataReference> references,
IReadOnlyDictionary<string, string> features,
Type submissionReturnType,
Type hostObjectType,
bool isSubmission,
ImmutableDictionary<SyntaxTree, int> syntaxTreeOrdinalMap,
AsyncQueue<CompilationEvent> eventQueue)
{
Debug.Assert(!references.IsDefault);
Debug.Assert(features != null);
this.AssemblyName = name;
this.ExternalReferences = references;
this.syntaxTreeOrdinalMap = syntaxTreeOrdinalMap;
this.EventQueue = eventQueue;
if (isSubmission)
......@@ -82,10 +79,10 @@ public abstract partial class Compilation
_lazySubmissionSlotIndex = SubmissionSlotIndexNotApplicable;
}
_features = SyntaxTreeCommonFeatures(syntaxTreeOrdinalMap.Keys);
_features = features;
}
private IReadOnlyDictionary<string, string> SyntaxTreeCommonFeatures(IEnumerable<SyntaxTree> trees)
protected static IReadOnlyDictionary<string, string> SyntaxTreeCommonFeatures(IEnumerable<SyntaxTree> trees)
{
IReadOnlyDictionary<string, string> set = null;
......@@ -2137,14 +2134,10 @@ internal int CompareSyntaxTreeOrdering(SyntaxTree tree1, SyntaxTree tree2)
Debug.Assert(this.ContainsSyntaxTree(tree1));
Debug.Assert(this.ContainsSyntaxTree(tree2));
return this.syntaxTreeOrdinalMap[tree1] - this.syntaxTreeOrdinalMap[tree2];
return this.GetSyntaxTreeOrdinal(tree1) - this.GetSyntaxTreeOrdinal(tree2);
}
internal int GetSyntaxTreeOrdinal(SyntaxTree tree)
{
Debug.Assert(this.ContainsSyntaxTree(tree));
return this.syntaxTreeOrdinalMap[tree];
}
internal abstract int GetSyntaxTreeOrdinal(SyntaxTree tree);
/// <summary>
/// Compare two source locations, using their containing trees, and then by Span.First within a tree.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal struct LoadDirective : IEquatable<LoadDirective>
{
public readonly string ResolvedPath;
public readonly ImmutableArray<Diagnostic> Diagnostics;
public LoadDirective(string resolvedPath, ImmutableArray<Diagnostic> diagnostics)
{
Debug.Assert((resolvedPath != null) || !diagnostics.IsEmpty);
Debug.Assert(!diagnostics.IsDefault);
Debug.Assert(diagnostics.IsEmpty || diagnostics.All(d => d.Severity == DiagnosticSeverity.Error));
ResolvedPath = resolvedPath;
Diagnostics = diagnostics;
}
public bool Equals(LoadDirective other)
{
return this.ResolvedPath == other.ResolvedPath &&
this.Diagnostics.SequenceEqual(other.Diagnostics);
}
public override bool Equals(object obj)
{
return obj is LoadDirective && Equals((LoadDirective)obj);
}
public override int GetHashCode()
{
return Hash.Combine(this.Diagnostics.GetHashCode(), this.ResolvedPath.GetHashCode());
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis
{
......@@ -53,5 +55,14 @@ internal Stream OpenReadChecked(string fullPath)
return stream;
}
/// <summary>
/// Reads the contents of <paramref name="resolvedPath"/> and returns a <see cref="SourceText"/>.
/// </summary>
/// <param name="resolvedPath">Path returned by <see cref="ResolveReference(string, string)"/>.</param>
public virtual SourceText ReadText(string resolvedPath)
{
return SourceText.From(OpenRead(resolvedPath));
}
}
}
......@@ -48,4 +48,5 @@ static Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzerExtensions.WithAnaly
static Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry.GetAnalyzerActionCountsAsync(this Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers compilationWithAnalyzers, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry.ActionCounts>
static Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetry.GetAnalyzerExecutionTime(this Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers compilationWithAnalyzers, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer) -> System.TimeSpan
static Microsoft.CodeAnalysis.SyntaxNodeExtensions.NormalizeWhitespace<TNode>(this TNode node, string indentation = " ", string eol = "\r\n", bool elasticTrivia = false) -> TNode
static Microsoft.CodeAnalysis.SyntaxNodeExtensions.NormalizeWhitespace<TNode>(this TNode node, string indentation, bool elasticTrivia) -> TNode
\ No newline at end of file
static Microsoft.CodeAnalysis.SyntaxNodeExtensions.NormalizeWhitespace<TNode>(this TNode node, string indentation, bool elasticTrivia) -> TNode
virtual Microsoft.CodeAnalysis.SourceReferenceResolver.ReadText(string resolvedPath) -> Microsoft.CodeAnalysis.Text.SourceText
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;
......@@ -17,6 +18,13 @@ private PooledDictionary(ObjectPool<PooledDictionary<K, V>> pool)
_pool = pool;
}
public ImmutableDictionary<K, V> ToImmutableDictionaryAndFree()
{
var result = this.ToImmutableDictionary();
this.Free();
return result;
}
public void Free()
{
this.Clear();
......
......@@ -80,6 +80,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' </summary>
Private ReadOnly _syntaxTrees As ImmutableArray(Of SyntaxTree)
Private ReadOnly _syntaxTreeOrdinalMap As ImmutableDictionary(Of SyntaxTree, Integer)
''' <summary>
''' The syntax trees of this compilation plus all 'hidden' trees
''' added to the compilation by compiler, e.g. Vb Core Runtime.
......@@ -411,7 +413,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
reuseReferenceManager As Boolean,
Optional eventQueue As AsyncQueue(Of CompilationEvent) = Nothing
)
MyBase.New(assemblyName, references, submissionReturnType, hostObjectType, isSubmission, syntaxTreeOrdinalMap, eventQueue)
MyBase.New(assemblyName, references, SyntaxTreeCommonFeatures(syntaxTrees), submissionReturnType, hostObjectType, isSubmission, eventQueue)
Debug.Assert(rootNamespaces IsNot Nothing)
Debug.Assert(declarationTable IsNot Nothing)
......@@ -421,6 +423,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
_options = options
_syntaxTrees = syntaxTrees
_syntaxTreeOrdinalMap = syntaxTreeOrdinalMap
_rootNamespaces = rootNamespaces
_embeddedTrees = embeddedTrees
_declarationTable = declarationTable
......@@ -486,7 +489,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
_options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -538,7 +541,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -579,7 +582,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
ValidateReferences(Of VisualBasicCompilationReference)(newReferences),
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
embeddedTrees,
declTable,
......@@ -632,7 +635,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
newOptions,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
declMap,
embeddedTrees,
declTable,
......@@ -660,7 +663,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -681,7 +684,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.Options,
Me.ExternalReferences,
_syntaxTrees,
Me.syntaxTreeOrdinalMap,
_syntaxTreeOrdinalMap,
_rootNamespaces,
_embeddedTrees,
_declarationTable,
......@@ -845,7 +848,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim referenceDirectivesChanged = False
Dim oldTreeCount = _syntaxTrees.Length
Dim ordinalMap = Me.syntaxTreeOrdinalMap
Dim ordinalMap = _syntaxTreeOrdinalMap
Dim declMap = _rootNamespaces
Dim declTable = _declarationTable
Dim i = 0
......@@ -1020,7 +1023,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
RemoveSyntaxTreeFromDeclarationMapAndTable(vbOldTree, declMap, declTable, referenceDirectivesChanged)
AddSyntaxTreeToDeclarationMapAndTable(vbNewTree, _options, Me.IsSubmission, declMap, declTable, referenceDirectivesChanged)
Dim ordinalMap = Me.syntaxTreeOrdinalMap
Dim ordinalMap = _syntaxTreeOrdinalMap
Debug.Assert(ordinalMap.ContainsKey(oldTree)) ' Checked by RemoveSyntaxTreeFromDeclarationMapAndTable
Dim oldOrdinal = ordinalMap(oldTree)
......@@ -1159,6 +1162,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return LexicalSortKey.Compare(first, second, Me)
End Function
Friend Overrides Function GetSyntaxTreeOrdinal(tree As SyntaxTree) As Integer
Debug.Assert(Me.ContainsSyntaxTree(tree))
Return _syntaxTreeOrdinalMap(tree)
End Function
#End Region
#Region "References"
......
......@@ -278,7 +278,6 @@
<Compile Include="Formatting\Indentation\SmartTokenFormatterFormatTokenTests.cs" />
<Compile Include="Interactive\BraceMatching\InteractiveBraceHighlightingTests.cs" />
<Compile Include="Interactive\CodeActions\InteractiveIntroduceVariableTests.cs" />
<Compile Include="Interactive\CommandArgumentsParsingTest.cs" />
<Compile Include="Interactive\NavigateTo\InteractiveNavigateToTests.cs" />
<Compile Include="KeywordHighlighting\AbstractCSharpKeywordHighlighterTests.cs" />
<Compile Include="KeywordHighlighting\AsyncAnonymousMethodHighlighterTests.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Editor.Implementation.Interactive;
using Xunit;
namespace Roslyn.VisualStudio.CSharp.UnitTests.Interactive
{
public class CommandArgumentsParsingTest
{
[Fact]
public void Path()
{
TestPath("", expected: null, validArg: true, readToEnd: true);
TestPath("blah", expected: null, validArg: true, readToEnd: false);
TestPath(@"""blah""", expected: "blah", validArg: true, readToEnd: true);
TestPath(@"""b\l\a\h""", expected: @"b\l\a\h", validArg: true, readToEnd: true);
TestPath(@"""b\l\a\h"" // comment", expected: @"b\l\a\h", validArg: true, readToEnd: true);
TestPath("\t \"x\tx\" \t \r\n \t ", expected: "x\tx", validArg: true, readToEnd: true);
TestPath(@"""b\l\a\h", expected: @"b\l\a\h", validArg: false);
TestPath(@"""blah" + "\r\n" + @"""", expected: "blah", validArg: false);
TestPath(@"""blah""" + "\r\n" + @"""", expected: "blah", validArg: true, readToEnd: false);
TestPath(@"""blah//foo", expected: "blah//foo", validArg: false);
TestPath(@"""blah//foo""", expected: "blah//foo", validArg: true);
}
private void TestPath(string args, string expected, bool validArg, bool? readToEnd = null)
{
int i = 0;
string actual;
Assert.Equal(validArg, CommandArgumentsParser.ParsePath(args, ref i, out actual));
Assert.Equal(expected, actual);
if (readToEnd != null)
{
Assert.Equal(readToEnd, CommandArgumentsParser.ParseTrailingTrivia(args, ref i));
}
}
}
}
......@@ -487,33 +487,9 @@ public async Task<ExecutionResult> ExecuteCodeAsync(string text)
if (result.Success)
{
SubmissionSuccessfullyExecuted(result);
}
return new ExecutionResult(result.Success);
}
catch (Exception e) when (FatalError.Report(e))
{
throw ExceptionUtilities.Unreachable;
}
}
public async Task<ExecutionResult> LoadCommandAsync(string path)
{
try
{
var result = await _interactiveHost.ExecuteFileAsync(path).ConfigureAwait(false);
if (result.Success)
{
// We are executing a command, which means the current content type has been switched to "Command"
// and the source document removed.
Debug.Assert(!_workspace.CurrentSolution.GetProject(_currentSubmissionProjectId).HasDocuments);
Debug.Assert(result.ResolvedPath != null);
var documentId = DocumentId.CreateNewId(_currentSubmissionProjectId, result.ResolvedPath);
var newSolution = _workspace.CurrentSolution.AddDocument(documentId, Path.GetFileName(result.ResolvedPath), new FileTextLoader(result.ResolvedPath, defaultEncoding: null));
_workspace.SetCurrentSolution(newSolution);
// We are not executing a command (the current content type is not "Interactive Command"),
// so the source document should not have been removed.
Debug.Assert(_workspace.CurrentSolution.GetProject(_currentSubmissionProjectId).HasDocuments);
SubmissionSuccessfullyExecuted(result);
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Text;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Interactive
{
internal static class CommandArgumentsParser
{
internal static void SkipWhiteSpace(string args, ref int i)
{
while (!IsEnd(args, i) && char.IsWhiteSpace(args[i]))
{
i++;
}
}
internal static bool IsSingleLineCommentStart(string args, int i)
{
return i + 1 < args.Length && args[i] == '/' && args[i + 1] == '/';
}
internal static bool IsEnd(string args, int i)
{
return i == args.Length || args[i] == '\n' || args[i] == '\r';
}
internal static void SkipSingleLineComment(string args, ref int i)
{
if (IsSingleLineCommentStart(args, i))
{
i += 2;
while (!IsEnd(args, i))
{
i++;
}
}
}
/// <summary>
/// Parses an optional path argument. Path is a double-quoted string with no escapes.
/// </summary>
/// <param name="args">Arguments.</param>
/// <param name="i">Current position in <paramref name="args"/>.</param>
/// <param name="path">The path (might be incomplete if closing quote is missing) or null if the argument is missing.</param>
/// <returns>True iff parsing succeeds.</returns>
internal static bool ParsePath(string args, ref int i, out string path)
{
int stringStart, stringEnd;
return ParsePath(args, ref i, out path, out stringStart, out stringEnd);
}
internal static bool ParsePath(string args, ref int i, out string path, out int stringStart, out int stringEnd)
{
SkipWhiteSpace(args, ref i);
if (IsEnd(args, i) || args[i] != '"')
{
path = null;
stringStart = stringEnd = -1;
return true;
}
stringStart = i;
i++;
int start = i;
var result = false;
while (!IsEnd(args, i))
{
if (args[i] == '"')
{
result = true;
break;
}
i++;
}
// missing closing quote
path = args.Substring(start, i - start);
// skip closing quote:
if (result)
{
i++;
}
stringEnd = i;
return result;
}
/// <summary>
/// Parses an optional trailing single-line C# comment, whitespace and line breaks.
/// </summary>
/// <param name="args">Arguments.</param>
/// <param name="i">Current position in <paramref name="args"/>.</param>
/// <returns>True iff parsing succeeds.</returns>
internal static bool ParseTrailingTrivia(string args, ref int i)
{
int commentStart, commentEnd;
return ParseTrailingTrivia(args, ref i, out commentStart, out commentEnd);
}
internal static bool ParseTrailingTrivia(string args, ref int i, out int commentStart, out int commentEnd)
{
SkipWhiteSpace(args, ref i);
commentStart = i;
SkipSingleLineComment(args, ref i);
commentEnd = i;
// skip trailing whitespace and new lines:
while (i < args.Length && char.IsWhiteSpace(args[i]))
{
i++;
}
return i == args.Length;
}
/// <summary>
/// Parses an optional double-quoted string argument. The string may contain backslash-escaped quotes and backslashes.
/// </summary>
/// <param name="args">Arguments.</param>
/// <param name="i">Current position in <paramref name="args"/>.</param>
/// <param name="result">The string.</param>
/// <returns>True iff parsing succeeds.</returns>
internal static bool ParseQuotedString(string args, ref int i, out string result)
{
int start, end;
return ParseQuotedString(args, ref i, out result, out start, out end);
}
internal static bool ParseQuotedString(string args, ref int i, out string result, out int start, out int end)
{
result = null;
SkipWhiteSpace(args, ref i);
if (IsEnd(args, i) || args[i] != '"')
{
start = end = -1;
return true;
}
start = i;
i++;
var sb = new StringBuilder();
while (!IsEnd(args, i))
{
if (args[i] == '"')
{
result = sb.ToString();
i++;
end = i;
return true;
}
if (args[i] == '\\' && i + 1 < args.Length)
{
i++;
if (args[i] == '"' || args[i] == '\\')
{
sb.Append(args[i]);
}
else
{
end = i;
return false;
}
}
else
{
sb.Append(args[i]);
}
i++;
}
// missing closing quote
end = i;
return false;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Interactive;
using Microsoft.VisualStudio.Language.StandardClassification;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.InteractiveWindow;
using Microsoft.VisualStudio.InteractiveWindow.Commands;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Interactive
{
[Export(typeof(IInteractiveWindowCommand))]
[ContentType(PredefinedInteractiveCommandsContentTypes.InteractiveCommandContentTypeName)]
internal sealed class LoadCommand : IInteractiveWindowCommand
{
private const string CommandName = "load";
private readonly IStandardClassificationService _registry;
[ImportingConstructor]
public LoadCommand(IStandardClassificationService registry)
{
_registry = registry;
}
public IEnumerable<KeyValuePair<string, string>> ParametersDescription
{
get { return null; }
}
public IEnumerable<string> DetailedDescription
{
get { return null; }
}
public string Description
{
// TODO: Needs localization...
get { return "Executes the specified file within the current interactive session."; }
}
public IEnumerable<string> Names
{
get { yield return CommandName; }
}
public string CommandLine
{
get { return "\"path to .csx file\""; }
}
public Task<ExecutionResult> Execute(IInteractiveWindow window, string arguments)
{
var engine = window.Evaluator as InteractiveEvaluator;
if (engine != null)
{
int i = 0;
string path;
if (!CommandArgumentsParser.ParsePath(arguments, ref i, out path) || path == null)
{
ReportInvalidArguments(window);
return ExecutionResult.Failed;
}
if (!CommandArgumentsParser.ParseTrailingTrivia(arguments, ref i))
{
window.ErrorOutputWriter.WriteLine(string.Format(EditorFeaturesResources.UnexpectedText, arguments.Substring(i)));
return ExecutionResult.Failed;
}
return engine.LoadCommandAsync(path);
}
return ExecutionResult.Failed;
}
public IEnumerable<ClassificationSpan> ClassifyArguments(ITextSnapshot snapshot, Span argumentsSpan, Span spanToClassify)
{
string path;
var arguments = snapshot.GetText();
int i = argumentsSpan.Start;
int start, end;
CommandArgumentsParser.ParsePath(arguments, ref i, out path, out start, out end);
if (end > start)
{
yield return new ClassificationSpan(new SnapshotSpan(snapshot, Span.FromBounds(start, end)), _registry.StringLiteral);
}
CommandArgumentsParser.ParseTrailingTrivia(arguments, ref i, out start, out end);
if (end > start)
{
yield return new ClassificationSpan(new SnapshotSpan(snapshot, Span.FromBounds(start, end)), _registry.Comment);
}
}
private void ReportInvalidArguments(IInteractiveWindow window)
{
var commands = (IInteractiveWindowCommands)window.Properties[typeof(IInteractiveWindowCommands)];
commands.DisplayCommandUsage(this, window.ErrorOutputWriter, displayDetails: false);
}
}
}
......@@ -132,8 +132,6 @@
<Compile Include="Extensibility\Interactive\CSharpVBInteractiveCommandContentTypes.cs" />
<Compile Include="Implementation\Completion\InteractiveCommandCompletionService.cs" />
<Compile Include="Implementation\Completion\Presentation\CompletionPresenter.cs" />
<Compile Include="Implementation\Interactive\Commands\CommandArgumentsParser.cs" />
<Compile Include="Implementation\Interactive\Commands\LoadCommand.cs" />
<Compile Include="Implementation\Interactive\InertClassifierProvider.cs" />
<Compile Include="Implementation\Interactive\InertClassifierProvider.InertClassifier.cs" />
<Compile Include="Implementation\Interactive\InteractiveCommandContentTypeLanguageService.cs" />
......
......@@ -485,7 +485,7 @@ public void ExecuteFileAsync(RemoteAsyncOperation<RemoteExecutionResult> operati
}
}
private TaskResult CompleteExecution(TaskResult result, RemoteAsyncOperation<RemoteExecutionResult> operation, bool success, string resolvedPath = null)
private TaskResult CompleteExecution(TaskResult result, RemoteAsyncOperation<RemoteExecutionResult> operation, bool success)
{
// TODO (tomat): we should be resetting this info just before the execution to ensure that the services see the same
// as the next execution.
......@@ -512,7 +512,7 @@ private TaskResult CompleteExecution(TaskResult result, RemoteAsyncOperation<Rem
options = options.WithBaseDirectory(currentDirectory);
operation.Completed(new RemoteExecutionResult(success, newSourcePaths, newReferencePaths, newWorkingDirectory, resolvedPath));
operation.Completed(new RemoteExecutionResult(success, newSourcePaths, newReferencePaths, newWorkingDirectory));
return result.With(options);
}
......@@ -637,7 +637,7 @@ public void SetTestObjectFormattingOptions()
}
finally
{
result = CompleteExecution(result, operation, true);
result = CompleteExecution(result, operation, success: true);
}
return result;
......
......@@ -24,23 +24,16 @@ internal struct RemoteExecutionResult
/// </summary>
public readonly string NewWorkingDirectory;
/// <summary>
/// Resolved path if applicable. Used by ExecuteFile.
/// </summary>
public readonly string ResolvedPath;
public RemoteExecutionResult(
bool success,
string[] newSourcePaths = null,
string[] newReferencePaths = null,
string newWorkingDirectory = null,
string resolvedPath = null)
string newWorkingDirectory = null)
{
this.Success = success;
this.NewSourcePaths = newSourcePaths;
this.NewReferencePaths = newReferencePaths;
this.NewWorkingDirectory = newWorkingDirectory;
this.ResolvedPath = resolvedPath;
}
}
}
......@@ -420,8 +420,8 @@ public void AsyncExecuteFile_ScriptFileWithBuildErrors()
Host.ExecuteFileAsync(file.Path).Wait();
var errorOut = ReadErrorOutputToEnd().Trim();
Assert.True(errorOut.StartsWith(file.Path + "(1,2):", StringComparison.Ordinal), "Error output should start with file name, line and column");
Assert.True(errorOut.Contains("CS1024"), "Error output should include error CS1024");
Assert.True(errorOut.StartsWith(file.Path + "(1,7):", StringComparison.Ordinal), "Error output should start with file name, line and column");
Assert.True(errorOut.Contains("CS7010"), "Error output should include error CS7010");
}
/// <summary>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Globalization;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Scripting.CSharp
{
......@@ -44,12 +46,12 @@ public override Compilation CreateSubmission(Script script)
scriptClassName: submissionTypeName,
usings: script.Options.Namespaces,
optimizationLevel: OptimizationLevel.Debug, // TODO
checkOverflow: false, // TODO
allowUnsafe: true, // TODO
checkOverflow: false, // TODO
allowUnsafe: true, // TODO
platform: Platform.AnyCpu,
warningLevel: 4,
xmlReferenceResolver: null, // don't support XML file references in interactive (permissions & doc comment includes)
sourceReferenceResolver: SourceFileResolver.Default, // TODO
sourceReferenceResolver: LoadDirectiveResolver.Default,
metadataReferenceResolver: script.Options.ReferenceResolver,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default
),
......@@ -60,5 +62,25 @@ public override Compilation CreateSubmission(Script script)
return compilation;
}
private class LoadDirectiveResolver : SourceFileResolver
{
public static new LoadDirectiveResolver Default { get; } = new LoadDirectiveResolver();
private LoadDirectiveResolver()
: base(ImmutableArray<string>.Empty, baseDirectory: null)
{
}
public override SourceText ReadText(string resolvedPath)
{
string unused;
return CommonCompiler.ReadFileContentHelper(
resolvedPath,
encoding: null,
checksumAlgorithm: SourceHashAlgorithm.Sha1, // TODO: Should we be fetching the checksum algorithm from somewhere?
normalizedFilePath: out unused);
}
}
}
}
......@@ -54,11 +54,6 @@
<Compile Include="CSharpObjectFormatter.cs" />
<Compile Include="CSharpScript.cs" />
<Compile Include="CSharpScriptCompiler.cs" />
<Compile Include="CSharpScriptingResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>CSharpScriptingResources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<InternalsVisibleToTest Include="Roslyn.Compilers.CSharp.Emit.UnitTests" />
......@@ -67,12 +62,6 @@
<InternalsVisibleToTest Include="Microsoft.CodeAnalysis.Scripting.UnitTests" />
<InternalsVisibleToTest Include="Microsoft.CodeAnalysis.Scripting.CSharp.UnitTests" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="CSharpScriptingResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>CSharpScriptingResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
......
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.CodeAnalysis.Scripting.CSharp {
using System;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CSharpScriptingResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal CSharpScriptingResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CodeAnalysis.Scripting.CSharp.CSharpScriptingResources", typeof(CSharpScriptingResources).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
......@@ -24,7 +24,7 @@ public abstract class Script
private ScriptBuilder _lazyBuilder;
private Compilation _lazyCompilation;
internal Script(ScriptCompiler compiler, string code, ScriptOptions options, Type globalsType, ScriptBuilder builder, Script previous)
{
Compiler = compiler;
......@@ -116,7 +116,7 @@ internal ScriptBuilder Builder
/// <param name="globalsType">The type that defines members that can be accessed by the script.</param>
public Script WithGlobalsType(Type globalsType) => this.WithGlobalsTypeInternal(globalsType);
internal abstract Script WithGlobalsTypeInternal(Type globalsType);
/// <summary>
/// Continues the script with given code snippet.
/// </summary>
......@@ -215,14 +215,14 @@ internal ImmutableArray<MetadataReference> GetReferencesForCompilation()
references = references.Add(corLib);
if (this.GlobalsType != null)
{
{
var globalsTypeAssembly = MetadataReference.CreateFromAssemblyInternal(this.GlobalsType.GetTypeInfo().Assembly);
references = references.Add(globalsTypeAssembly);
}
return references;
}
}
}
}
public sealed class Script<T> : Script
{
......@@ -248,19 +248,19 @@ public new Script<T> WithCode(string code)
if (code == null)
{
code = "";
}
}
return (code == this.Code) ?
this :
new Script<T>(this.Compiler, code, this.Options, this.GlobalsType, this.LazyBuilder, this.Previous);
}
}
public new Script<T> WithGlobalsType(Type globalsType)
{
{
return (globalsType == this.GlobalsType) ?
this :
new Script<T>(this.Compiler, this.Code, this.Options, globalsType, this.LazyBuilder, this.Previous);
}
}
internal override Script WithOptionsInternal(ScriptOptions options) => WithOptions(options);
internal override Script WithCodeInternal(string code) => WithCode(code);
......@@ -268,10 +268,10 @@ public new Script<T> WithGlobalsType(Type globalsType)
/// <exception cref="CompilationErrorException">Compilation has errors.</exception>
internal override void CommonBuild(CancellationToken cancellationToken)
{
{
GetPrecedingExecutors(cancellationToken);
GetExecutor(cancellationToken);
}
}
internal override Func<object[], Task> CommonGetExecutor(CancellationToken cancellationToken)
=> GetExecutor(cancellationToken);
......@@ -304,7 +304,7 @@ internal override void CommonBuild(CancellationToken cancellationToken)
var preceding = TryGetPrecedingExecutors(null, cancellationToken);
Debug.Assert(!preceding.IsDefault);
InterlockedOperations.Initialize(ref _lazyPrecedingExecutors, preceding);
}
}
return _lazyPrecedingExecutors;
}
......@@ -314,32 +314,32 @@ internal override void CommonBuild(CancellationToken cancellationToken)
{
Script script = Previous;
if (script == lastExecutedScriptInChainOpt)
{
{
return ImmutableArray<Func<object[], Task>>.Empty;
}
}
var scriptsReversed = ArrayBuilder<Script>.GetInstance();
while (script != null && script != lastExecutedScriptInChainOpt)
{
{
scriptsReversed.Add(script);
script = script.Previous;
}
}
if (lastExecutedScriptInChainOpt != null && script != lastExecutedScriptInChainOpt)
{
{
scriptsReversed.Free();
return default(ImmutableArray<Func<object[], Task>>);
}
}
var executors = ArrayBuilder<Func<object[], Task>>.GetInstance(scriptsReversed.Count);
// We need to build executors in the order in which they are chained,
// so that assemblies created for the submissions are loaded in the correct order.
for (int i = scriptsReversed.Count - 1; i >= 0; i--)
{
{
executors.Add(scriptsReversed[i].CommonGetExecutor(cancellationToken));
}
}
return executors.ToImmutableAndFree();
}
......@@ -379,7 +379,7 @@ public new Task<ScriptState<T>> RunAsync(object globals = null, CancellationToke
var currentExecutor = GetExecutor(cancellationToken);
return RunSubmissionsAsync(executionState, precedingExecutors, currentExecutor, cancellationToken);
}
}
/// <summary>
/// Creates a delegate that will run this script from the beginning when invoked.
......@@ -388,7 +388,7 @@ public new Task<ScriptState<T>> RunAsync(object globals = null, CancellationToke
/// The delegate doesn't hold on this script or its compilation.
/// </remarks>
public ScriptRunner<T> CreateDelegate(CancellationToken cancellationToken = default(CancellationToken))
{
{
var precedingExecutors = GetPrecedingExecutors(cancellationToken);
var currentExecutor = GetExecutor(cancellationToken);
var globalsType = GlobalsType;
......@@ -411,26 +411,26 @@ public ScriptRunner<T> CreateDelegate(CancellationToken cancellationToken = defa
/// <exception cref="ArgumentNullException"><paramref name="previousState"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="previousState"/> is not a previous execution state of this script.</exception>
public new Task<ScriptState<T>> ContinueAsync(ScriptState previousState, CancellationToken cancellationToken = default(CancellationToken))
{
{
// The following validation and executor contruction may throw;
// do so synchronously so that the exception is not wrapped in the task.
if (previousState == null)
{
{
throw new ArgumentNullException(nameof(previousState));
}
}
if (previousState.Script == this)
{
{
// this state is already the output of running this script.
return Task.FromResult((ScriptState<T>)previousState);
}
}
var precedingExecutors = TryGetPrecedingExecutors(previousState.Script, cancellationToken);
if (precedingExecutors.IsDefault)
{
{
throw new ArgumentException(ScriptingResources.StartingStateIncompatible, nameof(previousState));
}
}
var currentExecutor = GetExecutor(cancellationToken);
ScriptExecutionState newExecutionState = previousState.ExecutionState.FreezeAndClone();
......@@ -447,22 +447,22 @@ private async Task<ScriptState<T>> RunSubmissionsAsync(ScriptExecutionState exec
private static void ValidateGlobals(object globals, Type globalsType)
{
if (globalsType != null)
{
{
if (globals == null)
{
{
throw new ArgumentException(ScriptingResources.ScriptRequiresGlobalVariables, nameof(globals));
}
}
var runtimeType = globals.GetType().GetTypeInfo();
var globalsTypeInfo = globalsType.GetTypeInfo();
if (!globalsTypeInfo.IsAssignableFrom(runtimeType))
{
{
throw new ArgumentException(string.Format(ScriptingResources.GlobalsNotAssignable, runtimeType, globalsTypeInfo), nameof(globals));
}
}
}
else if (globals != null)
{
{
throw new ArgumentException(ScriptingResources.GlobalVariablesWithoutGlobalType, nameof(globals));
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册