Skip to content
This repository has been archived by the owner on Jan 9, 2025. It is now read-only.

Commit

Permalink
Use Option<T> for parsing as well.
Browse files Browse the repository at this point in the history
  • Loading branch information
GGG-KILLER committed Jun 15, 2021
1 parent 20ed12d commit 208da53
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 162 deletions.
12 changes: 5 additions & 7 deletions GParse/Parsing/IPrattParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GParse.Lexing;
using Tsu;

namespace GParse.Parsing
{
Expand Down Expand Up @@ -31,15 +31,13 @@ public interface IPrattParser<TTokenType, TExpressionNode>
/// of possible parselets.
/// </remarks>
/// <param name="minPrecedence"></param>
/// <param name="expression"></param>
/// <returns></returns>
Boolean TryParseExpression(Int32 minPrecedence, [NotNullWhen(true)] out TExpressionNode expression);
/// <returns>The parsed expression if successful.</returns>
Option<TExpressionNode> ParseExpression(int minPrecedence);

/// <summary>
/// Attempts to parse an expression.
/// </summary>
/// <param name="expression">The parsed expression if successful.</param>
/// <returns>Whether the parsing happened without any fatal errors.</returns>
Boolean TryParseExpression([NotNullWhen(true)] out TExpressionNode expression);
/// <returns>The parsed expression if successful.</returns>
Option<TExpressionNode> ParseExpression();
}
}
5 changes: 2 additions & 3 deletions GParse/Parsing/IPrattParserBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using GParse;
using GParse.Lexing;
using GParse.Parsing.Parselets;

Expand All @@ -26,7 +25,7 @@ public interface IPrattParserBuilder<TTokenType, TExpressionNode>
/// <param name="tokenType"></param>
/// <param name="id"></param>
/// <param name="prefixModule"></param>
void Register(TTokenType tokenType, String id, IPrefixParselet<TTokenType, TExpressionNode> prefixModule);
void Register(TTokenType tokenType, string id, IPrefixParselet<TTokenType, TExpressionNode> prefixModule);

/// <summary>
/// Registers an infix expression parser module
Expand All @@ -41,7 +40,7 @@ public interface IPrattParserBuilder<TTokenType, TExpressionNode>
/// <param name="tokenType"></param>
/// <param name="id"></param>
/// <param name="infixModule"></param>
void Register(TTokenType tokenType, String id, IInfixParselet<TTokenType, TExpressionNode> infixModule);
void Register(TTokenType tokenType, string id, IInfixParselet<TTokenType, TExpressionNode> infixModule);

/// <summary>
/// Initializes a new Pratt Parser
Expand Down
13 changes: 5 additions & 8 deletions GParse/Parsing/Parselets/IInfixParselet.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GParse;
using GParse.Lexing;
using Tsu;

namespace GParse.Parsing.Parselets
{
Expand All @@ -16,20 +15,18 @@ public interface IInfixParselet<TTokenType, TExpressionNode>
/// <summary>
/// The precedence of the operator this module parses.
/// </summary>
Int32 Precedence { get; }
int Precedence { get; }

/// <summary>
/// Attempts to parse an infix/postfix expression. State should be restored by the caller on failure.
/// </summary>
/// <param name="parser">The parser that called this parselet.</param>
/// <param name="expression">The expression that was parsed on the left side of the infix.</param>
/// <param name="diagnostics">The diagnostic list to be used when reporting new diagnostics.</param>
/// <param name="parsedExpression">The resulting parsed expression.</param>
/// <returns>Whether the parsing was succesful.</returns>
Boolean TryParse(
/// <returns>The resulting parsed expression if parsing was succesful.</returns>
Option<TExpressionNode> Parse(
IPrattParser<TTokenType, TExpressionNode> parser,
TExpressionNode expression,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode parsedExpression);
DiagnosticList diagnostics);
}
}
14 changes: 5 additions & 9 deletions GParse/Parsing/Parselets/IPrefixParselet.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GParse;
using GParse.Lexing;
using GParse.Lexing;
using Tsu;

namespace GParse.Parsing.Parselets
{
Expand All @@ -18,11 +16,9 @@ public interface IPrefixParselet<TTokenType, TExpressionNode>
/// </summary>
/// <param name="parser">The parser that called this parselet.</param>
/// <param name="diagnostics">The diagnostic list to use when reporting new diagnostics.</param>
/// <param name="parsedExpression">The resulting parsed expression.</param>
/// <returns>Whether the parsing was successful.</returns>
Boolean TryParse(
/// <returns>The resulting parsed expression if successful.</returns>
Option<TExpressionNode> Parse(
IPrattParser<TTokenType, TExpressionNode> parser,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode parsedExpression);
DiagnosticList diagnostics);
}
}
20 changes: 9 additions & 11 deletions GParse/Parsing/Parselets/LiteralParselet.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GParse.Lexing;
using Tsu;

namespace GParse.Parsing.Parselets
{
Expand All @@ -11,12 +12,10 @@ namespace GParse.Parsing.Parselets
/// <typeparam name="TExpressionNode">The base type of expression nodes.</typeparam>
/// <param name="token">The obtained token.</param>
/// <param name="diagnostics">The diagnostic list to use when reporting new diagnostics.</param>
/// <param name="expression">The resulting expression node.</param>
/// <returns>Whether the expression was able to be parsed.</returns>
public delegate Boolean LiteralNodeFactory<TTokenType, TExpressionNode>(
/// <returns>The resulting expression node if it was succesful.</returns>
public delegate Option<TExpressionNode> LiteralNodeFactory<TTokenType, TExpressionNode>(
Token<TTokenType> token,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode expression)
DiagnosticList diagnostics)
where TTokenType : notnull;

/// <summary>
Expand All @@ -27,29 +26,28 @@ public delegate Boolean LiteralNodeFactory<TTokenType, TExpressionNode>(
public class LiteralParselet<TTokenType, TExpressionNode> : IPrefixParselet<TTokenType, TExpressionNode>
where TTokenType : notnull
{
private readonly LiteralNodeFactory<TTokenType, TExpressionNode> factory;
private readonly LiteralNodeFactory<TTokenType, TExpressionNode> _factory;

/// <summary>
/// Initializes a new literal parselet.
/// </summary>
/// <param name="factory">The function that transforms a token into an expression node.</param>
public LiteralParselet(LiteralNodeFactory<TTokenType, TExpressionNode> factory)
{
this.factory = factory ?? throw new ArgumentNullException(nameof(factory));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}

/// <inheritdoc />
public Boolean TryParse(
public Option<TExpressionNode> Parse(
IPrattParser<TTokenType, TExpressionNode> parser,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode parsedExpression)
DiagnosticList diagnostics)
{
if (parser is null)
throw new ArgumentNullException(nameof(parser));
if (diagnostics is null)
throw new ArgumentNullException(nameof(diagnostics));

return this.factory(parser.TokenReader.Consume(), diagnostics, out parsedExpression);
return _factory(parser.TokenReader.Consume(), diagnostics);
}
}
}
48 changes: 21 additions & 27 deletions GParse/Parsing/Parselets/SingleTokenInfixOperatorParselet.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GParse.Lexing;
using Tsu;

namespace GParse.Parsing.Parselets
{
Expand All @@ -12,13 +12,11 @@ namespace GParse.Parsing.Parselets
/// <param name="left">The expression on the left side of the operator.</param>
/// <param name="op">The operator token.</param>
/// <param name="right">The expression on the right side of the operator.</param>
/// <param name="expression">The resulting parsed expression.</param>
/// <returns>Whether it was possible to parse the expression or not.</returns>
public delegate Boolean InfixNodeFactory<TTokenType, TExpressionNode>(
/// <returns>The resulting parsed expression if it was successful.</returns>
public delegate Option<TExpressionNode> InfixNodeFactory<TTokenType, TExpressionNode>(
TExpressionNode left,
Token<TTokenType> op,
TExpressionNode right,
[NotNullWhen(true)] out TExpressionNode expression)
TExpressionNode right)
where TTokenType : notnull;

/// <summary>
Expand All @@ -29,11 +27,11 @@ public delegate Boolean InfixNodeFactory<TTokenType, TExpressionNode>(
public class SingleTokenInfixOperatorParselet<TTokenType, TExpressionNode> : IInfixParselet<TTokenType, TExpressionNode>
where TTokenType : notnull
{
private readonly Boolean isRightAssociative;
private readonly InfixNodeFactory<TTokenType, TExpressionNode> factory;
private readonly bool _isRightAssociative;
private readonly InfixNodeFactory<TTokenType, TExpressionNode> _factory;

/// <inheritdoc />
public Int32 Precedence { get; }
public int Precedence { get; }

/// <summary>
/// Initializes a new single token infix operator parselet.
Expand All @@ -42,21 +40,20 @@ public class SingleTokenInfixOperatorParselet<TTokenType, TExpressionNode> : IIn
/// <param name="isRightAssociative">Whether the operator is right-associative.</param>
/// <param name="factory">The method that transforms the infix operation into an expression node.</param>
public SingleTokenInfixOperatorParselet(
Int32 precedence,
Boolean isRightAssociative,
int precedence,
bool isRightAssociative,
InfixNodeFactory<TTokenType, TExpressionNode> factory)
{
this.Precedence = precedence;
this.isRightAssociative = isRightAssociative;
this.factory = factory ?? throw new ArgumentNullException(nameof(factory));
Precedence = precedence;
_isRightAssociative = isRightAssociative;
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}

/// <inheritdoc />
public Boolean TryParse(
public Option<TExpressionNode> Parse(
IPrattParser<TTokenType, TExpressionNode> parser,
TExpressionNode expression,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode parsedExpression)
DiagnosticList diagnostics)
{
if (parser is null)
throw new ArgumentNullException(nameof(parser));
Expand All @@ -65,23 +62,20 @@ public Boolean TryParse(
if (diagnostics is null)
throw new ArgumentNullException(nameof(diagnostics));

parsedExpression = default!;
Token<TTokenType> op = parser.TokenReader.Consume();
var op = parser.TokenReader.Consume();

// We decrease the precedence by one on right-associative operators because the minimum
// precedence passed to TryParseExpression is exclusive (meaning that the precedence of the
// infix parselets must be higher than the one we pass it.
// TODO: Check if this cannot create bugs with other operators that have the same precedence.
Int32 minPrecedence;
if (this.isRightAssociative)
minPrecedence = this.Precedence - 1;
int minPrecedence;
if (_isRightAssociative)
minPrecedence = Precedence - 1;
else
minPrecedence = this.Precedence;
minPrecedence = Precedence;

if (parser.TryParseExpression(minPrecedence, out TExpressionNode nextExpr))
return this.factory(expression, op, nextExpr, out parsedExpression);
else
return false;
return parser.ParseExpression(minPrecedence)
.AndThen(nextExpr => _factory(expression, op, nextExpr));
}
}
}
26 changes: 12 additions & 14 deletions GParse/Parsing/Parselets/SingleTokenPostfixOperatorParselet.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GParse.Lexing;
using Tsu;

namespace GParse.Parsing.Parselets
{
Expand All @@ -12,13 +13,11 @@ namespace GParse.Parsing.Parselets
/// <param name="operand">The operand expression.</param>
/// <param name="operator">The operator token.</param>
/// <param name="diagnostics">The diagnostic list to use when reporting new diagnostics.</param>
/// <param name="expression">The parsed expression if successful.</param>
/// <returns>Whether the expression was able to be parsed.</returns>
public delegate Boolean PostfixNodeFactory<TTokenType, TExpressionNode>(
/// <returns>The parsed expression if successful.</returns>
public delegate Option<TExpressionNode> PostfixNodeFactory<TTokenType, TExpressionNode>(
TExpressionNode operand,
Token<TTokenType> @operator,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode expression)
DiagnosticList diagnostics)
where TTokenType : notnull;

/// <summary>
Expand All @@ -30,31 +29,30 @@ public delegate Boolean PostfixNodeFactory<TTokenType, TExpressionNode>(
public class SingleTokenPostfixOperatorParselet<TTokenType, TExpressionNode> : IInfixParselet<TTokenType, TExpressionNode>
where TTokenType : notnull
{
private readonly PostfixNodeFactory<TTokenType, TExpressionNode> factory;
private readonly PostfixNodeFactory<TTokenType, TExpressionNode> _factory;

/// <inheritdoc />
public Int32 Precedence { get; }
public int Precedence { get; }

/// <summary>
/// Initializes a new single token postfix operator parselet.
/// </summary>
/// <param name="precedence">The precedence of the operator this parselet is parsing.</param>
/// <param name="factory">The method responsible for creating the postfix expression node.</param>
public SingleTokenPostfixOperatorParselet(Int32 precedence, PostfixNodeFactory<TTokenType, TExpressionNode> factory)
public SingleTokenPostfixOperatorParselet(int precedence, PostfixNodeFactory<TTokenType, TExpressionNode> factory)
{
if (precedence < 1)
throw new ArgumentOutOfRangeException(nameof(precedence), "Precedence of the operator must be greater than 0");

this.Precedence = precedence;
this.factory = factory ?? throw new ArgumentNullException(nameof(factory));
Precedence = precedence;
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}

/// <inheritdoc />
public Boolean TryParse(
public Option<TExpressionNode> Parse(
IPrattParser<TTokenType, TExpressionNode> parser,
TExpressionNode expression,
DiagnosticList diagnostics,
[NotNullWhen(true)] out TExpressionNode parsedExpression)
DiagnosticList diagnostics)
{
if (parser is null)
throw new ArgumentNullException(nameof(parser));
Expand All @@ -63,7 +61,7 @@ public Boolean TryParse(
if (diagnostics is null)
throw new ArgumentNullException(nameof(diagnostics));

return this.factory(expression, parser.TokenReader.Consume(), diagnostics, out parsedExpression);
return _factory(expression, parser.TokenReader.Consume(), diagnostics);
}
}
}
Loading

0 comments on commit 208da53

Please sign in to comment.