diff --git a/SwiftBindings.sln b/SwiftBindings.sln
new file mode 100644
index 000000000000..0153ec68a445
--- /dev/null
+++ b/SwiftBindings.sln
@@ -0,0 +1,48 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntaxDynamo", "src\SyntaxDynamo\src\SyntaxDynamo.csproj", "{E05ECC4A-7212-4077-AD30-E4183CA3C1AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntaxDynamo.Tests", "src\SyntaxDynamo\tests\SyntaxDynamo.Tests.csproj", "{0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Debug|x64.Build.0 = Debug|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Debug|x86.Build.0 = Debug|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Release|x64.ActiveCfg = Release|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Release|x64.Build.0 = Release|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Release|x86.ActiveCfg = Release|Any CPU
+ {E05ECC4A-7212-4077-AD30-E4183CA3C1AF}.Release|x86.Build.0 = Release|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Debug|x64.Build.0 = Debug|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Debug|x86.Build.0 = Debug|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Release|x64.ActiveCfg = Release|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Release|x64.Build.0 = Release|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Release|x86.ActiveCfg = Release|Any CPU
+ {0C13F0AC-76F1-4FCB-AF42-9CB910A9471B}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/eng/pipelines/runtimelab.yml b/eng/pipelines/runtimelab.yml
index a2d5f7dda0f4..3d3a7752e8c7 100644
--- a/eng/pipelines/runtimelab.yml
+++ b/eng/pipelines/runtimelab.yml
@@ -49,16 +49,33 @@ stages:
- stage: build
displayName: Build
jobs:
- - template: /eng/pipelines/templates/build-job.yml
- parameters:
- osGroup: OSX
- archType: x64
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - template: /eng/pipelines/templates/build-job.yml
+ parameters:
+ osGroup: OSX
+ archType: x64
isOfficialBuild: true
runTests: false
pool:
vmImage: 'macOS-latest'
+ - ${{ if or(eq(variables['System.TeamProject'], 'public'), in(variables['Build.Reason'], 'PullRequest')) }}:
+ - template: /eng/pipelines/templates/build-job.yml
+ parameters:
+ osGroup: OSX
+ archType: arm64
+ runTests: true
+ pool:
+ vmImage: 'macOS-latest'
+
+ - template: /eng/pipelines/templates/build-job.yml
+ parameters:
+ osGroup: OSX
+ archType: x64
+ runTests: true
+ pool:
+ vmImage: 'macOS-latest'
+
# Publish and validation steps. Only run in official builds
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- template: \eng\common\templates\post-build\post-build.yml
diff --git a/global.json b/global.json
index ef7775d375fe..c5c66e5ff962 100644
--- a/global.json
+++ b/global.json
@@ -8,6 +8,6 @@
"dotnet": "8.0.100"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24102.4"
+ "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.22430.3"
}
}
diff --git a/src/SwiftBindings/SwiftBindings.sln b/src/SwiftBindings/SwiftBindings.sln
deleted file mode 100644
index 039811c309a5..000000000000
--- a/src/SwiftBindings/SwiftBindings.sln
+++ /dev/null
@@ -1,48 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26124.0
-MinimumVisualStudioVersion = 15.0.26124.0
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwiftBindings", "src\SwiftBindings.csproj", "{B7977360-6671-4707-9A1C-1C29D5BE2674}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwiftBindings.Tests", "tests\SwiftBindings.Tests.csproj", "{CE81B6BD-CCCC-4223-9069-B28435A4A5C1}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Debug|x64.Build.0 = Debug|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Debug|x86.Build.0 = Debug|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Release|Any CPU.Build.0 = Release|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Release|x64.ActiveCfg = Release|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Release|x64.Build.0 = Release|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Release|x86.ActiveCfg = Release|Any CPU
- {B7977360-6671-4707-9A1C-1C29D5BE2674}.Release|x86.Build.0 = Release|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Debug|x64.Build.0 = Debug|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Debug|x86.Build.0 = Debug|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Release|Any CPU.Build.0 = Release|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Release|x64.ActiveCfg = Release|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Release|x64.Build.0 = Release|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Release|x86.ActiveCfg = Release|Any CPU
- {CE81B6BD-CCCC-4223-9069-B28435A4A5C1}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/src/SwiftBindings/src/MyClass.cs b/src/SwiftBindings/src/MyClass.cs
deleted file mode 100644
index 907d856d3f57..000000000000
--- a/src/SwiftBindings/src/MyClass.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-
-namespace SwiftBindings
-{
- public class MyClass
- {
- public static bool ReturnTrue => true;
- public static void Main(string[] args)
- {
- Console.WriteLine("Hello World!");
- }
- }
-}
diff --git a/src/SwiftBindings/tests/SmokeTests.cs b/src/SwiftBindings/tests/SmokeTests.cs
deleted file mode 100644
index db7c93457129..000000000000
--- a/src/SwiftBindings/tests/SmokeTests.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using Xunit;
-
-namespace SwiftBindings.Tests
-{
- public class MyClassTests
- {
- [Fact]
- public void Test1()
- {
- Assert.True(MyClass.ReturnTrue);
- }
- }
-}
diff --git a/src/SwiftBindings/tests/SwiftBindings.Tests.csproj b/src/SwiftBindings/tests/SwiftBindings.Tests.csproj
deleted file mode 100644
index b09cc9165c4c..000000000000
--- a/src/SwiftBindings/tests/SwiftBindings.Tests.csproj
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- net8.0
-
-
-
-
-
-
diff --git a/src/SyntaxDynamo/src/CodeElementCollection.cs b/src/SyntaxDynamo/src/CodeElementCollection.cs
new file mode 100644
index 000000000000..e51256417970
--- /dev/null
+++ b/src/SyntaxDynamo/src/CodeElementCollection.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SyntaxDynamo
+{
+ public class CodeElementCollection : List, ICodeElementSet where T : ICodeElement
+ {
+ public CodeElementCollection() : base()
+ {
+ }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public virtual object? BeginWrite(ICodeWriter writer)
+ {
+ OnBeginWrite(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBeginWrite(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public virtual void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public virtual void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEndWrite(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEndWrite(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public System.Collections.Generic.IEnumerable Elements
+ {
+ get
+ {
+ return this.Cast();
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/CodeWriter.cs b/src/SyntaxDynamo/src/CodeWriter.cs
new file mode 100644
index 000000000000..67381570d55d
--- /dev/null
+++ b/src/SyntaxDynamo/src/CodeWriter.cs
@@ -0,0 +1,157 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Globalization;
+using System.IO;
+
+namespace SyntaxDynamo
+{
+ public class CodeWriter : ICodeWriter
+ {
+ int charsWrittenThisLine;
+ bool indentedThisLine;
+
+ const int kSpacesPerIndent = 4;
+ const int kWrapPoint = 60;
+
+ public CodeWriter(Stream stm)
+ : this(new StreamWriter(stm))
+ {
+ }
+
+ public CodeWriter(TextWriter tw)
+ {
+ ArgumentNullException.ThrowIfNull(tw, nameof(tw));
+ TextWriter = tw;
+ charsWrittenThisLine = 0;
+ IndentLevel = 0;
+ IsAtLineStart = true;
+ }
+
+ public static void WriteToFile(string fileName, ICodeElement element)
+ {
+ using (var stm = new FileStream(fileName, FileMode.Create))
+ {
+ CodeWriter writer = new CodeWriter(stm);
+ element.WriteAll(writer);
+ writer.TextWriter.Flush();
+ }
+ }
+
+ public static Stream WriteToStream(ICodeElement element)
+ {
+ var stm = new MemoryStream();
+ var codeWriter = new CodeWriter(stm);
+ element.WriteAll(codeWriter);
+ codeWriter.TextWriter.Flush();
+ stm.Flush();
+ stm.Seek(0, SeekOrigin.Begin);
+ return stm;
+ }
+
+ public static string WriteToString(ICodeElement element)
+ {
+ using (var reader = new StreamReader(WriteToStream(element)))
+ return reader.ReadToEnd();
+ }
+
+ public TextWriter TextWriter { get; private set; }
+
+ #region ICodeWriter implementation
+
+ public void BeginNewLine(bool prependIndents)
+ {
+ Write(Environment.NewLine, false);
+ if (prependIndents)
+ WriteIndents();
+ IsAtLineStart = true;
+ }
+
+ public void EndLine()
+ {
+ charsWrittenThisLine = 0;
+ if (indentedThisLine)
+ {
+ indentedThisLine = false;
+ // strictly speaking, this test shouldn't be necessary
+ if (IndentLevel > 0)
+ Exdent();
+ }
+ }
+
+ public bool IsAtLineStart { get; private set; }
+
+ public void Write(string code, bool allowSplit)
+ {
+ var characterEnum = StringInfo.GetTextElementEnumerator(code);
+ while (characterEnum.MoveNext())
+ {
+ string c = characterEnum.GetTextElement();
+ WriteUnicode(c, allowSplit);
+ }
+ }
+
+ public void Write(char c, bool allowSplit)
+ {
+ Write(c.ToString(), allowSplit);
+ }
+
+ void WriteUnicode(string c, bool allowSplit)
+ {
+ var info = new StringInfo(c);
+ if (info.LengthInTextElements > 1)
+ throw new ArgumentOutOfRangeException(nameof(c), $"Expected a single unicode value but got '{c}'");
+ WriteNoBookKeeping(c);
+ IsAtLineStart = false;
+ charsWrittenThisLine++;
+ if (allowSplit && charsWrittenThisLine > kWrapPoint && IsWhiteSpace(c))
+ {
+ if (!indentedThisLine)
+ {
+ Indent();
+ indentedThisLine = true;
+ }
+ WriteNoBookKeeping(Environment.NewLine);
+ charsWrittenThisLine = 0;
+ WriteIndents();
+ IsAtLineStart = true;
+ }
+ }
+
+ bool IsWhiteSpace(string c)
+ {
+ return c.Length == 1 && Char.IsWhiteSpace(c[0]);
+
+ }
+
+ void WriteNoBookKeeping(string s)
+ {
+ TextWriter.Write(s);
+ }
+
+ void WriteIndents()
+ {
+ int totalSpaces = IndentLevel * kSpacesPerIndent;
+ // know what's embarrassing? When your indents cause breaks which generates more indents.
+ for (int i = 0; i < totalSpaces; i++)
+ Write(" ", false);
+ }
+
+ public void Indent()
+ {
+ IndentLevel++;
+ }
+
+ public void Exdent()
+ {
+ if (IndentLevel == 0)
+ throw new Exception("IndentLevel is at 0.");
+ IndentLevel--;
+ }
+
+ public int IndentLevel { get; private set; }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/CommaListElementCollection.cs b/src/SyntaxDynamo/src/CommaListElementCollection.cs
new file mode 100644
index 000000000000..04d99a13d763
--- /dev/null
+++ b/src/SyntaxDynamo/src/CommaListElementCollection.cs
@@ -0,0 +1,87 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public class CommaListElementCollection : List, ICodeElement where T : ICodeElement
+ {
+ public CommaListElementCollection()
+ : this("", "")
+ {
+ }
+
+ public CommaListElementCollection(IEnumerable objs)
+ : this("", "", objs)
+ {
+ }
+
+ public CommaListElementCollection(string prefix, string suffix)
+ : base()
+ {
+ ArgumentNullException.ThrowIfNull(prefix, nameof(prefix));
+ ArgumentNullException.ThrowIfNull(suffix, nameof(suffix));
+ Prefix = prefix;
+ Suffix = suffix;
+ }
+
+ public CommaListElementCollection(string prefix, string suffix, IEnumerable objs, bool newlineAfterEach = false)
+ : this(prefix, suffix)
+ {
+ ArgumentNullException.ThrowIfNull(objs, nameof(objs));
+ AddRange(objs);
+ NewlineAfterEach = newlineAfterEach;
+ }
+
+ public string Prefix { get; private set; }
+ public string Suffix { get; private set; }
+ public bool NewlineAfterEach { get; private set; }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ writer.Write(Prefix, true);
+ for (int i = 0; i < Count; i++)
+ {
+ this[i].WriteAll(writer);
+ if (i < Count - 1)
+ writer.Write(", ", true);
+ if (NewlineAfterEach && !writer.IsAtLineStart)
+ {
+ writer.BeginNewLine(true);
+ }
+ }
+ writer.Write(Suffix, true);
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/DecoratedCodeElementCollection.cs b/src/SyntaxDynamo/src/DecoratedCodeElementCollection.cs
new file mode 100644
index 000000000000..3171c83b5863
--- /dev/null
+++ b/src/SyntaxDynamo/src/DecoratedCodeElementCollection.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public class DecoratedCodeElementCollection : CodeElementCollection where T : ICodeElement
+ {
+ bool startOnOwnLine, endOnOwnLine, indent;
+
+ public DecoratedCodeElementCollection(string startDecoration, string endDecoration,
+ bool startOnOwnLine, bool endOnOwnLine, bool indent,
+ IEnumerable? elems)
+ : base()
+ {
+ StartDecoration = startDecoration;
+ EndDecoration = endDecoration;
+ this.startOnOwnLine = startOnOwnLine;
+ this.endOnOwnLine = endOnOwnLine;
+ this.indent = indent;
+ if (elems != null)
+ AddRange(elems);
+ }
+
+ public DecoratedCodeElementCollection(string startDecoration, string endDecoration,
+ bool startOnOwnLine, bool endOnOwnLine, bool indent)
+ : this(startDecoration, endDecoration, startOnOwnLine, endOnOwnLine, indent, null)
+ {
+ }
+
+ public string StartDecoration { get; private set; }
+ public string EndDecoration { get; private set; }
+
+ public override void Write(ICodeWriter writer, object? o)
+ {
+ if (StartDecoration != null)
+ {
+ if (startOnOwnLine)
+ writer.BeginNewLine(true);
+ writer.Write(StartDecoration, true);
+ if (startOnOwnLine)
+ writer.EndLine();
+ }
+ if (indent)
+ writer.Indent();
+ }
+
+ public override void EndWrite(ICodeWriter writer, object? o)
+ {
+ if (indent)
+ writer.Exdent();
+ if (EndDecoration != null)
+ {
+ if (endOnOwnLine)
+ writer.BeginNewLine(true);
+ writer.Write(EndDecoration, true);
+ if (endOnOwnLine)
+ writer.EndLine();
+ }
+
+ base.EndWrite(writer, o);
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}{1}{2}",
+ StartDecoration ?? "",
+ StartDecoration != null && EndDecoration != null ? "..." : "",
+ EndDecoration ?? "");
+ }
+
+ public static DecoratedCodeElementCollection CBlock(IEnumerable elems)
+ {
+ var col = new DecoratedCodeElementCollection("{", "}", true, true, true);
+ if (elems != null)
+ col.AddRange(elems);
+ return col;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/DelegatedCommaListElementCollection.cs b/src/SyntaxDynamo/src/DelegatedCommaListElementCollection.cs
new file mode 100644
index 000000000000..843845db6b7e
--- /dev/null
+++ b/src/SyntaxDynamo/src/DelegatedCommaListElementCollection.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public class DelegatedCommaListElemCollection : List, ICodeElement where T : ICodeElement
+ {
+ Action elementWriter;
+ public DelegatedCommaListElemCollection(Action elementWriter)
+ : base()
+ {
+ ArgumentNullException.ThrowIfNull(elementWriter, nameof(elementWriter));
+ this.elementWriter = elementWriter;
+ }
+
+ public DelegatedCommaListElemCollection(Action elementWriter, IEnumerable objs)
+ : base()
+ {
+ ArgumentNullException.ThrowIfNull(elementWriter, nameof(elementWriter));
+ ArgumentNullException.ThrowIfNull(objs, nameof(objs));
+ this.elementWriter = elementWriter;
+ AddRange(objs);
+ }
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ for (int i = 0; i < Count; i++)
+ {
+ elementWriter(writer, i, this[i]);
+ if (i < Count - 1)
+ writer.Write(", ", true);
+ }
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/DelegatedSimpleElement.cs b/src/SyntaxDynamo/src/DelegatedSimpleElement.cs
new file mode 100644
index 000000000000..354054caa4cd
--- /dev/null
+++ b/src/SyntaxDynamo/src/DelegatedSimpleElement.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo
+{
+ public abstract class DelegatedSimpleElement : ICodeElement
+ {
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ LLWrite(writer, o);
+ }
+
+ protected abstract void LLWrite(ICodeWriter writer, object? o);
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+ }
+
+ public class LineBreak : DelegatedSimpleElement
+ {
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.EndLine();
+ writer.BeginNewLine(true);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/Extensions.cs b/src/SyntaxDynamo/src/Extensions.cs
new file mode 100644
index 000000000000..812243f0d4cb
--- /dev/null
+++ b/src/SyntaxDynamo/src/Extensions.cs
@@ -0,0 +1,75 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public static class Extensions
+ {
+ public static void WriteAll(this ICodeElement elem, ICodeWriter writer)
+ {
+ object? memento = elem.BeginWrite(writer);
+ elem.Write(writer, memento);
+ ICodeElementSet? set = elem as ICodeElementSet;
+ if (set != null)
+ {
+ foreach (ICodeElement sub in set.Elements)
+ {
+ sub.WriteAll(writer);
+ }
+ }
+ elem.EndWrite(writer, memento);
+ }
+
+ public static void FireInReverse(this EventHandler handler, object sender, EventArgs args) where T : EventArgs
+ {
+ var dels = handler.GetInvocationList();
+ for (int i = dels.Length - 1; i >= 0; i--)
+ {
+ dels[i].DynamicInvoke(new object[] { sender, args });
+ }
+ }
+
+ public static IEnumerable Interleave(this IEnumerable contents, T separator, bool includeSeparatorFirst = false)
+ {
+ bool first = true;
+ foreach (T t in contents)
+ {
+ if (!first || includeSeparatorFirst)
+ yield return separator;
+ first = false;
+ yield return t;
+ }
+ }
+
+ public static IEnumerable BracketInterleave(this IEnumerable contents, T start, T end, T separator, bool includeSeparatorFirst = false)
+ {
+ yield return start;
+ foreach (T t in contents.Interleave(separator, includeSeparatorFirst))
+ yield return t;
+ yield return end;
+ }
+
+ public static T AttachBefore(this T attacher, ICodeElement attachTo) where T : ICodeElement
+ {
+ ArgumentNullException.ThrowIfNull(attachTo, nameof(attachTo));
+ attachTo.Begin += (s, eventArgs) =>
+ {
+ attacher.WriteAll(eventArgs.Writer);
+ };
+ return attacher;
+ }
+
+ public static T AttachAfter(this T attacher, ICodeElement attachTo) where T : ICodeElement
+ {
+ ArgumentNullException.ThrowIfNull(attachTo, nameof(attachTo));
+ attachTo.End += (s, eventArgs) =>
+ {
+ attacher.WriteAll(eventArgs.Writer);
+ };
+ return attacher;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/ICodeElement.cs b/src/SyntaxDynamo/src/ICodeElement.cs
new file mode 100644
index 000000000000..f9a06cf22cbb
--- /dev/null
+++ b/src/SyntaxDynamo/src/ICodeElement.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo
+{
+ public interface ICodeElement
+ {
+ // these three methods represent the memento pattern. The object returned is only ever used by
+ // the ICodeElem.
+ object? BeginWrite(ICodeWriter writer);
+ void Write(ICodeWriter writer, object? o);
+ void EndWrite(ICodeWriter writer, object? o);
+
+ // These events seem redundant, but they are intended for use for non-structural code elements
+ // such as block comments or #region or #if/#else/#endif
+
+ // Begin should be fired by BeginWrite BEFORE anything is written
+ event EventHandler Begin;
+ // Note, when you implement End, it should use GetInvocationList and fire in reverse order.
+ // End should be fired by EndWrite AFTER anything is written
+ event EventHandler End;
+ }
+}
diff --git a/src/SyntaxDynamo/src/ICodeElementSet.cs b/src/SyntaxDynamo/src/ICodeElementSet.cs
new file mode 100644
index 000000000000..3ee50301f0a5
--- /dev/null
+++ b/src/SyntaxDynamo/src/ICodeElementSet.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public interface ICodeElementSet : ICodeElement
+ {
+ IEnumerable Elements { get; }
+ }
+}
diff --git a/src/SyntaxDynamo/src/ICodeWriter.cs b/src/SyntaxDynamo/src/ICodeWriter.cs
new file mode 100644
index 000000000000..3b51aff75bf6
--- /dev/null
+++ b/src/SyntaxDynamo/src/ICodeWriter.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo
+{
+ public interface ICodeWriter
+ {
+ void BeginNewLine(bool prependIndents);
+ void EndLine();
+ void Write(char c, bool allowSplit);
+ void Write(string code, bool allowSplit);
+ void Indent();
+ void Exdent();
+ int IndentLevel { get; }
+ bool IsAtLineStart { get; }
+ }
+}
diff --git a/src/SyntaxDynamo/src/LabeledCodeElementCollection.cs b/src/SyntaxDynamo/src/LabeledCodeElementCollection.cs
new file mode 100644
index 000000000000..8a3938a3a47c
--- /dev/null
+++ b/src/SyntaxDynamo/src/LabeledCodeElementCollection.cs
@@ -0,0 +1,69 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public class LabeledCodeElementCollection : ICodeElementSet where T : ICodeElement
+ {
+ public LabeledCodeElementCollection(SimpleLineElement label, CodeElementCollection block)
+ {
+ ArgumentNullException.ThrowIfNull(label, nameof(label));
+ ArgumentNullException.ThrowIfNull(block, nameof(block));
+ Label = label;
+ Block = block;
+ }
+
+ public SimpleLineElement Label { get; private set; }
+ public CodeElementCollection Block { get; private set; }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public IEnumerable Elements
+ {
+ get
+ {
+ yield return Label;
+ yield return Block;
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/LineCodeElementCollection.cs b/src/SyntaxDynamo/src/LineCodeElementCollection.cs
new file mode 100644
index 000000000000..d7505ab99f0a
--- /dev/null
+++ b/src/SyntaxDynamo/src/LineCodeElementCollection.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+
+namespace SyntaxDynamo
+{
+ public class LineCodeElementCollection : CodeElementCollection where T : ICodeElement
+ {
+ bool indent, prependIndents, isSingleLine;
+ public LineCodeElementCollection(IEnumerable? elems, bool indent, bool prependIndents)
+ : this(elems, true, indent, prependIndents)
+ {
+ }
+
+ public LineCodeElementCollection(bool isSingleLine, bool indent, bool prependIndents)
+ : this(null, isSingleLine, indent, prependIndents)
+ {
+ }
+
+ public LineCodeElementCollection(IEnumerable? elems, bool isSingleLine, bool indent, bool prependIndents)
+ {
+ this.isSingleLine = isSingleLine;
+ this.indent = indent;
+ this.prependIndents = prependIndents;
+ if (elems != null)
+ AddRange(elems);
+ }
+
+ public override void Write(ICodeWriter writer, object? o)
+ {
+ if (isSingleLine)
+ {
+ if (indent)
+ writer.Indent();
+ writer.BeginNewLine(prependIndents);
+ }
+ }
+
+ protected override void OnEndWrite(WriteEventArgs args)
+ {
+ if (isSingleLine)
+ args.Writer.EndLine();
+ base.OnEndWrite(args);
+ }
+
+ public LineCodeElementCollection And(T elem)
+ {
+ Add(elem);
+ return this;
+ }
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SimpleElement.cs b/src/SyntaxDynamo/src/SimpleElement.cs
new file mode 100644
index 000000000000..efdd94f66ee1
--- /dev/null
+++ b/src/SyntaxDynamo/src/SimpleElement.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo
+{
+ public class SimpleElement : ICodeElement
+ {
+ bool allowSplit;
+ public SimpleElement(string label, bool allowSplit = false)
+ {
+ Label = label;
+ this.allowSplit = allowSplit;
+ }
+
+ public string Label { get; private set; }
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ writer.Write(Label, allowSplit);
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ public override string ToString()
+ {
+ return Label;
+ }
+
+ static SimpleElement spacer = new SimpleElement(" ", true);
+ public static SimpleElement Spacer { get { return spacer; } }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SimpleLineElement.cs b/src/SyntaxDynamo/src/SimpleLineElement.cs
new file mode 100644
index 000000000000..fc58691fed06
--- /dev/null
+++ b/src/SyntaxDynamo/src/SimpleLineElement.cs
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo
+{
+ public class SimpleLineElement : ICodeElement
+ {
+ bool indent, prependIndents, allowSplit;
+
+ public SimpleLineElement(string contents, bool indent, bool prependIdents, bool allowSplit)
+ {
+ Contents = contents ?? "";
+ this.indent = indent;
+ this.prependIndents = prependIdents;
+ this.allowSplit = allowSplit;
+ }
+
+ public string Contents { get; private set; }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ if (indent)
+ writer.Indent();
+ writer.BeginNewLine(prependIndents);
+ writer.Write(Contents, allowSplit);
+ writer.EndLine();
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ public override string ToString()
+ {
+ return Contents;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSArgument.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSArgument.cs
new file mode 100644
index 000000000000..08bc6f9abfe7
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSArgument.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSArgument : DelegatedSimpleElement
+ {
+ public CSArgument(ICSExpression expr)
+ {
+ ArgumentNullException.ThrowIfNull(expr, nameof(expr));
+ Value = expr;
+ }
+
+ public ICSExpression Value { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ Value.WriteAll(writer);
+ }
+ }
+
+ public class CSArgumentList : CommaListElementCollection
+ {
+
+ public void Add(ICSExpression expr)
+ {
+ Add(new CSArgument(expr));
+ }
+
+ public static CSArgumentList FromExpressions(params ICSExpression[] exprs)
+ {
+ var al = new CSArgumentList();
+ foreach (var ex in exprs)
+ al.Add(new CSArgument(ex));
+ return al;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSArray1D.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSArray1D.cs
new file mode 100644
index 000000000000..c0005edc3988
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSArray1D.cs
@@ -0,0 +1,122 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSArray1D : CSBaseExpression
+ {
+ public CSArray1D(CSIdentifier name, CommaListElementCollection paramList)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ ArgumentNullException.ThrowIfNull(paramList, nameof(paramList));
+ Name = name;
+ Parameters = paramList;
+ }
+
+ public CSArray1D(string name, params CSBaseExpression[] parameters)
+ : this(new CSIdentifier(name), new CommaListElementCollection(parameters))
+ {
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ Name.WriteAll(writer);
+ writer.Write("[", false);
+ Parameters.WriteAll(writer);
+ writer.Write("]", false);
+ }
+
+ public CSIdentifier Name { get; private set; }
+ public CommaListElementCollection Parameters { get; private set; }
+
+ public static CSArray1D New(CSSimpleType type, bool isStackAlloc, params CSBaseExpression[] parameters)
+ {
+ string ID = (isStackAlloc ? "stackalloc " : "new ") + type.Name;
+ return new CSArray1D(ID, parameters);
+ }
+ }
+
+ public class CSArray1DInitialized : CSBaseExpression
+ {
+ public CSArray1DInitialized(CSType type, CommaListElementCollection initializers)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(initializers, nameof(initializers));
+ Type = type;
+ Parameters = initializers;
+ }
+
+ public CSArray1DInitialized(CSType type, params CSBaseExpression[] parameters)
+ : this(type, new CommaListElementCollection(parameters))
+ {
+ }
+
+ public CSArray1DInitialized(string typeName, params CSBaseExpression[] parameters)
+ : this(new CSSimpleType(typeName), new CommaListElementCollection(parameters))
+ {
+ }
+
+ public CSArray1DInitialized(string typeName, IEnumerable parameters)
+ : this(new CSSimpleType(typeName), new CommaListElementCollection(parameters))
+ {
+ }
+
+ public CSType Type { get; private set; }
+ public CommaListElementCollection Parameters { get; private set; }
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("new ", true);
+ Type.WriteAll(writer);
+ writer.Write("[", false);
+ writer.Write("] ", true);
+ writer.Write("{ ", true);
+ Parameters.WriteAll(writer);
+ writer.Write("}", false);
+ }
+
+ }
+
+ public class CSListInitialized : CSBaseExpression
+ {
+ public CSListInitialized(CSType type, CommaListElementCollection initializers)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(initializers, nameof(initializers));
+ Type = type;
+ Parameters = initializers;
+ }
+
+ public CSListInitialized(CSType type, params CSBaseExpression[] parameters)
+ : this(type, new CommaListElementCollection(parameters))
+ {
+ }
+
+ public CSListInitialized(string typeName, params CSBaseExpression[] parameters)
+ : this(new CSSimpleType(typeName), new CommaListElementCollection(parameters))
+ {
+ }
+
+ public CSListInitialized(string typeName, IEnumerable parameters)
+ : this(new CSSimpleType(typeName), new CommaListElementCollection(parameters))
+ {
+ }
+
+ public CSType Type { get; private set; }
+ public CommaListElementCollection Parameters { get; private set; }
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("new List<", true);
+ Type.WriteAll(writer);
+ writer.Write(">", true);
+ writer.Write("(", false);
+ writer.Write(") ", true);
+ writer.Write("{ ", true);
+ Parameters.WriteAll(writer);
+ writer.Write("}", false);
+ }
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSAssignment.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSAssignment.cs
new file mode 100644
index 000000000000..0d78c0643044
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSAssignment.cs
@@ -0,0 +1,83 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSAssignment : CSBaseExpression, ICSLineable
+ {
+ public CSAssignment(CSBaseExpression lhs, CSAssignmentOperator op, CSBaseExpression rhs)
+ {
+ ArgumentNullException.ThrowIfNull(lhs, nameof(lhs));
+ ArgumentNullException.ThrowIfNull(rhs, nameof(rhs));
+ Target = lhs;
+ Value = rhs;
+ Operation = op;
+ }
+
+ public CSAssignment(string lhs, CSAssignmentOperator op, CSBaseExpression rhs)
+ : this(new CSIdentifier(lhs), op, rhs)
+ {
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ Target.WriteAll(writer);
+ writer.Write(string.Format(" {0} ", ToAssignmentOpString(Operation)), true);
+ Value.WriteAll(writer);
+ }
+
+ public CSBaseExpression Target { get; private set; }
+ public CSBaseExpression Value { get; private set; }
+ public CSAssignmentOperator Operation { get; private set; }
+
+ static string ToAssignmentOpString(CSAssignmentOperator op)
+ {
+ switch (op)
+ {
+ case CSAssignmentOperator.Assign:
+ return "=";
+ case CSAssignmentOperator.AddAssign:
+ return "+=";
+ case CSAssignmentOperator.SubAssign:
+ return "-=";
+ case CSAssignmentOperator.MulAssign:
+ return "*=";
+ case CSAssignmentOperator.DivAssign:
+ return "/=";
+ case CSAssignmentOperator.ModAssign:
+ return "%=";
+ case CSAssignmentOperator.AndAssign:
+ return "&=";
+ case CSAssignmentOperator.OrAssign:
+ return "|=";
+ case CSAssignmentOperator.XorAssign:
+ return "^=";
+ default:
+ throw new ArgumentOutOfRangeException("op");
+ }
+ }
+
+ public static CSLine Assign(string name, CSAssignmentOperator op, CSBaseExpression value)
+ {
+ return new CSLine(new CSAssignment(name, op, value));
+ }
+
+ public static CSLine Assign(string name, CSBaseExpression value)
+ {
+ return Assign(name, CSAssignmentOperator.Assign, value);
+ }
+
+ public static CSLine Assign(CSBaseExpression name, CSBaseExpression value)
+ {
+ return Assign(name, CSAssignmentOperator.Assign, value);
+ }
+
+ public static CSLine Assign(CSBaseExpression name, CSAssignmentOperator op, CSBaseExpression value)
+ {
+ return new CSLine(new CSAssignment(name, op, value));
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSAttribute.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSAttribute.cs
new file mode 100644
index 000000000000..4d00608f8fb9
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSAttribute.cs
@@ -0,0 +1,100 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSAttribute : LineCodeElementCollection
+ {
+ public CSAttribute(CSIdentifier name, CSArgumentList args, bool isSingleLine = false, bool isReturn = false)
+ : base(isSingleLine, false, isSingleLine)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Add(new SimpleElement("["));
+ if (isReturn)
+ Add(new SimpleElement("return:"));
+ Add(name);
+ if (args != null)
+ {
+ Add(new SimpleElement("("));
+ Add(args);
+ Add(new SimpleElement(")"));
+ }
+ Add(new SimpleElement("]"));
+ }
+
+ public CSAttribute(string name, CSArgumentList args)
+ : this(new CSIdentifier(name), args)
+ {
+ }
+
+ public CSAttribute(string name, params ICSExpression[] exprs)
+ : this(new CSIdentifier(name), CSArgumentList.FromExpressions(exprs))
+ {
+ }
+
+ // DllImport("msvcrt.dll", EntryPoint="puts")
+ public static CSAttribute DllImport(string dllName, string? entryPoint = null)
+ {
+ CSArgumentList args = new CSArgumentList();
+ args.Add(CSConstant.Val(dllName));
+ if (entryPoint != null)
+ args.Add(new CSAssignment("EntryPoint", CSAssignmentOperator.Assign, CSConstant.Val(entryPoint)));
+ return new CSAttribute(new CSIdentifier("DllImport"), args, true);
+ }
+
+ public static CSAttribute DllImport(CSBaseExpression dllName, string? entryPoint = null)
+ {
+ CSArgumentList args = new CSArgumentList();
+ args.Add(dllName);
+ if (entryPoint != null)
+ args.Add(new CSAssignment("EntryPoint", CSAssignmentOperator.Assign, CSConstant.Val(entryPoint)));
+ return new CSAttribute(new CSIdentifier("DllImport"), args, true);
+ }
+
+ public static CSAttribute UnmanagedCallConv(string callconv)
+ {
+ CSArgumentList args = new CSArgumentList();
+
+ args.Add(new CSAssignment("CallConvs", CSAssignmentOperator.Assign, new CSIdentifier(string.Format("new Type[] { typeof({0}) }", callconv))));
+ return new CSAttribute(new CSIdentifier("UnmanagedCallConv"), args, true);
+ }
+
+ static CSAttribute returnMarshalAsI1 = new CSAttribute("return: MarshalAs", new CSIdentifier("UnmanagedType.I1"));
+
+ public static CSAttribute ReturnMarshalAsI1 => returnMarshalAsI1;
+
+ public static CSAttribute FieldOffset(int offset)
+ {
+ CSArgumentList args = new CSArgumentList();
+ args.Add(CSConstant.Val(offset));
+ return new CSAttribute(new CSIdentifier("FieldOffset"), args, true);
+ }
+
+ public static CSAttribute LayoutKind(LayoutKind layout)
+ {
+ CSArgumentList args = new CSArgumentList();
+ args.Add(new CSIdentifier(String.Format("LayoutKind.{0}", layout)));
+ return new CSAttribute(new CSIdentifier("StructLayout"), args, true);
+ }
+
+ public static CSAttribute FromAttr(Type attribute, CSArgumentList args, bool isSingleLine = false, bool isReturn = false)
+ {
+ ArgumentNullException.ThrowIfNull(attribute, nameof(attribute));
+ if (!attribute.IsSubclassOf(typeof(Attribute)))
+ throw new ArgumentException(String.Format("Type {0} is not an Attribute type.", attribute.Name), nameof(attribute));
+ var name = attribute.Name.EndsWith("Attribute") ?
+ attribute.Name.Substring(0, attribute.Name.Length - "Attribute".Length) : attribute.Name;
+ return new CSAttribute(new CSIdentifier(name), args, isSingleLine, isReturn);
+ }
+
+ public static CSAttribute MarshalAsFunctionPointer()
+ {
+ CSArgumentList list = new CSArgumentList();
+ list.Add(new CSArgument(new CSIdentifier("UnmanagedType.FunctionPtr")));
+ return FromAttr(typeof(MarshalAsAttribute), list, false);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBaseExpression.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBaseExpression.cs
new file mode 100644
index 000000000000..eb1115cac859
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBaseExpression.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public abstract class CSBaseExpression : DelegatedSimpleElement, ICSExpression
+ {
+ public CSBaseExpression Dot(CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Dot, this, rhs);
+ }
+ public static CSBaseExpression operator +(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Add, lhs, rhs);
+ }
+ public static CSBaseExpression operator -(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Sub, lhs, rhs);
+ }
+ public static CSBaseExpression operator *(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Mul, lhs, rhs);
+ }
+ public static CSBaseExpression operator /(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Div, lhs, rhs);
+ }
+ public static CSBaseExpression operator %(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Mod, lhs, rhs);
+ }
+ public static CSBaseExpression operator <(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Less, lhs, rhs);
+ }
+ public static CSBaseExpression operator >(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Greater, lhs, rhs);
+ }
+ public static CSBaseExpression operator ==(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.Equal, lhs, rhs);
+ }
+ public static CSBaseExpression operator !=(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.NotEqual, lhs, rhs);
+ }
+ public static CSBaseExpression operator <=(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.LessEqual, lhs, rhs);
+ }
+ public static CSBaseExpression operator >=(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.GreaterEqual, lhs, rhs);
+ }
+ public static CSBaseExpression operator &(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.BitAnd, lhs, rhs);
+ }
+ public static CSBaseExpression operator |(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.BitOr, lhs, rhs);
+ }
+ public static CSBaseExpression operator ^(CSBaseExpression lhs, CSBaseExpression rhs)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.BitXor, lhs, rhs);
+ }
+ public static CSBaseExpression operator <<(CSBaseExpression lhs, int bits)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.LeftShift, lhs, CSConstant.Val(bits));
+ }
+ public static CSBaseExpression operator >>(CSBaseExpression lhs, int bits)
+ {
+ return new CSBinaryExpression(CSBinaryOperator.RightShift, lhs, CSConstant.Val(bits));
+ }
+ public override bool Equals(object? obj)
+ {
+ if (obj == null || GetType() != obj.GetType())
+ {
+ return false;
+ }
+
+ // Add your custom equality logic here
+
+ return base.Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ // Add your custom hash code logic here
+
+ return base.GetHashCode();
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBinaryExpression.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBinaryExpression.cs
new file mode 100644
index 000000000000..e372626d558d
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBinaryExpression.cs
@@ -0,0 +1,83 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSBinaryExpression : CSBaseExpression
+ {
+ public CSBinaryExpression(CSBinaryOperator op, ICSExpression lhs, ICSExpression rhs)
+ {
+ ArgumentNullException.ThrowIfNull(lhs, nameof(lhs));
+ ArgumentNullException.ThrowIfNull(rhs, nameof(rhs));
+ Operation = op;
+ Left = lhs;
+ Right = rhs;
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ Left.WriteAll(writer);
+ writer.Write(string.Format(Operation == CSBinaryOperator.Dot ? "{0}" : " {0} ", OpToString(Operation)), true);
+ Right.WriteAll(writer);
+ }
+
+ public CSBinaryOperator Operation { get; private set; }
+ public ICSExpression Left { get; private set; }
+ public ICSExpression Right { get; private set; }
+
+ static string OpToString(CSBinaryOperator op)
+ {
+ switch (op)
+ {
+ case CSBinaryOperator.Add:
+ return "+";
+ case CSBinaryOperator.Sub:
+ return "-";
+ case CSBinaryOperator.Mul:
+ return "*";
+ case CSBinaryOperator.Div:
+ return "/";
+ case CSBinaryOperator.Mod:
+ return "%";
+ case CSBinaryOperator.And:
+ return "&&";
+ case CSBinaryOperator.Or:
+ return "||";
+ case CSBinaryOperator.Less:
+ return "<";
+ case CSBinaryOperator.Greater:
+ return ">";
+ case CSBinaryOperator.Equal:
+ return "==";
+ case CSBinaryOperator.NotEqual:
+ return "!=";
+ case CSBinaryOperator.LessEqual:
+ return "<=";
+ case CSBinaryOperator.GreaterEqual:
+ return ">=";
+ case CSBinaryOperator.BitAnd:
+ return "&";
+ case CSBinaryOperator.BitOr:
+ return "|";
+ case CSBinaryOperator.BitXor:
+ return "^";
+ case CSBinaryOperator.LeftShift:
+ return ">>";
+ case CSBinaryOperator.RightShift:
+ return "<<";
+ case CSBinaryOperator.Dot:
+ return ".";
+ case CSBinaryOperator.Is:
+ return "is";
+ case CSBinaryOperator.As:
+ return "as";
+ case CSBinaryOperator.NullCoalesce:
+ return "??";
+ default:
+ throw new ArgumentOutOfRangeException("op");
+ }
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBinding.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBinding.cs
new file mode 100644
index 000000000000..e49d5881baca
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSBinding.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSBinding : ICodeElementSet
+ {
+ public CSBinding(CSIdentifier name, ICSExpression? val = null, bool onOwnLine = false)
+ {
+ Name = name;
+ Value = val;
+ OnOwnLine = onOwnLine;
+ }
+
+ public CSBinding(string name, ICSExpression? val = null, bool onOwnLine = false)
+ : this(new CSIdentifier(name), val, onOwnLine)
+ {
+ }
+
+ public CSIdentifier Name { get; private set; }
+ public ICSExpression? Value { get; private set; }
+ public bool OnOwnLine { get; private set; }
+
+ public override string ToString()
+ {
+ return string.Format("{0}{1}{2}",
+ Name.Name, Value == null ? "" : " = ", Value == null ? "" : Value.ToString());
+ }
+
+ #region ICodeElem implementation
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ if (OnOwnLine)
+ args.Writer.BeginNewLine(true);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+ #endregion
+
+ #region ICodeElemSet implementation
+ public IEnumerable Elements
+ {
+ get
+ {
+ yield return Name;
+ if (Value != null)
+ {
+ yield return new SimpleElement(" = ", true);
+ yield return Value;
+ }
+ }
+ }
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSClass.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSClass.cs
new file mode 100644
index 000000000000..fe1685cfff5f
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSClass.cs
@@ -0,0 +1,218 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSClass : ICodeElementSet, ICSTopLevelDeclaration
+ {
+ public CSClass(CSVisibility vis, CSIdentifier name, IEnumerable? methods = null,
+ bool isStatic = false, bool isSealed = false)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Visibility = vis;
+ IsStatic = isStatic;
+ IsSealed = isSealed;
+ Name = name;
+ Inheritance = new CSInheritance();
+ Delegates = new List();
+ Fields = new List();
+ Constructors = new List();
+ Methods = new List();
+ Properties = new List();
+ InnerClasses = new CSClasses();
+ InnerEnums = new List();
+ StaticConstructor = new CSCodeBlock();
+ GenericParams = new CSGenericTypeDeclarationCollection();
+ GenericConstraints = new CSGenericConstraintCollection();
+
+ if (methods != null)
+ Methods.AddRange(methods);
+ }
+
+ public CSClass(CSVisibility vis, string name,
+ IEnumerable? members = null, bool isStatic = false, bool isSealed = false)
+ : this(vis, new CSIdentifier(name), members, isStatic, isSealed)
+ {
+ }
+
+ protected virtual string EntityLabel { get { return "class"; } }
+
+ public CSVisibility Visibility { get; private set; }
+ public bool IsStatic { get; private set; }
+ public bool IsSealed { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CSInheritance Inheritance { get; private set; }
+ public List Delegates { get; private set; }
+ public List Fields { get; private set; }
+ public List Constructors { get; private set; }
+ public List Methods { get; private set; }
+ public List Properties { get; private set; }
+ public CSClasses InnerClasses { get; private set; }
+ public List InnerEnums { get; private set; }
+ public CSCodeBlock StaticConstructor { get; private set; }
+ public CSGenericTypeDeclarationCollection GenericParams { get; private set; }
+ public CSGenericConstraintCollection GenericConstraints { get; private set; }
+
+ public CSType ToCSType(IEnumerable genericReplacements)
+ {
+ List replacements = genericReplacements.ToList();
+ if (replacements.Count < GenericParams.Count)
+ {
+ replacements.AddRange(GenericParams.Skip(replacements.Count).Select(gen => new CSSimpleType(gen.Name.Name)));
+ }
+ CSSimpleType t = new CSSimpleType(Name.Name, false, replacements.ToArray());
+ return t;
+ }
+
+ public CSType ToCSType()
+ {
+ return ToCSType(GenericParams.Select(gen => new CSSimpleType(gen.Name.Name)));
+ }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public virtual object? BeginWrite(ICodeWriter writer)
+ {
+ OnBeginWrite(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBeginWrite(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public virtual void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public virtual void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEndWrite(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEndWrite(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public IEnumerable Elements
+ {
+ get
+ {
+ var decl = new LineCodeElementCollection(true, false, true);
+ if (Visibility != CSVisibility.None)
+ decl.Add(new SimpleElement(CSMethod.VisibilityToString(Visibility) + " "));
+ if (IsStatic)
+ decl.Add(new SimpleElement("static ", true));
+ if (IsSealed)
+ decl.Add(new SimpleElement("sealed ", true));
+ decl.Add(new CSIdentifier(EntityLabel + " "));
+ decl.Add(Name);
+ decl.Add(GenericParams);
+ if (Inheritance.Count > 0)
+ {
+ decl.Add(new SimpleElement(" : ", true));
+ decl.Add(Inheritance);
+ }
+ if (GenericConstraints.Count > 0)
+ {
+ decl.Add(SimpleElement.Spacer);
+ decl.Add(GenericConstraints);
+ }
+ yield return decl;
+
+ var contents = new DecoratedCodeElementCollection("{", "}",
+ true, true, true);
+
+ contents.AddRange(Delegates);
+ contents.AddRange(Fields);
+
+ if (StaticConstructor.Count > 0)
+ {
+ var m = new CSMethod(CSVisibility.None, CSMethodKind.Static,
+ null, Name, new CSParameterList(), StaticConstructor);
+ contents.Add(m);
+ }
+ contents.AddRange(Constructors);
+ contents.AddRange(Methods);
+ contents.AddRange(Properties);
+ contents.Add(InnerClasses);
+ contents.AddRange(InnerEnums);
+
+ yield return contents;
+
+ }
+ }
+
+ #endregion
+ }
+
+ public class CSClasses : CodeElementCollection
+ {
+ public CSClasses(IEnumerable? classes = null)
+ : base()
+ {
+ if (classes != null)
+ AddRange(classes);
+ }
+
+ public CSClasses And(CSClass use)
+ {
+ Add(use);
+ return this;
+ }
+ }
+
+ public class CSStruct : CSClass
+ {
+ public CSStruct(CSVisibility vis, CSIdentifier name, IEnumerable? methods = null,
+ bool isStatic = false, bool isSealed = false)
+ : base(vis, name, methods, isStatic, isSealed)
+ {
+ }
+
+ public CSStruct(CSVisibility vis, string name,
+ IEnumerable? members = null, bool isStatic = false, bool isSealed = false)
+ : this(vis, new CSIdentifier(name), members, isStatic, isSealed)
+ {
+ }
+
+ protected override string EntityLabel
+ {
+ get
+ {
+ return "struct";
+ }
+ }
+ }
+
+ public class CSStructs : CodeElementCollection
+ {
+ public CSStructs(IEnumerable? structs = null)
+ : base()
+ {
+ if (structs != null)
+ AddRange(structs);
+ }
+
+ public CSStructs And(CSStruct st)
+ {
+ Add(st);
+ return this;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSCodeBlock.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSCodeBlock.cs
new file mode 100644
index 000000000000..acff4591d330
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSCodeBlock.cs
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSCodeBlock : DecoratedCodeElementCollection, ICSStatement
+ {
+ public CSCodeBlock()
+ : this(null)
+ {
+
+ }
+
+ public CSCodeBlock(IEnumerable? statements)
+ : this("{", "}", statements)
+ {
+ }
+
+ public static CSCodeBlock Create(params ICodeElement[] statements)
+ {
+ return new CSCodeBlock(statements);
+ }
+
+ public CSCodeBlock(string start, string end, IEnumerable? statements)
+ : base(start, end, true, true, true)
+ {
+ if (statements != null)
+ {
+ foreach (ICodeElement elem in statements)
+ {
+ And(elem);
+ }
+ }
+ }
+
+ public CSCodeBlock And(ICodeElement elem)
+ {
+ if (!(elem is ICSStatement))
+ throw new ArgumentException($"contents must each be an IStatement, got {elem.GetType()}");
+ Add(elem);
+ return this;
+ }
+ }
+
+ public class CSUnsafeCodeBlock : CSCodeBlock
+ {
+ public CSUnsafeCodeBlock(IEnumerable statements)
+ : base("unsafe {", "}", statements)
+ {
+ }
+ }
+
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSComment.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSComment.cs
new file mode 100644
index 000000000000..cd152bb04a91
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSComment.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSComment : SimpleLineElement
+ {
+ public CSComment(string text)
+ : base(Commentize(text), false, true, false)
+ {
+ }
+
+ static string Commentize(string text)
+ {
+ text = text ?? "";
+ if (text.Contains("\n"))
+ throw new ArgumentException("Comment text must not contain new line characters.", "text");
+ return "// " + text;
+ }
+ }
+
+ public class CSCommentBlock : CodeElementCollection
+ {
+ public CSCommentBlock(params CSComment[] comments)
+ {
+ AddRange(comments);
+ }
+
+ public CSCommentBlock(params string[] text)
+ {
+ ArgumentNullException.ThrowIfNull(text, nameof(text));
+ AddRange(Sanitize(text));
+ }
+
+ static IEnumerable Sanitize(string[] text)
+ {
+ foreach (string s in text)
+ {
+ string[] lines = s.Split('\n');
+ foreach (string line in lines)
+ yield return new CSComment(line);
+ }
+ }
+
+ public CSCommentBlock And(string text)
+ {
+ AddRange(Sanitize(new string[] { text }));
+ return this;
+ }
+
+ public CSCommentBlock And(CSComment comment)
+ {
+ ArgumentNullException.ThrowIfNull(comment, nameof(comment));
+ Add(comment);
+ return this;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSConditionalCompilation.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSConditionalCompilation.cs
new file mode 100644
index 000000000000..dc939eba3e58
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSConditionalCompilation.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSConditionalCompilation : LineCodeElementCollection
+ {
+ CSConditionalCompilation(CSIdentifier tag, CSIdentifier? condition)
+ : base(true, false, false)
+ {
+ Add(tag);
+ if ((object?)condition != null)
+ {
+ Add(SimpleElement.Spacer);
+ Add(condition);
+ }
+ }
+
+ static CSConditionalCompilation _else = new CSConditionalCompilation(new CSIdentifier("#else"), null);
+ public static CSConditionalCompilation Else { get { return _else; } }
+ static CSConditionalCompilation _endif = new CSConditionalCompilation(new CSIdentifier("#endif"), null);
+ public static CSConditionalCompilation Endif { get { return _endif; } }
+
+ public static CSConditionalCompilation If(CSIdentifier condition)
+ {
+ ArgumentNullException.ThrowIfNull(condition, nameof(condition));
+ return new CSConditionalCompilation(new CSIdentifier("#if"), condition);
+ }
+
+ public static void ProtectWithIfEndif(CSIdentifier condition, ICodeElement elem)
+ {
+ var @if = If(condition);
+ @if.AttachBefore(elem);
+ Endif.AttachAfter(elem);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSConstant.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSConstant.cs
new file mode 100644
index 000000000000..6e28b1f1bcc9
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSConstant.cs
@@ -0,0 +1,78 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+using System.IO;
+using System.CodeDom.Compiler;
+using System.CodeDom;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSConstant : CSBaseExpression
+ {
+ public CSConstant(string val)
+ {
+ ArgumentNullException.ThrowIfNull(val, nameof(val));
+ Value = val;
+ }
+
+ public static explicit operator CSConstant(string val)
+ {
+ return new CSConstant(val);
+ }
+
+ public string Value { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write(Value, false);
+ }
+
+ public static CSConstant Val(byte b) { return new CSConstant(b.ToString()); }
+ public static CSConstant Val(sbyte sb) { return new CSConstant(sb.ToString()); }
+ public static CSConstant Val(ushort us) { return new CSConstant(us.ToString()); }
+ public static CSConstant Val(short s) { return new CSConstant(s.ToString()); }
+ public static CSConstant Val(uint ui) { return new CSConstant(ui.ToString()); }
+ public static CSConstant Val(int i) { return new CSConstant(i.ToString()); }
+ public static CSConstant Val(ulong ul) { return new CSConstant(ul.ToString()); }
+ public static CSConstant Val(long l) { return new CSConstant(l.ToString()); }
+ public static CSConstant Val(float f)
+ {
+ return new CSConstant(f.ToString() + "f");
+ }
+ public static CSConstant Val(double d) { return new CSConstant(d.ToString()); }
+ public static CSConstant Val(bool b) { return new CSConstant(b ? "true" : "false"); }
+ public static CSConstant Val(char c) { return new CSConstant(ToCharLiteral(c)); }
+ public static CSConstant Val(string s) { return new CSConstant(ToStringLiteral(s)); }
+ static CSConstant cNull = new CSConstant("null");
+ public static CSConstant Null { get { return cNull; } }
+ static CSConstant cIntPtrZero = new CSConstant("IntPtr.Zero");
+ public static CSConstant IntPtrZero { get { return cIntPtrZero; } }
+ public static CSBaseExpression ValNFloat(double d) { return new CSCastExpression(CSSimpleType.NFloat, Val(d)); }
+
+ static string ToCharLiteral(char c)
+ {
+ using (var writer = new StringWriter())
+ {
+ using (var provider = CodeDomProvider.CreateProvider("CSharp"))
+ {
+ provider.GenerateCodeFromExpression(new CodePrimitiveExpression(c), writer, new CodeGeneratorOptions());
+ return writer.ToString();
+ }
+ }
+ }
+
+ static string ToStringLiteral(string s)
+ {
+ using (var writer = new StringWriter())
+ {
+ using (var provider = CodeDomProvider.CreateProvider("CSharp"))
+ {
+ provider.GenerateCodeFromExpression(new CodePrimitiveExpression(s), writer, new CodeGeneratorOptions());
+ return writer.ToString();
+ }
+ }
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSDelegateTypeDecl.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSDelegateTypeDecl.cs
new file mode 100644
index 000000000000..94b9d6326324
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSDelegateTypeDecl.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSDelegateTypeDecl : DelegatedSimpleElement, ICSStatement
+ {
+ public CSDelegateTypeDecl(CSVisibility vis, CSType type, CSIdentifier name, CSParameterList parms, bool isUnsafe = false)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Visibility = vis;
+ Type = type != null ? type : CSSimpleType.Void;
+ Name = name;
+ Parameters = parms;
+ IsUnsafe = isUnsafe;
+ }
+
+ public CSVisibility Visibility { get; private set; }
+ public CSType Type { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CSParameterList Parameters { get; private set; }
+ public bool IsUnsafe { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.BeginNewLine(true);
+ writer.Write(CSMethod.VisibilityToString(Visibility), false);
+ if (IsUnsafe)
+ writer.Write(" unsafe", true);
+ writer.Write(" delegate ", true);
+ Type.WriteAll(writer);
+ writer.Write(' ', true);
+ Name.WriteAll(writer);
+ writer.Write('(', true);
+ Parameters.WriteAll(writer);
+ writer.Write(')', true);
+ writer.Write(';', false);
+ writer.EndLine();
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSEnum.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSEnum.cs
new file mode 100644
index 000000000000..14bd0db4cd89
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSEnum.cs
@@ -0,0 +1,107 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSEnum : ICodeElementSet, ICSTopLevelDeclaration
+ {
+ public CSEnum(CSVisibility vis, CSIdentifier name, CSType optionalType)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Values = new List();
+ Name = name;
+ OptionalType = optionalType;
+ Visibility = vis;
+ }
+
+ public CSEnum(CSVisibility vis, string name, CSType optionalType)
+ : this(vis, new CSIdentifier(name), optionalType)
+ {
+ }
+
+ public List Values { get; private set; }
+ public CSVisibility Visibility { get; private set; }
+ public CSType OptionalType { get; private set; }
+ public CSIdentifier Name { get; private set; }
+
+ public CSType ToCSType()
+ {
+ return new CSSimpleType(Name.Name);
+ }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public virtual object? BeginWrite(ICodeWriter writer)
+ {
+ OnBeginWrite(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBeginWrite(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public virtual void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public virtual void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEndWrite(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEndWrite(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public IEnumerable Elements
+ {
+ get
+ {
+ var decl = new LineCodeElementCollection(true, false, true);
+ if (Visibility != CSVisibility.None)
+ decl.Add(new SimpleElement(CSMethod.VisibilityToString(Visibility) + " "));
+ decl.Add(new CSIdentifier("enum" + " "));
+ decl.Add(Name);
+
+ if (OptionalType != null)
+ {
+ decl.Add(new SimpleElement(" : ", true));
+ decl.Add(OptionalType);
+ }
+ yield return decl;
+
+ var contents = new DecoratedCodeElementCollection("{", "}",
+ true, true, true);
+
+ var bindings = new CommaListElementCollection();
+ bindings.AddRange(Values);
+ if (bindings.Count > 0 && !bindings[0].OnOwnLine)
+ {
+ bindings[0] = new CSBinding(bindings[0].Name, bindings[0].Value, true);
+ }
+ contents.Add(bindings);
+
+ yield return contents;
+
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFieldDeclaration.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFieldDeclaration.cs
new file mode 100644
index 000000000000..880b50353b37
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFieldDeclaration.cs
@@ -0,0 +1,112 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSVariableDeclaration : LineCodeElementCollection, ICSExpression, ICSLineable
+ {
+ public CSVariableDeclaration(CSType type, IEnumerable bindings)
+ : base(null, false, true)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(bindings, nameof(bindings));
+ Type = type;
+ And(Type).And(SimpleElement.Spacer);
+ Bindings = new CommaListElementCollection(bindings);
+ Add(Bindings);
+ }
+
+ public CSVariableDeclaration(CSType type, string name, ICSExpression? value = null)
+ : this(type, new CSIdentifier(name), value)
+ {
+ }
+
+ public CSVariableDeclaration(CSType type, CSIdentifier name, ICSExpression? value = null)
+ : this(type, new CSBinding[] { new CSBinding(name, value) })
+ {
+ }
+
+ public CSType Type { get; private set; }
+ public CommaListElementCollection Bindings { get; private set; }
+
+ public static CSLine VarLine(CSType type, CSIdentifier name, ICSExpression? value = null)
+ {
+ return new CSLine(new CSVariableDeclaration(type, name, value));
+ }
+
+ public static CSLine VarLine(CSType type, string name, ICSExpression? value = null)
+ {
+ return new CSLine(new CSVariableDeclaration(type, name, value));
+ }
+
+ public static CSLine VarLine(string name, ICSExpression value)
+ {
+ return new CSLine(new CSVariableDeclaration(CSSimpleType.Var, name, value));
+ }
+
+ public static CSLine VarLine(CSIdentifier name, ICSExpression value)
+ {
+ return new CSLine(new CSVariableDeclaration(CSSimpleType.Var, name, value));
+ }
+ }
+
+ public class CSFieldDeclaration : CSVariableDeclaration
+ {
+ public CSFieldDeclaration(CSType type, IEnumerable bindings, CSVisibility vis = CSVisibility.None, bool isStatic = false, bool isReadonly = false, bool isUnsafe = false)
+ : base(type, bindings)
+ {
+ Visibilty = vis;
+ IsStatic = isStatic;
+ IsUnsafe = isUnsafe;
+ if (isReadonly)
+ {
+ this.Insert(0, new SimpleElement("readonly"));
+ this.Insert(1, SimpleElement.Spacer);
+ }
+ if (IsUnsafe)
+ {
+ this.Insert(0, new SimpleElement("unsafe"));
+ this.Insert(1, SimpleElement.Spacer);
+ }
+ if (isStatic)
+ {
+ this.Insert(0, new SimpleElement("static"));
+ this.Insert(1, SimpleElement.Spacer);
+ }
+ if (vis != CSVisibility.None)
+ {
+ this.Insert(0, new SimpleElement(CSMethod.VisibilityToString(vis)));
+ this.Insert(1, SimpleElement.Spacer);
+ }
+ }
+
+ public CSFieldDeclaration(CSType type, string name, ICSExpression? value = null, CSVisibility vis = CSVisibility.None, bool isStatic = false, bool isReadonly = false, bool isUnsafe = false)
+ : this(type, new CSIdentifier(name), value, vis, isStatic, isReadonly, isUnsafe)
+ {
+ }
+
+ public CSFieldDeclaration(CSType type, CSIdentifier name, ICSExpression? value = null, CSVisibility vis = CSVisibility.None, bool isStatic = false, bool isReadOnly = false, bool isUnsafe = false)
+ : this(type, new CSBinding[] { new CSBinding(name, value) }, vis, isStatic, isReadOnly, isUnsafe)
+ {
+ }
+
+ public CSVisibility Visibilty { get; private set; }
+ public bool IsStatic { get; private set; }
+ public bool IsUnsafe { get; private set; }
+
+ public static CSLine FieldLine(CSType type, CSIdentifier name, ICSExpression? value = null, CSVisibility vis = CSVisibility.None, bool isStatic = false)
+ {
+ return new CSLine(new CSFieldDeclaration(type, name, value, vis, isStatic));
+ }
+
+ public static CSLine FieldLine(CSType type, string name, ICSExpression? value = null, CSVisibility vis = CSVisibility.None, bool isStatic = false)
+ {
+ return new CSLine(new CSFieldDeclaration(type, name, value, vis, isStatic));
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFile.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFile.cs
new file mode 100644
index 000000000000..2587b2b2e9bb
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFile.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSFile : ICodeElementSet
+ {
+ public CSFile(CSUsingPackages use, IEnumerable ns)
+ {
+ Using = use ?? new CSUsingPackages();
+ ns = ns ?? new CSNamespace[0];
+ Namespaces = new CSNamespaceBlock(ns);
+ }
+
+ public static CSFile Create(CSUsingPackages use, params CSNamespace[] ns)
+ {
+ return new CSFile(use, ns);
+ }
+
+ public CSUsingPackages Using { get; private set; }
+ public CSNamespaceBlock Namespaces { get; private set; }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ OnBegin(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBegin(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEnd(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEnd(WriteEventArgs args)
+ {
+ End(this, args);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public System.Collections.Generic.IEnumerable Elements
+ {
+ get
+ {
+ yield return Using;
+ yield return Namespaces;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFileBasic.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFileBasic.cs
new file mode 100644
index 000000000000..57fc2f050595
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFileBasic.cs
@@ -0,0 +1,69 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSFileBasic : ICodeElementSet
+ {
+ string nameSpace;
+
+ public CSFileBasic(string nameSpace)
+ {
+ ArgumentNullException.ThrowIfNull(nameSpace, nameof(nameSpace));
+ this.nameSpace = nameSpace;
+ Using = new CSUsingPackages();
+ Classes = new CSClasses();
+ }
+
+ #region ICodeElem implementation
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public CSClasses Classes { get; private set; }
+ public CSUsingPackages Using { get; private set; }
+
+ public object? BeginWrite(ICodeWriter writer)
+ {
+ return null;
+ }
+
+ public void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public void EndWrite(ICodeWriter writer, object? o)
+ {
+ }
+
+ protected virtual void OnBegin(WriteEventArgs e)
+ {
+ Begin(this, e);
+ }
+
+ protected virtual void OnEnd(WriteEventArgs e)
+ {
+ End(this, e);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public System.Collections.Generic.IEnumerable Elements
+ {
+ get
+ {
+ yield return Using;
+ CSNamespace ns = new CSNamespace(nameSpace);
+ ns.Block.AddRange(Classes);
+ yield return ns;
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFixed.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFixed.cs
new file mode 100644
index 000000000000..023be1f6292b
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFixed.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSFixedCodeBlock : CSCodeBlock, ICSStatement
+ {
+ public CSFixedCodeBlock(CSType type, CSIdentifier ident, CSBaseExpression expr, IEnumerable body)
+ : base(body)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(ident, nameof(ident));
+ ArgumentNullException.ThrowIfNull(expr, nameof(expr));
+ Type = type;
+ Identifier = ident;
+ Expr = expr;
+ }
+
+ public override void Write(ICodeWriter writer, object? o)
+ {
+ writer.BeginNewLine(true);
+ writer.Write("fixed (", true);
+ Type.Write(writer, o);
+ writer.Write(' ', false);
+ Identifier.Write(writer, o);
+ writer.Write(" = ", true);
+ Expr.Write(writer, o);
+ writer.Write(") ", true);
+ base.Write(writer, o);
+ }
+
+ public CSType Type { get; private set; }
+ public CSIdentifier Identifier { get; private set; }
+ public CSBaseExpression Expr { get; private set; }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSForEach.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSForEach.cs
new file mode 100644
index 000000000000..7719ee0e83b9
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSForEach.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+namespace SyntaxDynamo.CSLang
+{
+ public class CSForEach : CodeElementCollection, ICSStatement
+ {
+
+ class ForElement : DelegatedSimpleElement, ICSStatement
+ {
+ public ForElement(CSType type, CSIdentifier ident, CSBaseExpression expr)
+ : base()
+ {
+ Type = type;
+ Ident = ident;
+ Expr = expr;
+ }
+
+ public CSType Type { get; private set; }
+ public CSIdentifier Ident { get; private set; }
+ public CSBaseExpression Expr { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.BeginNewLine(true);
+ writer.Write("foreach (", false);
+ if (Type != null)
+ {
+ Type.WriteAll(writer);
+ }
+ else
+ {
+ writer.Write("var", false);
+ }
+ SimpleElement.Spacer.WriteAll(writer);
+ Ident.WriteAll(writer);
+ writer.Write(" in ", true);
+ Expr.WriteAll(writer);
+ writer.Write(")", false);
+ writer.EndLine();
+ }
+ }
+
+ public CSForEach(CSType type, CSIdentifier ident, CSBaseExpression expr, CSCodeBlock body)
+ {
+ ArgumentNullException.ThrowIfNull(ident, nameof(ident));
+ ArgumentNullException.ThrowIfNull(expr, nameof(expr));
+ Type = type;
+ Ident = ident;
+ Expr = expr;
+ Body = body ?? new CSCodeBlock();
+ Add(new ForElement(type, ident, expr));
+ Add(Body);
+ }
+
+ public CSForEach(CSType type, string ident, CSBaseExpression expr, CSCodeBlock body)
+ : this(type, new CSIdentifier(ident), expr, body)
+ {
+ }
+
+ public CSType Type { get; private set; }
+ public CSIdentifier Ident { get; private set; }
+ public CSBaseExpression Expr { get; private set; }
+ public CSCodeBlock Body { get; private set; }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFunctionCall.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFunctionCall.cs
new file mode 100644
index 000000000000..c043a6fc58c6
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSFunctionCall.cs
@@ -0,0 +1,136 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSFunctionCall : CSBaseExpression, ICSLineable
+ {
+ public CSFunctionCall(CSIdentifier ident, CommaListElementCollection paramList, bool isConstructor = false)
+ {
+ ArgumentNullException.ThrowIfNull(ident, nameof(ident));
+ ArgumentNullException.ThrowIfNull(paramList, nameof(paramList));
+ Name = ident;
+ Parameters = paramList;
+ IsConstructor = isConstructor;
+ }
+
+ public CSFunctionCall(string identifier, bool isConstructor, params CSBaseExpression[] parameters)
+ : this(new CSIdentifier(identifier), new CommaListElementCollection(parameters), isConstructor)
+ {
+ }
+
+ public static CSFunctionCall Function(string identifier, params CSBaseExpression[] parameters)
+ {
+ return new CSFunctionCall(identifier, false, parameters);
+ }
+ public static CSLine FunctionLine(string identifier, params CSBaseExpression[] parameters) => new CSLine(Function(identifier, parameters));
+
+ public static CSFunctionCall Ctor(string identifier, params CSBaseExpression[] parameters)
+ {
+ return new CSFunctionCall(identifier, true, parameters);
+ }
+ public static CSLine CtorLine(string identifier, params CSBaseExpression[] parameters) => new CSLine(Ctor(identifier, parameters));
+
+ public static CSLine ConsoleWriteLine(params CSBaseExpression[] parameters) => FunctionLine("Console.WriteLine", parameters);
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ if (IsConstructor)
+ writer.Write("new ", false);
+ Name.WriteAll(writer);
+ writer.Write("(", false);
+ Parameters.WriteAll(writer);
+ writer.Write(")", false);
+ }
+
+ public bool IsConstructor { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CommaListElementCollection Parameters { get; private set; }
+
+ public static CSLine FunctionCallLine(CSIdentifier identifier, params CSBaseExpression[] parameters)
+ {
+ return FunctionCallLine(identifier, false, parameters);
+ }
+
+ public static CSLine FunctionCallLine(CSIdentifier identifier, bool isConstructor, params CSBaseExpression[] parameters)
+ {
+ return new CSLine(new CSFunctionCall(identifier,
+ new CommaListElementCollection(parameters), isConstructor));
+ }
+
+ public static CSLine FunctionCallLine(string identifier, params CSBaseExpression[] parameters)
+ {
+ return FunctionCallLine(identifier, false, parameters);
+ }
+
+ public static CSLine FunctionCallLine(string identifier, bool isConstructor, params CSBaseExpression[] parameters)
+ {
+ ArgumentNullException.ThrowIfNull(identifier, nameof(identifier));
+ return new CSLine(new CSFunctionCall(new CSIdentifier(identifier),
+ new CommaListElementCollection(parameters), isConstructor));
+ }
+
+ static CSIdentifier iNameOf = new CSIdentifier("nameof");
+
+ public static CSFunctionCall Nameof(CSIdentifier id)
+ {
+ return FooOf(iNameOf, id);
+ }
+
+ public static CSFunctionCall Nameof(string name)
+ {
+ return Nameof(new CSIdentifier(name));
+ }
+
+ static CSIdentifier iTypeof = new CSIdentifier("typeof");
+
+ public static CSFunctionCall Typeof(Type t)
+ {
+ return Typeof(t.Name);
+ }
+
+ public static CSFunctionCall Typeof(string t)
+ {
+ return FooOf(iTypeof, new CSIdentifier(t));
+ }
+
+ public static CSFunctionCall Typeof(CSSimpleType t)
+ {
+ return Typeof(t.Name);
+ }
+
+ static CSIdentifier iSizeof = new CSIdentifier("sizeof");
+
+ public static CSFunctionCall Sizeof(CSBaseExpression expr)
+ {
+ return FooOf(iSizeof, expr);
+ }
+
+ static CSIdentifier iDefault = new CSIdentifier("default");
+
+ public static CSFunctionCall Default(Type t)
+ {
+ return Default(t.Name);
+ }
+
+ public static CSFunctionCall Default(string t)
+ {
+ return FooOf(iDefault, new CSIdentifier(t));
+ }
+
+ public static CSFunctionCall Default(CSSimpleType t)
+ {
+ return Default(t.Name);
+ }
+
+ static CSFunctionCall FooOf(CSIdentifier foo, CSBaseExpression parameter)
+ {
+ CommaListElementCollection parms = new CommaListElementCollection();
+ parms.Add(parameter);
+ return new CSFunctionCall(foo, parms, false);
+ }
+ }
+
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSGenericConstraint.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSGenericConstraint.cs
new file mode 100644
index 000000000000..032508626b3d
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSGenericConstraint.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSGenericConstraint : DelegatedSimpleElement
+ {
+ public CSGenericConstraint(CSIdentifier name, CSIdentifier isA)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ ArgumentNullException.ThrowIfNull(isA, nameof(isA));
+ Name = name;
+ IsA = new CommaListElementCollection();
+ IsA.Add(isA);
+ }
+
+ public CSGenericConstraint(CSIdentifier name, IEnumerable multiIs)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Name = name;
+ IsA = new CommaListElementCollection();
+ if (multiIs != null)
+ IsA.AddRange(multiIs);
+ }
+
+ public CSIdentifier Name { get; private set; }
+ public CommaListElementCollection IsA { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("where ", true);
+ Name.Write(writer, o);
+ writer.Write(" : ", true);
+ IsA.WriteAll(writer);
+ }
+ }
+
+ public class CSGenericConstraintCollection : List, ICodeElementSet
+ {
+ public IEnumerable Elements
+ {
+ get
+ {
+ bool first = true;
+ foreach (CSGenericConstraint tc in this)
+ {
+ if (!first)
+ {
+ yield return new LineBreak();
+ }
+ first = false;
+ yield return tc;
+ }
+ }
+ }
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public virtual object? BeginWrite(ICodeWriter writer)
+ {
+ OnBeginWrite(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBeginWrite(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public virtual void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public virtual void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEndWrite(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEndWrite(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ }
+
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSGenericTypeDeclaration.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSGenericTypeDeclaration.cs
new file mode 100644
index 000000000000..8609da198d21
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSGenericTypeDeclaration.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSGenericTypeDeclaration
+ {
+ public CSGenericTypeDeclaration(CSIdentifier name)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Name = name;
+ }
+
+ public CSIdentifier Name { get; private set; }
+ }
+
+ public class CSGenericTypeDeclarationCollection : List, ICodeElementSet
+ {
+ public CSGenericTypeDeclarationCollection()
+ : base()
+ {
+ }
+
+ public IEnumerable Elements
+ {
+ get
+ {
+ if (this.Count > 0)
+ {
+ yield return new SimpleElement("<");
+ bool first = true;
+ foreach (CSGenericTypeDeclaration decl in this)
+ {
+ if (!first)
+ {
+ yield return new SimpleElement(",", true);
+ yield return SimpleElement.Spacer;
+ }
+ else
+ {
+ first = false;
+ }
+ yield return decl.Name;
+ }
+ yield return new SimpleElement(">");
+ }
+ }
+ }
+
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public virtual object? BeginWrite(ICodeWriter writer)
+ {
+ OnBeginWrite(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBeginWrite(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public virtual void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public virtual void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEndWrite(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEndWrite(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIdentifier.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIdentifier.cs
new file mode 100644
index 000000000000..a6596679d4dc
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIdentifier.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSIdentifier : CSBaseExpression
+ {
+ public CSIdentifier(string name)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Name = name;
+ }
+
+ public static explicit operator CSIdentifier(string name)
+ {
+ return new CSIdentifier(name);
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write(Name, false);
+ }
+
+ public string Name { get; private set; }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+
+ public static CSIdentifier Create(string name) => new CSIdentifier(name);
+
+ static CSIdentifier thisID = new CSIdentifier("this");
+ public static CSIdentifier This { get { return thisID; } }
+ static CSIdentifier baseID = new CSIdentifier("base");
+ public static CSIdentifier Base { get { return baseID; } }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIfElse.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIfElse.cs
new file mode 100644
index 000000000000..3338fb44ce54
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIfElse.cs
@@ -0,0 +1,62 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSIfElse : CodeElementCollection, ICSStatement
+ {
+ class CSIfElement : DelegatedSimpleElement, ICSStatement
+ {
+ public CSIfElement(CSBaseExpression condition)
+ : base()
+ {
+ Condition = condition;
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.BeginNewLine(true);
+ writer.Write("if (", false);
+ Condition.WriteAll(writer);
+ writer.Write(")", false);
+ writer.EndLine();
+ }
+
+ public CSBaseExpression Condition { get; private set; }
+ }
+
+ public CSIfElse(CSBaseExpression condition, CSCodeBlock ifClause, CSCodeBlock? elseClause = null)
+ : base()
+ {
+ ArgumentNullException.ThrowIfNull(condition, nameof(condition));
+ ArgumentNullException.ThrowIfNull(ifClause, nameof(ifClause));
+ Condition = new CSIfElement(condition);
+ IfClause = ifClause;
+ ElseClause = elseClause;
+
+ Add(Condition);
+ Add(IfClause);
+ if (ElseClause != null && ElseClause.Count > 0)
+ {
+ Add(new SimpleLineElement("else", false, true, false));
+ Add(ElseClause);
+ }
+ }
+
+ public CSIfElse(CSBaseExpression expr, IEnumerable ifClause, IEnumerable elseClause)
+ : this(expr, new CSCodeBlock(ifClause),
+ elseClause != null ? new CSCodeBlock(elseClause) : null)
+
+ {
+
+ }
+
+ public DelegatedSimpleElement Condition { get; private set; }
+ public CSCodeBlock IfClause { get; private set; }
+ public CSCodeBlock? ElseClause { get; private set; }
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIndexExpression.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIndexExpression.cs
new file mode 100644
index 000000000000..dff95a42f838
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSIndexExpression.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSIndexExpression : CSBaseExpression
+ {
+ public CSIndexExpression(CSBaseExpression aggregate, CommaListElementCollection paramList, bool addParensAroundAggregate)
+ {
+ ArgumentNullException.ThrowIfNull(aggregate, nameof(aggregate));
+ ArgumentNullException.ThrowIfNull(paramList, nameof(paramList));
+ AddParensAroundAggregate = addParensAroundAggregate;
+ Aggregate = aggregate;
+ Parameters = paramList;
+ }
+
+ public CSIndexExpression(string identifier, bool addParensAroundAggregate, params CSBaseExpression[] parameters)
+ : this(new CSIdentifier(identifier), new CommaListElementCollection(parameters), addParensAroundAggregate)
+ {
+ }
+
+ public CSIndexExpression(CSBaseExpression aggregate, bool addParensAroundAggregate, params CSBaseExpression[] parameters)
+ : this(aggregate, new CommaListElementCollection(parameters), addParensAroundAggregate)
+ {
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ if (AddParensAroundAggregate)
+ writer.Write('(', false);
+ Aggregate.WriteAll(writer);
+ if (AddParensAroundAggregate)
+ writer.Write(')', false);
+ writer.Write("[", false);
+ Parameters.WriteAll(writer);
+ writer.Write("]", false);
+ }
+
+ public bool AddParensAroundAggregate { get; private set; }
+ public CSBaseExpression Aggregate { get; private set; }
+ public CommaListElementCollection Parameters { get; private set; }
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInheritance.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInheritance.cs
new file mode 100644
index 000000000000..fa8bad2f7580
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInheritance.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.IO;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSInheritance : CommaListElementCollection
+ {
+ public CSInheritance(IEnumerable identifiers)
+ {
+ if (identifiers != null)
+ AddRange(identifiers);
+ }
+
+ public CSInheritance(params string[] identifiers)
+ : this(identifiers.Select(str => new CSIdentifier(str)))
+ {
+ }
+
+ public void Add(Type t)
+ {
+ ArgumentNullException.ThrowIfNull(t, "t");
+ Add(new CSIdentifier(t.Name));
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInitializer.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInitializer.cs
new file mode 100644
index 000000000000..cfa46418fe33
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInitializer.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSInitializer : CSBaseExpression
+ {
+ public CSInitializer(IEnumerable parameters, bool appendNewlineAfterEach)
+ {
+ Parameters = new CommaListElementCollection("", "", parameters, appendNewlineAfterEach);
+ }
+
+ public CommaListElementCollection Parameters { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("{ ", false);
+ Parameters.WriteAll(writer);
+ writer.Write(" }", false);
+ }
+ }
+
+ public class CSInitializedType : CSBaseExpression
+ {
+ public CSInitializedType(CSFunctionCall call, CSInitializer initializer)
+ {
+ ArgumentNullException.ThrowIfNull(call, nameof(call));
+ ArgumentNullException.ThrowIfNull(initializer, nameof(initializer));
+ Call = call;
+ Initializer = initializer;
+ }
+
+ public CSInitializedType(CSFunctionCall call, IEnumerable parameters, bool appendNewlineAfterEach)
+ : this(call, new CSInitializer(parameters, appendNewlineAfterEach))
+ {
+ }
+
+ public CSFunctionCall Call { get; private set; }
+ public CSInitializer Initializer { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ Call.WriteAll(writer);
+ SimpleElement.Spacer.WriteAll(writer);
+ Initializer.WriteAll(writer);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInject.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInject.cs
new file mode 100644
index 000000000000..a522a92b4e8f
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInject.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace SyntaxDynamo.CSLang
+{
+ // CSInject is a way to more formalize the notion of code that is just plain easier to
+ // inject as raw text. It's not strictly necessary, but when you see a CSInject, it will make
+ // it clear that you're doing something not quite on the up and up.
+ public class CSInject : CSIdentifier
+ {
+ public CSInject(string name)
+ : base(name)
+ {
+ }
+
+ public static explicit operator CSInject(string name)
+ {
+ return new CSInject(name);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInterface.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInterface.cs
new file mode 100644
index 000000000000..5cb27359879a
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSInterface.cs
@@ -0,0 +1,125 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSInterface : ICodeElementSet, ICSTopLevelDeclaration
+ {
+ public CSInterface(CSVisibility vis, CSIdentifier name,
+ IEnumerable? methods = null)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ Visibility = vis;
+ Name = name;
+ Inheritance = new CSInheritance();
+ Methods = new List();
+ Properties = new List();
+ GenericParams = new CSGenericTypeDeclarationCollection();
+ GenericConstraints = new CSGenericConstraintCollection();
+ if (methods != null)
+ Methods.AddRange(methods);
+ }
+
+ public CSInterface(CSVisibility vis, string name, IEnumerable? methods = null)
+ : this(vis, new CSIdentifier(name), methods)
+ {
+ }
+
+ public CSType ToCSType(IEnumerable genericReplacements)
+ {
+ var replacements = genericReplacements.ToList();
+ if (replacements.Count < GenericParams.Count)
+ {
+ replacements.AddRange(GenericParams.Skip(replacements.Count).Select(gen => new CSSimpleType(gen.Name.Name)));
+ }
+ return new CSSimpleType(Name.Name, false, replacements.ToArray());
+ }
+
+ public CSType ToCSType()
+ {
+ return ToCSType(GenericParams.Select(gen => new CSSimpleType(gen.Name.Name)));
+ }
+
+ public CSVisibility Visibility { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CSInheritance Inheritance { get; private set; }
+ public List Methods { get; private set; }
+ public List Properties { get; private set; }
+ public CSGenericTypeDeclarationCollection GenericParams { get; private set; }
+ public CSGenericConstraintCollection GenericConstraints { get; private set; }
+
+ #region ICodeElem implementation
+ public event EventHandler Begin = (s, e) => { };
+
+ public event EventHandler End = (s, e) => { };
+
+ public virtual object? BeginWrite(ICodeWriter writer)
+ {
+ OnBeginWrite(new WriteEventArgs(writer));
+ return null;
+ }
+
+ protected virtual void OnBeginWrite(WriteEventArgs args)
+ {
+ Begin(this, args);
+ }
+
+ public virtual void Write(ICodeWriter writer, object? o)
+ {
+ }
+
+ public virtual void EndWrite(ICodeWriter writer, object? o)
+ {
+ OnEndWrite(new WriteEventArgs(writer));
+ }
+
+ protected virtual void OnEndWrite(WriteEventArgs args)
+ {
+ End.FireInReverse(this, args);
+ }
+
+ #endregion
+
+ #region ICodeElemSet implementation
+
+ public IEnumerable Elements
+ {
+ get
+ {
+ var decl = new LineCodeElementCollection(true, false, true);
+ if (Visibility != CSVisibility.None)
+ decl.Add(new SimpleElement(CSMethod.VisibilityToString(Visibility) + " "));
+ decl.Add(new CSIdentifier("interface "));
+ decl.Add(Name);
+
+ decl.Add(GenericParams);
+ if (Inheritance.Count > 0)
+ {
+ decl.Add(new SimpleElement(" : ", true));
+ decl.Add(Inheritance);
+ }
+ if (GenericConstraints.Count > 0)
+ {
+ decl.Add(SimpleElement.Spacer);
+ decl.Add(GenericConstraints);
+ }
+ yield return decl;
+
+ var contents = new DecoratedCodeElementCollection("{", "}",
+ true, true, true);
+
+ contents.AddRange(Methods);
+ contents.AddRange(Properties);
+
+ yield return contents;
+
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSLambda.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSLambda.cs
new file mode 100644
index 000000000000..bdabf7d746da
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSLambda.cs
@@ -0,0 +1,81 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSLambda : CSBaseExpression
+ {
+ public CSLambda(CSParameterList parameters, ICSExpression value)
+ {
+ ArgumentNullException.ThrowIfNull(value, nameof(value));
+ Parameters = parameters ?? new CSParameterList();
+ Value = value;
+ Body = null;
+ }
+
+ public CSLambda(CSParameterList parameters, CSCodeBlock body)
+ {
+ body = body ?? new CSCodeBlock();
+ Parameters = parameters ?? new CSParameterList();
+ Value = null;
+ Body = body;
+ }
+
+ public CSLambda(ICSExpression value, params string[] parameters)
+ : this(new CSParameterList(parameters.Select(p => new CSParameter(CSSimpleType.Void, new CSIdentifier(p)))), value)
+ {
+ }
+
+ public CSLambda(CSCodeBlock body, params string[] parameters)
+ : this(new CSParameterList(parameters.Select(p => new CSParameter(CSSimpleType.Void, new CSIdentifier(p)))), body)
+ {
+ }
+
+ public CSParameterList Parameters { get; private set; }
+ public ICSExpression? Value { get; private set; }
+ public CSCodeBlock? Body { get; private set; }
+
+ #region implemented abstract members of DelegatedSimpleElem
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ // hack - Parameters really want types. If you set them to void, we'll consider them to be
+ // typeless.
+ bool allVoid = Parameters.All(p => p.CSType == CSSimpleType.Void);
+
+ writer.Write('(', true);
+ if (allVoid)
+ {
+ bool didFirst = false;
+ foreach (CSParameter p in Parameters)
+ {
+ if (didFirst)
+ {
+ writer.Write(", ", true);
+ }
+ p.Name.WriteAll(writer);
+ didFirst = true;
+ }
+ }
+ else
+ {
+ Parameters.WriteAll(writer);
+ }
+ writer.Write(") => ", true);
+ if (Value != null)
+ {
+ Value.WriteAll(writer);
+ }
+ else
+ {
+ Body?.WriteAll(writer);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSLine.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSLine.cs
new file mode 100644
index 000000000000..75a7af80c699
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSLine.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSLine : DelegatedSimpleElement, ICSStatement
+ {
+ public CSLine(ICodeElement contents, bool addSemicolon = true)
+ {
+ ArgumentNullException.ThrowIfNull(contents, nameof(contents));
+ Contents = contents;
+ if (!(contents is ICSLineable) && addSemicolon)
+ throw new ArgumentException("contents must be ILineable", nameof(contents));
+ AddSemicolon = addSemicolon;
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.BeginNewLine(true);
+ Contents.WriteAll(writer);
+ if (AddSemicolon)
+ writer.Write(';', false);
+ writer.EndLine();
+ }
+
+ public ICodeElement Contents { get; private set; }
+ public bool AddSemicolon { get; set; }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSMethod.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSMethod.cs
new file mode 100644
index 000000000000..8640544ece58
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSMethod.cs
@@ -0,0 +1,249 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSMethod : CodeElementCollection
+ {
+ public CSMethod(CSVisibility vis, CSMethodKind kind, CSType? type, CSIdentifier name, CSParameterList parms, CSCodeBlock? body)
+ : this(vis, kind, type, name, parms, null, false, body)
+ {
+
+ }
+ public CSMethod(CSVisibility vis, CSMethodKind kind, CSType? type, CSIdentifier name,
+ CSParameterList parms, CSBaseExpression[]? baseOrThisCallParms, bool callsBase, CSCodeBlock? body, bool isSealed = false,
+ bool isAsync = false)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ ArgumentNullException.ThrowIfNull(parms, nameof(parms));
+ GenericParameters = new CSGenericTypeDeclarationCollection();
+ GenericConstraints = new CSGenericConstraintCollection();
+ Visibility = vis;
+ Kind = kind;
+ Type = type; // no throw on null - could be constructor
+ Name = name;
+ Parameters = parms;
+ CallsBase = callsBase;
+ BaseOrThisCallParameters = baseOrThisCallParms;
+
+ Body = body; // can be null
+ IsSealed = isSealed;
+ IsAsync = isAsync;
+
+ LineCodeElementCollection lc = new LineCodeElementCollection(new ICodeElement[0], false, true);
+ if (vis != CSVisibility.None)
+ {
+ lc.And(new SimpleElement(VisibilityToString(vis))).And(SimpleElement.Spacer);
+ }
+
+ if (isSealed)
+ {
+ lc.And(new SimpleElement("sealed")).And(SimpleElement.Spacer);
+ }
+
+ if (isAsync)
+ {
+ lc.And(new SimpleElement("async")).And(SimpleElement.Spacer);
+ }
+
+ lc.And(new SimpleElement(MethodKindToString(kind))).And(SimpleElement.Spacer);
+
+ if (type != null)
+ {
+ lc.And(type).And(SimpleElement.Spacer);
+ }
+
+ lc.And(name).And(GenericParameters).And(new SimpleElement("(")).And(parms).And(new SimpleElement(")")).And(GenericConstraints);
+ if (body == null)
+ {
+ if (!(kind == CSMethodKind.StaticExtern || kind == CSMethodKind.Interface))
+ throw new ArgumentException("Method body is only optional when method kind kind is either StaticExtern or Interface",
+ nameof(body));
+ lc.Add(new SimpleElement(";"));
+ }
+ Add(lc);
+ if (BaseOrThisCallParameters != null)
+ {
+ Add(new CSFunctionCall(CallsBase ? ": base" : ": this", false, BaseOrThisCallParameters));
+ }
+ if (body != null)
+ Add(body);
+ }
+
+ public CSVisibility Visibility { get; private set; }
+ public CSMethodKind Kind { get; private set; }
+ public CSType? Type { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CSParameterList Parameters { get; private set; }
+ public bool CallsBase { get; private set; }
+ public CSBaseExpression[]? BaseOrThisCallParameters { get; private set; }
+ public CSCodeBlock? Body { get; private set; }
+ public CSGenericTypeDeclarationCollection GenericParameters { get; private set; }
+ public CSGenericConstraintCollection GenericConstraints { get; private set; }
+ public bool IsSealed { get; private set; }
+ public bool IsAsync { get; private set; }
+
+ public CSMethod AsSealed()
+ {
+ var sealedMethod = new CSMethod(Visibility, Kind, Type, Name, Parameters, BaseOrThisCallParameters, CallsBase, Body, true);
+ return CopyGenerics(this, sealedMethod);
+ }
+
+ public CSMethod AsOverride()
+ {
+ var overrideMethod = new CSMethod(Visibility, CSMethodKind.Override, Type, Name, Parameters, BaseOrThisCallParameters, CallsBase, Body, IsSealed);
+ return CopyGenerics(this, overrideMethod);
+ }
+
+ public CSMethod AsPrivate()
+ {
+ var privateMethod = new CSMethod(CSVisibility.None, Kind, Type, Name, Parameters, BaseOrThisCallParameters, CallsBase, Body, IsSealed);
+ return CopyGenerics(this, privateMethod);
+ }
+
+ public static CSMethod CopyGenerics(CSMethod from, CSMethod to)
+ {
+ to.GenericParameters.AddRange(from.GenericParameters);
+ to.GenericConstraints.AddRange(from.GenericConstraints);
+ return to;
+ }
+
+ public static CSMethod RemoveGenerics(CSMethod from)
+ {
+ var newMethod = new CSMethod(from.Visibility, from.Kind, from.Type, from.Name, from.Parameters, from.Body);
+ return newMethod;
+ }
+
+ public static string VisibilityToString(CSVisibility visibility)
+ {
+ switch (visibility)
+ {
+ case CSVisibility.None:
+ return "";
+ case CSVisibility.Internal:
+ return "internal";
+ case CSVisibility.Private:
+ return "private";
+ case CSVisibility.Public:
+ return "public";
+ case CSVisibility.Protected:
+ return "protected";
+ default:
+ throw new ArgumentOutOfRangeException("vis");
+ }
+ }
+
+ public static string MethodKindToString(CSMethodKind kind)
+ {
+ switch (kind)
+ {
+ case CSMethodKind.None:
+ case CSMethodKind.Interface:
+ return "";
+ case CSMethodKind.Extern:
+ return "extern";
+ case CSMethodKind.New:
+ return "new";
+ case CSMethodKind.Override:
+ return "override";
+ case CSMethodKind.Static:
+ return "static";
+ case CSMethodKind.StaticExtern:
+ return "static extern";
+ case CSMethodKind.StaticNew:
+ return "static new";
+ case CSMethodKind.Virtual:
+ return "virtual";
+ case CSMethodKind.Abstract:
+ return "abstract";
+ case CSMethodKind.Unsafe:
+ return "unsafe";
+ case CSMethodKind.StaticUnsafe:
+ return "static unsafe";
+ default:
+ throw new ArgumentOutOfRangeException(nameof(kind));
+ }
+ }
+
+ public static CSMethod PublicMethod(CSType type, string name, CSParameterList parms, CSCodeBlock body)
+ {
+ ArgumentNullException.ThrowIfNull(body, nameof(body));
+ return new CSMethod(CSVisibility.Public, CSMethodKind.None, type, new CSIdentifier(name), parms, body);
+ }
+
+ public static CSMethod PublicMethod(CSMethodKind kind, CSType type, string name, CSParameterList parms, CSCodeBlock body)
+ {
+ ArgumentNullException.ThrowIfNull(body, nameof(body));
+ return new CSMethod(CSVisibility.Public, kind, type, new CSIdentifier(name), parms, body);
+ }
+
+ public static CSMethod PublicConstructor(string name, CSParameterList parms, CSCodeBlock body)
+ {
+ ArgumentNullException.ThrowIfNull(body, nameof(body));
+ return new CSMethod(CSVisibility.Public, CSMethodKind.None, null, new CSIdentifier(name), parms, body);
+ }
+
+ public static CSMethod PublicConstructor(string name, CSParameterList parms, CSCodeBlock body, params CSBaseExpression[] baseParams)
+ {
+ ArgumentNullException.ThrowIfNull(body, nameof(body));
+ return new CSMethod(CSVisibility.Public, CSMethodKind.None, null, new CSIdentifier(name), parms,
+ baseParams, true, body);
+ }
+
+ public static CSMethod PrivateConstructor(string name, CSParameterList parms, CSCodeBlock body)
+ {
+ ArgumentNullException.ThrowIfNull(body, nameof(body));
+ return new CSMethod(CSVisibility.None, CSMethodKind.None, null, new CSIdentifier(name), parms, body);
+ }
+
+ public static CSMethod PrivateConstructor(string name, CSParameterList parms, CSCodeBlock body, params CSBaseExpression[] baseParams)
+ {
+ ArgumentNullException.ThrowIfNull(body, nameof(body));
+ return new CSMethod(CSVisibility.None, CSMethodKind.None, null, new CSIdentifier(name), parms,
+ baseParams, true, body);
+ }
+
+ public static CSMethod PInvoke(CSVisibility vis, CSType type, string name, string dllName, string externName, CSParameterList parms)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ CSMethod method = new CSMethod(vis, CSMethodKind.StaticExtern, type,
+ new CSIdentifier(name), parms, null);
+
+ CSAttribute.DllImport(dllName, externName).AttachBefore(method);
+
+ return method;
+ }
+
+ public static CSMethod PInvoke(CSVisibility vis, CSType type, string name, CSBaseExpression dllName, string externName, CSParameterList parms)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ CSMethod method = new CSMethod(vis, CSMethodKind.StaticExtern, type,
+ new CSIdentifier(name), parms, null);
+
+ CSAttribute.DllImport(dllName, externName).AttachBefore(method);
+
+ return method;
+ }
+
+ public static CSMethod PublicPInvoke(CSType type, string name, string dllName, string externName, CSParameterList parms)
+ {
+ return PInvoke(CSVisibility.Public, type, name, dllName, externName, parms);
+ }
+
+ public static CSMethod PrivatePInvoke(CSType type, string name, string dllName, string externName, CSParameterList parms)
+ {
+ return PInvoke(CSVisibility.None, type, name, dllName, externName, parms);
+ }
+
+ public static CSMethod InternalPInvoke(CSType type, string name, string dllName, string externName, CSParameterList parms)
+ {
+ return PInvoke(CSVisibility.Internal, type, name, dllName, externName, parms);
+ }
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSNamespace.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSNamespace.cs
new file mode 100644
index 000000000000..6899c4b68b6b
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSNamespace.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSNamespace : LabeledCodeElementCollection
+ {
+ public CSNamespace()
+ : base(new SimpleLineElement(string.Empty, false, false, false),
+ new DecoratedCodeElementCollection(string.Empty, string.Empty, false, false, false))
+ {
+ }
+
+ public CSNamespace(string nameSpace)
+ : base(new SimpleLineElement(string.Format("namespace {0}", nameSpace),
+ false, true, false),
+ new DecoratedCodeElementCollection("{", "}", true, true, true))
+ {
+ }
+ }
+
+ public class CSNamespaceBlock : CodeElementCollection
+ {
+ public CSNamespaceBlock(params string[] nameSpaces)
+ : base()
+ {
+ this.AddRange(nameSpaces.Select(s => new CSNamespace(s)));
+ }
+
+ public CSNamespaceBlock(IEnumerable nameSpaces)
+ : base()
+ {
+ this.AddRange(nameSpaces);
+ }
+
+ public CSNamespaceBlock And(string s)
+ {
+ return And(new CSNamespace(s));
+ }
+
+ public CSNamespaceBlock And(CSNamespace ns)
+ {
+ ArgumentNullException.ThrowIfNull(ns, nameof(ns));
+ Add(ns);
+ return this;
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSParameter.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSParameter.cs
new file mode 100644
index 000000000000..d0b08e384e18
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSParameter.cs
@@ -0,0 +1,117 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSParameter : DelegatedSimpleElement
+ {
+ public CSParameter(CSType type, CSIdentifier name,
+ CSParameterKind parameterKind = CSParameterKind.None,
+ CSConstant? defaultValue = null)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ CSType = type;
+ Name = name;
+ ParameterKind = parameterKind;
+ DefaultValue = defaultValue;
+ }
+
+ public CSParameter(CSType type, string name,
+ CSParameterKind parameterKind = CSParameterKind.None,
+ CSConstant? defaultValue = null)
+ : this(type, new CSIdentifier(name), parameterKind, defaultValue)
+ {
+ }
+
+ public CSParameter(string type, string name,
+ CSParameterKind parameterKind = CSParameterKind.None,
+ CSConstant? defaultValue = null)
+ : this(new CSSimpleType(type), new CSIdentifier(name), parameterKind, defaultValue)
+ {
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ if (this.ParameterKind != CSParameterKind.None)
+ {
+ writer.Write(ToParameterKindString(this.ParameterKind), false);
+ writer.Write(' ', false);
+ }
+ this.CSType.WriteAll(writer);
+ writer.Write(' ', true);
+ Name.WriteAll(writer);
+ if ((object?)DefaultValue != null)
+ {
+ writer.Write(" = ", true);
+ DefaultValue.WriteAll(writer);
+ }
+ }
+
+ static string ToParameterKindString(CSParameterKind parameterKind)
+ {
+ switch (parameterKind)
+ {
+ case CSParameterKind.None:
+ return "";
+ case CSParameterKind.Out:
+ return "out";
+ case CSParameterKind.Ref:
+ return "ref";
+ case CSParameterKind.This:
+ return "this";
+ case CSParameterKind.Params:
+ return "params";
+ default:
+ throw new ArgumentOutOfRangeException(nameof(parameterKind), "unexpected parameter kind " + parameterKind.ToString());
+ }
+ }
+
+ public CSType CSType { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CSConstant? DefaultValue { get; private set; }
+ public CSParameterKind ParameterKind { get; private set; }
+ }
+
+ public class CSParameterList : CommaListElementCollection
+ {
+ public CSParameterList(IEnumerable? parameters)
+ : base()
+ {
+ if (parameters != null)
+ AddRange(parameters);
+ }
+ public CSParameterList(params CSParameter[] parameters)
+ : base()
+ {
+ if (parameters != null)
+ AddRange(parameters);
+ }
+
+ public CSParameterList() : this((IEnumerable?)null) { }
+
+ public CSParameterList(CSParameter parameter) : this(new CSParameter[] { parameter }) { }
+
+ public CSParameterList And(CSParameter parameter)
+ {
+ ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
+ Add(parameter);
+ return this;
+ }
+
+ public CSParameterList And(string type, string identifier,
+ CSParameterKind parameterKind = CSParameterKind.None,
+ CSConstant? defaultValue = null)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(identifier, nameof(identifier));
+ return And(new CSParameter(new CSSimpleType(type),
+ new CSIdentifier(identifier), parameterKind, defaultValue));
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSParenthesisExpression.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSParenthesisExpression.cs
new file mode 100644
index 000000000000..49854ba97270
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSParenthesisExpression.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSParenthesisExpression : CSBaseExpression
+ {
+ public CSParenthesisExpression(ICSExpression within)
+ {
+ ArgumentNullException.ThrowIfNull(within, nameof(within));
+ Within = within;
+ }
+
+ public ICSExpression Within { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write('(', true);
+ Within.WriteAll(writer);
+ writer.Write(')', true);
+ }
+ }
+
+ public class CSCastExpression : CSBaseExpression, ICSLineable
+ {
+ public CSCastExpression(string type, ICSExpression toCast)
+ : this(new CSSimpleType(type), toCast)
+ {
+ }
+
+ public CSCastExpression(CSType type, ICSExpression toCast)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(toCast, nameof(toCast));
+ Type = type;
+ ToCast = toCast;
+ }
+
+ public CSType Type { get; private set; }
+ public ICSExpression ToCast { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("(", true);
+ Type.WriteAll(writer);
+ writer.Write(')', true);
+ ToCast.WriteAll(writer);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSProperty.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSProperty.cs
new file mode 100644
index 000000000000..bffde0716e1e
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSProperty.cs
@@ -0,0 +1,202 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Text;
+using System.Collections.Generic;
+using System.Linq;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSProperty : CodeElementCollection
+ {
+ public CSProperty(CSType type, CSMethodKind kind, CSIdentifier name,
+ CSVisibility getVis, IEnumerable getter,
+ CSVisibility setVis, IEnumerable setter)
+ : this(type, kind, name,
+ getVis, getter != null ? new CSCodeBlock(getter) : null,
+ setVis, setter != null ? new CSCodeBlock(setter) : null)
+ {
+ }
+
+ public CSProperty(CSType type, CSMethodKind kind, CSIdentifier name,
+ CSVisibility getVis, CSCodeBlock? getter,
+ CSVisibility setVis, CSCodeBlock? setter)
+ : this(type, kind, name, getVis, getter, setVis, setter, null)
+ {
+ }
+
+ public CSProperty(CSType type, CSMethodKind kind,
+ CSVisibility getVis, CSCodeBlock getter,
+ CSVisibility setVis, CSCodeBlock setter, CSParameterList parms)
+ : this(type, kind, new CSIdentifier("this"), getVis, getter, setVis, setter,
+ parms)
+ {
+ }
+
+ CSProperty(CSType type, CSMethodKind kind, CSIdentifier name,
+ CSVisibility getVis, CSCodeBlock? getter,
+ CSVisibility setVis, CSCodeBlock? setter, CSParameterList? parms)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ bool unifiedVis = getVis == setVis;
+ IndexerParameters = parms;
+
+ LineCodeElementCollection decl = new LineCodeElementCollection(null, false, true);
+
+ GetterVisibility = getVis;
+ SetterVisibility = setVis;
+ CSVisibility bestVis = (CSVisibility)Math.Min((int)getVis, (int)setVis);
+ decl.And(new SimpleElement(CSMethod.VisibilityToString(bestVis))).And(SimpleElement.Spacer);
+ if (kind != CSMethodKind.None)
+ decl.And(new SimpleElement(CSMethod.MethodKindToString(kind))).And(SimpleElement.Spacer);
+
+ PropType = type;
+ Name = name;
+
+ decl.And(type).And(SimpleElement.Spacer)
+ .And(name);
+ if (parms != null)
+ {
+ decl.And(new SimpleElement("[", true)).And(parms).And(new SimpleElement("]"));
+ }
+ Add(decl);
+
+ CSCodeBlock cb = new CSCodeBlock(null);
+
+ if (getter != null)
+ {
+ Getter = getter;
+ LineCodeElementCollection getLine = MakeEtter(getVis, "get", unifiedVis, getVis > setVis);
+ cb.Add(getLine);
+ if (getter.Count() == 0)
+ {
+ getLine.Add(new SimpleElement(";"));
+ }
+ else
+ {
+ cb.Add(getter);
+ }
+ }
+ if (setter != null)
+ {
+ Setter = setter;
+ LineCodeElementCollection setLine = MakeEtter(setVis, "set", unifiedVis, setVis > getVis);
+ cb.Add(setLine);
+ if (setter.Count() == 0)
+ {
+ setLine.Add(new SimpleElement(";"));
+ }
+ else
+ {
+ cb.Add(setter);
+ }
+ }
+
+ Add(cb);
+ }
+ public CSType PropType { get; private set; }
+ public CSIdentifier Name { get; private set; }
+ public CSParameterList? IndexerParameters { get; private set; }
+ public CSVisibility? GetterVisibility { get; private set; }
+ public CSVisibility? SetterVisibility { get; private set; }
+
+ public CSCodeBlock? Getter { get; private set; }
+
+ public CSCodeBlock? Setter { get; private set; }
+
+ static LineCodeElementCollection MakeEtter(CSVisibility vis, string getset,
+ bool unifiedVis, bool moreRestrictiveVis)
+ {
+ LineCodeElementCollection getLine = new LineCodeElementCollection(null, false, true);
+ if (!unifiedVis && vis != CSVisibility.None && moreRestrictiveVis)
+ getLine.And(new SimpleElement(CSMethod.VisibilityToString(vis))).And(SimpleElement.Spacer);
+ return getLine.And(new SimpleElement(getset, false));
+ }
+
+ public static CSProperty PublicGetSet(CSType type, string name)
+ {
+ return new CSProperty(type, CSMethodKind.None, new CSIdentifier(name),
+ CSVisibility.Public, new CSCodeBlock(), CSVisibility.Public, new CSCodeBlock());
+ }
+
+ public static CSProperty PublicGetPrivateSet(CSType type, string name)
+ {
+ return new CSProperty(type, CSMethodKind.None, new CSIdentifier(name),
+ CSVisibility.Public, new CSCodeBlock(), CSVisibility.Private, new CSCodeBlock());
+ }
+
+ static CSProperty PublicGetPubPrivSetBacking(CSType type, string name, bool declareField, bool setIsPublic, string? backingFieldName = null)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ if (!declareField && backingFieldName == null)
+ throw new ArgumentException("declareField must be true if there is no supplied field name", nameof(declareField));
+ backingFieldName = backingFieldName ?? MassageName(name);
+
+ CSIdentifier backingIdent = new CSIdentifier(backingFieldName);
+ LineCodeElementCollection getCode =
+ new LineCodeElementCollection(new ICodeElement[] { CSReturn.ReturnLine(backingIdent) }, false, true);
+ LineCodeElementCollection setCode =
+ new LineCodeElementCollection(
+ new ICodeElement[] {
+ CSAssignment.Assign (backingFieldName, new CSIdentifier ("value"))
+ }, false, true);
+ CSProperty prop = new CSProperty(type, CSMethodKind.None, new CSIdentifier(name), CSVisibility.Public,
+ new CSCodeBlock(getCode),
+ (setIsPublic ? CSVisibility.Public : CSVisibility.Private), new CSCodeBlock(setCode));
+ if (declareField)
+ prop.Insert(0, CSFieldDeclaration.FieldLine(type, backingFieldName));
+ return prop;
+ }
+
+ public static CSProperty PublicGetSetBacking(CSType type, string name, bool declareField, string? backingFieldName = null)
+ {
+ return PublicGetPubPrivSetBacking(type, name, true, declareField, backingFieldName);
+ }
+
+ public static CSProperty PublicGetPrivateSetBacking(CSType type, string name, bool declareField, string? backingFieldName = null)
+ {
+ return PublicGetPubPrivSetBacking(type, name, false, declareField, backingFieldName);
+ }
+
+ public static CSProperty PublicGetBacking(CSType type, CSIdentifier name, CSIdentifier backingFieldName,
+ bool includeBackingFieldDeclaration = false, CSMethodKind methodKind = CSMethodKind.None)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ ArgumentNullException.ThrowIfNull(backingFieldName, nameof(backingFieldName));
+ LineCodeElementCollection getCode =
+ new LineCodeElementCollection(
+ new ICodeElement[] {
+ CSReturn.ReturnLine (backingFieldName)
+ }, false, true);
+ CSProperty prop = new CSProperty(type, methodKind, name,
+ CSVisibility.Public, new CSCodeBlock(getCode),
+ CSVisibility.Public, null);
+ if (includeBackingFieldDeclaration)
+ prop.Insert(0, CSFieldDeclaration.FieldLine(type, backingFieldName));
+ return prop;
+ }
+
+ public static CSProperty PublicGetBacking(CSType type, string name, string backingFieldName, bool includeBackingFieldDeclaration = false)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ ArgumentNullException.ThrowIfNull(backingFieldName, nameof(backingFieldName));
+ return PublicGetBacking(type,
+ new CSIdentifier(name),
+ new CSIdentifier(backingFieldName),
+ includeBackingFieldDeclaration);
+ }
+
+ static string MassageName(string name)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("_");
+ sb.Append(Char.ToLowerInvariant(name[0]));
+ if (name.Length > 0)
+ sb.Append(name.Substring(1));
+ return sb.ToString();
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSReturn.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSReturn.cs
new file mode 100644
index 000000000000..1756c4faf225
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSReturn.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSReturn : DelegatedSimpleElement, ICSExpression, ICSLineable
+ {
+ public CSReturn(ICSExpression expr)
+ {
+ Value = expr;
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("return ", true);
+ if (Value != null)
+ Value.WriteAll(writer);
+ }
+
+ public ICSExpression Value { get; private set; }
+
+ public static CSLine ReturnLine(ICSExpression expr)
+ {
+ return new CSLine(new CSReturn(expr));
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSShortCircuit.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSShortCircuit.cs
new file mode 100644
index 000000000000..df8584c574cf
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSShortCircuit.cs
@@ -0,0 +1,34 @@
+using System;
+namespace SyntaxDynamo.CSLang
+{
+ public class CSShortCircuit : DelegatedSimpleElement, ICSLineable
+ {
+ public CSShortCircuit(CSShortCircuitKind kind)
+ {
+ Kind = kind;
+ }
+
+ public CSShortCircuitKind Kind { get; private set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ var keyword = Kind == CSShortCircuitKind.Break ? "break" : "continue";
+ writer.Write(keyword, false);
+ }
+
+ public static CSLine ShortCircuit(CSShortCircuitKind kind)
+ {
+ return new CSLine(new CSShortCircuit(kind));
+ }
+
+ public static CSLine Continue()
+ {
+ return ShortCircuit(CSShortCircuitKind.Continue);
+ }
+
+ public static CSLine Break()
+ {
+ return ShortCircuit(CSShortCircuitKind.Break);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSTernary.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSTernary.cs
new file mode 100644
index 000000000000..d9078259b297
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSTernary.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSTernary : CSBaseExpression
+ {
+ public CSTernary(CSBaseExpression predicate, CSBaseExpression onTrue, CSBaseExpression onFalse, bool addParentheses)
+ {
+ ArgumentNullException.ThrowIfNull(predicate, nameof(predicate));
+ ArgumentNullException.ThrowIfNull(onTrue, nameof(onTrue));
+ ArgumentNullException.ThrowIfNull(onFalse, nameof(onFalse));
+ Predicate = predicate;
+ OnTrue = onTrue;
+ OnFalse = onFalse;
+ AddParentheses = addParentheses;
+ }
+ public CSBaseExpression Predicate { get; private set; }
+ public CSBaseExpression OnTrue { get; private set; }
+ public CSBaseExpression OnFalse { get; private set; }
+ public bool AddParentheses { get; set; }
+
+ #region implemented abstract members of DelegatedSimpleElem
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ if (AddParentheses)
+ {
+ writer.Write('(', true);
+ }
+ Predicate.WriteAll(writer);
+ writer.Write(" ? ", true);
+ OnTrue.WriteAll(writer);
+ writer.Write(" : ", true);
+ OnFalse.WriteAll(writer);
+ if (AddParentheses)
+ {
+ writer.Write(')', true);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSThrow.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSThrow.cs
new file mode 100644
index 000000000000..274d3232b39a
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSThrow.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSThrow : CSBaseExpression, ICSStatement, ICSLineable
+ {
+ public CSThrow(CSBaseExpression expr)
+ {
+ ArgumentNullException.ThrowIfNull(expr, nameof(expr));
+ Expr = expr;
+ }
+
+ public CSBaseExpression Expr { get; private set; }
+
+ #region implemented abstract members of DelegatedSimpleElem
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write("throw ", true);
+ Expr.WriteAll(writer);
+ }
+
+ #endregion
+
+ public static CSLine ThrowLine(T exType, CommaListElementCollection args) where T : Exception
+ {
+ return new CSLine(new CSThrow(new CSFunctionCall(new CSIdentifier(exType.GetType().Name), args, true)));
+ }
+
+ public static CSLine ThrowLine(T exType, string message) where T : Exception
+ {
+ CommaListElementCollection args = new CommaListElementCollection();
+ if (message != null)
+ args.Add(CSConstant.Val(message));
+ return ThrowLine(exType, args);
+ }
+
+ public static CSLine ThrowLine(T exType, CSBaseExpression expr) where T : Exception
+ {
+ ArgumentNullException.ThrowIfNull(expr, nameof(expr));
+ CommaListElementCollection args = new CommaListElementCollection();
+ args.Add(expr);
+ return ThrowLine(exType, args);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSTryCatch.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSTryCatch.cs
new file mode 100644
index 000000000000..da74a4793bcf
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSTryCatch.cs
@@ -0,0 +1,83 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+namespace SyntaxDynamo.CSLang
+{
+ public class CSCatch : DelegatedSimpleElement, ICSStatement
+ {
+ public CSCatch(CSType? catchType, CSIdentifier? name, CSCodeBlock body)
+ {
+ CatchType = catchType;
+ Name = name;
+ Body = body ?? new CSCodeBlock();
+ }
+
+ public CSCatch(string catchType, string name, CSCodeBlock body)
+ : this(new CSSimpleType(catchType), name != null ? new CSIdentifier(name) : null, body)
+ {
+ }
+
+ public CSCatch(Type catchType, string name, CSCodeBlock body)
+ : this(new CSSimpleType(catchType), name != null ? new CSIdentifier(name) : null, body)
+ {
+ }
+
+ public CSCatch(CSCodeBlock body)
+ : this((CSType?)null, null, body)
+ {
+ }
+
+ public CSType? CatchType { get; private set; }
+ public CSIdentifier? Name { get; private set; }
+ public CSCodeBlock Body { get; private set; }
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+
+ writer.BeginNewLine(true);
+ writer.Write("catch ", false);
+ if (CatchType != null)
+ {
+ writer.Write("(", false);
+ CatchType.WriteAll(writer);
+ if ((object?)Name != null)
+ {
+ SimpleElement.Spacer.WriteAll(writer);
+ Name?.WriteAll(writer);
+ }
+ writer.Write(")", false);
+ }
+ writer.EndLine();
+ Body.WriteAll(writer);
+ writer.EndLine();
+ }
+ }
+
+ public class CSTryCatch : CodeElementCollection, ICSStatement
+ {
+ public CSTryCatch(CSCodeBlock tryBlock, params CSCatch[] catchBlocks)
+ {
+ TryBlock = tryBlock ?? new CSCodeBlock();
+ CatchBlocks = new CodeElementCollection();
+ CatchBlocks.AddRange(catchBlocks);
+
+ Add(new SimpleElement("try ", true));
+ Add(TryBlock);
+ Add(CatchBlocks);
+ }
+
+ public CSTryCatch(CSCodeBlock tryBlock, Type catchType, string name, CSCodeBlock catchBlock)
+ : this(tryBlock, new CSCatch(catchType, name, catchBlock))
+ {
+ }
+
+ public override void Write(ICodeWriter writer, object? o)
+ {
+ writer.BeginNewLine(true);
+ base.Write(writer, o);
+ }
+
+ public CSCodeBlock TryBlock { get; private set; }
+ public CodeElementCollection CatchBlocks { get; private set; }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSType.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSType.cs
new file mode 100644
index 000000000000..b1155cfa1edb
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSType.cs
@@ -0,0 +1,277 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+using System.IO;
+using System.Text;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace SyntaxDynamo.CSLang
+{
+ public abstract class CSType : DelegatedSimpleElement
+ {
+ public override string ToString() => CodeWriter.WriteToString(this);
+
+ public abstract CSFunctionCall Typeof();
+ public abstract CSFunctionCall Default();
+ public abstract CSFunctionCall Ctor();
+
+ public static CSType Copy(CSType csType)
+ {
+ if (csType is CSSimpleType csSimpleType)
+ {
+ return new CSSimpleType(csSimpleType);
+ }
+ if (csType is CSGenericReferenceType csGen)
+ {
+ return new CSGenericReferenceType(csGen);
+ }
+ throw new NotImplementedException($"Type {csType.GetType().Name} needs a copy constructor");
+ }
+ }
+
+ public class CSSimpleType : CSType
+ {
+ public CSSimpleType(Type t)
+ : this(t.Name)
+ {
+ }
+ public CSSimpleType(string name)
+ : this(name, false)
+ {
+ }
+
+ public CSSimpleType(CSSimpleType csSimpleType)
+ : this(csSimpleType.Name, csSimpleType.IsArray)
+ {
+ if (csSimpleType.GenericTypes != null)
+ {
+ GenericTypes = new CSType[csSimpleType.GenericTypes.Length];
+ for (int i = 0; i < GenericTypes.Length; i++)
+ {
+ GenericTypes[i] = CSType.Copy(csSimpleType.GenericTypes[i]);
+ }
+ }
+ }
+
+ public CSSimpleType(string name, bool isArray)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ hiddenName = name + (isArray ? "[]" : "");
+ }
+
+ public static explicit operator CSSimpleType(string name)
+ {
+ return new CSSimpleType(name);
+ }
+
+ public static CSSimpleType CreateArray(string name)
+ {
+ return new CSSimpleType(name, true);
+ }
+
+ public CSSimpleType(string name, bool isArray, params CSType[] genericSpecialization)
+ {
+ ArgumentNullException.ThrowIfNull(name, nameof(name));
+ IsGeneric = genericSpecialization != null && genericSpecialization.Length > 0;
+ GenericTypes = genericSpecialization;
+ GenericTypeName = name;
+ IsArray = isArray;
+ }
+
+ public CSSimpleType(string name, bool isArray, params string[] genericSpecialization)
+ : this(name, isArray, genericSpecialization.Select(s => new CSSimpleType(s)).ToArray())
+ {
+ }
+
+ string? hiddenName;
+ public string Name
+ {
+ get
+ {
+ return hiddenName ?? GenerateName();
+ }
+ }
+ public bool IsGeneric { get; private set; }
+ public string? GenericTypeName { get; private set; }
+ public CSType[]? GenericTypes { get; private set; }
+ public bool IsArray { get; private set; }
+ public bool IsPointer { get; private set; }
+
+ string GenerateName()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append(GenericTypeName);
+ if (GenericTypes != null && GenericTypes.Length > 0)
+ {
+ sb.Append("<");
+ int i = 0;
+ foreach (CSType type in GenericTypes)
+ {
+ if (i > 0)
+ sb.Append(", ");
+ sb.Append(type.ToString());
+ i++;
+ }
+ sb.Append(">");
+ }
+ if (IsArray)
+ sb.Append("[]");
+ return sb.ToString();
+ }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write(Name, false);
+ }
+
+ public override CSFunctionCall Typeof()
+ {
+ return new CSFunctionCall("typeof", false, new CSIdentifier(Name));
+ }
+
+ public override CSFunctionCall Default()
+ {
+ return new CSFunctionCall("default", false, new CSIdentifier(Name));
+ }
+
+ public override CSFunctionCall Ctor()
+ {
+ return new CSFunctionCall(Name, true);
+ }
+
+ static CSSimpleType
+ tBool = new CSSimpleType("bool"),
+ tChar = new CSSimpleType("char"),
+ tSbyte = new CSSimpleType("sbyte"),
+ tShort = new CSSimpleType("short"),
+ tInt = new CSSimpleType("int"),
+ tLong = new CSSimpleType("long"),
+ tFloat = new CSSimpleType("float"),
+ tByte = new CSSimpleType("byte"),
+ tUshort = new CSSimpleType("ushort"),
+ tUint = new CSSimpleType("uint"),
+ tUlong = new CSSimpleType("ulong"),
+ tDouble = new CSSimpleType("double"),
+ tString = new CSSimpleType("string"),
+ tObject = new CSSimpleType("object"),
+ tIntPtr = new CSSimpleType("IntPtr"),
+ tVoid = new CSSimpleType("void"),
+ tByteStar = new CSSimpleType("byte").Star,
+ tType = new CSSimpleType("Type"),
+ tVar = new CSSimpleType("var"),
+ tNfloat = new CSSimpleType("nfloat"),
+ tNint = new CSSimpleType("nint"),
+ tNUint = new CSSimpleType("nuint")
+ ;
+
+ public CSSimpleType Star
+ {
+ get
+ {
+ if (Name.EndsWith("[]"))
+ {
+ throw new NotImplementedException("Blindly making an array a pointer doesn't do what you think.");
+ }
+ else
+ {
+ var ptrType = new CSSimpleType(Name + " *", false);
+ ptrType.IsPointer = true;
+ return ptrType;
+ }
+ }
+ }
+
+ public static CSSimpleType Bool { get { return tBool; } }
+ public static CSSimpleType Char { get { return tChar; } }
+ public static CSSimpleType SByte { get { return tSbyte; } }
+ public static CSSimpleType Short { get { return tShort; } }
+ public static CSSimpleType Int { get { return tInt; } }
+ public static CSSimpleType Long { get { return tLong; } }
+ public static CSSimpleType Float { get { return tFloat; } }
+ public static CSSimpleType Byte { get { return tByte; } }
+ public static CSSimpleType UShort { get { return tUshort; } }
+ public static CSSimpleType UInt { get { return tUint; } }
+ public static CSSimpleType ULong { get { return tUlong; } }
+ public static CSSimpleType Double { get { return tDouble; } }
+ public static CSSimpleType String { get { return tString; } }
+ public static CSSimpleType Object { get { return tObject; } }
+ public static CSSimpleType IntPtr { get { return tIntPtr; } }
+ public static CSSimpleType Void { get { return tVoid; } }
+ public static CSSimpleType ByteStar { get { return tByteStar; } }
+ public static CSSimpleType Type { get { return tType; } }
+ public static CSSimpleType Var { get { return tVar; } }
+ public static CSSimpleType NFloat { get { return tNfloat; } }
+ public static CSSimpleType NInt => tNint;
+ public static CSSimpleType NUInt => tNUint;
+ }
+
+ public class CSGenericReferenceType : CSType
+ {
+ public CSGenericReferenceType(int depth, int index)
+ {
+ Depth = depth;
+ Index = index;
+ InterfaceConstraints = new List();
+ }
+
+ public CSGenericReferenceType(CSGenericReferenceType csGeneric)
+ : this(csGeneric.Depth, csGeneric.Index)
+ {
+ foreach (var elem in csGeneric.InterfaceConstraints)
+ {
+ InterfaceConstraints.Add(CSType.Copy(elem));
+ }
+ ReferenceNamer = csGeneric.ReferenceNamer;
+ }
+
+ // this doesn't really belong here, but I'm going to need it.
+ public List InterfaceConstraints { get; private set; }
+
+ public int Depth { get; private set; }
+ public int Index { get; private set; }
+ public Func? ReferenceNamer { get; set; }
+
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ writer.Write(Name, true);
+ }
+
+ public string Name
+ {
+ get
+ {
+ Func namer = ReferenceNamer ?? DefaultNamer;
+ return namer(Depth, Index);
+ }
+ }
+
+ const string kNames = "TUVWABCDEFGHIJKLMN";
+
+ public static string DefaultNamer(int depth, int index)
+ {
+ if (depth < 0 || depth >= kNames.Length)
+ throw new ArgumentOutOfRangeException(nameof(depth));
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ return String.Format("{0}{1}", kNames[depth], index);
+ }
+
+ public override CSFunctionCall Typeof()
+ {
+ return new CSFunctionCall("typeof", false, new CSIdentifier(Name));
+ }
+
+ public override CSFunctionCall Default()
+ {
+ return new CSFunctionCall("default", false, new CSIdentifier(Name));
+ }
+
+ public override CSFunctionCall Ctor()
+ {
+ return new CSFunctionCall(Name, true);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSUnaryExpression.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSUnaryExpression.cs
new file mode 100644
index 000000000000..2acfe41f6852
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSUnaryExpression.cs
@@ -0,0 +1,116 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSUnaryExpression : CSBaseExpression
+ {
+ public CSUnaryExpression(CSUnaryOperator op, ICSExpression expr)
+ {
+ ArgumentNullException.ThrowIfNull(expr, nameof(expr));
+ Operation = op;
+ Expr = expr;
+ }
+ protected override void LLWrite(ICodeWriter writer, object? o)
+ {
+ if (IsPostfix(Operation))
+ {
+ Expr.WriteAll(writer);
+ writer.Write(OperatorToString(Operation), true);
+ }
+ else
+ {
+ writer.Write(OperatorToString(Operation), true);
+ Expr.WriteAll(writer);
+ }
+ }
+
+ public CSUnaryOperator Operation { get; private set; }
+ public ICSExpression Expr { get; private set; }
+
+ static string OperatorToString(CSUnaryOperator op)
+ {
+ switch (op)
+ {
+ case CSUnaryOperator.At:
+ return "@";
+ case CSUnaryOperator.BitNot:
+ return "~";
+ case CSUnaryOperator.Neg:
+ return "-";
+ case CSUnaryOperator.Not:
+ return "!";
+ case CSUnaryOperator.Out:
+ return "out ";
+ case CSUnaryOperator.Pos:
+ return "+";
+ case CSUnaryOperator.Ref:
+ return "ref ";
+ case CSUnaryOperator.AddressOf:
+ return "&";
+ case CSUnaryOperator.Indirection:
+ return "*";
+ case CSUnaryOperator.Await:
+ return "await ";
+ case CSUnaryOperator.PostBang:
+ return "!";
+ case CSUnaryOperator.Question:
+ return "?";
+ default:
+ throw new ArgumentOutOfRangeException(nameof(op));
+ }
+ }
+
+ static bool IsPostfix(CSUnaryOperator op)
+ {
+ return op == CSUnaryOperator.PostBang || op == CSUnaryOperator.Question;
+ }
+
+ public static CSUnaryExpression AddressOf(ICSExpression expr)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.AddressOf, expr);
+ }
+
+ public static CSUnaryExpression Star(ICSExpression expr)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.Indirection, expr);
+ }
+
+ public static CSUnaryExpression Out(CSIdentifier id)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.Out, id);
+ }
+
+ public static CSUnaryExpression Out(string id)
+ {
+ return Out(new CSIdentifier(id));
+ }
+
+ public static CSUnaryExpression Ref(CSIdentifier id)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.Ref, id);
+ }
+
+ public static CSUnaryExpression Ref(string id)
+ {
+ return Ref(new CSIdentifier(id));
+ }
+
+ public static CSUnaryExpression Await(ICSExpression expr)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.Await, expr);
+ }
+
+ public static CSUnaryExpression PostBang(ICSExpression expr)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.PostBang, expr);
+ }
+
+ public static CSUnaryExpression Question(ICSExpression expr)
+ {
+ return new CSUnaryExpression(CSUnaryOperator.Question, expr);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSUsing.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSUsing.cs
new file mode 100644
index 000000000000..c4c3b0741012
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/CSUsing.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public class CSUsing : SimpleLineElement
+ {
+ public CSUsing(string package)
+ : base(string.Format("using {0};", package), false, false, false)
+ {
+ Package = package;
+ }
+
+ public string Package { get; private set; }
+ }
+
+ public class CSUsingPackages : CodeElementCollection
+ {
+ public CSUsingPackages() : base() { }
+ public CSUsingPackages(params CSUsing[] use)
+ : this()
+ {
+ AddRange(use);
+ }
+ public CSUsingPackages(params string[] use)
+ : this()
+ {
+ AddRange(use.Select(s => new CSUsing(s)));
+ }
+
+ public CSUsingPackages And(CSUsing use)
+ {
+ Add(use);
+ return this;
+ }
+
+ public CSUsingPackages And(string package) { return And(new CSUsing(package)); }
+
+ public void AddIfNotPresent(string? package, CSIdentifier? protectedBy = null)
+ {
+ if (String.IsNullOrEmpty(package))
+ return;
+ CSUsing target = new CSUsing(package);
+ if (!this.Exists(use => use.Contents == target.Contents))
+ {
+ if ((object?)protectedBy != null)
+ {
+ CSConditionalCompilation.ProtectWithIfEndif(protectedBy, target);
+ }
+ Add(target);
+ }
+ }
+
+ public void AddIfNotPresent(Type t, CSIdentifier? protectedBy = null)
+ {
+ AddIfNotPresent(t.Namespace, protectedBy);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/Enums.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/Enums.cs
new file mode 100644
index 000000000000..9a1fb38b2d45
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/Enums.cs
@@ -0,0 +1,100 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace SyntaxDynamo.CSLang
+{
+ public enum CSVisibility
+ {
+ None = 0,
+ Public,
+ Internal,
+ Protected,
+ Private,
+ }
+
+ public enum CSMethodKind
+ {
+ None = 0,
+ Static,
+ StaticExtern,
+ StaticNew,
+ Virtual,
+ Override,
+ Extern,
+ New,
+ Abstract,
+ Interface,
+ Unsafe,
+ StaticUnsafe,
+ }
+
+ public enum CSBinaryOperator
+ {
+ Add = 0,
+ Sub,
+ Mul,
+ Div,
+ Mod,
+ And,
+ Or,
+ Less,
+ Greater,
+ Equal,
+ NotEqual,
+ LessEqual,
+ GreaterEqual,
+ BitAnd,
+ BitOr,
+ BitXor,
+ LeftShift,
+ RightShift,
+ Dot,
+ Is,
+ As,
+ NullCoalesce,
+ }
+
+ public enum CSUnaryOperator
+ {
+ Neg = 0,
+ Pos,
+ At,
+ Not,
+ BitNot,
+ Ref,
+ Out,
+ AddressOf,
+ Indirection,
+ Await,
+ PostBang,
+ Question,
+ }
+
+ public enum CSAssignmentOperator
+ {
+ Assign,
+ AddAssign,
+ SubAssign,
+ MulAssign,
+ DivAssign,
+ ModAssign,
+ AndAssign,
+ OrAssign,
+ XorAssign
+ }
+
+ public enum CSParameterKind
+ {
+ None,
+ Ref,
+ Out,
+ Params,
+ This
+ }
+
+ public enum CSShortCircuitKind
+ {
+ Break,
+ Continue,
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSExpression.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSExpression.cs
new file mode 100644
index 000000000000..ce563ba75dd2
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSExpression.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using SyntaxDynamo;
+
+namespace SyntaxDynamo.CSLang
+{
+ public interface ICSExpression : ICodeElement
+ {
+ }
+
+ public interface ICSExpressionList : ICodeElementSet
+ {
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSLineable.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSLineable.cs
new file mode 100644
index 000000000000..6fad9246fd72
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSLineable.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public interface ICSLineable
+ {
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSStatement.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSStatement.cs
new file mode 100644
index 000000000000..1ded5a424803
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSStatement.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo.CSLang
+{
+ public interface ICSStatement
+ {
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSTopLevelDeclaration.cs b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSTopLevelDeclaration.cs
new file mode 100644
index 000000000000..1f43e8a95161
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.CSLang/ICSTopLevelDeclaration.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace SyntaxDynamo.CSLang
+{
+ public interface ICSTopLevelDeclaration : ICodeElement
+ {
+ }
+
+ public class CSTopLevelDeclations : CodeElementCollection
+ {
+ public CSTopLevelDeclations(params ICSTopLevelDeclaration[] decls)
+ : base()
+ {
+ ArgumentNullException.ThrowIfNull(decls, nameof(decls));
+ AddRange(decls);
+ }
+
+ }
+}
diff --git a/src/SyntaxDynamo/src/SyntaxDynamo.csproj b/src/SyntaxDynamo/src/SyntaxDynamo.csproj
new file mode 100644
index 000000000000..ca1712d0c0cd
--- /dev/null
+++ b/src/SyntaxDynamo/src/SyntaxDynamo.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Library
+ net8.0
+ enable
+ enable
+ true
+
+
+
+
+
+
diff --git a/src/SyntaxDynamo/src/WriteEventArgs.cs b/src/SyntaxDynamo/src/WriteEventArgs.cs
new file mode 100644
index 000000000000..4d1dcc000963
--- /dev/null
+++ b/src/SyntaxDynamo/src/WriteEventArgs.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+
+namespace SyntaxDynamo
+{
+ public class WriteEventArgs : EventArgs
+ {
+ public WriteEventArgs(ICodeWriter writer)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+ Writer = writer;
+ }
+
+ public ICodeWriter Writer { get; private set; }
+ }
+}
diff --git a/src/SyntaxDynamo/tests/SimpleClassTests.cs b/src/SyntaxDynamo/tests/SimpleClassTests.cs
new file mode 100644
index 000000000000..6ae1e6690cfb
--- /dev/null
+++ b/src/SyntaxDynamo/tests/SimpleClassTests.cs
@@ -0,0 +1,303 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Xunit;
+using SyntaxDynamo.CSLang;
+using System.Reflection;
+using TestingUtils;
+
+namespace SyntaxDynamo.Tests;
+
+public class SimpleClassTests
+{
+ public delegate CSClass ClassMutator(CSClass cl);
+ public delegate CSUsingPackages UsingMutator(CSUsingPackages pkg);
+
+ public static Stream BasicClass(string nameSpace, string className, CSMethod? m, ClassMutator? mutator, UsingMutator? useMutator = null)
+ {
+ CSUsingPackages use = new CSUsingPackages("System");
+ if(useMutator != null)
+ use = useMutator(use);
+
+ CSClass cl = new CSClass(CSVisibility.Public, className, m != null ? new CSMethod [] { m } : null);
+ if(mutator != null)
+ cl = mutator(cl);
+
+ CSNamespace ns = new CSNamespace(nameSpace);
+ ns.Block.Add(cl);
+
+ CSFile file = CSFile.Create(use, ns);
+ return CodeWriter.WriteToStream(file);
+ }
+
+ [Fact]
+ public void EmptyClass()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, null)) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ void DeclExposure(CSVisibility vis)
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Fields.Add(CSFieldDeclaration.FieldLine(CSSimpleType.Byte, "b", null, CSVisibility.Public));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void ClassWithSingleDeclAllExposures()
+ {
+ foreach(var vis in Enum.GetValues(typeof(CSVisibility))) {
+ DeclExposure((CSVisibility)vis);
+ }
+ }
+
+ void DeclInitExposure(CSVisibility vis)
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Fields.Add(CSFieldDeclaration.FieldLine(CSSimpleType.Byte, "b", CSConstant.Val((byte)0), CSVisibility.Public));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void ClassWithSingleDeclInitAllExposures()
+ {
+ foreach(var vis in Enum.GetValues(typeof(CSVisibility))) {
+ DeclInitExposure((CSVisibility)vis);
+ }
+ }
+
+ void DeclType(CSType type)
+ {
+ if(type == CSSimpleType.Void)
+ return;
+
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Fields.Add(CSFieldDeclaration.FieldLine(type, "b", null, CSVisibility.Public));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void ClassWithSingleDeclAllTypes()
+ {
+ foreach(MethodInfo mi in typeof(CSType).GetMethods().Where(mii => mii.IsStatic && mii.IsPublic &&
+ mii.ReturnType == typeof(CSType) && mii.Name != "Copy")) {
+ CSType? cs = mi.Invoke(null, null) as CSType;
+ if(cs != null)
+ DeclType(cs);
+ }
+ }
+
+ [Fact]
+ public void ConstructorTest()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Constructors.Add(CSMethod.PublicConstructor("AClass", new CSParameterList(), new CSCodeBlock()));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void ConstructorTestParam()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, new CSIdentifier("x")));
+ cl.Constructors.Add(CSMethod.PublicConstructor("AClass", pl, new CSCodeBlock()));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void ConstructorTestParamList()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"))
+ .And(new CSParameter(CSSimpleType.Int, "y"));
+ cl.Constructors.Add(CSMethod.PublicConstructor("AClass", pl, new CSCodeBlock()));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void MethodNoParams()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList();
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void MethodParam()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"));
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void MethodParamList()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"))
+ .And(new CSParameter(CSSimpleType.Int, "y"));
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void VirtualMethodNoParams()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList();
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSMethodKind.Virtual, CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void VirtualMethodParam()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"));
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSMethodKind.Virtual, CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void VirtualMethodParamList()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"))
+ .And(new CSParameter(CSSimpleType.Int, "y"));
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSMethodKind.Virtual, CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void StaticMethodNoParams()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList();
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSMethodKind.Virtual, CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void StaticMethodParam()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"));
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSMethodKind.Virtual, CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void StaticMethodParamList()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ CSParameterList pl = new CSParameterList().And(new CSParameter(CSSimpleType.Int, "x"))
+ .And(new CSParameter(CSSimpleType.Int, "y"));
+ CSCodeBlock b = new CSCodeBlock().And(CSReturn.ReturnLine(CSConstant.Val(0)));
+ cl.Methods.Add(CSMethod.PublicMethod(CSMethodKind.Virtual, CSSimpleType.Int, "Foo", pl, b));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void PublicGetPrivateSetProp()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Properties.Add(CSProperty.PublicGetPrivateSet(CSSimpleType.Int, "Foo"));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void PublicGetSetProp()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Properties.Add(CSProperty.PublicGetSet(CSSimpleType.Int, "Foo"));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void PublicGetSetBacking()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Properties.Add(CSProperty.PublicGetSetBacking(CSSimpleType.Int, "Foo", true, "_bar"));
+ return cl;
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+
+ [Fact]
+ public void Pinvoke()
+ {
+ using(Stream stm = BasicClass("None", "AClass", null, cl => {
+ cl.Methods.Add(CSMethod.PInvoke(CSVisibility.Public,
+ CSSimpleType.IntPtr, "Walter", "__Internal", "_walter", new CSParameterList()));
+ return cl;
+ }, use => {
+ return use.And(new CSUsing("System.Runtime.InteropServices"));
+ })) {
+ TestHelpers.CompileAndExecute(stm, string.Empty, string.Empty);
+ }
+ }
+}
diff --git a/src/SyntaxDynamo/tests/SyntaxDynamo.Tests.csproj b/src/SyntaxDynamo/tests/SyntaxDynamo.Tests.csproj
new file mode 100644
index 000000000000..367b314e4c99
--- /dev/null
+++ b/src/SyntaxDynamo/tests/SyntaxDynamo.Tests.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+ true
+
+
+
+
+
+
+
diff --git a/src/TestingUtils/src/TestingUtils.cs b/src/TestingUtils/src/TestingUtils.cs
new file mode 100644
index 000000000000..8425ee899bb7
--- /dev/null
+++ b/src/TestingUtils/src/TestingUtils.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Emit;
+
+namespace TestingUtils
+{
+ public static class TestHelpers
+ {
+ private static int uniqueId = 0;
+
+ public static object? CompileAndExecute(Stream stream, string typeName, string methodName)
+ {
+ using (StreamReader reader = new StreamReader(stream))
+ {
+ string fileSourceCode = reader.ReadToEnd();
+ var sourceCodes = new[] { fileSourceCode };
+ return CompileAndExecute(sourceCodes, typeName, methodName);
+ }
+ }
+
+ public static object? CompileAndExecute(string filePath, string sourceCode, string typeName, string methodName)
+ {
+ string fileSourceCode = File.ReadAllText(filePath);
+ var sourceCodes = new[] { fileSourceCode, sourceCode };
+ return CompileAndExecute(sourceCodes, typeName, methodName);
+ }
+
+ private static object? CompileAndExecute(string[] sourceCodes, string typeName, string methodName)
+ {
+ OutputKind outputKind = OutputKind.ConsoleApplication;
+ if (typeName == string.Empty || methodName == string.Empty)
+ {
+ outputKind = OutputKind.DynamicallyLinkedLibrary;
+ }
+ var options = new CSharpCompilationOptions(outputKind);
+ var syntaxTrees = sourceCodes.Select(code => CSharpSyntaxTree.ParseText(code)).ToArray();
+ var systemRuntimeAssemblyPath = Assembly.Load("System.Runtime").Location;
+
+ var references = new[]
+ {
+ MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
+ MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
+ MetadataReference.CreateFromFile(systemRuntimeAssemblyPath),
+ };
+
+ var compilation = CSharpCompilation.Create($"CompiledAssembly{uniqueId}",
+ syntaxTrees: syntaxTrees,
+ references: references,
+ options: options);
+
+ string assemblyPath = Path.Combine(Path.GetTempPath(), $"CompiledAssembly{uniqueId++}.dll");
+ using (var stream = new FileStream(assemblyPath, FileMode.Create))
+ {
+ EmitResult emitResult = compilation.Emit(stream);
+
+ if (!emitResult.Success)
+ {
+ string errorMessage = "Compilation failed:";
+ foreach (var diagnostic in emitResult.Diagnostics)
+ {
+ errorMessage += $"\n{diagnostic}";
+ }
+ throw new InvalidOperationException(errorMessage);
+ }
+ }
+
+ if (outputKind == OutputKind.ConsoleApplication)
+ {
+ Assembly compiledAssembly = Assembly.LoadFile(assemblyPath);
+ Type? targetType = compiledAssembly?.GetType(typeName);
+ MethodInfo? customMethod = targetType?.GetMethod(methodName);
+ return customMethod?.Invoke(null, new object[] { });
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/SwiftBindings/src/SwiftBindings.csproj b/src/TestingUtils/src/TestingUtils.csproj
similarity index 52%
rename from src/SwiftBindings/src/SwiftBindings.csproj
rename to src/TestingUtils/src/TestingUtils.csproj
index 91b464afeacc..96578232595d 100644
--- a/src/SwiftBindings/src/SwiftBindings.csproj
+++ b/src/TestingUtils/src/TestingUtils.csproj
@@ -1,10 +1,14 @@
- Exe
+ Library
net8.0
enable
enable
+ true
+
+
+