From d262a831bf197827a8528dc12ef8535903214fe6 Mon Sep 17 00:00:00 2001 From: caran Date: Mon, 10 Jun 2024 16:09:29 +0200 Subject: [PATCH] Handles both top level and node-data notifications --- TestData/YangSource/ExampleYangServer.cs | 283 +++++++++++++----- YangParser/Generator/YangGenerator.cs | 8 - YangParser/SemanticModel/Action.cs | 117 +------- .../Builtins/BuiltinTypeReference.cs | 20 +- YangParser/SemanticModel/Builtins/Union.cs | 5 +- YangParser/SemanticModel/CompilationUnit.cs | 23 +- YangParser/SemanticModel/NodeDataStatement.cs | 120 ++++++++ YangParser/SemanticModel/Notification.cs | 145 +++------ YangSourceTests/BfdIpMhTests.cs | 20 +- YangSourceTests/RpcTests.cs | 113 ++++--- benchmarks/Program.cs | 28 +- 11 files changed, 524 insertions(+), 358 deletions(-) create mode 100644 YangParser/SemanticModel/NodeDataStatement.cs diff --git a/TestData/YangSource/ExampleYangServer.cs b/TestData/YangSource/ExampleYangServer.cs index 226ce4a..c5c954e 100644 --- a/TestData/YangSource/ExampleYangServer.cs +++ b/TestData/YangSource/ExampleYangServer.cs @@ -5,52 +5,74 @@ namespace YangSource; public class ExampleYangServer : YangSource.IYangServer { - public Task OnActiveRoute(YangNode.RoutingContainer root, YangNode.RoutingContainer.RibsContainer.RibEntry target) + public Task OnActiveRoute( + YangNode.RoutingContainer root, YangNode.RoutingContainer.RibsContainer.RibEntry target) { throw new NotImplementedException(); } - public Task OnActiveRoute(YangNode.RoutingStateContainer root, YangNode.RoutingStateContainer.RibsContainer.RibEntry target) + public Task OnActiveRoute( + YangNode.RoutingStateContainer root, YangNode.RoutingStateContainer.RibsContainer.RibEntry target) { throw new NotImplementedException(); } - public Task OnClearGroups(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.IgmpContainer.ClearGroupsInput input) + public Task OnClearGroups(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.IgmpContainer. + ClearGroupsInput input) { throw new NotImplementedException(); } - public Task OnClearGroups(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MldContainer.ClearGroupsInput input) + public Task OnClearGroups(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MldContainer.ClearGroupsInput + input) { throw new NotImplementedException(); } - public Task OnSetOperatorState(Ietf.Alarms.YangNode.AlarmsContainer root, Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.SetOperatorStateInput input) + public Task OnSetOperatorState(Ietf.Alarms.YangNode.AlarmsContainer root, + Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.SetOperatorStateInput input) { return Task.CompletedTask; } - public Task OnPurgeAlarms(Ietf.Alarms.YangNode.AlarmsContainer root, Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.PurgeAlarmsInput input) + public Task OnPurgeAlarms( + Ietf.Alarms.YangNode.AlarmsContainer root, + Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.PurgeAlarmsInput input) { throw new NotImplementedException(); } - public Task OnCompressAlarms(Ietf.Alarms.YangNode.AlarmsContainer root, Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.CompressAlarmsInput input) + public Task OnCompressAlarms( + Ietf.Alarms.YangNode.AlarmsContainer root, + Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.CompressAlarmsInput input) { throw new NotImplementedException(); } - public Task OnPurgeShelvedAlarms(Ietf.Alarms.YangNode.AlarmsContainer root, Ietf.Alarms.YangNode.AlarmsContainer.ShelvedAlarmsContainer.PurgeShelvedAlarmsInput input) + public Task + OnPurgeShelvedAlarms(Ietf.Alarms.YangNode.AlarmsContainer root, + Ietf.Alarms.YangNode.AlarmsContainer.ShelvedAlarmsContainer.PurgeShelvedAlarmsInput input) { throw new NotImplementedException(); } - public Task OnCompressShelvedAlarms(Ietf.Alarms.YangNode.AlarmsContainer root, Ietf.Alarms.YangNode.AlarmsContainer.ShelvedAlarmsContainer.CompressShelvedAlarmsInput input) + public Task + OnCompressShelvedAlarms(Ietf.Alarms.YangNode.AlarmsContainer root, + Ietf.Alarms.YangNode.AlarmsContainer.ShelvedAlarmsContainer.CompressShelvedAlarmsInput input) { throw new NotImplementedException(); } - public Task OnOperatorAction(Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.OperatorAction notification, DateTime eventTime) + public Task OnOperatorAction(Ietf.Alarms.YangNode.AlarmsContainer notification, DateTime eventTime) + { + return Task.CompletedTask; + } + + public Task OnOperatorAction( + Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.OperatorAction notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -65,17 +87,22 @@ public Task OnAlarmInventoryChanged(Ietf.Alarms.YangNode.AlarmInventoryChanged n throw new NotImplementedException(); } - public Task OnTransmitLoopback(Ieee802.Dot1q.Cfm.YangNode.CfmContainer root, Ieee802.Dot1q.Cfm.YangNode.CfmContainer.MaintenanceGroupEntry.MepEntry.TransmitLoopbackInput input) + public Task + OnTransmitLoopback(Ieee802.Dot1q.Cfm.YangNode.CfmContainer root, + Ieee802.Dot1q.Cfm.YangNode.CfmContainer.MaintenanceGroupEntry.MepEntry.TransmitLoopbackInput input) { throw new NotImplementedException(); } - public Task OnTransmitLinktrace(Ieee802.Dot1q.Cfm.YangNode.CfmContainer root, Ieee802.Dot1q.Cfm.YangNode.CfmContainer.MaintenanceGroupEntry.MepEntry.TransmitLinktraceInput input) + public Task + OnTransmitLinktrace(Ieee802.Dot1q.Cfm.YangNode.CfmContainer root, + Ieee802.Dot1q.Cfm.YangNode.CfmContainer.MaintenanceGroupEntry.MepEntry.TransmitLinktraceInput input) { throw new NotImplementedException(); } - public Task OnEstablishSubscription(Ietf.Subscribed.Notifications.YangNode.EstablishSubscriptionInput input) + public Task OnEstablishSubscription( + Ietf.Subscribed.Notifications.YangNode.EstablishSubscriptionInput input) { throw new NotImplementedException(); } @@ -95,137 +122,188 @@ public Task OnKillSubscription(Ietf.Subscribed.Notifications.YangNode.KillSubscr throw new NotImplementedException(); } - public Task OnReset(Ietf.Subscribed.Notifications.YangNode.SubscriptionsContainer root, Ietf.Subscribed.Notifications.YangNode.SubscriptionsContainer.SubscriptionEntry.ReceiversContainer.ReceiverEntry target) + public + Task OnReset(Ietf.Subscribed.Notifications.YangNode.SubscriptionsContainer root, + Ietf.Subscribed.Notifications.YangNode.SubscriptionsContainer.SubscriptionEntry.ReceiversContainer. + ReceiverEntry target) + { + throw new NotImplementedException(); + } + + public Task OnReplayCompleted(Ietf.Subscribed.Notifications.YangNode.ReplayCompleted notification, + DateTime eventTime) + { + throw new NotImplementedException(); + } + + public Task OnSubscriptionCompleted(Ietf.Subscribed.Notifications.YangNode.SubscriptionCompleted notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnReplayCompleted(Ietf.Subscribed.Notifications.YangNode.ReplayCompleted notification, DateTime eventTime) + public Task OnSubscriptionModified(Ietf.Subscribed.Notifications.YangNode.SubscriptionModified notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSubscriptionCompleted(Ietf.Subscribed.Notifications.YangNode.SubscriptionCompleted notification, DateTime eventTime) + public Task OnSubscriptionResumed(Ietf.Subscribed.Notifications.YangNode.SubscriptionResumed notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSubscriptionModified(Ietf.Subscribed.Notifications.YangNode.SubscriptionModified notification, DateTime eventTime) + public Task OnSubscriptionStarted(Ietf.Subscribed.Notifications.YangNode.SubscriptionStarted notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSubscriptionResumed(Ietf.Subscribed.Notifications.YangNode.SubscriptionResumed notification, DateTime eventTime) + public Task OnSubscriptionSuspended(Ietf.Subscribed.Notifications.YangNode.SubscriptionSuspended notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSubscriptionStarted(Ietf.Subscribed.Notifications.YangNode.SubscriptionStarted notification, DateTime eventTime) + public Task OnSubscriptionTerminated(Ietf.Subscribed.Notifications.YangNode.SubscriptionTerminated notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSubscriptionSuspended(Ietf.Subscribed.Notifications.YangNode.SubscriptionSuspended notification, DateTime eventTime) + public Task OnClearPeer(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MsdpContainer.PeersContainer. + PeerEntry target) { throw new NotImplementedException(); } - public Task OnSubscriptionTerminated(Ietf.Subscribed.Notifications.YangNode.SubscriptionTerminated notification, DateTime eventTime) + public Task OnClearAllPeers(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MsdpContainer target) { throw new NotImplementedException(); } - public Task OnClearPeer(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MsdpContainer.PeersContainer.PeerEntry target) + public Task OnClear(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MsdpContainer. + SaCacheContainer.ClearInput input) { throw new NotImplementedException(); } - public Task OnClearAllPeers(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MsdpContainer target) + public Task OnClearIgmpSnoopingGroups(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.IgmpSnoopingInstanceContainer + .ClearIgmpSnoopingGroupsInput input) { throw new NotImplementedException(); } - public Task OnClear(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MsdpContainer.SaCacheContainer.ClearInput input) + public Task OnClearMldSnoopingGroups(YangNode.RoutingContainer root, + YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MldSnoopingInstanceContainer. + ClearMldSnoopingGroupsInput input) { throw new NotImplementedException(); } - public Task OnClearIgmpSnoopingGroups(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.IgmpSnoopingInstanceContainer.ClearIgmpSnoopingGroupsInput input) + public Task + OnRemoteLoopback(Ietf.Interfaces.YangNode.InterfacesContainer root, + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer.RemoteLoopbackInput input) { throw new NotImplementedException(); } - public Task OnClearMldSnoopingGroups(YangNode.RoutingContainer root, YangNode.RoutingContainer.ControlPlaneProtocolsContainer.ControlPlaneProtocolEntry.MldSnoopingInstanceContainer.ClearMldSnoopingGroupsInput input) + public Task + OnResetStats(Ietf.Interfaces.YangNode.InterfacesContainer root, + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer target) { throw new NotImplementedException(); } - public Task OnRemoteLoopback(Ietf.Interfaces.YangNode.InterfacesContainer root, Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer.RemoteLoopbackInput input) + public Task OnNonThresholdEvent(Ietf.Interfaces.YangNode.InterfacesContainer notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnResetStats(Ietf.Interfaces.YangNode.InterfacesContainer root, Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer target) + public Task OnThresholdEvent(Ietf.Interfaces.YangNode.InterfacesContainer notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnNonThresholdEvent(Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer.NonThresholdEvent notification, DateTime eventTime) + public Task OnNonThresholdEvent( + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer.NonThresholdEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnThresholdEvent(Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer.ThresholdEvent notification, DateTime eventTime) + public Task OnThresholdEvent( + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.LinkOamContainer.ThresholdEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnStateChangeActionType(Ietf.Interfaces.YangNode.InterfacesContainer root, Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.EthernetContainer.MpcpLogicalLinkAdminActionsContainer.StateChangeActionTypeInput input) + public Task OnStateChangeActionType(Ietf.Interfaces.YangNode.InterfacesContainer root, + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.EthernetContainer. + MpcpLogicalLinkAdminActionsContainer.StateChangeActionTypeInput input) { throw new NotImplementedException(); } - public Task OnResetActionType(Ietf.Interfaces.YangNode.InterfacesContainer root, Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.EthernetContainer.MpcpLogicalLinkAdminActionsContainer.ResetActionTypeInput input) + public Task OnResetActionType(Ietf.Interfaces.YangNode.InterfacesContainer root, + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.EthernetContainer. + MpcpLogicalLinkAdminActionsContainer.ResetActionTypeInput input) { throw new NotImplementedException(); } - public Task OnRegisterType(Ietf.Interfaces.YangNode.InterfacesContainer root, Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.EthernetContainer.MpcpLogicalLinkAdminActionsContainer.RegisterTypeInput input) + public Task OnRegisterType(Ietf.Interfaces.YangNode.InterfacesContainer root, + Ietf.Interfaces.YangNode.InterfacesContainer.InterfaceEntry.EthernetContainer. + MpcpLogicalLinkAdminActionsContainer.RegisterTypeInput input) { throw new NotImplementedException(); } - public Task OnManualSwitchWorking(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnManualSwitchWorking(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } - public Task OnManualSwitchProtection(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnManualSwitchProtection(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } - public Task OnForcedSwitch(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnForcedSwitch(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } - public Task OnLockoutOfProtection(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnLockoutOfProtection(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } - public Task OnFreeze(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnFreeze(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } - public Task OnExercise(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnExercise(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } - public Task OnClear(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) + public Task OnClear(Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer root, + Ietf.Microwave.Radio.Link.YangNode.RadioLinkProtectionGroupsContainer.ProtectionGroupEntry target) { throw new NotImplementedException(); } @@ -255,12 +333,14 @@ public Task OnPimRpEvent(Ietf.Pim.Rp.YangNode.PimRpEvent notification, DateTime throw new NotImplementedException(); } - public Task OnContinuityCheck(Ietf.Connection.Oriented.Oam.YangNode.ContinuityCheckInput input) + public Task OnContinuityCheck( + Ietf.Connection.Oriented.Oam.YangNode.ContinuityCheckInput input) { throw new NotImplementedException(); } - public Task OnContinuityVerification(Ietf.Connection.Oriented.Oam.YangNode.ContinuityVerificationInput input) + public Task OnContinuityVerification( + Ietf.Connection.Oriented.Oam.YangNode.ContinuityVerificationInput input) { throw new NotImplementedException(); } @@ -309,12 +389,19 @@ public Task OnPimRpEvent(Ietf.Pim.Rp.YangNode.PimRpEvent notification, DateTime }); } - public Task OnDefectConditionNotification(Ietf.Connection.Oriented.Oam.YangNode.DefectConditionNotification notification, DateTime eventTime) + public Task OnDefectConditionNotification( + Ietf.Connection.Oriented.Oam.YangNode.DefectConditionNotification notification, DateTime eventTime) + { + throw new NotImplementedException(); + } + + public Task OnDefectClearedNotification( + Ietf.Connection.Oriented.Oam.YangNode.DefectClearedNotification notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnDefectClearedNotification(Ietf.Connection.Oriented.Oam.YangNode.DefectClearedNotification notification, DateTime eventTime) + public Task OnMepFaultAlarm(Ieee802.Dot1q.Cfm.YangNode.CfmContainer notification, DateTime eventTime) { throw new NotImplementedException(); } @@ -354,7 +441,8 @@ public Task OnDefectClearedNotification(Ietf.Connection.Oriented.Oam.YangNode.De throw new NotImplementedException(); } - public Task OnNexthopResolutionStatusChange(Ietf.I2rs.Rib.YangNode.NexthopResolutionStatusChange notification, DateTime eventTime) + public Task OnNexthopResolutionStatusChange(Ietf.I2rs.Rib.YangNode.NexthopResolutionStatusChange notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -364,17 +452,20 @@ public Task OnRouteChange(Ietf.I2rs.Rib.YangNode.RouteChange notification, DateT throw new NotImplementedException(); } - public Task OnClearPrefixEntry(Ietf.Dhcpv6.Relay.YangNode.ClearPrefixEntryInput input) + public Task OnClearPrefixEntry( + Ietf.Dhcpv6.Relay.YangNode.ClearPrefixEntryInput input) { throw new NotImplementedException(); } - public Task OnClearClientPrefixes(Ietf.Dhcpv6.Relay.YangNode.ClearClientPrefixesInput input) + public Task OnClearClientPrefixes( + Ietf.Dhcpv6.Relay.YangNode.ClearClientPrefixesInput input) { throw new NotImplementedException(); } - public Task OnClearInterfacePrefixes(Ietf.Dhcpv6.Relay.YangNode.ClearInterfacePrefixesInput input) + public Task OnClearInterfacePrefixes( + Ietf.Dhcpv6.Relay.YangNode.ClearInterfacePrefixesInput input) { throw new NotImplementedException(); } @@ -414,7 +505,8 @@ public Task OnNbrStateChange(Ietf.Ospf.YangNode.NbrStateChange notification, Dat throw new NotImplementedException(); } - public Task OnNbrRestartHelperStatusChange(Ietf.Ospf.YangNode.NbrRestartHelperStatusChange notification, DateTime eventTime) + public Task OnNbrRestartHelperStatusChange(Ietf.Ospf.YangNode.NbrRestartHelperStatusChange notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -434,7 +526,8 @@ public Task OnLsdbOverflow(Ietf.Ospf.YangNode.LsdbOverflow notification, DateTim throw new NotImplementedException(); } - public Task OnNssaTranslatorStatusChange(Ietf.Ospf.YangNode.NssaTranslatorStatusChange notification, DateTime eventTime) + public Task OnNssaTranslatorStatusChange(Ietf.Ospf.YangNode.NssaTranslatorStatusChange notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -449,28 +542,33 @@ public Task OnRestartStatusChange(Ietf.Ospf.YangNode.RestartStatusChange notific throw new NotImplementedException(); } - public Task OnDeleteAddressLease(Ietf.Dhcpv6.Server.YangNode.DeleteAddressLeaseInput input) + public Task OnDeleteAddressLease( + Ietf.Dhcpv6.Server.YangNode.DeleteAddressLeaseInput input) { throw new NotImplementedException(); } - public Task OnDeletePrefixLease(Ietf.Dhcpv6.Server.YangNode.DeletePrefixLeaseInput input) + public Task OnDeletePrefixLease( + Ietf.Dhcpv6.Server.YangNode.DeletePrefixLeaseInput input) { throw new NotImplementedException(); } - public Task OnAddressPoolUtilizationThresholdExceeded(Ietf.Dhcpv6.Server.YangNode.AddressPoolUtilizationThresholdExceeded notification, + public Task OnAddressPoolUtilizationThresholdExceeded( + Ietf.Dhcpv6.Server.YangNode.AddressPoolUtilizationThresholdExceeded notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnPrefixPoolUtilizationThresholdExceeded(Ietf.Dhcpv6.Server.YangNode.PrefixPoolUtilizationThresholdExceeded notification, DateTime eventTime) + public Task OnPrefixPoolUtilizationThresholdExceeded( + Ietf.Dhcpv6.Server.YangNode.PrefixPoolUtilizationThresholdExceeded notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnInvalidClientDetected(Ietf.Dhcpv6.Server.YangNode.InvalidClientDetected notification, DateTime eventTime) + public Task OnInvalidClientDetected(Ietf.Dhcpv6.Server.YangNode.InvalidClientDetected notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -515,7 +613,8 @@ public Task OnCorruptedLspDetected(Ietf.Isis.YangNode.CorruptedLspDetected notif throw new NotImplementedException(); } - public Task OnAttemptToExceedMaxSequence(Ietf.Isis.YangNode.AttemptToExceedMaxSequence notification, DateTime eventTime) + public Task OnAttemptToExceedMaxSequence(Ietf.Isis.YangNode.AttemptToExceedMaxSequence notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -540,7 +639,8 @@ public Task OnSequenceNumberSkipped(Ietf.Isis.YangNode.SequenceNumberSkipped not throw new NotImplementedException(); } - public Task OnAuthenticationTypeFailure(Ietf.Isis.YangNode.AuthenticationTypeFailure notification, DateTime eventTime) + public Task OnAuthenticationTypeFailure(Ietf.Isis.YangNode.AuthenticationTypeFailure notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -565,7 +665,8 @@ public Task OnRejectedAdjacency(Ietf.Isis.YangNode.RejectedAdjacency notificatio throw new NotImplementedException(); } - public Task OnProtocolsSupportedMismatch(Ietf.Isis.YangNode.ProtocolsSupportedMismatch notification, DateTime eventTime) + public Task OnProtocolsSupportedMismatch(Ietf.Isis.YangNode.ProtocolsSupportedMismatch notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -615,7 +716,8 @@ public Task OnMplsLdpPeerEvent(Ietf.Mpls.Ldp.YangNode.MplsLdpPeerEvent notificat throw new NotImplementedException(); } - public Task OnMplsLdpHelloAdjacencyEvent(Ietf.Mpls.Ldp.YangNode.MplsLdpHelloAdjacencyEvent notification, DateTime eventTime) + public Task OnMplsLdpHelloAdjacencyEvent(Ietf.Mpls.Ldp.YangNode.MplsLdpHelloAdjacencyEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -710,7 +812,8 @@ public Task OnPushChangeUpdate(Ietf.Yang.Push.YangNode.PushChangeUpdate notifica throw new NotImplementedException(); } - public Task OnGetBootstrappingData(Ietf.Sztp.Bootstrap.Server.YangNode.GetBootstrappingDataInput input) + public Task OnGetBootstrappingData( + Ietf.Sztp.Bootstrap.Server.YangNode.GetBootstrappingDataInput input) { throw new NotImplementedException(); } @@ -735,12 +838,14 @@ public Task OnHardwareStateChange(Ietf.Hardware.State.YangNode.HardwareStateChan throw new NotImplementedException(); } - public Task OnHardwareStateOperEnabled(Ietf.Hardware.State.YangNode.HardwareStateOperEnabled notification, DateTime eventTime) + public Task OnHardwareStateOperEnabled(Ietf.Hardware.State.YangNode.HardwareStateOperEnabled notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnHardwareStateOperDisabled(Ietf.Hardware.State.YangNode.HardwareStateOperDisabled notification, DateTime eventTime) + public Task OnHardwareStateOperDisabled(Ietf.Hardware.State.YangNode.HardwareStateOperDisabled notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -765,7 +870,8 @@ public Task OnVrrpProtocolErrorEvent(Ietf.Vrrp.YangNode.VrrpProtocolErrorEvent n throw new NotImplementedException(); } - public Task OnVrrpVirtualRouterErrorEvent(Ietf.Vrrp.YangNode.VrrpVirtualRouterErrorEvent notification, DateTime eventTime) + public Task OnVrrpVirtualRouterErrorEvent(Ietf.Vrrp.YangNode.VrrpVirtualRouterErrorEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -785,7 +891,8 @@ public Task OnL3PrefixEvent(Ietf.L3.Unicast.Topology.State.YangNode.L3PrefixEven throw new NotImplementedException(); } - public Task OnTerminationPointEvent(Ietf.L3.Unicast.Topology.State.YangNode.TerminationPointEvent notification, DateTime eventTime) + public Task OnTerminationPointEvent(Ietf.L3.Unicast.Topology.State.YangNode.TerminationPointEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -800,17 +907,20 @@ public Task OnPimInterfaceEvent(Ietf.Pim.Base.YangNode.PimInterfaceEvent notific throw new NotImplementedException(); } - public Task OnSegmentRoutingSrgbCollision(Ietf.Segment.Routing.Mpls.YangNode.SegmentRoutingSrgbCollision notification, DateTime eventTime) + public Task OnSegmentRoutingSrgbCollision( + Ietf.Segment.Routing.Mpls.YangNode.SegmentRoutingSrgbCollision notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSegmentRoutingGlobalSidCollision(Ietf.Segment.Routing.Mpls.YangNode.SegmentRoutingGlobalSidCollision notification, DateTime eventTime) + public Task OnSegmentRoutingGlobalSidCollision( + Ietf.Segment.Routing.Mpls.YangNode.SegmentRoutingGlobalSidCollision notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSegmentRoutingIndexOutOfRange(Ietf.Segment.Routing.Mpls.YangNode.SegmentRoutingIndexOutOfRange notification, DateTime eventTime) + public Task OnSegmentRoutingIndexOutOfRange( + Ietf.Segment.Routing.Mpls.YangNode.SegmentRoutingIndexOutOfRange notification, DateTime eventTime) { throw new NotImplementedException(); } @@ -825,17 +935,20 @@ public Task OnYangLibraryChange(Ietf.Yang.Library.YangNode.YangLibraryChange not throw new NotImplementedException(); } - public Task OnB4AddressChangeLimitPolicyViolation(Ietf.Dslite.YangNode.B4AddressChangeLimitPolicyViolation notification, DateTime eventTime) + public Task OnB4AddressChangeLimitPolicyViolation( + Ietf.Dslite.YangNode.B4AddressChangeLimitPolicyViolation notification, DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSoftwireBindingInstanceEvent(Ietf.Softwire.Br.YangNode.SoftwireBindingInstanceEvent notification, DateTime eventTime) + public Task OnSoftwireBindingInstanceEvent(Ietf.Softwire.Br.YangNode.SoftwireBindingInstanceEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnSoftwireAlgorithmInstanceEvent(Ietf.Softwire.Br.YangNode.SoftwireAlgorithmInstanceEvent notification, DateTime eventTime) + public Task OnSoftwireAlgorithmInstanceEvent(Ietf.Softwire.Br.YangNode.SoftwireAlgorithmInstanceEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -850,7 +963,8 @@ public Task OnL2LinkEvent(Ietf.L2.Topology.State.YangNode.L2LinkEvent notificati throw new NotImplementedException(); } - public Task OnL2TerminationPointEvent(Ietf.L2.Topology.State.YangNode.L2TerminationPointEvent notification, DateTime eventTime) + public Task OnL2TerminationPointEvent(Ietf.L2.Topology.State.YangNode.L2TerminationPointEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -865,12 +979,14 @@ public Task OnL2LinkEvent(Ietf.L2.Topology.YangNode.L2LinkEvent notification, Da throw new NotImplementedException(); } - public Task OnL2TerminationPointEvent(Ietf.L2.Topology.YangNode.L2TerminationPointEvent notification, DateTime eventTime) + public Task OnL2TerminationPointEvent(Ietf.L2.Topology.YangNode.L2TerminationPointEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnBindLneNameFailed(Ietf.Logical.Network.Element.YangNode.BindLneNameFailed notification, DateTime eventTime) + public Task OnBindLneNameFailed(Ietf.Logical.Network.Element.YangNode.BindLneNameFailed notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -895,7 +1011,8 @@ public Task OnL3PrefixEvent(Ietf.L3.Unicast.Topology.YangNode.L3PrefixEvent noti throw new NotImplementedException(); } - public Task OnTerminationPointEvent(Ietf.L3.Unicast.Topology.YangNode.TerminationPointEvent notification, DateTime eventTime) + public Task OnTerminationPointEvent(Ietf.L3.Unicast.Topology.YangNode.TerminationPointEvent notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -910,17 +1027,20 @@ public Task OnHardwareStateChange(Ietf.Hardware.YangNode.HardwareStateChange not throw new NotImplementedException(); } - public Task OnHardwareStateOperEnabled(Ietf.Hardware.YangNode.HardwareStateOperEnabled notification, DateTime eventTime) + public Task OnHardwareStateOperEnabled(Ietf.Hardware.YangNode.HardwareStateOperEnabled notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnHardwareStateOperDisabled(Ietf.Hardware.YangNode.HardwareStateOperDisabled notification, DateTime eventTime) + public Task OnHardwareStateOperDisabled(Ietf.Hardware.YangNode.HardwareStateOperDisabled notification, + DateTime eventTime) { throw new NotImplementedException(); } - public Task OnInvalidIaAddressDetected(Ietf.Dhcpv6.Client.YangNode.InvalidIaAddressDetected notification, DateTime eventTime) + public Task OnInvalidIaAddressDetected(Ietf.Dhcpv6.Client.YangNode.InvalidIaAddressDetected notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -930,7 +1050,8 @@ public Task OnTransmissionFailed(Ietf.Dhcpv6.Client.YangNode.TransmissionFailed throw new NotImplementedException(); } - public Task OnUnsuccessfulStatusCode(Ietf.Dhcpv6.Client.YangNode.UnsuccessfulStatusCode notification, DateTime eventTime) + public Task OnUnsuccessfulStatusCode(Ietf.Dhcpv6.Client.YangNode.UnsuccessfulStatusCode notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -940,7 +1061,9 @@ public Task OnServerDuidChanged(Ietf.Dhcpv6.Client.YangNode.ServerDuidChanged no throw new NotImplementedException(); } - public Task OnMepFaultAlarm(Ieee802.Dot1q.Cfm.YangNode.CfmContainer.MaintenanceGroupEntry.MepEntry.MepFaultAlarm notification, DateTime eventTime) + public Task OnMepFaultAlarm( + Ieee802.Dot1q.Cfm.YangNode.CfmContainer.MaintenanceGroupEntry.MepEntry.MepFaultAlarm notification, + DateTime eventTime) { throw new NotImplementedException(); } @@ -987,7 +1110,7 @@ public Task OnSinglehopNotification(Ietf.Bfd.Ip.Sh.YangNode.SinglehopNotificatio public Task OnMultihopNotification(Ietf.Bfd.Ip.Mh.YangNode.MultihopNotification notification, DateTime eventTime) { - throw new NotImplementedException(); + return Task.CompletedTask; } public Task OnFactoryReset() diff --git a/YangParser/Generator/YangGenerator.cs b/YangParser/Generator/YangGenerator.cs index 5f57ca7..ee22772 100644 --- a/YangParser/Generator/YangGenerator.cs +++ b/YangParser/Generator/YangGenerator.cs @@ -475,19 +475,11 @@ public static async Task ExpectOkRpcReply(XmlReader reader, int messageID) throw new Exception($"Expected stream to start with a element with message id {messageID} & \"urn:ietf:params:xml:ns:netconf:base:1.0\" but got {reader.NodeType}: {reader.Name} in {reader.NamespaceURI}"); } await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } if(reader.NodeType != XmlNodeType.Element || reader.Name != "ok") { throw new Exception($"Expected element {reader.NodeType}: {reader.Name}"); } await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } if(reader.NodeType != XmlNodeType.EndElement) { throw new Exception($"Expected closing element {reader.NodeType}: {reader.Name}"); diff --git a/YangParser/SemanticModel/Action.cs b/YangParser/SemanticModel/Action.cs index 07f678c..178c36f 100644 --- a/YangParser/SemanticModel/Action.cs +++ b/YangParser/SemanticModel/Action.cs @@ -1,11 +1,9 @@ -using System.Collections.Generic; using System.Linq; -using System.Text; using YangParser.Parser; namespace YangParser.SemanticModel; -public class Action : Statement, IXMLParseable +public class Action : NodeDataStatement, IXMLParseable { public Action(YangStatement statement) : base(statement) { @@ -33,104 +31,6 @@ public Action(YangStatement statement) : base(statement) new ChildRule(TypeDefinition.Keyword, Cardinality.ZeroOrMore), ]; - private string? _targetPath; - public string TargetPath => _targetPath ??= GetTargetPath(); - - private string GetTargetPath() - { - StringBuilder entries = new StringBuilder(); - entries.Append(TargetName); - var parent = Parent; - while (parent is not null) - { - if (parent is Module) break; - if (parent is IXMLParseable parseable) - { - entries.Insert(0, parseable.TargetName! + "?."); - } - else if (parent is List list) - { - var content = entries.ToString(); - entries.Insert(0, - list.TargetName + - $"?.FirstOrDefault({list.ClassName.ToLower()} => {list.ClassName.ToLower()}?.{content} != null)?."); - } - else - { - throw new SemanticError( - $"Could not describe full target path of action {Argument}: encountered unknown {parent.GetType().Name} {parent.Argument}", - parent.Source); - } - - parent = parent.Parent; - } - - return entries.ToString(); - } - - private IXMLParseable QualifiedRoot() - { - var parent = Parent; - while (parent is not Module && parent is not null) - { - if (parent.Parent is Module) - { - if (parent is not IXMLParseable parseable) - { - throw new SemanticError( - $"Action {Argument}: qualified root '{parent.GetType().Name} {parent.Argument}' was not Parseable or readable", - Source); - } - - return parseable; - } - - parent = parent.Parent; - } - - if (parent is null or Module) - { - throw new SemanticError($"Action {Argument}: qualified root was null or a module", Source); - } - - if (parent is not IXMLParseable xmlParseable) - { - throw new SemanticError( - $"Action {Argument}: qualified root '{parent.GetType().Name} {parent.Argument}' was not Parseable or readable", - Source); - } - - return xmlParseable; - } - - private string FullyQualifiedNamespace() - { - var parent = Parent; - List classChain = new(); - while (parent is not Module && parent is not null) - { - switch (parent) - { - case IXMLParseable xml: - classChain.Insert(0, xml.ClassName); - break; - case IXMLReadValue readValue: - classChain.Insert(0, readValue.ClassName); - break; - } - - parent = parent.Parent; - } - - if (parent is Module module) - { - classChain.Insert(0, "YangNode"); - classChain.Insert(0, MakeNamespace(module.Argument)); - } - - return string.Join(".", classChain); - } - public string ServerDeclaration => ReturnType + " On" + MakeName(Argument) + $"({QualifiedRootName} root, " + (Ingoing is null ? FullyQualifiedNamespace() + " target" @@ -253,17 +153,6 @@ public class {{ClassName}} """; } - private string? _rootName; - - public string QualifiedRootName => - _rootName ??= - MakeNamespace(Root.GetModule()!.Argument) + ".YangNode." + - Root.ClassName; - - private IXMLParseable? _root; - public IXMLParseable Root => _root ??= QualifiedRoot(); - - protected override void ValidateParent() { var parent = Parent; @@ -304,7 +193,7 @@ protected override void ValidateParent() private string? _target; - public string TargetName => _target ??= MakeName(Argument) + "ActionNode"; + public override string TargetName => _target ??= MakeName(Argument) + "ActionNode"; public string WriteCall => Ingoing is not null @@ -333,5 +222,5 @@ Ingoing is not null : "await reader.ReadAsync();"; private string? _className; - public string ClassName => _className ??= MakeName(Argument) + "Class"; + public override string ClassName => _className ??= MakeName(Argument) + "Class"; } \ No newline at end of file diff --git a/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs b/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs index e8bfc6c..9eea476 100644 --- a/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs +++ b/YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs @@ -50,6 +50,23 @@ public static bool IsBuiltinKeyword(string keyword) return m_builtIns.Any(b => b.Name == keyword); } + public static string Stringification(Type type, string targetName) + { + var toString = targetName + ".ToString()!"; + switch (type.Argument) + { + case "bits": + case "enumeration": + case "identityref": + toString = $"GetEncodedValue({targetName})"; + + break; + default: break; + } + + return toString; + } + public static string DefaultPattern(IStatement statement, IEnumerable staticFields, IEnumerable constructorStatements, string baseTypeName, string typeName) @@ -152,7 +169,6 @@ public override string ToString() private static string GetText(string argument) => $$""" await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) await reader.ReadAsync(); if(reader.NodeType != XmlNodeType.Text) { throw new Exception($"Expected token in ParseCall for '{{argument}}' to be text, but was '{reader.NodeType}'"); @@ -164,7 +180,6 @@ private static string EndElement(string argument) => $$""" { await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) await reader.ReadAsync(); if(reader.NodeType != XmlNodeType.EndElement) { throw new Exception($"Expected token in ParseCall for '{{argument}}' to be an element closure, but was '{reader.NodeType}'"); @@ -290,6 +305,7 @@ public static string ValueParsing(Type type, string typeName) var p = prefix.Contains('.') ? prefix : prefix + ":"; return $"return {p}Get{local}Value(value);"; } + return $"return {typeName}.Parse(value);"; default: return $"return {typeName}.Parse(value);"; diff --git a/YangParser/SemanticModel/Builtins/Union.cs b/YangParser/SemanticModel/Builtins/Union.cs index 78b1a31..5e07c9a 100644 --- a/YangParser/SemanticModel/Builtins/Union.cs +++ b/YangParser/SemanticModel/Builtins/Union.cs @@ -10,6 +10,7 @@ public class Union() : BuiltinType("union", s => List types = []; List declarations = []; List switches = []; + List stringifications = []; foreach (var option in options) { var typeName = option.Name!; @@ -24,6 +25,8 @@ public class Union() : BuiltinType("union", s => switches.Add($$""" try { {{BuiltinTypeReference.ValueParsing(option, typeName)}} } catch(Exception ex) { errors += " " + ex.Message; } """); + stringifications.Add( + $"if({VariableName(typeName)} is not null) return {BuiltinTypeReference.Stringification(option, VariableName(typeName))};"); } var name = sourceName; @@ -38,7 +41,7 @@ public class {{name}} {{Statement.Indent(string.Join("\n", declarations))}} public override string? ToString() { - {{Statement.Indent(Statement.Indent(string.Join("\n", types.Select(typeName => $"if({VariableName(typeName)} is not null) return {VariableName(typeName)}.ToString();"))))}} + {{Statement.Indent(Statement.Indent(string.Join("\n", stringifications)))}} return string.Empty; } public static {{name}} Parse(string value) diff --git a/YangParser/SemanticModel/CompilationUnit.cs b/YangParser/SemanticModel/CompilationUnit.cs index c080f90..dd965b2 100644 --- a/YangParser/SemanticModel/CompilationUnit.cs +++ b/YangParser/SemanticModel/CompilationUnit.cs @@ -34,6 +34,7 @@ public override string ToCode() Argument = "root"; Dictionary> ActionCases = []; + Dictionary> NotificationCases = []; foreach (var module in Children.OfType()) { foreach (var action in module.Actions) @@ -52,6 +53,23 @@ public override string ToCode() list.Add(action.ReceiveCase); } + + foreach (var notification in module.Notifications.Where(n => n.IsTopLevel == false)) + { + var caseName = $$""" + case "{{notification.Root.XmlObjectName}}": + { + var {{notification.Root.TargetName}} = await {{notification.QualifiedRootName}}.ParseAsync(reader); + + """; + if (!NotificationCases.TryGetValue(caseName, out var list)) + { + NotificationCases[caseName] = []; + list = NotificationCases[caseName]; + } + + list.Add(notification.ReceiveCase); + } } return $$""" @@ -132,14 +150,15 @@ public static async Task ReceiveAction(this IYangServer server, XmlReader reader await reader.ReadAsync(); switch(reader.Name) { - {{Indent(Indent(Indent(string.Join("\n", ActionCases.Select(c => c.Key + Indent(string.Join("\n", c.Value)) + $"\n}}\nthrow new Exception(\"Could not find valid action\");")))))}} + {{Indent(Indent(Indent(string.Join("\n", ActionCases.Select(c => c.Key + Indent(string.Join("\n", c.Value)) + "\n}\nthrow new Exception(\"Could not find valid action\");")))))}} } } public static async Task ReceiveNotification(this IYangServer server, XmlReader reader, DateTime eventTime) { switch(reader.Name) { - {{Indent(Indent(Indent(string.Join("\n", Children.OfType().SelectMany(m => m.Notifications).Select(rpc => rpc.ReceiveCase).Distinct()))))}} + {{Indent(Indent(Indent(string.Join("\n", Children.OfType().SelectMany(m => m.Notifications.Where(n => n.IsTopLevel)).Select(rpc => rpc.ReceiveCase).Distinct()))))}} + {{Indent(Indent(Indent(string.Join("\n", NotificationCases.Select(c => c.Key + Indent(string.Join("\n", c.Value)) + "\n}\nthrow new Exception(\"Could not find valid notification\");")))))}} } } } diff --git a/YangParser/SemanticModel/NodeDataStatement.cs b/YangParser/SemanticModel/NodeDataStatement.cs new file mode 100644 index 0000000..331249a --- /dev/null +++ b/YangParser/SemanticModel/NodeDataStatement.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using System.Text; +using YangParser.Parser; + +namespace YangParser.SemanticModel; + +public abstract class NodeDataStatement(YangStatement statement) : Statement(statement), IXMLParseable +{ + private string? _targetPath; + public string TargetPath => _targetPath ??= GetTargetPath(); + + private string GetTargetPath() + { + StringBuilder entries = new StringBuilder(); + entries.Append(TargetName); + var parent = Parent; + while (parent is not null) + { + if (parent is Module) break; + if (parent is IXMLParseable parseable) + { + entries.Insert(0, parseable.TargetName! + "?."); + } + else if (parent is List list) + { + var content = entries.ToString(); + entries.Insert(0, + list.TargetName + + $"?.FirstOrDefault({list.ClassName.ToLower()} => {list.ClassName.ToLower()}?.{content} != null)?."); + } + else + { + throw new SemanticError( + $"Could not describe full target path of action {Argument}: encountered unknown {parent.GetType().Name} {parent.Argument}", + parent.Source); + } + + parent = parent.Parent; + } + + return entries.ToString(); + } + + private IXMLParseable? _root; + public IXMLParseable Root => _root ??= QualifiedRoot(); + + private IXMLParseable QualifiedRoot() + { + if (Parent is Module module) return this; + var parent = Parent; + while (parent is not Module && parent is not null) + { + if (parent.Parent is Module) + { + if (parent is not IXMLParseable parseable) + { + throw new SemanticError( + $"Action {Argument}: qualified root '{parent.GetType().Name} {parent.Argument}' was not Parseable or readable", + Source); + } + + return parseable; + } + + parent = parent.Parent; + } + + if (parent is null or Module) + { + throw new SemanticError($"Action {Argument}: qualified root was null or a module", Source); + } + + if (parent is not IXMLParseable xmlParseable) + { + throw new SemanticError( + $"Action {Argument}: qualified root '{parent.GetType().Name} {parent.Argument}' was not Parseable or readable", + Source); + } + + return xmlParseable; + } + + private string? _rootName; + + public string QualifiedRootName => + _rootName ??= + MakeNamespace(Root.GetModule()!.Argument) + ".YangNode." + + Root.ClassName; + + public string FullyQualifiedNamespace() + { + var parent = Parent; + List classChain = new(); + while (parent is not Module && parent is not null) + { + switch (parent) + { + case IXMLParseable xml: + classChain.Insert(0, xml.ClassName); + break; + case IXMLReadValue readValue: + classChain.Insert(0, readValue.ClassName); + break; + } + + parent = parent.Parent; + } + + if (parent is Module module) + { + classChain.Insert(0, "YangNode"); + classChain.Insert(0, MakeNamespace(module.Argument)); + } + + return string.Join(".", classChain); + } + + public abstract string? TargetName { get; } + public abstract string ClassName { get; } +} \ No newline at end of file diff --git a/YangParser/SemanticModel/Notification.cs b/YangParser/SemanticModel/Notification.cs index 182dba2..7906671 100644 --- a/YangParser/SemanticModel/Notification.cs +++ b/YangParser/SemanticModel/Notification.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using YangParser.Parser; namespace YangParser.SemanticModel; -public class Notification : Statement +public class Notification : NodeDataStatement, IXMLParseable { public Notification(YangStatement statement) : base(statement) { @@ -33,58 +34,43 @@ public Notification(YangStatement statement) : base(statement) new ChildRule(Uses.Keyword, Cardinality.ZeroOrMore) ]; - private string FullyQualifiedNamespace() - { - var parent = Parent; - List classChain = new(); - while (parent is not Module && parent is not null) - { - switch (parent) - { - case IXMLParseable xml: - classChain.Insert(0, xml.ClassName); - break; - case IXMLReadValue readValue: - classChain.Insert(0, readValue.ClassName); - break; - } - - parent = parent.Parent; - } - - if (parent is Module module) - { - classChain.Insert(0, "YangNode"); - classChain.Insert(0, MakeNamespace(module.Argument)); - } + private string? _className; + public bool IsTopLevel => Root == this; - return string.Join(".", classChain); - } - - public string ServerDeclaration => "Task On" + MakeName(Argument) + "(" + - FullyQualifiedNamespace() + "." + MakeName(Argument) + + public string ServerDeclaration => "Task On" + ClassName + "(" + ParsedType + " notification, global::System.DateTime eventTime);"; - public string ReceiveCase => $"case \"{Argument}\" when reader.NamespaceURI is \"{Namespace}\":\n" + $$""" - { - var input = await {{FullyQualifiedNamespace() + "." + MakeName(Argument)}}.ParseAsync(reader); - await server.On{{MakeName(Argument)}}(input, eventTime); - break; - } - """; + public string ReceiveCase => IsTopLevel + ? $"case \"{XmlObjectName}\" when reader.NamespaceURI is \"{Namespace}\":\n" + $$""" + { + var input = await {{ParsedType}}.ParseAsync(reader); + await server.On{{ClassName}}(input, eventTime); + break; + } + """ + : $$""" + if({{TargetPath}} != null) { + await server.On{{ClassName}}({{Root.TargetName}}, eventTime); + break; + } + """; + + private string ParsedType => IsTopLevel ? FullyQualifiedNamespace() + "." + ClassName : QualifiedRootName; public override string ToCode() { var nodes = Children.Select(child => child.ToCode()).ToArray(); var xmlWrite = GetXmlWriting(); var xmlRead = GetXmlReading(); + var addRoot = IsTopLevel ? string.Empty : $", {QualifiedRootName} source"; return $$""" + public {{ClassName}}? {{TargetName}}; {{DescriptionString}}{{AttributeString}} - public class {{MakeName(Argument)}} + public class {{ClassName}} { {{string.Join("\n\t", nodes.Select(Indent))}} - public async Task ToXML() + public async Task Send(IChannel channel{{addRoot}}) { StringBuilder stringBuilder = new StringBuilder(); using XmlWriter writer = XmlWriter.Create(stringBuilder, SerializationHelper.GetStandardWriterSettings()); @@ -95,9 +81,10 @@ public async Task ToXML() {{xmlWrite}} await writer.WriteEndElementAsync(); await writer.FlushAsync(); - return stringBuilder.ToString(); + var response = await channel.Send(stringBuilder.ToString()); + response.Dispose(); } - public static async Task<{{MakeName(Argument)}}> ParseAsync(global::System.IO.Stream xmlStream) + public static async Task<{{ParsedType}}> ParseAsync(global::System.IO.Stream xmlStream) { using XmlReader reader = XmlReader.Create(xmlStream,SerializationHelper.GetStandardReaderSettings()); await reader.ReadAsync(); @@ -106,43 +93,23 @@ public async Task ToXML() throw new Exception($"Expected stream to start with a element with namespace \"urn:ietf:params:xml:ns:netconf:notification:1.0\" but got {reader.NodeType}: {reader.Name} in {reader.NamespaceURI}"); } await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } if(reader.NodeType != XmlNodeType.Element || reader.Name != "eventTime") { throw new Exception($"Expected stream to have a second element called element but got {reader.NodeType}: {reader.Name}"); } await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } if(reader.NodeType != XmlNodeType.Text) { if(!global::System.DateTime.TryParse(await reader.GetValueAsync(), out _)) throw new Exception($"Expected element to contain a valid dateTime but got {reader.NodeType}: {reader.Name}"); } await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } if(reader.NodeType != XmlNodeType.EndElement) { throw new Exception($"Expected element to only have one child but got {reader.NodeType}: {reader.Name}"); } await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } var value = {{xmlRead}} await reader.ReadAsync(); - while(reader.NodeType == XmlNodeType.Whitespace) - { - await reader.ReadAsync(); - } if(reader.NodeType != XmlNodeType.EndElement) { throw new Exception($"Expected closing element {reader.NodeType}: {reader.Name}"); @@ -150,64 +117,22 @@ public async Task ToXML() return value; } {{Indent(WriteFunction())}} - {{Indent(ReadFunction(MakeName(Argument)))}} + {{Indent(ReadFunction())}} } """; } private string GetXmlWriting() { - if (Parent is Module) - { - return "await WriteXMLAsync(writer);"; - } - - var parent = Parent; - while (parent != null) - { - if (parent.Parent is Module or Submodule) - { - break; - } - - parent = parent.Parent; - } - - if (parent is IXMLSource) - { - return "await WriteXMLAsync(writer);"; - } - - throw new SemanticError( - $"Top level statement of 'notification {Argument}' ({parent?.Source.Keyword} {parent?.Argument}) was not a valid XML source", - Source); + return IsTopLevel ? "await WriteXMLAsync(writer);" : "await source.WriteXMLAsync(writer);"; } private string GetXmlReading() { - if (Parent is Module) - { - return "await ParseAsync(reader);"; - } - - var parent = Parent; - while (parent != null) - { - if (parent.Parent is Module or Submodule) - { - break; - } - - parent = parent.Parent; - } - - if (parent is IXMLSource) - { - return "await ParseAsync(reader);"; - } - - throw new SemanticError( - $"Top level statement of 'notification {Argument}' ({parent?.Source.Keyword} {parent?.Argument}) was not a valid XML source", - Source); + return IsTopLevel ? "await ParseAsync(reader);" : $"await {QualifiedRootName}.ParseAsync(reader);"; } + + private string? _targetName; + public override string? TargetName => _targetName ??= ClassName + "Instance"; + public override string ClassName => _className ??= MakeName(Argument); } \ No newline at end of file diff --git a/YangSourceTests/BfdIpMhTests.cs b/YangSourceTests/BfdIpMhTests.cs index edddb67..b40130b 100644 --- a/YangSourceTests/BfdIpMhTests.cs +++ b/YangSourceTests/BfdIpMhTests.cs @@ -1,11 +1,21 @@ using System.Text; using Ietf.Inet.Types; using Xunit.Abstractions; +using Yang.Attributes; namespace YangSourceTests; public class BfdIpMhTests(ITestOutputHelper output) { + private class VoidChannel : IChannel + { + public string? LastSent { get; private set; } + public Task Send(string xml) + { + LastSent = xml; + return Task.FromResult(new MemoryStream() as Stream); + } + } [Fact] public async Task NotificationSerializationTest() { @@ -14,8 +24,9 @@ public async Task NotificationSerializationTest() 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); + var channel = new VoidChannel(); + await notification.Send(channel); + output.WriteLine(channel.LastSent); } [Fact] @@ -26,8 +37,9 @@ public async Task NotificationDeserializationTest() DestAddr = new YangNode.IpAddress(new YangNode.Ipv4Address("192.168.0.1")), NewState = Ietf.Bfd.Types.YangNode.State.AdminDown }; - var result = await notification.ToXML(); - using var ms = new MemoryStream(Encoding.UTF8.GetBytes(result)); + var channel = new VoidChannel(); + await notification.Send(channel); + using var ms = new MemoryStream(Encoding.UTF8.GetBytes(channel.LastSent!)); var newNotification = await Ietf.Bfd.Ip.Mh.YangNode.MultihopNotification.ParseAsync(ms); Assert.Equal(notification.DestAddr!.Ipv4AddressValue!.WrittenValue, newNotification.DestAddr!.Ipv4AddressValue!.WrittenValue); diff --git a/YangSourceTests/RpcTests.cs b/YangSourceTests/RpcTests.cs index 6008503..d616001 100644 --- a/YangSourceTests/RpcTests.cs +++ b/YangSourceTests/RpcTests.cs @@ -80,6 +80,47 @@ public async Task RpcSend() // output.Response![1].Ttl); } + private static readonly Ietf.Alarms.YangNode.AlarmsContainer root = new() + { + AlarmList = new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer + { + Alarm = + [ + new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry + { + TimeCreated = "2015-01-23T12:23:34Z", + Resource = "something", + AlarmTypeId = Ietf.Alarms.YangNode.AlarmTypeIdIdentity.AlarmTypeId, + IsCleared = false, + LastRaised = "2014-01-23T12:23:34Z", + LastChanged = "2014-01-22T12:23:34Z", + PerceivedSeverity = Ietf.Alarms.YangNode.Severity.Critical, + AlarmText = "boo", + }, + new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry + { + TimeCreated = "2015-01-23T12:25:34Z", + Resource = "something", + AlarmTypeId = Ietf.Alarms.YangNode.AlarmTypeIdIdentity.AlarmTypeId, + IsCleared = false, + LastRaised = "2014-01-23T12:28:34Z", + LastChanged = "2014-01-22T12:22:34Z", + PerceivedSeverity = Ietf.Alarms.YangNode.Severity.Critical, + AlarmText = "baa", + OperatorActionInstance = + new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.OperatorAction + { + Operator = "Me", + State = new Ietf.Alarms.YangNode.OperatorState(Ietf.Alarms.YangNode.OperatorState + .OperatorState1.Shelved), + Time = "2014-01-23T12:28:34Z", + Text = "Some fine message" + } + } + ] + } + }; + [Fact] public async Task ActionSend() { @@ -87,44 +128,46 @@ public async Task ActionSend() { MessageID = Random.Shared.Next() }; - - var root = new Ietf.Alarms.YangNode.AlarmsContainer - { - AlarmList = new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer + await root.AlarmList!.Alarm![0].SetOperatorState(channel, channel.MessageID, root, + new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.SetOperatorStateInput { - Alarm = - [ - new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry - { - TimeCreated = "2015-01-23T12:23:34Z", - Resource = "something", - AlarmTypeId = Ietf.Alarms.YangNode.AlarmTypeIdIdentity.AlarmTypeId, - IsCleared = false, - LastRaised = "2014-01-23T12:23:34Z", - LastChanged = "2014-01-22T12:23:34Z", - PerceivedSeverity = Ietf.Alarms.YangNode.Severity.Critical, - AlarmText = "boo" - }, - new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry - { - TimeCreated = "2015-01-23T12:25:34Z", - Resource = "something", - AlarmTypeId = Ietf.Alarms.YangNode.AlarmTypeIdIdentity.AlarmTypeId, - IsCleared = false, - LastRaised = "2014-01-23T12:28:34Z", - LastChanged = "2014-01-22T12:22:34Z", - PerceivedSeverity = Ietf.Alarms.YangNode.Severity.Critical, - AlarmText = "baa" - } - ] - } + State = Ietf.Alarms.YangNode.WritableOperatorState.Ack, + Text = "Acked" + }); + + outputHelper.WriteLine(channel.LastXML); + outputHelper.WriteLine("_____________________________________"); + outputHelper.WriteLine(channel.LastWritten); + } + + [Fact] + public async Task NotificationSend() + { + var channel = new TestChannel + { + MessageID = Random.Shared.Next() }; - await root.AlarmList.Alarm[0].SetOperatorState(channel,channel.MessageID,root,new Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer.AlarmEntry.SetOperatorStateInput + + await root.AlarmList!.Alarm![1].OperatorActionInstance!.Send(channel, root); + + outputHelper.WriteLine(channel.LastXML); + outputHelper.WriteLine("_____________________________________"); + outputHelper.WriteLine(channel.LastWritten); + } + [Fact] + public async Task TopLevelNotificationSend() + { + var channel = new TestChannel { - State = Ietf.Alarms.YangNode.WritableOperatorState.Ack, - Text = "Acked" - }); - + MessageID = Random.Shared.Next() + }; + + 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 + }; + await notification.Send(channel); outputHelper.WriteLine(channel.LastXML); outputHelper.WriteLine("_____________________________________"); outputHelper.WriteLine(channel.LastWritten); diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs index c7076b4..72a565e 100644 --- a/benchmarks/Program.cs +++ b/benchmarks/Program.cs @@ -87,6 +87,17 @@ private static readonly Ietf.Alarms.YangNode.AlarmsContainer.AlarmListContainer. } }; + private class VoidChannel : IChannel + { + public string LastSent { get; private set; } + + public Task Send(string xml) + { + LastSent = xml; + return Task.FromResult(new MemoryStream() as Stream); + } + } + [GlobalSetup] public void Setup() { @@ -99,7 +110,9 @@ public void Setup() NewState = Ietf.Bfd.Types.YangNode.State.Init, SourceAddr = new YangNode.IpAddress(new YangNode.Ipv4Address("2.3.4.5")) }; - serialized = notification.ToXML().Result; + var tmp = new VoidChannel(); + notification.Send(tmp).Wait(); + serialized = tmp.LastSent; server = new ExampleYangServer(); channel = new BenchmarkingChannel(server); } @@ -123,7 +136,12 @@ public Ietf.Bfd.Ip.Mh.YangNode.MultihopNotification MultihopNotificationCreation }; [Benchmark] - public async Task SerializerMultihopNotification() => await notification.ToXML(); + public async Task SerializerMultihopNotification() + { + var tmp = new VoidChannel(); + await notification.Send(tmp); + return tmp.LastSent; + } [Benchmark] public MemoryStream ToMemoryStream() @@ -152,6 +170,12 @@ public async Task SetOperatorStateRoundTrip() await alarmsContainer.AlarmList!.Alarm![0] .SetOperatorState(channel, 123, alarmsContainer, SetOperatorStateInput); } + + [Benchmark] + public async Task NotificationRoundTrip() + { + await notification.Send(channel); + } } internal class BenchmarkingChannel(IYangServer server) : IChannel