Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/issue #507 #508

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ coverage.json
ruleset1.ruleset
opencov.bat
BenchmarkDotNet.Artifacts

*.nupkg
*.snupkg
*.swp
AotTester/*
*.dtp
*.dtp.state
10 changes: 9 additions & 1 deletion src/samples/ParserExample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ public static object Rec(List<object> args)
}


private static void TestIssue507()
{
var tests = new EBNFTests();
//tests.TestIssue507TransitiveEmptyStarter();
tests.TestIssue507MoreTransitiveEmptyStarter();
}

private static void BenchSimpleExpression()
{
GenericSimpleExpressionParser p = new GenericSimpleExpressionParser();
Expand Down Expand Up @@ -1353,7 +1360,8 @@ print a
}
private static void Main(string[] args)
{
TestFStrings();
TestIssue507();
//TestFStrings();
//TestIssue495();
//testGenericLexerJson();
// TestIssue487();
Expand Down
26 changes: 26 additions & 0 deletions src/sly/parser/generator/EBNFParserBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public override BuildResult<Parser<IN, OUT>> BuildParser(object parserInstance,
configuration.AutoCloseIndentations = autoCloseIndentations;
LeftRecursionChecker<IN, OUT> recursionChecker = new LeftRecursionChecker<IN, OUT>();

SetEmptyNonTerminals(configuration);
// check left recursion.
var (foundRecursion, recursions) = LeftRecursionChecker<IN, OUT>.CheckLeftRecursion(configuration);
if (foundRecursion)
Expand Down Expand Up @@ -118,6 +119,31 @@ protected override ISyntaxParser<IN, OUT> BuildSyntaxParser(ParserConfiguration<
return parser;
}

private void SetEmptyNonTerminals(ParserConfiguration<IN, OUT> conf)
{
bool stillSetting = true;
while (stillSetting)
{
stillSetting = false;
foreach (var nt in conf.NonTerminals)
{
foreach (var rule in nt.Value.Rules)
{
foreach (var clause in rule.Clauses)
{
if (clause is NonTerminalClause<IN> nonTerminalClause)
{
var rules = conf.GetRulesForNonTerminal(nonTerminalClause.NonTerminalName);
stillSetting |= nonTerminalClause.SetMayBeEmpty(rules.Exists(x => x.MayBeEmpty));
}
}
}
}
}
}




#region configuration

Expand Down
9 changes: 9 additions & 0 deletions src/sly/parser/generator/ParserConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ public List<TerminalClause<IN>> GetAllExplicitTokenClauses()
return clauses;
}

public List<Rule<IN>> GetRulesForNonTerminal(string nonTerminal)
{
if (NonTerminals.TryGetValue(nonTerminal, out NonTerminal<IN> nonTerminalConfig))
{
return nonTerminalConfig.Rules.ToList();
}
return new List<Rule<IN>>();
}

[ExcludeFromCodeCoverage]
public string Dump()
{
Expand Down
12 changes: 10 additions & 2 deletions src/sly/parser/syntax/grammar/NonTerminalClause.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Diagnostics.CodeAnalysis;

namespace sly.parser.syntax.grammar
Expand All @@ -14,9 +13,18 @@ public NonTerminalClause(string name)

public bool IsGroup { get; set; } = false;

private bool _mayBeEmpty = false;

public bool MayBeEmpty()
{
return false;
return _mayBeEmpty;
}

public bool SetMayBeEmpty(bool mayBeEmpty)
{
bool setted = mayBeEmpty && !_mayBeEmpty;
_mayBeEmpty = mayBeEmpty;
return setted;
}


Expand Down
2 changes: 1 addition & 1 deletion src/sly/sly.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net7.0;netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
Expand Down
95 changes: 94 additions & 1 deletion tests/ParserTests/EBNFTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using expressionparser;
using indented;
using jsonparser;
using jsonparser.JsonModel;
Expand Down Expand Up @@ -580,6 +579,64 @@ public string A(Token<OptionTestToken> t)

}

public class Issue507TransitiveEmptyStarterParser
{
[Production("x : y")]
public string X(string y)
{
return y;
}

[Production("y : z*")]
public string Y(List<string> zs)
{
if (zs.Any())
{
return string.Join(",", zs);
}

return "empty";
}

[Production("z : a")]
public string Z(Token<OptionTestToken> a)
{
return a.Value;
}
}

public class Issue507MoreTransitiveEmptyStarterParser
{
[Production("x : w")]
public string X(string w)
{
return w;
}

[Production("w : y")]
public string W(string y)
{
return y;
}

[Production("y : z*")]
public string Y(List<string> zs)
{
if (zs.Any())
{
return string.Join(",", zs);
}

return "empty";
}

[Production("z : a")]
public string Z(Token<OptionTestToken> a)
{
return a.Value;
}
}

public class Bugfix104Test
{
[Production("testNonTerm : sub (COMMA[d] unreachable)? ")]
Expand Down Expand Up @@ -1324,6 +1381,42 @@ public void TestAlternateChoiceInGroupLeftRecursion()
}


[Fact]
public void TestIssue507TransitiveEmptyStarter()
{
var startingRule = $"x";
var parserInstance = new Issue507TransitiveEmptyStarterParser();
var builder = new ParserBuilder<OptionTestToken, string>();
var builtParser = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, startingRule);
Check.That(builtParser).IsOk();
var parser = builtParser.Result;
var parserResultNotEmpty = parser.Parse("a a a");
Check.That(parserResultNotEmpty).IsOkParsing();
Check.That(parserResultNotEmpty.Result).IsEqualTo("a,a,a");

var parserResultEmpty = parser.Parse("");
Check.That(parserResultEmpty).IsOkParsing();
Check.That(parserResultEmpty.Result).IsEqualTo("empty");
}

[Fact]
public void TestIssue507MoreTransitiveEmptyStarter()
{
var startingRule = $"x";
var parserInstance = new Issue507MoreTransitiveEmptyStarterParser();
var builder = new ParserBuilder<OptionTestToken, string>();
var builtParser = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, startingRule);
Check.That(builtParser).IsOk();
var parser = builtParser.Result;
var parserResultNotEmpty = parser.Parse("a a a");
Check.That(parserResultNotEmpty).IsOkParsing();
Check.That(parserResultNotEmpty.Result).IsEqualTo("a,a,a");

var parserResultEmpty = parser.Parse("");
Check.That(parserResultEmpty).IsOkParsing();
Check.That(parserResultEmpty.Result).IsEqualTo("empty");
}

[Fact]
public void TestIssue190()
{
Expand Down
1 change: 1 addition & 0 deletions tests/ParserTests/ParserTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<ProjectReference Include="..\..\src\samples\SlowEOS\SlowEOS.csproj" />
<ProjectReference Include="..\..\src\samples\while\while.csproj" />
<ProjectReference Include="..\..\src\samples\XML\XML.csproj" />
<ProjectReference Include="..\..\src\sly\sly.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
Expand Down
Loading