Skip to content

Commit 74410b0

Browse files
committed
Added support for intercepting parser errors in the Analyzer.
1 parent da4dab3 commit 74410b0

File tree

5 files changed

+188
-7
lines changed

5 files changed

+188
-7
lines changed

TestRig/Grammar/Analyzer.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
using JetBrains.Annotations;
4343

4444
using Org.Edgerunner.ANTLR4.Tools.Testing.Exceptions;
45+
using Org.Edgerunner.ANTLR4.Tools.Testing.Grammar.Errors;
4546

4647
namespace Org.Edgerunner.ANTLR4.Tools.Testing.Grammar
4748
{
@@ -129,11 +130,13 @@ public IList<IToken> Tokenize()
129130
/// </summary>
130131
/// <param name="ruleName">Name of the rule.</param>
131132
/// <param name="option">The parsing options to use.</param>
132-
/// <exception cref="ArgumentNullException"><paramref name="ruleName"/> is <see langword="null"/> or empty.</exception>
133-
/// <exception cref="GrammarException">No parser found for supplied grammar</exception>
134-
/// <exception cref="GrammarException"><paramref name="ruleName"/> is not a valid parser rule.</exception>
135-
/// <exception cref="T:System.ArgumentNullException">No parser found for the specified grammar.</exception>
136-
public void Parse([NotNull] string ruleName, ParseOption option)
133+
/// <param name="listener">The error listener.</param>
134+
/// <exception cref="ArgumentNullException">ruleName</exception>
135+
/// <exception cref="GrammarException">No parser found for grammar \"{Grammar.GrammarName}\"</exception>
136+
/// <exception cref="GrammarException">No parser rule with name \"{ruleName}\" found.</exception>
137+
/// <exception cref="GrammarException"><paramref name="ruleName" /> is <see langword="null" /> or empty.</exception>
138+
/// <exception cref="T:System.ArgumentNullException">No parser found for supplied grammar</exception>
139+
public void Parse([NotNull] string ruleName, ParseOption option, TestingErrorListener listener = null)
137140
{
138141
if (string.IsNullOrEmpty(ruleName))
139142
throw new ArgumentNullException(nameof(ruleName));
@@ -171,6 +174,12 @@ public void Parse([NotNull] string ruleName, ParseOption option)
171174
// Handle Trace parsing option
172175
parser.Trace = option.HasFlag(ParseOption.Trace);
173176

177+
if (listener != null)
178+
{
179+
parser.RemoveErrorListeners();
180+
parser.AddErrorListener(listener);
181+
}
182+
174183
var methodInfo = Grammar.Parser.GetMethod(ruleName);
175184
if (methodInfo == null)
176185
throw new GrammarException($"No parser rule with name \"{ruleName}\" found.");
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#region BSD 3-Clause License
2+
// <copyright file="ParseError.cs" company="Edgerunner.org">
3+
// Copyright 2020 Thaddeus Ryker
4+
// </copyright>
5+
//
6+
// BSD 3-Clause License
7+
//
8+
// Copyright (c) 2020, Thaddeus Ryker
9+
// All rights reserved.
10+
//
11+
// Redistribution and use in source and binary forms, with or without
12+
// modification, are permitted provided that the following conditions are met:
13+
//
14+
// 1. Redistributions of source code must retain the above copyright notice, this
15+
// list of conditions and the following disclaimer.
16+
//
17+
// 2. Redistributions in binary form must reproduce the above copyright notice,
18+
// this list of conditions and the following disclaimer in the documentation
19+
// and/or other materials provided with the distribution.
20+
//
21+
// 3. Neither the name of the copyright holder nor the names of its
22+
// contributors may be used to endorse or promote products derived from
23+
// this software without specific prior written permission.
24+
//
25+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35+
#endregion
36+
37+
namespace Org.Edgerunner.ANTLR4.Tools.Testing.Grammar.Errors
38+
{
39+
/// <summary>
40+
/// Struct that represents a parsing error.
41+
/// </summary>
42+
public struct ParseError
43+
{
44+
/// <summary>
45+
/// Initializes a new instance of the <see cref="ParseError"/> struct.
46+
/// </summary>
47+
/// <param name="lineNumber">The line number.</param>
48+
/// <param name="column">The column.</param>
49+
/// <param name="message">The message.</param>
50+
public ParseError(int lineNumber, int column, string message)
51+
{
52+
LineNumber = lineNumber;
53+
Column = column;
54+
Message = message;
55+
}
56+
57+
public int LineNumber { get; set; }
58+
59+
public int Column { get; set; }
60+
61+
public string Message { get; set; }
62+
}
63+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#region BSD 3-Clause License
2+
// <copyright file="TestingErrorListener.cs" company="Edgerunner.org">
3+
// Copyright 2020 Thaddeus Ryker
4+
// </copyright>
5+
//
6+
// BSD 3-Clause License
7+
//
8+
// Copyright (c) 2020, Thaddeus Ryker
9+
// All rights reserved.
10+
//
11+
// Redistribution and use in source and binary forms, with or without
12+
// modification, are permitted provided that the following conditions are met:
13+
//
14+
// 1. Redistributions of source code must retain the above copyright notice, this
15+
// list of conditions and the following disclaimer.
16+
//
17+
// 2. Redistributions in binary form must reproduce the above copyright notice,
18+
// this list of conditions and the following disclaimer in the documentation
19+
// and/or other materials provided with the distribution.
20+
//
21+
// 3. Neither the name of the copyright holder nor the names of its
22+
// contributors may be used to endorse or promote products derived from
23+
// this software without specific prior written permission.
24+
//
25+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35+
#endregion
36+
37+
using System.Collections.Generic;
38+
39+
using Antlr4.Runtime;
40+
41+
namespace Org.Edgerunner.ANTLR4.Tools.Testing.Grammar.Errors
42+
{
43+
/// <summary>
44+
/// Class for gathering ANTLR4 parsing errors during testing.
45+
/// Implements the <see cref="IToken" />
46+
/// </summary>
47+
/// <seealso cref="IToken" />
48+
public class TestingErrorListener : Antlr4.Runtime.IAntlrErrorListener<IToken>
49+
{
50+
/// <summary>
51+
/// Initializes a new instance of the <see cref="TestingErrorListener"/> class.
52+
/// </summary>
53+
public TestingErrorListener()
54+
{
55+
Errors = new List<ParseError>();
56+
}
57+
58+
/// <summary>
59+
/// Gets the parsing errors.
60+
/// </summary>
61+
/// <value>The parsing errors.</value>
62+
public List<ParseError> Errors { get; }
63+
64+
/// <summary>
65+
/// Upon syntax error, notify any interested parties.
66+
/// </summary>
67+
/// <param name="recognizer">What parser got the error. From this
68+
/// object, you can access the context as well
69+
/// as the input stream.</param>
70+
/// <param name="offendingSymbol">The offending token in the input token
71+
/// stream, unless recognizer is a lexer (then it's null). If
72+
/// no viable alternative error,
73+
/// <paramref name="e" />
74+
/// has token at which we
75+
/// started production for the decision.</param>
76+
/// <param name="line">The line number in the input where the error occurred.</param>
77+
/// <param name="charPositionInLine">The character position within that line where the error occurred.</param>
78+
/// <param name="msg">The message to emit.</param>
79+
/// <param name="e">The exception generated by the parser that led to
80+
/// the reporting of an error. It is null in the case where
81+
/// the parser was able to recover in line without exiting the
82+
/// surrounding rule.</param>
83+
/// <remarks>Upon syntax error, notify any interested parties. This is not how to
84+
/// recover from errors or compute error messages.
85+
/// <see cref="T:Antlr4.Runtime.IAntlrErrorStrategy" />
86+
/// specifies how to recover from syntax errors and how to compute error
87+
/// messages. This listener's job is simply to emit a computed message,
88+
/// though it has enough information to create its own message in many cases.
89+
/// <p>The
90+
/// <see cref="T:Antlr4.Runtime.RecognitionException" />
91+
/// is non-null for all syntax errors except
92+
/// when we discover mismatched token errors that we can recover from
93+
/// in-line, without returning from the surrounding rule (via the single
94+
/// token insertion and deletion mechanism).</p></remarks>
95+
// ReSharper disable once TooManyArguments
96+
public void SyntaxError(
97+
IRecognizer recognizer,
98+
IToken offendingSymbol,
99+
int line,
100+
int charPositionInLine,
101+
string msg,
102+
RecognitionException e)
103+
{
104+
Errors.Add(new ParseError(line, charPositionInLine, msg));
105+
}
106+
}
107+
}

TestRig/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.0.20065.1")]
36-
[assembly: AssemblyFileVersion("1.0.20065.1")]
35+
[assembly: AssemblyVersion("1.0.20065.2")]
36+
[assembly: AssemblyFileVersion("1.0.20065.2")]

TestRig/TestRig.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@
5151
<Compile Include="Exceptions\GrammarException.cs" />
5252
<Compile Include="GrammarReference.cs" />
5353
<Compile Include="Grammar\Analyzer.cs" />
54+
<Compile Include="Grammar\Errors\ParseError.cs" />
5455
<Compile Include="Grammar\Loader.cs" />
5556
<Compile Include="Grammar\ParseOption.cs" />
5657
<Compile Include="Grammar\Scanner.cs" />
58+
<Compile Include="Grammar\Errors\TestingErrorListener.cs" />
5759
<Compile Include="Grammar\TokenViewModel.cs" />
5860
<Compile Include="Properties\AssemblyInfo.cs" />
5961
<Compile Include="Types\LexerType.cs" />

0 commit comments

Comments
 (0)