From 4c78737565b4109afedd55eb0a09feda493e298c Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sat, 26 Aug 2023 10:30:48 +0200 Subject: [PATCH 1/5] Foreach loops (#302) * Lexing done * Parsing done * Binding done * Lowering done * Flow analysis done * Update FlowAnalysisPass.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Update Binder_UntypedExpression.cs * Crash fix * Made member error not propagate * Added highlighting for new keywords * Added completion for the for keyword * Added inlay hint for iterator variables * Added renaming for iterator variables * Added vsce as dev dep * Made the YAML syntax highlight auto-copy * Crash fix * Update ConstraintSolver_Rules.cs * Better naming * Update Binder_UntypedExpression.cs * Made diag inherit on await * Update Binder_UntypedExpression.cs * Crash bugs * Update BclUsageTests.cs * Undid ripping out json * Update package-lock.json * Basic symbol resolution test * Update SymbolResolutionTests.cs * Fixes * Update LocalRewriter.cs --- .../EndToEnd/BclUsageTests.cs | 42 + .../Semantics/SymbolResolutionTests.cs | 123 ++ .../KeywordCompletionProvider.cs | 3 + .../Api/Syntax/SyntaxFactory.cs | 25 + src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs | 2 + src/Draco.Compiler/Api/Syntax/TokenKind.cs | 10 + src/Draco.Compiler/Internal/Binding/Binder.cs | 3 +- .../Internal/Binding/BinderCache.cs | 7 +- .../Internal/Binding/BinderFacts.cs | 3 +- .../Binding/Binder_BoundExpression.cs | 24 + .../Binding/Binder_UntypedExpression.cs | 168 +- .../Internal/Binding/Binder_UntypedLvalue.cs | 1 + .../Internal/Binding/ForLoopBinder.cs | 43 + .../Internal/Binding/ImportBinder.cs | 13 +- .../Internal/Binding/IncrementalBinder.cs | 4 +- .../Internal/Binding/LoopBinder.cs | 2 +- .../Binding/SymbolResolutionErrors.cs | 9 + .../Internal/BoundTree/BoundNodes.xml | 11 + .../Internal/FlowAnalysis/FlowAnalysisPass.cs | 17 + .../Internal/Lowering/LocalRewriter.cs | 65 + .../Internal/Solver/AwaitConstraint.cs | 11 + .../Internal/Solver/Constraint.cs | 10 +- .../Internal/Solver/ConstraintSolver.cs | 7 - .../Solver/ConstraintSolver_Constraints.cs | 9 +- .../Internal/Solver/ConstraintSolver_Rules.cs | 70 +- .../Internal/Solver/OverloadConstraint.cs | 7 + .../Symbols/Error/UndefinedMemberSymbol.cs | 9 + .../Symbols/Source/SourceLocalSymbol.cs | 2 +- .../Symbols/Source/UntypedLocalSymbol.cs | 16 +- src/Draco.Compiler/Internal/Syntax/Lexer.cs | 2 + src/Draco.Compiler/Internal/Syntax/Parser.cs | 28 +- src/Draco.Compiler/Internal/Syntax/Syntax.xml | 57 + .../Internal/UntypedTree/UntypedNodes.xml | 11 + src/Draco.Extension.VsCode/package-lock.json | 1907 ++++++++++++++++- src/Draco.Extension.VsCode/package.json | 1 + .../Capabilities/InlayHint.cs | 17 + .../Capabilities/Rename.cs | 8 +- .../draco.tmLanguage.json | 2 +- .../draco.tmLanguage.yml | 2 +- 39 files changed, 2659 insertions(+), 92 deletions(-) create mode 100644 src/Draco.Compiler/Internal/Binding/ForLoopBinder.cs diff --git a/src/Draco.Compiler.Tests/EndToEnd/BclUsageTests.cs b/src/Draco.Compiler.Tests/EndToEnd/BclUsageTests.cs index 6920d1b4a..a5d6327cc 100644 --- a/src/Draco.Compiler.Tests/EndToEnd/BclUsageTests.cs +++ b/src/Draco.Compiler.Tests/EndToEnd/BclUsageTests.cs @@ -342,4 +342,46 @@ public func foo(): string { Assert.Equal("1;2;3", result); } + + [Fact] + public void ForLoopSumming() + { + var assembly = Compile(""" + import System.Collections.Generic; + + public func sum(ns: IEnumerable): int32 { + var s = 0; + for (n in ns) s += n; + return s; + } + """); + var result = Invoke( + assembly: assembly, + methodName: "sum", + args: new[] { 1, 1, 2, 3, 5, 8, 13 }); + + Assert.Equal(33, result); + } + + [Fact] + public void ForLoopPrinting() + { + var assembly = Compile(""" + import System.Collections.Generic; + import System.Console; + + public func log(ns: IEnumerable) { + for (n in ns) Write(n); + } + """); + var stringWriter = new StringWriter(); + _ = Invoke( + assembly: assembly, + methodName: "log", + args: new[] { 1, 1, 2, 3, 5, 8, 13 }, + stdin: null, + stdout: stringWriter); + + Assert.Equal("11235813", stringWriter.ToString()); + } } diff --git a/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs b/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs index c7c351a0c..1c0e0c8ca 100644 --- a/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs +++ b/src/Draco.Compiler.Tests/Semantics/SymbolResolutionTests.cs @@ -4170,4 +4170,127 @@ public void InCodeModules() Assert.True(SymbolEqualityComparer.Default.Equals(moduleDefSymbol, moduleRefSymbol)); Assert.Empty(diags); } + + [Fact] + public void ForeachSequenceHasNoGetEnumerator() + { + // func main() { + // for (i in 0) {} + // } + + var main = SyntaxTree.Create(CompilationUnit( + FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody( + ExpressionStatement(ForExpression("i", LiteralExpression(0), BlockExpression())))))); + + // Act + var compilation = CreateCompilation(main); + + var semanticModel = compilation.GetSemanticModel(main); + + var diags = semanticModel.Diagnostics; + + // Assert + Assert.Single(diags); + AssertDiagnostic(diags, SymbolResolutionErrors.MemberNotFound); + } + + [Fact] + public void ForeachEnumeratorHasNoMoveNext() + { + // func foo() { + // for (i in Seq()) {} + // } + + var main = SyntaxTree.Create(CompilationUnit( + FunctionDeclaration( + "foo", + ParameterList(), + null, + BlockFunctionBody( + ExpressionStatement(ForExpression( + "i", + CallExpression(NameExpression("Seq")), + BlockExpression())))))); + + var fooRef = CompileCSharpToMetadataRef(""" + public class Seq + { + public TestEnumerator GetEnumerator() => default; + } + + public struct TestEnumerator + { + public int Current => 0; + } + """); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(main), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(fooRef) + .ToImmutableArray()); + + var semanticModel = compilation.GetSemanticModel(main); + + var diags = semanticModel.Diagnostics; + + // Assert + Assert.Single(diags); + AssertDiagnostic(diags, SymbolResolutionErrors.MemberNotFound); + } + + [Fact] + public void ForeachEnumeratorHasNoCurrentProperty() + { + // func foo() { + // for (i in Seq()) {} + // } + + var main = SyntaxTree.Create(CompilationUnit( + FunctionDeclaration( + "foo", + ParameterList(), + null, + BlockFunctionBody( + ExpressionStatement(ForExpression( + "i", + CallExpression(NameExpression("Seq")), + BlockExpression())))))); + + var fooRef = CompileCSharpToMetadataRef(""" + public class Seq + { + public TestEnumerator GetEnumerator() => default; + } + + public struct TestEnumerator + { + public int Current; + + public bool MoveNext() => true; + } + """); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(main), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(fooRef) + .ToImmutableArray()); + + var semanticModel = compilation.GetSemanticModel(main); + + var diags = semanticModel.Diagnostics; + + // Assert + Assert.Single(diags); + AssertDiagnostic(diags, SymbolResolutionErrors.NotGettableProperty); + } } diff --git a/src/Draco.Compiler/Api/CodeCompletion/KeywordCompletionProvider.cs b/src/Draco.Compiler/Api/CodeCompletion/KeywordCompletionProvider.cs index 7c0776a09..731620286 100644 --- a/src/Draco.Compiler/Api/CodeCompletion/KeywordCompletionProvider.cs +++ b/src/Draco.Compiler/Api/CodeCompletion/KeywordCompletionProvider.cs @@ -22,6 +22,9 @@ private static ImmutableArray GetDeclarationKeywords(SyntaxRange private static ImmutableArray GetExpressionKeywords(SyntaxRange range) => ImmutableArray.Create( CompletionItem.Create("if", range, CompletionKind.Keyword), CompletionItem.Create("while", range, CompletionKind.Keyword), + CompletionItem.Create("for", range, CompletionKind.Keyword), + // TODO: Is this the right context? + // CompletionItem.Create("in", range, CompletionKind.Keyword), CompletionItem.Create("return", range, CompletionKind.Keyword), CompletionItem.Create("goto", range, CompletionKind.Keyword), CompletionItem.Create("and", range, CompletionKind.Keyword), diff --git a/src/Draco.Compiler/Api/Syntax/SyntaxFactory.cs b/src/Draco.Compiler/Api/Syntax/SyntaxFactory.cs index f1cf68279..0f74a4d34 100644 --- a/src/Draco.Compiler/Api/Syntax/SyntaxFactory.cs +++ b/src/Draco.Compiler/Api/Syntax/SyntaxFactory.cs @@ -257,6 +257,29 @@ public static WhileExpressionSyntax WhileExpression( CloseParen, body); + public static ForExpressionSyntax ForExpression( + string iterator, + TypeSyntax? elementType, + ExpressionSyntax sequence, + ExpressionSyntax body) => ForExpression( + For, + OpenParen, + Name(iterator), + elementType is null ? null : TypeSpecifier(Colon, elementType), + In, + sequence, + CloseParen, + body); + + public static ForExpressionSyntax ForExpression( + string iterator, + ExpressionSyntax sequence, + ExpressionSyntax body) => ForExpression( + iterator, + null, + sequence, + body); + public static CallExpressionSyntax CallExpression( ExpressionSyntax called, IEnumerable args) => CallExpression( @@ -318,6 +341,8 @@ public static TextStringPartSyntax TextStringPart(string value) => public static SyntaxToken Return { get; } = MakeToken(TokenKind.KeywordReturn); public static SyntaxToken If { get; } = MakeToken(TokenKind.KeywordIf); public static SyntaxToken While { get; } = MakeToken(TokenKind.KeywordWhile); + public static SyntaxToken For { get; } = MakeToken(TokenKind.KeywordFor); + public static SyntaxToken In { get; } = MakeToken(TokenKind.KeywordIn); public static SyntaxToken Else { get; } = MakeToken(TokenKind.KeywordElse); public static SyntaxToken Var { get; } = MakeToken(TokenKind.KeywordVar); public static SyntaxToken Val { get; } = MakeToken(TokenKind.KeywordVal); diff --git a/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs b/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs index 5d704be4c..cbce84d21 100644 --- a/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs +++ b/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs @@ -18,11 +18,13 @@ public static class SyntaxFacts TokenKind.KeywordAnd => "and", TokenKind.KeywordElse => "else", TokenKind.KeywordFalse => "false", + TokenKind.KeywordFor => "for", TokenKind.KeywordFrom => "from", TokenKind.KeywordFunc => "func", TokenKind.KeywordGoto => "goto", TokenKind.KeywordIf => "if", TokenKind.KeywordImport => "import", + TokenKind.KeywordIn => "in", TokenKind.KeywordInternal => "internal", TokenKind.KeywordMod => "mod", TokenKind.KeywordModule => "module", diff --git a/src/Draco.Compiler/Api/Syntax/TokenKind.cs b/src/Draco.Compiler/Api/Syntax/TokenKind.cs index 56c468e53..01cf8db03 100644 --- a/src/Draco.Compiler/Api/Syntax/TokenKind.cs +++ b/src/Draco.Compiler/Api/Syntax/TokenKind.cs @@ -90,6 +90,11 @@ public enum TokenKind /// KeywordFalse, + /// + /// The keyword 'for'. + /// + KeywordFor, + /// /// The keyword 'from'. /// @@ -115,6 +120,11 @@ public enum TokenKind /// KeywordImport, + /// + /// The keyword 'in'. + /// + KeywordIn, + /// /// The keyword 'internal'. /// diff --git a/src/Draco.Compiler/Internal/Binding/Binder.cs b/src/Draco.Compiler/Internal/Binding/Binder.cs index 0c1a7819e..a7936e0b9 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder.cs @@ -134,7 +134,8 @@ public virtual (TypeSymbol Type, BoundExpression? Value) BindGlobal(SourceGlobal // We essentially use this to notify incremental binder that a left-hand side of a module or a type access // will be erased, won't be present in the bound tree. // Once we start modeling module member access without throwing it away, we can get rid of it. - internal virtual void BindModuleSyntaxToSymbol(SyntaxNode syntax, ModuleSymbol module) { } + // In addition, this is used by for-loops too to associate the iterator with its symbol + internal virtual void BindSyntaxToSymbol(SyntaxNode syntax, Symbol module) { } internal virtual void BindTypeSyntaxToSymbol(SyntaxNode syntax, TypeSymbol type) { } private FunctionSymbol GetGetterSymbol(SyntaxNode? syntax, PropertySymbol prop, DiagnosticBag diags) diff --git a/src/Draco.Compiler/Internal/Binding/BinderCache.cs b/src/Draco.Compiler/Internal/Binding/BinderCache.cs index 170f6950c..4e6845966 100644 --- a/src/Draco.Compiler/Internal/Binding/BinderCache.cs +++ b/src/Draco.Compiler/Internal/Binding/BinderCache.cs @@ -42,6 +42,7 @@ public Binder GetBinder(SyntaxNode syntax) FunctionBodySyntax body => this.BuildFunctionBodyBinder(body), BlockExpressionSyntax block => this.BuildLocalBinder(block), WhileExpressionSyntax loop => this.BuildLoopBinder(loop), + ForExpressionSyntax loop => this.BuildLoopBinder(loop), _ => throw new ArgumentOutOfRangeException(nameof(syntax)), }; @@ -106,7 +107,11 @@ private Binder BuildLoopBinder(SyntaxNode syntax) { Debug.Assert(syntax.Parent is not null); var parent = this.GetBinder(syntax.Parent); - return new LoopBinder(parent, syntax); + return syntax switch + { + ForExpressionSyntax @for => new ForLoopBinder(parent, @for), + _ => new LoopBinder(parent, syntax), + }; } /// diff --git a/src/Draco.Compiler/Internal/Binding/BinderFacts.cs b/src/Draco.Compiler/Internal/Binding/BinderFacts.cs index 35dd0bbbe..64cb2e4b2 100644 --- a/src/Draco.Compiler/Internal/Binding/BinderFacts.cs +++ b/src/Draco.Compiler/Internal/Binding/BinderFacts.cs @@ -119,7 +119,8 @@ or FunctionDeclarationSyntax or ModuleDeclarationSyntax or FunctionBodySyntax or BlockExpressionSyntax - or WhileExpressionSyntax; + or WhileExpressionSyntax + or ForExpressionSyntax; /// /// Checks, if a given syntax node defines a symbol. diff --git a/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs index ff9295050..3773fa67c 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs @@ -42,6 +42,7 @@ internal partial class Binder UntypedGotoExpression @goto => this.TypeGotoExpression(@goto, constraints, diagnostics), UntypedIfExpression @if => this.TypeIfExpression(@if, constraints, diagnostics), UntypedWhileExpression @while => this.TypeWhileExpression(@while, constraints, diagnostics), + UntypedForExpression @for => this.TypeForExpression(@for, constraints, diagnostics), UntypedCallExpression call => this.TypeCallExpression(call, constraints, diagnostics), UntypedIndirectCallExpression call => this.TypeIndirectCallExpression(call, constraints, diagnostics), UntypedAssignmentExpression assignment => this.TypeAssignmentExpression(assignment, constraints, diagnostics), @@ -182,6 +183,29 @@ private BoundExpression TypeWhileExpression(UntypedWhileExpression @while, Const return new BoundWhileExpression(@while.Syntax, typedCondition, typedThen, @while.ContinueLabel, @while.BreakLabel); } + private BoundExpression TypeForExpression(UntypedForExpression @for, ConstraintSolver constraints, DiagnosticBag diagnostics) + { + var iterator = constraints.GetTypedLocal(@for.Iterator, diagnostics); + + // NOTE: Hack, see the note above this method definition + var iteratorSyntax = (@for.Syntax as ForExpressionSyntax)?.Iterator; + if (iteratorSyntax is not null) this.BindSyntaxToSymbol(iteratorSyntax, iterator); + + var sequence = this.TypeExpression(@for.Sequence, constraints, diagnostics); + var then = this.TypeExpression(@for.Then, constraints, diagnostics); + + return new BoundForExpression( + @for.Syntax, + iterator, + sequence, + then, + @for.ContinueLabel, + @for.BreakLabel, + @for.GetEnumeratorMethod.Result, + @for.MoveNextMethod.Result, + @for.CurrentProperty.Result); + } + private BoundExpression TypeCallExpression(UntypedCallExpression call, ConstraintSolver constraints, DiagnosticBag diagnostics) { var receiver = call.Receiver is null ? null : this.TypeExpression(call.Receiver, constraints, diagnostics); diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs index 0ad5315b3..504a33678 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs @@ -11,6 +11,7 @@ using Draco.Compiler.Internal.Symbols.Source; using Draco.Compiler.Internal.Symbols.Synthetized; using Draco.Compiler.Internal.UntypedTree; +using Draco.Compiler.Internal.Utilities; namespace Draco.Compiler.Internal.Binding; @@ -37,6 +38,7 @@ internal partial class Binder ReturnExpressionSyntax @return => this.BindReturnExpression(@return, constraints, diagnostics), IfExpressionSyntax @if => this.BindIfExpression(@if, constraints, diagnostics), WhileExpressionSyntax @while => this.BindWhileExpression(@while, constraints, diagnostics), + ForExpressionSyntax @for => this.BindForExpression(@for, constraints, diagnostics), CallExpressionSyntax call => this.BindCallExpression(call, constraints, diagnostics), UnaryExpressionSyntax ury => this.BindUnaryExpression(ury, constraints, diagnostics), BinaryExpressionSyntax bin => this.BindBinaryExpression(bin, constraints, diagnostics), @@ -226,6 +228,142 @@ private UntypedExpression BindWhileExpression(WhileExpressionSyntax syntax, Cons return new UntypedWhileExpression(syntax, condition, then, continueLabel, breakLabel); } + private UntypedExpression BindForExpression(ForExpressionSyntax syntax, ConstraintSolver constraints, DiagnosticBag diagnostics) + { + var binder = this.GetBinder(syntax); + + // Resolve iterator + var iterator = binder.DeclaredSymbols + .OfType() + .Single(); + + var type = syntax.ElementType is null ? null : this.BindTypeToTypeSymbol(syntax.ElementType.Type, diagnostics); + var elementType = constraints.DeclareLocal(iterator, type); + + var sequence = binder.BindExpression(syntax.Sequence, constraints, diagnostics); + + var then = binder.BindExpression(syntax.Then, constraints, diagnostics); + // Body must be unit + constraints + .SameType(IntrinsicSymbols.Unit, then.TypeRequired) + .ConfigureDiagnostic(diag => diag + .WithLocation(ExtractValueSyntax(syntax.Then).Location)); + + // Resolve labels + var continueLabel = binder.DeclaredSymbols + .OfType() + .First(sym => sym.Name == "continue"); + var breakLabel = binder.DeclaredSymbols + .OfType() + .First(sym => sym.Name == "break"); + + // GetEnumerator + var getEnumeratorMethodsPromise = constraints.Member(sequence.TypeRequired, "GetEnumerator", out _); + getEnumeratorMethodsPromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.Sequence.Location)); + + var exprPromise = constraints.Await(getEnumeratorMethodsPromise, UntypedExpression () => + { + var getEnumeratorResult = getEnumeratorMethodsPromise.Result; + if (getEnumeratorResult.IsError) + { + constraints.UnifyAsserted(elementType, IntrinsicSymbols.ErrorType); + return new UntypedForExpression( + syntax, + iterator, + sequence, + then, + continueLabel, + breakLabel, + ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(0) as FunctionSymbol), + ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(0) as FunctionSymbol), + ConstraintPromise.FromResult(UndefinedMemberSymbol.Instance as Symbol)); + } + + // Look up the overload + var getEnumeratorFunctions = GetFunctions(getEnumeratorResult); + var getEnumeratorPromise = constraints.Overload( + "GetEnumerator", + getEnumeratorFunctions, + ImmutableArray.Empty, + out var enumeratorType); + getEnumeratorPromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.Sequence.Location)); + + // Look up MoveNext + var moveNextMethodsPromise = constraints.Member(enumeratorType, "MoveNext", out _); + moveNextMethodsPromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.Sequence.Location)); + + var moveNextPromise = constraints.Await(moveNextMethodsPromise, () => + { + var moveNextResult = moveNextMethodsPromise.Result; + + // Don't propagate errors + if (moveNextResult.IsError) + { + return ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(0) as FunctionSymbol); + } + + var moveNextFunctions = GetFunctions(moveNextResult); + + var moveNextPromise = constraints.Overload( + "MoveNext", + moveNextFunctions, + ImmutableArray.Empty, + out var moveNextReturnType); + moveNextPromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.Sequence.Location)); + + var moveNextReturnsBoolPromise = constraints.SameType(this.IntrinsicSymbols.Bool, moveNextReturnType); + moveNextReturnsBoolPromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.Sequence.Location)); + + return moveNextPromise; + }).Unwrap(); + + // Look up Current + var currentPromise = constraints.Member(enumeratorType, "Current", out var currentType); + currentPromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.Sequence.Location)); + + var elementAssignablePromise = constraints.Assignable(elementType, currentType); + elementAssignablePromise.ConfigureDiagnostic(diag => diag + .WithLocation(syntax.ElementType?.Location ?? syntax.Iterator.Location)); + + // Current needs to be a gettable property + constraints.Await(currentPromise, () => + { + var current = currentPromise.Result; + + // Don't propagate error + if (current.IsError) return default(Unit); + + if (current is not PropertySymbol propSymbol || propSymbol.Getter is null) + { + diagnostics.Add(Diagnostic.Create( + template: SymbolResolutionErrors.NotGettableProperty, + location: syntax.Sequence.Location, + formatArgs: current.Name)); + } + + return default; + }); + + return new UntypedForExpression( + syntax, + iterator, + sequence, + then, + continueLabel, + breakLabel, + getEnumeratorPromise, + moveNextPromise, + currentPromise); + }); + return new UntypedDelayedExpression(syntax, exprPromise, IntrinsicSymbols.Unit); + } + private UntypedExpression BindCallExpression(CallExpressionSyntax syntax, ConstraintSolver constraints, DiagnosticBag diagnostics) { var method = this.BindExpression(syntax.Function, constraints, diagnostics); @@ -261,6 +399,7 @@ private UntypedExpression BindCallExpression( // Simple overload // Resolve symbol overload var symbolPromise = constraints.Overload( + group.Functions[0].Name, group.Functions, args.Cast().ToImmutableArray(), out var resultType); @@ -283,13 +422,9 @@ private UntypedExpression BindCallExpression( if (members is FunctionSymbol or OverloadSymbol) { // Overloaded member call - var functions = members switch - { - OverloadSymbol o => o.Functions, - FunctionSymbol f => ImmutableArray.Create(f), - _ => throw new InvalidOperationException(), - }; + var functions = GetFunctions(members); var symbolPromise = constraints.Overload( + members.Name, functions, args.Cast().ToImmutableArray(), out var resultType); @@ -335,6 +470,7 @@ private UntypedExpression BindUnaryExpression(UnaryExpressionSyntax syntax, Cons // Resolve symbol overload var symbolPromise = constraints.Overload( + operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(operand), out var resultType); @@ -389,6 +525,7 @@ private UntypedExpression BindBinaryExpression(BinaryExpressionSyntax syntax, Co // Resolve symbol overload var symbolPromise = constraints.Overload( + operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(left, right), out var resultType); @@ -414,6 +551,7 @@ private UntypedExpression BindBinaryExpression(BinaryExpressionSyntax syntax, Co // Resolve symbol overload var symbolPromise = constraints.Overload( + operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(left, right), out var resultType); @@ -452,6 +590,7 @@ private UntypedComparison BindComparison( // NOTE: We know it must be bool, no need to pass it on to comparison // Resolve symbol overload var symbolPromise = constraints.Overload( + operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(prev, right), out var resultType); @@ -535,6 +674,7 @@ private UntypedExpression BindIndexExpression(IndexExpressionSyntax index, Const return ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(args.Length)); } var overloaded = constraints.Overload( + "operator[]", indexers, args.Cast().ToImmutableArray(), out var gotReturnType); @@ -595,12 +735,7 @@ private UntypedExpression BindGenericExpression(GenericExpressionSyntax syntax, { var members = member.Member.Result; // Search for all function members with the same number of generic parameters - var withSameNoParams = members switch - { - OverloadSymbol o => o.Functions, - FunctionSymbol f => ImmutableArray.Create(f), - _ => ImmutableArray.Empty, - }; + var withSameNoParams = GetFunctions(members); if (withSameNoParams.Length == 0) { // No generic functions with this number of parameters @@ -654,11 +789,11 @@ private UntypedExpression SymbolToExpression(SyntaxNode syntax, Symbol symbol, C case Symbol when symbol.IsError: return new UntypedReferenceErrorExpression(syntax, symbol); case ModuleSymbol module: - // NOTE: Hack, see the node above this method definition - this.BindModuleSyntaxToSymbol(syntax, module); + // NOTE: Hack, see the note above this method definition + this.BindSyntaxToSymbol(syntax, module); return new UntypedModuleExpression(syntax, module); case TypeSymbol type: - // NOTE: Hack, see the node above this method definition + // NOTE: Hack, see the note above this method definition this.BindTypeSyntaxToSymbol(syntax, type); return new UntypedTypeExpression(syntax, type); case ParameterSymbol param: @@ -685,13 +820,14 @@ private UntypedExpression SymbolToExpression(SyntaxNode syntax, Symbol symbol, C { FunctionSymbol f => ImmutableArray.Create(f), OverloadSymbol o => o.Functions, - _ => throw new ArgumentOutOfRangeException(nameof(symbol)), + _ => ImmutableArray.Empty, }; private static ExpressionSyntax ExtractValueSyntax(ExpressionSyntax syntax) => syntax switch { IfExpressionSyntax @if => ExtractValueSyntax(@if.Then), WhileExpressionSyntax @while => ExtractValueSyntax(@while.Then), + ForExpressionSyntax @for => ExtractValueSyntax(@for.Then), BlockExpressionSyntax block => block.Value is null ? block : ExtractValueSyntax(block.Value), _ => syntax, }; diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs index f786db0b8..042a8e267 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs @@ -133,6 +133,7 @@ private UntypedLvalue BindIndexLvalue(IndexExpressionSyntax index, ConstraintSol return ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(args.Length + 1)); } var overloaded = constraints.Overload( + "operator[]", indexers, args.Append(returnType as object).ToImmutableArray(), // NOTE: We don't care about the return type, this is an lvalue diff --git a/src/Draco.Compiler/Internal/Binding/ForLoopBinder.cs b/src/Draco.Compiler/Internal/Binding/ForLoopBinder.cs new file mode 100644 index 000000000..7d29341c7 --- /dev/null +++ b/src/Draco.Compiler/Internal/Binding/ForLoopBinder.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Draco.Compiler.Api.Syntax; +using Draco.Compiler.Internal.Symbols; +using Draco.Compiler.Internal.Symbols.Source; + +namespace Draco.Compiler.Internal.Binding; + +/// +/// Binds the iterator variable on top of . +/// +internal sealed class ForLoopBinder : LoopBinder +{ + /// + /// The introduced iterator variable. + /// + public UntypedLocalSymbol Iterator { get; } + + public override ForExpressionSyntax DeclaringSyntax { get; } + + public override IEnumerable DeclaredSymbols => + base.DeclaredSymbols.Append(this.Iterator); + + public ForLoopBinder(Binder parent, ForExpressionSyntax declaringSyntax) + : base(parent, declaringSyntax) + { + this.DeclaringSyntax = declaringSyntax; + this.Iterator = new( + this.ContainingSymbol!, + declaringSyntax.Iterator.Text, + isMutable: false, + declaringSyntax.Iterator); + } + + internal override void LookupLocal(LookupResult result, string name, ref LookupFlags flags, Predicate allowSymbol, SyntaxNode? currentReference) + { + if (flags.HasFlag(LookupFlags.DisallowLocals)) return; + + if (name == this.Iterator.Name && allowSymbol(this.Iterator)) result.Add(this.Iterator); + base.LookupLocal(result, name, ref flags, allowSymbol, currentReference); + } +} diff --git a/src/Draco.Compiler/Internal/Binding/ImportBinder.cs b/src/Draco.Compiler/Internal/Binding/ImportBinder.cs index 5825eee5d..3943881f4 100644 --- a/src/Draco.Compiler/Internal/Binding/ImportBinder.cs +++ b/src/Draco.Compiler/Internal/Binding/ImportBinder.cs @@ -109,8 +109,7 @@ Symbol BindImportPath(ImportPathSyntax syntax) // Don't cascade errors if (parent.IsError) { - var symbol = new UndefinedMemberSymbol(); - parts!.Add(new(mem, symbol)); + parts!.Add(new(mem, UndefinedMemberSymbol.Instance)); return parent; } // Look up in parent @@ -132,9 +131,8 @@ Symbol BindImportPath(ImportPathSyntax syntax) template: SymbolResolutionErrors.MemberNotFound, location: mem.Member.Location, formatArgs: new[] { mem.Member.Text, parent.Name })); - var symbol = new UndefinedMemberSymbol(); - parts!.Add(new(mem, symbol)); - return symbol; + parts!.Add(new(mem, UndefinedMemberSymbol.Instance)); + return UndefinedMemberSymbol.Instance; } else { @@ -144,9 +142,8 @@ Symbol BindImportPath(ImportPathSyntax syntax) location: mem.Location, formatArgs: mem.Member.Text)); // NOTE: For now this result is fine - var symbol = new UndefinedMemberSymbol(); - parts!.Add(new(mem, symbol)); - return symbol; + parts!.Add(new(mem, UndefinedMemberSymbol.Instance)); + return UndefinedMemberSymbol.Instance; } } default: diff --git a/src/Draco.Compiler/Internal/Binding/IncrementalBinder.cs b/src/Draco.Compiler/Internal/Binding/IncrementalBinder.cs index 6d29d2286..7b2a47c5a 100644 --- a/src/Draco.Compiler/Internal/Binding/IncrementalBinder.cs +++ b/src/Draco.Compiler/Internal/Binding/IncrementalBinder.cs @@ -84,8 +84,8 @@ internal override Symbol BindType(TypeSyntax syntax, DiagnosticBag diagnostics) this.BindSymbol(syntax, () => base.BindType(syntax, diagnostics)); // TODO: Hack - internal override void BindModuleSyntaxToSymbol(SyntaxNode syntax, Internal.Symbols.ModuleSymbol module) => - this.semanticModel.symbolMap[syntax] = module; + internal override void BindSyntaxToSymbol(SyntaxNode syntax, Internal.Symbols.Symbol symbol) => + this.semanticModel.symbolMap[syntax] = symbol; internal override void BindTypeSyntaxToSymbol(SyntaxNode syntax, Internal.Symbols.TypeSymbol type) { diff --git a/src/Draco.Compiler/Internal/Binding/LoopBinder.cs b/src/Draco.Compiler/Internal/Binding/LoopBinder.cs index f43458d3d..7fc00a63e 100644 --- a/src/Draco.Compiler/Internal/Binding/LoopBinder.cs +++ b/src/Draco.Compiler/Internal/Binding/LoopBinder.cs @@ -9,7 +9,7 @@ namespace Draco.Compiler.Internal.Binding; /// /// Binds the break and continue labels in the loop body. /// -internal sealed class LoopBinder : Binder +internal class LoopBinder : Binder { /// /// The break label. diff --git a/src/Draco.Compiler/Internal/Binding/SymbolResolutionErrors.cs b/src/Draco.Compiler/Internal/Binding/SymbolResolutionErrors.cs index 6a524062e..fc7526330 100644 --- a/src/Draco.Compiler/Internal/Binding/SymbolResolutionErrors.cs +++ b/src/Draco.Compiler/Internal/Binding/SymbolResolutionErrors.cs @@ -173,4 +173,13 @@ internal static class SymbolResolutionErrors severity: DiagnosticSeverity.Error, format: "the variadic parameter {0} must be last in the parameter list", code: Code(18)); + + /// + /// The member is not a gettable property. + /// + public static readonly DiagnosticTemplate NotGettableProperty = DiagnosticTemplate.Create( + title: "not a gettable property", + severity: DiagnosticSeverity.Error, + format: "the member {0} must be a gettable property", + code: Code(19)); } diff --git a/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml b/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml index 0c2c110c9..aa95b43cc 100644 --- a/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml +++ b/src/Draco.Compiler/Internal/BoundTree/BoundNodes.xml @@ -99,6 +99,17 @@ + + + + + + + + + + + diff --git a/src/Draco.Compiler/Internal/FlowAnalysis/FlowAnalysisPass.cs b/src/Draco.Compiler/Internal/FlowAnalysis/FlowAnalysisPass.cs index afd28b090..9e9fb0b3f 100644 --- a/src/Draco.Compiler/Internal/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Draco.Compiler/Internal/FlowAnalysis/FlowAnalysisPass.cs @@ -131,6 +131,7 @@ private void LoopHead(LabelSymbol continueLabel) this.labeledStates[continueLabel] = this.Clone(in this.State); } + // TODO: We might have a bug, we don't consider break labels private void LoopTail(LabelSymbol continueLabel) { var prevState = this.labeledStates[continueLabel]; @@ -176,6 +177,22 @@ public override void VisitWhileExpression(BoundWhileExpression node) this.State = breakState; } + public override void VisitForExpression(BoundForExpression node) + { + // First, the sequence is always evaluated + this.VisitExpression(node.Sequence); + // We join in with the continue label + this.LoopHead(node.ContinueLabel); + // Body does not necessarily run + var breakState = this.Clone(in this.State); + // We continue with the looping, run body + this.VisitExpression(node.Then); + // Loop back to continue + this.LoopTail(node.ContinueLabel); + // We continue with the break state + this.State = breakState; + } + public override void VisitLabelStatement(BoundLabelStatement node) { // Look up the previously saved label state diff --git a/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs b/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs index 75221eb53..92444094a 100644 --- a/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs +++ b/src/Draco.Compiler/Internal/Lowering/LocalRewriter.cs @@ -237,6 +237,71 @@ public override BoundNode VisitWhileExpression(BoundWhileExpression node) return result.Accept(this); } + public override BoundNode VisitForExpression(BoundForExpression node) + { + // TODO: Once we have try-finally and a way to do checked casts, fix this + // 1. Wrap in try-finally + // 2. Call Dispose in finally block, if enumerator is IDisposable + + // for (i in sequence) + // { + // body... + // } + // + // => + // + // { + // val enumerator = sequence.GetEnumerator(); + // while (enumerator.MoveNext()) { + // i = enumerator.Current; + // body... + // } + // } + // + // NOTE: For loops are desugared into while loops, + // which are then desugared again using the existing lowering step + // Because of this, we do not need to lower each individual member here, they will be lowered + // while rewriting the while loop + + var enumerator = new SynthetizedLocalSymbol(node.GetEnumeratorMethod.ReturnType, false); + + // NOTE: Checked during binding + var currentProp = (PropertySymbol)node.CurrentProperty; + if (currentProp.Getter is null) throw new InvalidOperationException(); + + var result = BlockExpression( + locals: ImmutableArray.Create(enumerator), + statements: ImmutableArray.Create( + ExpressionStatement(AssignmentExpression( + compoundOperator: null, + left: LocalLvalue(enumerator), + right: CallExpression( + receiver: node.Sequence, + method: node.GetEnumeratorMethod, + arguments: ImmutableArray.Empty))), + ExpressionStatement(WhileExpression( + condition: CallExpression( + receiver: LocalExpression(enumerator), + method: node.MoveNextMethod, + arguments: ImmutableArray.Empty), + then: BlockExpression( + locals: ImmutableArray.Create(node.Iterator), + statements: ImmutableArray.Create( + ExpressionStatement(AssignmentExpression( + compoundOperator: null, + left: LocalLvalue(node.Iterator), + right: PropertyGetExpression( + receiver: LocalExpression(enumerator), + getter: currentProp.Getter))), + ExpressionStatement(node.Then)), + value: BoundUnitExpression.Default), + continueLabel: node.ContinueLabel, + breakLabel: node.BreakLabel))), + value: BoundUnitExpression.Default); + // Desugaring the while-loop + return result.Accept(this); + } + public override BoundNode VisitRelationalExpression(BoundRelationalExpression node) { // In case there are only two operands, don't do any of the optimizations below diff --git a/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs b/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs index e50ffcb1f..6893d8717 100644 --- a/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs @@ -1,4 +1,5 @@ using System; +using Draco.Compiler.Api.Diagnostics; namespace Draco.Compiler.Internal.Solver; @@ -18,6 +19,16 @@ internal sealed class AwaitConstraint : Constraint /// public Func Map { get; } + public AwaitConstraint( + Func awaited, + Func map, + Diagnostic.Builder diagnostic) + : base(diagnostic) + { + this.Awaited = awaited; + this.Map = map; + } + public AwaitConstraint(Func awaited, Func map) { this.Awaited = awaited; diff --git a/src/Draco.Compiler/Internal/Solver/Constraint.cs b/src/Draco.Compiler/Internal/Solver/Constraint.cs index 4ff73d4c4..cf7baf6a3 100644 --- a/src/Draco.Compiler/Internal/Solver/Constraint.cs +++ b/src/Draco.Compiler/Internal/Solver/Constraint.cs @@ -10,11 +10,17 @@ internal abstract class Constraint : IConstraint { public IConstraintPromise Promise { get; } IConstraintPromise IConstraint.Promise => this.Promise; - public Diagnostic.Builder Diagnostic { get; } = new(); + public Diagnostic.Builder Diagnostic { get; } - protected Constraint() + protected Constraint(Diagnostic.Builder diagnostic) { this.Promise = ConstraintPromise.Create(this); + this.Diagnostic = diagnostic; + } + + protected Constraint() + : this(new()) + { } public override abstract string ToString(); diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver.cs index 849717be4..8ac0be07a 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver.cs @@ -93,13 +93,6 @@ private void CheckForIncompleteInference(DiagnosticBag diagnostics) // To avoid major trip-ups later, we resolve all constraints to some sentinel value this.FailRemainingRules(); - - // We also unify type variables with the error type - foreach (var typeVar in this.typeVariables) - { - var unwrapped = typeVar.Substitution; - if (unwrapped is TypeVariable unwrappedTv) this.UnifyAsserted(unwrappedTv, IntrinsicSymbols.UninferredType); - } } /// diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs index 8ab606ce3..480584541 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs @@ -138,17 +138,19 @@ public IConstraintPromise Call( /// /// Adds an overload constraint to the solver. /// + /// The function name the overload is created from. /// The functions to choose an overload from. /// The passed in arguments. /// The return type of the call. /// The promise for the resolved overload. public IConstraintPromise Overload( + string name, ImmutableArray functions, ImmutableArray args, out TypeSymbol returnType) { returnType = this.AllocateTypeVariable(); - var constraint = new OverloadConstraint(functions, args, returnType); + var constraint = new OverloadConstraint(name, functions, args, returnType); this.Add(constraint); return constraint.Promise; } @@ -173,7 +175,10 @@ public IConstraintPromise Await( } else { - var constraint = new AwaitConstraint(() => awaited.IsResolved, map); + var constraint = new AwaitConstraint( + () => awaited.IsResolved, + map, + awaited.Constraint.Diagnostic); this.Add(constraint); return constraint.Promise; } diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs index 1e01d7893..e0a552fe9 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs @@ -8,12 +8,13 @@ using Draco.Compiler.Internal.Symbols.Error; using Draco.Compiler.Internal.Symbols.Synthetized; using Draco.Compiler.Internal.UntypedTree; +using Draco.Compiler.Internal.Utilities; namespace Draco.Compiler.Internal.Solver; internal sealed partial class ConstraintSolver { - private bool ApplyRules(DiagnosticBag diagnostics) + private bool ApplyRules(DiagnosticBag? diagnostics) { if (this.TryDequeue(out var sameType)) { @@ -63,6 +64,12 @@ private bool ApplyRules(DiagnosticBag diagnostics) return true; } + if (this.TryDequeue>(out var wait5, w => w.Awaited())) + { + this.HandleRule(wait5); + return true; + } + foreach (var overload in this.Enumerate()) { this.HandleRule(overload, diagnostics); @@ -134,23 +141,21 @@ private bool ApplyRules(DiagnosticBag diagnostics) private void FailRemainingRules() { - foreach (var constraint in this.constraints) this.FailRemainingRule(constraint); - } + // We unify type variables with the error type + foreach (var typeVar in this.typeVariables) + { + var unwrapped = typeVar.Substitution; + if (unwrapped is TypeVariable unwrappedTv) this.UnifyAsserted(unwrappedTv, IntrinsicSymbols.UninferredType); + } - private void FailRemainingRule(IConstraint constraint) - { - switch (constraint) + while (this.constraints.Count > 0) { - case CallConstraint call: - this.FailRule(call); - break; - case OverloadConstraint overload: - this.FailRule(overload); - break; + // Apply rules once + if (!this.ApplyRules(null)) break; } } - private void HandleRule(SameTypeConstraint constraint, DiagnosticBag diagnostics) + private void HandleRule(SameTypeConstraint constraint, DiagnosticBag? diagnostics) { for (var i = 1; i < constraint.Types.Length; ++i) { @@ -169,7 +174,7 @@ private void HandleRule(SameTypeConstraint constraint, DiagnosticBag diagnostics constraint.Promise.Resolve(default); } - private void HandleRule(AssignableConstraint constraint, DiagnosticBag diagnostics) + private void HandleRule(AssignableConstraint constraint, DiagnosticBag? diagnostics) { if (!SymbolEqualityComparer.Default.IsBaseOf(constraint.TargetType, constraint.AssignedType)) { @@ -185,7 +190,7 @@ private void HandleRule(AssignableConstraint constraint, DiagnosticBag diagnosti constraint.Promise.Resolve(default); } - private void HandleRule(CommonTypeConstraint constraint, DiagnosticBag diagnostics) + private void HandleRule(CommonTypeConstraint constraint, DiagnosticBag? diagnostics) { foreach (var type in constraint.AlternativeTypes) { @@ -206,7 +211,7 @@ private void HandleRule(CommonTypeConstraint constraint, DiagnosticBag diagnosti constraint.Promise.Fail(default, diagnostics); } - private void HandleRule(MemberConstraint constraint, DiagnosticBag diagnostics) + private void HandleRule(MemberConstraint constraint, DiagnosticBag? diagnostics) { var accessed = constraint.Accessed.Substitution; // We can't advance on type variables @@ -215,6 +220,14 @@ private void HandleRule(MemberConstraint constraint, DiagnosticBag diagnostics) throw new InvalidOperationException("rule handling for member constraint called prematurely"); } + // Don't propagate type errors + if (accessed.IsError) + { + this.Unify(constraint.MemberType, IntrinsicSymbols.ErrorType); + constraint.Promise.Resolve(UndefinedMemberSymbol.Instance); + return; + } + // Not a type variable, we can look into members var membersWithName = accessed.InstanceMembers .Where(m => m.Name == constraint.MemberName) @@ -227,16 +240,22 @@ private void HandleRule(MemberConstraint constraint, DiagnosticBag diagnostics) .WithTemplate(SymbolResolutionErrors.MemberNotFound) .WithFormatArgs(constraint.MemberName, accessed); // We still provide a single error symbol - var errorSymbol = new UndefinedMemberSymbol(); this.UnifyAsserted(constraint.MemberType, IntrinsicSymbols.ErrorType); - constraint.Promise.Fail(errorSymbol, diagnostics); + constraint.Promise.Fail(UndefinedMemberSymbol.Instance, diagnostics); return; } if (membersWithName.Length == 1) { // One member, we know what type the member type is - this.UnifyAsserted(((ITypedSymbol)membersWithName[0]).Type, constraint.MemberType); + var memberType = ((ITypedSymbol)membersWithName[0]).Type; + var assignablePromise = this.Assignable(constraint.MemberType, memberType); + // TODO: This location config is horrible, we need that refactor SOON + if (constraint.Diagnostic.Location is not null) + { + assignablePromise.ConfigureDiagnostic(diag => diag + .WithLocation(constraint.Diagnostic.Location)); + } constraint.Promise.Resolve(membersWithName[0]); return; } @@ -267,9 +286,9 @@ private void HandleRule(AwaitConstraint constraint) constraint.Promise.Resolve(mappedValue); } - private void HandleRule(OverloadConstraint constraint, DiagnosticBag diagnostics) + private void HandleRule(OverloadConstraint constraint, DiagnosticBag? diagnostics) { - var functionName = constraint.Candidates[0].Name; + var functionName = constraint.Name; var functionsWithMatchingArgc = constraint.Candidates .Where(f => MatchesParameterCount(f, constraint.Arguments.Length)) .ToList(); @@ -358,7 +377,7 @@ private void HandleRule(OverloadConstraint constraint, DiagnosticBag diagnostics } } - private void HandleRule(CallConstraint constraint, DiagnosticBag diagnostics) + private void HandleRule(CallConstraint constraint, DiagnosticBag? diagnostics) { var called = constraint.CalledType.Substitution; // We can't advance on type variables @@ -432,13 +451,6 @@ private void HandleRule(CallConstraint constraint, DiagnosticBag diagnostics) } } - private void FailRule(OverloadConstraint constraint) - { - this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); - var errorSymbol = new NoOverloadFunctionSymbol(constraint.Arguments.Length); - constraint.Promise.Fail(errorSymbol, null); - } - private void FailRule(CallConstraint constraint) { this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); diff --git a/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs b/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs index 64c4cdc3c..32cbfb01e 100644 --- a/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs @@ -10,6 +10,11 @@ internal sealed class OverloadConstraint : Constraint { private readonly record struct Candidate(FunctionSymbol Symbol, CallScore Score); + /// + /// The function name. + /// + public string Name { get; } + /// /// The candidate functions to search among. /// @@ -26,10 +31,12 @@ internal sealed class OverloadConstraint : Constraint public TypeSymbol ReturnType { get; } public OverloadConstraint( + string name, ImmutableArray candidates, ImmutableArray arguments, TypeSymbol returnType) { + this.Name = name; this.Candidates = candidates; this.Arguments = arguments; this.ReturnType = returnType; diff --git a/src/Draco.Compiler/Internal/Symbols/Error/UndefinedMemberSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Error/UndefinedMemberSymbol.cs index 46af65446..c718658f6 100644 --- a/src/Draco.Compiler/Internal/Symbols/Error/UndefinedMemberSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Error/UndefinedMemberSymbol.cs @@ -7,6 +7,11 @@ namespace Draco.Compiler.Internal.Symbols.Error; /// internal sealed class UndefinedMemberSymbol : Symbol, ITypedSymbol, IMemberSymbol { + /// + /// A singleton instance to use. + /// + public static UndefinedMemberSymbol Instance { get; } = new(); + public override bool IsError => true; public override Symbol? ContainingSymbol => null; @@ -15,6 +20,10 @@ internal sealed class UndefinedMemberSymbol : Symbol, ITypedSymbol, IMemberSymbo public bool IsStatic => true; + private UndefinedMemberSymbol() + { + } + public override Api.Semantics.ISymbol ToApiSymbol() => new Api.Semantics.AnySymbol(this); public override void Accept(SymbolVisitor visitor) => throw new System.NotSupportedException(); diff --git a/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs index 33bc03bd5..41a71edbc 100644 --- a/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs @@ -13,7 +13,7 @@ internal sealed class SourceLocalSymbol : LocalSymbol, ISourceSymbol public override Symbol ContainingSymbol => this.untypedSymbol.ContainingSymbol; public override string Name => this.untypedSymbol.Name; - public override VariableDeclarationSyntax DeclaringSyntax => this.untypedSymbol.DeclaringSyntax; + public override SyntaxNode DeclaringSyntax => this.untypedSymbol.DeclaringSyntax; public override bool IsMutable => this.untypedSymbol.IsMutable; diff --git a/src/Draco.Compiler/Internal/Symbols/Source/UntypedLocalSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Source/UntypedLocalSymbol.cs index 05b3cae57..efc2ab2b4 100644 --- a/src/Draco.Compiler/Internal/Symbols/Source/UntypedLocalSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Source/UntypedLocalSymbol.cs @@ -11,16 +11,22 @@ namespace Draco.Compiler.Internal.Symbols.Source; internal sealed class UntypedLocalSymbol : Symbol, ISourceSymbol { public override Symbol ContainingSymbol { get; } - public override string Name => this.DeclaringSyntax.Name.Text; + public override string Name { get; } + public bool IsMutable { get; } - public override VariableDeclarationSyntax DeclaringSyntax { get; } + public override SyntaxNode DeclaringSyntax { get; } - public bool IsMutable => this.DeclaringSyntax.Keyword.Kind == TokenKind.KeywordVar; + public UntypedLocalSymbol(Symbol containingSymbol, string name, bool isMutable, SyntaxNode declaringSyntax) + { + this.ContainingSymbol = containingSymbol; + this.Name = name; + this.IsMutable = isMutable; + this.DeclaringSyntax = declaringSyntax; + } public UntypedLocalSymbol(Symbol containingSymbol, VariableDeclarationSyntax syntax) + : this(containingSymbol, syntax.Name.Text, syntax.Keyword.Kind == TokenKind.KeywordVar, syntax) { - this.ContainingSymbol = containingSymbol; - this.DeclaringSyntax = syntax; } public override ISymbol ToApiSymbol() => throw new NotSupportedException(); diff --git a/src/Draco.Compiler/Internal/Syntax/Lexer.cs b/src/Draco.Compiler/Internal/Syntax/Lexer.cs index de291a5e5..2729d9c20 100644 --- a/src/Draco.Compiler/Internal/Syntax/Lexer.cs +++ b/src/Draco.Compiler/Internal/Syntax/Lexer.cs @@ -322,11 +322,13 @@ Unit TakeWithText(TokenKind tokenKind, int length) var _ when ident.Span.SequenceEqual("and") => TokenKind.KeywordAnd, var _ when ident.Span.SequenceEqual("else") => TokenKind.KeywordElse, var _ when ident.Span.SequenceEqual("false") => TokenKind.KeywordFalse, + var _ when ident.Span.SequenceEqual("for") => TokenKind.KeywordFor, var _ when ident.Span.SequenceEqual("from") => TokenKind.KeywordFrom, var _ when ident.Span.SequenceEqual("func") => TokenKind.KeywordFunc, var _ when ident.Span.SequenceEqual("goto") => TokenKind.KeywordGoto, var _ when ident.Span.SequenceEqual("if") => TokenKind.KeywordIf, var _ when ident.Span.SequenceEqual("import") => TokenKind.KeywordImport, + var _ when ident.Span.SequenceEqual("in") => TokenKind.KeywordIn, var _ when ident.Span.SequenceEqual("internal") => TokenKind.KeywordInternal, var _ when ident.Span.SequenceEqual("mod") => TokenKind.KeywordMod, var _ when ident.Span.SequenceEqual("module") => TokenKind.KeywordModule, diff --git a/src/Draco.Compiler/Internal/Syntax/Parser.cs b/src/Draco.Compiler/Internal/Syntax/Parser.cs index 9bb4665ed..9064935b6 100644 --- a/src/Draco.Compiler/Internal/Syntax/Parser.cs +++ b/src/Draco.Compiler/Internal/Syntax/Parser.cs @@ -188,6 +188,7 @@ private ExpressionParserDelegate BinaryRight(params TokenKind[] operators) => le TokenKind.KeywordReturn, TokenKind.KeywordTrue, TokenKind.KeywordWhile, + TokenKind.KeywordFor, TokenKind.ParenOpen, TokenKind.CurlyOpen, TokenKind.BracketOpen, @@ -311,6 +312,7 @@ internal StatementSyntax ParseStatement(bool allowDecl) case TokenKind.CurlyOpen: case TokenKind.KeywordIf: case TokenKind.KeywordWhile: + case TokenKind.KeywordFor: { var expr = this.ParseControlFlowExpression(ControlFlowContext.Stmt); return new ExpressionStatementSyntax(expr, null); @@ -666,12 +668,14 @@ private ExpressionSyntax ParseControlFlowExpression(ControlFlowContext ctx) var peekKind = this.Peek(); Debug.Assert(peekKind is TokenKind.CurlyOpen or TokenKind.KeywordIf - or TokenKind.KeywordWhile); + or TokenKind.KeywordWhile + or TokenKind.KeywordFor); return peekKind switch { TokenKind.CurlyOpen => this.ParseBlockExpression(ctx), TokenKind.KeywordIf => this.ParseIfExpression(ctx), TokenKind.KeywordWhile => this.ParseWhileExpression(ctx), + TokenKind.KeywordFor => this.ParseForExpression(ctx), _ => throw new InvalidOperationException(), }; } @@ -738,6 +742,7 @@ private ParsedBlock ParseBlock(ControlFlowContext ctx) case TokenKind.CurlyOpen: case TokenKind.KeywordIf: case TokenKind.KeywordWhile: + case TokenKind.KeywordFor: { var expr = this.ParseControlFlowExpression(ctx); if (ctx == ControlFlowContext.Expr && this.Peek() == TokenKind.CurlyClose) @@ -833,6 +838,26 @@ private WhileExpressionSyntax ParseWhileExpression(ControlFlowContext ctx) return new(whileKeyword, openParen, condition, closeParen, body); } + /// + /// Parses a for-expression. + /// + /// The current context we are in. + /// The parsed . + private ForExpressionSyntax ParseForExpression(ControlFlowContext ctx) + { + // for (i: T in seq) { ... } + var forKeyword = this.Expect(TokenKind.KeywordFor); + var openParen = this.Expect(TokenKind.ParenOpen); + var iterator = this.Expect(TokenKind.Identifier); + TypeSpecifierSyntax? elementType = null; + if (this.Peek() == TokenKind.Colon) elementType = this.ParseTypeSpecifier(); + var inKeyword = this.Expect(TokenKind.KeywordIn); + var sequence = this.ParseExpression(); + var closeParen = this.Expect(TokenKind.ParenClose); + var body = this.ParseControlFlowBody(ctx); + return new(forKeyword, openParen, iterator, elementType, inKeyword, sequence, closeParen, body); + } + /// /// Parses an expression. /// @@ -1003,6 +1028,7 @@ private ExpressionSyntax ParseAtomExpression(int level) case TokenKind.CurlyOpen: case TokenKind.KeywordIf: case TokenKind.KeywordWhile: + case TokenKind.KeywordFor: return this.ParseControlFlowExpression(ControlFlowContext.Expr); default: { diff --git a/src/Draco.Compiler/Internal/Syntax/Syntax.xml b/src/Draco.Compiler/Internal/Syntax/Syntax.xml index 87424a0ea..a34baeb51 100644 --- a/src/Draco.Compiler/Internal/Syntax/Syntax.xml +++ b/src/Draco.Compiler/Internal/Syntax/Syntax.xml @@ -780,6 +780,63 @@ + + + A for-expression. + + + + + The keyword 'for'. + + + + + + + The open parenthesis before the iterator. + + + + + + + The iterator variable name. + + + + + + + The optional type of the sequence elements. + + + + + The keyword 'in'. + + + + + + + The expression of the sequence we are iterating over. + + + + + The close parenthesis after the iterator. + + + + + + + The portion evaluated repeatedly, substituting each element in the sequence for the iterator variable. + + + + A goto-expression. diff --git a/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml b/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml index 2e7effabb..440ddc156 100644 --- a/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml +++ b/src/Draco.Compiler/Internal/UntypedTree/UntypedNodes.xml @@ -73,6 +73,17 @@ + + + + + + + + + + + diff --git a/src/Draco.Extension.VsCode/package-lock.json b/src/Draco.Extension.VsCode/package-lock.json index 48fe97fa6..4cf90d5b3 100644 --- a/src/Draco.Extension.VsCode/package-lock.json +++ b/src/Draco.Extension.VsCode/package-lock.json @@ -18,6 +18,7 @@ "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", "@vscode/test-electron": "^2.1.5", + "@vscode/vsce": "^2.20.1", "copyfiles": "^2.4.1", "eslint": "^8.20.0", "glob": "^8.0.3", @@ -472,6 +473,143 @@ "node": ">=8.9.3" } }, + "node_modules/@vscode/vsce": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.20.1.tgz", + "integrity": "sha512-ilbvoqvR/1/zseRPBAzYR6aKqSJ+jvda4/BqIwOqTxajpvLtEpK3kMLs77+dJdrlygS+VrP7Yhad8j0ukyD96g==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^7.5.2", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@vscode/vsce/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@vscode/vsce/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@vscode/vsce/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@vscode/vsce/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/vsce/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -794,11 +932,42 @@ "node": ">=8" } }, + "node_modules/azure-devops-node-api": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", + "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "dev": true, + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -830,12 +999,45 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -891,6 +1093,40 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -915,6 +1151,19 @@ "node": ">=0.2.0" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -980,6 +1229,44 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1019,6 +1306,13 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "optional": true + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -1159,6 +1453,34 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1188,12 +1510,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -1227,6 +1585,61 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -1248,6 +1661,16 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", @@ -1261,6 +1684,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -1513,6 +1948,16 @@ "node": ">=0.8.x" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1577,6 +2022,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1645,6 +2099,13 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "optional": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1727,6 +2188,28 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "optional": true + }, "node_modules/glob": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", @@ -1853,6 +2336,30 @@ "node": ">=8" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1862,6 +2369,37 @@ "he": "bin/he" } }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -1889,6 +2427,27 @@ "node": ">= 6" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -1958,6 +2517,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -2158,6 +2724,24 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -2167,6 +2751,15 @@ "node": ">=0.10.0" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2180,6 +2773,15 @@ "node": ">= 0.8.0" } }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -2243,6 +2845,37 @@ "node": ">=10" } }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -2271,6 +2904,18 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2292,6 +2937,19 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2324,6 +2982,13 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "optional": true + }, "node_modules/mocha": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", @@ -2444,6 +3109,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "node_modules/nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", @@ -2456,6 +3127,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true, + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2474,6 +3152,26 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/node-abi": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.46.0.tgz", + "integrity": "sha512-LXvP3AqTIrtvH/jllXjkNVbYifpRbt9ThTtymSMSuHmhugQLAWr99QQFTm+ZRht9ziUvdGOgB+esme1C6iE6Lg==", + "dev": true, + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "optional": true + }, "node_modules/node-releases": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", @@ -2523,6 +3221,27 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2600,6 +3319,49 @@ "node": ">=6" } }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2642,6 +3404,12 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2724,6 +3492,33 @@ "node": ">=8" } }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2739,6 +3534,17 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2748,6 +3554,21 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2777,6 +3598,44 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -2978,6 +3837,12 @@ } ] }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "node_modules/schema-utils": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", @@ -2997,9 +3862,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3058,6 +3923,67 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -3172,6 +4098,51 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/terser": { "version": "5.17.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz", @@ -3249,6 +4220,18 @@ "xtend": "~4.0.1" } }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3310,6 +4293,28 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3334,6 +4339,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, "node_modules/typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", @@ -3347,6 +4363,18 @@ "node": ">=4.2.0" } }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -3409,6 +4437,12 @@ "punycode": "^2.1.0" } }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3610,9 +4644,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3647,6 +4681,28 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -3712,6 +4768,25 @@ "node": ">=10" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -4035,6 +5110,113 @@ "unzipper": "^0.10.11" } }, + "@vscode/vsce": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.20.1.tgz", + "integrity": "sha512-ilbvoqvR/1/zseRPBAzYR6aKqSJ+jvda4/BqIwOqTxajpvLtEpK3kMLs77+dJdrlygS+VrP7Yhad8j0ukyD96g==", + "dev": true, + "requires": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^7.5.2", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -4307,11 +5489,28 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "azure-devops-node-api": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", + "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "dev": true, + "requires": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "optional": true + }, "big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -4334,12 +5533,44 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "optional": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4376,6 +5607,23 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "optional": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4394,6 +5642,16 @@ "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", "dev": true }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -4431,6 +5689,35 @@ "supports-color": "^7.1.0" } }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -4458,6 +5745,13 @@ } } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "optional": true + }, "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -4572,6 +5866,25 @@ "which": "^2.0.1" } }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4587,12 +5900,36 @@ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "optional": true, + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true, + "optional": true + }, "diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -4617,6 +5954,43 @@ "esutils": "^2.0.2" } }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -4638,6 +6012,16 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "optional": true, + "requires": { + "once": "^1.4.0" + } + }, "enhanced-resolve": { "version": "5.14.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", @@ -4648,6 +6032,12 @@ "tapable": "^2.2.0" } }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, "envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -4833,6 +6223,13 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "optional": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4890,6 +6287,15 @@ "reusify": "^1.0.4" } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4940,6 +6346,13 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "optional": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5002,6 +6415,25 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "optional": true + }, "glob": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", @@ -5100,12 +6532,45 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -5127,6 +6592,13 @@ "debug": "4" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "optional": true + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -5175,6 +6647,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, "interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -5326,12 +6805,35 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5342,6 +6844,15 @@ "type-check": "~0.4.0" } }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -5387,6 +6898,33 @@ "yallist": "^4.0.0" } }, + "markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5409,6 +6947,12 @@ "picomatch": "^2.3.1" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -5424,6 +6968,13 @@ "mime-db": "1.52.0" } }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "optional": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5447,6 +6998,13 @@ "minimist": "^1.2.6" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "optional": true + }, "mocha": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", @@ -5544,12 +7102,25 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true, + "optional": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5568,6 +7139,23 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node-abi": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.46.0.tgz", + "integrity": "sha512-LXvP3AqTIrtvH/jllXjkNVbYifpRbt9ThTtymSMSuHmhugQLAWr99QQFTm+ZRht9ziUvdGOgB+esme1C6iE6Lg==", + "dev": true, + "optional": true, + "requires": { + "semver": "^7.3.5" + } + }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "optional": true + }, "node-releases": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", @@ -5616,6 +7204,21 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5672,6 +7275,42 @@ "callsites": "^3.0.0" } }, + "parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "requires": { + "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5702,6 +7341,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -5762,6 +7407,27 @@ } } }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5774,12 +7440,32 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "optional": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5795,6 +7481,37 @@ "safe-buffer": "^5.1.0" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "optional": true + } + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -5928,6 +7645,12 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "schema-utils": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", @@ -5940,9 +7663,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -5986,6 +7709,36 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "optional": true + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "optional": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6072,6 +7825,47 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "optional": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "optional": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "terser": { "version": "5.17.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.3.tgz", @@ -6124,6 +7918,15 @@ "xtend": "~4.0.1" } }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6166,6 +7969,22 @@ "tslib": "^1.8.1" } }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6181,12 +8000,35 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "requires": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, "typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "dev": true }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, "untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", @@ -6230,6 +8072,12 @@ "punycode": "^2.1.0" } }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6367,9 +8215,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "workerpool": { @@ -6395,6 +8243,22 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -6445,6 +8309,25 @@ "is-plain-obj": "^2.1.0" } }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/src/Draco.Extension.VsCode/package.json b/src/Draco.Extension.VsCode/package.json index 8c9576ced..1c19794a9 100644 --- a/src/Draco.Extension.VsCode/package.json +++ b/src/Draco.Extension.VsCode/package.json @@ -203,6 +203,7 @@ "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", "@vscode/test-electron": "^2.1.5", + "@vscode/vsce": "^2.20.1", "copyfiles": "^2.4.1", "eslint": "^8.20.0", "glob": "^8.0.3", diff --git a/src/Draco.LanguageServer/Capabilities/InlayHint.cs b/src/Draco.LanguageServer/Capabilities/InlayHint.cs index e4066b6bd..e62f42c53 100644 --- a/src/Draco.LanguageServer/Capabilities/InlayHint.cs +++ b/src/Draco.LanguageServer/Capabilities/InlayHint.cs @@ -51,6 +51,23 @@ public Task> InlayHintAsync(InlayHintParams param, Cancellation Label = $": {varType}", }); } + else if (config.VariableTypes && node is ForExpressionSyntax @for) + { + if (@for.ElementType is not null) continue; + + var symbol = semanticModel.GetDeclaredSymbol(@for.Iterator); + if (symbol is not IVariableSymbol varSymbol) continue; + + var varType = varSymbol.Type; + var position = @for.Iterator.Range.End; + + inlayHints.Add(new InlayHint() + { + Position = Translator.ToLsp(position), + Kind = InlayHintKind.Type, + Label = $": {varType}", + }); + } else if (config.ParameterNames && node is CallExpressionSyntax call) { var symbol = semanticModel.GetReferencedSymbol(call.Function); diff --git a/src/Draco.LanguageServer/Capabilities/Rename.cs b/src/Draco.LanguageServer/Capabilities/Rename.cs index 46aeb25ec..88303988a 100644 --- a/src/Draco.LanguageServer/Capabilities/Rename.cs +++ b/src/Draco.LanguageServer/Capabilities/Rename.cs @@ -29,8 +29,12 @@ internal partial class DracoLanguageServer : IRename var semanticModel = compilation.GetSemanticModel(syntaxTree); var cursorPosition = Translator.ToCompiler(param.Position); + // TODO: Consider adding an API that allows for right-inclusive subtree iteration + var cursorRange = cursorPosition.Column == 0 + ? new SyntaxRange(cursorPosition, 1) + : new SyntaxRange(new SyntaxPosition(Line: cursorPosition.Line, Column: cursorPosition.Column - 1), 1); var referencedSymbol = syntaxTree - .TraverseSubtreesAtPosition(cursorPosition) + .TraverseSubtreesIntersectingRange(cursorRange) .Select(symbol => semanticModel.GetReferencedSymbol(symbol) ?? semanticModel.GetDeclaredSymbol(symbol)) .LastOrDefault(symbol => symbol is not null); if (referencedSymbol is null) return Task.FromResult(null); @@ -93,6 +97,8 @@ private static IEnumerable FindAllAppearances( NameExpressionSyntax n => RenameToken(n.Name, name), NameTypeSyntax n => RenameToken(n.Name, name), NameLabelSyntax n => RenameToken(n.Name, name), + SyntaxToken t when t.Parent is ForExpressionSyntax @for + && @for.Iterator == t => RenameToken(t, name), _ => throw new ArgumentOutOfRangeException(nameof(original)), }; diff --git a/src/Draco.SyntaxHighlighting/draco.tmLanguage.json b/src/Draco.SyntaxHighlighting/draco.tmLanguage.json index 77713f0ee..4e493e0f0 100644 --- a/src/Draco.SyntaxHighlighting/draco.tmLanguage.json +++ b/src/Draco.SyntaxHighlighting/draco.tmLanguage.json @@ -277,7 +277,7 @@ }, { "name": "keyword.control.draco", - "match": "\\b(if|else|while|return|goto)\\b" + "match": "\\b(if|else|while|for|in|return|goto)\\b" }, { "include": "#call-expression" diff --git a/src/Draco.SyntaxHighlighting/draco.tmLanguage.yml b/src/Draco.SyntaxHighlighting/draco.tmLanguage.yml index e510a3fe5..3d15abe80 100644 --- a/src/Draco.SyntaxHighlighting/draco.tmLanguage.yml +++ b/src/Draco.SyntaxHighlighting/draco.tmLanguage.yml @@ -139,7 +139,7 @@ repository: match: '[><=!]=?' # Control keywords that build up expressions - name: keyword.control.draco - match: \b(if|else|while|return|goto)\b + match: \b(if|else|while|for|in|return|goto)\b - include: '#call-expression' # Variable name - name: variable.other.draco From 41ed3828867cd4febdbda5da093902e24a4a0ec1 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Tue, 29 Aug 2023 20:44:19 +0200 Subject: [PATCH 2/5] Constraint locators (#314) * Basic type and ripped out old API * More changes * Provided ctor args * Update ConstraintLocator.cs * Update AwaitConstraint.cs * Removed crud * Update Diagnostic_Builder.cs * MOOOAR * Update Constraint.cs * Update ConstraintSolver_Rules.cs * Update ConstraintSolver_Constraints.cs * Update ConstraintSolver_Constraints.cs * Update Binder_UntypedExpression.cs * Lotta fixes * Compiles * Added util for locator * Update Binder_UntypedExpression.cs * Cleanup --- .../Api/Diagnostics/Diagnostic_Builder.cs | 10 + src/Draco.Compiler/Internal/Binding/Binder.cs | 5 +- .../Internal/Binding/Binder_UntypedCommon.cs | 8 +- .../Binding/Binder_UntypedExpression.cs | 177 +++++++----------- .../Internal/Binding/Binder_UntypedLvalue.cs | 26 +-- .../Binding/Binder_UntypedStatement.cs | 5 +- .../Internal/Solver/AssignableConstraint.cs | 6 +- .../Internal/Solver/AwaitConstraint.cs | 11 +- .../Internal/Solver/CallConstraint.cs | 4 +- .../Internal/Solver/CommonTypeConstraint.cs | 6 +- .../Internal/Solver/Constraint.cs | 14 +- .../Internal/Solver/ConstraintLocator.cs | 116 ++++++++++++ .../Internal/Solver/ConstraintPromise.cs | 36 +--- .../Solver/ConstraintSolver_Constraints.cs | 73 ++++++-- .../Internal/Solver/ConstraintSolver_Rules.cs | 86 ++++----- .../Internal/Solver/ConstraintSolver_Utils.cs | 9 +- .../Internal/Solver/IConstraint.cs | 6 +- .../Internal/Solver/IConstraintPromise.cs | 19 +- .../Internal/Solver/MemberConstraint.cs | 7 +- .../Internal/Solver/OverloadConstraint.cs | 4 +- .../Internal/Solver/SameTypeConstraint.cs | 5 +- 21 files changed, 354 insertions(+), 279 deletions(-) create mode 100644 src/Draco.Compiler/Internal/Solver/ConstraintLocator.cs diff --git a/src/Draco.Compiler/Api/Diagnostics/Diagnostic_Builder.cs b/src/Draco.Compiler/Api/Diagnostics/Diagnostic_Builder.cs index 121d1136b..4166f0217 100644 --- a/src/Draco.Compiler/Api/Diagnostics/Diagnostic_Builder.cs +++ b/src/Draco.Compiler/Api/Diagnostics/Diagnostic_Builder.cs @@ -6,6 +6,12 @@ namespace Draco.Compiler.Api.Diagnostics; public sealed partial class Diagnostic { + /// + /// Constructs a new builder for diagnostics. + /// + /// A new, empty diagnostic builder. + public static Builder CreateBuilder() => new(); + /// /// A builder type for . /// @@ -16,6 +22,10 @@ public sealed class Builder public Location? Location { get; private set; } public ImmutableArray.Builder? RelatedInformation { get; private set; } + internal Builder() + { + } + /// /// Attempts to build a , if at least is filled. /// diff --git a/src/Draco.Compiler/Internal/Binding/Binder.cs b/src/Draco.Compiler/Internal/Binding/Binder.cs index a7936e0b9..8f74caf2e 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder.cs @@ -100,10 +100,7 @@ public virtual (TypeSymbol Type, BoundExpression? Value) BindGlobal(SourceGlobal // Add assignability constraint, if needed if (untypedValue is not null) { - constraints - .Assignable(declaredType, untypedValue.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(global.DeclaringSyntax.Value!.Value.Location)); + constraints.Assignable(declaredType, untypedValue.TypeRequired, global.DeclaringSyntax.Value!.Value); } // Solve diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedCommon.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedCommon.cs index 9c81f2785..2d7eb294f 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedCommon.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedCommon.cs @@ -14,10 +14,10 @@ protected void ConstraintReturnType(SyntaxNode returnSyntax, UntypedExpression r var containingFunction = (FunctionSymbol?)this.ContainingSymbol; Debug.Assert(containingFunction is not null); var returnTypeSyntax = (containingFunction as SourceFunctionSymbol)?.DeclaringSyntax?.ReturnType?.Type; - constraints - .Assignable(containingFunction.ReturnType, returnValue.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(returnSyntax.Location) + constraints.Assignable( + containingFunction.ReturnType, + returnValue.TypeRequired, + ConstraintLocator.Syntax(returnSyntax) .WithRelatedInformation( format: "return type declared to be {0}", formatArgs: containingFunction.ReturnType, diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs index 504a33678..753818f16 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs @@ -167,10 +167,7 @@ private UntypedExpression BindIfExpression(IfExpressionSyntax syntax, Constraint { var condition = this.BindExpression(syntax.Condition, constraints, diagnostics); // Condition must be bool - constraints - .SameType(this.IntrinsicSymbols.Bool, condition.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + constraints.SameType(this.IntrinsicSymbols.Bool, condition.TypeRequired, syntax); var then = this.BindExpression(syntax.Then, constraints, diagnostics); var @else = syntax.Else is null @@ -179,22 +176,20 @@ private UntypedExpression BindIfExpression(IfExpressionSyntax syntax, Constraint // Then and else must be compatible types var resultType = constraints.AllocateTypeVariable(); - constraints - .CommonType(resultType, ImmutableArray.Create(then.TypeRequired, @else.TypeRequired)) - .ConfigureDiagnostic(diag => - { - // The location will point at the else value, assuming that the latter expression is - // the offending one - // If there is no else clause, we just point at the then clause - diag.WithLocation(syntax.Else is null - ? ExtractValueSyntax(syntax.Then).Location - : ExtractValueSyntax(syntax.Else.Expression).Location); - // If there is an else clause, we annotate the then clause as related info - diag.WithRelatedInformation( + constraints.CommonType( + resultType, + ImmutableArray.Create(then.TypeRequired, @else.TypeRequired), + // The location will point at the else value, assuming that the latter expression is + // the offending one + // If there is no else clause, we just point at the then clause + ConstraintLocator.Syntax(syntax.Else is null + ? ExtractValueSyntax(syntax.Then) + : ExtractValueSyntax(syntax.Else.Expression)) + .WithRelatedInformation( format: "the other branch is inferred to be {0}", formatArgs: then.TypeRequired, - location: ExtractValueSyntax(syntax.Then).Location); - }); + // If there is an else clause, we annotate the then clause as related info + location: ExtractValueSyntax(syntax.Then).Location)); return new UntypedIfExpression(syntax, condition, then, @else, resultType); } @@ -205,17 +200,11 @@ private UntypedExpression BindWhileExpression(WhileExpressionSyntax syntax, Cons var condition = binder.BindExpression(syntax.Condition, constraints, diagnostics); // Condition must be bool - constraints - .SameType(this.IntrinsicSymbols.Bool, condition.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + constraints.SameType(this.IntrinsicSymbols.Bool, condition.TypeRequired, syntax); var then = binder.BindExpression(syntax.Then, constraints, diagnostics); // Body must be unit - constraints - .SameType(IntrinsicSymbols.Unit, then.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(ExtractValueSyntax(syntax.Then).Location)); + constraints.SameType(IntrinsicSymbols.Unit, then.TypeRequired, ExtractValueSyntax(syntax.Then)); // Resolve labels var continueLabel = binder.DeclaredSymbols @@ -244,10 +233,7 @@ private UntypedExpression BindForExpression(ForExpressionSyntax syntax, Constrai var then = binder.BindExpression(syntax.Then, constraints, diagnostics); // Body must be unit - constraints - .SameType(IntrinsicSymbols.Unit, then.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(ExtractValueSyntax(syntax.Then).Location)); + constraints.SameType(IntrinsicSymbols.Unit, then.TypeRequired, ExtractValueSyntax(syntax.Then)); // Resolve labels var continueLabel = binder.DeclaredSymbols @@ -258,9 +244,7 @@ private UntypedExpression BindForExpression(ForExpressionSyntax syntax, Constrai .First(sym => sym.Name == "break"); // GetEnumerator - var getEnumeratorMethodsPromise = constraints.Member(sequence.TypeRequired, "GetEnumerator", out _); - getEnumeratorMethodsPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Sequence.Location)); + var getEnumeratorMethodsPromise = constraints.Member(sequence.TypeRequired, "GetEnumerator", out _, syntax.Sequence); var exprPromise = constraints.Await(getEnumeratorMethodsPromise, UntypedExpression () => { @@ -286,14 +270,11 @@ private UntypedExpression BindForExpression(ForExpressionSyntax syntax, Constrai "GetEnumerator", getEnumeratorFunctions, ImmutableArray.Empty, - out var enumeratorType); - getEnumeratorPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Sequence.Location)); + out var enumeratorType, + syntax.Sequence); // Look up MoveNext - var moveNextMethodsPromise = constraints.Member(enumeratorType, "MoveNext", out _); - moveNextMethodsPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Sequence.Location)); + var moveNextMethodsPromise = constraints.Member(enumeratorType, "MoveNext", out _, syntax.Sequence); var moveNextPromise = constraints.Await(moveNextMethodsPromise, () => { @@ -311,25 +292,28 @@ private UntypedExpression BindForExpression(ForExpressionSyntax syntax, Constrai "MoveNext", moveNextFunctions, ImmutableArray.Empty, - out var moveNextReturnType); - moveNextPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Sequence.Location)); + out var moveNextReturnType, + syntax.Sequence); - var moveNextReturnsBoolPromise = constraints.SameType(this.IntrinsicSymbols.Bool, moveNextReturnType); - moveNextReturnsBoolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Sequence.Location)); + var moveNextReturnsBoolPromise = constraints.SameType( + this.IntrinsicSymbols.Bool, + moveNextReturnType, + syntax.Sequence); return moveNextPromise; }).Unwrap(); // Look up Current - var currentPromise = constraints.Member(enumeratorType, "Current", out var currentType); - currentPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Sequence.Location)); + var currentPromise = constraints.Member( + enumeratorType, + "Current", + out var currentType, + syntax.Sequence); - var elementAssignablePromise = constraints.Assignable(elementType, currentType); - elementAssignablePromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.ElementType?.Location ?? syntax.Iterator.Location)); + var elementAssignablePromise = constraints.Assignable( + elementType, + currentType, + syntax.ElementType as SyntaxNode ?? syntax.Iterator); // Current needs to be a gettable property constraints.Await(currentPromise, () => @@ -402,9 +386,8 @@ private UntypedExpression BindCallExpression( group.Functions[0].Name, group.Functions, args.Cast().ToImmutableArray(), - out var resultType); - symbolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Function.Location)); + out var resultType, + syntax.Function); return new UntypedCallExpression(syntax, null, symbolPromise, args, resultType); } @@ -427,9 +410,8 @@ private UntypedExpression BindCallExpression( members.Name, functions, args.Cast().ToImmutableArray(), - out var resultType); - symbolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Function.Location)); + out var resultType, + syntax.Function); constraints.UnifyAsserted(resultType, promisedType); return new UntypedCallExpression(syntax, mem.Accessed, symbolPromise, args, resultType); @@ -439,9 +421,8 @@ private UntypedExpression BindCallExpression( var callPromise = constraints.Call( method.TypeRequired, args.Cast().ToImmutableArray(), - out var resultType); - callPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + out var resultType, + syntax); constraints.UnifyAsserted(resultType, promisedType); return new UntypedIndirectCallExpression(syntax, mem, args, resultType); @@ -454,9 +435,8 @@ private UntypedExpression BindCallExpression( var callPromise = constraints.Call( method.TypeRequired, args.Cast().ToImmutableArray(), - out var resultType); - callPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + out var resultType, + syntax); return new UntypedIndirectCallExpression(syntax, method, args, resultType); } } @@ -473,9 +453,8 @@ private UntypedExpression BindUnaryExpression(UnaryExpressionSyntax syntax, Cons operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(operand), - out var resultType); - symbolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Operator.Location)); + out var resultType, + syntax.Operator); return new UntypedUnaryExpression(syntax, symbolPromise, operand, resultType); } @@ -488,10 +467,7 @@ private UntypedExpression BindBinaryExpression(BinaryExpressionSyntax syntax, Co var right = this.BindExpression(syntax.Right, constraints, diagnostics); // Right must be assignable to left - constraints - .Assignable(left.Type, right.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + constraints.Assignable(left.Type, right.TypeRequired, syntax); return new UntypedAssignmentExpression(syntax, null, left, right); } @@ -501,14 +477,8 @@ private UntypedExpression BindBinaryExpression(BinaryExpressionSyntax syntax, Co var right = this.BindExpression(syntax.Right, constraints, diagnostics); // Both left and right must be bool - constraints - .SameType(this.IntrinsicSymbols.Bool, left.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Left.Location)); - constraints - .SameType(this.IntrinsicSymbols.Bool, right.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Right.Location)); + constraints.SameType(this.IntrinsicSymbols.Bool, left.TypeRequired, syntax.Left); + constraints.SameType(this.IntrinsicSymbols.Bool, right.TypeRequired, syntax.Right); return syntax.Operator.Kind == TokenKind.KeywordAnd ? new UntypedAndExpression(syntax, left, right) @@ -528,16 +498,12 @@ private UntypedExpression BindBinaryExpression(BinaryExpressionSyntax syntax, Co operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(left, right), - out var resultType); - symbolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Operator.Location)); + out var resultType, + syntax.Operator); // The result of the binary operator must be assignable to the left-hand side // For example, a + b in the form of a += b means that a + b has to result in a type // that is assignable to a, hence the extra constraint - constraints - .Assignable(left.Type, resultType) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + constraints.Assignable(left.Type, resultType, syntax); return new UntypedAssignmentExpression(syntax, symbolPromise, left, right); } @@ -554,9 +520,8 @@ private UntypedExpression BindBinaryExpression(BinaryExpressionSyntax syntax, Co operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(left, right), - out var resultType); - symbolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Operator.Location)); + out var resultType, + syntax.Operator); return new UntypedBinaryExpression(syntax, symbolPromise, left, right, resultType); } @@ -593,14 +558,10 @@ private UntypedComparison BindComparison( operatorName, GetFunctions(operatorSymbol), ImmutableArray.Create(prev, right), - out var resultType); - symbolPromise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Operator.Location)); + out var resultType, + syntax.Operator); // For safety, we assume it has to be bool - constraints - .SameType(this.IntrinsicSymbols.Bool, resultType) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Operator.Location)); + constraints.SameType(this.IntrinsicSymbols.Bool, resultType, syntax.Operator); return new UntypedComparison(syntax, symbolPromise, right); } @@ -636,21 +597,19 @@ private UntypedExpression BindMemberExpression(MemberExpressionSyntax syntax, Co else { // Value, add constraint - var promise = constraints.Member(left.TypeRequired, memberName, out var memberType); - promise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + var promise = constraints.Member(left.TypeRequired, memberName, out var memberType, syntax); return new UntypedMemberExpression(syntax, left, promise, memberType); } } - private UntypedExpression BindIndexExpression(IndexExpressionSyntax index, ConstraintSolver constraints, DiagnosticBag diagnostics) + private UntypedExpression BindIndexExpression(IndexExpressionSyntax syntax, ConstraintSolver constraints, DiagnosticBag diagnostics) { - var receiver = this.BindExpression(index.Indexed, constraints, diagnostics); + var receiver = this.BindExpression(syntax.Indexed, constraints, diagnostics); if (receiver is UntypedReferenceErrorExpression err) { - return new UntypedReferenceErrorExpression(index, err.Symbol); + return new UntypedReferenceErrorExpression(syntax, err.Symbol); } - var args = index.IndexList.Values.Select(x => this.BindExpression(x, constraints, diagnostics)).ToImmutableArray(); + var args = syntax.IndexList.Values.Select(x => this.BindExpression(x, constraints, diagnostics)).ToImmutableArray(); var returnType = constraints.AllocateTypeVariable(); var promise = constraints.Substituted(receiver.TypeRequired, () => { @@ -668,7 +627,7 @@ private UntypedExpression BindIndexExpression(IndexExpressionSyntax index, Const { diagnostics.Add(Diagnostic.Create( template: SymbolResolutionErrors.NoGettableIndexerInType, - location: index.Location, + location: syntax.Location, formatArgs: receiver.Type)); constraints.UnifyAsserted(returnType, IntrinsicSymbols.ErrorType); return ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(args.Length)); @@ -677,17 +636,13 @@ private UntypedExpression BindIndexExpression(IndexExpressionSyntax index, Const "operator[]", indexers, args.Cast().ToImmutableArray(), - out var gotReturnType); + out var gotReturnType, + syntax); constraints.UnifyAsserted(returnType, gotReturnType); - overloaded.ConfigureDiagnostic(diag => diag - .WithLocation(index.Location)); return overloaded; - }).Unwrap(); - - promise.ConfigureDiagnostic(diag => diag - .WithLocation(index.Location)); + }, syntax).Unwrap(); - return new UntypedIndexGetExpression(index, receiver, promise, args, returnType); + return new UntypedIndexGetExpression(syntax, receiver, promise, args, returnType); } private UntypedExpression BindGenericExpression(GenericExpressionSyntax syntax, ConstraintSolver constraints, DiagnosticBag diagnostics) diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs index 042a8e267..0911e1cbc 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs @@ -83,9 +83,7 @@ private UntypedLvalue BindMemberLvalue(MemberExpressionSyntax syntax, Constraint else { // Value, add constraint - var promise = constraints.Member(left.TypeRequired, memberName, out var memberType); - promise.ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Location)); + var promise = constraints.Member(left.TypeRequired, memberName, out var memberType, syntax); return new UntypedMemberLvalue(syntax, left, promise, memberType); } } @@ -100,14 +98,14 @@ private UntypedLvalue BindIllegalLvalue(SyntaxNode syntax, ConstraintSolver cons return new UntypedIllegalLvalue(syntax); } - private UntypedLvalue BindIndexLvalue(IndexExpressionSyntax index, ConstraintSolver constraints, DiagnosticBag diagnostics) + private UntypedLvalue BindIndexLvalue(IndexExpressionSyntax syntax, ConstraintSolver constraints, DiagnosticBag diagnostics) { - var receiver = this.BindExpression(index.Indexed, constraints, diagnostics); + var receiver = this.BindExpression(syntax.Indexed, constraints, diagnostics); if (receiver is UntypedReferenceErrorExpression err) { - return new UntypedIllegalLvalue(index); + return new UntypedIllegalLvalue(syntax); } - var args = index.IndexList.Values + var args = syntax.IndexList.Values .Select(x => this.BindExpression(x, constraints, diagnostics)) .ToImmutableArray(); var returnType = constraints.AllocateTypeVariable(); @@ -127,7 +125,7 @@ private UntypedLvalue BindIndexLvalue(IndexExpressionSyntax index, ConstraintSol { diagnostics.Add(Diagnostic.Create( template: SymbolResolutionErrors.NoSettableIndexerInType, - location: index.Location, + location: syntax.Location, formatArgs: receiverType)); constraints.UnifyAsserted(returnType, IntrinsicSymbols.ErrorType); return ConstraintPromise.FromResult(new NoOverloadFunctionSymbol(args.Length + 1)); @@ -137,16 +135,12 @@ private UntypedLvalue BindIndexLvalue(IndexExpressionSyntax index, ConstraintSol indexers, args.Append(returnType as object).ToImmutableArray(), // NOTE: We don't care about the return type, this is an lvalue - out _); - overloaded.ConfigureDiagnostic(diag => diag - .WithLocation(index.Location)); + out _, + syntax); return overloaded; - }).Unwrap(); - - promise.ConfigureDiagnostic(diag => diag - .WithLocation(index.Location)); + }, syntax).Unwrap(); - return new UntypedIndexSetLvalue(index, receiver, promise, args, returnType); + return new UntypedIndexSetLvalue(syntax, receiver, promise, args, returnType); } private UntypedLvalue SymbolToLvalue(SyntaxNode syntax, Symbol symbol, ConstraintSolver constraints, DiagnosticBag diagnostics) diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedStatement.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedStatement.cs index 01c55b161..7796aef38 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedStatement.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedStatement.cs @@ -107,10 +107,7 @@ private UntypedStatement BindVariableDeclaration(VariableDeclarationSyntax synta if (value is not null) { // It has to be assignable - constraints - .Assignable(declaredType, value.TypeRequired) - .ConfigureDiagnostic(diag => diag - .WithLocation(syntax.Value!.Value.Location)); + constraints.Assignable(declaredType, value.TypeRequired, syntax.Value!.Value); } return new UntypedLocalDeclaration(syntax, localSymbol, value); diff --git a/src/Draco.Compiler/Internal/Solver/AssignableConstraint.cs b/src/Draco.Compiler/Internal/Solver/AssignableConstraint.cs index 9c8d09214..f3621e95e 100644 --- a/src/Draco.Compiler/Internal/Solver/AssignableConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/AssignableConstraint.cs @@ -18,7 +18,11 @@ internal sealed class AssignableConstraint : Constraint /// public TypeSymbol AssignedType { get; } - public AssignableConstraint(TypeSymbol targetType, TypeSymbol assignedType) + public AssignableConstraint( + TypeSymbol targetType, + TypeSymbol assignedType, + ConstraintLocator locator) + : base(locator) { this.TargetType = targetType; this.AssignedType = assignedType; diff --git a/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs b/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs index 6893d8717..2496f7254 100644 --- a/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/AwaitConstraint.cs @@ -1,5 +1,4 @@ using System; -using Draco.Compiler.Api.Diagnostics; namespace Draco.Compiler.Internal.Solver; @@ -22,14 +21,8 @@ internal sealed class AwaitConstraint : Constraint public AwaitConstraint( Func awaited, Func map, - Diagnostic.Builder diagnostic) - : base(diagnostic) - { - this.Awaited = awaited; - this.Map = map; - } - - public AwaitConstraint(Func awaited, Func map) + ConstraintLocator locator) + : base(locator) { this.Awaited = awaited; this.Map = map; diff --git a/src/Draco.Compiler/Internal/Solver/CallConstraint.cs b/src/Draco.Compiler/Internal/Solver/CallConstraint.cs index 6d33b8a4b..60fbea49b 100644 --- a/src/Draco.Compiler/Internal/Solver/CallConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/CallConstraint.cs @@ -27,7 +27,9 @@ internal sealed class CallConstraint : Constraint public CallConstraint( TypeSymbol calledType, ImmutableArray arguments, - TypeSymbol returnType) + TypeSymbol returnType, + ConstraintLocator locator) + : base(locator) { this.CalledType = calledType; this.Arguments = arguments; diff --git a/src/Draco.Compiler/Internal/Solver/CommonTypeConstraint.cs b/src/Draco.Compiler/Internal/Solver/CommonTypeConstraint.cs index 95b1c8f4b..5b165634e 100644 --- a/src/Draco.Compiler/Internal/Solver/CommonTypeConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/CommonTypeConstraint.cs @@ -19,7 +19,11 @@ internal sealed class CommonTypeConstraint : Constraint /// public ImmutableArray AlternativeTypes { get; } - public CommonTypeConstraint(TypeSymbol commonType, ImmutableArray alternativeTypes) + public CommonTypeConstraint( + TypeSymbol commonType, + ImmutableArray alternativeTypes, + ConstraintLocator locator) + : base(locator) { this.CommonType = commonType; this.AlternativeTypes = alternativeTypes; diff --git a/src/Draco.Compiler/Internal/Solver/Constraint.cs b/src/Draco.Compiler/Internal/Solver/Constraint.cs index cf7baf6a3..1c042bf6d 100644 --- a/src/Draco.Compiler/Internal/Solver/Constraint.cs +++ b/src/Draco.Compiler/Internal/Solver/Constraint.cs @@ -1,3 +1,4 @@ +using System; using Draco.Compiler.Api.Diagnostics; namespace Draco.Compiler.Internal.Solver; @@ -10,17 +11,20 @@ internal abstract class Constraint : IConstraint { public IConstraintPromise Promise { get; } IConstraintPromise IConstraint.Promise => this.Promise; - public Diagnostic.Builder Diagnostic { get; } + public ConstraintLocator Locator { get; } - protected Constraint(Diagnostic.Builder diagnostic) + protected Constraint(ConstraintLocator locator) { this.Promise = ConstraintPromise.Create(this); - this.Diagnostic = diagnostic; + this.Locator = locator; } - protected Constraint() - : this(new()) + public Diagnostic.Builder BuildDiagnostic(Action config) { + var builder = Diagnostic.CreateBuilder(); + config(builder); + this.Locator.Locate(builder); + return builder; } public override abstract string ToString(); diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintLocator.cs b/src/Draco.Compiler/Internal/Solver/ConstraintLocator.cs new file mode 100644 index 000000000..f5f43ea96 --- /dev/null +++ b/src/Draco.Compiler/Internal/Solver/ConstraintLocator.cs @@ -0,0 +1,116 @@ +using Draco.Compiler.Api.Diagnostics; +using Draco.Compiler.Api.Syntax; + +namespace Draco.Compiler.Internal.Solver; + +/// +/// Locator for a constraint. +/// +internal abstract class ConstraintLocator +{ + /// + /// A constraint locator not providing any information. + /// + public static ConstraintLocator Null { get; } = new NullConstraintLocator(); + + /// + /// Creates a simple syntactic locator. + /// + /// The syntax node to connect the location to. + /// The locator that will point at the syntax. + public static ConstraintLocator Syntax(SyntaxNode syntax) => new SyntaxConstraintLocator(syntax); + + /// + /// Creates a constraint locator based on anonter constraint. + /// + /// The constraint to base the locator on. + /// The locator that will point point wherever the locator of the constraint would point to. + public static ConstraintLocator Constraint(IConstraint constraint) => new ReferenceConstraintLocator(constraint); + + /// + /// Creates a constraint locator based on a constraint promise. + /// + /// The promise to base the locator on. + /// The locator that will point point wherever the locator of the promises constraint would point to. + public static ConstraintLocator Promise(IConstraintPromise promise) => Constraint(promise.Constraint); + + /// + /// Locates information for the constraint. + /// + /// The diagnostic builder to help the location for. + public abstract void Locate(Diagnostic.Builder diagnostic); + + /// + /// Wraps the constraint locator to provide additional information. + /// + /// The related information to append. + /// The wrapped locator. + public ConstraintLocator WithRelatedInformation(DiagnosticRelatedInformation relatedInformation) => + new WithRelatedInfoConstraintLocator(this, relatedInformation); + + /// + /// Wraps the constraint locator to provide additional information. + /// + /// The location of the related information. + /// The format message. + /// The format arguments. + /// The wrapped locator. + public ConstraintLocator WithRelatedInformation( + Location? location, + string format, + params object?[] formatArgs) => this.WithRelatedInformation(DiagnosticRelatedInformation.Create( + location: location, + format: format, + formatArgs: formatArgs)); + + private sealed class NullConstraintLocator : ConstraintLocator + { + public override void Locate(Diagnostic.Builder diagnostic) { } + } + + private sealed class SyntaxConstraintLocator : ConstraintLocator + { + private readonly SyntaxNode syntax; + + public SyntaxConstraintLocator(SyntaxNode syntax) + { + this.syntax = syntax; + } + + public override void Locate(Diagnostic.Builder diagnostic) => + diagnostic.WithLocation(this.syntax.Location); + } + + private sealed class ReferenceConstraintLocator : ConstraintLocator + { + private readonly IConstraint constraint; + + public ReferenceConstraintLocator(IConstraint constraint) + { + this.constraint = constraint; + } + + public override void Locate(Diagnostic.Builder diagnostic) => + this.constraint.Locator.Locate(diagnostic); + } + + private sealed class WithRelatedInfoConstraintLocator : ConstraintLocator + { + private readonly ConstraintLocator underlying; + private DiagnosticRelatedInformation relatedInfo; + + public WithRelatedInfoConstraintLocator( + ConstraintLocator underlying, + DiagnosticRelatedInformation relatedInfo) + { + this.underlying = underlying; + this.relatedInfo = relatedInfo; + } + + public override void Locate(Diagnostic.Builder diagnostic) + { + this.underlying.Locate(diagnostic); + diagnostic.WithRelatedInformation(this.relatedInfo); + } + } +} diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintPromise.cs b/src/Draco.Compiler/Internal/Solver/ConstraintPromise.cs index d2595ced4..a965d9c22 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintPromise.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintPromise.cs @@ -1,6 +1,4 @@ using System; -using Draco.Compiler.Api.Diagnostics; -using Draco.Compiler.Internal.Diagnostics; namespace Draco.Compiler.Internal.Solver; @@ -50,12 +48,8 @@ public ResolvedConstraintPromise(TResult result) public void Resolve(TResult result) => throw new InvalidOperationException("can not resolve an already solved constraint"); - public void Fail(TResult result, DiagnosticBag? diagnostics) => + public void Fail(TResult result) => throw new InvalidOperationException("can not resolve an already solved constraint"); - - public IConstraintPromise ConfigureDiagnostic(Action configure) => this; - IConstraintPromise IConstraintPromise.ConfigureDiagnostic(Action configure) => - this.ConfigureDiagnostic(configure); } private sealed class ResolvableConstraintPromise : IConstraintPromise @@ -86,24 +80,8 @@ public ResolvableConstraintPromise(IConstraint constraint) this.Constraint = constraint; } - public IConstraintPromise ConfigureDiagnostic(Action configure) - { - configure(this.Constraint.Diagnostic); - return this; - } - IConstraintPromise IConstraintPromise.ConfigureDiagnostic(Action configure) => - this.ConfigureDiagnostic(configure); - public void Resolve(TResult result) => this.Result = result; - public void Fail(TResult result, DiagnosticBag? diagnostics) - { - this.Result = result; - if (diagnostics is not null) - { - var diag = this.Constraint.Diagnostic.Build(); - diagnostics.Add(diag); - } - } + public void Fail(TResult result) => this.Result = result; } private sealed class UnwrapConstraintPromise : IConstraintPromise @@ -121,15 +99,7 @@ public UnwrapConstraintPromise(IConstraintPromise> u this.underlying = underlying; } - public IConstraintPromise ConfigureDiagnostic(Action configure) - { - this.underlying.ConfigureDiagnostic(configure); - return this; - } - IConstraintPromise IConstraintPromise.ConfigureDiagnostic(Action configure) => - this.ConfigureDiagnostic(configure); - public void Resolve(TResult result) => throw new NotSupportedException("can not resolve unwrap promise"); - public void Fail(TResult result, DiagnosticBag? diagnostics) => throw new NotSupportedException("can not fail unwrap promise"); + public void Fail(TResult result) => throw new NotSupportedException("can not fail unwrap promise"); } } diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs index 480584541..84bf614d3 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Constraints.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Draco.Compiler.Api.Syntax; using Draco.Compiler.Internal.Symbols; using Draco.Compiler.Internal.Utilities; @@ -68,10 +69,11 @@ public bool TryDequeue( /// /// The type that is constrained to be the same as . /// The type that is constrained to be the same as . + /// The syntax that the constraint originates from. /// The promise for the constraint added. - public IConstraintPromise SameType(TypeSymbol first, TypeSymbol second) + public IConstraintPromise SameType(TypeSymbol first, TypeSymbol second, SyntaxNode syntax) { - var constraint = new SameTypeConstraint(ImmutableArray.Create(first, second)); + var constraint = new SameTypeConstraint(ImmutableArray.Create(first, second), ConstraintLocator.Syntax(syntax)); this.Add(constraint); return constraint.Promise; } @@ -81,10 +83,21 @@ public IConstraintPromise SameType(TypeSymbol first, TypeSymbol second) /// /// The type being assigned to. /// The type assigned. + /// The syntax that the constraint originates from. /// The promise for the constraint added. - public IConstraintPromise Assignable(TypeSymbol targetType, TypeSymbol assignedType) + public IConstraintPromise Assignable(TypeSymbol targetType, TypeSymbol assignedType, SyntaxNode syntax) => + this.Assignable(targetType, assignedType, ConstraintLocator.Syntax(syntax)); + + /// + /// Adds an assignable constraint to the solver. + /// + /// The type being assigned to. + /// The type assigned. + /// The locator for the constraint. + /// The promise for the constraint added. + public IConstraintPromise Assignable(TypeSymbol targetType, TypeSymbol assignedType, ConstraintLocator locator) { - var constraint = new AssignableConstraint(targetType, assignedType); + var constraint = new AssignableConstraint(targetType, assignedType, locator); this.Add(constraint); return constraint.Promise; } @@ -94,10 +107,26 @@ public IConstraintPromise Assignable(TypeSymbol targetType, TypeSymbol ass /// /// The common type of the provided alternative types. /// The alternative types to find the common type of. + /// The syntax that the constraint originates from. /// The promise of the constraint added. - public IConstraintPromise CommonType(TypeSymbol commonType, ImmutableArray alternativeTypes) + public IConstraintPromise CommonType( + TypeSymbol commonType, + ImmutableArray alternativeTypes, + SyntaxNode syntax) => this.CommonType(commonType, alternativeTypes, ConstraintLocator.Syntax(syntax)); + + /// + /// Adds a common-type constraint to the solver. + /// + /// The common type of the provided alternative types. + /// The alternative types to find the common type of. + /// The locator for this constraint. + /// The promise of the constraint added. + public IConstraintPromise CommonType( + TypeSymbol commonType, + ImmutableArray alternativeTypes, + ConstraintLocator locator) { - var constraint = new CommonTypeConstraint(commonType, alternativeTypes); + var constraint = new CommonTypeConstraint(commonType, alternativeTypes, locator); this.Add(constraint); return constraint.Promise; } @@ -108,11 +137,16 @@ public IConstraintPromise CommonType(TypeSymbol commonType, ImmutableArray /// The accessed object type. /// The accessed member name. /// The type of the member. + /// The syntax that the constraint originates from. /// The promise of the accessed member symbol. - public IConstraintPromise Member(TypeSymbol accessedType, string memberName, out TypeSymbol memberType) + public IConstraintPromise Member( + TypeSymbol accessedType, + string memberName, + out TypeSymbol memberType, + SyntaxNode syntax) { memberType = this.AllocateTypeVariable(); - var constraint = new MemberConstraint(accessedType, memberName, memberType); + var constraint = new MemberConstraint(accessedType, memberName, memberType, ConstraintLocator.Syntax(syntax)); this.Add(constraint); return constraint.Promise; } @@ -123,14 +157,16 @@ public IConstraintPromise Member(TypeSymbol accessedType, string memberN /// The called function type. /// The calling arguments. /// The return type. + /// The syntax that the constraint originates from. /// The promise of the constraint. public IConstraintPromise Call( TypeSymbol calledType, ImmutableArray args, - out TypeSymbol returnType) + out TypeSymbol returnType, + SyntaxNode syntax) { returnType = this.AllocateTypeVariable(); - var constraint = new CallConstraint(calledType, args, returnType); + var constraint = new CallConstraint(calledType, args, returnType, ConstraintLocator.Syntax(syntax)); this.Add(constraint); return constraint.Promise; } @@ -142,15 +178,17 @@ public IConstraintPromise Call( /// The functions to choose an overload from. /// The passed in arguments. /// The return type of the call. + /// The syntax that the constraint originates from. /// The promise for the resolved overload. public IConstraintPromise Overload( string name, ImmutableArray functions, ImmutableArray args, - out TypeSymbol returnType) + out TypeSymbol returnType, + SyntaxNode syntax) { returnType = this.AllocateTypeVariable(); - var constraint = new OverloadConstraint(name, functions, args, returnType); + var constraint = new OverloadConstraint(name, functions, args, returnType, ConstraintLocator.Syntax(syntax)); this.Add(constraint); return constraint.Promise; } @@ -178,7 +216,7 @@ public IConstraintPromise Await( var constraint = new AwaitConstraint( () => awaited.IsResolved, map, - awaited.Constraint.Diagnostic); + ConstraintLocator.Promise(awaited)); this.Add(constraint); return constraint.Promise; } @@ -189,8 +227,12 @@ public IConstraintPromise Await( /// /// The original type, usually a type variable. /// Function that executes once the is substituted. + /// The syntax that the constraint originates from. /// The promise of the type symbol symbol. - public IConstraintPromise Substituted(TypeSymbol original, Func map) + public IConstraintPromise Substituted( + TypeSymbol original, + Func map, + SyntaxNode syntax) { if (!original.IsTypeVariable) { @@ -199,7 +241,8 @@ public IConstraintPromise Substituted(TypeSymbol original, Fun } else { - var constraint = new AwaitConstraint(() => !original.Substitution.IsTypeVariable, map); + var constraint = new AwaitConstraint( + () => !original.Substitution.IsTypeVariable, map, ConstraintLocator.Syntax(syntax)); this.Add(constraint); return constraint.Promise; } diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs index e0a552fe9..8f843fe2f 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs @@ -112,10 +112,9 @@ private bool ApplyRules(DiagnosticBag? diagnostics) .Append(assignable.AssignedType) .ToImmutableArray(); - // TODO: We forget diag info... - this.CommonType(commonType, alternatives); // New assignable - this.Assignable(assignable.TargetType, commonType); + this.CommonType(commonType, alternatives, ConstraintLocator.Constraint(assignable)); + this.Assignable(assignable.TargetType, commonType, ConstraintLocator.Constraint(assignable)); return true; } @@ -162,10 +161,11 @@ private void HandleRule(SameTypeConstraint constraint, DiagnosticBag? diagnostic if (!this.Unify(constraint.Types[0], constraint.Types[i])) { // Type-mismatch - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.TypeMismatch) - .WithFormatArgs(constraint.Types[0].Substitution, constraint.Types[i].Substitution); - constraint.Promise.Fail(default, diagnostics); + .WithFormatArgs(constraint.Types[0].Substitution, constraint.Types[i].Substitution)) + .Build()); + constraint.Promise.Fail(default); return; } } @@ -179,10 +179,11 @@ private void HandleRule(AssignableConstraint constraint, DiagnosticBag? diagnost if (!SymbolEqualityComparer.Default.IsBaseOf(constraint.TargetType, constraint.AssignedType)) { // Type-mismatch - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.TypeMismatch) - .WithFormatArgs(constraint.TargetType.Substitution, constraint.AssignedType.Substitution); - constraint.Promise.Fail(default, diagnostics); + .WithFormatArgs(constraint.TargetType.Substitution, constraint.AssignedType.Substitution)) + .Build()); + constraint.Promise.Fail(default); return; } @@ -204,11 +205,12 @@ private void HandleRule(CommonTypeConstraint constraint, DiagnosticBag? diagnost } // No common type - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.NoCommonType) - .WithFormatArgs(string.Join(", ", constraint.AlternativeTypes)); + .WithFormatArgs(string.Join(", ", constraint.AlternativeTypes))) + .Build()); this.UnifyAsserted(constraint.CommonType, IntrinsicSymbols.ErrorType); - constraint.Promise.Fail(default, diagnostics); + constraint.Promise.Fail(default); } private void HandleRule(MemberConstraint constraint, DiagnosticBag? diagnostics) @@ -236,12 +238,13 @@ private void HandleRule(MemberConstraint constraint, DiagnosticBag? diagnostics) if (membersWithName.Length == 0) { // No such member, error - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(SymbolResolutionErrors.MemberNotFound) - .WithFormatArgs(constraint.MemberName, accessed); + .WithFormatArgs(constraint.MemberName, accessed)) + .Build()); // We still provide a single error symbol this.UnifyAsserted(constraint.MemberType, IntrinsicSymbols.ErrorType); - constraint.Promise.Fail(UndefinedMemberSymbol.Instance, diagnostics); + constraint.Promise.Fail(UndefinedMemberSymbol.Instance); return; } @@ -249,13 +252,7 @@ private void HandleRule(MemberConstraint constraint, DiagnosticBag? diagnostics) { // One member, we know what type the member type is var memberType = ((ITypedSymbol)membersWithName[0]).Type; - var assignablePromise = this.Assignable(constraint.MemberType, memberType); - // TODO: This location config is horrible, we need that refactor SOON - if (constraint.Diagnostic.Location is not null) - { - assignablePromise.ConfigureDiagnostic(diag => diag - .WithLocation(constraint.Diagnostic.Location)); - } + var assignablePromise = this.Assignable(constraint.MemberType, memberType, ConstraintLocator.Constraint(constraint)); constraint.Promise.Resolve(membersWithName[0]); return; } @@ -314,10 +311,11 @@ private void HandleRule(OverloadConstraint constraint, DiagnosticBag? diagnostic this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); // Best-effort shape approximation var errorSymbol = new NoOverloadFunctionSymbol(constraint.Arguments.Length); - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.NoMatchingOverload) - .WithFormatArgs(functionName); - constraint.Promise.Fail(errorSymbol, diagnostics); + .WithFormatArgs(functionName)) + .Build()); + constraint.Promise.Fail(errorSymbol); return; } @@ -355,13 +353,7 @@ private void HandleRule(OverloadConstraint constraint, DiagnosticBag? diagnostic } } // In all cases, return type is simple, it's an assignment - var returnTypePromise = this.Assignable(constraint.ReturnType, chosen.ReturnType); - // TODO: This location config is horrible, we need that refactor SOON - if (constraint.Diagnostic.Location is not null) - { - returnTypePromise.ConfigureDiagnostic(diag => diag - .WithLocation(constraint.Diagnostic.Location)); - } + var returnTypePromise = this.Assignable(constraint.ReturnType, chosen.ReturnType, ConstraintLocator.Constraint(constraint)); // Resolve promise constraint.Promise.Resolve(chosen); } @@ -370,10 +362,11 @@ private void HandleRule(OverloadConstraint constraint, DiagnosticBag? diagnostic // Best-effort shape approximation this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); var errorSymbol = new NoOverloadFunctionSymbol(constraint.Arguments.Length); - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.AmbiguousOverloadedCall) - .WithFormatArgs(functionName, string.Join(", ", dominatingCandidates)); - constraint.Promise.Fail(errorSymbol, diagnostics); + .WithFormatArgs(functionName, string.Join(", ", dominatingCandidates))) + .Build()); + constraint.Promise.Fail(errorSymbol); } } @@ -398,10 +391,11 @@ private void HandleRule(CallConstraint constraint, DiagnosticBag? diagnostics) { // Error this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.CallNonFunction) - .WithFormatArgs(called); - constraint.Promise.Fail(default, diagnostics); + .WithFormatArgs(called)) + .Build()); + constraint.Promise.Fail(default); return; } @@ -414,12 +408,13 @@ private void HandleRule(CallConstraint constraint, DiagnosticBag? diagnostics) { // Error this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.TypeMismatch) .WithFormatArgs( functionType, - MakeMismatchedFunctionType(constraint.Arguments, functionType.ReturnType)); - constraint.Promise.Fail(default, diagnostics); + MakeMismatchedFunctionType(constraint.Arguments, functionType.ReturnType))) + .Build()); + constraint.Promise.Fail(default); return; } @@ -432,12 +427,13 @@ private void HandleRule(CallConstraint constraint, DiagnosticBag? diagnostics) { // Error this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); - constraint.Diagnostic + diagnostics?.Add(constraint.BuildDiagnostic(diag => diag .WithTemplate(TypeCheckingErrors.TypeMismatch) .WithFormatArgs( functionType, - MakeMismatchedFunctionType(constraint.Arguments, functionType.ReturnType)); - constraint.Promise.Fail(default, diagnostics); + MakeMismatchedFunctionType(constraint.Arguments, functionType.ReturnType))) + .Build()); + constraint.Promise.Fail(default); return; } if (score.IsWellDefined) break; @@ -454,6 +450,6 @@ private void HandleRule(CallConstraint constraint, DiagnosticBag? diagnostics) private void FailRule(CallConstraint constraint) { this.UnifyAsserted(constraint.ReturnType, IntrinsicSymbols.ErrorType); - constraint.Promise.Fail(default, null); + constraint.Promise.Fail(default); } } diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Utils.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Utils.cs index 6663dad71..1d9f14010 100644 --- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Utils.cs +++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Utils.cs @@ -62,12 +62,11 @@ private FunctionSymbol ChooseSymbol(FunctionSymbol chosen) private void UnifyParameterWithArgument(TypeSymbol paramType, object argument) { - var promise = this.Assignable(paramType, ExtractArgumentType(argument)); var syntax = ExtractSyntax(argument); - if (syntax is not null) - { - promise.ConfigureDiagnostic(diag => diag.WithLocation(syntax.Location)); - } + var promise = this.Assignable( + paramType, + ExtractArgumentType(argument), + syntax is null ? ConstraintLocator.Null : ConstraintLocator.Syntax(syntax)); } private static bool MatchesParameterCount(FunctionSymbol function, int argc) diff --git a/src/Draco.Compiler/Internal/Solver/IConstraint.cs b/src/Draco.Compiler/Internal/Solver/IConstraint.cs index 9d3405643..244650501 100644 --- a/src/Draco.Compiler/Internal/Solver/IConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/IConstraint.cs @@ -1,5 +1,3 @@ -using Draco.Compiler.Api.Diagnostics; - namespace Draco.Compiler.Internal.Solver; /// @@ -13,9 +11,9 @@ internal interface IConstraint public IConstraintPromise Promise { get; } /// - /// The builder for the . + /// The locator for the constraint. /// - public Diagnostic.Builder Diagnostic { get; } + public ConstraintLocator Locator { get; } } /// diff --git a/src/Draco.Compiler/Internal/Solver/IConstraintPromise.cs b/src/Draco.Compiler/Internal/Solver/IConstraintPromise.cs index 74c00f75f..6a8cfae3e 100644 --- a/src/Draco.Compiler/Internal/Solver/IConstraintPromise.cs +++ b/src/Draco.Compiler/Internal/Solver/IConstraintPromise.cs @@ -1,7 +1,3 @@ -using System; -using Draco.Compiler.Api.Diagnostics; -using Draco.Compiler.Internal.Diagnostics; - namespace Draco.Compiler.Internal.Solver; /// @@ -20,13 +16,6 @@ internal interface IConstraintPromise /// True, if this promise is resolved, either ba succeeding or failing. /// public bool IsResolved { get; } - - /// - /// Configures the diagnostic messages for the constraint of this promise in case it fails. - /// - /// The configuration function. - /// The promise instance. - public IConstraintPromise ConfigureDiagnostic(Action configure); } /// @@ -55,11 +44,5 @@ internal interface IConstraintPromise : IConstraintPromise /// Fails this constraint, reporting the error. /// /// The result for the failure. - /// The diagnostics to report to, if needed. - public void Fail(TResult result, DiagnosticBag? diagnostics); - - /// - /// . - /// - public new IConstraintPromise ConfigureDiagnostic(Action configure); + public void Fail(TResult result); } diff --git a/src/Draco.Compiler/Internal/Solver/MemberConstraint.cs b/src/Draco.Compiler/Internal/Solver/MemberConstraint.cs index 4aca726ca..a02a11698 100644 --- a/src/Draco.Compiler/Internal/Solver/MemberConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/MemberConstraint.cs @@ -22,7 +22,12 @@ internal sealed class MemberConstraint : Constraint /// public TypeSymbol MemberType { get; } - public MemberConstraint(TypeSymbol accessed, string memberName, TypeSymbol memberType) + public MemberConstraint( + TypeSymbol accessed, + string memberName, + TypeSymbol memberType, + ConstraintLocator locator) + : base(locator) { this.Accessed = accessed; this.MemberName = memberName; diff --git a/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs b/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs index 32cbfb01e..7fd997798 100644 --- a/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/OverloadConstraint.cs @@ -34,7 +34,9 @@ public OverloadConstraint( string name, ImmutableArray candidates, ImmutableArray arguments, - TypeSymbol returnType) + TypeSymbol returnType, + ConstraintLocator locator) + : base(locator) { this.Name = name; this.Candidates = candidates; diff --git a/src/Draco.Compiler/Internal/Solver/SameTypeConstraint.cs b/src/Draco.Compiler/Internal/Solver/SameTypeConstraint.cs index 63fe9e301..f1b7ce7aa 100644 --- a/src/Draco.Compiler/Internal/Solver/SameTypeConstraint.cs +++ b/src/Draco.Compiler/Internal/Solver/SameTypeConstraint.cs @@ -14,7 +14,10 @@ internal sealed class SameTypeConstraint : Constraint /// public ImmutableArray Types { get; } - public SameTypeConstraint(ImmutableArray types) + public SameTypeConstraint( + ImmutableArray types, + ConstraintLocator locator) + : base(locator) { this.Types = types; } From ab43ddf12a6ea4fa11231187329d7e214ae573d8 Mon Sep 17 00:00:00 2001 From: LPeter1997 Date: Sat, 2 Sep 2023 15:02:30 +0200 Subject: [PATCH 3/5] Cleanup patch (#315) * Small staticness cleanup * Removed unused keywords * Update LexerTests.cs * Update LexerTests.cs --- src/Draco.Compiler.Tests/Syntax/LexerTests.cs | 8 ++------ src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs | 1 - src/Draco.Compiler/Api/Syntax/TokenKind.cs | 5 ----- src/Draco.Compiler/Internal/Binding/Binder.cs | 4 ++-- .../Internal/Binding/Binder_BoundExpression.cs | 6 +++--- .../Internal/Binding/Binder_UntypedExpression.cs | 2 +- .../Internal/Binding/Binder_UntypedLvalue.cs | 2 +- src/Draco.Compiler/Internal/Syntax/Lexer.cs | 1 - src/Draco.Compiler/Internal/Syntax/SyntaxTreeFormatter.cs | 4 ++-- 9 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/Draco.Compiler.Tests/Syntax/LexerTests.cs b/src/Draco.Compiler.Tests/Syntax/LexerTests.cs index 653725aa1..3a65b67e5 100644 --- a/src/Draco.Compiler.Tests/Syntax/LexerTests.cs +++ b/src/Draco.Compiler.Tests/Syntax/LexerTests.cs @@ -1250,20 +1250,16 @@ public void TestEndOfInputAfterSingleQuote() public void TestHelloWorld() { var text = """ - from System.Console import { WriteLine }; + import System.Console; func main() = WriteLine("Hello, World!"); """; this.Lex(text); - this.AssertNextToken(TokenKind.KeywordFrom, "from"); + this.AssertNextToken(TokenKind.KeywordImport, "import"); this.AssertNextToken(TokenKind.Identifier, "System", "System"); this.AssertNextToken(TokenKind.Dot, "."); this.AssertNextToken(TokenKind.Identifier, "Console", "Console"); - this.AssertNextToken(TokenKind.KeywordImport, "import"); - this.AssertNextToken(TokenKind.CurlyOpen, "{"); - this.AssertNextToken(TokenKind.Identifier, "WriteLine", "WriteLine"); - this.AssertNextToken(TokenKind.CurlyClose, "}"); this.AssertNextToken(TokenKind.Semicolon, ";"); this.AssertNextToken(TokenKind.KeywordFunc, "func"); this.AssertNextToken(TokenKind.Identifier, "main", "main"); diff --git a/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs b/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs index cbce84d21..280767a54 100644 --- a/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs +++ b/src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs @@ -19,7 +19,6 @@ public static class SyntaxFacts TokenKind.KeywordElse => "else", TokenKind.KeywordFalse => "false", TokenKind.KeywordFor => "for", - TokenKind.KeywordFrom => "from", TokenKind.KeywordFunc => "func", TokenKind.KeywordGoto => "goto", TokenKind.KeywordIf => "if", diff --git a/src/Draco.Compiler/Api/Syntax/TokenKind.cs b/src/Draco.Compiler/Api/Syntax/TokenKind.cs index 01cf8db03..9c6c533e5 100644 --- a/src/Draco.Compiler/Api/Syntax/TokenKind.cs +++ b/src/Draco.Compiler/Api/Syntax/TokenKind.cs @@ -95,11 +95,6 @@ public enum TokenKind /// KeywordFor, - /// - /// The keyword 'from'. - /// - KeywordFrom, - /// /// The keyword 'func'. /// diff --git a/src/Draco.Compiler/Internal/Binding/Binder.cs b/src/Draco.Compiler/Internal/Binding/Binder.cs index 8f74caf2e..071bd8a0e 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder.cs @@ -135,7 +135,7 @@ public virtual (TypeSymbol Type, BoundExpression? Value) BindGlobal(SourceGlobal internal virtual void BindSyntaxToSymbol(SyntaxNode syntax, Symbol module) { } internal virtual void BindTypeSyntaxToSymbol(SyntaxNode syntax, TypeSymbol type) { } - private FunctionSymbol GetGetterSymbol(SyntaxNode? syntax, PropertySymbol prop, DiagnosticBag diags) + private static FunctionSymbol GetGetterSymbol(SyntaxNode? syntax, PropertySymbol prop, DiagnosticBag diags) { var result = prop.Getter; if (result is null) @@ -149,7 +149,7 @@ private FunctionSymbol GetGetterSymbol(SyntaxNode? syntax, PropertySymbol prop, return result; } - private FunctionSymbol GetSetterSymbol(SyntaxNode? syntax, PropertySymbol prop, DiagnosticBag diags) + private static FunctionSymbol GetSetterSymbol(SyntaxNode? syntax, PropertySymbol prop, DiagnosticBag diags) { var result = prop.Setter; if (result is null) diff --git a/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs index 3773fa67c..615979a3b 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_BoundExpression.cs @@ -302,7 +302,7 @@ compoundOperator is not null else if (assignment.Left is UntypedMemberLvalue mem && mem.Member.Result is PropertySymbol pr) { var receiver = this.TypeExpression(mem.Accessed, constraints, diagnostics); - var setter = this.GetSetterSymbol(assignment.Syntax, pr, diagnostics); + var setter = GetSetterSymbol(assignment.Syntax, pr, diagnostics); return new BoundPropertySetExpression( assignment.Syntax, receiver, @@ -385,7 +385,7 @@ private BoundExpression TypeMemberExpression(UntypedMemberExpression mem, Constr } else { - var getter = this.GetGetterSymbol(mem.Syntax, prop, diagnostics); + var getter = GetGetterSymbol(mem.Syntax, prop, diagnostics); return new BoundPropertyGetExpression(mem.Syntax, left, getter); } } @@ -418,7 +418,7 @@ private BoundExpression CompoundPropertyExpression( ImmutableArray args, DiagnosticBag diagnostics) { - var getter = this.GetGetterSymbol(syntax, prop, diagnostics); + var getter = GetGetterSymbol(syntax, prop, diagnostics); var getterCall = new BoundCallExpression(null, receiver, getter, args); return new BoundBinaryExpression(syntax, compoundOperator, getterCall, right, right.TypeRequired); } diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs index 753818f16..c43165169 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedExpression.cs @@ -760,7 +760,7 @@ private UntypedExpression SymbolToExpression(SyntaxNode syntax, Symbol symbol, C case FieldSymbol field: return new UntypedFieldExpression(syntax, null, field); case PropertySymbol prop: - var getter = this.GetGetterSymbol(syntax, prop, diagnostics); + var getter = GetGetterSymbol(syntax, prop, diagnostics); return new UntypedPropertyGetExpression(syntax, null, getter); case FunctionSymbol func: return new UntypedFunctionGroupExpression(syntax, ImmutableArray.Create(func)); diff --git a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs index 0911e1cbc..3d6509abd 100644 --- a/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs +++ b/src/Draco.Compiler/Internal/Binding/Binder_UntypedLvalue.cs @@ -150,7 +150,7 @@ private UntypedLvalue SymbolToLvalue(SyntaxNode syntax, Symbol symbol, Constrain case FieldSymbol field: return new UntypedFieldLvalue(syntax, null, field); case PropertySymbol prop: - var setter = this.GetSetterSymbol(syntax, prop, diagnostics); + var setter = GetSetterSymbol(syntax, prop, diagnostics); return new UntypedPropertySetLvalue(syntax, null, setter); default: // NOTE: The error is already reported diff --git a/src/Draco.Compiler/Internal/Syntax/Lexer.cs b/src/Draco.Compiler/Internal/Syntax/Lexer.cs index 2729d9c20..97e2a4a53 100644 --- a/src/Draco.Compiler/Internal/Syntax/Lexer.cs +++ b/src/Draco.Compiler/Internal/Syntax/Lexer.cs @@ -323,7 +323,6 @@ var _ when ident.Span.SequenceEqual("and") => TokenKind.KeywordAnd, var _ when ident.Span.SequenceEqual("else") => TokenKind.KeywordElse, var _ when ident.Span.SequenceEqual("false") => TokenKind.KeywordFalse, var _ when ident.Span.SequenceEqual("for") => TokenKind.KeywordFor, - var _ when ident.Span.SequenceEqual("from") => TokenKind.KeywordFrom, var _ when ident.Span.SequenceEqual("func") => TokenKind.KeywordFunc, var _ when ident.Span.SequenceEqual("goto") => TokenKind.KeywordGoto, var _ when ident.Span.SequenceEqual("if") => TokenKind.KeywordIf, diff --git a/src/Draco.Compiler/Internal/Syntax/SyntaxTreeFormatter.cs b/src/Draco.Compiler/Internal/Syntax/SyntaxTreeFormatter.cs index a17b6e49e..85d4926d3 100644 --- a/src/Draco.Compiler/Internal/Syntax/SyntaxTreeFormatter.cs +++ b/src/Draco.Compiler/Internal/Syntax/SyntaxTreeFormatter.cs @@ -130,7 +130,7 @@ private SyntaxToken FormatToken(SyntaxToken token) // Note: TokenKind.Comma is exception, in case it is in label declaration, it is handeled outside of this function TokenKind.Assign or TokenKind.Colon or TokenKind.Comma or TokenKind.Equal or TokenKind.GreaterEqual or TokenKind.GreaterThan or TokenKind.InterpolationStart or - TokenKind.KeywordAnd or TokenKind.KeywordFrom or TokenKind.KeywordImport or + TokenKind.KeywordAnd or TokenKind.KeywordImport or TokenKind.KeywordMod or TokenKind.KeywordNot or TokenKind.KeywordOr or TokenKind.KeywordRem or TokenKind.LessEqual or TokenKind.LessThan or TokenKind.Minus or TokenKind.MinusAssign or TokenKind.NotEqual or @@ -193,7 +193,7 @@ TokenKind.Semicolon or TokenKind.CurlyOpen or TokenKind.CurlyClose or { lastToken: TokenKind.KeywordVal or TokenKind.KeywordVar, nextToken: TokenKind.Colon } => SetTrivia(newToken, noSpaceTrivia, noSpaceTrivia), { - lastToken: TokenKind.KeywordFrom or TokenKind.KeywordVal or TokenKind.KeywordVar or TokenKind.Colon, + lastToken: TokenKind.KeywordVal or TokenKind.KeywordVar or TokenKind.Colon, nextToken: TokenKind.Semicolon or TokenKind.Assign or TokenKind.PlusAssign or TokenKind.MinusAssign or TokenKind.Slash or TokenKind.StarAssign } => SetTrivia(newToken, noSpaceTrivia, oneSpaceTrivia), From 3a759b5155a7e35087934562d84e82f2a9047dbc Mon Sep 17 00:00:00 2001 From: Kuinox Date: Sat, 2 Sep 2023 15:15:18 +0200 Subject: [PATCH 4/5] Added cache invalidation when the playground have a new build. (#316) * Added cache invalidation when the playground have a new build. * Be more defensive when setting the cache date. * Update src/Draco.Editor.Web/app/ts/cache.ts Co-authored-by: LPeter1997 * Update cache.ts --------- Co-authored-by: LPeter1997 --- src/Draco.Editor.Web/app/build.js | 9 ++++- src/Draco.Editor.Web/app/package-lock.json | 39 ++++++++++++++++++++++ src/Draco.Editor.Web/app/package.json | 1 + src/Draco.Editor.Web/app/ts/cache.ts | 30 +++++++++++++---- src/Draco.Editor.Web/app/ts/metadata.ts | 7 ++++ 5 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/Draco.Editor.Web/app/ts/metadata.ts diff --git a/src/Draco.Editor.Web/app/build.js b/src/Draco.Editor.Web/app/build.js index 9c765f616..a6a00113a 100644 --- a/src/Draco.Editor.Web/app/build.js +++ b/src/Draco.Editor.Web/app/build.js @@ -9,6 +9,7 @@ import JSON5 from 'json5'; import YAML from 'yaml'; import { defineConfig, build as viteBuild } from 'vite'; import { convertTheme } from './theme-converter.js'; +import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector'; // This file manage the build process of the webapp. const distDir = '../wwwroot'; @@ -84,7 +85,13 @@ await build({ '.png': 'dataurl' }, inject: ['ts/process.ts'], - plugins: [wasmPlugin], + plugins: [wasmPlugin, + esbuildPluginVersionInjector( + { + versionOrCurrentDate: 'current-date', + filter: /metadata.ts$/, + }) + ], external: ['dotnet.wasm'] }); diff --git a/src/Draco.Editor.Web/app/package-lock.json b/src/Draco.Editor.Web/app/package-lock.json index e5a3122c6..e3340920b 100644 --- a/src/Draco.Editor.Web/app/package-lock.json +++ b/src/Draco.Editor.Web/app/package-lock.json @@ -26,6 +26,7 @@ "@typescript-eslint/eslint-plugin": "^5.42.1", "@typescript-eslint/parser": "^5.42.1", "esbuild": "^0.15.13", + "esbuild-plugin-version-injector": "^1.2.0", "eslint": "^8.27.0", "json5": "^2.2.1", "node-ts": "^5.1.2", @@ -384,6 +385,16 @@ "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", "dev": true }, + "node_modules/@sapphire/result": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.6.4.tgz", + "integrity": "sha512-o6rAnNbtumhR4Iy9t1p3xtOG9WtfO2OyyyaBrGUNThmhqf1cwvl5CO3/E0Hd66qdkuSqpJqC9TnnGzTmSoDd6A==", + "dev": true, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -1309,6 +1320,19 @@ "node": ">=12" } }, + "node_modules/esbuild-plugin-version-injector": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/esbuild-plugin-version-injector/-/esbuild-plugin-version-injector-1.2.0.tgz", + "integrity": "sha512-AXU8/RgtpUNrI8c7LAnWXS+6gtuVkOrykYCzu0MV8K0kCPN4LljnXgPqus1Z6kHr4ARRA8LQwzaiTDOlHdcnMA==", + "dev": true, + "dependencies": { + "@sapphire/result": "^2.6.4" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/esbuild-sunos-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", @@ -3192,6 +3216,12 @@ } } }, + "@sapphire/result": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.6.4.tgz", + "integrity": "sha512-o6rAnNbtumhR4Iy9t1p3xtOG9WtfO2OyyyaBrGUNThmhqf1cwvl5CO3/E0Hd66qdkuSqpJqC9TnnGzTmSoDd6A==", + "dev": true + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -3766,6 +3796,15 @@ "dev": true, "optional": true }, + "esbuild-plugin-version-injector": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/esbuild-plugin-version-injector/-/esbuild-plugin-version-injector-1.2.0.tgz", + "integrity": "sha512-AXU8/RgtpUNrI8c7LAnWXS+6gtuVkOrykYCzu0MV8K0kCPN4LljnXgPqus1Z6kHr4ARRA8LQwzaiTDOlHdcnMA==", + "dev": true, + "requires": { + "@sapphire/result": "^2.6.4" + } + }, "esbuild-sunos-64": { "version": "0.15.13", "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", diff --git a/src/Draco.Editor.Web/app/package.json b/src/Draco.Editor.Web/app/package.json index f552197c1..663a3cda2 100644 --- a/src/Draco.Editor.Web/app/package.json +++ b/src/Draco.Editor.Web/app/package.json @@ -26,6 +26,7 @@ "@typescript-eslint/eslint-plugin": "^5.42.1", "@typescript-eslint/parser": "^5.42.1", "esbuild": "^0.15.13", + "esbuild-plugin-version-injector": "^1.2.0", "eslint": "^8.27.0", "json5": "^2.2.1", "node-ts": "^5.1.2", diff --git a/src/Draco.Editor.Web/app/ts/cache.ts b/src/Draco.Editor.Web/app/ts/cache.ts index 82c9bfa2c..a91f6846f 100644 --- a/src/Draco.Editor.Web/app/ts/cache.ts +++ b/src/Draco.Editor.Web/app/ts/cache.ts @@ -1,4 +1,5 @@ import { blobToBase64 } from './helpers.js'; +import { buildDate } from './metadata.js'; const elements = []; @@ -15,8 +16,23 @@ export function getDownloadViewElement() { } export async function downloadAssemblies(cfg: unknown) { + try { + const cache = await caches.open('assembly-cache'); + const result = await cache.match('appBuildDate'); + const cachedDate = await result.text(); + console.log(`Current build: ${buildDate} cache build: ${cachedDate}`); + + if (result == null || cachedDate != buildDate) { + console.log('Cache nuked.'); + await caches.delete('assembly-cache'); + const newCache = await caches.open('assembly-cache'); + await newCache.put('appBuildDate', new Response(buildDate)); + } + } catch (e) { + console.log('Could not open cache: ', e); + } const assets = cfg['assets']; - if (assets != null) { + if (assets != null) { const promises = assets.map(async (asset) => { if (asset['buffer'] == null) { await downloadAssembly(cfg['assemblyRootFolder'], asset); @@ -40,9 +56,9 @@ async function downloadAssembly(dlPath: string, asset: unknown): Promise { } catch (e) { console.log('Could not open cache: ', e); } - console.log('Cache miss:'+dlPath); + console.log(`Cache miss: ${dlPath}`); setDownloadViewVisible(true); - const progresses = elements.map( (element) => { + const progresses = elements.map((element) => { const progressContainer = document.createElement('div'); const progressText = document.createElement('span'); progressText.classList.add('monaco-editor'); @@ -55,7 +71,7 @@ async function downloadAssembly(dlPath: string, asset: unknown): Promise { return progress; }); const assemblyBlob = await progressFetch(dlPath + '/' + asset['name'], (loaded, total) => { - progresses.forEach(progress=> { + progresses.forEach(progress => { progress.max = total; progress.value = loaded; }); @@ -66,7 +82,7 @@ async function downloadAssembly(dlPath: string, asset: unknown): Promise { if (cache != null) { await cache.put(asset['name'], response); } - progresses.forEach(progress=> { + progresses.forEach(progress => { progress.parentElement.remove(); }); } @@ -75,7 +91,7 @@ function wait(milliseconds) { return new Promise(resolve => setTimeout(resolve, milliseconds)); } -async function progressFetch(url: string, onProgress: (loaded: number, total: number) => void) : Promise { +async function progressFetch(url: string, onProgress: (loaded: number, total: number) => void): Promise { const response = await fetch(url); const contentLength = response.headers.get('content-length'); const total = parseInt(contentLength, 10); @@ -85,7 +101,7 @@ async function progressFetch(url: string, onProgress: (loaded: number, total: nu async start(controller) { const reader = response.body.getReader(); while (true) { - const {done, value} = await reader.read(); + const { done, value } = await reader.read(); if (done) break; loaded += value.byteLength; onProgress(loaded, total); diff --git a/src/Draco.Editor.Web/app/ts/metadata.ts b/src/Draco.Editor.Web/app/ts/metadata.ts new file mode 100644 index 000000000..937f27878 --- /dev/null +++ b/src/Draco.Editor.Web/app/ts/metadata.ts @@ -0,0 +1,7 @@ +/** + * The current version that you are currently using. + * + * Note to developers: This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild + */ +// eslint-disable-next-line @typescript-eslint/no-inferrable-types +export const buildDate: string = '[VI]{{inject}}[/VI]'; From 10d26b5f780c898aac17f48337e15cde41a2167b Mon Sep 17 00:00:00 2001 From: Binto86 <76395771+Binto86@users.noreply.github.com> Date: Tue, 5 Sep 2023 07:41:31 +0200 Subject: [PATCH 5/5] Documentation comments from metadata (#290) * Added XmlDocument to MetadataAssemblySymbol * Updated the way documentation is passed to MetadataReference * First docs from metadata test * Documentation for types works * Documentation is loaded for most types of symbols * More structure work * Generics work for types * Added edge case test * Generics work * Started on syntax tree for documentation * Added parameters * Added structured documentation to Symbol * Work on XmlDocumentationExtractor * Returning XElement instead of string * Added paramref * Added code tag * Updated formating * Update DocumentationCommentsTests.cs * Links work * Fixes * Update DocumentationCommentsTests.cs * Type parametrs support * Added tests for type params * Update XmlDocumentationExtractor.cs * PR comments * Added markdown documentation structure * After merge cleanup * Added documentation * cleanup * PR comments * sections are not responsible for generating their own markdown and xml * Remove most of sections * Update src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs Co-authored-by: LPeter1997 * Update MetadataMethodSymbol.cs * Added PrefixedDocumentationFullName * Removed paramref and typeparamref as separate nodes * Removed RawDocumentation * PR comments * Refactor XmlDocumentationExtractor * PR comments * PR comments * PR comments * Update XmlDocumentationExtractor.cs * Update src/Draco.Compiler/Internal/Symbols/Synthetized/PrimitiveTypeSymbol.cs Co-authored-by: LPeter1997 * PR comments * Update SourceModuleSymbol.cs * Update src/Draco.Compiler/Internal/Symbols/Source/SourceModuleSymbol.cs Co-authored-by: LPeter1997 * PR comments * Update src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs Co-authored-by: LPeter1997 * PR comments * PR comments * Update src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs Co-authored-by: LPeter1997 * Update src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs Co-authored-by: LPeter1997 * PR comments * PR comments * Last cleanup --------- Co-authored-by: LPeter1997 --- .../Semantics/DocumentationCommentsTests.cs | 593 +++++++++++++++++- .../Semantics/TypeCheckingTests.cs | 42 ++ src/Draco.Compiler.Tests/TestUtilities.cs | 9 +- src/Draco.Compiler/Api/Compilation.cs | 2 +- src/Draco.Compiler/Api/MetadataReference.cs | 22 +- src/Draco.Compiler/Api/Semantics/Symbol.cs | 2 +- .../Documentation/DocumentationElement.cs | 130 ++++ .../Documentation/DocumentationSection.cs | 59 ++ .../MarkdownDocumentationExtractor.cs | 31 + .../Extractors/XmlDocumentationExtractor.cs | 116 ++++ .../Documentation/SymbolDocumentation.cs | 126 ++++ .../Metadata/MetadataAssemblySymbol.cs | 10 +- .../Symbols/Metadata/MetadataFieldSymbol.cs | 14 + .../Symbols/Metadata/MetadataMethodSymbol.cs | 14 + .../Metadata/MetadataNamespaceSymbol.cs | 24 + .../Metadata/MetadataPropertySymbol.cs | 14 + .../Metadata/MetadataStaticClassSymbol.cs | 14 + .../Symbols/Metadata/MetadataSymbol.cs | 73 ++- .../Symbols/Metadata/MetadataTypeSymbol.cs | 14 + .../Symbols/Source/SourceFunctionSymbol.cs | 10 +- .../Symbols/Source/SourceGlobalSymbol.cs | 10 +- .../Symbols/Source/SourceLocalSymbol.cs | 10 +- .../Symbols/Source/SourceModuleSymbol.cs | 21 +- src/Draco.Compiler/Internal/Symbols/Symbol.cs | 28 +- .../MetadataBackedPrimitiveTypeSymbol.cs | 5 +- .../Internal/Symbols/TypeParameterSymbol.cs | 2 +- .../Internal/Symbols/TypeVariable.cs | 1 - 27 files changed, 1367 insertions(+), 29 deletions(-) create mode 100644 src/Draco.Compiler/Internal/Documentation/DocumentationElement.cs create mode 100644 src/Draco.Compiler/Internal/Documentation/DocumentationSection.cs create mode 100644 src/Draco.Compiler/Internal/Documentation/Extractors/MarkdownDocumentationExtractor.cs create mode 100644 src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs create mode 100644 src/Draco.Compiler/Internal/Documentation/SymbolDocumentation.cs diff --git a/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs b/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs index 276d72806..00d157cd7 100644 --- a/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs +++ b/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs @@ -1,11 +1,54 @@ +using System.Collections.Immutable; +using System.Text; +using System.Xml; +using System.Xml.Linq; +using Draco.Compiler.Api; using Draco.Compiler.Api.Syntax; using Draco.Compiler.Internal.Symbols; using static Draco.Compiler.Api.Syntax.SyntaxFactory; +using static Draco.Compiler.Tests.TestUtilities; namespace Draco.Compiler.Tests.Semantics; public sealed class DocumentationCommentsTests : SemanticTestsBase { + private static string CreateXmlDocComment(string originalXml) + { + var result = new StringBuilder(); + originalXml = originalXml.ReplaceLineEndings("\n"); + foreach (var line in originalXml.Split('\n')) + { + result.Append($"/// {line}{Environment.NewLine}"); + } + return result.ToString(); + } + + private static string AddDocumentationTag(string insideXml) => $""" + + {insideXml} + + """; + + private static string PrettyXml(XElement element) + { + var stringBuilder = new StringBuilder(); + + var settings = new XmlWriterSettings() + { + OmitXmlDeclaration = true, + Indent = true, + IndentChars = string.Empty, + NewLineOnAttributes = false, + }; + + using (var xmlWriter = XmlWriter.Create(stringBuilder, settings)) + { + element.Save(xmlWriter); + } + + return stringBuilder.ToString(); + } + [Theory] [InlineData("This is doc comment")] [InlineData(""" @@ -36,7 +79,7 @@ public void FunctionDocumentationComment(string docComment) // Assert Assert.Empty(semanticModel.Diagnostics); - Assert.Equal(docComment, funcSym.Documentation); + Assert.Equal(docComment, funcSym.Documentation.ToMarkdown()); } [Theory] @@ -68,7 +111,7 @@ public void VariableDocumentationComment(string docComment) // Assert Assert.Empty(semanticModel.Diagnostics); - Assert.Equal(docComment, xSym.Documentation); + Assert.Equal(docComment, xSym.Documentation.ToMarkdown()); } [Theory] @@ -104,6 +147,550 @@ public void LabelDocumentationComment(string docComment) // Assert Assert.Empty(semanticModel.Diagnostics); - Assert.Equal(string.Empty, labelSym.Documentation); + Assert.Equal(string.Empty, labelSym.Documentation.ToMarkdown()); + } + + [Theory] + [InlineData("This is doc comment")] + [InlineData(""" + This is + multiline doc comment + """)] + public void ModuleDocumentationComment(string docComment) + { + // /// This is doc comment + // module documentedModule{ + // public var Foo = 0; + // } + // + // func foo(){ + // var x = documentedModule.Foo; + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit( + WithDocumentation(ModuleDeclaration( + "documentedModule", + VariableDeclaration(Api.Semantics.Visibility.Public, "Foo", null, LiteralExpression(0))), + docComment), + FunctionDeclaration( + "foo", + ParameterList(), + null, + BlockFunctionBody( + DeclarationStatement(VariableDeclaration("x", null, MemberExpression(NameExpression("documentedModule"), "Foo"))))))); + + var moduleRef = tree.FindInChildren(0).Accessed; + + // Act + var compilation = CreateCompilation(tree); + var semanticModel = compilation.GetSemanticModel(tree); + + var moduleSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(moduleRef)); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(docComment, moduleSym.Documentation.ToMarkdown()); + } + + [Fact] + public void TypeDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var docs = " Documentation for TestClass "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + /// {{docs}} + public class TestClass { } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(typeSym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void NestedTypeDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var docs = " Documentation for NestedTestClass "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + public class TestClass + { + /// {{docs}} + public class NestedTestClass { } + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var nestedTypeSym = GetMemberSymbol(typeSym, "NestedTestClass"); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(nestedTypeSym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void StaticTypeDocumentationFromMetadata() + { + // func main() { + // var x = TestClass.foo; + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(DeclarationStatement(VariableDeclaration("x", null, MemberExpression(NameExpression("TestClass"), "foo"))))))); + + var docs = " Documentation for TestClass "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + /// {{docs}} + public static class TestClass + { + // Just so i can use it in draco + public static int foo = 0; + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var @class = tree.FindInChildren(0).Accessed; + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(@class)); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(typeSym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void MethodDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var docs = " Documentation for TestMethod "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + public class TestClass + { + /// {{docs}} + public void TestMethod(int arg1, string arg2) { } + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var methodSym = GetMemberSymbol(typeSym, "TestMethod"); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(methodSym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void NoParamsMethodDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var docs = " Documentation for TestMethod "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + using System; + + public class TestClass + { + /// {{docs}} + public void TestMethod() { } + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var methodSym = GetMemberSymbol(typeSym, "TestMethod"); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(methodSym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void FieldDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var docs = " Documentation for TestField "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + public class TestClass + { + /// {{docs}} + public int TestField = 5; + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var fieldSym = GetMemberSymbol(typeSym, "TestField"); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(fieldSym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void PropertyDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var docs = " Documentation for TestProperty "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + public class TestClass + { + /// {{docs}} + public int TestProperty { get; } + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var propertySym = GetMemberSymbol(typeSym, "TestProperty"); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(docs), PrettyXml(propertySym.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void GenericsDocumentationFromMetadata() + { + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit(FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(GenericExpression(NameExpression("TestClass"), NameType("int32")))))))); + + var classDocs = " Documentation for TestClass "; + var methodDocs = " Documentation for TestMethod "; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + using System; + + /// {{classDocs}} + public class TestClass + { + /// {{methodDocs}} + public void TestMethod(T arg1, T arg2, U arg3) { } + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var methodSym = GetMemberSymbol(typeSym, "TestMethod"); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(classDocs), PrettyXml(typeSym.GenericDefinition!.Documentation.ToXml()), ignoreLineEndingDifferences: true); + Assert.Equal(AddDocumentationTag(methodDocs), PrettyXml(methodSym.GenericDefinition!.Documentation.ToXml()), ignoreLineEndingDifferences: true); + } + + [Fact] + public void XmlDocumentationExtractorTest() + { + // import TestNamespace; + // func main() { + // TestClass(); + // } + + // Arrange + var tree = SyntaxTree.Create(CompilationUnit( + ImportDeclaration("TestNamespace"), + FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody(ExpressionStatement(CallExpression(NameExpression("TestClass"))))))); + + var originalDocs = """ + Documentation for TestMethod, which is in , random generic link + Documentation for arg1 + Documentation for arg2 + Useless type param + + var x = 0; + void Foo(int z) { } + + added to , is not used + """; + + var xmlStream = new MemoryStream(); + + var testRef = CompileCSharpToMetadataRef($$""" + namespace TestNamespace; + public class TestClass + { + {{CreateXmlDocComment(originalDocs)}} + public int TestMethod(int arg1, int arg2) => arg1 + arg2; + } + """, xmlStream: xmlStream).WithDocumentation(xmlStream); + + var call = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(testRef) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var typeSym = GetInternalSymbol(semanticModel.GetReferencedSymbol(call)).ReturnType; + var methodSym = GetMemberSymbol(typeSym, "TestMethod"); + + var xmlGeneratedDocs = """ + Documentation for TestMethod, which is in , random generic link + Documentation for arg1 + Documentation for arg2 + Useless type param + var x = 0; + void Foo(int z) { } + + added to , is not used + """; + + var mdGeneratedDocs = """ + Documentation for TestMethod, which is in [TestNamespace.TestClass](), random generic link [System.Collections.Generic.List]() + # parameters + - arg1: Documentation for arg1 + - arg2: Documentation for arg2 + # type parameters + - T: Useless type param + ```cs + var x = 0; + void Foo(int z) { } + ``` + # returns + [arg1]() added to [arg2](), [T]() is not used + """; + + var resultXml = PrettyXml(methodSym.Documentation.ToXml()); + var resultMd = methodSym.Documentation.ToMarkdown(); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(AddDocumentationTag(xmlGeneratedDocs), resultXml, ignoreLineEndingDifferences: true); + Assert.Equal(mdGeneratedDocs, resultMd, ignoreLineEndingDifferences: true); + } + + [Fact] + public void MarkdownDocumentationExtractorTest() + { + // Arrange + var originalDocs = """ + Documentation for TestMethod, which is in [TestNamespace.TestClass](), random generic link [System.Collections.Generic.List]() + # parameters + - arg1: Documentation for arg1 + - arg2: Documentation for arg2 + # type parameters + - T: Useless type param + ```cs + var x = 0; + void Foo(int z) { } + ``` + # returns + [arg1]() added to [arg2](), [T]() is not used + """; + + // /// documentation + // func TestMethod() { } + + var tree = SyntaxTree.Create(CompilationUnit( + WithDocumentation(FunctionDeclaration( + "TestMethod", + ParameterList(), + null, + BlockFunctionBody()), originalDocs))); + + var testMethodDecl = tree.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(tree), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .ToImmutableArray()); + var semanticModel = compilation.GetSemanticModel(tree); + + var methodSym = GetInternalSymbol(semanticModel.GetDeclaredSymbol(testMethodDecl)); + + var resultMd = methodSym.Documentation.ToMarkdown(); + + // Assert + Assert.Empty(semanticModel.Diagnostics); + Assert.Equal(originalDocs, resultMd); + Assert.Equal(methodSym.Documentation.ToMarkdown(), resultMd); } } diff --git a/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs b/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs index 9c0e7657b..9ba838701 100644 --- a/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs +++ b/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs @@ -2179,4 +2179,46 @@ public void IndexerWitingOverloadedCall() Assert.Single(diags); AssertDiagnostic(diags, TypeCheckingErrors.TypeMismatch); } + + [Fact] + public void GettingTypeFromReference() + { + // func main(){ + // var x = FooModule.foo; + // } + + var main = SyntaxTree.Create(CompilationUnit( + FunctionDeclaration( + "main", + ParameterList(), + null, + BlockFunctionBody( + DeclarationStatement(VariableDeclaration("x", null, MemberExpression(NameExpression("FooModule"), "foo"))))))); + + var fooRef = CompileCSharpToMetadataRef(""" + using System; + public static class FooModule{ + public static Random foo; + } + """); + + var xDecl = main.FindInChildren(0); + + // Act + var compilation = Compilation.Create( + syntaxTrees: ImmutableArray.Create(main), + metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All + .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes))) + .Append(fooRef) + .ToImmutableArray()); + + var semanticModel = compilation.GetSemanticModel(main); + + var diags = semanticModel.Diagnostics; + var xSym = GetInternalSymbol(semanticModel.GetDeclaredSymbol(xDecl)); + + // Assert + Assert.Empty(diags); + Assert.Equal("System.Random", xSym.Type.FullName); + } } diff --git a/src/Draco.Compiler.Tests/TestUtilities.cs b/src/Draco.Compiler.Tests/TestUtilities.cs index 2296f21b1..db26c1398 100644 --- a/src/Draco.Compiler.Tests/TestUtilities.cs +++ b/src/Draco.Compiler.Tests/TestUtilities.cs @@ -12,13 +12,13 @@ internal static class TestUtilities public static string ToPath(params string[] parts) => Path.GetFullPath(Path.Combine(parts)); - public static MetadataReference CompileCSharpToMetadataRef(string code, string assemblyName = DefaultAssemblyName, IEnumerable? aditionalReferences = null) + public static MetadataReference CompileCSharpToMetadataRef(string code, string assemblyName = DefaultAssemblyName, IEnumerable? aditionalReferences = null, Stream? xmlStream = null) { - var stream = CompileCSharpToStream(code, assemblyName, aditionalReferences); + var stream = CompileCSharpToStream(code, assemblyName, aditionalReferences, xmlStream); return MetadataReference.FromPeStream(stream); } - public static Stream CompileCSharpToStream(string code, string assemblyName = DefaultAssemblyName, IEnumerable? aditionalReferences = null) + public static Stream CompileCSharpToStream(string code, string assemblyName = DefaultAssemblyName, IEnumerable? aditionalReferences = null, Stream? xmlStream = null) { aditionalReferences ??= Enumerable.Empty(); var sourceText = SourceText.From(code, Encoding.UTF8); @@ -35,10 +35,11 @@ public static Stream CompileCSharpToStream(string code, string assemblyName = De options: new CSharpCompilationOptions(Microsoft.CodeAnalysis.OutputKind.DynamicallyLinkedLibrary)); var stream = new MemoryStream(); - var emitResult = compilation.Emit(stream); + var emitResult = compilation.Emit(stream, xmlDocumentationStream: xmlStream); Assert.True(emitResult.Success); stream.Position = 0; + if (xmlStream is not null) xmlStream.Position = 0; return stream; } } diff --git a/src/Draco.Compiler/Api/Compilation.cs b/src/Draco.Compiler/Api/Compilation.cs index 5473df3fd..ed086906f 100644 --- a/src/Draco.Compiler/Api/Compilation.cs +++ b/src/Draco.Compiler/Api/Compilation.cs @@ -334,7 +334,7 @@ internal Binder GetBinder(Symbol symbol) private ImmutableDictionary BuildMetadataAssemblies() => this.MetadataReferences .ToImmutableDictionary( r => r, - r => new MetadataAssemblySymbol(this, r.MetadataReader)); + r => new MetadataAssemblySymbol(this, r.MetadataReader, r.Documentation)); private ModuleSymbol BuildRootModule() => new MergedModuleSymbol( containingSymbol: null, name: string.Empty, diff --git a/src/Draco.Compiler/Api/MetadataReference.cs b/src/Draco.Compiler/Api/MetadataReference.cs index 927538420..824ae2aba 100644 --- a/src/Draco.Compiler/Api/MetadataReference.cs +++ b/src/Draco.Compiler/Api/MetadataReference.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using System.Xml; namespace Draco.Compiler.Api; @@ -16,6 +17,11 @@ public abstract class MetadataReference /// public abstract MetadataReader MetadataReader { get; } + /// + /// The documentation for this reference. + /// + public abstract XmlDocument? Documentation { get; } + /// /// Creates a metadata reference from the given assembly. /// @@ -47,13 +53,27 @@ public static MetadataReference FromPeStream(Stream peStream) return new MetadataReaderReference(metadataReader); } + /// + /// Adds xml documentation to this metadata reference. + /// + /// The stream with the xml documentation. + /// New metadata reference containing xml documentation. + public MetadataReference WithDocumentation(Stream xmlStream) + { + var doc = new XmlDocument(); + doc.Load(xmlStream); + return new MetadataReaderReference(this.MetadataReader, doc); + } + private sealed class MetadataReaderReference : MetadataReference { public override MetadataReader MetadataReader { get; } + public override XmlDocument? Documentation { get; } - public MetadataReaderReference(MetadataReader metadataReader) + public MetadataReaderReference(MetadataReader metadataReader, XmlDocument? documentation = null) { this.MetadataReader = metadataReader; + this.Documentation = documentation; } } } diff --git a/src/Draco.Compiler/Api/Semantics/Symbol.cs b/src/Draco.Compiler/Api/Semantics/Symbol.cs index 38ed6b6c1..33e7d5e6d 100644 --- a/src/Draco.Compiler/Api/Semantics/Symbol.cs +++ b/src/Draco.Compiler/Api/Semantics/Symbol.cs @@ -176,7 +176,7 @@ internal abstract class SymbolBase : ISymbol public bool IsError => this.Symbol.IsError; public bool IsSpecialName => this.Symbol.IsSpecialName; public Location? Definition => this.Symbol.DeclaringSyntax?.Location; - public string Documentation => this.Symbol.Documentation; + public string Documentation => this.Symbol.Documentation.ToMarkdown(); public IEnumerable Members => this.Symbol.Members.Select(x => x.ToApiSymbol()); public SymbolBase(Symbol symbol) diff --git a/src/Draco.Compiler/Internal/Documentation/DocumentationElement.cs b/src/Draco.Compiler/Internal/Documentation/DocumentationElement.cs new file mode 100644 index 000000000..dab7a4a91 --- /dev/null +++ b/src/Draco.Compiler/Internal/Documentation/DocumentationElement.cs @@ -0,0 +1,130 @@ +using System.Collections.Immutable; +using System.Linq; +using System.Xml.Linq; +using Draco.Compiler.Internal.Symbols; +using Draco.Compiler.Internal.Symbols.Metadata; + +namespace Draco.Compiler.Internal.Documentation; + +/// +/// Represents single documentation element. +/// +internal abstract record class DocumentationElement +{ + /// + /// Creates a markdown representation of this documentation element. + /// + /// The documentation in markdown format. + public abstract string ToMarkdown(); + + /// + /// Creates an XML representation of this documentation element. + /// + /// The documentation in XML format. + public abstract XNode ToXml(); +} + +/// +/// Represents regular text inside documentation. +/// +/// The text represented by this element. +internal sealed record class TextDocumentationElement(string Text) : DocumentationElement +{ + public override string ToMarkdown() => this.Text; + + public override XText ToXml() => new XText(this.Text); +} + +/// +/// Any kind of symbol reference. +/// +/// The referenced symbol. +/// The inner s of this . +internal abstract record class SymbolDocumentationElement(Symbol? Symbol, ImmutableArray Elements) : DocumentationElement +{ + protected string Name => this.Symbol?.Name ?? string.Empty; + protected string? FilePath => this.Symbol?.DeclaringSyntax?.Location.SourceText.Path?.LocalPath; + // Note: For future when we will probably want to optionally return link to the param + public string Link => this.FilePath is null + ? string.Empty + : $"{this.FilePath}#L{this.Symbol?.DeclaringSyntax?.Location.Range?.Start.Line}"; + + public override string ToMarkdown() => $"- {this.Name}: {string.Join("", this.Elements.Select(x => x.ToMarkdown()))}"; +} + +/// +/// A single parameter. +/// +/// The parameter symbol. +/// The s that are contained in the description of this parameter. +internal sealed record class ParameterDocumentationElement(ParameterSymbol? Parameter, ImmutableArray Elements) : SymbolDocumentationElement(Parameter, Elements) +{ + public override XElement ToXml() => new XElement("param", + new XAttribute("name", this.Name), + this.Elements.Select(x => x.ToXml())); +} + +/// +/// A single type parameter. +/// +/// The type parameter symbol. +/// The s that are contained in the description of this type parameter. +internal sealed record class TypeParameterDocumentationElement(TypeParameterSymbol? TypeParameter, ImmutableArray Elements) : SymbolDocumentationElement(TypeParameter, Elements) +{ + public override XElement ToXml() => new XElement("typeparam", + new XAttribute("name", this.Name), + this.Elements.Select(x => x.ToXml())); +} + +/// +/// A link to some symbol in code. +/// +/// The symbol that is linked. +/// The text that should be displayed in the link. +internal sealed record class ReferenceDocumentationElement : DocumentationElement +{ + public Symbol? ReferencedSymbol { get; } + public string DisplayText { get; } + + private string? FilePath => this.ReferencedSymbol?.DeclaringSyntax?.Location.SourceText.Path?.LocalPath; + private string Link => this.FilePath is null + ? string.Empty + : $"{this.FilePath}#L{this.ReferencedSymbol?.DeclaringSyntax?.Location.Range?.Start.Line}"; + + public ReferenceDocumentationElement(Symbol? referencedSymbol, string? displayText = null) + { + this.ReferencedSymbol = referencedSymbol; + this.DisplayText = displayText ?? GetDisplayText(referencedSymbol); + } + + private static string GetDisplayText(Symbol? symbol) => symbol switch + { + ParameterSymbol or TypeParameterSymbol => symbol?.Name ?? string.Empty, + _ => symbol?.FullName ?? string.Empty, + }; + + public override string ToMarkdown() => $"[{this.DisplayText}]({this.Link})"; + + public override XElement ToXml() => this.ReferencedSymbol switch + { + ParameterSymbol => new XElement("paramref", new XAttribute("name", this.DisplayText)), + TypeParameterSymbol => new XElement("typeparamref", new XAttribute("name", this.DisplayText)), + _ => new XElement("see", new XAttribute("cref", MetadataSymbol.GetPrefixedDocumentationName(this.ReferencedSymbol))), + }; +} + +/// +/// Code element. +/// +/// The code. +/// The ID of the programming language this code is written in. +internal sealed record class CodeDocumentationElement(string Code, string Lang) : DocumentationElement +{ + public override string ToMarkdown() => $""" + ```{this.Lang} + {this.Code} + ``` + """; + + public override XNode ToXml() => new XElement("code", this.Code); +} diff --git a/src/Draco.Compiler/Internal/Documentation/DocumentationSection.cs b/src/Draco.Compiler/Internal/Documentation/DocumentationSection.cs new file mode 100644 index 000000000..d4abcb090 --- /dev/null +++ b/src/Draco.Compiler/Internal/Documentation/DocumentationSection.cs @@ -0,0 +1,59 @@ +using System.Collections.Immutable; + +namespace Draco.Compiler.Internal.Documentation; + +/// +/// Represents a section of the documentation. +/// +internal sealed class DocumentationSection +{ + public string Name { get; } + public SectionKind Kind { get; } + public ImmutableArray Elements { get; } + + private DocumentationSection(SectionKind kind, string name, ImmutableArray elements) + { + this.Kind = kind; + this.Name = name.ToLowerInvariant(); + this.Elements = elements; + } + + public DocumentationSection(SectionKind kind, ImmutableArray elements) + : this(kind, GetSectionName(kind), elements) + { + // NOTE: GetSectionName throws on Other + } + + public DocumentationSection(string name, ImmutableArray elements) + : this(GetSectionKind(name), name, elements) + { + } + + private static string GetSectionName(SectionKind kind) => kind switch + { + SectionKind.Summary => "summary", + SectionKind.Parameters => "parameters", + SectionKind.TypeParameters => "type parameters", + SectionKind.Code => "code", + _ => throw new System.ArgumentOutOfRangeException(nameof(kind)), + }; + + private static SectionKind GetSectionKind(string? name) => name switch + { + "summary" => SectionKind.Summary, + "parameters" => SectionKind.Parameters, + "type parameters" => SectionKind.TypeParameters, + "code" => SectionKind.Code, + _ => SectionKind.Other, + }; +} + +// Note: The values of the sections are used for ordering from smallest to highest +internal enum SectionKind +{ + Summary = 1, + Parameters = 2, + TypeParameters = 3, + Code = 4, + Other = 5, +} diff --git a/src/Draco.Compiler/Internal/Documentation/Extractors/MarkdownDocumentationExtractor.cs b/src/Draco.Compiler/Internal/Documentation/Extractors/MarkdownDocumentationExtractor.cs new file mode 100644 index 000000000..ed453fab7 --- /dev/null +++ b/src/Draco.Compiler/Internal/Documentation/Extractors/MarkdownDocumentationExtractor.cs @@ -0,0 +1,31 @@ +using Draco.Compiler.Internal.Symbols; + +namespace Draco.Compiler.Internal.Documentation.Extractors; + +/// +/// Extracts markdown into . +/// +internal sealed class MarkdownDocumentationExtractor +{ + /// + /// Extracts the markdown documentation from . + /// + /// The extracted markdown as . + public static SymbolDocumentation Extract(Symbol containingSymbol) => + new MarkdownDocumentationExtractor(containingSymbol.RawDocumentation, containingSymbol).Extract(); + + private readonly string markdown; + private readonly Symbol containingSymbol; + + private MarkdownDocumentationExtractor(string markdown, Symbol containingSymbol) + { + this.markdown = markdown; + this.containingSymbol = containingSymbol; + } + + /// + /// Extracts the . + /// + /// The extracted markdown as . + private SymbolDocumentation Extract() => new MarkdownSymbolDocumentation(this.markdown); +} diff --git a/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs b/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs new file mode 100644 index 000000000..587ea6f43 --- /dev/null +++ b/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs @@ -0,0 +1,116 @@ +using System.Collections.Immutable; +using System.Linq; +using System.Xml; +using Draco.Compiler.Internal.Symbols; +using Draco.Compiler.Internal.Symbols.Metadata; +using Draco.Compiler.Internal.Symbols.Synthetized; + +namespace Draco.Compiler.Internal.Documentation.Extractors; + +/// +/// Extracts XML into . +/// +internal sealed class XmlDocumentationExtractor +{ + /// + /// Extracts the xml documentation from . + /// + /// The extracted XMl as . + public static SymbolDocumentation Extract(Symbol containingSymbol) => + new XmlDocumentationExtractor(containingSymbol.RawDocumentation, containingSymbol).Extract(); + + private readonly string xml; + private readonly Symbol containingSymbol; + private MetadataAssemblySymbol Assembly => this.containingSymbol.AncestorChain.OfType().First(); + + private XmlDocumentationExtractor(string xml, Symbol containingSymbol) + { + this.xml = xml; + this.containingSymbol = containingSymbol; + } + + /// + /// Extracts the . + /// + /// The extracted XMl as . + private SymbolDocumentation Extract() + { + // TODO: exception + // para + // list + // c + // see - not cref links + // seealso + // b ? + // i ? + + var xml = $""" + + {this.xml} + + """; + var doc = new XmlDocument(); + doc.LoadXml(xml); + + var raw = doc.DocumentElement!.ChildNodes + .Cast() + .Select(this.ExtractSectionOrElement); + + var sections = raw.OfType().ToList(); + var elements = raw.OfType(); + + foreach (var grouped in elements.GroupBy(x => x.GetType())) + { + if (grouped.Key == typeof(ParameterDocumentationElement)) sections.Add(new DocumentationSection(SectionKind.Parameters, grouped.ToImmutableArray())); + else if (grouped.Key == typeof(TypeParameterDocumentationElement)) sections.Add(new DocumentationSection(SectionKind.TypeParameters, grouped.ToImmutableArray())); + } + return new SymbolDocumentation(sections.ToImmutableArray()); + } + + private object ExtractSectionOrElement(XmlNode node) => node.Name switch + { + "param" => new ParameterDocumentationElement(this.GetParameter(node.Attributes?["name"]?.Value ?? string.Empty), this.ExtractElementsFromNode(node)), + "typeparam" => new TypeParameterDocumentationElement(this.GetTypeParameter(node.Attributes?["name"]?.Value ?? string.Empty), this.ExtractElementsFromNode(node)), + "code" => new DocumentationSection(SectionKind.Code, ImmutableArray.Create(this.ExtractElement(node))), + "summary" => new DocumentationSection(SectionKind.Summary, this.ExtractElementsFromNode(node)), + _ => new DocumentationSection(node.Name, this.ExtractElementsFromNode(node)), + }; + + private DocumentationElement ExtractElement(XmlNode node) => node.LocalName switch + { + "#text" => new TextDocumentationElement(node.InnerText), + "see" => this.ConstructReference(node), + "paramref" => new ReferenceDocumentationElement(this.GetParameter(node.Attributes?["name"]?.Value ?? string.Empty)), + "typeparamref" => new ReferenceDocumentationElement(this.GetTypeParameter(node.Attributes?["name"]?.Value ?? string.Empty)), + "code" => new CodeDocumentationElement(node.InnerXml.Trim('\r', '\n'), "cs"), + _ => new TextDocumentationElement(node.InnerText), + }; + + private ImmutableArray ExtractElementsFromNode(XmlNode node) + { + var elements = ImmutableArray.CreateBuilder(); + foreach (XmlNode child in node.ChildNodes) elements.Add(this.ExtractElement(child)); + return elements.ToImmutable(); + } + + private ReferenceDocumentationElement ConstructReference(XmlNode node) + { + var cref = node.Attributes?["cref"]?.Value; + var symbol = this.GetSymbolFromDocumentationName(cref ?? string.Empty) + // NOTE: The first two characters of the link is the documentation prefix + ?? new PrimitiveTypeSymbol(cref?[2..] ?? string.Empty, false); + return new ReferenceDocumentationElement(symbol, string.IsNullOrEmpty(node.InnerText) ? null : node.InnerText); + } + + private Symbol? GetSymbolFromDocumentationName(string documentationName) => + this.Assembly.Compilation.MetadataAssemblies.Values + .Select(x => x.RootNamespace.LookupByPrefixedDocumentationName(documentationName)) + .OfType() + .FirstOrDefault(); + + private ParameterSymbol? GetParameter(string paramName) => + (this.containingSymbol as FunctionSymbol)?.Parameters.FirstOrDefault(x => x.Name == paramName); + + private TypeParameterSymbol? GetTypeParameter(string paramName) => + (this.containingSymbol as FunctionSymbol)?.GenericParameters.FirstOrDefault(x => x.Name == paramName); +} diff --git a/src/Draco.Compiler/Internal/Documentation/SymbolDocumentation.cs b/src/Draco.Compiler/Internal/Documentation/SymbolDocumentation.cs new file mode 100644 index 000000000..89b619226 --- /dev/null +++ b/src/Draco.Compiler/Internal/Documentation/SymbolDocumentation.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Draco.Compiler.Internal.Documentation; + +/// +/// Represents documentation for a . +/// +/// The s this documentation contains. +internal record class SymbolDocumentation +{ + /// + /// Empty documentation; + /// + public static SymbolDocumentation Empty = new SymbolDocumentation(ImmutableArray.Empty); + + /// + /// The summary documentation section. + /// + public DocumentationSection? Summary => this.unorderedSections.FirstOrDefault(x => x.Name?.ToLower() == "summary"); + + /// + /// The sections ordered conventionally. + /// + public ImmutableArray Sections => InterlockedUtils.InitializeDefault(ref this.sections, this.BuildOrderedSections); + private ImmutableArray sections; + + private readonly ImmutableArray unorderedSections; + + public SymbolDocumentation(ImmutableArray sections) + { + this.unorderedSections = sections; + } + + /// + /// Creates a markdown representation of this documentation. + /// + /// The documentation in markdown format. + public virtual string ToMarkdown() + { + var builder = new StringBuilder(); + for (var i = 0; i < this.Sections.Length; i++) + { + var section = this.Sections[i]; + builder.Append(section.Kind switch + { + SectionKind.Summary => string.Join(string.Empty, section.Elements.Select(x => x.ToMarkdown())), + + SectionKind.Parameters or SectionKind.TypeParameters => + $""" + # {section.Name} + {string.Join(Environment.NewLine, section.Elements.Select(x => x.ToMarkdown()))} + """, + + SectionKind.Code => section.Elements[0].ToMarkdown(), + + _ => $""" + # {section.Name} + {string.Join(string.Empty, section.Elements.Select(x => x.ToMarkdown()))} + """ + }); + + // Newline after each section except the last one + if (i != this.Sections.Length - 1) builder.Append(Environment.NewLine); + } + return builder.ToString(); + } + + + /// + /// Creates an XML representation of this documentation. + /// + /// The documentation in XML format, encapsulated by a documentation tag. + public virtual XElement ToXml() + { + var sections = new List(); + foreach (var section in this.Sections) + { + switch (section.Kind) + { + case SectionKind.Summary: + sections.Add(new XElement("summary", section.Elements.Select(x => x.ToXml()))); + break; + case SectionKind.Parameters: + case SectionKind.TypeParameters: + sections.AddRange(section.Elements.Select(x => x.ToXml())); + break; + case SectionKind.Code: + sections.Add(section.Elements[0].ToXml()); + break; + default: + // Note: The "Unknown" is for soft failing as string.Empty would throw + sections.Add(new XElement(section.Name, section.Elements.Select(x => x.ToXml()))); + break; + } + } + return new XElement("documentation", sections); + } + + private ImmutableArray BuildOrderedSections() => + this.unorderedSections.OrderBy(x => (int)x.Kind).ToImmutableArray(); +} + +/// +/// Temporary structure for storing markdown documentation. +/// +/// The markdown documentation. +internal sealed record class MarkdownSymbolDocumentation(string Markdown) : SymbolDocumentation(ImmutableArray.Empty) +{ + public override string ToMarkdown() => this.Markdown; + + public override XElement ToXml() => throw new NotSupportedException(); +} + +// TODO: Re-add this once we have proper markdown extractor +#if false +internal sealed record class FunctionDocumentation(ImmutableArray Sections) : SymbolDocumentation(Sections) +{ + public DocumentationSection? Return => this.Sections.FirstOrDefault(x => x.Name.ToLower() == "return"); + public ParametersDocumentationSection? Parameters => this.Sections.OfType().FirstOrDefault(); +} +#endif diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataAssemblySymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataAssemblySymbol.cs index 705d1adde..b606dde19 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataAssemblySymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataAssemblySymbol.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Reflection; using System.Reflection.Metadata; +using System.Xml; using Draco.Compiler.Api; namespace Draco.Compiler.Internal.Symbols.Metadata; @@ -42,6 +43,11 @@ internal class MetadataAssemblySymbol : ModuleSymbol, IMetadataSymbol public MetadataReader MetadataReader { get; } + /// + /// XmlDocument containing documentation for this assembly. + /// + public XmlDocument? AssemblyDocumentation { get; } + /// /// The compilation this assembly belongs to. /// @@ -52,12 +58,14 @@ internal class MetadataAssemblySymbol : ModuleSymbol, IMetadataSymbol public MetadataAssemblySymbol( Compilation compilation, - MetadataReader metadataReader) + MetadataReader metadataReader, + XmlDocument? documentation) { this.Compilation = compilation; this.MetadataReader = metadataReader; this.moduleDefinition = metadataReader.GetModuleDefinition(); this.assemblyDefinition = metadataReader.GetAssemblyDefinition(); + this.AssemblyDocumentation = documentation; } private MetadataNamespaceSymbol BuildRootNamespace() diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs index 4c6e1aaca..41e404483 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataFieldSymbol.cs @@ -1,6 +1,8 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Metadata; @@ -35,6 +37,12 @@ public override Api.Semantics.Visibility Visibility } } + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => InterlockedUtils.InitializeNull(ref this.rawDocumentation, this.BuildRawDocumentation); + private string? rawDocumentation; + public override Symbol? ContainingSymbol { get; } /// @@ -84,4 +92,10 @@ private TypeSymbol BuildType() var constant = this.MetadataReader.GetConstant(constantHandle); return MetadataSymbol.DecodeConstant(constant, this.MetadataReader); } + + private SymbolDocumentation BuildDocumentation() => + XmlDocumentationExtractor.Extract(this); + + private string BuildRawDocumentation() => + MetadataSymbol.GetDocumentation(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs index 81ed250ec..0cdf860e9 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs @@ -4,6 +4,8 @@ using System.Reflection; using System.Reflection.Metadata; using System.Threading; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Metadata; @@ -87,6 +89,12 @@ public override FunctionSymbol? Override private volatile bool overrideNeedsBuild = true; private readonly object overrideBuildLock = new(); + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => InterlockedUtils.InitializeNull(ref this.rawDocumentation, this.BuildRawDocumentation); + private string? rawDocumentation; + public override Symbol ContainingSymbol { get; } // IMPORTANT: Choice of flag field because of write order @@ -231,4 +239,10 @@ private static bool SignaturesMatch(FunctionSymbol function, MethodSignature + XmlDocumentationExtractor.Extract(this); + + private string BuildRawDocumentation() => + MetadataSymbol.GetDocumentation(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataNamespaceSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataNamespaceSymbol.cs index b22a350df..9a19e1998 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataNamespaceSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataNamespaceSymbol.cs @@ -65,4 +65,28 @@ private ImmutableArray BuildMembers() // Done return result.ToImmutable(); } + + /// + /// Looks up symbol by its prefixed documentation name. + /// + /// The prefixed documentation name to lookup by. + /// The looked up symbol, or null, if such symbol doesn't exist under this module symbol. + public Symbol? LookupByPrefixedDocumentationName(string prefixedDocumentationName) + { + // Note: we cut off the first two chars, because the first two chars are always the prefix annotating what kind of symbol this is + var parts = prefixedDocumentationName[2..].Split('.'); + if (parts.Length == 0) return this; + + var current = this as Symbol; + for (var i = 0; i < parts.Length - 1; ++i) + { + var part = parts[i]; + current = current.Members + .Where(m => m.MetadataName == part && m is ModuleSymbol or TypeSymbol) + .SingleOrDefault(); + if (current is null) return null; + } + + return current.Members.SingleOrDefault(m => MetadataSymbol.GetPrefixedDocumentationName(m) == prefixedDocumentationName); + } } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs index 90b5d2848..58f518a55 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Reflection.Metadata; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Metadata; @@ -43,6 +45,12 @@ public override PropertySymbol? Override private volatile bool overrideNeedsBuild = true; private readonly object overrideBuildLock = new(); + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => InterlockedUtils.InitializeNull(ref this.rawDocumentation, this.BuildRawDocumentation); + private string? rawDocumentation; + public override Symbol ContainingSymbol { get; } /// @@ -99,4 +107,10 @@ private void BuildOverride() if (accessor.Override is not null) return (accessor.Override as IPropertyAccessorSymbol)?.Property; return null; } + + private SymbolDocumentation BuildDocumentation() => + XmlDocumentationExtractor.Extract(this); + + private string BuildRawDocumentation() => + MetadataSymbol.GetDocumentation(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs index 8160ba72c..ffb73d131 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataStaticClassSymbol.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Metadata; @@ -20,6 +22,12 @@ internal sealed class MetadataStaticClassSymbol : ModuleSymbol, IMetadataSymbol, public override Api.Semantics.Visibility Visibility => this.typeDefinition.Attributes.HasFlag(TypeAttributes.Public) ? Api.Semantics.Visibility.Public : Api.Semantics.Visibility.Internal; + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => InterlockedUtils.InitializeNull(ref this.rawDocumentation, this.BuildRawDocumentation); + private string? rawDocumentation; + public override Symbol ContainingSymbol { get; } // NOTE: thread-safety does not matter, same instance @@ -102,4 +110,10 @@ private ImmutableArray BuildMembers() // Done return result.ToImmutable(); } + + private SymbolDocumentation BuildDocumentation() => + XmlDocumentationExtractor.Extract(this); + + private string BuildRawDocumentation() => + MetadataSymbol.GetDocumentation(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs index 8cf1b6360..0fcc0b05e 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataSymbol.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Metadata; using Draco.Compiler.Api; @@ -70,7 +71,7 @@ public static IEnumerable ToSymbol( var memberType = reader.GetTypeReference((TypeReferenceHandle)member.Parent); if (reader.GetString(memberType.Name) == "DefaultMemberAttribute") return attribute.DecodeValue(typeProvider).FixedArguments[0].Value?.ToString(); break; - default: throw new System.InvalidOperationException(); + default: throw new InvalidOperationException(); }; } return null; @@ -108,4 +109,74 @@ public static IEnumerable ToSymbol( private static FunctionSymbol SynthetizeConstructor( MetadataTypeSymbol type, MethodDefinition ctorMethod) => new SynthetizedMetadataConstructorSymbol(type, ctorMethod); + + /// + /// Gets the documentation XML as text for the given . + /// + /// The to get documentation for. + /// The documentation, or empty string, if no documentation was found. + public static string GetDocumentation(Symbol symbol) + { + var assembly = symbol.AncestorChain.OfType().FirstOrDefault(); + if (assembly is null) return string.Empty; + var documentationName = GetPrefixedDocumentationName(symbol); + var root = assembly.AssemblyDocumentation?.DocumentElement; + var xml = root?.SelectSingleNode($"//member[@name='{documentationName}']")?.InnerXml ?? string.Empty; + return string.Join(Environment.NewLine, xml.ReplaceLineEndings("\n").Split('\n').Select(x => x.TrimStart())); + } + + /// + /// Gets the full name of a used to retrieve documentation from metadata. + /// + /// The symbol to get documentation name of. + /// The documentation name, or empty string, if is null. + public static string GetDocumentationName(Symbol? symbol) => symbol switch + { + FunctionSymbol function => GetFunctionDocumentationName(function), + TypeParameterSymbol typeParam => GetTypeParameterDocumentationName(typeParam), + null => string.Empty, + _ => symbol.MetadataFullName, + }; + + /// + /// The documentation name of with prepended documentation prefix, documentation prefix specifies the type of symbol the documentation name represents. + /// For example has the prefix "T:". + /// + /// The symbol to get prefixed documentation name of. + /// The prefixed documentation name, or empty string, if is null. + public static string GetPrefixedDocumentationName(Symbol? symbol) => $"{GetDocumentationPrefix(symbol)}{GetDocumentationName(symbol)}"; + + private static string GetDocumentationPrefix(Symbol? symbol) => symbol switch + { + TypeSymbol => "T:", + ModuleSymbol => "T:", + FunctionSymbol => "M:", + PropertySymbol => "P:", + FieldSymbol => "F:", + _ => string.Empty, + }; + + private static string GetFunctionDocumentationName(FunctionSymbol function) + { + var parametersJoined = function.Parameters.Length == 0 + ? string.Empty + : $"({string.Join(",", function.Parameters.Select(x => GetDocumentationName(x.Type)))})"; + + var generics = function.GenericParameters.Length == 0 + ? string.Empty + : $"``{function.GenericParameters.Length}"; + return $"{function.MetadataFullName}{generics}{parametersJoined}"; + } + + private static string GetTypeParameterDocumentationName(TypeParameterSymbol typeParameter) + { + var index = typeParameter.ContainingSymbol?.GenericParameters.IndexOf(typeParameter); + if (index is null || index.Value == -1) return typeParameter.MetadataFullName; + return typeParameter.ContainingSymbol switch + { + TypeSymbol => $"`{index.Value}", + FunctionSymbol => $"``{index.Value}", + _ => typeParameter.MetadataFullName, + }; + } } diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs index fef1c243c..a14ad8f2b 100644 --- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Metadata; @@ -27,6 +29,12 @@ internal sealed class MetadataTypeSymbol : TypeSymbol, IMetadataSymbol, IMetadat InterlockedUtils.InitializeDefault(ref this.genericParameters, this.BuildGenericParameters); private ImmutableArray genericParameters; + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => InterlockedUtils.InitializeNull(ref this.rawDocumentation, this.BuildRawDocumentation); + private string? rawDocumentation; + public override Symbol ContainingSymbol { get; } public override bool IsValueType => this.BaseTypes.Contains( @@ -169,4 +177,10 @@ private ImmutableArray BuildMembers() // Done return result.ToImmutable(); } + + private SymbolDocumentation BuildDocumentation() => + XmlDocumentationExtractor.Extract(this); + + private string BuildRawDocumentation() => + MetadataSymbol.GetDocumentation(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Source/SourceFunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Source/SourceFunctionSymbol.cs index 6007e33c8..4a934edac 100644 --- a/src/Draco.Compiler/Internal/Symbols/Source/SourceFunctionSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Source/SourceFunctionSymbol.cs @@ -6,6 +6,8 @@ using Draco.Compiler.Internal.BoundTree; using Draco.Compiler.Internal.Declarations; using Draco.Compiler.Internal.Diagnostics; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; using Draco.Compiler.Internal.FlowAnalysis; using Draco.Compiler.Internal.Symbols.Synthetized; @@ -34,7 +36,10 @@ internal sealed class SourceFunctionSymbol : FunctionSymbol, ISourceSymbol public BoundStatement Body => this.BindBodyIfNeeded(this.DeclaringCompilation!); private BoundStatement? body; - public override string Documentation => this.DeclaringSyntax.Documentation; + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => this.DeclaringSyntax.Documentation; public SourceFunctionSymbol(Symbol? containingSymbol, FunctionDeclarationSyntax syntax) { @@ -204,4 +209,7 @@ private static bool HasSameParameterTypes(FunctionSymbol f1, FunctionSymbol f2) return true; } + + private SymbolDocumentation BuildDocumentation() => + MarkdownDocumentationExtractor.Extract(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Source/SourceGlobalSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Source/SourceGlobalSymbol.cs index 87ecd28cb..428c64020 100644 --- a/src/Draco.Compiler/Internal/Symbols/Source/SourceGlobalSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Source/SourceGlobalSymbol.cs @@ -3,6 +3,8 @@ using Draco.Compiler.Internal.Binding; using Draco.Compiler.Internal.BoundTree; using Draco.Compiler.Internal.Declarations; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; using Draco.Compiler.Internal.FlowAnalysis; namespace Draco.Compiler.Internal.Symbols.Source; @@ -19,7 +21,10 @@ internal sealed class SourceGlobalSymbol : GlobalSymbol, ISourceSymbol public BoundExpression? Value => this.BindTypeAndValueIfNeeded(this.DeclaringCompilation!).Value; - public override string Documentation => this.DeclaringSyntax.Documentation; + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => this.DeclaringSyntax.Documentation; // IMPORTANT: flag is type, needs to be written last // NOTE: We check the TYPE here, as value is nullable @@ -69,4 +74,7 @@ public void Bind(IBinderProvider binderProvider) var binder = binderProvider.GetBinder(this.DeclaringSyntax); return binder.BindGlobal(this, binderProvider.DiagnosticBag); } + + private SymbolDocumentation BuildDocumentation() => + MarkdownDocumentationExtractor.Extract(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs index 41a71edbc..55f1bebea 100644 --- a/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Source/SourceLocalSymbol.cs @@ -1,5 +1,7 @@ using Draco.Compiler.Api.Syntax; using Draco.Compiler.Internal.Binding; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Source; @@ -17,7 +19,10 @@ internal sealed class SourceLocalSymbol : LocalSymbol, ISourceSymbol public override bool IsMutable => this.untypedSymbol.IsMutable; - public override string Documentation => this.DeclaringSyntax.Documentation; + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; + + internal override string RawDocumentation => this.DeclaringSyntax.Documentation; private readonly UntypedLocalSymbol untypedSymbol; @@ -28,4 +33,7 @@ public SourceLocalSymbol(UntypedLocalSymbol untypedSymbol, TypeSymbol type) } public void Bind(IBinderProvider binderProvider) { } + + private SymbolDocumentation BuildDocumentation() => + MarkdownDocumentationExtractor.Extract(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Source/SourceModuleSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Source/SourceModuleSymbol.cs index e1d2e34bd..c5dcfa9cd 100644 --- a/src/Draco.Compiler/Internal/Symbols/Source/SourceModuleSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Source/SourceModuleSymbol.cs @@ -8,6 +8,8 @@ using Draco.Compiler.Api.Syntax; using Draco.Compiler.Internal.Binding; using Draco.Compiler.Internal.Declarations; +using Draco.Compiler.Internal.Documentation; +using Draco.Compiler.Internal.Documentation.Extractors; namespace Draco.Compiler.Internal.Symbols.Source; @@ -24,13 +26,19 @@ internal sealed class SourceModuleSymbol : ModuleSymbol, ISourceSymbol public override Symbol? ContainingSymbol { get; } public override string Name => this.declaration.Name; - public override SyntaxNode? DeclaringSyntax => null; + public override SymbolDocumentation Documentation => InterlockedUtils.InitializeNull(ref this.documentation, this.BuildDocumentation); + private SymbolDocumentation? documentation; /// /// The syntaxes contributing to this module. /// public IEnumerable DeclaringSyntaxes => this.declaration.DeclaringSyntaxes; + internal override string RawDocumentation => this.DeclaringSyntaxes + .Select(syntax => syntax.Documentation) + .Where(doc => !string.IsNullOrEmpty(doc)) + .FirstOrDefault() ?? string.Empty; + private readonly Declaration declaration; private SourceModuleSymbol( @@ -43,14 +51,6 @@ private SourceModuleSymbol( this.declaration = declaration; } - public SourceModuleSymbol( - Compilation compilation, - Symbol? containingSymbol, - SingleModuleDeclaration declaration) - : this(compilation, containingSymbol, declaration as Declaration) - { - } - public SourceModuleSymbol( Compilation compilation, Symbol? containingSymbol, @@ -105,4 +105,7 @@ private ImmutableArray BindMembers(IBinderProvider binderProvider) private FunctionSymbol BuildFunction(FunctionDeclaration declaration) => new SourceFunctionSymbol(this, declaration); private GlobalSymbol BuildGlobal(GlobalDeclaration declaration) => new SourceGlobalSymbol(this, declaration); private ModuleSymbol BuildModule(MergedModuleDeclaration declaration) => new SourceModuleSymbol(this.DeclaringCompilation, this, declaration); + + private SymbolDocumentation BuildDocumentation() => + MarkdownDocumentationExtractor.Extract(this); } diff --git a/src/Draco.Compiler/Internal/Symbols/Symbol.cs b/src/Draco.Compiler/Internal/Symbols/Symbol.cs index 7c3ac51c3..c17a6ab63 100644 --- a/src/Draco.Compiler/Internal/Symbols/Symbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Symbol.cs @@ -3,7 +3,9 @@ using System.Linq; using Draco.Compiler.Api; using Draco.Compiler.Api.Syntax; +using Draco.Compiler.Internal.Documentation; using Draco.Compiler.Internal.Symbols.Generic; +using Draco.Compiler.Internal.Symbols.Metadata; using Draco.Compiler.Internal.Utilities; namespace Draco.Compiler.Internal.Symbols; @@ -89,6 +91,23 @@ public virtual string FullName } } + /// + /// The fully qualified metadata name of this symbol. + /// + public virtual string MetadataFullName + { + get + { + var parentFullName = this.ContainingSymbol is not MetadataAssemblySymbol + ? this.ContainingSymbol?.MetadataFullName + : null; + + return string.IsNullOrWhiteSpace(parentFullName) + ? this.MetadataName + : $"{parentFullName}.{this.MetadataName}"; + } + } + /// /// All the members within this symbol. /// @@ -105,9 +124,14 @@ public virtual string FullName public virtual IEnumerable InstanceMembers => this.Members.Where(x => x is IMemberSymbol mem && !mem.IsStatic); /// - /// Documentation attached to this symbol. + /// The structured documentation attached to this symbol. + /// + public virtual SymbolDocumentation Documentation => SymbolDocumentation.Empty; + + /// + /// The documentation of symbol as raw xml or markdown; /// - public virtual string Documentation => string.Empty; + internal virtual string RawDocumentation => string.Empty; /// /// The visibility of this symbol. diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataBackedPrimitiveTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataBackedPrimitiveTypeSymbol.cs index 34ea6a3ad..4f0e6012b 100644 --- a/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataBackedPrimitiveTypeSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/MetadataBackedPrimitiveTypeSymbol.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using Draco.Compiler.Internal.Documentation; namespace Draco.Compiler.Internal.Symbols.Synthetized; @@ -16,9 +17,11 @@ internal sealed class MetadataBackedPrimitiveTypeSymbol : PrimitiveTypeSymbol /// public TypeSymbol MetadataType { get; } + public override string MetadataName => this.MetadataType.MetadataName; + public override string MetadataFullName => this.MetadataType.MetadataFullName; public override ImmutableArray ImmediateBaseTypes => this.MetadataType.ImmediateBaseTypes; public override IEnumerable DefinedMembers => this.MetadataType.DefinedMembers; - public override string Documentation => this.MetadataType.Documentation; + public override SymbolDocumentation Documentation => this.MetadataType.Documentation; public MetadataBackedPrimitiveTypeSymbol(string name, bool isValueType, TypeSymbol metadataType) : base(name, isValueType) diff --git a/src/Draco.Compiler/Internal/Symbols/TypeParameterSymbol.cs b/src/Draco.Compiler/Internal/Symbols/TypeParameterSymbol.cs index 709fcae40..3ef0a26ec 100644 --- a/src/Draco.Compiler/Internal/Symbols/TypeParameterSymbol.cs +++ b/src/Draco.Compiler/Internal/Symbols/TypeParameterSymbol.cs @@ -9,7 +9,7 @@ namespace Draco.Compiler.Internal.Symbols; internal abstract class TypeParameterSymbol : TypeSymbol { public override TypeSymbol GenericInstantiate(Symbol? containingSymbol, ImmutableArray arguments) => - (TypeSymbol)base.GenericInstantiate(containingSymbol, arguments); + base.GenericInstantiate(containingSymbol, arguments); public override TypeSymbol GenericInstantiate(Symbol? containingSymbol, GenericContext context) => context.TryGetValue(this, out var type) ? type : this; diff --git a/src/Draco.Compiler/Internal/Symbols/TypeVariable.cs b/src/Draco.Compiler/Internal/Symbols/TypeVariable.cs index d4e576b68..546a9a072 100644 --- a/src/Draco.Compiler/Internal/Symbols/TypeVariable.cs +++ b/src/Draco.Compiler/Internal/Symbols/TypeVariable.cs @@ -24,7 +24,6 @@ public override bool IsGroundType public override bool IsError => throw new NotSupportedException(); public override Symbol? ContainingSymbol => throw new NotSupportedException(); public override IEnumerable DefinedMembers => throw new NotSupportedException(); - public override string Documentation => throw new NotSupportedException(); public override TypeSymbol Substitution => this.solver.Unwrap(this);