From 785e2c9bfbebc27a30383733f4dfd68d2bcc2ec6 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 2 Oct 2019 15:47:24 +0200 Subject: [PATCH] ZoneCodeGenerator: Add Evaluation as basis for specifying conditions and counts --- .../Domain/Evaluation/IEvaluation.cs | 15 ++ .../Domain/Evaluation/OperandDynamic.cs | 17 +++ .../Domain/Evaluation/OperandStatic.cs | 24 +++ .../Domain/Evaluation/Operation.cs | 29 ++++ .../Domain/Evaluation/OperationType.cs | 138 ++++++++++++++++++ .../Domain/ReferenceTypePointer.cs | 10 +- .../StructureInformation.cs | 5 +- .../Generating/Templates/ZoneLoad.stg | 28 ++-- .../PostProcessor/PostProcessorUsages.cs | 21 ++- .../ZoneCodeGenerator.csproj | 6 + 10 files changed, 271 insertions(+), 22 deletions(-) create mode 100644 src/ZoneCodeGenerator/Domain/Evaluation/IEvaluation.cs create mode 100644 src/ZoneCodeGenerator/Domain/Evaluation/OperandDynamic.cs create mode 100644 src/ZoneCodeGenerator/Domain/Evaluation/OperandStatic.cs create mode 100644 src/ZoneCodeGenerator/Domain/Evaluation/Operation.cs create mode 100644 src/ZoneCodeGenerator/Domain/Evaluation/OperationType.cs diff --git a/src/ZoneCodeGenerator/Domain/Evaluation/IEvaluation.cs b/src/ZoneCodeGenerator/Domain/Evaluation/IEvaluation.cs new file mode 100644 index 00000000..ae186a38 --- /dev/null +++ b/src/ZoneCodeGenerator/Domain/Evaluation/IEvaluation.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZoneCodeGenerator.Domain.Evaluation +{ + interface IEvaluation + { + bool IsStatic { get; } + + int EvaluateNumeric(); + } +} diff --git a/src/ZoneCodeGenerator/Domain/Evaluation/OperandDynamic.cs b/src/ZoneCodeGenerator/Domain/Evaluation/OperandDynamic.cs new file mode 100644 index 00000000..54013162 --- /dev/null +++ b/src/ZoneCodeGenerator/Domain/Evaluation/OperandDynamic.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZoneCodeGenerator.Domain.Evaluation +{ + class OperandDynamic : IEvaluation + { + public bool IsStatic => false; + public int EvaluateNumeric() + { + throw new Exception("A dynamic operand cannot be evaluated."); + } + } +} diff --git a/src/ZoneCodeGenerator/Domain/Evaluation/OperandStatic.cs b/src/ZoneCodeGenerator/Domain/Evaluation/OperandStatic.cs new file mode 100644 index 00000000..0bcdfe35 --- /dev/null +++ b/src/ZoneCodeGenerator/Domain/Evaluation/OperandStatic.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZoneCodeGenerator.Domain.Evaluation +{ + class OperandStatic : IEvaluation + { + public int Value { get; } + + public bool IsStatic => true; + public int EvaluateNumeric() + { + return Value; + } + + public OperandStatic(int value) + { + Value = value; + } + } +} diff --git a/src/ZoneCodeGenerator/Domain/Evaluation/Operation.cs b/src/ZoneCodeGenerator/Domain/Evaluation/Operation.cs new file mode 100644 index 00000000..ef031984 --- /dev/null +++ b/src/ZoneCodeGenerator/Domain/Evaluation/Operation.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZoneCodeGenerator.Domain.Evaluation +{ + class Operation : IEvaluation + { + public IEvaluation Operand1 { get; } + public IEvaluation Operand2 { get; } + public OperationType OperationType { get; } + + public bool IsStatic => Operand1.IsStatic && Operand2.IsStatic; + + public int EvaluateNumeric() + { + return OperationType.Function(Operand1.EvaluateNumeric(), Operand2.EvaluateNumeric()); + } + + public Operation(IEvaluation operand1, IEvaluation operand2, OperationType type) + { + Operand1 = operand1; + Operand2 = operand2; + OperationType = type; + } + } +} diff --git a/src/ZoneCodeGenerator/Domain/Evaluation/OperationType.cs b/src/ZoneCodeGenerator/Domain/Evaluation/OperationType.cs new file mode 100644 index 00000000..a91d217a --- /dev/null +++ b/src/ZoneCodeGenerator/Domain/Evaluation/OperationType.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace ZoneCodeGenerator.Domain.Evaluation +{ + sealed class OperationType + { + // https://en.cppreference.com/w/cpp/language/operator_precedence + public enum OperationPrecedence + { + MultiplicationDivisionRemainder = 1, + AdditionSubtraction = 2, + BitwiseShift = 3, + RelationalGreaterLessThan = 4, + RelationalEquals = 5, + LogicalAnd = 6, + LogicalOr = 7 + } + + public delegate int EvaluationFunction(int operand1, int operand2); + + public string Syntax { get; } + public OperationPrecedence Precedence { get; } + public EvaluationFunction Function { get; } + + public override string ToString() + { + return Syntax; + } + + private OperationType(string syntax, OperationPrecedence precedence, EvaluationFunction function) + { + Syntax = syntax; + Precedence = precedence; + Function = function; + } + + public static OperationType OperationAdd = new OperationType( + "+", + OperationPrecedence.AdditionSubtraction, + (operand1, operand2) => operand1 + operand2 + ); + + public static OperationType OperationSubtract = new OperationType( + "-", + OperationPrecedence.AdditionSubtraction, + (operand1, operand2) => operand1 - operand2 + ); + + public static OperationType OperationMultiply = new OperationType( + "*", + OperationPrecedence.MultiplicationDivisionRemainder, + (operand1, operand2) => operand1 * operand2 + ); + + public static OperationType OperationDivide = new OperationType( + "/", + OperationPrecedence.MultiplicationDivisionRemainder, + (operand1, operand2) => operand1 / operand2 + ); + + public static OperationType OperationRemainder = new OperationType( + "%", + OperationPrecedence.MultiplicationDivisionRemainder, + (operand1, operand2) => operand1 % operand2 + ); + + public static OperationType OperationShiftLeft = new OperationType( + "<<", + OperationPrecedence.BitwiseShift, + (operand1, operand2) => operand1 << operand2 + ); + + public static OperationType OperationShiftRight = new OperationType( + ">>", + OperationPrecedence.BitwiseShift, + (operand1, operand2) => operand1 >> operand2 + ); + + public static OperationType OperationGreaterThan = new OperationType( + ">", + OperationPrecedence.RelationalGreaterLessThan, + (operand1, operand2) => operand1 > operand2 ? 1 : 0 + ); + + public static OperationType OperationGreaterEqualsThan = new OperationType( + ">=", + OperationPrecedence.RelationalGreaterLessThan, + (operand1, operand2) => operand1 >= operand2 ? 1 : 0 + ); + + public static OperationType OperationLessThan = new OperationType( + "<", + OperationPrecedence.RelationalGreaterLessThan, + (operand1, operand2) => operand1 < operand2 ? 1 : 0 + ); + + public static OperationType OperationLessEqualsThan = new OperationType( + "<=", + OperationPrecedence.RelationalGreaterLessThan, + (operand1, operand2) => operand1 <= operand2 ? 1 : 0 + ); + + public static OperationType OperationEquals = new OperationType( + "==", + OperationPrecedence.RelationalEquals, + (operand1, operand2) => operand1 == operand2 ? 1 : 0 + ); + + public static OperationType OperationNotEquals = new OperationType( + "!=", + OperationPrecedence.RelationalEquals, + (operand1, operand2) => operand1 != operand2 ? 1 : 0 + ); + + public static OperationType OperationAnd = new OperationType( + "&&", + OperationPrecedence.LogicalAnd, + (operand1, operand2) => operand1 > 0 && operand2 > 0 ? 1 : 0 + ); + + public static OperationType OperationOr = new OperationType( + "||", + OperationPrecedence.LogicalOr, + (operand1, operand2) => operand1 > 0 || operand2 > 0 ? 1 : 0 + ); + + public static List Types => typeof(OperationType) + .GetFields(BindingFlags.Static | BindingFlags.Public) + .Select(info => info.GetValue(null)) + .OfType() + .ToList(); + } +} \ No newline at end of file diff --git a/src/ZoneCodeGenerator/Domain/ReferenceTypePointer.cs b/src/ZoneCodeGenerator/Domain/ReferenceTypePointer.cs index fab73a2a..2cb9d6de 100644 --- a/src/ZoneCodeGenerator/Domain/ReferenceTypePointer.cs +++ b/src/ZoneCodeGenerator/Domain/ReferenceTypePointer.cs @@ -1,6 +1,14 @@ -namespace ZoneCodeGenerator.Domain +using System; +using ZoneCodeGenerator.Domain.Evaluation; + +namespace ZoneCodeGenerator.Domain { class ReferenceTypePointer : ReferenceType { + public static IEvaluation DefaultCount = new OperandStatic(1); + + public IEvaluation Count { get; set; } = DefaultCount; + + public bool IsArray => !Count.IsStatic || Count.EvaluateNumeric() > 1; } } diff --git a/src/ZoneCodeGenerator/Domain/StructureInformation/StructureInformation.cs b/src/ZoneCodeGenerator/Domain/StructureInformation/StructureInformation.cs index c4be7381..dd805455 100644 --- a/src/ZoneCodeGenerator/Domain/StructureInformation/StructureInformation.cs +++ b/src/ZoneCodeGenerator/Domain/StructureInformation/StructureInformation.cs @@ -26,7 +26,8 @@ namespace ZoneCodeGenerator.Domain.StructureInformation public List Usages { get; } public List OrderedMembers { get; } public bool NonEmbeddedReferenceExists { get; set; } - public bool PointerReferenceExists { get; set; } + public bool SinglePointerReferenceExists { get; set; } + public bool ArrayPointerReferenceExists { get; set; } public bool ArrayReferenceExists { get; set; } public bool HasNameMember => Type.Members.Any(variable => variable.Name.Equals("name", StringComparison.CurrentCultureIgnoreCase)); @@ -37,7 +38,7 @@ namespace ZoneCodeGenerator.Domain.StructureInformation fastFileAlign = null; Type = type; NonEmbeddedReferenceExists = false; - PointerReferenceExists = false; + SinglePointerReferenceExists = false; ArrayReferenceExists = false; Usages = new List(); OrderedMembers = new List(); diff --git a/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg b/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg index 58e2abdf..036a2959 100644 --- a/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg +++ b/src/ZoneCodeGenerator/Generating/Templates/ZoneLoad.stg @@ -9,21 +9,21 @@ LoaderClassName(asset) ::= "Loader_$asset.Type.Name$" HeaderConstructor(context) ::= "$LoaderClassName(context.Asset)$(IZoneScriptStringProvider* scriptStringProvider, Zone* zone, IZoneInputStream* stream);" -HeaderPtrLoadMethodDeclaration(structure) ::= "void LoadPtr_$structure.Type.Name$($structure.Type.FullName$** pPtr);" -HeaderArrayLoadMethodDeclaration(structure) ::= "void LoadArray_$structure.Type.Name$($structure.Type.FullName$** pArray, size_t count, bool atStreamStart);" +HeaderSinglePtrLoadMethodDeclaration(structure) ::= "void LoadPtr_$structure.Type.Name$($structure.Type.FullName$** pPtr);" +HeaderArrayPtrLoadMethodDeclaration(structure) ::= "void LoadArray_$structure.Type.Name$($structure.Type.FullName$** pArray, size_t count, bool atStreamStart);" HeaderLoadMethodDeclaration(structure) ::= "void Load_$structure.Type.Name$($structure.Type.FullName$* p$structure.Type.Name$, bool atStreamStart);" HeaderGetNameMethodDeclaration(asset) ::= "static std::string GetAssetName($asset.Type.FullName$* p$asset.Type.Name$);" HeaderAssetLoadMethodDeclaration(asset) ::= "void LoadAsset_$asset.Type.Name$($asset.Type.FullName$** pPtr);" HeaderDeclaration(structure) ::= <% -$if(structure.PointerReferenceExists)$ -$HeaderPtrLoadMethodDeclaration(structure)$ +$if(structure.SinglePointerReferenceExists)$ +$HeaderSinglePtrLoadMethodDeclaration(structure)$ $\n$ $endif$ -$if(structure.ArrayReferenceExists)$ -$HeaderArrayLoadMethodDeclaration(structure)$ +$if(structure.ArrayPointerReferenceExists)$ +$HeaderArrayPtrLoadMethodDeclaration(structure)$ $\n$ $endif$ @@ -60,7 +60,7 @@ namespace $context.Game$ public: $HeaderConstructor(context)$ - $HeaderPtrLoadMethodDeclaration(context.Asset)$ + $HeaderSinglePtrLoadMethodDeclaration(context.Asset)$ $HeaderGetNameMethodDeclaration(context.Asset)$ }; } @@ -91,7 +91,7 @@ void $LoaderClassName(context.Asset)$::Load_$structure.Type.Name$($structure.Typ } >> -LoadPtrMethod(structure, context) ::= << +LoadSinglePtrMethod(structure, context) ::= << void $LoaderClassName(context.Asset)$::LoadPtr_$structure.Type.Name$($structure.Type.FullName$** pPtr) { assert(pPtr != nullptr); @@ -141,7 +141,7 @@ void $LoaderClassName(context.Asset)$::LoadPtr_$structure.Type.Name$($structure. } >> -LoadArrayMethod(structure, context) ::= << +LoadArrayPtrMethod(structure, context) ::= << void $LoaderClassName(context.Asset)$::LoadArray_$structure.Type.Name$($structure.Type.FullName$** pArray, const size_t count, const bool atStreamStart) { assert(pArray != nullptr); @@ -161,12 +161,12 @@ $if(structure.NonEmbeddedReferenceExists)$ $LoadMethod(structure, context)$ $endif$ -$if(structure.PointerReferenceExists)$ -$LoadPtrMethod(structure, context)$ +$if(structure.SinglePointerReferenceExists)$ +$LoadSinglePtrMethod(structure, context)$ $endif$ -$if(structure.ArrayReferenceExists)$ -$LoadArrayMethod(structure, context)$ +$if(structure.ArrayPointerReferenceExists)$ +$LoadArrayPtrMethod(structure, context)$ $endif$ >> @@ -220,7 +220,7 @@ $LoadMethod(context.Asset, context)$ $LoadAssetMethod(context.Asset, context)$ -$LoadPtrMethod(context.Asset, context)$ +$LoadSinglePtrMethod(context.Asset, context)$ $GetNameMethod(context)$ >> \ No newline at end of file diff --git a/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUsages.cs b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUsages.cs index 8af46d29..afee570f 100644 --- a/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUsages.cs +++ b/src/ZoneCodeGenerator/Parsing/CommandFile/PostProcessor/PostProcessorUsages.cs @@ -23,11 +23,14 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.PostProcessor if (IsNonEmbeddedReference(memberInformation.Member)) memberInformation.StructureType.NonEmbeddedReferenceExists = true; - if (IsPointerReference(memberInformation.Member)) - memberInformation.StructureType.PointerReferenceExists = true; + if (IsSinglePointerReference(memberInformation.Member)) + memberInformation.StructureType.SinglePointerReferenceExists = true; + + if (IsArrayPointerReference(memberInformation.Member)) + memberInformation.StructureType.ArrayPointerReferenceExists = true; if (IsArrayReference(memberInformation.Member)) - memberInformation.StructureType.PointerReferenceExists = true; + memberInformation.StructureType.ArrayReferenceExists = true; } } @@ -39,10 +42,18 @@ namespace ZoneCodeGenerator.Parsing.CommandFile.PostProcessor return var.VariableType.References.Any(); } - private static bool IsPointerReference(Variable var) + private static bool IsSinglePointerReference(Variable var) { return var.VariableType.References.Any() - && var.VariableType.References.Last() is ReferenceTypePointer; + && var.VariableType.References.Last() is ReferenceTypePointer pointerReference + && !pointerReference.IsArray; + } + + private static bool IsArrayPointerReference(Variable var) + { + return var.VariableType.References.Any() + && var.VariableType.References.Last() is ReferenceTypePointer pointerReference + && pointerReference.IsArray; } private static bool IsArrayReference(Variable var) diff --git a/src/ZoneCodeGenerator/ZoneCodeGenerator.csproj b/src/ZoneCodeGenerator/ZoneCodeGenerator.csproj index 1d3b76a4..882fed23 100644 --- a/src/ZoneCodeGenerator/ZoneCodeGenerator.csproj +++ b/src/ZoneCodeGenerator/ZoneCodeGenerator.csproj @@ -63,6 +63,11 @@ + + + + + @@ -169,5 +174,6 @@ + \ No newline at end of file