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

Added support of one or more of choice clauses to EBNF parser: #161

Merged
merged 1 commit into from Feb 22, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 79 additions & 4 deletions ParserTests/EBNFTests.cs
Expand Up @@ -220,7 +220,16 @@ public string Choice(List<Token<OptionTestToken>> list)
return string.Join(",",list.Select(x => x.Value));
}
}


public class AlternateChoiceTestOneOrMoreTerminal
{
[Production("choice : [ a | b | c]+")]
public string Choice(List<Token<OptionTestToken>> list)
{
return string.Join(",", list.Select(x => x.Value));
}
}

public class AlternateChoiceTestOptionTerminal
{
[Production("choice : [ a | b | c] [ b | c]?")]
Expand Down Expand Up @@ -310,7 +319,35 @@ public string A(Token<OptionTestToken> t)
}

}


public class AlternateChoiceTestOneOrMoreNonTerminal
{
[Production("choice : [ A | B | C]+")]
public string Choice(List<String> choices)
{
return string.Join(" ", choices);
}

[Production("C : c")]
public string C(Token<OptionTestToken> t)
{
return $"C({t.Value})";
}

[Production("B : b")]
public string B(Token<OptionTestToken> t)
{
return $"B({t.Value})";
}

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

}

public class Bugfix104Test
{
[Production("testNonTerm : sub (COMMA[d] unreachable)? ")]
Expand Down Expand Up @@ -866,7 +903,29 @@ public void TestAlternateChoiceNonTerminal()
parseResult = builtParser.Result.Parse("d", "choice");
Assert.False(parseResult.IsOk);
}


[Fact]
public void TestAlternateChoiceOneOrMoreNonTerminal()
{
var startingRule = $"choice";
var parserInstance = new AlternateChoiceTestOneOrMoreNonTerminal();
var builder = new ParserBuilder<OptionTestToken, string>();
var builtParser = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, startingRule);
Assert.False(builtParser.IsError);
Assert.False(builtParser.Errors.Any());
var parseResult = builtParser.Result.Parse("a b", "choice");
Assert.True(parseResult.IsOk);
Assert.Equal("A(a) B(b)", parseResult.Result);
parseResult = builtParser.Result.Parse("b", "choice");
Assert.True(parseResult.IsOk);
Assert.Equal("B(b)", parseResult.Result);
parseResult = builtParser.Result.Parse("c", "choice");
Assert.True(parseResult.IsOk);
Assert.Equal("C(c)", parseResult.Result);
parseResult = builtParser.Result.Parse("d", "choice");
Assert.False(parseResult.IsOk);
}

[Fact]
public void TestAlternateChoiceZeroOrMoreTerminal()
{
Expand All @@ -882,7 +941,23 @@ public void TestAlternateChoiceZeroOrMoreTerminal()
parseResult = builtParser.Result.Parse("b", "choice");
Assert.True(parseResult.IsOk);
}


[Fact]
public void TestAlternateChoiceOneOrMoreTerminal()
{
var startingRule = $"choice";
var parserInstance = new AlternateChoiceTestOneOrMoreTerminal();
var builder = new ParserBuilder<OptionTestToken, string>();
var builtParser = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, startingRule);
Assert.False(builtParser.IsError);
Assert.False(builtParser.Errors.Any());
var parseResult = builtParser.Result.Parse("a b c", "choice");
Assert.True(parseResult.IsOk);
Assert.Equal("a,b,c", parseResult.Result);
parseResult = builtParser.Result.Parse("b", "choice");
Assert.True(parseResult.IsOk);
}

[Fact]
public void TestAlternateChoiceOptionTerminal()
{
Expand Down
6 changes: 4 additions & 2 deletions sly/parser/generator/ParserBuilder.cs
Expand Up @@ -289,8 +289,10 @@ private static bool NonTerminalReferences(NonTerminal<IN> nonTerminal, string re
}
else if (clause is OneOrMoreClause<IN> oneOrMore)
{
if (oneOrMore.Clause is NonTerminalClause<IN> inner)
found = inner.NonTerminalName == referenceName;
if (oneOrMore.Clause is NonTerminalClause<IN> innerNonTerminal)
found = innerNonTerminal.NonTerminalName == referenceName;
if (oneOrMore.Clause is ChoiceClause<IN> innerChoice && innerChoice.IsNonTerminalChoice)
found = innerChoice.Choices.Where(c => (c as NonTerminalClause<IN>).NonTerminalName == referenceName).Any();
}
else if (clause is ChoiceClause<IN> choice)
{
Expand Down
Expand Up @@ -368,6 +368,12 @@ public SyntaxParseResult<IN> ParseOneOrMore(IList<Token<IN>> tokens, OneOrMoreCl
manyNode.IsManyValues = true;
firstInnerResult = ParseNonTerminal(tokens, innerClause as NonTerminalClause<IN>, currentPosition);
}
else if (innerClause is ChoiceClause<IN> choice)
{
manyNode.IsManyTokens = choice.IsTerminalChoice;
manyNode.IsManyValues = choice.IsNonTerminalChoice;
firstInnerResult = ParseChoice(tokens, choice, currentPosition);
}
else
{
throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name);
Expand Down