Skip to content

Commit f2d35e2

Browse files
[WIP] First draft of Code-Gen
1 parent d502688 commit f2d35e2

File tree

176 files changed

+10613
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

176 files changed

+10613
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// -------------------------------------------------------------------------------------------------
2+
// <copyright file="UmlCoreTextualNotationBuilderGeneratorTestFixture.cs" company="Starion Group S.A.">
3+
//
4+
// Copyright 2022-2026 Starion Group S.A.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// </copyright>
19+
// ------------------------------------------------------------------------------------------------
20+
21+
namespace SysML2.NET.CodeGenerator.Tests.Generators.UmlHandleBarsGenerators
22+
{
23+
using System.IO;
24+
using System.Linq;
25+
using System.Threading.Tasks;
26+
27+
using NUnit.Framework;
28+
29+
using SysML2.NET.CodeGenerator.Generators.UmlHandleBarsGenerators;
30+
using SysML2.NET.CodeGenerator.Grammar;
31+
using SysML2.NET.CodeGenerator.Grammar.Model;
32+
33+
[TestFixture]
34+
public class UmlCoreTextualNotationBuilderGeneratorTestFixture
35+
{
36+
private DirectoryInfo umlPocoDirectoryInfo;
37+
private UmlCoreTextualNotationBuilderGenerator umlCoreTextualNotationBuilderGenerator;
38+
private TextualNotationSpecification textualNotationSpecification;
39+
40+
[OneTimeSetUp]
41+
public void OneTimeSetup()
42+
{
43+
var directoryInfo = new DirectoryInfo(TestContext.CurrentContext.TestDirectory);
44+
45+
var path = Path.Combine("UML", "_SysML2.NET.Core.UmlCoreTextualNotationBuilderGenerator");
46+
47+
this.umlPocoDirectoryInfo = directoryInfo.CreateSubdirectory(path);
48+
this.umlCoreTextualNotationBuilderGenerator = new UmlCoreTextualNotationBuilderGenerator();
49+
50+
var textualRulesFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "datamodel");
51+
var kermlRules = GrammarLoader.LoadTextualNotationSpecification(Path.Combine(textualRulesFolder, "KerML-textual-bnf.kebnf"));
52+
var sysmlRules = GrammarLoader.LoadTextualNotationSpecification(Path.Combine(textualRulesFolder, "SysML-textual-bnf.kebnf"));
53+
54+
var combinesRules = new TextualNotationSpecification();
55+
combinesRules.Rules.AddRange(sysmlRules.Rules);
56+
57+
foreach (var rule in kermlRules.Rules.Where(rule => combinesRules.Rules.All(r => r.RuleName != rule.RuleName)))
58+
{
59+
combinesRules.Rules.Add(rule);
60+
}
61+
62+
this.textualNotationSpecification = combinesRules;
63+
}
64+
65+
[Test]
66+
public async Task VerifyCanGenerateTextualNotation()
67+
{
68+
await Assert.ThatAsync(() => this.umlCoreTextualNotationBuilderGenerator.GenerateAsync(GeneratorSetupFixture.XmiReaderResult, this.textualNotationSpecification, this.umlPocoDirectoryInfo), Throws.Nothing);
69+
}
70+
}
71+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// -------------------------------------------------------------------------------------------------
2+
// <copyright file="UmlCoreTextualNotationBuilderGenerator.cs" company="Starion Group S.A.">
3+
//
4+
// Copyright 2022-2026 Starion Group S.A.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// </copyright>
19+
// ------------------------------------------------------------------------------------------------
20+
21+
namespace SysML2.NET.CodeGenerator.Generators.UmlHandleBarsGenerators
22+
{
23+
using System;
24+
using System.IO;
25+
using System.Linq;
26+
using System.Threading.Tasks;
27+
28+
using SysML2.NET.CodeGenerator.Extensions;
29+
using SysML2.NET.CodeGenerator.Grammar.Model;
30+
31+
using uml4net.Extensions;
32+
using uml4net.HandleBars;
33+
using uml4net.StructuredClassifiers;
34+
using uml4net.xmi.Readers;
35+
36+
using NamedElementHelper = SysML2.NET.CodeGenerator.HandleBarHelpers.NamedElementHelper;
37+
38+
/// <summary>
39+
/// An <see cref="UmlHandleBarsGenerator"/> to generate Textual Notation Builder
40+
/// </summary>
41+
public class UmlCoreTextualNotationBuilderGenerator: UmlHandleBarsGenerator
42+
{
43+
/// <summary>
44+
/// Gets the name of template for builder classes
45+
/// </summary>
46+
private const string BuilderTemplateName = "core-textual-notation-builder-template";
47+
48+
/// <summary>
49+
/// Gets the name of template for builder facade class
50+
/// </summary>
51+
private const string BuilderFacadeTemplateName = "core-textual-notation-builder-facade-template";
52+
53+
/// <summary>
54+
/// Register the custom helpers
55+
/// </summary>
56+
protected override void RegisterHelpers()
57+
{
58+
NamedElementHelper.RegisterNamedElementHelper(this.Handlebars);
59+
this.Handlebars.RegisterStringHelper();
60+
}
61+
62+
/// <summary>
63+
/// Register the code templates
64+
/// </summary>
65+
protected override void RegisterTemplates()
66+
{
67+
this.RegisterTemplate(BuilderTemplateName);
68+
this.RegisterTemplate(BuilderFacadeTemplateName);
69+
}
70+
71+
/// <summary>
72+
/// Generates code specific to the concrete implementation
73+
/// </summary>
74+
/// <param name="xmiReaderResult">
75+
/// the <see cref="XmiReaderResult"/> that contains the UML model to generate from
76+
/// </param>
77+
/// <param name="outputDirectory">
78+
/// The target <see cref="DirectoryInfo"/>
79+
/// </param>
80+
/// <exception cref="NotSupportedException">This method cannot be used since it requires to have <see cref="TextualNotationSpecification"/>. Uses <see cref="GenerateAsync(uml4net.xmi.Readers.XmiReaderResult,TextualNotationSpecification, System.IO.DirectoryInfo)"/></exception>
81+
/// <returns>
82+
/// an awaitable <see cref="Task"/>
83+
/// </returns>
84+
public override Task GenerateAsync(XmiReaderResult xmiReaderResult, DirectoryInfo outputDirectory)
85+
{
86+
throw new NotSupportedException("The generator needs TextualNotationSpecification access");
87+
}
88+
89+
/// <summary>
90+
/// Generates code specific to the concrete implementation
91+
/// </summary>
92+
/// <param name="xmiReaderResult">
93+
/// the <see cref="XmiReaderResult"/> that contains the UML model to generate from
94+
/// </param>
95+
/// <param name="textualNotationSpecification">The <see cref="TextualNotationSpecification"/> that contains specific grammar rules to produce textual notation</param>
96+
/// <param name="outputDirectory">
97+
/// The target <see cref="DirectoryInfo"/>
98+
/// </param>
99+
/// <returns>
100+
/// an awaitable <see cref="Task"/>
101+
/// </returns>
102+
public async Task GenerateAsync(XmiReaderResult xmiReaderResult, TextualNotationSpecification textualNotationSpecification, DirectoryInfo outputDirectory)
103+
{
104+
await this.GenerateBuilderClasses(xmiReaderResult, textualNotationSpecification, outputDirectory);
105+
await this.GenerateBuilderFacade(xmiReaderResult, outputDirectory);
106+
}
107+
108+
/// <summary>
109+
/// Generates Textual Notation builder classes for each concrete <see cref="IClass"/>
110+
/// </summary>
111+
/// <param name="xmiReaderResult">
112+
/// the <see cref="XmiReaderResult"/> that contains the UML model to generate from
113+
/// </param>
114+
/// <param name="textualNotationSpecification">The <see cref="TextualNotationSpecification"/> that contains specific grammar rules to produce textual notation</param>
115+
/// <param name="outputDirectory">
116+
/// The target <see cref="DirectoryInfo"/>
117+
/// </param>
118+
/// <exception cref="ArgumentNullException">If one of the given parameters is null</exception>
119+
/// <returns>
120+
/// an awaitable <see cref="Task"/>
121+
/// </returns>
122+
private Task GenerateBuilderClasses(XmiReaderResult xmiReaderResult, TextualNotationSpecification textualNotationSpecification, DirectoryInfo outputDirectory)
123+
{
124+
ArgumentNullException.ThrowIfNull(xmiReaderResult);
125+
ArgumentNullException.ThrowIfNull(textualNotationSpecification);
126+
ArgumentNullException.ThrowIfNull(outputDirectory);
127+
128+
return this.GenerateBuilderClassesInternal(xmiReaderResult, textualNotationSpecification, outputDirectory);
129+
}
130+
131+
/// <summary>
132+
/// Generates Textual Notation builder classes for each concrete <see cref="IClass"/>
133+
/// </summary>
134+
/// <param name="xmiReaderResult">
135+
/// the <see cref="XmiReaderResult"/> that contains the UML model to generate from
136+
/// </param>
137+
/// <param name="textualNotationSpecification">The <see cref="TextualNotationSpecification"/> that contains specific grammar rules to produce textual notation</param>
138+
/// <param name="outputDirectory">
139+
/// The target <see cref="DirectoryInfo"/>
140+
/// </param>
141+
/// <returns>
142+
/// an awaitable <see cref="Task"/>
143+
/// </returns>
144+
private async Task GenerateBuilderClassesInternal(XmiReaderResult xmiReaderResult, TextualNotationSpecification textualNotationSpecification, DirectoryInfo outputDirectory)
145+
{
146+
var template = this.Templates[BuilderTemplateName];
147+
148+
var classes = xmiReaderResult.QueryContainedAndImported("SysML")
149+
.SelectMany(x => x.PackagedElement.OfType<IClass>())
150+
.Where(x => !x.IsAbstract)
151+
.ToList();
152+
153+
foreach (var umlClass in classes)
154+
{
155+
var generatedBuilder = template(umlClass);
156+
generatedBuilder = this.CodeCleanup(generatedBuilder);
157+
158+
var fileName = $"{umlClass.Name.CapitalizeFirstLetter()}TextualNotationBuilder.cs";
159+
160+
await WriteAsync(generatedBuilder, outputDirectory, fileName);
161+
}
162+
}
163+
164+
/// <summary>
165+
/// Generates the Textual Notation builder facade
166+
/// </summary>
167+
/// <param name="xmiReaderResult">the <see cref="XmiReaderResult"/> that contains the UML model to generate from</param>
168+
/// <param name="outputDirectory">The target <see cref="DirectoryInfo"/></param>
169+
/// <exception cref="ArgumentNullException">If one of the given parameters is null</exception>
170+
/// <returns>an awaitable <see cref="Task"/></returns>
171+
private Task GenerateBuilderFacade(XmiReaderResult xmiReaderResult, DirectoryInfo outputDirectory)
172+
{
173+
ArgumentNullException.ThrowIfNull(xmiReaderResult);
174+
ArgumentNullException.ThrowIfNull(outputDirectory);
175+
return this.GenerateBuilderFacadeInternal(xmiReaderResult, outputDirectory);
176+
}
177+
178+
/// <summary>
179+
/// Generates the Textual Notation builder facade
180+
/// </summary>
181+
/// <param name="xmiReaderResult">the <see cref="XmiReaderResult"/> that contains the UML model to generate from</param>
182+
/// <param name="outputDirectory">The target <see cref="DirectoryInfo"/></param>
183+
/// <returns>an awaitable <see cref="Task"/></returns>
184+
private async Task GenerateBuilderFacadeInternal(XmiReaderResult xmiReaderResult, DirectoryInfo outputDirectory)
185+
{
186+
var template = this.Templates[BuilderFacadeTemplateName];
187+
188+
var classes = xmiReaderResult.QueryContainedAndImported("SysML")
189+
.SelectMany(x => x.PackagedElement.OfType<IClass>())
190+
.Where(x => !x.IsAbstract)
191+
.ToList();
192+
193+
var generatedFacade = template(classes);
194+
generatedFacade = this.CodeCleanup(generatedFacade);
195+
196+
await WriteAsync(generatedFacade, outputDirectory, "TextualNotationBuilderFacade.cs");
197+
}
198+
}
199+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// -------------------------------------------------------------------------------------------------
2+
// <copyright file="GrammarLoader.cs" company="Starion Group S.A.">
3+
//
4+
// Copyright 2022-2026 Starion Group S.A.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// </copyright>
19+
// ------------------------------------------------------------------------------------------------
20+
21+
namespace SysML2.NET.CodeGenerator.Grammar
22+
{
23+
using System.IO;
24+
25+
using Antlr4.Runtime;
26+
27+
using SysML2.NET.CodeGenerator.Grammar.Model;
28+
29+
/// <summary>
30+
/// Provides direct access to <see cref="TextualNotationSpecification"/> by providing file path
31+
/// </summary>
32+
public static class GrammarLoader
33+
{
34+
/// <summary>
35+
/// Loads the <see cref="TextualNotationSpecification" />
36+
/// </summary>
37+
/// <param name="fileUri">The string uri that locates the KEBNF file to load</param>
38+
/// <returns>The loaded <see cref="TextualNotationSpecification"/></returns>
39+
/// <exception cref="FileNotFoundException">If the <paramref name="fileUri"/> does not locate an existing <see cref="File"/></exception>
40+
public static TextualNotationSpecification LoadTextualNotationSpecification(string fileUri)
41+
{
42+
if (!File.Exists(fileUri))
43+
{
44+
throw new FileNotFoundException("File not found", fileUri);
45+
}
46+
47+
var stream = CharStreams.fromPath(fileUri);
48+
var lexer = new kebnfLexer(stream);
49+
var tokens = new CommonTokenStream(lexer);
50+
var parser = new kebnfParser(tokens);
51+
52+
var tree = parser.specification();
53+
var explorer = new TextualNotationSpecificationVisitor();
54+
return (TextualNotationSpecification)explorer.Visit(tree);
55+
}
56+
}
57+
}

SysML2.NET.CodeGenerator/SysML2.NET.CodeGenerator.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@
212212
<None Update="Templates\Uml\core-poco-reference-resolve-extension-facade-template.hbs">
213213
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
214214
</None>
215+
<None Update="Templates\Uml\core-textual-notation-builder-template.hbs">
216+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
217+
</None>
218+
<None Update="Templates\Uml\core-textual-notation-builder-facade-template.hbs">
219+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
220+
</None>
215221
</ItemGroup>
216222
<ItemGroup>
217223
<Folder Include="Resources\HtmlDocs\" />

0 commit comments

Comments
 (0)