Skip to content

Commit

Permalink
More proper implementation of 'leafref'
Browse files Browse the repository at this point in the history
  • Loading branch information
carl-andersson-at-westermo committed Jun 18, 2024
1 parent 10cc7aa commit 6bdae8a
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 71 deletions.
37 changes: 13 additions & 24 deletions YangSourceTests/RpcTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ public class RpcTests(ITestOutputHelper outputHelper)
{
private class TestChannel : IChannel, IAsyncDisposable
{
public string? LastXML => Encoding.UTF8.GetString(((MemoryStream)WriteStream).GetBuffer()).Replace("\0", "");
public string? LastWritten => Encoding.UTF8.GetString(((MemoryStream)ReadStream).GetBuffer()).Replace("\0", "");
private ExampleYangServer server = new();
public string LastXML => Encoding.UTF8.GetString(((MemoryStream)WriteStream).GetBuffer()).Replace("\0", "");
public string LastWritten => Encoding.UTF8.GetString(((MemoryStream)ReadStream).GetBuffer()).Replace("\0", "");
private readonly ExampleYangServer server = new();

public async Task Send()
{
Expand All @@ -24,8 +24,8 @@ public async Task Send()
(LastReadIndex, WriteStream.Position) = (WriteStream.Position, LastReadIndex);
}

private long LastSentIndex = 0;
private long LastReadIndex = 0;
private long LastSentIndex;
private long LastReadIndex;
public Stream WriteStream { get; } = new MemoryStream();
public Stream ReadStream { get; } = new MemoryStream();

Expand All @@ -49,8 +49,8 @@ public async Task RpcSend()
var reply = await Ietf.Connection.Oriented.Oam.YangNode.Traceroute(channel, 1,
new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput
{
MaNameStringValue = new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput.MaNameString(),
MdNameStringValue = new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput.MdNameString(),
MaNameString = "MA",
MdNameString = "MD",
Ttl = 2,
Count = 4,
Interval = 6,
Expand All @@ -65,7 +65,6 @@ public async Task RpcSend()
}
}
},
SourceMepValue = new(),
CommandSubType = Ietf.Connection.Oriented.Oam.YangNode.CommandSubTypeIdentity.Proactive
});
outputHelper.WriteLine(channel.LastXML);
Expand All @@ -81,11 +80,11 @@ public async Task RpcSend()
var replyString = Encoding.UTF8.GetString(ms.GetBuffer());
Assert.Equal(channel.LastWritten, replyString);

reply = await Ietf.Connection.Oriented.Oam.YangNode.Traceroute(channel, 2,
await Ietf.Connection.Oriented.Oam.YangNode.Traceroute(channel, 2,
new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput
{
MaNameStringValue = new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput.MaNameString(),
MdNameStringValue = new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput.MdNameString(),
MaNameString = "Ma",
MdNameString = "Md",
Ttl = 2,
Count = 4,
Interval = 6,
Expand All @@ -100,17 +99,9 @@ public async Task RpcSend()
}
}
},
SourceMepValue = new(),
SourceMep = "Meppy",
CommandSubType = Ietf.Connection.Oriented.Oam.YangNode.CommandSubTypeIdentity.Proactive
});
// Assert.Equal(
// reply.Response![0].Mip!.MipAddress!.IpAddressCaseValue!.IpAddress!.Ipv4AddressValue!
// .WrittenValue,
// output.Response![0].Mip!.MipAddress!.IpAddressCaseValue!.IpAddress!.Ipv4AddressValue!
// .WrittenValue);
// Assert.Equal(
// reply.Response![1].Ttl,
// output.Response![1].Ttl);
}

private static readonly Ietf.Alarms.YangNode.AlarmsContainer root = new()
Expand Down Expand Up @@ -221,7 +212,7 @@ public async Task ExceptionThrowingTest()
await using var channel = new TestChannel();
try
{
var result = await Ietf.Subscribed.Notifications.YangNode.EstablishSubscription(channel,
await Ietf.Subscribed.Notifications.YangNode.EstablishSubscription(channel,
Random.Shared.Next(),
new Ietf.Subscribed.Notifications.YangNode.EstablishSubscriptionInput
{
Expand All @@ -240,9 +231,7 @@ public async Task ExceptionThrowingTest()
EstablishSubscriptionInput.TargetChoice.StreamCaseValueCase.
StreamFilterChoice.ByReferenceCaseValueCase()
{
StreamFilterName =
new Ietf.Subscribed.Notifications.YangNode.
StreamFilterRef()
StreamFilterName = "FilteryMacFilter"
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public class ParsingBenchmarks
private static readonly Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput input =
new()
{
MaNameStringValue = new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput.MaNameString(),
MdNameStringValue = new Ietf.Connection.Oriented.Oam.YangNode.TracerouteInput.MdNameString(),
MaNameString = "Mama String",
MdNameString = "Maddy String",
Ttl = 2,
Count = 4,
Interval = 6,
Expand All @@ -44,7 +44,7 @@ public class ParsingBenchmarks
}
}
},
SourceMepValue = new(),
SourceMep = "Meppity",
CommandSubType = Ietf.Connection.Oriented.Oam.YangNode.CommandSubTypeIdentity.Proactive
};

Expand Down
16 changes: 15 additions & 1 deletion dotnetYang/SemanticModel/Augment.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using YangParser.Generator;
using YangParser.Parser;
using YangParser.SemanticModel.Builtins;

Expand Down Expand Up @@ -186,8 +187,21 @@ private void PrepareTransitionTo(IStatement top)

continue;
}
if(type.Argument.Contains("leafref")){
var path = type.GetChild<Path>();
var value = path.Argument;
var components = value.Split('/');
var index = value.StartsWith("/") ? 1 : 0;
var prefix = components[index].Prefix(out var component);
if (string.IsNullOrWhiteSpace(prefix))
{
components[index] = this.GetInheritedPrefix() + ":" + components[index];
}

path.Argument = string.Join("/", components);
}

if (BuiltinTypeReference.IsBuiltin(type, out _, out _))
if (BuiltinTypeReference.IsBuiltinKeyword(type.Argument))
{
continue;
}
Expand Down
28 changes: 5 additions & 23 deletions dotnetYang/SemanticModel/Builtins/BuiltinTypeReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public static bool IsBuiltin(Type type, out string? cSharpType, out string? defi

public static bool IsBuiltinKeyword(string keyword)
{
return m_builtIns.Any(b => b.Name == keyword);
keyword.Prefix(out var name);
return m_builtIns.Any(b => b.Name == name);
}

public static string Stringification(Type type, string targetName)
Expand Down Expand Up @@ -85,14 +86,6 @@ public static string DefaultPattern(IStatement statement, IEnumerable<string> st
}
""";
break;
case "leafref":
parseFunction = $$"""
public static {{typeName}} Parse(string value)
{
return new {{typeName}}(new {{baseTypeName}}());
}
""";
break;
case "bits":
case "enumeration":
case "identityref":
Expand Down Expand Up @@ -198,15 +191,6 @@ public static string ValueTransformation(Type type, string typeName, string targ
""";
}

if (type.Argument == "leafref")
{
return $"""
{GetText(argument)}
{target} = new {typeName}();
{EndElement(argument)}
""";
}

var baseType = type.GetBaseType(out var prefix, out var chosenType);
switch (baseType)
{
Expand All @@ -231,7 +215,7 @@ public static string ValueTransformation(Type type, string typeName, string targ
if (string.IsNullOrEmpty(prefix))
{
//Is local reference.
return IsBuiltin(type, out _, out _)
return IsBuiltinKeyword(type.Argument)
? //Is direct subtype
$"""
{GetText(argument)}
Expand Down Expand Up @@ -274,7 +258,7 @@ public static string ValueParsing(Type type, string typeName)
{
if (typeName == "string")
{
return $"return value;";
return "return value;";
}

var baseType = type.GetBaseType(out var prefix, out var chosen);
Expand All @@ -284,8 +268,6 @@ public static string ValueParsing(Type type, string typeName)
return $"return {typeName}.Parse(value);";
case "empty":
return "if(string.IsNullOrWhiteSpace(value)) return new object();";
case "leafref":
return $"if(string.IsNullOrWhiteSpace(value)) return new {typeName}();";
case "bits":
case "enumeration":
case "identityref":
Expand All @@ -295,7 +277,7 @@ public static string ValueParsing(Type type, string typeName)
if (string.IsNullOrEmpty(prefix))
{
//Is local reference.
return IsBuiltin(type, out _, out _)
return IsBuiltinKeyword(type.Argument)
? //Is direct subtype
$"return Get{local}Value(value);"
: $"return YangNode.Get{local}Value(value);";
Expand Down
56 changes: 46 additions & 10 deletions dotnetYang/SemanticModel/Builtins/LeafReference.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace YangParser.SemanticModel.Builtins;

public class LeafReference() : BuiltinType("leafref", (statement) =>
{
var path = (Path)statement.Children.First(c => c is Path);
var name = BuiltinTypeReference.TypeName(statement);
var definition = $$"""
{{statement.DescriptionString}}{{statement.AttributeString}}
public class {{name}}() : InstanceIdentifier("{{path.Argument}}")
{
public new static {{name}} Parse(string value) => new();
}
""";
return (name, definition);
var target = statement.Parent.Navigate(path.Argument);
var prefix = path.Argument.Split('/').Last().Prefix(out _);
var assignation = prefix.Contains('.') ? prefix : prefix + ":";
if (statement.FindSourceFor(prefix) == target.GetModule())
{
prefix = string.Empty;
assignation = string.Empty;
}

var type = target!.GetChild<Type>();
var bname = target switch
{
IXMLReadValue rw => rw.ClassName,
IXMLParseable ps => ps.ClassName,
_ => "string"
};
if (bname.Contains(":") || bname.Contains("."))
{
var p = bname.Prefix(out _);
if (bname.Contains(":") && !statement.GetModule()!.Usings.ContainsKey(p))
{
statement.GetModule()!.Usings[p] = target.GetModule()!.Usings[p];
}

return (bname, null);
}

if (bname == "string") return (bname, null);
if (type.Definition is null && !BuiltinTypeReference.IsBuiltinKeyword(type.Argument))
{
return (target.ModuleQualifiedClassName(), null);
}

if (string.IsNullOrWhiteSpace(prefix) && !BuiltinTypeReference.IsBuiltinKeyword(type.Argument))
{
return (target.FullyQualifiedClassName(), null);
}

if (BuiltinTypeReference.IsBuiltin(type, out var name, out var def))
{
return def is null ? (name!, null) : (target.FullyQualifiedClassName(), null);
}

return (assignation + bname, null);
});
2 changes: 1 addition & 1 deletion dotnetYang/SemanticModel/CompilationUnit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public static async Task Receive(this IYangServer server, global::System.IO.Stre
await writer.FlushAsync();
output.Position = initialPosition;
output.SetLength(initialLength);
output.SerializeRegularExceptionAsync(ex,id);
await output.SerializeRegularExceptionAsync(ex,id);
}
}
public static async Task ReceiveRPC(this IYangServer server, XmlReader reader, XmlWriter writer)
Expand Down
6 changes: 3 additions & 3 deletions dotnetYang/SemanticModel/DefaultValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ private string GetTypeSpecification(string prefix, string value, Type type, bool
return $"new(\"{Argument}\")";
}

if (BuiltinTypeReference.IsBuiltin(subType, out var typeName, out _))
if (BuiltinTypeReference.IsBuiltinKeyword(subType.Argument))
{
return chained
? "new(" + possible + $"/*{typeName}*/" + ")"
: possible + $"/*{typeName}*/";
? "new(" + possible + ")"
: possible;
}

return "new(new " + MakeName(subType.Argument) + "(" + possible + "))";
Expand Down
24 changes: 21 additions & 3 deletions dotnetYang/SemanticModel/Grouping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ public IStatement[] WithUse(Uses use)
{
use.GetModule()?.Rpcs.Add(rpc);
}

if (child is Notification notification)
{
use.GetModule()?.Notifications.Add(notification);
}

if (child is Action action)
{
use.GetModule()?.Actions.Add(action);
Expand All @@ -79,7 +81,23 @@ public IStatement[] WithUse(Uses use)
continue;
}

if (BuiltinTypeReference.IsBuiltin(type, out _, out _))
if (type.Argument.Contains("leafref"))
{
var path = type.GetChild<Path>();
var value = path.Argument;
var components = value.Split('/');
var index = value.StartsWith("/") ? 1 : 0;
var prefix = components[index].Prefix(out var component);
if (string.IsNullOrWhiteSpace(prefix))
{
components[index] = this.GetInheritedPrefix() + ":" + components[index];
}

path.Argument = string.Join("/", components);
}


if (BuiltinTypeReference.IsBuiltinKeyword(type.Argument))
{
continue;
}
Expand Down Expand Up @@ -137,11 +155,11 @@ public IStatement[] WithUse(Uses use)
{
element.Prefix(out var name);
var origin = current;
current = origin.Children.FirstOrDefault(c => c.Argument == name);
current = StatementExtensions.LocateChildWithInvisibleAllowed(current.Children, name);
if (current is null)
{
Log.Write(
$"Could not find part '{name}' of path {refinement.Argument} in source {origin.Source.Keyword} {origin.Argument}");
$"Missing '{name}' in '{refinement.Argument}' at '{origin.Source.Keyword} {origin.Argument}' [{string.Join(", ", origin.Children.Select(o => o.GetType().Name + " " + o.Argument))}]");
break; //Target not present, nothing to refine.
}
}
Expand Down
2 changes: 1 addition & 1 deletion dotnetYang/SemanticModel/Statement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ public static string Capitalize(string section)
return (char.ToUpperInvariant(first) + rest);
}

protected static string MakeNamespace(string argument)
public static string MakeNamespace(string argument)
{
var output = new StringBuilder(argument.Length);
foreach (var section in argument.Split('-'))
Expand Down
Loading

0 comments on commit 6bdae8a

Please sign in to comment.