diff --git a/src/Kingsland.MofParser.HtmlReport/Resources/DscResource.cs b/src/Kingsland.MofParser.HtmlReport/Resources/DscResource.cs index 166f173..7fe2cd5 100644 --- a/src/Kingsland.MofParser.HtmlReport/Resources/DscResource.cs +++ b/src/Kingsland.MofParser.HtmlReport/Resources/DscResource.cs @@ -1,4 +1,6 @@ using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; using System.Collections.ObjectModel; namespace Kingsland.MofParser.HtmlReport.Resources; @@ -53,13 +55,11 @@ public Instance Instance : DscResource.GetResourceNameFromResourceId(this.ResourceId); public ReadOnlyCollection DependsOn => - new( - new List( - this.Instance.Properties.Single( - property => property.Name == "ResourceID" - ).Value as string[] ?? Enumerable.Empty() - ) - ); + this.Instance.Properties + .Where(property => property.Name == "ResourceID") + .SelectMany(property => ((LiteralValueArray)property.Value).Values) + .Select(literalValue => ((StringValue)literalValue).Value) + .ToList().AsReadOnly(); public string? ModuleName => this.GetStringProperty(nameof(this.ModuleName)); @@ -98,9 +98,14 @@ public static DscResource FromInstance(string filename, string computerName, Ins protected string? GetStringProperty(string propertyName) { - return this.Instance.Properties.SingleOrDefault( - property => property.Name == propertyName - )?.Value as string; + var property = this.Instance.Properties + .SingleOrDefault(property => property.Name == propertyName); + if (property is null) + { + return null; + } + var value = ((StringValue)property.Value).Value; + return value; } #endregion diff --git a/src/Kingsland.MofParser.HtmlReport/Resources/ScriptResource.cs b/src/Kingsland.MofParser.HtmlReport/Resources/ScriptResource.cs index af8f0c3..32338be 100644 --- a/src/Kingsland.MofParser.HtmlReport/Resources/ScriptResource.cs +++ b/src/Kingsland.MofParser.HtmlReport/Resources/ScriptResource.cs @@ -1,4 +1,5 @@ using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Types; namespace Kingsland.MofParser.HtmlReport.Resources; diff --git a/src/Kingsland.MofParser.HtmlReport/Wrappers/ResourceGroup.cs b/src/Kingsland.MofParser.HtmlReport/Wrappers/ResourceGroup.cs index 3a15073..bf71c5e 100644 --- a/src/Kingsland.MofParser.HtmlReport/Wrappers/ResourceGroup.cs +++ b/src/Kingsland.MofParser.HtmlReport/Wrappers/ResourceGroup.cs @@ -12,11 +12,9 @@ public ResourceGroup( { this.Filename = filename ?? throw new ArgumentNullException(nameof(filename)); this.ComputerName = computerName ?? throw new ArgumentNullException(nameof(computerName)); - this.Wrappers = new( - new List( - wrappers ?? throw new ArgumentNullException(nameof(wrappers)) - ) - ); + this.Wrappers = new List( + wrappers ?? throw new ArgumentNullException(nameof(wrappers)) + ).AsReadOnly(); } public string Filename diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests.cs index 33974b1..cbede08 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests.cs @@ -1,7 +1,8 @@ using Kingsland.MofParser.Ast; using Kingsland.MofParser.CodeGen; using Kingsland.MofParser.Lexing; -using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Converter; +using Kingsland.MofParser.Models.Types; using Kingsland.MofParser.Parsing; using Kingsland.MofParser.UnitTests.Helpers; using Kingsland.ParseFx.Parsing; @@ -80,6 +81,12 @@ private static void AssertRoundtrip( ) ); Assert.That(actualAstText, Is.EqualTo(sourceText)); + // check the model converter works + var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); + if (expectedModule is not null) + { + ModelAssert.AreDeepEqual(actualModule, expectedModule); + } } private static void AssertRoundtripException(string sourceText, string expectedMessage, ParserQuirks parserQuirks = ParserQuirks.None) diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ClassDeclaration.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ClassDeclaration.cs index 85e805a..554fcf6 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ClassDeclaration.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ClassDeclaration.cs @@ -36,12 +36,12 @@ class GOLF_Base .StatementEndToken() .ToList(); var expectedAst = new MofSpecificationAst.Builder { - Productions = new List { + Productions = [ new ClassDeclarationAst.Builder { ClassName = new IdentifierToken("GOLF_Base"), ClassFeatures = [] }.Build() - } + ] }.Build(); RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst); } @@ -73,12 +73,12 @@ class GOLF_Base : GOLF_Superclass .StatementEndToken() .ToList(); var expectedAst = new MofSpecificationAst.Builder { - Productions = new List { + Productions = [ new ClassDeclarationAst.Builder { ClassName = new IdentifierToken("GOLF_Base"), SuperClass = new IdentifierToken("GOLF_Superclass"), }.Build() - } + ] }.Build(); RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst); } @@ -125,10 +125,10 @@ class GOLF_Base .StatementEndToken() .ToList(); var expectedAst = new MofSpecificationAst.Builder { - Productions = new List { + Productions = [ new ClassDeclarationAst.Builder { ClassName = new IdentifierToken("GOLF_Base"), - ClassFeatures = new List { + ClassFeatures = [ new PropertyDeclarationAst.Builder { ReturnType = new IdentifierToken("string"), PropertyName = new IdentifierToken("InstanceID"), @@ -140,9 +140,9 @@ class GOLF_Base new NullLiteralToken("Null") ) }.Build() - } + ] }.Build() - } + ] }.Build(); RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst); } @@ -227,61 +227,57 @@ class GOLF_Base .StatementEndToken() .ToList(); var expectedAst = new MofSpecificationAst.Builder { - Productions = new List { + Productions = [ new ClassDeclarationAst.Builder { ClassName = new IdentifierToken("GOLF_Base"), - ClassFeatures = new List { + ClassFeatures = [ new PropertyDeclarationAst.Builder { - QualifierList = new QualifierListAst( - new List { - new QualifierValueAst.Builder { - QualifierName = new IdentifierToken("Description"), - Initializer = new QualifierValueInitializerAst( - new StringValueAst( - new StringLiteralToken("an instance of a class that derives from the GOLF_Base class. "), - "an instance of a class that derives from the GOLF_Base class. " - ) + QualifierList = new QualifierListAst([ + new QualifierValueAst.Builder { + QualifierName = new IdentifierToken("Description"), + Initializer = new QualifierValueInitializerAst( + new StringValueAst( + new StringLiteralToken("an instance of a class that derives from the GOLF_Base class. "), + "an instance of a class that derives from the GOLF_Base class. " ) - }.Build(), - new QualifierValueAst.Builder { - QualifierName = new IdentifierToken("Key"), - }.Build() - } - ), + ) + }.Build(), + new QualifierValueAst.Builder { + QualifierName = new IdentifierToken("Key"), + }.Build() + ]), ReturnType = new IdentifierToken("string"), PropertyName = new IdentifierToken("InstanceID") }.Build(), new PropertyDeclarationAst.Builder { - QualifierList = new QualifierListAst( - new List { - new QualifierValueAst.Builder { - QualifierName = new IdentifierToken("Description"), - Initializer = new QualifierValueInitializerAst( - new StringValueAst( - new StringLiteralToken("A short textual description (one- line string) of the"), - "an instance of a class that derives from the GOLF_Base class. " - ) + QualifierList = new QualifierListAst([ + new QualifierValueAst.Builder { + QualifierName = new IdentifierToken("Description"), + Initializer = new QualifierValueInitializerAst( + new StringValueAst( + new StringLiteralToken("A short textual description (one- line string) of the"), + "an instance of a class that derives from the GOLF_Base class. " ) - }.Build(), - new QualifierValueAst.Builder { - QualifierName = new IdentifierToken("MaxLen"), - Initializer = new QualifierValueInitializerAst( - new IntegerValueAst( - new IntegerLiteralToken(IntegerKind.DecimalValue, 64) - ) + ) + }.Build(), + new QualifierValueAst.Builder { + QualifierName = new IdentifierToken("MaxLen"), + Initializer = new QualifierValueInitializerAst( + new IntegerValueAst( + new IntegerLiteralToken(IntegerKind.DecimalValue, 64) ) - }.Build() - } - ), + ) + }.Build() + ]), ReturnType = new IdentifierToken("string"), PropertyName = new IdentifierToken("Caption"), Initializer = new NullValueAst( new NullLiteralToken("Null") ) }.Build() - }, + ], }.Build() - } + ] }.Build(); RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst); } diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ComplexValue.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ComplexValue.cs index 69593d8..7a01a36 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ComplexValue.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_ComplexValue.cs @@ -1,4 +1,7 @@ using Kingsland.MofParser.Ast; +using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; using Kingsland.MofParser.Tokens; using Kingsland.MofParser.UnitTests.Extensions; using NUnit.Framework; @@ -48,25 +51,23 @@ instance of GOLF_ClubMember .StatementEndToken() .ToList(); var expectedAst = new MofSpecificationAst.Builder { - Productions = new List { + Productions = [ new InstanceValueDeclarationAst.Builder { Instance = new IdentifierToken("instance"), Of = new IdentifierToken("of"), TypeName = new IdentifierToken("GOLF_ClubMember"), - PropertyValues = new PropertyValueListAst( - new List { - new PropertySlotAst.Builder { - PropertyName = new IdentifierToken("LastPaymentDate"), - PropertyValue = new ComplexValueAst.Builder { - Alias = new AliasIdentifierToken("MyAliasIdentifier") - }.Build() + PropertyValues = new PropertyValueListAst([ + new PropertySlotAst.Builder { + PropertyName = new IdentifierToken("LastPaymentDate"), + PropertyValue = new ComplexValueAst.Builder { + Alias = new AliasIdentifierToken("MyAliasIdentifier") + }.Build() - }.Build() - } - ), + }.Build() + ]), StatementEnd = new StatementEndToken() }.Build() - } + ] }.Build(); RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst); } @@ -126,7 +127,52 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst.Builder + { + Productions = [ + new InstanceValueDeclarationAst.Builder { + Instance = new IdentifierToken("instance"), + Of = new IdentifierToken("of"), + TypeName = new IdentifierToken("GOLF_ClubMember"), + PropertyValues = new PropertyValueListAst([ + new PropertySlotAst.Builder { + PropertyName = new IdentifierToken("LastPaymentDate"), + PropertyValue = new ComplexValueAst.Builder { + Value = new IdentifierToken("value"), + Of = new IdentifierToken("of"), + TypeName = new IdentifierToken("GOLF_Date"), + PropertyValues = new PropertyValueListAst([ + new( + new("Month"), + new EnumValueAst( + new("July") + ) + ) + ]) + }.Build() + }.Build() + ]), + StatementEnd = new StatementEndToken() + }.Build() + ] + }.Build(); + var expectedModule = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new Property( + "LastPaymentDate", + new ComplexValueObject( + "GOLF_Date", + [ + new("Month", new EnumValue("July")) + ] + ) + ) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModule); } } diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_InstanceValueDeclaration.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_InstanceValueDeclaration.cs index c5b80ed..4b16151 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_InstanceValueDeclaration.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_InstanceValueDeclaration.cs @@ -1,5 +1,6 @@ using Kingsland.MofParser.Ast; -using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; using Kingsland.MofParser.Tokens; using Kingsland.MofParser.UnitTests.Extensions; using NUnit.Framework; @@ -40,20 +41,18 @@ instance of GOLF_ClubMember .ToList(); var expectedAst = new MofSpecificationAst([ new InstanceValueDeclarationAst( - new IdentifierToken("instance"), - new IdentifierToken("of"), - new IdentifierToken("GOLF_ClubMember"), - new PropertyValueListAst(), - new StatementEndToken() + new("instance"), new("of"), new("GOLF_ClubMember"), + new([]), + new() ) ]); - var expectedModule = new Module([]); - RoundtripTests.AssertRoundtrip( - sourceText, - expectedTokens, - expectedAst, - expectedModule - ); + var expectedModule = new Module([ + new( + "GOLF_ClubMember", + [] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModule); } [Test] @@ -101,39 +100,24 @@ instance of GOLF_ClubMember .ToList(); var expectedAst = new MofSpecificationAst([ new InstanceValueDeclarationAst( - new IdentifierToken("instance"), - new IdentifierToken("of"), - new IdentifierToken("GOLF_ClubMember"), - new PropertyValueListAst([ - new( - new("FirstName"), - new StringValueAst( - [ - new StringLiteralToken("John") - ], - "John" - ) - ), - new( - new("LastName"), - new StringValueAst( - [ - new StringLiteralToken("Doe") - ], - "Doe" - ) - ) + new("instance"), new("of"), new("GOLF_ClubMember"), + new([ + new(new("FirstName"), new StringValueAst(new StringLiteralToken("John"), "John")), + new(new("LastName"), new StringValueAst(new StringLiteralToken("Doe"), "Doe")) ]), - new StatementEndToken() + new() + ) + ]); + var expectedModule = new Module([ + new( + "GOLF_ClubMember", + [ + new("FirstName", "John"), + new("LastName", "Doe") + ] ) ]); - var expectedModule = new Module([]); - RoundtripTests.AssertRoundtrip( - sourceText, - expectedTokens, - expectedAst, - expectedModule - ); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModule); } [Test] @@ -166,22 +150,18 @@ instance of GOLF_ClubMember as $MyAliasIdentifier .ToList(); var expectedAst = new MofSpecificationAst([ new InstanceValueDeclarationAst( - new IdentifierToken("instance"), - new IdentifierToken("of"), - new IdentifierToken("GOLF_ClubMember"), - new IdentifierToken("as"), - new AliasIdentifierToken("MyAliasIdentifier"), - new PropertyValueListAst(), - new StatementEndToken() + new("instance"), new("of"), new("GOLF_ClubMember"), new("as"), new("MyAliasIdentifier"), + new([]), + new() + ) + ]); + var expectedModule = new Module([ + new( + "GOLF_ClubMember", "MyAliasIdentifier", + [] ) ]); - var expectedModule = new Module([]); - RoundtripTests.AssertRoundtrip( - sourceText, - expectedTokens, - expectedAst, - expectedModule - ); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModule); } //[Test] diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValue.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValue.cs index c5f2484..f5d640b 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValue.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValue.cs @@ -1,4 +1,7 @@ -using Kingsland.MofParser.Tokens; +using Kingsland.MofParser.Ast; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; +using Kingsland.MofParser.Tokens; using Kingsland.MofParser.UnitTests.Extensions; using NUnit.Framework; @@ -46,7 +49,24 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new IntegerValueAst(new(IntegerKind.DecimalValue, 1))) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new("LastPaymentDate", 1) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); } [Test] @@ -83,7 +103,24 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new RealValueAst(new(0.5))) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new("LastPaymentDate", 0.5) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); } [Test] @@ -120,7 +157,24 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new BooleanValueAst(new(true))) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new("LastPaymentDate", true) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); } [Test] @@ -157,7 +211,24 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new NullValueAst(new())) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new("LastPaymentDate", NullValue.Null) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); } [Test] @@ -194,7 +265,24 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new StringValueAst(new StringLiteralToken("aaa"), "aaa")) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new("LastPaymentDate", "aaa") + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); } } diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValueArray.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValueArray.cs index 512b3d8..6e7a6a8 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValueArray.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_LiteralValueArray.cs @@ -1,4 +1,7 @@ -using Kingsland.MofParser.Tokens; +using Kingsland.MofParser.Ast; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; +using Kingsland.MofParser.Tokens; using Kingsland.MofParser.UnitTests.Extensions; using NUnit.Framework; @@ -12,6 +15,61 @@ public static partial class RoundtripTests public static class LiteralValueArrayTests { + [Test] + public static void LiteralValueArrayWithNoItemsShouldRoundtrip() + { + var newline = Environment.NewLine; + var indent = " "; + var sourceText = @" + instance of GOLF_ClubMember + { + LastPaymentDate = {}; + }; + ".TrimIndent(newline).TrimString(newline); + var expectedTokens = new TokenBuilder() + // instance of GOLF_ClubMember + .IdentifierToken("instance") + .WhitespaceToken(" ") + .IdentifierToken("of") + .WhitespaceToken(" ") + .IdentifierToken("GOLF_ClubMember") + .WhitespaceToken(newline) + // { + .BlockOpenToken() + .WhitespaceToken(newline + indent) + // LastPaymentDate = { }; + .IdentifierToken("LastPaymentDate") + .WhitespaceToken(" ") + .EqualsOperatorToken() + .WhitespaceToken(" ") + .BlockOpenToken() + .BlockCloseToken() + .StatementEndToken() + .WhitespaceToken(newline) + // }; + .BlockCloseToken() + .StatementEndToken() + .ToList(); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new LiteralValueArrayAst([])) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new("LastPaymentDate", new LiteralValueArray()) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); + } + [Test] public static void LiteralValueArrayWithOneItemShouldRoundtrip() { @@ -48,7 +106,31 @@ instance of GOLF_ClubMember .BlockCloseToken() .StatementEndToken() .ToList(); - RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); + var expectedAst = new MofSpecificationAst([ + new InstanceValueDeclarationAst( + new("instance"), new("of"), new("GOLF_ClubMember"), null, null, + new([ + new(new("LastPaymentDate"), new LiteralValueArrayAst( + new IntegerValueAst(new(IntegerKind.DecimalValue, 1)) + )) + ]), + new() + ) + ]); + var expectedModel = new Module([ + new Instance( + "GOLF_ClubMember", + [ + new( + "LastPaymentDate", + new LiteralValueArray([ + 1 + ]) + ) + ] + ) + ]); + RoundtripTests.AssertRoundtrip(sourceText, expectedTokens, expectedAst, expectedModel); } [Test] diff --git a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_MethodDeclaration.cs b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_MethodDeclaration.cs index fffa226..b9fff2f 100644 --- a/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_MethodDeclaration.cs +++ b/src/Kingsland.MofParser.UnitTests/CodeGen/RoundtripTests_MethodDeclaration.cs @@ -1,4 +1,5 @@ -using Kingsland.MofParser.Tokens; +using Kingsland.MofParser.Ast; +using Kingsland.MofParser.Tokens; using Kingsland.MofParser.UnitTests.Extensions; using NUnit.Framework; @@ -250,7 +251,7 @@ class GOLF_Professional : GOLF_ClubMember .ToList(); //var expectedAst = new MofSpecificationAst.Builder //{ - // Productions = new List { + // Productions = [ // new ClassDeclarationAst.Builder { // ClassName = new IdentifierToken("GOLF_Professional"), // SuperClass = new IdentifierToken("GOLF_ClubMember"), @@ -268,7 +269,7 @@ class GOLF_Professional : GOLF_ClubMember // }.Build(), // } // }.Build() - // } + // ] //}.Build(); RoundtripTests.AssertRoundtrip(sourceText, expectedTokens); } diff --git a/src/Kingsland.MofParser.UnitTests/Helpers/AstAssert.cs b/src/Kingsland.MofParser.UnitTests/Helpers/AstAssert.cs index f7c4cfc..9362d70 100644 --- a/src/Kingsland.MofParser.UnitTests/Helpers/AstAssert.cs +++ b/src/Kingsland.MofParser.UnitTests/Helpers/AstAssert.cs @@ -308,18 +308,27 @@ private static void AreEqual(PropertyValueAst? expected, PropertyValueAst? actua case ComplexTypeValueAst ast: AstAssert.AreEqual(ast, (ComplexTypeValueAst)actual, ignoreExtent); return; + case EnumTypeValueAst ast: + AstAssert.AreEqual(ast, (EnumTypeValueAst)actual, ignoreExtent); + return; case BooleanValueAst ast: AstAssert.AreEqual(ast, (BooleanValueAst)actual, ignoreExtent); return; case IntegerValueAst ast: AstAssert.AreEqual(ast, (IntegerValueAst)actual, ignoreExtent); return; + case RealValueAst ast: + AstAssert.AreEqual(ast, (RealValueAst)actual, ignoreExtent); + return; case StringValueAst ast: AstAssert.AreEqual(ast, (StringValueAst)actual, ignoreExtent); return; case NullValueAst ast: AstAssert.AreEqual(ast, (NullValueAst)actual, ignoreExtent); return; + case LiteralValueArrayAst ast: + AstAssert.AreEqual(ast, (LiteralValueArrayAst)actual, ignoreExtent); + return; default: throw new NotImplementedException($"unhandled node type {expected.GetType().Name}"); } @@ -387,6 +396,16 @@ private static void AreEqual(IntegerValueAst? expected, IntegerValueAst? actual, Assert.That(actual.Value, Is.EqualTo(expected.Value)); } + private static void AreEqual(RealValueAst? expected, RealValueAst? actual, bool ignoreExtent) + { + if ((expected == null) || (actual == null)) + { + Assert.That(actual, Is.EqualTo(expected)); + return; + } + Assert.That(actual.Value, Is.EqualTo(expected.Value)); + } + private static void AreEqual(StringValueAst? expected, StringValueAst? actual, bool ignoreExtent) { if ((expected == null) || (actual == null)) @@ -401,7 +420,8 @@ private static void AreEqual(StringValueAst? expected, StringValueAst? actual, b } } - private static void AreEqual(NullValueAst? expected, NullValueAst? actual, bool ignoreExtent) { + private static void AreEqual(NullValueAst? expected, NullValueAst? actual, bool ignoreExtent) + { if ((expected == null) || (actual == null)) { Assert.That(actual, Is.EqualTo(expected)); @@ -410,6 +430,66 @@ private static void AreEqual(NullValueAst? expected, NullValueAst? actual, bool TokenAssert.AreEqual(expected.Token, actual.Token, ignoreExtent); } + private static void AreEqual(LiteralValueArrayAst? expected, LiteralValueArrayAst? actual, bool ignoreExtent) + { + if ((expected == null) || (actual == null)) + { + Assert.That(actual, Is.EqualTo(expected)); + return; + } + Assert.That(actual.Values.Count, Is.EqualTo(expected.Values.Count)); + for (var i = 0; i < expected.Values.Count; i++) + { + AstAssert.AreEqual(expected.Values[i], actual.Values[i], ignoreExtent); + } + } + + private static void AreEqual(EnumTypeValueAst? expected, EnumTypeValueAst? actual, bool ignoreExtent) + { + if ((expected == null) || (actual == null)) + { + Assert.That(actual, Is.EqualTo(expected)); + return; + } + Assert.That(actual, Is.InstanceOf(expected.GetType())); + switch (expected) + { + case EnumValueAst ast: + AstAssert.AreEqual(ast, (EnumValueAst)actual, ignoreExtent); + return; + case EnumValueArrayAst ast: + AstAssert.AreEqual(ast, (EnumValueArrayAst)actual, ignoreExtent); + return; + default: + throw new NotImplementedException($"unhandled node type {expected.GetType().Name}"); + } + } + + private static void AreEqual(EnumValueAst? expected, EnumValueAst? actual, bool ignoreExtent) + { + if ((expected == null) || (actual == null)) + { + Assert.That(actual, Is.EqualTo(expected)); + return; + } + TokenAssert.AreEqual(expected.EnumName, actual.EnumName, ignoreExtent); + TokenAssert.AreEqual(expected.EnumLiteral, actual.EnumLiteral, ignoreExtent); + } + + private static void AreEqual(EnumValueArrayAst? expected, EnumValueArrayAst? actual, bool ignoreExtent) + { + if ((expected == null) || (actual == null)) + { + Assert.That(actual, Is.EqualTo(expected)); + return; + } + Assert.That(actual.Values.Count, Is.EqualTo(expected.Values.Count)); + for (var i = 0; i < expected.Values.Count; i++) + { + AstAssert.AreEqual(expected.Values[i], actual.Values[i], ignoreExtent); + } + } + #endregion } diff --git a/src/Kingsland.MofParser.UnitTests/Helpers/ModelAssert.cs b/src/Kingsland.MofParser.UnitTests/Helpers/ModelAssert.cs index 7a9ba6c..c4536e2 100644 --- a/src/Kingsland.MofParser.UnitTests/Helpers/ModelAssert.cs +++ b/src/Kingsland.MofParser.UnitTests/Helpers/ModelAssert.cs @@ -1,4 +1,5 @@ -using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; using NUnit.Framework; namespace Kingsland.MofParser.UnitTests.Helpers; @@ -6,36 +7,257 @@ namespace Kingsland.MofParser.UnitTests.Helpers; internal static class ModelAssert { - public static void AreEqual(Module expected, Module actual) + public static void AreDeepEqual(object? actual, object? expected) { - Assert.That(expected, Is.Not.Null); - Assert.That(actual, Is.Not.Null); - Assert.That(actual.Instances.Count, Is.EqualTo(expected.Instances.Count)); - for (var i = 0; i < expected.Instances.Count; i++) + // handle null values + if ((actual is null) || (expected is null)) { - ModelAssert.AreEqual(expected.Instances[i], actual.Instances[i]); + Assert.That(actual, Is.EqualTo(expected)); + return; } - } - - public static void AreEqual(Instance expected, Instance actual) - { - Assert.That(expected, Is.Not.Null); - Assert.That(actual, Is.Not.Null); - Assert.That(actual.TypeName, Is.EqualTo(expected.TypeName)); - Assert.That(actual.Alias, Is.EqualTo(expected.Alias)); - Assert.That(actual.Properties.Count, Is.EqualTo(expected.Properties.Count)); - for (var i = 0; i < expected.Properties.Count; i++) + // make sure types match + var expectedType = expected.GetType(); + Assert.That(actual, Is.TypeOf(expectedType)); + // handle value types + if (expectedType.IsValueType) + { + Assert.That(actual, Is.EqualTo(expected)); + return; + } + // handle strings first, otherwise they get detected as IEnumerable + if (expected is string expectedString) + { + Assert.That((string)actual, Is.EqualTo(expectedString)); + return; + } + // handle collections + if (expected is System.Collections.IEnumerable expectedEnumerable) { - ModelAssert.AreEqual(expected.Properties[i], actual.Properties[i]); + var actualItems = ((System.Collections.IEnumerable)actual).Cast().ToList(); + var expectedItems = expectedEnumerable.Cast().ToList(); + Assert.That(actualItems.Count, Is.EqualTo(expectedItems.Count)); + for (var i = 0; i < expectedItems.Count; i++) + { + ModelAssert.AreDeepEqual(actualItems[i], expectedItems[i]); + } + return; + } + // compare properties + var properties = expectedType.GetProperties(); + foreach (var property in properties) + { + var actualValue = property.GetValue(actual); + var expectedValue = property.GetValue(expected); + ModelAssert.AreDeepEqual(actualValue, expectedValue); } } - public static void AreEqual(Property expected, Property actual) - { - Assert.That(expected, Is.Not.Null); - Assert.That(actual, Is.Not.Null); - Assert.That(actual.Name, Is.EqualTo(expected.Name)); - Assert.That(actual.Value, Is.EqualTo(expected.Value)); - } + //public static void AreEqual(Module actual, Module expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual.Instances.Count, Is.EqualTo(expected.Instances.Count)); + // for (var i = 0; i < expected.Instances.Count; i++) + // { + // ModelAssert.AreEqual(actual.Instances[i], expected.Instances[i]); + // } + //} + + //public static void AreEqual(Instance actual, Instance expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, + // Has.Property(nameof(actual.TypeName)).EqualTo(expected.TypeName) + // ); + // Assert.That(actual, + // Has.Property(nameof(actual.Alias)).EqualTo(expected.Alias) + // ); + // Assert.That(actual.Properties.Count, Is.EqualTo(expected.Properties.Count)); + // for (var i = 0; i < expected.Properties.Count; i++) + // { + // ModelAssert.AreEqual(actual.Properties[i], expected.Properties[i]); + // } + //} + + //public static void AreEqual(Property actual, Property expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, + // Has.Property(nameof(actual.Name)).EqualTo(expected.Name) + // ); + // ModelAssert.AreEqual(actual.Value, expected.Value); + //} + + //private static void AreEqual(PropertyValue actual, PropertyValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // switch (expected) + // { + // case PrimitiveTypeValue exp: + // ModelAssert.AreEqual((PrimitiveTypeValue)actual, exp); + // break; + // case ComplexTypeValue exp: + // ModelAssert.AreEqual((ComplexTypeValue)actual, exp); + // break; + // case EnumTypeValue exp: + // ModelAssert.AreEqual((EnumTypeValue)actual, exp); + // break; + // default: + // throw new NotImplementedException(); + // }; + //} + + //private static void AreEqual(PrimitiveTypeValue actual, PrimitiveTypeValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // switch (expected) + // { + // case LiteralValue exp: + // ModelAssert.AreEqual((LiteralValue)actual, exp); + // break; + // case LiteralValueArray exp: + // ModelAssert.AreEqual((LiteralValueArray)actual, exp); + // break; + // default: + // throw new NotImplementedException(); + // } + //} + + //private static void AreEqual(LiteralValue actual, LiteralValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // switch (expected) + // { + // case IntegerValue exp: + // ModelAssert.AreEqual((IntegerValue)actual, exp); + // break; + // case RealValue exp: + // ModelAssert.AreEqual((RealValue)actual, exp); + // break; + // case BooleanValue exp: + // ModelAssert.AreEqual((BooleanValue)actual, exp); + // break; + // case NullValue exp: + // ModelAssert.AreEqual((NullValue)actual, exp); + // break; + // case StringValue exp: + // ModelAssert.AreEqual((StringValue)actual, exp); + // break; + // default: + // throw new NotImplementedException(); + // } + //} + + //private static void AreEqual(IntegerValue actual, IntegerValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // Assert.That(actual, + // Has.Property(nameof(actual.Value)).EqualTo(expected.Value) + // ); + //} + + //private static void AreEqual(RealValue actual, RealValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // Assert.That(actual, + // Has.Property(nameof(actual.Value)).EqualTo(expected.Value) + // ); + //} + + //private static void AreEqual(BooleanValue actual, BooleanValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // Assert.That(actual, + // Has.Property(nameof(actual.Value)).EqualTo(expected.Value) + // ); + //} + + //private static void AreEqual(NullValue actual, NullValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + //} + + //private static void AreEqual(StringValue actual, StringValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // Assert.That(actual, + // Has.Property(nameof(actual.Value)).EqualTo(expected.Value) + // ); + //} + + //private static void AreEqual(LiteralValueArray actual, LiteralValueArray expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual.Values.Count, Is.EqualTo(expected.Values.Count)); + // for (var i = 0; i < expected.Values.Count; i++) + // { + // ModelAssert.AreEqual(actual.Values[i], expected.Values[i]); + // } + //} + + //private static void AreEqual(ComplexTypeValue actual, ComplexTypeValue expected) + //{ + // throw new NotImplementedException(); + //} + + //private static void AreEqual(EnumTypeValue actual, EnumTypeValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, Is.TypeOf(expected.GetType())); + // switch (expected) + // { + // case EnumValue exp: + // ModelAssert.AreEqual((EnumValue)actual, exp); + // break; + // case EnumValueArray exp: + // ModelAssert.AreEqual((EnumValueArray)actual, exp); + // break; + // default: + // throw new NotImplementedException(); + // }; + //} + + //public static void AreEqual(EnumValue actual, EnumValue expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual, + // Has.Property(nameof(actual.Type)).EqualTo(expected.Type) + // ); + // Assert.That(actual, + // Has.Property(nameof(actual.Name)).EqualTo(expected.Name) + // ); + //} + + //public static void AreEqual(EnumValueArray actual, EnumValueArray expected) + //{ + // Assert.That(expected, Is.Not.Null); + // Assert.That(actual, Is.Not.Null); + // Assert.That(actual.Values.Count, Is.EqualTo(expected.Values.Count)); + // for (var i = 0; i < expected.Values.Count; i++) + // { + // ModelAssert.AreEqual(actual.Values[i], expected.Values[i]); + // } + //} } diff --git a/src/Kingsland.MofParser.UnitTests/Helpers/TokenCompare.cs b/src/Kingsland.MofParser.UnitTests/Helpers/TokenCompare.cs index 9d22318..115f229 100644 --- a/src/Kingsland.MofParser.UnitTests/Helpers/TokenCompare.cs +++ b/src/Kingsland.MofParser.UnitTests/Helpers/TokenCompare.cs @@ -216,8 +216,8 @@ public static bool AreEqual(IntegerLiteralToken? expected, IntegerLiteralToken? else { return (ignoreExtent || TokenCompare.AreEqual(expected.Extent, actual.Extent)) && - (expected.Kind == actual.Kind) && - (expected.Value == actual.Value); + (expected.Kind == actual.Kind) && + (expected.Value == actual.Value); } } @@ -298,7 +298,7 @@ public static bool AreEqual(RealLiteralToken? expected, RealLiteralToken? actual else { return (ignoreExtent || TokenCompare.AreEqual(expected.Extent, actual.Extent)) && - (expected.Value == actual.Value); + (expected.Value == actual.Value); } } @@ -331,7 +331,7 @@ public static bool AreEqual(StringLiteralToken? expected, StringLiteralToken? ac else { return (ignoreExtent || TokenCompare.AreEqual(expected.Extent, actual.Extent)) && - (expected.Value == actual.Value); + (expected.Value == actual.Value); } } @@ -348,7 +348,7 @@ public static bool AreEqual(WhitespaceToken? expected, WhitespaceToken? actual, else { return (ignoreExtent || TokenCompare.AreEqual(expected.Extent, actual.Extent)) && - (expected.Value == actual.Value); + (expected.Value == actual.Value); } } @@ -369,8 +369,8 @@ public static bool AreEqual(SourceExtent? expected, SourceExtent? actual) else { return TokenCompare.AreEqual(expected.StartPosition, actual.StartPosition) && - TokenCompare.AreEqual(expected.EndPosition, actual.EndPosition) && - (expected.Text == actual.Text); + TokenCompare.AreEqual(expected.EndPosition, actual.EndPosition) && + (expected.Text == actual.Text); } } @@ -387,8 +387,8 @@ public static bool AreEqual(SourcePosition? expected, SourcePosition? actual) else { return (expected.Position == actual.Position) && - (expected.LineNumber == actual.LineNumber) && - (expected.ColumnNumber == actual.ColumnNumber); + (expected.LineNumber == actual.LineNumber) && + (expected.ColumnNumber == actual.ColumnNumber); } } diff --git a/src/Kingsland.MofParser.UnitTests/Model/ModelConverter.cs b/src/Kingsland.MofParser.UnitTests/Model/ModelConverter.cs deleted file mode 100644 index d43125c..0000000 --- a/src/Kingsland.MofParser.UnitTests/Model/ModelConverter.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Kingsland.MofParser.Models; -using Kingsland.MofParser.Parsing; -using Kingsland.MofParser.UnitTests.Helpers; -using NUnit.Framework; - -namespace Kingsland.MofParser.UnitTests.Model; - -[TestFixture] -public static class ModelConverter -{ - - [TestFixture] - public static class ConvertMofSpecificationAstTests - { - - [Test] - public static void InstanceWithLiteralValuePropertiesShouldConvert() - { - const string sourceText = @" - instance of MyClass as $MyAlias - { - IntegerProperty = 100; - RealProperty = 10.5; - BooleanProperty = true; - NullProperty = null; - StringProperty = ""MyStringValue""; - }; - "; - var actual = Parser.ParseText(sourceText); - var expected = new Module( - instances: - [ - new( - typeName: "MyClass", - alias: "MyAlias", - properties: - [ - new("IntegerProperty", 100), - new("RealProperty", 10.5), - new("BooleanProperty", true), - new("NullProperty", null), - new("StringProperty", "MyStringValue"), - ] - ) - ] - ); - ModelAssert.AreEqual(expected, actual); - } - - [Test] - public static void InstanceWithLiteralValueArrayPropertiesShouldConvert() - { - const string sourceText = @" - instance of MyClass as $MyAlias - { - EmptyProperty = { }; - IntegerProperty = { 100, 200, 300 }; - RealProperty = { 10.5, 20.75, 30.99 }; - BooleanProperty = { true, false, true, false }; - NullProperty = { null, null, null }; - StringProperty = { ""MyStringValue"", ""MyOtherStringValue"" }; - }; - "; - var actual = Parser.ParseText(sourceText); - var expected = new Module( - instances: - [ - new( - typeName: "MyClass", - alias: "MyAlias", - properties: - [ - new("EmptyProperty", (int[])[]), - new("IntegerProperty", (int[])[100, 200, 300]), - new("RealProperty", (double[])[10.5, 20.75, 30.99]), - new("BooleanProperty", (bool[])[true, false, true, false]), - new("NullProperty", (object?[])[null, null, null]), - new("StringProperty", (string[])["MyStringValue", "MyOtherStringValue"]), - ] - ) - ] - ); - ModelAssert.AreEqual(expected, actual); - } - - } - -} diff --git a/src/Kingsland.MofParser.UnitTests/Parsing/ParserTests_ComplexTypeValue.cs b/src/Kingsland.MofParser.UnitTests/Parsing/ParserTests_ComplexTypeValue.cs index 57d20cd..ebbdb4c 100644 --- a/src/Kingsland.MofParser.UnitTests/Parsing/ParserTests_ComplexTypeValue.cs +++ b/src/Kingsland.MofParser.UnitTests/Parsing/ParserTests_ComplexTypeValue.cs @@ -1,6 +1,8 @@ using Kingsland.MofParser.Ast; using Kingsland.MofParser.Lexing; -using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Converter; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; using Kingsland.MofParser.Parsing; using Kingsland.MofParser.Tokens; using Kingsland.MofParser.UnitTests.Helpers; @@ -57,19 +59,16 @@ public static void ParsePropertyValueWithLiteralString() var expectedJson = TestUtils.ConvertToJson(expectedAst); Assert.That(actualJson, Is.EqualTo(expectedJson)); var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); - var expectedModule = new Module.Builder - { - Instances = [ - new Instance.Builder { - TypeName = "myType", - Alias = "Alias0000006E", - Properties = [ - new Property("ServerURL", "https://URL") - ] - }.Build() - ] - }.Build(); - ModelAssert.AreEqual(expectedModule, actualModule); + var expectedModule = new Module([ + new Instance( + typeName: "myType", + alias: "Alias0000006E", + properties: [ + new Property("ServerURL", "https://URL") + ] + ) + ]); + ModelAssert.AreDeepEqual(expectedModule, actualModule); } [Test] @@ -110,19 +109,16 @@ public static void ParsePropertyValueWithAliasIdentifier() var expectedJson = TestUtils.ConvertToJson(expectedAst); Assert.That(actualJson, Is.EqualTo(expectedJson)); var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); - var expectedModule = new Module.Builder - { - Instances = [ - new Instance.Builder { - TypeName = "myType", - Alias = "Alias00000070", - Properties = [ - new Property("Reference", "Alias0000006E") - ] - }.Build() - ] - }.Build(); - ModelAssert.AreEqual(expectedModule, actualModule); + var expectedModule = new Module([ + new Instance( + typeName: "myType", + alias: "Alias00000070", + properties: [ + new Property("Reference", new ComplexValueAlias("Alias0000006E")) + ] + ) + ]); + ModelAssert.AreDeepEqual(expectedModule, actualModule); } [Test] @@ -163,18 +159,16 @@ public static void ParsePropertyValueWithEmptyArray() var expectedJson = TestUtils.ConvertToJson(expectedAst); Assert.That(actualJson, Is.EqualTo(expectedJson)); var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); - var expectedModule = new Module.Builder { - Instances = [ - new Instance.Builder { - TypeName = "myType", - Alias = "Alias00000070", - Properties = [ - new Property("Reference", new List()) - ] - }.Build() - ] - }.Build(); - ModelAssert.AreEqual(expectedModule, actualModule); + var expectedModule = new Module([ + new Instance( + typeName: "myType", + alias: "Alias00000070", + properties: [ + new Property("Reference", new LiteralValueArray()) + ] + ) + ]); + ModelAssert.AreDeepEqual(expectedModule, actualModule); } [Test] @@ -219,22 +213,18 @@ public static void ParsePropertyValueArrayWithAliasIdentifier() var expectedJson = TestUtils.ConvertToJson(expectedAst); Assert.That(actualJson, Is.EqualTo(expectedJson)); var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); - var expectedModule = new Module.Builder - { - Instances = [ - new Instance.Builder - { - TypeName = "myType", - Alias = "Alias00000070", - Properties = [ - new Property("Reference", new List { - "Alias0000006E" - }) - ] - }.Build() - ] - }.Build(); - ModelAssert.AreEqual(expectedModule, actualModule); + var expectedModule = new Module([ + new Instance( + typeName: "myType", + alias: "Alias00000070", + properties: [ + new Property("Reference", new ComplexValueArray([ + new ComplexValueAlias("Alias0000006E") + ])) + ] + ) + ]); + ModelAssert.AreDeepEqual(expectedModule, actualModule); } [Test] @@ -286,20 +276,18 @@ public static void ParsePropertyValueArrayWithLiteralStrings() var expectedJson = TestUtils.ConvertToJson(expectedAst); Assert.That(actualJson, Is.EqualTo(expectedJson)); var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); - var expectedModule = new Module.Builder { - Instances = [ - new Instance.Builder { - TypeName = "myType", - Alias = "Alias00000070", - Properties = [ - new Property("ServerURLs", new List { - "https://URL1", "https://URL2" - }) - ] - }.Build() - ] - }.Build(); - ModelAssert.AreEqual(expectedModule, actualModule); + var expectedModule = new Module([ + new Instance( + typeName: "myType", + alias: "Alias00000070", + properties: [ + new Property("ServerURLs", new LiteralValueArray( + "https://URL1", "https://URL2" + )) + ] + ) + ]); + ModelAssert.AreDeepEqual(expectedModule, actualModule); } [Test] @@ -378,23 +366,20 @@ public static void ParsePropertyValueArrayWithNumericLiteralValues() var expectedJson = TestUtils.ConvertToJson(expectedAst); Assert.That(actualJson, Is.EqualTo(expectedJson)); var actualModule = ModelConverter.ConvertMofSpecificationAst(actualAst); - var expectedModule = new Module.Builder - { - Instances = [ - new Instance.Builder { - TypeName = "myType", - Alias = "Alias00000070", - Properties = [ - new Property("MyBinaryValue", 42), - new Property("MyOctalValue", 149796), - new Property("MyHexValue", 11256099), - new Property("MyDecimalValue", 12345), - new Property("MyRealValue", 123.45) - ] - }.Build() - ] - }.Build(); - ModelAssert.AreEqual(expectedModule, actualModule); + var expectedModule = new Module([ + new Instance( + typeName: "myType", + alias: "Alias00000070", + properties: [ + new Property("MyBinaryValue", 42), + new Property("MyOctalValue", 149796), + new Property("MyHexValue", 11256099), + new Property("MyDecimalValue", 12345), + new Property("MyRealValue", 123.45) + ] + ) + ]); + ModelAssert.AreDeepEqual(expectedModule, actualModule); } } diff --git a/src/Kingsland.MofParser/Ast/ComplexValueArrayAst.cs b/src/Kingsland.MofParser/Ast/ComplexValueArrayAst.cs index 69460cc..86ce546 100644 --- a/src/Kingsland.MofParser/Ast/ComplexValueArrayAst.cs +++ b/src/Kingsland.MofParser/Ast/ComplexValueArrayAst.cs @@ -45,6 +45,12 @@ public ComplexValueArrayAst Build() #region Constructors + public ComplexValueArrayAst(params ComplexValueAst[] values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + internal ComplexValueArrayAst( IEnumerable values ) diff --git a/src/Kingsland.MofParser/Ast/EnumValueArrayAst.cs b/src/Kingsland.MofParser/Ast/EnumValueArrayAst.cs index 3f3ffa1..020aa44 100644 --- a/src/Kingsland.MofParser/Ast/EnumValueArrayAst.cs +++ b/src/Kingsland.MofParser/Ast/EnumValueArrayAst.cs @@ -50,6 +50,12 @@ internal EnumValueArrayAst() { } + public EnumValueArrayAst(params EnumValueAst[] values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + internal EnumValueArrayAst( IEnumerable values ) diff --git a/src/Kingsland.MofParser/Ast/EnumValueAst.cs b/src/Kingsland.MofParser/Ast/EnumValueAst.cs index 846357c..1444ae1 100644 --- a/src/Kingsland.MofParser/Ast/EnumValueAst.cs +++ b/src/Kingsland.MofParser/Ast/EnumValueAst.cs @@ -55,6 +55,12 @@ public EnumValueAst Build() #region Constructors + internal EnumValueAst( + IdentifierToken enumLiteral + ) : this(null, enumLiteral) + { + } + internal EnumValueAst( IdentifierToken? enumName, IdentifierToken enumLiteral diff --git a/src/Kingsland.MofParser/Ast/LiteralValueArrayAst.cs b/src/Kingsland.MofParser/Ast/LiteralValueArrayAst.cs index be15fc0..7b294e0 100644 --- a/src/Kingsland.MofParser/Ast/LiteralValueArrayAst.cs +++ b/src/Kingsland.MofParser/Ast/LiteralValueArrayAst.cs @@ -50,6 +50,12 @@ internal LiteralValueArrayAst() { } + public LiteralValueArrayAst(params LiteralValueAst[] values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + internal LiteralValueArrayAst( IEnumerable values ) diff --git a/src/Kingsland.MofParser/Models/Class.cs b/src/Kingsland.MofParser/Models/Class.cs deleted file mode 100644 index dc944d8..0000000 --- a/src/Kingsland.MofParser/Models/Class.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace Kingsland.MofParser.Models; - -public sealed record Class -{ - - #region Builder - - public sealed class Builder - { - - public string? ClassName - { - get; - set; - } - - public string? SuperClass - { - get; - set; - } - - public Class Build() - { - return new Class( - this.ClassName ?? throw new InvalidOperationException( - $"{nameof(this.ClassName)} property must be set before calling {nameof(Build)}." - ), - this.SuperClass ?? throw new InvalidOperationException( - $"{nameof(this.SuperClass)} property must be set before calling {nameof(Build)}." - ) - ); - } - - } - - #endregion - - #region Constructors - - internal Class(string className, string superClass) - { - this.ClassName = className ?? throw new ArgumentNullException(nameof(className)); - this.SuperClass = superClass ?? throw new ArgumentNullException(nameof(superClass)); - } - - #endregion - - #region Properties - - public string ClassName - { - get; - } - - public string SuperClass - { - get; - } - - #endregion - -} diff --git a/src/Kingsland.MofParser/Models/ModelConverter.cs b/src/Kingsland.MofParser/Models/Converter/ModelConverter.cs similarity index 53% rename from src/Kingsland.MofParser/Models/ModelConverter.cs rename to src/Kingsland.MofParser/Models/Converter/ModelConverter.cs index f2b8c0d..038ea08 100644 --- a/src/Kingsland.MofParser/Models/ModelConverter.cs +++ b/src/Kingsland.MofParser/Models/Converter/ModelConverter.cs @@ -1,30 +1,12 @@ using Kingsland.MofParser.Ast; -using System.Collections.ObjectModel; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; -namespace Kingsland.MofParser.Models; +namespace Kingsland.MofParser.Models.Converter; -internal static class ModelConverter +internal static partial class ModelConverter { - #region 7.2 MOF specification - - public static Module ConvertMofSpecificationAst(MofSpecificationAst node) - { - return new Module.Builder - { - Enumerations = node.Productions - .OfType() - .Select(ModelConverter.ConvertEnumerationDeclarationAst) - .ToList(), - Instances = node.Productions - .OfType() - .Select(ModelConverter.ConvertInstanceValueDeclarationAst) - .ToList(), - }.Build(); - } - - #endregion - #region 7.3 Compiler directives public static void ConvertCompilerDirectiveAst(CompilerDirectiveAst node) @@ -90,11 +72,6 @@ public static void ConvertStructureFeatureAst(IStructureFeatureAst node) public static void ConvertClassDeclarationAst(ClassDeclarationAst node) { - // return new Class.Builder - // { - // ClassName = node.ClassName.Name, - // SuperClass = node.SuperClass.Name - // }.Build(); throw new NotImplementedException(); } @@ -160,69 +137,9 @@ public static void ConvertParameterDeclarationAst(ParameterDeclarationAst node) #endregion - #region 7.5.9 Complex type value - - public static object ConvertComplexTypeValueAst(ComplexTypeValueAst node) - { - return node switch - { - ComplexValueArrayAst n => ModelConverter.ConvertComplexValueArrayAst(n), - ComplexValueAst n => ModelConverter.ConvertComplexValueAst(n), - _ => throw new NotImplementedException(), - }; - } - - public static ReadOnlyCollection ConvertComplexValueArrayAst(ComplexValueArrayAst node) - { - return node.Values - .Select(ModelConverter.ConvertComplexValueAst) - .ToList() - .AsReadOnly(); - } - - public static object ConvertComplexValueAst(ComplexValueAst node) - { - if (node.IsAlias) - { - var alias = node.Alias ?? throw new NullReferenceException(); - return alias.Name; - } - return node switch - { - _ => throw new NotImplementedException() - }; - } - - public static ReadOnlyCollection ConvertPropertyValueListAst(PropertyValueListAst node) - { - return node.PropertyValues - .Select( - kvp => new Property.Builder - { - Name = kvp.Key, - Value = ModelConverter.ConvertPropertyValueAst(kvp.Value) - }.Build() - ).ToList() - .AsReadOnly(); - } - - public static object ConvertPropertyValueAst(PropertyValueAst node) - { - return node switch - { - PrimitiveTypeValueAst n => ModelConverter.ConvertPrimitiveTypeValueAst(n), - ComplexTypeValueAst n => ModelConverter.ConvertComplexTypeValueAst(n), - //ReferenceTypeValueAst n => ModelConverter.FromReferenceTypeValueAst(n), - //EnumTypeValueAst n => ModelConverter.FromEnumTypeValueAst(n), - _ => throw new NotImplementedException() - }; - } - - #endregion - #region 7.6.1 Primitive type value - public static object? ConvertPrimitiveTypeValueAst(PrimitiveTypeValueAst node) + public static PrimitiveTypeValue ConvertPrimitiveTypeValueAst(PrimitiveTypeValueAst node) { return node switch { @@ -232,7 +149,7 @@ public static object ConvertPropertyValueAst(PropertyValueAst node) }; } - public static object? ConvertLiteralValueAst(LiteralValueAst node) + public static LiteralValue ConvertLiteralValueAst(LiteralValueAst node) { return node switch { @@ -245,57 +162,56 @@ public static object ConvertPropertyValueAst(PropertyValueAst node) }; } - public static ReadOnlyCollection ConvertLiteralValueArrayAst(LiteralValueArrayAst node) + public static LiteralValueArray ConvertLiteralValueArrayAst(LiteralValueArrayAst node) { - return node.Values - .Select(ModelConverter.ConvertLiteralValueAst) - .ToList() - .AsReadOnly(); + return new( + node.Values.Select(ModelConverter.ConvertLiteralValueAst) + ); } #endregion #region 7.6.1.1 Integer value - public static long ConvertIntegerValueAst(IntegerValueAst node) + public static IntegerValue ConvertIntegerValueAst(IntegerValueAst node) { - return node.Value; + return new(node.Value); } #endregion #region 7.6.1.2 Real value - public static double ConvertRealValueAst(RealValueAst node) + public static RealValue ConvertRealValueAst(RealValueAst node) { - return node.Value; + return new(node.Value); } #endregion #region 7.6.1.3 String values - public static string ConvertStringValueAst(StringValueAst node) + public static StringValue ConvertStringValueAst(StringValueAst node) { - return node.Value; + return new(node.Value); } #endregion #region 7.6.1.5 Boolean value - public static bool ConvertBooleanValueAst(BooleanValueAst node) + public static BooleanValue ConvertBooleanValueAst(BooleanValueAst node) { - return node.Value; + return new(node.Value); } #endregion #region 7.6.1.6 Null value - public static object? ConvertNullValueAst(NullValueAst node) + public static NullValue ConvertNullValueAst(NullValueAst node) { - return null; + return NullValue.Null; } #endregion @@ -304,12 +220,11 @@ public static bool ConvertBooleanValueAst(BooleanValueAst node) public static Instance ConvertInstanceValueDeclarationAst(InstanceValueDeclarationAst node) { - return new Instance.Builder - { - TypeName = node.TypeName.Name, - Alias = node.Alias?.Name, - Properties = [.. ModelConverter.ConvertPropertyValueListAst(node.PropertyValues)] - }.Build(); + return new Instance( + typeName: node.TypeName.Name, + alias: node.Alias?.Name, + properties: [.. ModelConverter.ConvertPropertyValueListAst(node.PropertyValues)] + ); } public static void ConvertStructureValueDeclarationAst(StructureValueDeclarationAst node) @@ -321,19 +236,29 @@ public static void ConvertStructureValueDeclarationAst(StructureValueDeclaration #region 7.6.3 Enum type value - public static void ConvertEnumTypeValueAst(EnumTypeValueAst node) + public static EnumTypeValue ConvertEnumTypeValueAst(EnumTypeValueAst node) { - throw new NotImplementedException(); + return node switch + { + EnumValueAst n => ModelConverter.ConvertEnumValueAst(n), + EnumValueArrayAst n => ModelConverter.ConvertEnumValueArrayAst(n), + _ => throw new NotImplementedException() + }; } - public static void ConvertEnumValueAst(EnumValueAst node) + public static EnumValue ConvertEnumValueAst(EnumValueAst node) { - throw new NotImplementedException(); + return new( + node.EnumName?.Name, + node.EnumLiteral.Name + ); } - public static void ConvertEnumValueArrayAst(EnumValueArrayAst node) + public static EnumValueArray ConvertEnumValueArrayAst(EnumValueArrayAst node) { - throw new NotImplementedException(); + return new( + node.Values.Select(ModelConverter.ConvertEnumValueAst) + ); } #endregion diff --git a/src/Kingsland.MofParser/Models/Converter/ModelConverter_ComplexTypeValue.cs b/src/Kingsland.MofParser/Models/Converter/ModelConverter_ComplexTypeValue.cs new file mode 100644 index 0000000..57827cd --- /dev/null +++ b/src/Kingsland.MofParser/Models/Converter/ModelConverter_ComplexTypeValue.cs @@ -0,0 +1,71 @@ +using Kingsland.MofParser.Ast; +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Models.Values; + +namespace Kingsland.MofParser.Models.Converter; + +internal static partial class ModelConverter +{ + + #region 7.5.9 Complex type value + + public static PropertyValue ConvertComplexTypeValueAst(ComplexTypeValueAst node) + { + return node switch + { + ComplexValueArrayAst n => ModelConverter.ConvertComplexValueArrayAst(n), + ComplexValueAst n => ModelConverter.ConvertComplexValueAst(n), + _ => throw new NotImplementedException(), + }; + } + + public static ComplexValueArray ConvertComplexValueArrayAst(ComplexValueArrayAst node) + { + return new( + node.Values.Select(ModelConverter.ConvertComplexValueAst) + ); + } + + public static ComplexValueBase ConvertComplexValueAst(ComplexValueAst node) + { + if (node.IsAlias) + { + return new ComplexValueAlias( + (node.Alias ?? throw new InvalidOperationException()).Name + ); + } + else + { + return new ComplexValueObject( + (node.TypeName ?? throw new InvalidOperationException()).Name, + ModelConverter.ConvertPropertyValueListAst(node.PropertyValues) + ); + } + } + + public static IEnumerable ConvertPropertyValueListAst(PropertyValueListAst node) + { + return node.PropertyValues + .Select( + kvp => new Property( + name: kvp.Key, + value: ModelConverter.ConvertPropertyValueAst(kvp.Value) + ) + ); + } + + public static PropertyValue ConvertPropertyValueAst(PropertyValueAst node) + { + return node switch + { + PrimitiveTypeValueAst n => ModelConverter.ConvertPrimitiveTypeValueAst(n), + ComplexTypeValueAst n => ModelConverter.ConvertComplexTypeValueAst(n), + //ReferenceTypeValueAst n => ModelConverter.FromReferenceTypeValueAst(n), + EnumTypeValueAst n => ModelConverter.ConvertEnumTypeValueAst(n), + _ => throw new NotImplementedException() + }; + } + + #endregion + +} diff --git a/src/Kingsland.MofParser/Models/Converter/ModelConverter_MofSpecification.cs b/src/Kingsland.MofParser/Models/Converter/ModelConverter_MofSpecification.cs new file mode 100644 index 0000000..082fb65 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Converter/ModelConverter_MofSpecification.cs @@ -0,0 +1,27 @@ +using Kingsland.MofParser.Ast; +using Kingsland.MofParser.Models.Types; + +namespace Kingsland.MofParser.Models.Converter; + +internal static partial class ModelConverter +{ + + #region 7.2 MOF specification + + public static Module ConvertMofSpecificationAst(MofSpecificationAst node) + { + return new Module( + //enumerations: node.Productions + // .OfType() + // .Select(ModelConverter.ConvertEnumerationDeclarationAst) + // .ToList(), + instances: node.Productions + .OfType() + .Select(ModelConverter.ConvertInstanceValueDeclarationAst) + .ToList() + ); + } + + #endregion + +} diff --git a/src/Kingsland.MofParser/Models/ModelSerializer.cs b/src/Kingsland.MofParser/Models/ModelSerializer.cs new file mode 100644 index 0000000..b389948 --- /dev/null +++ b/src/Kingsland.MofParser/Models/ModelSerializer.cs @@ -0,0 +1,6 @@ +namespace Kingsland.MofParser.Models; + +internal sealed class ModelSerializer +{ + +} diff --git a/src/Kingsland.MofParser/Models/Module.cs b/src/Kingsland.MofParser/Models/Module.cs deleted file mode 100644 index 0f29d1d..0000000 --- a/src/Kingsland.MofParser/Models/Module.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.ObjectModel; - -namespace Kingsland.MofParser.Models; - -public sealed record Module -{ - - #region Builder - - public sealed class Builder - { - - public Builder() - { - this.Enumerations = []; - this.Instances = []; - } - - public List Enumerations - { - get; - set; - } - - public List Instances - { - get; - set; - } - - public Module Build() - { - return new Module( - this.Instances - ); - } - - } - - #endregion - - #region Constructors - - internal Module(IEnumerable instances) - { - this.Instances = (instances ?? throw new ArgumentNullException(nameof(instances))) - .ToList().AsReadOnly(); - } - - #endregion - - #region Properties - - public ReadOnlyCollection Instances - { - get; - } - - #endregion - -} diff --git a/src/Kingsland.MofParser/Models/Property.cs b/src/Kingsland.MofParser/Models/Property.cs deleted file mode 100644 index 35caf1f..0000000 --- a/src/Kingsland.MofParser/Models/Property.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Kingsland.MofParser.Parsing; -using Kingsland.MofParser.Tokens; -using System.Text; - -namespace Kingsland.MofParser.Models; - -public sealed record Property -{ - - #region Builder - - public sealed class Builder - { - - public string? Name - { - get; - set; - } - - public object? Value - { - get; - set; - } - - public Property Build() - { - return new Property( - this.Name ?? throw new InvalidOperationException( - $"{nameof(this.Name)} property must be set before calling {nameof(Build)}." - ), - this.Value - ); - } - - } - - #endregion - - #region Constructors - - internal Property(string name, object? value) - { - this.Name = name ?? throw new ArgumentNullException(nameof(name)); - this.Value = value; - } - - #endregion - - #region Properties - - public string Name - { - get; - } - - public object? Value - { - get; - } - - #endregion - - #region Object Interface - - public override string ToString() - { - var result = new StringBuilder(); - result.Append($"{this.Name} = "); - result.Append( - this.Value switch - { - null => Constants.NULL, - true => Constants.TRUE, - false => Constants.FALSE, - string s => $"\"{StringLiteralToken.EscapeString(s)}\"", - _ => $"!!!{this.Value.GetType().FullName}!!!" - } - ); - return result.ToString(); - } - - #endregion - -} diff --git a/src/Kingsland.MofParser/Models/Types/Class.cs b/src/Kingsland.MofParser/Models/Types/Class.cs new file mode 100644 index 0000000..ccc0fe9 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Types/Class.cs @@ -0,0 +1,22 @@ +namespace Kingsland.MofParser.Models.Types; + +public sealed record Class +{ + + internal Class(string className, string superClass) + { + this.ClassName = className ?? throw new ArgumentNullException(nameof(className)); + this.SuperClass = superClass ?? throw new ArgumentNullException(nameof(superClass)); + } + + public string ClassName + { + get; + } + + public string SuperClass + { + get; + } + +} diff --git a/src/Kingsland.MofParser/Models/Enumeration.cs b/src/Kingsland.MofParser/Models/Types/Enumeration.cs similarity index 84% rename from src/Kingsland.MofParser/Models/Enumeration.cs rename to src/Kingsland.MofParser/Models/Types/Enumeration.cs index 2e4d0d3..46455e5 100644 --- a/src/Kingsland.MofParser/Models/Enumeration.cs +++ b/src/Kingsland.MofParser/Models/Types/Enumeration.cs @@ -1,10 +1,8 @@ -namespace Kingsland.MofParser.Models; +namespace Kingsland.MofParser.Models.Types; public sealed class Enumeration { - #region Constructors - public Enumeration(string name, Type underlyingType) { this.Name = name ?? throw new ArgumentNullException(nameof(name)); @@ -18,10 +16,6 @@ public Enumeration(string name, Type underlyingType) ); } - #endregion - - #region Properties - public string Name { get; @@ -32,6 +26,4 @@ public Type UnderlyingType get; } - #endregion - } diff --git a/src/Kingsland.MofParser/Models/Instance.cs b/src/Kingsland.MofParser/Models/Types/Instance.cs similarity index 63% rename from src/Kingsland.MofParser/Models/Instance.cs rename to src/Kingsland.MofParser/Models/Types/Instance.cs index f87d04f..797379f 100644 --- a/src/Kingsland.MofParser/Models/Instance.cs +++ b/src/Kingsland.MofParser/Models/Types/Instance.cs @@ -2,56 +2,16 @@ using System.Collections.ObjectModel; using System.Text; -namespace Kingsland.MofParser.Models; +namespace Kingsland.MofParser.Models.Types; public sealed record Instance { - #region Builder - - public sealed class Builder + internal Instance(string typeName, IEnumerable properties) + : this(typeName, null, properties) { - - public Builder() - { - this.Properties = []; - } - - public string? TypeName - { - get; - set; - } - - public string? Alias - { - get; - set; - } - - public List Properties - { - get; - set; - } - - public Instance Build() - { - return new Instance( - this.TypeName ?? throw new InvalidOperationException( - $"{nameof(this.TypeName)} property must be set before calling {nameof(Build)}." - ), - this.Alias, - this.Properties - ); - } - } - #endregion - - #region Constructors - internal Instance(string typeName, string? alias, IEnumerable properties) { this.TypeName = typeName ?? throw new ArgumentNullException(nameof(typeName)); @@ -62,10 +22,6 @@ internal Instance(string typeName, string? alias, IEnumerable properti ); } - #endregion - - #region Properties - public string TypeName { get; @@ -81,10 +37,6 @@ public ReadOnlyCollection Properties get; } - #endregion - - #region Methods - //public T GetValue(string name) //{ // return (T)this.Properties.Single(p => p.Name == name).Value; @@ -108,10 +60,6 @@ public ReadOnlyCollection Properties // return false; //} - #endregion - - #region Object Interface - public override string ToString() { var result = new StringBuilder(); @@ -123,6 +71,4 @@ public override string ToString() return result.ToString(); } - #endregion - } diff --git a/src/Kingsland.MofParser/Models/Types/Module.cs b/src/Kingsland.MofParser/Models/Types/Module.cs new file mode 100644 index 0000000..08e7f52 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Types/Module.cs @@ -0,0 +1,19 @@ +using System.Collections.ObjectModel; + +namespace Kingsland.MofParser.Models.Types; + +public sealed record Module +{ + + internal Module(IEnumerable instances) + { + this.Instances = (instances ?? throw new ArgumentNullException(nameof(instances))) + .ToList().AsReadOnly(); + } + + public ReadOnlyCollection Instances + { + get; + } + +} diff --git a/src/Kingsland.MofParser/Models/Types/Property.cs b/src/Kingsland.MofParser/Models/Types/Property.cs new file mode 100644 index 0000000..507b2fd --- /dev/null +++ b/src/Kingsland.MofParser/Models/Types/Property.cs @@ -0,0 +1,29 @@ +using Kingsland.MofParser.Models.Values; + +namespace Kingsland.MofParser.Models.Types; + +public sealed record Property +{ + + internal Property(string name, PropertyValue value) + { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + this.Value = value ?? throw new ArgumentNullException(nameof(value)); + } + + public string Name + { + get; + } + + public PropertyValue Value + { + get; + } + + public override string ToString() + { + return $"{this.Name} = {this.Value}"; + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/BooleanValue .cs b/src/Kingsland.MofParser/Models/Values/BooleanValue .cs new file mode 100644 index 0000000..ac0a9c0 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/BooleanValue .cs @@ -0,0 +1,25 @@ +using Kingsland.MofParser.Parsing; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class BooleanValue : LiteralValue +{ + + public BooleanValue(bool value) + { + this.Value = value; + } + + public bool Value + { + get; + } + + public override string ToString() + { + return this.Value + ? Constants.TRUE + : Constants.FALSE; + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/ComplexTypeValue.cs b/src/Kingsland.MofParser/Models/Values/ComplexTypeValue.cs new file mode 100644 index 0000000..0d2cfb2 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/ComplexTypeValue.cs @@ -0,0 +1,10 @@ +namespace Kingsland.MofParser.Models.Values; + +public abstract class ComplexTypeValue : PropertyValue +{ + + internal ComplexTypeValue() + { + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/ComplexValueAlias.cs b/src/Kingsland.MofParser/Models/Values/ComplexValueAlias.cs new file mode 100644 index 0000000..3cf9ceb --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/ComplexValueAlias.cs @@ -0,0 +1,21 @@ +namespace Kingsland.MofParser.Models.Values; + +public sealed class ComplexValueAlias : ComplexValueBase +{ + + public ComplexValueAlias(string name) + { + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + } + + public string Name + { + get; + } + + public override string ToString() + { + return $"${this.Name}"; + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/ComplexValueArray.cs b/src/Kingsland.MofParser/Models/Values/ComplexValueArray.cs new file mode 100644 index 0000000..2127099 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/ComplexValueArray.cs @@ -0,0 +1,42 @@ +using System.Collections.ObjectModel; +using System.Text; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class ComplexValueArray : ComplexTypeValue +{ + + public ComplexValueArray(params ComplexValueBase[] values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + + public ComplexValueArray(IEnumerable values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + + public ReadOnlyCollection Values + { + get; + } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append("{"); + for (var i = 0; i < this.Values.Count; i++) + { + if (i > 0) + { + sb.Append(", "); + } + sb.Append(this.Values[i]); + } + sb.Append("}"); + return sb.ToString(); + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/ComplexValueBase.cs b/src/Kingsland.MofParser/Models/Values/ComplexValueBase.cs new file mode 100644 index 0000000..56969a9 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/ComplexValueBase.cs @@ -0,0 +1,10 @@ +namespace Kingsland.MofParser.Models.Values; + +public abstract class ComplexValueBase : ComplexTypeValue +{ + + internal ComplexValueBase() + { + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/ComplexValueObject.cs b/src/Kingsland.MofParser/Models/Values/ComplexValueObject.cs new file mode 100644 index 0000000..dd8d6c9 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/ComplexValueObject.cs @@ -0,0 +1,58 @@ +using Kingsland.MofParser.Models.Types; +using Kingsland.MofParser.Parsing; +using System.Collections.ObjectModel; +using System.Text; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class ComplexValueObject : ComplexValueBase +{ + + internal ComplexValueObject(string typeName, IEnumerable properties) + { + this.TypeName = typeName ?? throw new ArgumentNullException(nameof(typeName)); + this.Properties = (properties ?? throw new ArgumentNullException(nameof(properties))) + .ToList().AsReadOnly(); + } + + public string TypeName + { + get; + } + + public ReadOnlyCollection Properties + { + get; + } + + //public T GetValue(string name) + //{ + // return (T)this.Properties.Single(p => p.Name == name).Value; + //} + + //public bool TryGetValue(string name, out T result) + //{ + // var property = this.Properties.SingleOrDefault(p => p.Name == name); + // if (property == null) + // { + // result = default; + // return false; + // } + // var value = property.Value; + // if (value is T typed) + // { + // result = typed; + // return true; + // } + // result = default; + // return false; + //} + + public override string ToString() + { + var result = new StringBuilder(); + result.Append($"{Constants.VALUE} {Constants.OF} {this.TypeName}"); + return result.ToString(); + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/EnumTypeValue.cs b/src/Kingsland.MofParser/Models/Values/EnumTypeValue.cs new file mode 100644 index 0000000..045a7f6 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/EnumTypeValue.cs @@ -0,0 +1,10 @@ +namespace Kingsland.MofParser.Models.Values; + +public abstract class EnumTypeValue : PropertyValue +{ + + internal EnumTypeValue() + { + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/EnumValue.cs b/src/Kingsland.MofParser/Models/Values/EnumValue.cs new file mode 100644 index 0000000..7437cef --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/EnumValue.cs @@ -0,0 +1,27 @@ +namespace Kingsland.MofParser.Models.Values; + +public sealed class EnumValue : EnumTypeValue +{ + + public EnumValue(string name) + : this(null, name) + { + } + + public EnumValue(string? type, string name) + { + this.Type = type; + this.Name = name ?? throw new ArgumentNullException(nameof(name)); + } + + public string? Type + { + get; + } + + public string Name + { + get; + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/EnumValueArray.cs b/src/Kingsland.MofParser/Models/Values/EnumValueArray.cs new file mode 100644 index 0000000..a4f753e --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/EnumValueArray.cs @@ -0,0 +1,42 @@ +using System.Collections.ObjectModel; +using System.Text; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class EnumValueArray : EnumTypeValue +{ + + public EnumValueArray(params EnumValue[] values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + + public EnumValueArray(IEnumerable values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + + public ReadOnlyCollection Values + { + get; + } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append("{"); + for (var i = 0; i < this.Values.Count; i++) + { + if (i > 0) + { + sb.Append(", "); + } + sb.Append(this.Values[i]); + } + sb.Append("}"); + return sb.ToString(); + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/IntegerValue.cs b/src/Kingsland.MofParser/Models/Values/IntegerValue.cs new file mode 100644 index 0000000..07e95cd --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/IntegerValue.cs @@ -0,0 +1,23 @@ +using System.Globalization; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class IntegerValue : LiteralValue +{ + + public IntegerValue(long value) + { + this.Value = value; + } + + public long Value + { + get; + } + + public override string ToString() + { + return this.Value.ToString(CultureInfo.InvariantCulture); + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/LiteralValue.cs b/src/Kingsland.MofParser/Models/Values/LiteralValue.cs new file mode 100644 index 0000000..c054334 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/LiteralValue.cs @@ -0,0 +1,15 @@ +namespace Kingsland.MofParser.Models.Values; + +public abstract class LiteralValue : PrimitiveTypeValue +{ + + internal LiteralValue() + { + } + + public static implicit operator LiteralValue(int value) => new IntegerValue(value); + public static implicit operator LiteralValue(double value) => new RealValue(value); + public static implicit operator LiteralValue(bool value) => new BooleanValue(value); + public static implicit operator LiteralValue(string value) => new StringValue(value); + +} diff --git a/src/Kingsland.MofParser/Models/Values/LiteralValueArray.cs b/src/Kingsland.MofParser/Models/Values/LiteralValueArray.cs new file mode 100644 index 0000000..a0f1090 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/LiteralValueArray.cs @@ -0,0 +1,42 @@ +using System.Collections.ObjectModel; +using System.Text; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class LiteralValueArray : PrimitiveTypeValue +{ + + public LiteralValueArray(params LiteralValue[] values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + + public LiteralValueArray(IEnumerable values) + { + this.Values = (values ?? throw new ArgumentNullException(nameof(values))) + .ToList().AsReadOnly(); + } + + public ReadOnlyCollection Values + { + get; + } + + public override string ToString() + { + var sb = new StringBuilder(); + sb.Append("{"); + for (var i = 0; i < this.Values.Count; i++) + { + if (i > 0) + { + sb.Append(", "); + } + sb.Append(this.Values[i]); + } + sb.Append("}"); + return sb.ToString(); + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/NullValue.cs b/src/Kingsland.MofParser/Models/Values/NullValue.cs new file mode 100644 index 0000000..a002ff5 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/NullValue.cs @@ -0,0 +1,19 @@ +using Kingsland.MofParser.Parsing; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class NullValue : LiteralValue +{ + + public static readonly NullValue Null = new(); + + private NullValue() + { + } + + public override string ToString() + { + return Constants.NULL; + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/PrimitiveTypeValue.cs b/src/Kingsland.MofParser/Models/Values/PrimitiveTypeValue.cs new file mode 100644 index 0000000..f479b6f --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/PrimitiveTypeValue.cs @@ -0,0 +1,10 @@ +namespace Kingsland.MofParser.Models.Values; + +public abstract class PrimitiveTypeValue : PropertyValue +{ + + internal PrimitiveTypeValue() + { + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/PropertyValue.cs b/src/Kingsland.MofParser/Models/Values/PropertyValue.cs new file mode 100644 index 0000000..b6dbb3d --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/PropertyValue.cs @@ -0,0 +1,15 @@ +namespace Kingsland.MofParser.Models.Values; + +public abstract class PropertyValue +{ + + internal PropertyValue() + { + } + + public static implicit operator PropertyValue(int value) => new IntegerValue(value); + public static implicit operator PropertyValue(double value) => new RealValue(value); + public static implicit operator PropertyValue(bool value) => new BooleanValue(value); + public static implicit operator PropertyValue(string value) => new StringValue(value); + +} diff --git a/src/Kingsland.MofParser/Models/Values/RealValue.cs b/src/Kingsland.MofParser/Models/Values/RealValue.cs new file mode 100644 index 0000000..2c8fa5a --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/RealValue.cs @@ -0,0 +1,23 @@ +using System.Globalization; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class RealValue : LiteralValue +{ + + public RealValue(double value) + { + this.Value = value; + } + + public double Value + { + get; + } + + public override string ToString() + { + return this.Value.ToString(CultureInfo.InvariantCulture); + } + +} diff --git a/src/Kingsland.MofParser/Models/Values/StringValue.cs b/src/Kingsland.MofParser/Models/Values/StringValue.cs new file mode 100644 index 0000000..eb0c611 --- /dev/null +++ b/src/Kingsland.MofParser/Models/Values/StringValue.cs @@ -0,0 +1,23 @@ +using Kingsland.MofParser.Tokens; + +namespace Kingsland.MofParser.Models.Values; + +public sealed class StringValue : LiteralValue +{ + + public StringValue(string value) + { + this.Value = value ?? throw new ArgumentNullException(nameof(value)); + } + + public string Value + { + get; + } + + public override string ToString() + { + return $"\"{StringLiteralToken.EscapeString(this.Value)}\""; + } + +} diff --git a/src/Kingsland.MofParser/Parsing/Parser.cs b/src/Kingsland.MofParser/Parsing/Parser.cs index 8343616..e7024c3 100644 --- a/src/Kingsland.MofParser/Parsing/Parser.cs +++ b/src/Kingsland.MofParser/Parsing/Parser.cs @@ -1,6 +1,8 @@ using Kingsland.MofParser.Ast; using Kingsland.MofParser.Lexing; using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Converter; +using Kingsland.MofParser.Models.Types; using Kingsland.MofParser.Tokens; using Kingsland.ParseFx.Parsing; using Kingsland.ParseFx.Syntax; diff --git a/src/Kingsland.MofParser/Parsing/ParserQuirks.cs b/src/Kingsland.MofParser/Parsing/ParserQuirks.cs index df18ac5..79dca67 100644 --- a/src/Kingsland.MofParser/Parsing/ParserQuirks.cs +++ b/src/Kingsland.MofParser/Parsing/ParserQuirks.cs @@ -33,7 +33,7 @@ public enum ParserQuirks AllowMofV2Qualifiers = 0x0001, /// - /// Allows fully qualified enum namedto be iused in enum array values, e.g. "{ MonthEnum.January, MonthEnum.April}" + /// Allows fully qualified enum named to be used in enum array values, e.g. "{ MonthEnum.January, MonthEnum.April}" /// /// /// diff --git a/src/Kingsland.MofParser/PowerShellDscHelper.cs b/src/Kingsland.MofParser/PowerShellDscHelper.cs index 988308f..b7664b2 100644 --- a/src/Kingsland.MofParser/PowerShellDscHelper.cs +++ b/src/Kingsland.MofParser/PowerShellDscHelper.cs @@ -1,5 +1,6 @@ using Kingsland.MofParser.Lexing; -using Kingsland.MofParser.Models; +using Kingsland.MofParser.Models.Converter; +using Kingsland.MofParser.Models.Types; using Kingsland.MofParser.Parsing; using Kingsland.ParseFx.Text; using System.Collections.ObjectModel;