From 435322595ca9ce331873f2af771dc353610a2d1a Mon Sep 17 00:00:00 2001 From: PTKu <61538034+PTKu@users.noreply.github.com> Date: Tue, 7 May 2024 07:49:37 +0200 Subject: [PATCH] mend --- .../Onliner/CsOnlinerSourceBuilder.cs | 42 +- .../Plain/CsPlainSourceBuilder.cs | 32 +- .../AXSharp.Compiler.CsTests.csproj | 12 + .../Cs/CsSourceBuilderTests.cs | 3 +- .../IxProjectTests.IntegrationCs.cs | 6 +- .../units/expected/.g/Onliners/generics.g.cs | 583 ++++++++++++++++++ .../units/expected/.g/POCO/generics.g.cs | 23 + .../samples/units/src/generics.st | 9 +- .../ix/.g/Onliners/configuration.g.cs | 1 + .../ix/.g/POCO/configuration.g.cs | 1 + .../.g/Onliners/configuration.g.cs | 1 + .../.g/POCO/configuration.g.cs | 1 + .../axsharpblazor.twin/axsharpblazor.csproj | 21 + 13 files changed, 702 insertions(+), 33 deletions(-) create mode 100644 src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/Onliners/generics.g.cs create mode 100644 src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/POCO/generics.g.cs create mode 100644 templates/working/templates/axsharpblazor/axsharpblazor.twin/axsharpblazor.csproj diff --git a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Onliner/CsOnlinerSourceBuilder.cs b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Onliner/CsOnlinerSourceBuilder.cs index d029c02f..db28ff7a 100644 --- a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Onliner/CsOnlinerSourceBuilder.cs +++ b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Onliner/CsOnlinerSourceBuilder.cs @@ -54,14 +54,12 @@ public void CreateFile(IFileSyntax fileSyntax, IxNodeVisitor visitor) AddToSource("using AXSharp.Connector.ValueTypes;"); AddToSource("using System.Collections.Generic;"); AddToSource("using AXSharp.Connector.Localizations;"); - - foreach (var fileSyntaxUsingDirective in fileSyntax.UsingDirectives .Where(p => this.Compilation.GetSemanticTree().Namespaces.Select(p => p.FullyQualifiedName).Contains(p.QualifiedIdentifierList.GetText()))) { AddToSource($"using {fileSyntaxUsingDirective.QualifiedIdentifierList.GetText()};"); } - + fileSyntax.Declarations.ToList().ForEach(p => p.Visit(visitor, this)); } @@ -73,7 +71,7 @@ private string ReplaceGenericSignature(IClassDeclaration? classDeclaration) var generics = new List(); var genericSignature = classDeclaration?.ExtendedType?.GetGenericAttributes()?.Product; - if(string.IsNullOrEmpty(genericSignature)) + if (string.IsNullOrEmpty(genericSignature)) { return string.Empty; } @@ -89,11 +87,11 @@ private string ReplaceGenericSignature(IClassDeclaration? classDeclaration) { if (attribute.GenericTypeAssignment.isPoco) { - genericSignature = genericSignature.Replace(attribute.GenericTypeAssignment.type, $"Pocos.{fieldDeclaresGenericType?.Type.FullyQualifiedName}"); + genericSignature = genericSignature.Replace(attribute.GenericTypeAssignment.type, $"Pocos.{fieldDeclaresGenericType?.Type.FullyQualifiedName}"); } else { - genericSignature = genericSignature.Replace(attribute.GenericTypeAssignment.type, fieldDeclaresGenericType?.Type.FullyQualifiedName); + genericSignature = genericSignature.Replace(attribute.GenericTypeAssignment.type, fieldDeclaresGenericType?.Type.FullyQualifiedName); } } } @@ -110,10 +108,22 @@ public void CreateClassDeclaration(IClassDeclarationSyntax classDeclarationSynta IxNodeVisitor visitor) { TypeCommAccessibility = classDeclaration.GetCommAccessibility(this); - + + // This is a workaround for abstract classes where semantic model does not contain pragmas even when declared in the source. + if (classDeclarationSyntax.ClassKeyword.FullText.Trim().ToLower().StartsWith("{S7.extern=ReadWrite}".ToLower())) + { + TypeCommAccessibility = eCommAccessibility.ReadWrite; + } + + if (classDeclarationSyntax.ClassKeyword.FullText.Trim().ToLower().StartsWith("{S7.extern=Read}".ToLower())) + { + TypeCommAccessibility = eCommAccessibility.ReadOnly; + } + + classDeclarationSyntax.UsingDirectives.ToList().ForEach(p => p.Visit(visitor, this)); var generic = classDeclaration.GetGenericAttributes(); - + AddToSource(classDeclaration.Pragmas.AddAttributes()); AddToSource($"{classDeclaration.AccessModifier.Transform()}partial class {classDeclaration.Name}{generic?.Product}"); AddToSource(":"); @@ -149,7 +159,7 @@ public void CreateClassDeclaration(IClassDeclarationSyntax classDeclarationSynta AddToSource(CsOnlinerPlainerShadowToPlainBuilder.Create(visitor, classDeclaration, this, isExtended).Output); AddToSource(CsOnlinerPlainerShadowToPlainProtectedBuilder.Create(visitor, classDeclaration, this, isExtended).Output); AddToSource(CsOnlinerPlainerPlainToShadowBuilder.Create(visitor, classDeclaration, this, isExtended).Output); - + AddToSource(CsOnlinerHasChangedBuilder.Create(visitor, classDeclaration, this, isExtended).Output); AddPollingMethod(isExtended); @@ -178,7 +188,7 @@ public void CreateConfigDeclaration(IConfigDeclarationSyntax configDeclarationSy IxNodeVisitor visitor) { TypeCommAccessibility = eCommAccessibility.None; - + AddToSource( $"public partial class {Project.TargetProject.ProjectRootNamespace}TwinController : ITwinController {{"); AddToSource($"public {typeof(Connector.Connector).n()} Connector {{ get; }}"); @@ -205,9 +215,9 @@ public void CreateEnumTypeDeclaration(IEnumTypeDeclarationSyntax enumTypeDeclara IxNodeVisitor visitor) { TypeCommAccessibility = eCommAccessibility.None; - + AddToSource($"public enum {enumTypeDeclarationSyntax.Name.Text} {{"); - AddToSource(string.Join("\n,", enumTypeDeclarationSyntax.EnumValues.Select(p => p.Name.Text))); + AddToSource(string.Join("\n,", enumTypeDeclarationSyntax.EnumValueList.EnumValues.Select(p => p.Name.Text))); AddToSource("}"); } @@ -216,9 +226,9 @@ public void CreateNamedValueTypeDeclaration(INamedValueTypeDeclarationSyntax nam INamedValueTypeDeclaration namedValueTypeDeclaration, IxNodeVisitor visitor) { TypeCommAccessibility = eCommAccessibility.None; - + AddToSource( - $"public enum {namedValueTypeDeclarationSyntax.Name.Text} : {namedValueTypeDeclarationSyntax.Type.TransformType()} {{"); + $"public enum {namedValueTypeDeclarationSyntax.Name.Text} : {namedValueTypeDeclarationSyntax.BaseType.TransformType()} {{"); // TODO: Value re-interpretation should be done according to the type. @@ -267,7 +277,7 @@ public void CreateInterfaceDeclaration(IInterfaceDeclarationSyntax interfaceDecl IxNodeVisitor visitor) { TypeCommAccessibility = eCommAccessibility.None; - + AddToSource($"{interfaceDeclaration.AccessModifier.Transform()} partial interface {interfaceDeclaration.Name} {{}}"); } @@ -359,7 +369,7 @@ private void CreateITwinObjectImplementation() "public string HumanReadable { get => string.IsNullOrEmpty(_humanReadable) ? SymbolTail : _humanReadable.Interpolate(this).CleanUpLocalizationTokens(); set => _humanReadable = value; }" + "public System.String GetHumanReadable(System.Globalization.CultureInfo culture) { return this.Translate(_humanReadable, culture); }" + "protected System.String @SymbolTail { get; set;}" + - $"protected {typeof(ITwinObject).n()} @Parent {{ get; set; }}"+ + $"protected {typeof(ITwinObject).n()} @Parent {{ get; set; }}" + $"public AXSharp.Connector.Localizations.Translator Interpreter => global::{Project.TargetProject.ProjectRootNamespace}.PlcTranslator.Instance;" ); } diff --git a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Plain/CsPlainSourceBuilder.cs b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Plain/CsPlainSourceBuilder.cs index 111fd9c3..3e17b1f5 100644 --- a/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Plain/CsPlainSourceBuilder.cs +++ b/src/AXSharp.compiler/src/AXSharp.Cs.Compiler/Plain/CsPlainSourceBuilder.cs @@ -54,7 +54,18 @@ public void CreateClassDeclaration(IClassDeclarationSyntax classDeclarationSynta IxNodeVisitor visitor) { TypeCommAccessibility = classDeclaration.GetCommAccessibility(this); - + + // This is a workaround for abstract classes where semantic model does not contain pragmas even when declared in the source. + if (classDeclarationSyntax.ClassKeyword.FullText.Trim().ToLower().StartsWith("{S7.extern=ReadWrite}".ToLower())) + { + TypeCommAccessibility = eCommAccessibility.ReadWrite; + } + + if (classDeclarationSyntax.ClassKeyword.FullText.Trim().ToLower().StartsWith("{S7.extern=Read}".ToLower())) + { + TypeCommAccessibility = eCommAccessibility.ReadOnly; + } + classDeclarationSyntax.UsingDirectives.ToList().ForEach(p => p.Visit(visitor, this)); AddToSource($"{classDeclaration.AccessModifier.Transform()}partial class {classDeclaration.Name}"); @@ -64,17 +75,17 @@ public void CreateClassDeclaration(IClassDeclarationSyntax classDeclarationSynta if (isExtended) AddToSource($" : {classDeclaration.ExtendedTypeAccesses.FirstOrDefault()?.Type.FullyQualifiedName}"); - - + + AddToSource(isExtended ? ", AXSharp.Connector.IPlain" : ": AXSharp.Connector.IPlain"); AddToSource(classDeclarationSyntax.ImplementsList != null ? ", " : ""); - + classDeclarationSyntax.ImplementsList?.Visit(visitor, this); - + AddToSource("{"); classDeclarationSyntax.UsingDirectives.ToList().ForEach(p => p.Visit(visitor, this)); @@ -107,7 +118,7 @@ public void CreateFieldDeclaration(IFieldDeclaration fieldDeclaration, IxNodeVis AddToSource("[]"); AddToSource($" {fieldDeclaration.Name}"); AddToSource("{get; set;}"); - + AddToSource($"= new"); arrayType.ElementTypeAccess.Type.Accept(visitor, this); AddToSource($"["); @@ -168,14 +179,13 @@ public virtual void CreateNamedValueTypeDeclaration(INamedValueTypeDeclaration n public void CreateFile(IFileSyntax fileSyntax, IxNodeVisitor visitor) { AddToSource("using System;"); - - foreach (var fileSyntaxUsingDirective in + + foreach (var fileSyntaxUsingDirective in fileSyntax.UsingDirectives .Where(p => this.Compilation.GetSemanticTree().Namespaces.Select(p => p.FullyQualifiedName).Contains(p.QualifiedIdentifierList.GetText()))) { AddToSource($"using Pocos.{fileSyntaxUsingDirective.QualifiedIdentifierList.GetText()};"); } - AddToSource("namespace Pocos {"); fileSyntax.Declarations.ToList().ForEach(p => p.Visit(visitor, this)); AddToSource("}"); @@ -187,7 +197,7 @@ public void CreateConfigDeclaration(IConfigDeclarationSyntax configDeclarationSy IxNodeVisitor visitor) { TypeCommAccessibility = eCommAccessibility.None; - + AddToSource($"public partial class {Project.TargetProject.ProjectRootNamespace}TwinController{{"); configurationDeclaration.Variables.ToList().ForEach(p => p.Accept(visitor, this)); AddToSource("}"); @@ -288,7 +298,7 @@ public void CreateVariableDeclaration(IVariableDeclaration fieldDeclaration, IxN break; } } - + } /// diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/AXSharp.Compiler.CsTests.csproj b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/AXSharp.Compiler.CsTests.csproj index 8d500efb..dffc132c 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/AXSharp.Compiler.CsTests.csproj +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/AXSharp.Compiler.CsTests.csproj @@ -61,6 +61,18 @@ + + + PreserveNewest + + + + + + PreserveNewest + + + PreserveNewest diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Cs/CsSourceBuilderTests.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Cs/CsSourceBuilderTests.cs index d7754aab..05c1583b 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Cs/CsSourceBuilderTests.cs +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Cs/CsSourceBuilderTests.cs @@ -284,8 +284,7 @@ public void abstract_members() [Fact] public void generics() { - var memberName = GetMethodName(); - CompareOutputs(memberName); + CompareOutputs(GetMethodName()); } diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs index 32c8a581..0df76e57 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/Integration.Cs/IxProjectTests.IntegrationCs.cs @@ -9,6 +9,7 @@ using AXSharp.Compiler; using AXSharp.Compiler.Cs.Onliner; using AXSharp.Compiler.Cs.Plain; +using Castle.Core.Resource; using Polly; using Xunit.Abstractions; @@ -100,6 +101,8 @@ public void should_match_expected_and_generated_whole_project() if (Directory.Exists(project.OutputFolder)) Directory.Delete(project.OutputFolder, true); + + project.Generate(); var rootSourceFolder = Path.Combine(testFolder, @"samples\units\expected\.g\"); @@ -121,6 +124,7 @@ public void should_match_expected_and_generated_whole_project() var currentIndex = index++; var expectedFileContent = File.ReadAllText(exp); var actualFileContent = File.ReadAllText(actualList[currentIndex]); + try { var actualFileContentLines = actualFileContent.Split("\n").Select(a => a.Trim()).ToArray(); @@ -128,7 +132,7 @@ public void should_match_expected_and_generated_whole_project() for (int i = 0; i < expectedFileContentLines.Length; i++) { - Assert.Equal(expectedFileContentLines[i], actualFileContentLines[i]); + Assert.Equal(expectedFileContentLines[i], actualFileContentLines[i]); } } catch (Exception) diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/Onliners/generics.g.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/Onliners/generics.g.cs new file mode 100644 index 00000000..0aab9689 --- /dev/null +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/Onliners/generics.g.cs @@ -0,0 +1,583 @@ +using System; +using AXSharp.Connector; +using AXSharp.Connector.ValueTypes; +using System.Collections.Generic; +using AXSharp.Connector.Localizations; + +namespace GenericsTests +{ + public partial class Extender : AXSharp.Connector.ITwinObject where TOnline : ITwinObject + { + partial void PreConstruct(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail); + partial void PostConstruct(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail); + public Extender(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail) + { + Symbol = AXSharp.Connector.Connector.CreateSymbol(parent.Symbol, symbolTail); + this.@SymbolTail = symbolTail; + this.@Connector = parent.GetConnector(); + this.@Parent = parent; + HumanReadable = AXSharp.Connector.Connector.CreateHumanReadable(parent.HumanReadable, readableTail); + PreConstruct(parent, readableTail, symbolTail); + parent.AddChild(this); + parent.AddKid(this); + PostConstruct(parent, readableTail, symbolTail); + } + + public async virtual Task OnlineToPlain() + { + return await (dynamic)this.OnlineToPlainAsync(); + } + + public async Task OnlineToPlainAsync() + { + Pocos.GenericsTests.Extender plain = new Pocos.GenericsTests.Extender(); + await this.ReadAsync(); + return plain; + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `OnlineToPlain` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public async Task _OnlineToPlainNoacAsync() + { + Pocos.GenericsTests.Extender plain = new Pocos.GenericsTests.Extender(); + return plain; + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `OnlineToPlain` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + protected async Task _OnlineToPlainNoacAsync(Pocos.GenericsTests.Extender plain) + { + return plain; + } + + public async virtual Task PlainToOnline(T plain) + { + await this.PlainToOnlineAsync((dynamic)plain); + } + + public async Task> PlainToOnlineAsync(Pocos.GenericsTests.Extender plain) + { + return await this.WriteAsync(); + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `PlainToOnline` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public async Task _PlainToOnlineNoacAsync(Pocos.GenericsTests.Extender plain) + { + } + + public async virtual Task ShadowToPlain() + { + return await (dynamic)this.ShadowToPlainAsync(); + } + + public async Task ShadowToPlainAsync() + { + Pocos.GenericsTests.Extender plain = new Pocos.GenericsTests.Extender(); + return plain; + } + + protected async Task ShadowToPlainAsync(Pocos.GenericsTests.Extender plain) + { + return plain; + } + + public async virtual Task PlainToShadow(T plain) + { + await this.PlainToShadowAsync((dynamic)plain); + } + + public async Task> PlainToShadowAsync(Pocos.GenericsTests.Extender plain) + { + return this.RetrievePrimitives(); + } + + /// + public async virtual Task AnyChangeAsync(T plain) + { + return await this.DetectsAnyChangeAsync((dynamic)plain); + } + + /// + ///Compares if the current plain object has changed from the previous object.This method is used by the framework to determine if the object has changed and needs to be updated. + ///[!NOTE] Any member in the hierarchy that is ignored by the compilers (e.g. when CompilerOmitAttribute is used) will not be compared, and therefore will not be detected as changed. + /// + public async Task DetectsAnyChangeAsync(Pocos.GenericsTests.Extender plain, Pocos.GenericsTests.Extender latest = null) + { + if (latest == null) + latest = await this._OnlineToPlainNoacAsync(); + var somethingChanged = false; + return await Task.Run(async () => + { + plain = latest; + return somethingChanged; + }); + } + + public void Poll() + { + this.RetrievePrimitives().ToList().ForEach(x => x.Poll()); + } + + public Pocos.GenericsTests.Extender CreateEmptyPoco() + { + return new Pocos.GenericsTests.Extender(); + } + + private IList Children { get; } = new List(); + public IEnumerable GetChildren() + { + return Children; + } + + private IList Kids { get; } = new List(); + public IEnumerable GetKids() + { + return Kids; + } + + private IList ValueTags { get; } = new List(); + public IEnumerable GetValueTags() + { + return ValueTags; + } + + public void AddValueTag(AXSharp.Connector.ITwinPrimitive valueTag) + { + ValueTags.Add(valueTag); + } + + public void AddKid(AXSharp.Connector.ITwinElement kid) + { + Kids.Add(kid); + } + + public void AddChild(AXSharp.Connector.ITwinObject twinObject) + { + Children.Add(twinObject); + } + + protected AXSharp.Connector.Connector @Connector { get; } + + public AXSharp.Connector.Connector GetConnector() + { + return this.@Connector; + } + + public string GetSymbolTail() + { + return this.SymbolTail; + } + + public AXSharp.Connector.ITwinObject GetParent() + { + return this.@Parent; + } + + public string Symbol { get; protected set; } + + private string _attributeName; + public System.String AttributeName { get => string.IsNullOrEmpty(_attributeName) ? SymbolTail : _attributeName.Interpolate(this).CleanUpLocalizationTokens(); set => _attributeName = value; } + + public System.String GetAttributeName(System.Globalization.CultureInfo culture) + { + return this.Translate(_attributeName, culture).Interpolate(this); + } + + private string _humanReadable; + public string HumanReadable { get => string.IsNullOrEmpty(_humanReadable) ? SymbolTail : _humanReadable.Interpolate(this).CleanUpLocalizationTokens(); set => _humanReadable = value; } + + public System.String GetHumanReadable(System.Globalization.CultureInfo culture) + { + return this.Translate(_humanReadable, culture); + } + + protected System.String @SymbolTail { get; set; } + + protected AXSharp.Connector.ITwinObject @Parent { get; set; } + + public AXSharp.Connector.Localizations.Translator Interpreter => global::units.PlcTranslator.Instance; + } + + public partial class SomeTypeToBeGeneric : AXSharp.Connector.ITwinObject + { + public OnlinerBool Boolean { get; } + + public OnlinerInt Cele { get; } + + partial void PreConstruct(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail); + partial void PostConstruct(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail); + public SomeTypeToBeGeneric(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail) + { + Symbol = AXSharp.Connector.Connector.CreateSymbol(parent.Symbol, symbolTail); + this.@SymbolTail = symbolTail; + this.@Connector = parent.GetConnector(); + this.@Parent = parent; + HumanReadable = AXSharp.Connector.Connector.CreateHumanReadable(parent.HumanReadable, readableTail); + PreConstruct(parent, readableTail, symbolTail); + Boolean = @Connector.ConnectorAdapter.AdapterFactory.CreateBOOL(this, "Boolean", "Boolean"); + Cele = @Connector.ConnectorAdapter.AdapterFactory.CreateINT(this, "Cele", "Cele"); + parent.AddChild(this); + parent.AddKid(this); + PostConstruct(parent, readableTail, symbolTail); + } + + public async virtual Task OnlineToPlain() + { + return await (dynamic)this.OnlineToPlainAsync(); + } + + public async Task OnlineToPlainAsync() + { + Pocos.GenericsTests.SomeTypeToBeGeneric plain = new Pocos.GenericsTests.SomeTypeToBeGeneric(); + await this.ReadAsync(); + plain.Boolean = Boolean.LastValue; + plain.Cele = Cele.LastValue; + return plain; + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `OnlineToPlain` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public async Task _OnlineToPlainNoacAsync() + { + Pocos.GenericsTests.SomeTypeToBeGeneric plain = new Pocos.GenericsTests.SomeTypeToBeGeneric(); + plain.Boolean = Boolean.LastValue; + plain.Cele = Cele.LastValue; + return plain; + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `OnlineToPlain` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + protected async Task _OnlineToPlainNoacAsync(Pocos.GenericsTests.SomeTypeToBeGeneric plain) + { + plain.Boolean = Boolean.LastValue; + plain.Cele = Cele.LastValue; + return plain; + } + + public async virtual Task PlainToOnline(T plain) + { + await this.PlainToOnlineAsync((dynamic)plain); + } + + public async Task> PlainToOnlineAsync(Pocos.GenericsTests.SomeTypeToBeGeneric plain) + { +#pragma warning disable CS0612 + Boolean.LethargicWrite(plain.Boolean); +#pragma warning restore CS0612 +#pragma warning disable CS0612 + Cele.LethargicWrite(plain.Cele); +#pragma warning restore CS0612 + return await this.WriteAsync(); + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `PlainToOnline` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public async Task _PlainToOnlineNoacAsync(Pocos.GenericsTests.SomeTypeToBeGeneric plain) + { +#pragma warning disable CS0612 + Boolean.LethargicWrite(plain.Boolean); +#pragma warning restore CS0612 +#pragma warning disable CS0612 + Cele.LethargicWrite(plain.Cele); +#pragma warning restore CS0612 + } + + public async virtual Task ShadowToPlain() + { + return await (dynamic)this.ShadowToPlainAsync(); + } + + public async Task ShadowToPlainAsync() + { + Pocos.GenericsTests.SomeTypeToBeGeneric plain = new Pocos.GenericsTests.SomeTypeToBeGeneric(); + plain.Boolean = Boolean.Shadow; + plain.Cele = Cele.Shadow; + return plain; + } + + protected async Task ShadowToPlainAsync(Pocos.GenericsTests.SomeTypeToBeGeneric plain) + { + plain.Boolean = Boolean.Shadow; + plain.Cele = Cele.Shadow; + return plain; + } + + public async virtual Task PlainToShadow(T plain) + { + await this.PlainToShadowAsync((dynamic)plain); + } + + public async Task> PlainToShadowAsync(Pocos.GenericsTests.SomeTypeToBeGeneric plain) + { + Boolean.Shadow = plain.Boolean; + Cele.Shadow = plain.Cele; + return this.RetrievePrimitives(); + } + + /// + public async virtual Task AnyChangeAsync(T plain) + { + return await this.DetectsAnyChangeAsync((dynamic)plain); + } + + /// + ///Compares if the current plain object has changed from the previous object.This method is used by the framework to determine if the object has changed and needs to be updated. + ///[!NOTE] Any member in the hierarchy that is ignored by the compilers (e.g. when CompilerOmitAttribute is used) will not be compared, and therefore will not be detected as changed. + /// + public async Task DetectsAnyChangeAsync(Pocos.GenericsTests.SomeTypeToBeGeneric plain, Pocos.GenericsTests.SomeTypeToBeGeneric latest = null) + { + if (latest == null) + latest = await this._OnlineToPlainNoacAsync(); + var somethingChanged = false; + return await Task.Run(async () => + { + if (plain.Boolean != Boolean.LastValue) + somethingChanged = true; + if (plain.Cele != Cele.LastValue) + somethingChanged = true; + plain = latest; + return somethingChanged; + }); + } + + public void Poll() + { + this.RetrievePrimitives().ToList().ForEach(x => x.Poll()); + } + + public Pocos.GenericsTests.SomeTypeToBeGeneric CreateEmptyPoco() + { + return new Pocos.GenericsTests.SomeTypeToBeGeneric(); + } + + private IList Children { get; } = new List(); + public IEnumerable GetChildren() + { + return Children; + } + + private IList Kids { get; } = new List(); + public IEnumerable GetKids() + { + return Kids; + } + + private IList ValueTags { get; } = new List(); + public IEnumerable GetValueTags() + { + return ValueTags; + } + + public void AddValueTag(AXSharp.Connector.ITwinPrimitive valueTag) + { + ValueTags.Add(valueTag); + } + + public void AddKid(AXSharp.Connector.ITwinElement kid) + { + Kids.Add(kid); + } + + public void AddChild(AXSharp.Connector.ITwinObject twinObject) + { + Children.Add(twinObject); + } + + protected AXSharp.Connector.Connector @Connector { get; } + + public AXSharp.Connector.Connector GetConnector() + { + return this.@Connector; + } + + public string GetSymbolTail() + { + return this.SymbolTail; + } + + public AXSharp.Connector.ITwinObject GetParent() + { + return this.@Parent; + } + + public string Symbol { get; protected set; } + + private string _attributeName; + public System.String AttributeName { get => string.IsNullOrEmpty(_attributeName) ? SymbolTail : _attributeName.Interpolate(this).CleanUpLocalizationTokens(); set => _attributeName = value; } + + public System.String GetAttributeName(System.Globalization.CultureInfo culture) + { + return this.Translate(_attributeName, culture).Interpolate(this); + } + + private string _humanReadable; + public string HumanReadable { get => string.IsNullOrEmpty(_humanReadable) ? SymbolTail : _humanReadable.Interpolate(this).CleanUpLocalizationTokens(); set => _humanReadable = value; } + + public System.String GetHumanReadable(System.Globalization.CultureInfo culture) + { + return this.Translate(_humanReadable, culture); + } + + protected System.String @SymbolTail { get; set; } + + protected AXSharp.Connector.ITwinObject @Parent { get; set; } + + public AXSharp.Connector.Localizations.Translator Interpreter => global::units.PlcTranslator.Instance; + } + + public partial class Extendee2 : GenericsTests.Extender + { + [AXOpen.Data.AxoDataEntityAttribute] + [Container(Layout.Stack)] + public GenericsTests.SomeTypeToBeGeneric SomeData { get; } + + partial void PreConstruct(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail); + partial void PostConstruct(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail); + public Extendee2(AXSharp.Connector.ITwinObject parent, string readableTail, string symbolTail) : base(parent, readableTail, symbolTail) + { + Symbol = AXSharp.Connector.Connector.CreateSymbol(parent.Symbol, symbolTail); + PreConstruct(parent, readableTail, symbolTail); + SomeData = new GenericsTests.SomeTypeToBeGeneric(this, "Shared Header", "SomeData"); + SomeData.AttributeName = "Shared Header"; + PostConstruct(parent, readableTail, symbolTail); + } + + public async override Task OnlineToPlain() + { + return await (dynamic)this.OnlineToPlainAsync(); + } + + public new async Task OnlineToPlainAsync() + { + Pocos.GenericsTests.Extendee2 plain = new Pocos.GenericsTests.Extendee2(); + await this.ReadAsync(); +#pragma warning disable CS0612 + await base._OnlineToPlainNoacAsync(plain); +#pragma warning restore CS0612 +#pragma warning disable CS0612 + plain.SomeData = await SomeData._OnlineToPlainNoacAsync(); +#pragma warning restore CS0612 + return plain; + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `OnlineToPlain` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public new async Task _OnlineToPlainNoacAsync() + { + Pocos.GenericsTests.Extendee2 plain = new Pocos.GenericsTests.Extendee2(); +#pragma warning disable CS0612 + await base._OnlineToPlainNoacAsync(plain); +#pragma warning restore CS0612 +#pragma warning disable CS0612 + plain.SomeData = await SomeData._OnlineToPlainNoacAsync(); +#pragma warning restore CS0612 + return plain; + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `OnlineToPlain` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + protected async Task _OnlineToPlainNoacAsync(Pocos.GenericsTests.Extendee2 plain) + { +#pragma warning disable CS0612 + await base._OnlineToPlainNoacAsync(plain); +#pragma warning restore CS0612 +#pragma warning disable CS0612 + plain.SomeData = await SomeData._OnlineToPlainNoacAsync(); +#pragma warning restore CS0612 + return plain; + } + + public async override Task PlainToOnline(T plain) + { + await this.PlainToOnlineAsync((dynamic)plain); + } + + public async Task> PlainToOnlineAsync(Pocos.GenericsTests.Extendee2 plain) + { + await base._PlainToOnlineNoacAsync(plain); +#pragma warning disable CS0612 + await this.SomeData._PlainToOnlineNoacAsync(plain.SomeData); +#pragma warning restore CS0612 + return await this.WriteAsync(); + } + + [Obsolete("This method should not be used if you indent to access the controllers data. Use `PlainToOnline` instead.")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public async Task _PlainToOnlineNoacAsync(Pocos.GenericsTests.Extendee2 plain) + { + await base._PlainToOnlineNoacAsync(plain); +#pragma warning disable CS0612 + await this.SomeData._PlainToOnlineNoacAsync(plain.SomeData); +#pragma warning restore CS0612 + } + + public async override Task ShadowToPlain() + { + return await (dynamic)this.ShadowToPlainAsync(); + } + + public new async Task ShadowToPlainAsync() + { + Pocos.GenericsTests.Extendee2 plain = new Pocos.GenericsTests.Extendee2(); + await base.ShadowToPlainAsync(plain); + plain.SomeData = await SomeData.ShadowToPlainAsync(); + return plain; + } + + protected async Task ShadowToPlainAsync(Pocos.GenericsTests.Extendee2 plain) + { + await base.ShadowToPlainAsync(plain); + plain.SomeData = await SomeData.ShadowToPlainAsync(); + return plain; + } + + public async override Task PlainToShadow(T plain) + { + await this.PlainToShadowAsync((dynamic)plain); + } + + public async Task> PlainToShadowAsync(Pocos.GenericsTests.Extendee2 plain) + { + await base.PlainToShadowAsync(plain); + await this.SomeData.PlainToShadowAsync(plain.SomeData); + return this.RetrievePrimitives(); + } + + /// + public async override Task AnyChangeAsync(T plain) + { + return await this.DetectsAnyChangeAsync((dynamic)plain); + } + + /// + ///Compares if the current plain object has changed from the previous object.This method is used by the framework to determine if the object has changed and needs to be updated. + ///[!NOTE] Any member in the hierarchy that is ignored by the compilers (e.g. when CompilerOmitAttribute is used) will not be compared, and therefore will not be detected as changed. + /// + public new async Task DetectsAnyChangeAsync(Pocos.GenericsTests.Extendee2 plain, Pocos.GenericsTests.Extendee2 latest = null) + { + if (latest == null) + latest = await this._OnlineToPlainNoacAsync(); + var somethingChanged = false; + return await Task.Run(async () => + { + if (await base.DetectsAnyChangeAsync(plain)) + return true; + if (await SomeData.DetectsAnyChangeAsync(plain.SomeData, latest.SomeData)) + somethingChanged = true; + plain = latest; + return somethingChanged; + }); + } + + public new void Poll() + { + this.RetrievePrimitives().ToList().ForEach(x => x.Poll()); + } + + public new Pocos.GenericsTests.Extendee2 CreateEmptyPoco() + { + return new Pocos.GenericsTests.Extendee2(); + } + } +} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/POCO/generics.g.cs b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/POCO/generics.g.cs new file mode 100644 index 00000000..cace0f96 --- /dev/null +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/expected/.g/POCO/generics.g.cs @@ -0,0 +1,23 @@ +using System; + +namespace Pocos +{ + namespace GenericsTests + { + public partial class Extender : AXSharp.Connector.IPlain + { + } + + public partial class SomeTypeToBeGeneric : AXSharp.Connector.IPlain + { + public Boolean Boolean { get; set; } + + public Int16 Cele { get; set; } + } + + public partial class Extendee2 : GenericsTests.Extender, AXSharp.Connector.IPlain + { + public GenericsTests.SomeTypeToBeGeneric SomeData { get; set; } = new GenericsTests.SomeTypeToBeGeneric(); + } + } +} \ No newline at end of file diff --git a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/src/generics.st b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/src/generics.st index 32d49323..24aae06d 100644 --- a/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/src/generics.st +++ b/src/AXSharp.compiler/tests/AXSharp.Compiler.CsTests/samples/units/src/generics.st @@ -1,17 +1,20 @@ // GENERIC -NAMESPACE Generics +NAMESPACE GenericsTests {#ix-generic: where TOnline : ITwinObject} + {S7.extern=ReadWrite} CLASS PUBLIC Extender END_CLASS - CLASS SomeType + {S7.extern=ReadWrite} + CLASS PUBLIC SomeTypeToBeGeneric VAR PUBLIC Boolean : BOOL; Cele : INT; END_VAR END_CLASS + {S7.extern=ReadWrite} CLASS PUBLIC Extendee2 EXTENDS Extender VAR PUBLIC {#ix-generic:TOnline} @@ -19,7 +22,7 @@ NAMESPACE Generics {#ix-attr:[AXOpen.Data.AxoDataEntityAttribute]} {#ix-attr:[Container(Layout.Stack)]} {#ix-set:AttributeName = "Shared Header"} - SomeType : SomeType; + SomeData : SomeTypeToBeGeneric; END_VAR END_CLASS END_NAMESPACE \ No newline at end of file diff --git a/src/sanbox/integration/ix-integration-plc/ix/.g/Onliners/configuration.g.cs b/src/sanbox/integration/ix-integration-plc/ix/.g/Onliners/configuration.g.cs index 2ff7d06d..afe0ad8f 100644 --- a/src/sanbox/integration/ix-integration-plc/ix/.g/Onliners/configuration.g.cs +++ b/src/sanbox/integration/ix-integration-plc/ix/.g/Onliners/configuration.g.cs @@ -3,6 +3,7 @@ using AXSharp.Connector.ValueTypes; using System.Collections.Generic; using AXSharp.Connector.Localizations; +using MonsterData; public partial class ix_integration_plcTwinController : ITwinController { diff --git a/src/sanbox/integration/ix-integration-plc/ix/.g/POCO/configuration.g.cs b/src/sanbox/integration/ix-integration-plc/ix/.g/POCO/configuration.g.cs index 200a8736..8496ba66 100644 --- a/src/sanbox/integration/ix-integration-plc/ix/.g/POCO/configuration.g.cs +++ b/src/sanbox/integration/ix-integration-plc/ix/.g/POCO/configuration.g.cs @@ -1,4 +1,5 @@ using System; +using Pocos.MonsterData; namespace Pocos { diff --git a/src/tests.integrations/integrated/src/integrated.twin/.g/Onliners/configuration.g.cs b/src/tests.integrations/integrated/src/integrated.twin/.g/Onliners/configuration.g.cs index b261e984..08151d29 100644 --- a/src/tests.integrations/integrated/src/integrated.twin/.g/Onliners/configuration.g.cs +++ b/src/tests.integrations/integrated/src/integrated.twin/.g/Onliners/configuration.g.cs @@ -3,6 +3,7 @@ using AXSharp.Connector.ValueTypes; using System.Collections.Generic; using AXSharp.Connector.Localizations; +using RealMonsterData; public partial class integratedTwinController : ITwinController { diff --git a/src/tests.integrations/integrated/src/integrated.twin/.g/POCO/configuration.g.cs b/src/tests.integrations/integrated/src/integrated.twin/.g/POCO/configuration.g.cs index 423b45b7..cdea574d 100644 --- a/src/tests.integrations/integrated/src/integrated.twin/.g/POCO/configuration.g.cs +++ b/src/tests.integrations/integrated/src/integrated.twin/.g/POCO/configuration.g.cs @@ -1,4 +1,5 @@ using System; +using Pocos.RealMonsterData; namespace Pocos { diff --git a/templates/working/templates/axsharpblazor/axsharpblazor.twin/axsharpblazor.csproj b/templates/working/templates/axsharpblazor/axsharpblazor.twin/axsharpblazor.csproj new file mode 100644 index 00000000..6e9cb742 --- /dev/null +++ b/templates/working/templates/axsharpblazor/axsharpblazor.twin/axsharpblazor.csproj @@ -0,0 +1,21 @@ + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + \ No newline at end of file