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.Collections.Generic;
using System.Text;
using ZoneCodeGenerator.Domain.Evaluation;
using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers;
using ZoneCodeGenerator.Parsing.Testing;
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 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
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>);
// set condition <typename> (always | never | <CalculationStatementTag>);
private static readonly TokenMatcher[] matchers =
{
new MatcherLiteral("set"),
new MatcherLiteral("condition"),
new MatcherTypename().WithName(TypeNameToken),
new MatcherGroupOr(
new MatcherLiteral("always"),
new MatcherLiteral("never"),
new MatcherWithTag(ConditionChainTag)
new MatcherLiteral("always").WithTag(TagAlways),
new MatcherLiteral("never").WithTag(TagNever),
new MatcherWithTag(TagEvaluation)
),
new MatcherLiteral(";")
};
public TestCondition() : base(matchers)
{
AddTaggedMatcher(operand);
AddTaggedMatcher(operation);
AddTaggedMatcher(conditionStatement);
AddTaggedMatcher(conditionRelation);
AddTaggedMatcher(condition);
AddTaggedMatcher(conditionChainLink);
AddTaggedMatcher(conditionChain);
}
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.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;
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 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>;
private static readonly TokenMatcher[] matchers =
@ -62,84 +14,23 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
new MatcherLiteral("set"),
new MatcherLiteral("count"),
new MatcherTypename().WithName(TypeNameToken),
new MatcherWithTag(CalculationStatementTag),
new MatcherWithTag(TagEvaluation),
new MatcherLiteral(";")
};
public TestCount() : base(matchers)
{
AddTaggedMatcher(operand);
AddTaggedMatcher(operation);
AddTaggedMatcher(calculationStatement);
}
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");
}
}
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");
throw new Exception("Expected first count tag to be a calculation statement");
}
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;
var evaluation = ProcessEvaluation(state);
}
}
}

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;
}
}
}