diff --git a/YangParser/SemanticModel/Action.cs b/YangParser/SemanticModel/Action.cs index 13e2a5e..397fab2 100644 --- a/YangParser/SemanticModel/Action.cs +++ b/YangParser/SemanticModel/Action.cs @@ -5,7 +5,7 @@ namespace YangParser.SemanticModel; -public class Action : Statement +public class Action : Statement, IXMLValue { public Action(YangStatement statement) : base(statement) { @@ -35,29 +35,58 @@ public Action(YangStatement statement) : base(statement) public override string ToCode() { + //TODO: REWORK StringBuilder builder = new(); builder.AppendLine(DescriptionString); builder.AppendLine(AttributeString); - var returnType = Outgoing is null ? "void" : MakeName(Argument) + "Output"; + var outputType = MakeName(Argument) + "Output"; + var returnType = Outgoing is null ? "Task" : "Task<" + outputType + ">"; var inputType = Ingoing is null ? string.Empty : ", " + MakeName(Argument) + "Input input"; builder.AppendLine( - $"public static {returnType} {MakeName(Argument)}(IChannel channel, int messageID{inputType})"); - builder.AppendLine("{"); - var ns = Parent is Module module ? $"xmlns:{module.XmlNamespace?.Prefix}=\\\"" + module.XmlNamespace?.Namespace + "\\\"" : string.Empty; - builder.AppendLine(inputType != string.Empty - ? $$""" - var xml = $"<{{Argument}} {{ns}}>{input.ToXML()}"; - """ - : $$""" - var xml = $"<{{Argument}} {{ns}}/>"; - """); - - builder.AppendLine(returnType != "void" + $"public async {returnType} {MakeName(Argument)}(IChannel channel, int messageID{inputType})"); + builder.AppendLine(""" + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Indent = true; + settings.OmitXmlDeclaration = true; + settings.NewLineOnAttributes = true; + StringBuilder stringBuilder = new StringBuilder(); + using XmlWriter writer = XmlWriter.Create(stringBuilder, settings); + await writer.WriteStartElementAsync(null,"rpc","urn:ietf:params:xml:ns:netconf:base:1.0"); + await writer.WriteAttributeStringAsync(null,"message-id",null,messageID.ToString()); + await writer.WriteStartElementAsync(null,"action","urn:ietf:params:xml:ns:yang:1"); + """); + if (Ingoing is not null) + { + builder.AppendLine($"\tthis.{MakeName(Argument)}InputValue = input;"); + } + else + { + builder.AppendLine($"\tthis.{MakeName(Argument)}Active = true;"); + } + + builder.AppendLine(""" + await WriteXML(writer); + await writer.WriteEndElementAsync(); + await writer.WriteEndElementAsync(); + var xml = stringBuilder.ToString(); + """); + builder.AppendLine(returnType != "Task" ? "\tvar response = channel.Send(xml);" : "\tchannel.Send(xml);"); - if (returnType != "void") + if (Ingoing is not null) + { + builder.AppendLine($"\tthis.{MakeName(Argument)}InputValue = null;"); + } + else + { + + builder.AppendLine($"\tthis.{MakeName(Argument)}Active = false;"); + } + + if (returnType != "Task") { - builder.AppendLine($"\treturn {returnType}.Parse(response);"); + builder.AppendLine($"\treturn {outputType}.Parse(response);"); } builder.AppendLine("}"); @@ -69,6 +98,11 @@ public override string ToCode() if (Ingoing is not null) { builder.AppendLine(Ingoing.ToCode()); + builder.AppendLine($"private {MakeName(Argument)}Input? {MakeName(Argument)}InputValue {{ get; set; }}"); + } + else + { + builder.AppendLine($"private bool {MakeName(Argument)}Active {{ get; set; }}"); } return builder.ToString(); @@ -88,4 +122,32 @@ protected override void ValidateParent() parent = parent.Parent; } } + + public string TargetName => MakeName(Argument); + + public string WriteCall + { + get + { + if (Ingoing is not null) + { + return $$""" + if({{MakeName(Argument)}}InputValue is not null) + { + await writer.WriteStartElementAsync(null,"{{Source.Argument}}",null); + await {{MakeName(Argument)}}InputValue.WriteXML(writer); + await writer.WriteEndElementAsync(); + } + """; + } + + return $$""" + if({{MakeName(Argument)}}Active) + { + await writer.WriteStartElementAsync(null,"{Source.Argument}",null); + await writer.WriteEndElementAsync(); + } + """; + } + } } \ No newline at end of file diff --git a/YangParser/SemanticModel/AnyData.cs b/YangParser/SemanticModel/AnyData.cs index ecd10fc..6238e76 100644 --- a/YangParser/SemanticModel/AnyData.cs +++ b/YangParser/SemanticModel/AnyData.cs @@ -2,7 +2,7 @@ namespace YangParser.SemanticModel; -public class AnyData : Statement +public class AnyData : Statement, IXMLValue { public AnyData(YangStatement statement) : base(statement) { @@ -26,6 +26,24 @@ public AnyData(YangStatement statement) : base(statement) public override string ToCode() { - return "public string? Data { get; }"; + return $"public string? {TargetName} {{ get; set; }}"; + } + + public string TargetName => MakeName(Argument); + + public string WriteCall + { + get + { + var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\""; + return $$""" + if({{TargetName}} != null) + { + await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null); + await writer.WriteStringAsync({{TargetName}}); + await writer.WriteEndElementAsync(); + } + """; + } } } \ No newline at end of file diff --git a/YangParser/SemanticModel/AnyXml.cs b/YangParser/SemanticModel/AnyXml.cs index de41c16..a072b41 100644 --- a/YangParser/SemanticModel/AnyXml.cs +++ b/YangParser/SemanticModel/AnyXml.cs @@ -28,6 +28,24 @@ public AnyXml(YangStatement statement) : base(statement) public override string ToCode() { - return "public string? XML { get; }"; + return $"public string? {TargetName} {{ get; set; }}"; + } + + public string TargetName => MakeName(Argument); + + public string WriteCall + { + get + { + var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\""; + return $$""" + if({{TargetName}} != null) + { + await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null); + await writer.WriteStringAsync({{TargetName}}); + await writer.WriteEndElementAsync(); + } + """; + } } } \ No newline at end of file diff --git a/YangParser/SemanticModel/Builtins/IdentityReference.cs b/YangParser/SemanticModel/Builtins/IdentityReference.cs index 4a42c74..751a9b3 100644 --- a/YangParser/SemanticModel/Builtins/IdentityReference.cs +++ b/YangParser/SemanticModel/Builtins/IdentityReference.cs @@ -8,15 +8,16 @@ public class IdentityReference() : BuiltinType("identityref", statement => var inherits = statement.Children.OfType().Select(x => '"' + x.Argument + '"').ToArray(); var name = BuiltinTypeReference.TypeName(statement); var definition = $$""" - {{statement.DescriptionString}}{{statement.AttributeString}} - public class {{name}} - { - public string Identity { get; } - public static string[] Bases = [{{string.Join(", ", inherits)}}]; - public {{name}}(string input) => Identity = input; - public static implicit operator string?({{name}}? input) => input?.Identity; - public static implicit operator {{name}}(string input) => new(input); - } - """; + {{statement.DescriptionString}}{{statement.AttributeString}} + public class {{name}} + { + public string Identity { get; } + public static string[] Bases = [{{string.Join(", ", inherits)}}]; + public {{name}}(string input) => Identity = input; + public static implicit operator string?({{name}}? input) => input?.Identity; + public static implicit operator {{name}}(string input) => new(input); + public override string ToString() => Identity; + } + """; return (name, definition); }); \ No newline at end of file diff --git a/YangParser/SemanticModel/Case.cs b/YangParser/SemanticModel/Case.cs index 14f3458..e2b99c8 100644 --- a/YangParser/SemanticModel/Case.cs +++ b/YangParser/SemanticModel/Case.cs @@ -70,7 +70,7 @@ namespace YangParser.SemanticModel; /// | when | 7.19.5 | 0..1 | /// +--------------+---------+-------------+ /// -public class Case : Statement, IClassSource +public class Case : Statement, IClassSource, IXMLSource { public List Comments { get; } = new(); @@ -102,18 +102,20 @@ public Case(YangStatement statement) : base(statement) public override string ToCode() { var nodes = Children.Select(c => c.ToCode()).ToArray(); - return $$""" - public {{MakeName(Parent!.Argument)}}Choice({{MakeName(Argument)}}Case input) + public {{MakeName(Parent!.Argument)}}Choice({{TargetName}}Case input) { - {{MakeName(Argument)}} = input; + {{TargetName}} = input; } - public {{MakeName(Argument)}}Case? {{MakeName(Argument)}}; + public {{TargetName}}Case? {{TargetName}}; {{DescriptionString}}{{AttributeString}} - public class {{MakeName(Argument)}}Case + public class {{TargetName}}Case { {{Indent(string.Join("\n", nodes))}} + {{Indent(XmlFunctionWithInvisibleSelf())}} } """; } + + public string TargetName => MakeName(Argument); } \ No newline at end of file diff --git a/YangParser/SemanticModel/Choice.cs b/YangParser/SemanticModel/Choice.cs index 4bfd710..6d7dd8c 100644 --- a/YangParser/SemanticModel/Choice.cs +++ b/YangParser/SemanticModel/Choice.cs @@ -5,7 +5,7 @@ namespace YangParser.SemanticModel; -public class Choice : Statement, IClassSource +public class Choice : Statement, IClassSource, IXMLSource { private readonly YangStatement m_source; @@ -43,16 +43,17 @@ public Choice(YangStatement statement) : base(statement) public override string ToCode() { var nodes = Children.Where(t => t is not DefaultValue).Select(child => child.ToCode()).ToArray(); - string property = Parent is Module - ? string.Empty - : $"public{KeywordString}{MakeName(Argument)}Choice? {MakeName(Argument)} {{ get; set; }}"; + string property = $"public{KeywordString}{MakeName(Argument)}Choice? {MakeName(Argument)} {{ get; set; }}"; return $$""" {{property}} {{DescriptionString}}{{AttributeString}} public class {{MakeName(Argument)}}Choice { {{string.Join("\n\t", nodes.Select(Indent))}} + {{Indent(XmlFunctionWithInvisibleSelf())}} } """; } + + public string TargetName => MakeName(Argument); } \ No newline at end of file diff --git a/YangParser/SemanticModel/Input.cs b/YangParser/SemanticModel/Input.cs index a65e1dc..293518d 100644 --- a/YangParser/SemanticModel/Input.cs +++ b/YangParser/SemanticModel/Input.cs @@ -34,10 +34,11 @@ public Input(YangStatement statement) : base(statement) public override string ToCode() { return $$""" - public class {{MakeName(Parent!.Argument)}}Input : IXMLSource + public class {{MakeName(Parent!.Argument)}}Input { {{string.Join("\n\t", Children.Select(child => Indent(child.ToCode())))}} - public string ToXML() => string.Empty; //TODO + {{Indent(XmlFunction())}} + } """; } diff --git a/YangParser/SemanticModel/List.cs b/YangParser/SemanticModel/List.cs index 658c930..edcb634 100644 --- a/YangParser/SemanticModel/List.cs +++ b/YangParser/SemanticModel/List.cs @@ -53,9 +53,8 @@ public List(YangStatement statement) : base(statement) public override string ToCode() { var nodes = Children.Select(child => child.ToCode()).ToArray(); - TargetName = MakeName(Argument); string property = - $"\n{DescriptionString}\npublic{KeywordString}List<{MakeName(Argument)}Entry> {MakeName(Argument)} {{ get; }} = new();"; + $"\n{DescriptionString}\npublic{KeywordString}List<{MakeName(Argument)}Entry> {TargetName} {{ get; }} = new();"; return $$""" {{property}} {{AttributeString}} @@ -67,7 +66,7 @@ public class {{MakeName(Argument)}}Entry """; } - public string TargetName { get; private set; } + public string TargetName => MakeName(Argument); public string WriteCall { diff --git a/YangParser/SemanticModel/Module.cs b/YangParser/SemanticModel/Module.cs index 7ddcd4b..f493f25 100644 --- a/YangParser/SemanticModel/Module.cs +++ b/YangParser/SemanticModel/Module.cs @@ -116,6 +116,7 @@ public override string ToCode() var raw = $$""" using System; using System.Xml; + using System.Text; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Xml.Linq; diff --git a/YangParser/SemanticModel/Rpc.cs b/YangParser/SemanticModel/Rpc.cs index 1238671..3e9eee1 100644 --- a/YangParser/SemanticModel/Rpc.cs +++ b/YangParser/SemanticModel/Rpc.cs @@ -49,26 +49,41 @@ public override string ToCode() StringBuilder builder = new(); builder.AppendLine(DescriptionString); builder.AppendLine(AttributeString); - var returnType = Outgoing is null ? "void" : MakeName(Argument) + "Output"; + var outputType = MakeName(Argument) + "Output"; + var returnType = Outgoing is null ? "Task" : "Task<" + outputType + ">"; var inputType = Ingoing is null ? string.Empty : ", " + MakeName(Argument) + "Input input"; builder.AppendLine( - $"public static {returnType} {MakeName(Argument)}(IChannel channel, int messageID{inputType})"); - builder.AppendLine("{"); - var ns = Parent is Module module ? $"xmlns:{module.XmlNamespace?.Prefix}=\\\"" + module.XmlNamespace?.Namespace + "\\\"" : string.Empty; - builder.AppendLine(inputType != string.Empty - ? $$""" - var xml = $"<{{Argument}} {{ns}}>{input.ToXML()}"; - """ - : $$""" - var xml = $"<{{Argument}} {{ns}}/>"; - """); + $"public static async {returnType} {MakeName(Argument)}(IChannel channel, int messageID{inputType})"); + builder.AppendLine($$""" + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Indent = true; + settings.OmitXmlDeclaration = true; + settings.NewLineOnAttributes = true; + StringBuilder stringBuilder = new StringBuilder(); + using XmlWriter writer = XmlWriter.Create(stringBuilder, settings); + await writer.WriteStartElementAsync(null,"rpc","urn:ietf:params:xml:ns:netconf:base:1.0"); + await writer.WriteAttributeStringAsync(null,"message-id",null,messageID.ToString()); + await writer.WriteStartElementAsync("{{XmlNamespace?.Prefix}}","{{Argument}}","{{XmlNamespace?.Namespace}}"); - builder.AppendLine(returnType != "void" + """); + var ns = $"xmlns:{XmlNamespace?.Prefix}=\\\"" + XmlNamespace?.Namespace + "\\\""; + if (inputType != string.Empty) + { + builder.AppendLine("\tawait input.WriteXML(writer);"); + } + + builder.AppendLine($$""" + await writer.WriteEndElementAsync(); + await writer.WriteEndElementAsync(); + var xml = stringBuilder.ToString(); + """); + builder.AppendLine(returnType != "Task" ? "\tvar response = channel.Send(xml);" : "\tchannel.Send(xml);"); - if (returnType != "void") + if (returnType != "Task") { - builder.AppendLine($"\treturn {returnType}.Parse(response);"); + builder.AppendLine($"\treturn {outputType}.Parse(response);"); } builder.AppendLine("}"); diff --git a/YangParser/SemanticModel/Statement.cs b/YangParser/SemanticModel/Statement.cs index 7018c68..5811207 100644 --- a/YangParser/SemanticModel/Statement.cs +++ b/YangParser/SemanticModel/Statement.cs @@ -31,6 +31,34 @@ public async Task WriteXML(XmlWriter writer) """; } + protected string XmlFunctionWithInvisibleSelf() + { + var ns = XmlNamespace?.Namespace; + ns = ns is null ? "null" : $"\"{ns}\""; + var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\""; + var writeCalls = Children.OfType() + .Select(t => $"if({t.TargetName} is not null) await {t.TargetName}.WriteXML(writer);").ToArray(); + var elementCalls = Children.OfType() + .Select(t => t.WriteCall).ToArray(); + if (elementCalls.Length == 0 && writeCalls.Length == 0) + { + return """ + public async Task WriteXML(XmlWriter writer) + { + await writer.FlushAsync(); + } + """; + } + + return $$""" + public async Task WriteXML(XmlWriter writer) + { + {{Indent(string.Join("\n", elementCalls))}} + {{Indent(string.Join("\n", writeCalls))}} + } + """; + } + protected Statement(YangStatement statement, bool validate = true) { Argument = statement.Argument?.ToString() ?? string.Empty;