diff --git a/YangParser/SemanticModel/Builtins/Binary.cs b/YangParser/SemanticModel/Builtins/Binary.cs index 4857663..f261d11 100644 --- a/YangParser/SemanticModel/Builtins/Binary.cs +++ b/YangParser/SemanticModel/Builtins/Binary.cs @@ -1,3 +1,3 @@ namespace YangParser.SemanticModel.Builtins; -public class Binary() : BuiltinType("binary", (_) => ("byte[]", null)); \ No newline at end of file +public class Binary() : BuiltinType("binary", _ => ("byte[]", null)); \ No newline at end of file diff --git a/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs b/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs index 8c4cc3e..3c86493 100644 --- a/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs +++ b/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs @@ -43,6 +43,7 @@ public static bool IsBuiltin(Type type, out string? cSharpType, out string? defi return false; } + public static bool IsBuiltinKeyword(string keyword) { return m_builtIns.Any(b => b.Name == keyword); @@ -58,17 +59,21 @@ public class {{typeName}} { {{Statement.Indent(string.Join("\n", staticFields))}} public {{baseTypeName}} WrittenValue { get; } - public static implicit operator {{baseTypeName}}({{typeName}} input) => input.WrittenValue; + public static implicit operator {{baseTypeName}}?({{typeName}}? input) => input?.WrittenValue; public static implicit operator {{typeName}}({{baseTypeName}} input) => new {{typeName}}(input); public {{typeName}}({{baseTypeName}} input) { {{Statement.Indent(Statement.Indent(string.Join("\n", constructorStatements)))}} WrittenValue = input; } - + public override string ToString() + { + return WrittenValue.ToString(); + } } """; } + public static string TypeName(IStatement type) { string Postfix = string.Empty; @@ -78,6 +83,7 @@ public static string TypeName(IStatement type) Postfix += Array.IndexOf(parent.Children, type); parent = parent.Parent!; } + return Statement.MakeName(parent.Argument) + Postfix; } } \ No newline at end of file diff --git a/YangParser/SemanticModel/Container.cs b/YangParser/SemanticModel/Container.cs index 498c0e3..1d27982 100644 --- a/YangParser/SemanticModel/Container.cs +++ b/YangParser/SemanticModel/Container.cs @@ -5,7 +5,7 @@ namespace YangParser.SemanticModel; -public class Container : Statement, IClassSource +public class Container : Statement, IClassSource, IXMLSource { public List Comments { get; } = new(); @@ -62,6 +62,8 @@ public override string ToCode() name = "sub-" + name; } + TargetName = MakeName(name); + string property = $"public{KeywordString}{MakeName(name)}Container? {MakeName(name)} {{ get; set; }}"; return $$""" {{property}} @@ -69,7 +71,10 @@ public override string ToCode() public class {{MakeName(name)}}Container { {{string.Join("\n\t", nodes.Select(Indent))}} + {{Indent(XmlFunction())}} } """; } + + public string TargetName { get; private set; } } \ No newline at end of file diff --git a/YangParser/SemanticModel/IStatement.cs b/YangParser/SemanticModel/IStatement.cs index e2b73de..0b5d42b 100644 --- a/YangParser/SemanticModel/IStatement.cs +++ b/YangParser/SemanticModel/IStatement.cs @@ -23,6 +23,22 @@ public interface IStatement string Prefix { get; } } +/// +/// Implies this class makes an XElement with potential children +/// +public interface IXMLSource : IStatement +{ + string TargetName { get; } +} +/// +/// Implies this class makes a singular XElement with no children, and may not have a method +/// +public interface IXMLValue : IStatement +{ + string TargetName { get; } + string WriteCall { get; } +} + public interface ICommentable : IStatement { List Comments { get; } diff --git a/YangParser/SemanticModel/Leaf.cs b/YangParser/SemanticModel/Leaf.cs index 842a26d..327e88b 100644 --- a/YangParser/SemanticModel/Leaf.cs +++ b/YangParser/SemanticModel/Leaf.cs @@ -6,7 +6,7 @@ namespace YangParser.SemanticModel; -public class Leaf : Statement +public class Leaf : Statement, IXMLValue { public override ChildRule[] PermittedChildren { get; } = [ @@ -66,6 +66,8 @@ public override string ToCode() name += "Value"; } + TargetName = name; + return $$""" {{DescriptionString}}{{AttributeString}} public{{KeywordString}}{{typeName}}{{nullable}} {{name}} { get; set; } {{defaulting}} @@ -73,4 +75,22 @@ public override string ToCode() {{Default?.Addendum}} """; } + + public string TargetName { get; private set; } + + public string WriteCall + { + get + { + var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\""; + return $$""" + if({{TargetName}} != default) + { + await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null); + await writer.WriteStringAsync({{TargetName}}!.ToString()); + await writer.WriteEndElementAsync(); + } + """; + } + } } \ No newline at end of file diff --git a/YangParser/SemanticModel/LeafList.cs b/YangParser/SemanticModel/LeafList.cs index 38fd50d..735de3c 100644 --- a/YangParser/SemanticModel/LeafList.cs +++ b/YangParser/SemanticModel/LeafList.cs @@ -5,7 +5,7 @@ namespace YangParser.SemanticModel; -public class LeafList : Statement +public class LeafList : Statement, IXMLValue { public override ChildRule[] PermittedChildren { get; } = [ @@ -57,6 +57,8 @@ public override string ToCode() name += "Value"; } + TargetName = name + "List"; + return $$""" {{addendum}} {{DescriptionString}}{{AttributeString}} @@ -65,4 +67,25 @@ public override string ToCode() {{Default?.Addendum}} """; } + + public string TargetName { get; private set; } + + public string WriteCall + { + get + { + var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\""; + return $$""" + if({{TargetName}} != null) + { + foreach(var element in {{TargetName}}) + { + await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null); + await writer.WriteStringAsync(element!.ToString()); + await writer.WriteEndElementAsync(); + } + } + """; + } + } } \ No newline at end of file diff --git a/YangParser/SemanticModel/Module.cs b/YangParser/SemanticModel/Module.cs index 49fb196..a08f409 100644 --- a/YangParser/SemanticModel/Module.cs +++ b/YangParser/SemanticModel/Module.cs @@ -108,6 +108,7 @@ public override string ToCode() var extraDefinitions = HiddenDefinitions.Select(t => Indent(t.ToCode())).ToArray(); var raw = $$""" using System; + using System.Xml; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Xml.Linq; diff --git a/YangParser/SemanticModel/Statement.cs b/YangParser/SemanticModel/Statement.cs index 6a6e630..7018c68 100644 --- a/YangParser/SemanticModel/Statement.cs +++ b/YangParser/SemanticModel/Statement.cs @@ -11,6 +11,26 @@ namespace YangParser.SemanticModel; public abstract class Statement : IStatement { + protected string XmlFunction() + { + 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);"); + var elementCalls = Children.OfType() + .Select(t => t.WriteCall); + return $$""" + public async Task WriteXML(XmlWriter writer) + { + await writer.WriteStartElementAsync({{pre}},"{{Source.Argument}}",{{ns}}); + {{Indent(string.Join("\n", elementCalls))}} + {{Indent(string.Join("\n", writeCalls))}} + await writer.WriteEndElementAsync(); + } + """; + } + protected Statement(YangStatement statement, bool validate = true) { Argument = statement.Argument?.ToString() ?? string.Empty; @@ -26,9 +46,10 @@ protected Statement(YangStatement statement, bool validate = true) public (string Namespace, string Prefix)? XmlNamespace { get; set; } public string Prefix => XmlNamespace?.Prefix ?? Parent?.Prefix ?? string.Empty; + protected string XmlObjectName => (string.IsNullOrEmpty(Prefix) ? string.Empty : Prefix + ":") + Source.Argument; public string XPath => ((Parent?.XPath ?? String.Empty) + "/").Replace("//", "/") + - (string.IsNullOrEmpty(Prefix) ? string.Empty : Prefix + ":") + Source.Argument; + XmlObjectName; public YangStatement Source { get; set; }