ZoneCodeGenerator: Create parent class for all tests that use Evaluations

This commit is contained in:
Jan 2019-10-27 01:46:43 +02:00
parent 6ea19c6fe2
commit 5245f40307
3 changed files with 192 additions and 206 deletions

View File

@ -1,119 +1,57 @@
using System; using System;
using System.Collections.Generic; using ZoneCodeGenerator.Domain.Evaluation;
using System.Text;
using ZoneCodeGenerator.Parsing.Matching; using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers; using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing;
namespace ZoneCodeGenerator.Parsing.CommandFile.Tests namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{ {
class TestCondition : AbstractTokenTest<ICommandParserState> class TestCondition : TestWithEvaluation
{ {
private const string TagAlways = "always";
private const string TagNever = "never";
private const string TypeNameToken = "typeName"; private const string TypeNameToken = "typeName";
private const string ConditionStatementTag = "conditionStatement";
private const string ConditionTag = "condition";
private const string ConditionRelationTag = "conditionRelation";
private const string OperationTag = "operation";
private const string OperandTag = "operand";
private const string ConditionChainLinkTag = "conditionChainLink";
private const string ConditionChainTag = "conditionChain";
// operand ::= <typename> <array>+ | <number> | true | false // set condition <typename> (always | never | <CalculationStatementTag>);
private static readonly TokenMatcher operand = new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherTypename(),
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple, new MatcherArray())
),
new MatcherNumber(),
new MatcherLiteral("true"),
new MatcherLiteral("false")
).WithTag(OperandTag);
// 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(">"))
).WithTag(OperationTag);
// conditionStatement ::= ( <conditionStatement> ) | <operand> [<operation> <operand>]
private static readonly TokenMatcher conditionStatement = new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherLiteral("("),
new MatcherWithTag(ConditionStatementTag),
new MatcherLiteral(")")
),
new MatcherGroupAnd(
new MatcherWithTag(OperandTag),
new MatcherGroupOptional(new MatcherGroupAnd(
new MatcherWithTag(OperationTag),
new MatcherWithTag(ConditionStatementTag)
))
)
).WithTag(ConditionStatementTag);
// conditionChainLink ::= == | != | <= | >= | < | >
private static readonly TokenMatcher conditionRelation = new MatcherGroupOr(
new MatcherGroupAnd(new MatcherLiteral("="), new MatcherLiteral("=")),
new MatcherGroupAnd(new MatcherLiteral("!"), new MatcherLiteral("=")),
new MatcherGroupAnd(new MatcherLiteral("<"), new MatcherLiteral("=")),
new MatcherGroupAnd(new MatcherLiteral(">"), new MatcherLiteral("=")),
new MatcherLiteral("<"),
new MatcherLiteral(">")
).WithTag(ConditionRelationTag);
// condition ::= <conditionStatement> <conditionRelation> <conditionStatement>
private static readonly TokenMatcher condition = new MatcherGroupAnd(
new MatcherWithTag(ConditionStatementTag),
new MatcherWithTag(ConditionRelationTag),
new MatcherWithTag(ConditionStatementTag)
).WithTag(ConditionTag);
// conditionChainLink ::= && | ||
private static readonly TokenMatcher conditionChainLink = new MatcherGroupOr(
new MatcherGroupAnd(new MatcherLiteral("&"), new MatcherLiteral("&")),
new MatcherGroupAnd(new MatcherLiteral("|"), new MatcherLiteral("|"))
).WithTag(ConditionChainLinkTag);
// conditionChain ::= <condition> (<conditionChainLink> <condition>)*
private static readonly TokenMatcher conditionChain = new MatcherGroupAnd(
new MatcherWithTag(ConditionTag),
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple, new MatcherGroupAnd(
new MatcherWithTag(ConditionChainLinkTag),
new MatcherWithTag(ConditionTag)
))
).WithTag(ConditionChainTag);
// set condition <typename> (always | never | <conditionChain>);
private static readonly TokenMatcher[] matchers = private static readonly TokenMatcher[] matchers =
{ {
new MatcherLiteral("set"), new MatcherLiteral("set"),
new MatcherLiteral("condition"), new MatcherLiteral("condition"),
new MatcherTypename().WithName(TypeNameToken), new MatcherTypename().WithName(TypeNameToken),
new MatcherGroupOr( new MatcherGroupOr(
new MatcherLiteral("always"), new MatcherLiteral("always").WithTag(TagAlways),
new MatcherLiteral("never"), new MatcherLiteral("never").WithTag(TagNever),
new MatcherWithTag(ConditionChainTag) new MatcherWithTag(TagEvaluation)
), ),
new MatcherLiteral(";") new MatcherLiteral(";")
}; };
public TestCondition() : base(matchers) public TestCondition() : base(matchers)
{ {
AddTaggedMatcher(operand);
AddTaggedMatcher(operation);
AddTaggedMatcher(conditionStatement);
AddTaggedMatcher(conditionRelation);
AddTaggedMatcher(condition);
AddTaggedMatcher(conditionChainLink);
AddTaggedMatcher(conditionChain);
} }
protected override void ProcessMatch(ICommandParserState state) protected override void ProcessMatch(ICommandParserState state)
{ {
IEvaluation evaluation;
switch (NextTag())
{
case TagAlways:
evaluation = new OperandStatic(1);
break;
case TagNever:
evaluation = new OperandStatic(0);
break;
case TagEvaluation:
evaluation = ProcessEvaluation(state);
break;
default:
throw new Exception("Unexpected Tag in TestCondition");
}
} }
} }
} }

View File

@ -1,60 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
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;
namespace ZoneCodeGenerator.Parsing.CommandFile.Tests namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{ {
class TestCount : AbstractTokenTest<ICommandParserState> class TestCount : TestWithEvaluation
{ {
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 TypeNameToken = "typeName";
private const string OperationToken = "operationToken";
// operand ::= <typename> <array>* | <number>
private static readonly TokenMatcher operand = new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherTypename(),
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple, new MatcherArray())
),
new MatcherNumber()
).WithTag(OperandTag);
// operation ::= + | - | * | / | << | >>
private static readonly TokenMatcher operation = new MatcherGroupOr(
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 MatcherGroupAnd(
new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherLiteral("("),
new MatcherWithTag(CalculationStatementTag),
new MatcherLiteral(")")
),
new MatcherWithTag(OperandTag)
),
new MatcherGroupOptional(new MatcherGroupAnd(
new MatcherWithTag(OperationTag),
new MatcherWithTag(CalculationStatementTag)
)).WithTag(OperationOfCalculationStatementTag)
).WithTag(CalculationStatementTag);
// set count <typename> <calculationStatement>; // set count <typename> <calculationStatement>;
private static readonly TokenMatcher[] matchers = private static readonly TokenMatcher[] matchers =
@ -62,84 +14,23 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
new MatcherLiteral("set"), new MatcherLiteral("set"),
new MatcherLiteral("count"), new MatcherLiteral("count"),
new MatcherTypename().WithName(TypeNameToken), new MatcherTypename().WithName(TypeNameToken),
new MatcherWithTag(CalculationStatementTag), new MatcherWithTag(TagEvaluation),
new MatcherLiteral(";") new MatcherLiteral(";")
}; };
public TestCount() : base(matchers) public TestCount() : base(matchers)
{ {
AddTaggedMatcher(operand);
AddTaggedMatcher(operation);
AddTaggedMatcher(calculationStatement);
} }
protected override void ProcessMatch(ICommandParserState state) protected override void ProcessMatch(ICommandParserState state)
{ {
switch (NextTag()) if (!NextTag().Equals(TagEvaluation))
{ {
case CalculationStatementTag:
ProcessCalculationStatement(state);
break;
default:
throw new Exception("Expected first count tag to be a calculation statement"); throw new Exception("Expected first count tag to be a calculation statement");
} }
}
private IEvaluation ProcessCalculationStatement(ICommandParserState state) var evaluation = ProcessEvaluation(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,157 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ZoneCodeGenerator.Domain.Evaluation;
using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing;
namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
{
abstract class TestWithEvaluation : AbstractTokenTest<ICommandParserState>
{
private const string TagOperand = "operand";
private const string TagOperationType = "operationType";
private const string TokenOperationType = "operationTypeToken";
// Evaluation Sub-Tags
private const string TagEvaluationParenthesis = "evaluationParenthesis";
private const string TagEvaluationNot = "evaluationNot";
private const string TagEvaluationOperation = "evaluationOperation";
// Operand Sub-Tags
private const string TagOperandNumber = "operandNumber";
private const string TagOperandTypename = "operandTypename";
private const string TagOperandArray = "operandArray";
private const string TokenOperandNumber = "operandNumberToken";
private const string TokenOperandTypename = "operandTypenameToken";
private const string TokenOperandArray = "operandArrayToken";
// Visible to children
protected const string TagEvaluation = "evaluation";
// operand ::= <typename> <array>* | <number>
private static readonly TokenMatcher operand = new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherTypename().WithName(TokenOperandTypename),
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple, new MatcherArray().WithName(TokenOperandArray).WithTag(TagOperandArray))
).WithTag(TagOperandTypename),
new MatcherNumber().WithName(TokenOperandNumber).WithTag(TagOperandNumber)
).WithTag(TagOperand);
// operationType ::= + | - | * | / | << | >> | ...
private static readonly TokenMatcher operationType = new MatcherGroupOr(
OperationType.Types
.Select(type => new MatcherLiteral(type.Syntax.ToCharArray().Select(c => c.ToString()).ToArray()).WithName(TokenOperationType))
.Cast<TokenMatcher>().ToArray()
).WithTag(TagOperationType);
// evaluation ::= ( <evaluation> ) | <operand> [<operationType> <evaluation>]
private static readonly TokenMatcher evaluation = new MatcherGroupAnd(
new MatcherGroupOr(
new MatcherGroupAnd(
new MatcherGroupOptional(new MatcherLiteral("!")).WithTag(TagEvaluationNot),
new MatcherLiteral("("),
new MatcherWithTag(TagEvaluation),
new MatcherLiteral(")")
).WithTag(TagEvaluationParenthesis),
new MatcherWithTag(TagOperand)
),
new MatcherGroupOptional(new MatcherGroupAnd(
new MatcherWithTag(TagOperationType),
new MatcherWithTag(TagEvaluation)
)).WithTag(TagEvaluationOperation)
).WithTag(TagEvaluation);
protected TestWithEvaluation(TokenMatcher[] matchers) : base(matchers)
{
AddTaggedMatcher(operand);
AddTaggedMatcher(operationType);
AddTaggedMatcher(evaluation);
}
private IEvaluation ProcessOperand(ICommandParserState state)
{
var operandTypeTag = NextTag();
if (operandTypeTag.Equals(TagOperandNumber))
{
var numberString = NextMatch(TokenOperandNumber);
return new OperandStatic(int.Parse(numberString));
}
else if(operandTypeTag.Equals(TagOperandTypename))
{
var typenameString = NextMatch(TokenOperandTypename);
var arrayIndexStrings = new List<string>();
while (PeekTag().Equals(TagOperandArray))
{
NextTag();
arrayIndexStrings.Add(NextMatch(TokenOperandArray));
}
return new OperandDynamic();
}
else
{
throw new Exception("Unknown Operand Type");
}
}
private OperationType ProcessOperationType(ICommandParserState state)
{
var operationMatch = NextMatch(TokenOperationType);
return OperationType.Types.First(type => type.Syntax.Equals(operationMatch));
}
private IEvaluation ProcessEvaluationInParenthesis(ICommandParserState state)
{
if (NextTag().Equals(TagEvaluationNot))
{
NextTag();
return new Operation(ProcessEvaluation(state), new OperandStatic(0), OperationType.OperationEquals);
}
return ProcessEvaluation(state);
}
protected IEvaluation ProcessEvaluation(ICommandParserState state)
{
IEvaluation firstStatementPart;
switch (NextTag())
{
case TagEvaluationParenthesis:
firstStatementPart = ProcessEvaluationInParenthesis(state);
break;
case TagOperand:
firstStatementPart = ProcessOperand(state);
break;
default:
throw new Exception("Invalid followup tag @ Evaluation");
}
if (PeekTag() == TagEvaluationOperation)
{
NextTag();
if (NextTag() != TagOperationType)
throw new Exception("Expected operationType tag @ Evaluation");
var type = ProcessOperationType(state);
if (NextTag() != TagEvaluation)
throw new Exception("Expected EvaluationTag @ Evaluation");
var secondStatementPart = ProcessEvaluation(state);
return new Operation(firstStatementPart, secondStatementPart, type);
}
return firstStatementPart;
}
}
}