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 class CommandParserState : ICommandParserState
{ {
private static readonly ITokenTest<ICommandParserState>[] tests = { private static readonly ITokenTest<ICommandParserState>[] tests = {
new TestAlign(),
new TestAsset(), new TestAsset(),
new TestBlock(), new TestBlock(),
new TestCondition(), new TestCondition(),
@ -18,6 +19,7 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Impl
new TestGame(), new TestGame(),
new TestReorder(), new TestReorder(),
new TestScriptString(), new TestScriptString(),
new TestString(),
new TestUse() 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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ZoneCodeGenerator.Domain.Evaluation;
using ZoneCodeGenerator.Parsing.Matching; using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers; using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing; using ZoneCodeGenerator.Parsing.Testing;
@ -10,11 +11,15 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{ {
class TestCount : AbstractTokenTest<ICommandParserState> class TestCount : AbstractTokenTest<ICommandParserState>
{ {
private const string TypeNameToken = "typeName";
private const string CalculationStatementTag = "calculationStatement"; private const string CalculationStatementTag = "calculationStatement";
private const string OperationTag = "operation"; private const string OperationTag = "operation";
private const string OperandTag = "operand"; private const string OperandTag = "operand";
private const string OperationOfCalculationStatementTag = "operationOfCalculationStatement";
private const string TypeNameToken = "typeName";
private const string OperationToken = "operationToken";
// operand ::= <typename> <array>* | <number> // operand ::= <typename> <array>* | <number>
private static readonly TokenMatcher operand = new MatcherGroupOr( private static readonly TokenMatcher operand = new MatcherGroupOr(
new MatcherGroupAnd( new MatcherGroupAnd(
@ -26,28 +31,29 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
// operation ::= + | - | * | / | << | >> // operation ::= + | - | * | / | << | >>
private static readonly TokenMatcher operation = new MatcherGroupOr( private static readonly TokenMatcher operation = new MatcherGroupOr(
new MatcherLiteral("+"), new MatcherLiteral("+").WithName(OperationToken),
new MatcherLiteral("-"), new MatcherLiteral("-").WithName(OperationToken),
new MatcherLiteral("*"), new MatcherLiteral("*").WithName(OperationToken),
new MatcherLiteral("/"), new MatcherLiteral("/").WithName(OperationToken),
new MatcherGroupAnd(new MatcherLiteral("<"), new MatcherLiteral("<")), new MatcherLiteral("<", "<").WithName(OperationToken),
new MatcherGroupAnd(new MatcherLiteral(">"), new MatcherLiteral(">")) new MatcherLiteral(">", ">").WithName(OperationToken)
).WithTag(OperationTag); ).WithTag(OperationTag);
// calculationStatement ::= ( <calculationStatement> ) | <operand> [<operation> <calculationStatement>] // calculationStatement ::= ( <calculationStatement> ) | <operand> [<operation> <calculationStatement>]
private static readonly TokenMatcher calculationStatement = new MatcherGroupOr( private static readonly TokenMatcher calculationStatement = new MatcherGroupAnd(
new MatcherGroupOr(
new MatcherGroupAnd( new MatcherGroupAnd(
new MatcherLiteral("("), new MatcherLiteral("("),
new MatcherWithTag(CalculationStatementTag), new MatcherWithTag(CalculationStatementTag),
new MatcherLiteral(")") new MatcherLiteral(")")
), ),
new MatcherGroupAnd( new MatcherWithTag(OperandTag)
new MatcherWithTag(OperandTag), ),
new MatcherGroupOptional(new MatcherGroupAnd( new MatcherGroupOptional(new MatcherGroupAnd(
new MatcherWithTag(OperationTag), new MatcherWithTag(OperationTag),
new MatcherWithTag(CalculationStatementTag) new MatcherWithTag(CalculationStatementTag)
)) )).WithTag(OperationOfCalculationStatementTag)
)
).WithTag(CalculationStatementTag); ).WithTag(CalculationStatementTag);
// set count <typename> <calculationStatement>; // set count <typename> <calculationStatement>;
@ -69,6 +75,71 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
protected override void ProcessMatch(ICommandParserState state) 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 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) protected override MatchingResult Matches(MatchingContext context, int tokenOffset)
{
var matcherOutputBuilder = new StringBuilder();
foreach (var literal in literals)
{ {
var token = context.Lexer.PeekToken(tokenOffset); var token = context.Lexer.PeekToken(tokenOffset);
var isMatch = string.Equals(token, literal); var isMatch = string.Equals(token, literal);
if (!isMatch) return new MatchingResult(false, 0); if (!isMatch) return new MatchingResult(false, 0);
SetMatcherOutput(literal); matcherOutputBuilder.Append(literal);
return new MatchingResult(true, 1); }
SetMatcherOutput(matcherOutputBuilder.ToString());
return new MatchingResult(true, literals.Length);
} }
protected override string GetIdentifier() protected override string GetIdentifier()
{ {
return $"Literal(\"{literal}\")"; return $"Literal(\"{string.Join("", literals)}\")";
} }
} }
} }