Skip to content

Commit 80b4243

Browse files
authored
More ANTLR Utils and refactoring (#32)
* * Renamed MsgLevel =< MessageLevel - Avoids en-us acronym and clarifies intent better fitting with other names. * Moved types out of command line into general core and runtime. General refactoring of code to unify and eliminate redundancy of abstractions. There was a LOT of duplication of abstraction between command line and runtime that is now moved to the Extensions library. * Argument validation now moved to runtime independent "Requires" static class. - This contains the implementation which depending on targeted framework may be polyFilled. - This keeps intent clearer AND supports multi-targetting without pre-processor conditionals on all targets or compilations that support C#14 'extension' keyword. * Added SourceLocation to contain both the URI of the source text AND the range for the location. * Added more ANTLR common support * Removed shared source library - All of that functionality is now in Ubiquity.NET.Extensions >[!IMPORTANT] > The existing tests were updated to the refactoring and all > pass. The new functionality does NOT have testing yet. * * Updated demo app to account for refactoring * Updated docs and behavior of `Requires.NotDisposed` to avoid negative logic and provide clarity of intent. * new semantics allow use as a drop-in replacement for `ObjectDisposedException.ThrowIf`
1 parent a526ce6 commit 80b4243

144 files changed

Lines changed: 3536 additions & 2209 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Directory.Packages.props

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,7 @@
3030
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="5.0.0" />
3131
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0" />
3232
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.Features" Version="4.14.0" />
33-
<PackageVersion Include="Basic.Reference.Assemblies" Version="1.8.4" />
3433

35-
<!-- Until https://github.com/jaredpar/basic-reference-assemblies/issues/78 is resolved these are a specific version ref -->
36-
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.8.3" />
37-
<PackageVersion Include="Basic.Reference.Assemblies.Net90" Version="1.8.4" />
38-
<PackageVersion Include="Basic.Reference.Assemblies.Net100" Version="1.8.4" />
3934
<PackageVersion Include="PolySharp" Version="1.15.0" />
4035
<PackageVersion Include="System.Buffers" Version="4.6.1" />
4136
<PackageVersion Include="System.Collections.Immutable" Version="9.0.0" />

IgnoredWords.dic

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ invocable
103103
jit
104104
len
105105
Lexer
106+
lhs
106107
LibLLVM
107108
Licensor
108109
Llilum
@@ -158,6 +159,7 @@ referenceable
158159
Relocations
159160
repl
160161
repo
162+
rhs
161163
RMW
162164
runtimes
163165
RValue

docfx/ReadMe.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,15 @@ possible.
8787

8888
### Lists
8989
The largest intrusion of the XML into the source is that of lists. The XML doc comments
90-
official support is to use the `<list>` tag. However, that is VERY intrusive and doesn't
91-
easily support sub-lists. Consider:
90+
official support is to use the `<list>` tag. For an example of how intrusive and ugly these
91+
can become see this [Blog Article](https://documentation.contiem.com/HelpAuthoringTools/UseListsAndTablesInXmlComments.html)
92+
>[!NOTE]
93+
> The output shown in that article is using a theoretcial rendering. It is ***NOT*** how the
94+
> IDE Will present the text. Usually the IDE is not as "pretty".
95+
96+
#### Bulleted lists
97+
Unfortunately, the XML doc comments for a bulleted list (and any other form really) is VERY
98+
intrusive and doesn't easily support sub-lists. Consider:
9299

93100
``` C#
94101
/// Additional steps might include:
@@ -122,7 +129,7 @@ Which one would ***YOU*** rather encounter in code? Which one is easier to under
122129
reading the source? This repo chooses the latter. (If you favor the former, perhaps you
123130
should reconsider... :grinning:)
124131

125-
#### How to handle lists
132+
##### How to handle bulleted lists
126133
There is little that can be done to alter the rendering of any editor support, at most an
127134
editor might allow specification of a CSS file, but that is the lowest priority of doc
128135
comments. Readability by maintainers of the docs AND the rendering for final docs used by
@@ -151,3 +158,24 @@ render properly in final docs.
151158
1) Turning this off can greatly reduce the noise AND reduce the problems of
152159
different rendering as lists are generally not used in the other elements.
153160

161+
#### Tables
162+
There's sadly no simple rendering of these. Many user requests for a simpler markdown tag
163+
have gone unresolved. The docfx tool will render tables from the XML comment form though
164+
so a pattern of implementing them is possible
165+
166+
#### Guidance for tables
167+
1) Avoid using them if at all possible.
168+
- This is the simplest advice to give for these, they are ugly and intrusive so avoid
169+
them whenever possible.
170+
2) If they are unavoidable or alternate representations leads to even uglier forms then use
171+
the following guidance.
172+
173+
``` C#
174+
/// <list type="table">
175+
/// <listheader><term>{Header 1}</term><term>{Header 2}</term></listheader>
176+
/// <item><term>{Row 1, Col 1}</term><term>{Row 1, Col 2}</term></item>
177+
/// <item><term>{Row 2, Col 2}</term><term>{Row 2, Col 2}</term></item>
178+
/// </list>
179+
```
180+
If a table needs more than 3 columns this gets ugly, fast, don't do that. Re-think the docs,
181+
use an additional markdown file that includes a simpler form of the table, anything else...

src/DemoCommandLineSrcGen/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading.Tasks;
1010

1111
using Ubiquity.NET.CommandLine;
12+
using Ubiquity.NET.Extensions;
1213

1314
namespace TestNamespace
1415
{
@@ -25,7 +26,7 @@ public static async Task<int> Main( string[] args )
2526
};
2627

2728
// start with information level for parsing; parsed options might specify different level
28-
var reporter = new ColoredConsoleReporter( MsgLevel.Information );
29+
var reporter = new ColoredConsoleReporter( MessageLevel.Information );
2930

3031
return await TestOptions.BuildRootCommand( ( options, ct ) => AppMainAsync( options, reporter, ct ) )
3132
.ParseAndInvokeResultAsync( reporter, cts.Token, args );

src/DemoCommandLineSrcGen/TestOptions.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,11 @@
66
using System.IO;
77
using System.Linq;
88

9-
using Ubiquity.NET.CommandLine;
109
using Ubiquity.NET.CommandLine.GeneratorAttributes;
10+
using Ubiquity.NET.Extensions;
1111

1212
namespace TestNamespace
1313
{
14-
// It is important to understand how "required" is handled in the underlying command line handler
15-
// in System.CommandLine. The semantics are:
16-
// When the command is invoked, the value may not be null.
17-
// That is, it is NOT evaluated during parse, ONLY during invocation.
1814
[RootCommand( Description = "Root command for tests" )]
1915
internal partial class TestOptions
2016
{
@@ -23,7 +19,7 @@ internal partial class TestOptions
2319
public required DirectoryInfo SomePath { get; init; }
2420

2521
[Option( "-v", Description = "Verbosity Level" )]
26-
public MsgLevel Verbosity { get; init; } = MsgLevel.Information;
22+
public MessageLevel Verbosity { get; init; } = MessageLevel.Information;
2723

2824
[Option( "-b", Description = "Test Some existing Path", Required = true )]
2925
[FolderValidation( FolderValidation.ExistingOnly )]
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
namespace Ubiquity.NET.ANTLR.Utils
5+
{
6+
/// <summary>Adapter to translate ANTLR error listeners to an <see cref="IDiagnosticReporter"/></summary>
7+
/// <remarks>
8+
/// <para>This intentionally ignores the <see cref="TextWriter"/> provided by ANTLR and uses the <see cref="IDiagnosticReporter"/>
9+
/// provided in the constructor. This allows a much greater level of flexibility in reporting of diagnostics from
10+
/// a parser. Especially in abstracting the underlying parse technology from the diagnostic reporting</para>
11+
/// <para>
12+
/// The <see cref="SeverityMap"/> is used to allow for future adaptation of the parser to map errors from a
13+
/// recognizer state, which is not stable if the grammar changes. This ensures that the ID values remain unique
14+
/// even if the underlying grammar changes.
15+
/// </para>
16+
/// <para>The <see cref="DiagnosticMessage.Subcategory"/> for messages reported by this type are always null. If
17+
/// an application desires specific sub categories then it can use it's own implementation of this type</para>
18+
/// </remarks>
19+
public class AntlrErrorListenerAdapter
20+
: IAntlrErrorListener<int>
21+
, IAntlrErrorListener<IToken>
22+
{
23+
/// <summary>Initializes a new instance of the <see cref="AntlrErrorListenerAdapter"/> class</summary>
24+
/// <param name="sourceName">Source name for all errors</param>
25+
/// <param name="severityMap">Severity map to use when transforming errors</param>
26+
/// <param name="formatter">Formatter to use to form a string version of the error code</param>
27+
/// <param name="diagnosticReporter">Diagnostic reporter to adapt ANTL errors to</param>
28+
/// <exception cref="ArgumentException"><paramref name="sourceName"/> is null or whitespace</exception>
29+
public AntlrErrorListenerAdapter(
30+
string sourceName,
31+
IMessageLevelMap severityMap,
32+
IDiagnosticIdFormatter formatter,
33+
IDiagnosticReporter diagnosticReporter
34+
)
35+
{
36+
Requires.NotNullOrWhiteSpace( sourceName );
37+
38+
SeverityMap = severityMap;
39+
IdFormatter = formatter;
40+
Reporter = diagnosticReporter;
41+
}
42+
43+
/// <summary>Gets the severity mapping used when forming a diagnostic</summary>
44+
public IMessageLevelMap SeverityMap { get; init; }
45+
46+
/// <summary>Gets the error ID mapping used when forming a diagnostic</summary>
47+
public IDiagnosticIdFormatter IdFormatter { get; init; }
48+
49+
/// <summary>Gets the reporter this instance adapts to</summary>
50+
public IDiagnosticReporter Reporter { get; init; }
51+
52+
/// <inheritdoc/>
53+
public void SyntaxError( TextWriter output // ignored
54+
, IRecognizer recognizer
55+
, int offendingSymbol
56+
, int line
57+
, int charPositionInLine
58+
, string msg
59+
, RecognitionException? e
60+
)
61+
{
62+
var loc = new SourceLocation(recognizer.InputStream.SourceName, new SourcePosition(line, charPositionInLine, recognizer.InputStream.Index));
63+
var code = new ScopedDiagnosticId(ParseSource.Lexical, recognizer.State );
64+
var diagnostic = code.AsDiagnostic(SeverityMap, IdFormatter, msg, loc, subcategory: null);
65+
Reporter.Report( diagnostic );
66+
}
67+
68+
/// <inheritdoc/>
69+
public void SyntaxError( TextWriter output // ignored
70+
, IRecognizer recognizer
71+
, IToken? offendingSymbol
72+
, int line
73+
, int charPositionInLine
74+
, string msg
75+
, RecognitionException? e
76+
)
77+
{
78+
var loc = new SourceLocation(recognizer.InputStream.SourceName, new SourcePosition(line, charPositionInLine, recognizer.InputStream.Index));
79+
int id = e is ParseException pe ? pe.ErrorId : recognizer.State;
80+
var code = new ScopedDiagnosticId(ParseSource.Syntactic, id );
81+
var diagnostic = code.AsDiagnostic(SeverityMap, IdFormatter, msg, loc, subcategory: null);
82+
Reporter.Report( diagnostic );
83+
}
84+
}
85+
}

src/Ubiquity.NET.ANTLR.Utils/AntlrParseErrorListenerAdapter.cs

Lines changed: 0 additions & 98 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
2+
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
3+
4+
using System.Threading;
5+
6+
namespace Ubiquity.NET.ANTLR.Utils
7+
{
8+
/// <summary>IParseTreeListener that provides support for cancellation</summary>
9+
/// <remarks>
10+
/// This class will throw an OperationCanceled from any method when the provided
11+
/// <see cref="CancellationToken"/> has requested cancellation of the parse. Cancellable
12+
/// </remarks>
13+
public class CancellableParseTreeListener
14+
: IParseTreeListener
15+
{
16+
/// <summary>Initializes a new instance of the <see cref="CancellableParseTreeListener"/> class.</summary>
17+
/// <param name="ct">Token to use for detection of cancellation</param>
18+
public CancellableParseTreeListener( CancellationToken ct )
19+
{
20+
CancelToken = ct;
21+
}
22+
23+
/// <inheritdoc/>
24+
public void EnterEveryRule( ParserRuleContext ctx )
25+
{
26+
CancelToken.ThrowIfCancellationRequested();
27+
}
28+
29+
/// <inheritdoc/>
30+
public void ExitEveryRule( ParserRuleContext ctx )
31+
{
32+
CancelToken.ThrowIfCancellationRequested();
33+
}
34+
35+
/// <inheritdoc/>
36+
public void VisitErrorNode( IErrorNode node )
37+
{
38+
CancelToken.ThrowIfCancellationRequested();
39+
}
40+
41+
/// <inheritdoc/>
42+
public void VisitTerminal( ITerminalNode node )
43+
{
44+
CancelToken.ThrowIfCancellationRequested();
45+
}
46+
47+
private readonly CancellationToken CancelToken;
48+
}
49+
}

0 commit comments

Comments
 (0)