ZoneCodeGenerator: Add basis for align, strings and improved count tests

This commit is contained in:
Jan 2019-10-21 17:00:37 +02:00
parent 00d5cb40ae
commit 06585fb776
5 changed files with 179 additions and 29 deletions

View File

@ -11,6 +11,7 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Impl
class CommandParserState : ICommandParserState
{
private static readonly ITokenTest<ICommandParserState>[] tests = {
new TestAlign(),
new TestAsset(),
new TestBlock(),
new TestCondition(),
@ -18,6 +19,7 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Impl
new TestGame(),
new TestReorder(),
new TestScriptString(),
new TestString(),
new TestUse()
};

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing;
namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{
class TestAlign : AbstractTokenTest<ICommandParserState>
{
private const string MemberTypeNameToken = "name";
private const string AlignValueToken = "align";
private static readonly TokenMatcher[] matchers = {
new MatcherLiteral("set"),
new MatcherLiteral("align"),
new MatcherTypename().WithName(MemberTypeNameToken),
new MatcherNumber().WithName(AlignValueToken),
new MatcherLiteral(";")
};
public TestAlign() : base(matchers)
{
}
protected override void ProcessMatch(ICommandParserState state)
{
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZoneCodeGenerator.Domain.Evaluation;
using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing;
@ -10,11 +11,15 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{
class TestCount : AbstractTokenTest<ICommandParserState>
{
private const string TypeNameToken = "typeName";
private const string CalculationStatementTag = "calculationStatement";
private const string OperationTag = "operation";
private const string OperandTag = "operand";
private const string OperationOfCalculationStatementTag = "operationOfCalculationStatement";
private const string TypeNameToken = "typeName";
private const string OperationToken = "operationToken";
// operand ::= <typename> <array>* | <number>
private static readonly TokenMatcher operand = new MatcherGroupOr(
new MatcherGroupAnd(
@ -26,28 +31,29 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
// operation ::= + | - | * | / | << | >>
private static readonly TokenMatcher operation = new MatcherGroupOr(
new MatcherLiteral("+"),
new MatcherLiteral("-"),
new MatcherLiteral("*"),
new MatcherLiteral("/"),
new MatcherGroupAnd(new MatcherLiteral("<"), new MatcherLiteral("<")),
new MatcherGroupAnd(new MatcherLiteral(">"), new MatcherLiteral(">"))
new MatcherLiteral("+").WithName(OperationToken),
new MatcherLiteral("-").WithName(OperationToken),
new MatcherLiteral("*").WithName(OperationToken),
new MatcherLiteral("/").WithName(OperationToken),
new MatcherLiteral("<", "<").WithName(OperationToken),
new MatcherLiteral(">", ">").WithName(OperationToken)
).WithTag(OperationTag);
// calculationStatement ::= ( <calculationStatement> ) | <operand> [<operation> <calculationStatement>]
private static readonly TokenMatcher calculationStatement = new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherLiteral("("),
new MatcherWithTag(CalculationStatementTag),
new MatcherLiteral(")")
private static readonly TokenMatcher calculationStatement = new MatcherGroupAnd(
new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherLiteral("("),
new MatcherWithTag(CalculationStatementTag),
new MatcherLiteral(")")
),
new MatcherWithTag(OperandTag)
),
new MatcherGroupAnd(
new MatcherWithTag(OperandTag),
new MatcherGroupOptional(new MatcherGroupAnd(
new MatcherWithTag(OperationTag),
new MatcherWithTag(CalculationStatementTag)
))
)
new MatcherGroupOptional(new MatcherGroupAnd(
new MatcherWithTag(OperationTag),
new MatcherWithTag(CalculationStatementTag)
)).WithTag(OperationOfCalculationStatementTag)
).WithTag(CalculationStatementTag);
// set count <typename> <calculationStatement>;
@ -69,6 +75,71 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
protected override void ProcessMatch(ICommandParserState state)
{
switch (NextTag())
{
case CalculationStatementTag:
ProcessCalculationStatement(state);
break;
default:
throw new Exception("Expected first count tag to be a calculation statement");
}
}
private IEvaluation ProcessCalculationStatement(ICommandParserState state)
{
IEvaluation firstStatementPart;
switch (NextTag())
{
case CalculationStatementTag:
firstStatementPart = ProcessCalculationStatement(state);
break;
case OperandTag:
firstStatementPart = ProcessOperand(state);
break;
default:
throw new Exception("Invalid followup tag @ CalculationStatement");
}
if (PeekTag() == OperationOfCalculationStatementTag)
{
NextTag();
if(NextTag() != OperationTag)
throw new Exception("Expected operation tag @ CalculationStatement");
OperationType operationType = ProcessOperation(state);
if (NextTag() != CalculationStatementTag)
throw new Exception("Expected calculationStatement tag @ CalculationStatement");
var secondStatementPart = ProcessCalculationStatement(state);
return new Operation(firstStatementPart, secondStatementPart, operationType);
}
return firstStatementPart;
}
private IEvaluation ProcessOperand(ICommandParserState state)
{
return null;
}
private OperationType ProcessOperation(ICommandParserState state)
{
var operationToken = NextMatch(OperationToken);
var result = OperationType.Types.FirstOrDefault(type => type.Syntax.Equals(operationToken));
if (result == null)
{
throw new LoadingException($"Unknown operation '{operationToken}'");
}
return result;
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing;
namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{
class TestString : AbstractTokenTest<ICommandParserState>
{
private const string MemberTypeNameToken = "name";
private static readonly TokenMatcher[] matchers = {
new MatcherLiteral("set"),
new MatcherLiteral("string"),
new MatcherTypename().WithName(MemberTypeNameToken),
new MatcherLiteral(";")
};
public TestString() : base(matchers)
{
}
protected override void ProcessMatch(ICommandParserState state)
{
}
}
}

View File

@ -1,28 +1,37 @@
namespace ZoneCodeGenerator.Parsing.Matching.Matchers
using System.Text;
namespace ZoneCodeGenerator.Parsing.Matching.Matchers
{
class MatcherLiteral : BaseMatcher
{
private readonly string literal;
private readonly string[] literals;
public MatcherLiteral(string literal)
public MatcherLiteral(params string[] literals)
{
this.literal = literal;
this.literals = literals;
}
protected override MatchingResult Matches(MatchingContext context, int tokenOffset)
{
var token = context.Lexer.PeekToken(tokenOffset);
var isMatch = string.Equals(token, literal);
var matcherOutputBuilder = new StringBuilder();
if (!isMatch) return new MatchingResult(false, 0);
foreach (var literal in literals)
{
var token = context.Lexer.PeekToken(tokenOffset);
var isMatch = string.Equals(token, literal);
SetMatcherOutput(literal);
return new MatchingResult(true, 1);
if (!isMatch) return new MatchingResult(false, 0);
matcherOutputBuilder.Append(literal);
}
SetMatcherOutput(matcherOutputBuilder.ToString());
return new MatchingResult(true, literals.Length);
}
protected override string GetIdentifier()
{
return $"Literal(\"{literal}\")";
return $"Literal(\"{string.Join("", literals)}\")";
}
}
}