Skip to content

Commit

Permalink
feat: Better Precedence Handling
Browse files Browse the repository at this point in the history
  • Loading branch information
furesoft committed Jul 12, 2024
1 parent 3d52040 commit 3e8bcc6
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 71 deletions.
2 changes: 1 addition & 1 deletion Source/Samples/Sample.FuncLanguage/ExpressionGrammar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected override void InitParselets()
AddCommonLiterals();
AddArithmeticOperators();

Register("(", new CallParselet(BindingPowers.Get("Call")));
Register("(", new CallParselet(PrecedenceLevels.Get("Call")));
Register("(", new TupleOrGroupParselet());

Register(PredefinedSymbols.Name, new NameParselet());
Expand Down
2 changes: 2 additions & 0 deletions Source/Silverfly.Testing/SnapshotParserTestBase.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using Argon;
using Silverfly.Testing.Converter;
using static VerifyTests.VerifierSettings;
Expand Down
45 changes: 0 additions & 45 deletions Source/Silverfly/BindingPowerBuilder.cs

This file was deleted.

25 changes: 25 additions & 0 deletions Source/Silverfly/DefaultPrecedenceLevels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Silverfly;

public class DefaultPrecedenceLevels : PrecedenceLevels
{
public static string Assignment = nameof(Assignment);
public static string Conditional = nameof(Conditional);
public static string Sum = nameof(Sum);
public static string Product = nameof(Sum);
public static string Exponent = nameof(Exponent);
public static string Prefix = nameof(Prefix);
public static string PostFix = nameof(PostFix);
public static string Call = nameof(Call);

public DefaultPrecedenceLevels()
{
AddPrecedence(Assignment);
AddPrecedence(Conditional);
AddPrecedence(Sum);
AddPrecedence(Product);
AddPrecedence(Exponent);
AddPrecedence(Prefix);
AddPrecedence(PostFix);
AddPrecedence(Call);
}
}
30 changes: 6 additions & 24 deletions Source/Silverfly/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract partial class Parser
private readonly List<Token> _read = [];
private Lexer _lexer;

public SymbolPool BindingPowers { get; internal set; }
public PrecedenceLevels PrecedenceLevels = new DefaultPrecedenceLevels();

public SourceDocument Document => _lexer.Document;

Expand Down Expand Up @@ -91,11 +91,6 @@ public static TranslationUnit Parse<TParser>(string source, string filename = "s

var parser = new TParser { _lexer = lexer };

var bindingPowerBuilder = new BindingPowerBuilder();

parser.InitBindingPower(bindingPowerBuilder); // Have to be initialized before parselets to allow named reference
parser.BindingPowers = bindingPowerBuilder.BuildPool();

parser.InitParselets();

AddLexerSymbols(lexer, parser._prefixParselets);
Expand Down Expand Up @@ -164,19 +159,6 @@ public AstNode ParseExpression()
protected abstract void InitLexer(Lexer lexer);
protected abstract void InitParselets();

protected virtual void InitBindingPower(BindingPowerBuilder precedence)
{
precedence
.StrongerThan("Exponent", "Product")
.StrongerThan("Product", "Sum")
.StrongerThan("Sum", "Conditional")
.StrongerThan("Conditional", "Assignment")
.StrongerThan("Prefix", "Exponent")
.StrongerThan("Postfix", "Call")
.StrongerThan("Prefix", "Postfix")
.StrongerThan("Prefix", "Sum");
}

public bool Match(Symbol expected)
{
if (!IsMatch(expected))
Expand Down Expand Up @@ -297,31 +279,31 @@ private int GetBindingPower()
/// </summary>
protected void Postfix(Symbol token, string bindingPowerName = "Postfix")
{
Register(token, new PostfixOperatorParselet(BindingPowers.Get(bindingPowerName)));
Register(token, new PostfixOperatorParselet(PrecedenceLevels.GetPrecedence(bindingPowerName)));
}

/// <summary>
/// Registers a prefix unary operator parselet for the given token and binding power.
/// </summary>
protected void Prefix(Symbol token, string bindingPowerName = "Prefix")
{
Register(token, new PrefixOperatorParselet(BindingPowers.Get(bindingPowerName)));
Register(token, new PrefixOperatorParselet(PrecedenceLevels.GetPrecedence(bindingPowerName)));
}

/// <summary>
/// Registers a left-associative binary operator parselet for the given token and binding power.
/// </summary>
protected void InfixLeft(Symbol token, string bindingPowerName)
{
Register(token, new BinaryOperatorParselet(BindingPowers.Get(bindingPowerName), false));
Register(token, new BinaryOperatorParselet(PrecedenceLevels.GetPrecedence(bindingPowerName), false));
}

/// <summary>
/// Registers a right-associative binary operator parselet for the given token and binding power.
/// </summary>
protected void InfixRight(Symbol token, string bindingPowerName)
{
Register(token, new BinaryOperatorParselet(BindingPowers.Get(bindingPowerName), true));
Register(token, new BinaryOperatorParselet(PrecedenceLevels.GetPrecedence(bindingPowerName), true));
}

/// <summary>
Expand All @@ -332,6 +314,6 @@ protected void InfixRight(Symbol token, string bindingPowerName)
/// <param name="bindingPower"></param>
protected void Ternary(Symbol firstSymbol, Symbol secondSymbol, string bindingPowerName)
{
Register(firstSymbol, new TernaryOperatorParselet(secondSymbol, BindingPowers.Get(bindingPowerName)));
Register(firstSymbol, new TernaryOperatorParselet(secondSymbol, PrecedenceLevels.GetPrecedence(bindingPowerName)));
}
}
31 changes: 31 additions & 0 deletions Source/Silverfly/PrecedenceLevels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Generic;

namespace Silverfly;

public abstract class PrecedenceLevels
{
private readonly List<string> precedenceLevels = new List<string>();

public int GetPrecedence(string level)
{
var index = precedenceLevels.IndexOf(level);

return index == -1 ? precedenceLevels.Count : index;
}

public void AddPrecedence(string level)
{
if (!precedenceLevels.Contains(level))
{
precedenceLevels.Add(level);
}
}

public void InsertPrecedence(int index, string level)
{
if (!precedenceLevels.Contains(level))
{
precedenceLevels.Insert(index, level);
}
}
}
2 changes: 1 addition & 1 deletion Source/TestProject/TestParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ protected override void InitParselets()
{
Register(PredefinedSymbols.Name, new NameParselet());

Register("(", new CallParselet(BindingPowers.Get("Call").Id));
Register("(", new CallParselet(PrecedenceLevels.GetPrecedence("Call")));

Ternary("?", ":", "Conditional");
InfixLeft(".", "Call");
Expand Down

0 comments on commit 3e8bcc6

Please sign in to comment.