Skip to content

Commit

Permalink
Successfully serialize a notification
Browse files Browse the repository at this point in the history
  • Loading branch information
carl-andersson-at-westermo committed May 30, 2024
1 parent 96d8867 commit fb48140
Show file tree
Hide file tree
Showing 20 changed files with 170 additions and 35 deletions.
3 changes: 2 additions & 1 deletion YangParser/SemanticModel/Action.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public override string ToCode()
await WriteXML(writer);
await writer.WriteEndElementAsync();
await writer.WriteEndElementAsync();
await writer.FlushAsync();
var xml = stringBuilder.ToString();
""");
builder.AppendLine(returnType != "Task"
Expand Down Expand Up @@ -135,7 +136,7 @@ public string WriteCall
return $$"""
if({{MakeName(Argument)}}InputValue is not null)
{
await writer.WriteStartElementAsync(null,"{{Source.Argument}}",null);
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Source.Argument}}",{{xmlNs}});
await {{MakeName(Argument)}}InputValue.WriteXML(writer);
await writer.WriteEndElementAsync();
}
Expand Down
3 changes: 1 addition & 2 deletions YangParser/SemanticModel/AnyData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ public string WriteCall
{
get
{
var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\"";
return $$"""
if({{TargetName}} != null)
{
await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null);
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync({{TargetName}});
await writer.WriteEndElementAsync();
}
Expand Down
5 changes: 2 additions & 3 deletions YangParser/SemanticModel/AnyXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,17 @@ public override string ToCode()
{
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.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync({{TargetName}});
await writer.WriteEndElementAsync();
}
Expand Down
5 changes: 5 additions & 0 deletions YangParser/SemanticModel/Builtins/Union.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public class {{name}}
{{Statement.Indent(string.Join("\n", types.Select(typeName => $"public static implicit operator {typeName}?({name}? input) => input is null ? null : input.{varName(typeName)} ?? throw new InvalidOperationException(\"Union was not of effective type '{typeName}'\");")))}}
{{Statement.Indent(string.Join("\n", types.Select(typeName => $"public static implicit operator {name}({typeName} input) => new {name}(input);")))}}
{{Statement.Indent(string.Join("\n", declarations))}}
public override string? ToString()
{
{{Statement.Indent(Statement.Indent(string.Join("\n", types.Select(typeName => $"if({varName(typeName)} is not null) return {varName(typeName)}.ToString();"))))}}
return string.Empty;
}
}
""";
return (name, definition);
Expand Down
10 changes: 5 additions & 5 deletions YangParser/SemanticModel/CompilationUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ public CompilationUnit(Module[] modules, string Namespace = "Somewhere") : base(
string.Empty, [],
new Metadata(string.Empty, new Parser.Position(), 0)))
{
this.Namespace = Namespace;
this.MyNamespace = Namespace;
Children = modules;
}

public string Namespace { get; set; }
public string MyNamespace { get; set; }

public override ChildRule[] PermittedChildren { get; } =
[
Expand All @@ -27,7 +27,7 @@ public override string ToCode()
var members = new List<string>();
foreach (var module in Children.OfType<Module>())
{
var typeName = module.Namespace.Substring(0, module.Namespace.Length - 1);
var typeName = module.MyNamespace.Substring(0, module.MyNamespace.Length - 1);
var memberName = MakeName(module.Argument);
members.Add($"public {typeName}? {memberName} {{ get; set; }}");
}
Expand All @@ -36,9 +36,9 @@ public override string ToCode()
using System;
using System.Xml;
using Yang.Attributes;
namespace {{Namespace}};
namespace {{MyNamespace}};
///<summary>
///Configuration root object for {{Namespace}} based on provided .yang modules
///Configuration root object for {{MyNamespace}} based on provided .yang modules
///</summary>{{AttributeString}}
public class Configuration
{
Expand Down
1 change: 1 addition & 0 deletions YangParser/SemanticModel/IStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public interface IStatement
string XPath { get; }
(string Namespace, string Prefix)? XmlNamespace { get; set; }
string Prefix { get; }
string Namespace { get; }
}

/// <summary>
Expand Down
36 changes: 31 additions & 5 deletions YangParser/SemanticModel/Leaf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using YangParser.Parser;
using YangParser.SemanticModel.Builtins;

namespace YangParser.SemanticModel;

Expand Down Expand Up @@ -82,14 +83,39 @@ public string WriteCall
{
get
{
var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\"";
if (Type.Argument is "enumeration" or "bits")
if (Type.GetBaseType(out var prefix) is "enumeration" or "bits")
{
if (string.IsNullOrEmpty(prefix))
{
if (BuiltinTypeReference.IsBuiltin(Type, out _, out _)) //Is direct subtype
{
return $$"""
if({{TargetName}} != default)
{
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync(GetEncodedValue({{TargetName}}!));
await writer.WriteEndElementAsync();
}
""";
}

//Is local reference.
return $$"""
if({{TargetName}} != default)
{
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync(YangNode.GetEncodedValue({{TargetName}}!));
await writer.WriteEndElementAsync();
}
""";
}
//Is imported reference
var p = prefix.Contains('.') ? prefix : prefix + ":";
return $$"""
if({{TargetName}} != default)
{
await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null);
await writer.WriteStringAsync(GetEncodedValue({{TargetName}}!));
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync({{p}}GetEncodedValue({{TargetName}}!));
await writer.WriteEndElementAsync();
}
""";
Expand All @@ -98,7 +124,7 @@ public string WriteCall
return $$"""
if({{TargetName}} != default)
{
await writer.WriteStartElementAsync({{pre}},"{{Argument}}",null);
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync({{TargetName}}!.ToString());
await writer.WriteEndElementAsync();
}
Expand Down
3 changes: 1 addition & 2 deletions YangParser/SemanticModel/LeafList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,12 @@ 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.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteStringAsync(element!.ToString());
await writer.WriteEndElementAsync();
}
Expand Down
1 change: 0 additions & 1 deletion YangParser/SemanticModel/List.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ public string WriteCall
{
get
{
var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\"";
return $$"""
if({{TargetName}} != null)
{
Expand Down
6 changes: 3 additions & 3 deletions YangParser/SemanticModel/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ public Module(YangStatement statement) : base(statement)
throw new SemanticError($"Non-matching Keyword '{statement.Keyword}', expected {Keyword}", statement);
var localPrefix = this.GetChild<Prefix>().Argument;
var localNS = MakeNamespace(Argument) + ".YangNode.";
XmlNamespace = (Children.First(child => child is Namespace).Argument, localPrefix);
XmlNamespace = (Children.First(child => child is Namespace).Argument, string.Empty);
Usings = new()
{
[localPrefix] = localNS
};
ImportedModules[localPrefix] = Argument;
Namespace = localNS;
MyNamespace = localNS;

foreach (var child in this.Unwrap())
{
Expand Down Expand Up @@ -72,7 +72,7 @@ public Module(YangStatement statement) : base(statement)

public Dictionary<string, string> ImportedModules { get; } = [];
public Dictionary<string, string> Usings { get; }
public string Namespace { get; private set; }
public string MyNamespace { get; private set; }

public override ChildRule[] PermittedChildren { get; } =
[
Expand Down
3 changes: 1 addition & 2 deletions YangParser/SemanticModel/Notification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ public async Task<string> ToXML()
await writer.WriteStartElementAsync(null,"eventTime",null);
await writer.WriteStringAsync(DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ"));
await writer.WriteEndElementAsync();
await writer.WriteStartElementAsync("{{XmlNamespace?.Prefix}}","{{Argument}}","{{XmlNamespace?.Namespace}}");
{{xmlWrite}}
await writer.WriteEndElementAsync();
await writer.WriteEndElementAsync();
await writer.FlushAsync();
return stringBuilder.ToString();
}
{{Indent(XmlFunction())}}
Expand Down
1 change: 1 addition & 0 deletions YangParser/SemanticModel/Rpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public override string ToCode()
builder.AppendLine($$"""
await writer.WriteEndElementAsync();
await writer.WriteEndElementAsync();
await writer.FlushAsync();
var xml = stringBuilder.ToString();
""");
builder.AppendLine(returnType != "Task"
Expand Down
17 changes: 9 additions & 8 deletions YangParser/SemanticModel/Statement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ namespace YangParser.SemanticModel;

public abstract class Statement : IStatement
{
protected string xmlPrefix => (string.IsNullOrWhiteSpace(Prefix) || string.IsNullOrWhiteSpace(Namespace))
? "null"
: $"\"{Prefix}\"";

protected string xmlNs => string.IsNullOrWhiteSpace(Namespace) ? "null" : $"\"{Namespace}\"";

protected string XmlFunction()
{
var ns = XmlNamespace?.Namespace;
ns = ns is null ? "null" : $"\"{ns}\"";
var pre = string.IsNullOrWhiteSpace(Prefix) ? "null" : $"\"{Prefix}\"";
var writeCalls = Children.OfType<IXMLSource>()
.Select(t => $"if({t.TargetName} is not null) await {t.TargetName}.WriteXML(writer);");
var elementCalls = Children.OfType<IXMLValue>()
.Select(t => t.WriteCall);
return $$"""
public async Task WriteXML(XmlWriter writer)
{
await writer.WriteStartElementAsync({{pre}},"{{Source.Argument}}",{{ns}});
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Source.Argument}}",{{xmlNs}});
{{Indent(string.Join("\n", elementCalls))}}
{{Indent(string.Join("\n", writeCalls))}}
await writer.WriteEndElementAsync();
Expand All @@ -33,9 +36,6 @@ 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<IXMLSource>()
.Select(t => $"if({t.TargetName} is not null) await {t.TargetName}.WriteXML(writer);").ToArray();
var elementCalls = Children.OfType<IXMLValue>()
Expand Down Expand Up @@ -74,6 +74,7 @@ protected Statement(YangStatement statement, bool validate = true)

public (string Namespace, string Prefix)? XmlNamespace { get; set; }
public string Prefix => XmlNamespace?.Prefix ?? Parent?.Prefix ?? string.Empty;
public string Namespace => XmlNamespace?.Namespace ?? Parent?.Namespace ?? string.Empty;
protected string XmlObjectName => (string.IsNullOrEmpty(Prefix) ? string.Empty : Prefix + ":") + Source.Argument;

public string XPath => ((Parent?.XPath ?? String.Empty) + "/").Replace("//", "/") +
Expand Down Expand Up @@ -184,7 +185,7 @@ public string AttributeString
{
get
{
Attributes.Add("XPath(@\"" + XPath + '"' + ')');
if (this is IXMLValue || this is IXMLSource) Attributes.Add("XPath(@\"" + XPath + '"' + ')');
return "\n" + string.Join("\n", Attributes.OrderBy(x => x.Length).Select(attr => $"[{attr}]"));
}
}
Expand Down
29 changes: 27 additions & 2 deletions YangParser/SemanticModel/StatementExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Text;
using YangParser.Generator;
using YangParser.SemanticModel.Builtins;

namespace YangParser.SemanticModel;

Expand Down Expand Up @@ -151,7 +152,7 @@ private static Grouping GetGrouping(this Uses use)
}
else
{
var source = use.Root().Children.OfType<Module>().FirstOrDefault(m => m.Namespace == prefix) ??
var source = use.Root().Children.OfType<Module>().FirstOrDefault(m => m.MyNamespace == prefix) ??
throw new SemanticError($"Could not find a module with the key {prefix}", use.Source);
var grouping = use.FindGrouping(source) ?? throw new SemanticError(
$"Could not find a grouping statement to use for 'uses {use.Argument}' in module '{source.Argument}' from prefix '{prefix}'",
Expand Down Expand Up @@ -257,7 +258,7 @@ public static string Prefix(this string argument, out string name)
}
else
{
var module = source.Root().Children.OfType<Module>().FirstOrDefault(m => m.Namespace == prefix);
var module = source.Root().Children.OfType<Module>().FirstOrDefault(m => m.MyNamespace == prefix);
if (module is null)
{
Log.Write(
Expand Down Expand Up @@ -318,4 +319,28 @@ public static string Prefix(this string argument, out string name)
if (result is not null) return result;
return source.Parent.SearchUpwards<T>(argument);
}

public static string GetBaseType(this Type type, out string prefix)
{
prefix = string.Empty;
while (true)
{
if (BuiltinTypeReference.IsBuiltin(type, out _, out _))
{
_ = type.Argument.Prefix(out var arg);
return arg;
}

var newPrefix = type.Argument.Prefix(out _);
if (!string.IsNullOrEmpty(newPrefix)) prefix = newPrefix;

var source = type.FindReference<TypeDefinition>(type.Argument);
if (source is null)
{
throw new SemanticError($"Could not find source for type definition {type.Argument}", type.Source);
}

type = source.GetChild<Type>();
}
}
}
20 changes: 20 additions & 0 deletions YangSourceTests/BfdIpMhTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Ietf.Inet.Types;
using Xunit.Abstractions;

namespace YangSourceTests;

public class BfdIpMhTests(ITestOutputHelper output)
{
[Fact]
public async Task NotificationSerializationTest()
{
var notification = new Ietf.Bfd.Ip.Mh.YangNode.MultihopNotification
{
DestAddr = new YangNode.IpAddress(new YangNode.Ipv4Address("192.168.0.1")),
NewState = Ietf.Bfd.Types.YangNode.State.AdminDown
};
var result = await notification.ToXML();
output.WriteLine(result);

}
}
27 changes: 27 additions & 0 deletions YangSourceTests/YangSourceTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
</ItemGroup>

<ItemGroup>
<Using Include="Xunit"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TestData\YangSource\YangSource.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit fb48140

Please sign in to comment.