ZoneCodeGenerator: Make pointer counts be able to differ by array index

This commit is contained in:
Jan 2019-12-18 15:30:47 +01:00
parent a7936c9eaa
commit be17ae6a48
6 changed files with 123 additions and 22 deletions

View File

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using ZoneCodeGenerator.Domain.Evaluation; using ZoneCodeGenerator.Domain.Evaluation;
namespace ZoneCodeGenerator.Domain namespace ZoneCodeGenerator.Domain
@ -8,7 +10,20 @@ namespace ZoneCodeGenerator.Domain
public static IEvaluation DefaultCount = new OperandStatic(1); public static IEvaluation DefaultCount = new OperandStatic(1);
public IEvaluation Count { get; set; } = DefaultCount; public IEvaluation Count { get; set; } = DefaultCount;
public IEvaluation[] CountByArrayIndex { get; set; }
public bool HasCountByArrayIndex => CountByArrayIndex != null;
public bool IsArray => !Count.IsStatic || Count.EvaluateNumeric() > 1; private static bool EvaluationIsArray(IEvaluation eval)
{
return !eval.IsStatic || eval.EvaluateNumeric() > 1;
}
public bool IsArray(int index)
{
return EvaluationIsArray(HasCountByArrayIndex ? CountByArrayIndex[index] : Count);
}
public bool AnyIsArray =>
HasCountByArrayIndex ? CountByArrayIndex.Any(EvaluationIsArray) : EvaluationIsArray(Count);
} }
} }

View File

@ -20,12 +20,12 @@ namespace ZoneCodeGenerator.Generating.Computations
public bool ContainsSinglePointerReference => information.Member.VariableType.References.Any() public bool ContainsSinglePointerReference => information.Member.VariableType.References.Any()
&& information.Member.VariableType.References.Last() is && information.Member.VariableType.References.Last() is
ReferenceTypePointer pointerReference ReferenceTypePointer pointerReference
&& !pointerReference.IsArray; && !pointerReference.AnyIsArray;
public bool ContainsArrayPointerReference => information.Member.VariableType.References.Any() public bool ContainsArrayPointerReference => information.Member.VariableType.References.Any()
&& information.Member.VariableType.References.Last() is && information.Member.VariableType.References.Last() is
ReferenceTypePointer pointerReference ReferenceTypePointer pointerReference
&& pointerReference.IsArray; && pointerReference.AnyIsArray;
public bool ContainsPointerArrayReference => ContainsSinglePointerReference public bool ContainsPointerArrayReference => ContainsSinglePointerReference
&& (IsArray && PointerDepthIsOne || !IsArray && PointerDepthIsTwo); && (IsArray && PointerDepthIsOne || !IsArray && PointerDepthIsTwo);
@ -73,11 +73,16 @@ namespace ZoneCodeGenerator.Generating.Computations
public bool IsNotDefaultNormalBlock => public bool IsNotDefaultNormalBlock =>
information.Block != null && !(information.Block.IsNormal && information.Block.IsDefault); information.Block != null && !(information.Block.IsNormal && information.Block.IsDefault);
public bool IsTempBlock => information.Block != null && information.Block.IsTemp;
public bool IsRuntimeBlock => information.Block != null && information.Block.IsRuntime;
public bool IsFirstMember => public bool IsFirstMember =>
information.Parent.OrderedMembers.FirstOrDefault(member => !member.IsLeaf && !member.Computations.ShouldIgnore) == information; information.Parent.OrderedMembers.FirstOrDefault(member =>
!member.IsLeaf && !member.Computations.ShouldIgnore) == information;
public bool IsLastMember => public bool IsLastMember =>
information.Parent.OrderedMembers.LastOrDefault(member => !member.IsLeaf && !member.Computations.ShouldIgnore) == information; information.Parent.OrderedMembers.LastOrDefault(member =>
!member.IsLeaf && !member.Computations.ShouldIgnore) == information;
public MemberReferenceComputations References => new MemberReferenceComputations(information); public MemberReferenceComputations References => new MemberReferenceComputations(information);

View File

@ -10,6 +10,7 @@ namespace ZoneCodeGenerator.Generating.Computations
{ {
private readonly MemberInformation information; private readonly MemberInformation information;
private readonly List<int> referenceIndices; private readonly List<int> referenceIndices;
private readonly int combinedIndex;
public ReferenceType Reference => referenceIndices.Count < information.Member.VariableType.References.Count public ReferenceType Reference => referenceIndices.Count < information.Member.VariableType.References.Count
? information.Member.VariableType.References[referenceIndices.Count] ? information.Member.VariableType.References[referenceIndices.Count]
@ -32,21 +33,29 @@ namespace ZoneCodeGenerator.Generating.Computations
.Select(i => new MemberReferenceComputations(information, referenceIndices.Concat(new[] {i}))); .Select(i => new MemberReferenceComputations(information, referenceIndices.Concat(new[] {i})));
public bool IsSinglePointer => Reference is ReferenceTypePointer referenceTypePointer public bool IsSinglePointer => Reference is ReferenceTypePointer referenceTypePointer
&& !referenceTypePointer.IsArray && !referenceTypePointer.IsArray(combinedIndex)
&& !FollowingReferences.OfType<ReferenceTypePointer>().Any(); && !FollowingReferences.OfType<ReferenceTypePointer>().Any();
public bool IsArrayPointer => Reference is ReferenceTypePointer referenceTypePointer public bool IsArrayPointer => Reference is ReferenceTypePointer referenceTypePointer
&& referenceTypePointer.IsArray && referenceTypePointer.IsArray(combinedIndex)
&& !FollowingReferences.OfType<ReferenceTypePointer>().Any(); && !FollowingReferences.OfType<ReferenceTypePointer>().Any();
public IEvaluation ArrayPointerCountEvaluation => Reference is ReferenceTypePointer referenceTypePointer public IEvaluation ArrayPointerCountEvaluation
? referenceTypePointer.Count {
: null; get
{
if (!(Reference is ReferenceTypePointer pointer))
return null;
return pointer.HasCountByArrayIndex ? pointer.CountByArrayIndex[combinedIndex] : pointer.Count;
}
}
public bool IsPointerArray => public bool IsPointerArray =>
(Reference is ReferenceTypePointer referenceTypePointer && referenceTypePointer.IsArray || (Reference is ReferenceTypePointer referenceTypePointer && referenceTypePointer.IsArray(combinedIndex) ||
Reference is ReferenceTypeArray) Reference is ReferenceTypeArray)
&& NextReference is ReferenceTypePointer nextReferencePointer && !nextReferencePointer.IsArray; && NextReference is ReferenceTypePointer nextReferencePointer &&
!nextReferencePointer.IsArray(combinedIndex);
public IEvaluation PointerArrayCountEvaluation => NextReference is ReferenceTypePointer referenceTypePointer public IEvaluation PointerArrayCountEvaluation => NextReference is ReferenceTypePointer referenceTypePointer
? referenceTypePointer.Count ? referenceTypePointer.Count
@ -56,12 +65,29 @@ namespace ZoneCodeGenerator.Generating.Computations
{ {
this.information = information; this.information = information;
referenceIndices = new List<int>(); referenceIndices = new List<int>();
combinedIndex = 0;
} }
private MemberReferenceComputations(MemberInformation information, IEnumerable<int> referenceIndices) private MemberReferenceComputations(MemberInformation information, IEnumerable<int> referenceIndices)
{ {
this.information = information; this.information = information;
this.referenceIndices = new List<int>(referenceIndices); this.referenceIndices = new List<int>(referenceIndices);
var arraySizes = information.Member.VariableType.References
.OfType<ReferenceTypeArray>()
.Select(array => array.ArraySize)
.ToList();
var indexDepth = 0;
combinedIndex = 0;
foreach (var referenceIndex in this.referenceIndices)
{
var sizePerIndexInCurrentDepth = arraySizes.Count <= indexDepth + 1
? 1
: arraySizes.Skip(indexDepth + 1).Aggregate((i1, i2) => i1 * i2);
combinedIndex += referenceIndex * sizePerIndexInCurrentDepth;
indexDepth++;
}
} }
} }
} }

View File

@ -7,7 +7,7 @@ $TypeVarName(structure.Type)$->$member.Member.Name$$PrintArrayIndices(reference)
// $member.Member.VariableType.Type.Alignment$ // $member.Member.VariableType.Type.Alignment$
$\n$ $\n$
$if(member.StructureType && !member.StructureType.IsLeaf)$ $if(member.StructureType && !member.StructureType.IsLeaf && !member.Computations.IsRuntimeBlock)$
$TypeVarName(member.Member.VariableType.Type)$ = $TypeVarName(structure.Type)$->$member.Member.Name$$PrintArrayIndices(reference)$;$\n$ $TypeVarName(member.Member.VariableType.Type)$ = $TypeVarName(structure.Type)$->$member.Member.Name$$PrintArrayIndices(reference)$;$\n$
LoadArray_$member.Member.VariableType.Type.Name$(true, $PrintEvaluation(reference.ArrayPointerCountEvaluation)$); LoadArray_$member.Member.VariableType.Type.Name$(true, $PrintEvaluation(reference.ArrayPointerCountEvaluation)$);

View File

@ -73,8 +73,11 @@ namespace $context.Game$
} }
>> >>
LoadMember(context, member) ::= << LoadMemberReference_Array(context, structure, member, reference) ::= <<
Loading member $member.Member.Name$ $first(reference.ArrayEntries):{entry | $LoadMemberReference(context, structure, member, entry)$}$
$rest(reference.ArrayEntries):{entry |
$LoadMemberReference(context, structure, member, entry)$}$
>> >>
LoadMemberReference(context, structure, member, reference) ::= <% LoadMemberReference(context, structure, member, reference) ::= <%
@ -88,8 +91,10 @@ $elseif(reference.IsArray && !reference.NextReference)$
$LoadEmbeddedArray(context, structure, member, reference)$ $LoadEmbeddedArray(context, structure, member, reference)$
$elseif(!reference.Reference)$ $elseif(!reference.Reference)$
$LoadEmbedded(context, structure, member, reference)$ $LoadEmbedded(context, structure, member, reference)$
$elseif(reference.IsArray)$
$LoadMemberReference_Array(context, structure, member, reference)$
$else$ $else$
// $member.Member.Name$ // LoadMemberReference failed @ $member.Member.Name$
$endif$ $endif$
%> %>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ZoneCodeGenerator.Domain; using ZoneCodeGenerator.Domain;
using ZoneCodeGenerator.Domain.Evaluation;
using ZoneCodeGenerator.Domain.Information; using ZoneCodeGenerator.Domain.Information;
using ZoneCodeGenerator.Parsing.Matching; using ZoneCodeGenerator.Parsing.Matching;
using ZoneCodeGenerator.Parsing.Matching.Matchers; using ZoneCodeGenerator.Parsing.Matching.Matchers;
@ -14,27 +15,65 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
private StructureInformation referencedType; private StructureInformation referencedType;
private const string TokenTypeName = "typeName"; private const string TokenTypeName = "typeName";
private const string TokenPointerResolve = "pointerResolve"; private const string TokenPointerResolve = "pointerResolve";
private const string TokenArrayIndex = "arrayIndex";
// set count <typename> <calculationStatement>; // set count <typename> <calculationStatement>;
private static readonly TokenMatcher[] matchers = private static readonly TokenMatcher[] matchers =
{ {
new MatcherLiteral("set"), new MatcherLiteral("set"),
new MatcherLiteral("count"), new MatcherLiteral("count"),
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple, new MatcherLiteral("*").WithName(TokenPointerResolve)), new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple,
new MatcherLiteral("*").WithName(TokenPointerResolve)),
new MatcherTypename().WithName(TokenTypeName), new MatcherTypename().WithName(TokenTypeName),
new MatcherGroupLoop(MatcherGroupLoop.LoopMode.ZeroOneMultiple,
new MatcherArray().WithName(TokenArrayIndex)),
new MatcherWithTag(TagEvaluation), new MatcherWithTag(TagEvaluation),
new MatcherLiteral(";") new MatcherLiteral(";")
}; };
public TestCount() : base(matchers) public TestCount() : base(matchers)
{ {
}
private void SetCountByArrayIndex(MemberInformation referencedMember, ReferenceTypePointer pointer,
IEvaluation evaluation)
{
if (pointer.CountByArrayIndex == null)
{
pointer.CountByArrayIndex = new IEvaluation[referencedMember.Member.VariableType.References
.OfType<ReferenceTypeArray>().Select(array => array.ArraySize).Aggregate((i1, i2) => i1 * i2)];
}
var arraySizes = referencedMember.Member.VariableType.References
.OfType<ReferenceTypeArray>()
.Select(array => array.ArraySize)
.ToList();
var index = 0;
var indexDepth = 0;
string s;
while ((s = NextMatch(TokenArrayIndex)) != null)
{
var specifiedIndex = int.Parse(s);
if (specifiedIndex >= arraySizes[indexDepth])
{
throw new TestFailedException($"Specified index '{specifiedIndex}' is out of bounds at type '{referencedMember.Parent.Type.FullName}::{referencedMember.Member.Name}'");
}
var sizePerIndexInCurrentDepth = arraySizes.Count <= indexDepth + 1 ?
1 : arraySizes.Skip(indexDepth + 1).Aggregate((i1, i2) => i1 * i2);
index += specifiedIndex * sizePerIndexInCurrentDepth;
indexDepth++;
}
pointer.CountByArrayIndex[index] = evaluation;
} }
protected override void ProcessMatch(ICommandParserState state) protected override void ProcessMatch(ICommandParserState state)
{ {
var typeName = NextMatch(TokenTypeName); var typeName = NextMatch(TokenTypeName);
var typeNameParts = typeName.Split(new[] { "::" }, StringSplitOptions.None); var typeNameParts = typeName.Split(new[] {"::"}, StringSplitOptions.None);
if (state.DataTypeInUse != null if (state.DataTypeInUse != null
&& state.GetMembersFromParts(typeNameParts, state.DataTypeInUse, out var typeMembers)) && state.GetMembersFromParts(typeNameParts, state.DataTypeInUse, out var typeMembers))
{ {
@ -67,10 +106,21 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
.FirstOrDefault(); .FirstOrDefault();
if (reference != null) if (reference != null)
reference.Count = evaluation; {
if (HasMatcherTokens(TokenArrayIndex))
{
SetCountByArrayIndex(referencedMember, reference, evaluation);
}
else
{
reference.Count = evaluation;
}
}
else else
{
throw new TestFailedException( throw new TestFailedException(
$"Member '{referencedMember.Member.Name}' of type '{referencedMember.Member.VariableType.Type.FullName}' cannot have its count set due to it not having a pointer reference"); $"Member '{referencedMember.Member.Name}' of type '{referencedMember.Member.VariableType.Type.FullName}' cannot have its count set due to it not having a pointer reference");
}
} }
protected override IEnumerable<StructureInformation> GetUsedTypes(ICommandParserState state) protected override IEnumerable<StructureInformation> GetUsedTypes(ICommandParserState state)
@ -78,10 +128,10 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.Tests
if (state.DataTypeInUse != null if (state.DataTypeInUse != null
&& state.DataTypeInUse != referencedType) && state.DataTypeInUse != referencedType)
{ {
return new[] { state.DataTypeInUse, referencedType }; return new[] {state.DataTypeInUse, referencedType};
} }
return new[] { referencedType }; return new[] {referencedType};
} }
} }
} }