diff --git a/src/bgen/CodeBlocks/BlockContainer.cs b/src/bgen/CodeBlocks/BlockContainer.cs new file mode 100644 index 000000000000..cba0b428af79 --- /dev/null +++ b/src/bgen/CodeBlocks/BlockContainer.cs @@ -0,0 +1,11 @@ +using System.IO; + +public class BlockContainer : CodeBlock { + public override void Print (TextWriter writer) + { + foreach (ICodeBlock block in Blocks) { + block.SetIndent (CurrentIndent); + block.Print (writer); + } + } +} diff --git a/src/bgen/CodeBlocks/CodeBlock.cs b/src/bgen/CodeBlocks/CodeBlock.cs new file mode 100644 index 000000000000..e685c3ec48c1 --- /dev/null +++ b/src/bgen/CodeBlocks/CodeBlock.cs @@ -0,0 +1,108 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; + +public class CodeBlock : ICodeBlock, IEnumerable { + protected int CurrentIndent = 0; + protected int Indent = 4; + protected string HeaderText = string.Empty; + protected List Blocks = new (); + protected const char StartBrace = '{'; + protected const char EndBrace = '}'; + protected const char NewLine = '\n'; + + public CodeBlock () { } + + public CodeBlock (string text) + { + HeaderText = text; + } + + public CodeBlock (string text, IList blocks) + { + Blocks.AddRange (blocks); + HeaderText = text; + } + + public CodeBlock (IList blocks) + { + Blocks.AddRange (blocks); + } + + public CodeBlock (string headerText, params string [] lines) + { + HeaderText = headerText; + foreach (string line in lines) { + Blocks.Add (new LineBlock (line)); + } + } + + public CodeBlock (params string [] lines) + { + foreach (string line in lines) { + Blocks.Add (new LineBlock (line)); + } + } + + public void Add (ICodeBlock block) + { + block.SetIndent (CurrentIndent + Indent); + Blocks.Add (block); + } + + public void Add (string text) + { + LineBlock line = new LineBlock (text); + line.SetIndent (CurrentIndent + Indent); + Blocks.Add (line); + } + + public void AddLine (string text) + { + LineBlock line = new LineBlock (text); + line.SetIndent (CurrentIndent + Indent); + Blocks.Add (line); + } + + protected void WriteIndent (TextWriter writer) + { + for (var i = 0; i < CurrentIndent; i++) + writer.Write (' '); + } + + protected virtual void WriteHeaderText (TextWriter writer) + { + WriteIndent (writer); + writer.Write (HeaderText); + writer.Write (NewLine); + } + + public virtual void Print (TextWriter writer) + { + if (HeaderText != string.Empty) + WriteHeaderText (writer); + + WriteIndent (writer); + writer.Write (StartBrace); + writer.Write (NewLine); + + SetIndent (CurrentIndent + Indent); + foreach (ICodeBlock block in Blocks) { + block.SetIndent (CurrentIndent); + block.Print (writer); + } + SetIndent (CurrentIndent - Indent); + + WriteIndent (writer); + writer.Write (EndBrace); + writer.Write (NewLine); + } + + public void SetIndent (int indent) + { + CurrentIndent = indent; + } + + public IEnumerator GetEnumerator () => Blocks.GetEnumerator (); + IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); +} diff --git a/src/bgen/CodeBlocks/ICodeBlock.cs b/src/bgen/CodeBlocks/ICodeBlock.cs new file mode 100644 index 000000000000..474e7f8ea8b0 --- /dev/null +++ b/src/bgen/CodeBlocks/ICodeBlock.cs @@ -0,0 +1,7 @@ +using System.IO; + +public interface ICodeBlock { + public void Print (TextWriter writer); + public void SetIndent (int indent); +} + diff --git a/src/bgen/CodeBlocks/IfBlock.cs b/src/bgen/CodeBlocks/IfBlock.cs new file mode 100644 index 000000000000..89123ea39ea9 --- /dev/null +++ b/src/bgen/CodeBlocks/IfBlock.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; +using System.IO; + +public class IfBlock : CodeBlock { + List ElseIfBlocks = new (); + CodeBlock? ElseBlock = null; + public IfBlock (string condition) + { + HeaderText = condition; + } + + public IfBlock (string condition, List blocks) + { + HeaderText = condition; + Blocks.AddRange (blocks); + } + + public IfBlock (string condition, params string [] lines) + { + HeaderText = condition; + Blocks.AddRange (new CodeBlock (lines)); + } + + public IfBlock AddElseIf (string condition, List blocks) + { + ElseIfBlocks.Add (new IfBlock (condition, blocks)); + return this; + } + + public IfBlock AddElseIf (string condition, params string [] lines) + { + ElseIfBlocks.Add (new IfBlock (condition, lines)); + return this; + } + + public IfBlock AddElse (List blocks) + { + ElseBlock = new CodeBlock ("else", blocks); + return this; + } + + public IfBlock AddElse (params string [] lines) + { + ElseBlock = new CodeBlock ("else", lines); + return this; + } + + protected override void WriteHeaderText (TextWriter writer) + { + WriteIndent (writer); + writer.Write ("if ("); + writer.Write (HeaderText); + writer.Write (')'); + writer.Write (NewLine); + } + + protected void WriteElseHeaderText (TextWriter writer) + { + WriteIndent (writer); + writer.Write ("else if ("); + writer.Write (HeaderText); + writer.Write (')'); + writer.Write (NewLine); + } + + public override void Print (TextWriter writer) + { + if (HeaderText != string.Empty) + WriteHeaderText (writer); + + WriteIndent (writer); + writer.Write (StartBrace); + writer.Write (NewLine); + + SetIndent (CurrentIndent + Indent); + foreach (ICodeBlock block in Blocks) { + block.SetIndent (CurrentIndent); + block.Print (writer); + } + SetIndent (CurrentIndent - Indent); + WriteIndent (writer); + writer.Write (EndBrace); + writer.Write (NewLine); + + foreach (IfBlock block in ElseIfBlocks) { + block.SetIndent (CurrentIndent); + block.WriteElseHeaderText (writer); + writer.Write (StartBrace); + writer.Write (NewLine); + foreach (ICodeBlock b in block.Blocks) { + b.SetIndent (CurrentIndent + Indent); + b.Print (writer); + + } + writer.Write (EndBrace); + writer.Write (NewLine); + } + + if (ElseBlock is not null) + ElseBlock.Print (writer); + } +} diff --git a/src/bgen/CodeBlocks/LineBlock.cs b/src/bgen/CodeBlocks/LineBlock.cs new file mode 100644 index 000000000000..d2e32f5cc47a --- /dev/null +++ b/src/bgen/CodeBlocks/LineBlock.cs @@ -0,0 +1,30 @@ +using System.IO; + +public class LineBlock : ICodeBlock { + readonly string line; + int currentIndent = 0; + const char newLine = '\n'; + + public LineBlock (string line) + { + this.line = line; + } + + public void SetIndent (int indent) + { + currentIndent = indent; + } + + public void WriteIndent (TextWriter writer) + { + for (var i = 0; i < currentIndent; i++) + writer.Write (' '); + } + + public void Print (TextWriter writer) + { + WriteIndent (writer); + writer.Write (line); + writer.Write (newLine); + } +} diff --git a/src/bgen/CodeBlocks/MethodBlock.cs b/src/bgen/CodeBlocks/MethodBlock.cs new file mode 100644 index 000000000000..15c28e9f9939 --- /dev/null +++ b/src/bgen/CodeBlocks/MethodBlock.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Text; + +public class MethodBlock : CodeBlock { + public MethodBlock (string methodSignature, params string [] parameters) + { + StringBuilder allParameters = new (); + for (int i = 0; i < parameters.Length; i++) { + allParameters.Append (parameters [i]); + if (i != parameters.Length - 1) { + allParameters.Append (", "); + } + } + HeaderText = methodSignature + "(" + allParameters + ")"; + } + + public MethodBlock (string methodSignature, List blocks, params string [] parameters) + { + StringBuilder allParameters = new (); + for (int i = 0; i < parameters.Length; i++) { + allParameters.Append (parameters [i]); + if (i != parameters.Length - 1) { + allParameters.Append (", "); + } + } + HeaderText = methodSignature + "(" + allParameters + ")"; + this.Blocks = blocks; + } +} diff --git a/src/generator.csproj b/src/generator.csproj index a62bd3256c9d..68e25135b3d5 100644 --- a/src/generator.csproj +++ b/src/generator.csproj @@ -169,6 +169,12 @@ + + + + + + Resources.resx diff --git a/tests/bgen/bgen-tests.csproj b/tests/bgen/bgen-tests.csproj index c283fb0844a6..64f2f3b276a7 100644 --- a/tests/bgen/bgen-tests.csproj +++ b/tests/bgen/bgen-tests.csproj @@ -30,6 +30,9 @@ BGenTool.cs + + CodeBlockTests.cs + AttributeFactoryTests.cs diff --git a/tests/generator/CodeBlockTests.cs b/tests/generator/CodeBlockTests.cs new file mode 100644 index 000000000000..c75256eca121 --- /dev/null +++ b/tests/generator/CodeBlockTests.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; + +namespace GeneratorTests { + public class CodeBlockTests { + string PerformWriting (ICodeBlock codeBlock) + { + using var writer = new StringWriter (); + codeBlock.Print (writer); + return writer.ToString (); + } + + [Test] + public void LineBlockTest () + { + string expectedText = + "{\n" + + " using System;\n" + + " using Network;\n" + + "}\n"; + CodeBlock codeBlock = new (new string [] { "using System;", "using Network;" }); + string output = PerformWriting (codeBlock); + Assert.AreEqual (expectedText, output); + + expectedText = + "{\n" + + " using System;\n" + + " using Network;\n" + + " using NUnit;\n" + + "}\n"; + codeBlock.AddLine ("using NUnit;"); + output = PerformWriting (codeBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void MethodBlockConstructionTest () + { + string expectedText = + "public void Foobinate(int count, bool isFoo)\n" + + "{\n" + + " int fooCount = 1;\n" + + " string [] fooNames = new [] {\"foo\"};\n" + + "}\n"; + MethodBlock methodBlock = new ("public void Foobinate", "int count", "bool isFoo") + { + "int fooCount = 1;", + "string [] fooNames = new [] {\"foo\"};", + }; + string output = PerformWriting (methodBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void MethodBlockTest () + { + string expectedText = + "public void Foobinate(int count, bool isFoo)\n" + + "{\n" + + " int fooCount = 1;\n" + + " string[] fooNames = new [] {\"foo\"};\n" + + "}\n"; + List blocks = new List () { new LineBlock ("int fooCount = 1;"), new LineBlock ("string[] fooNames = new [] {\"foo\"};") }; + MethodBlock methodBlock = new ("public void Foobinate", blocks, "int count", "bool isFoo"); + string output = PerformWriting (methodBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void CodeBlockAsClassTest () + { + string expectedText = + "public class FooClass\n" + + "{\n" + + " public string FooText {get;set;}\n" + + "}\n"; + CodeBlock codeBlock = new ("public class FooClass", + "public string FooText {get;set;}"); + string output = PerformWriting (codeBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void IfBlockTest () + { + string expectedText = + "if (fooCount == 5)\n" + + "{\n" + + " Console.WriteLine(fooCount);\n" + + "}\n"; + IfBlock ifBlock = new ("fooCount == 5") { + "Console.WriteLine(fooCount);" + }; + string output = PerformWriting (ifBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void IfElseBlockTest () + { + string expectedText = + "if (fooCount == 5)\n" + + "{\n" + + " Console.WriteLine(fooCount);\n" + + "}\n" + + "else\n" + + "{\n" + + " Console.WriteLine(booCount);\n" + + "}\n"; + IfBlock ifBlock = new IfBlock ("fooCount == 5") { + "Console.WriteLine(fooCount);" + }.AddElse ( + "Console.WriteLine(booCount);" + ); + string output = PerformWriting (ifBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void IfElseIfElseBlockTest () + { + string expectedText = + "if (fooCount == 5)\n" + + "{\n" + + " Console.WriteLine(fooCount);\n" + + "}\n" + + "else if (fooCount == 10)\n" + + "{\n" + + " Console.WriteLine(booCount);\n" + + "}\n" + + "else\n" + + "{\n" + + " Console.WriteLine(zooCount);\n" + + "}\n"; + IfBlock ifBlock = new IfBlock ("fooCount == 5") { + "Console.WriteLine(fooCount);" + }.AddElseIf ("fooCount == 10", + "Console.WriteLine(booCount);" + ).AddElse ( + "Console.WriteLine(zooCount);" + ); + string output = PerformWriting (ifBlock); + Assert.AreEqual (expectedText, output); + } + + [Test] + public void ComprehensiveTest () + { + string expectedText = "using Network;\n" + + "\n" + + "public namespace FooSpace\n{\n" + + " public class FooClass\n" + + " {\n" + + " public string FooText { get; set; }\n" + + " public void Foobinate(int count, bool isFoo)\n" + + " {\n" + + " }\n" + + " }\n" + + "}\n"; + BlockContainer blockContainer = new () { "using Network;", String.Empty }; + CodeBlock block = new CodeBlock ("public namespace FooSpace") { + new CodeBlock ("public class FooClass") { + "public string FooText { get; set; }", + new MethodBlock ("public void Foobinate", + "int count", "bool isFoo") { } + } + }; + blockContainer.Add (block); + + string output = PerformWriting (blockContainer); + Assert.AreEqual (expectedText, output); + } + } +} diff --git a/tests/generator/generator-tests.csproj b/tests/generator/generator-tests.csproj index 9e55a14219dd..8ba75d22f379 100644 --- a/tests/generator/generator-tests.csproj +++ b/tests/generator/generator-tests.csproj @@ -45,6 +45,7 @@ NullableAttributes.cs +