├── demos ├── FizzBuzz │ ├── Program.cs │ ├── README.md │ └── FizzBuzz.csproj ├── HelloWorld │ ├── README.md │ ├── Program.c♯ │ └── HelloWorld.csproj ├── Sandbox │ ├── Program.cs │ ├── README.md │ ├── MyClass.c♯ │ └── Sandbox.csproj └── WebAPI │ ├── WebAPI.http │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── README.md │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Services │ ├── Abstractions │ │ └── ITestService.c♯ │ └── Implementations │ │ └── TestService.c♯ │ ├── WebAPI.csproj │ └── Models │ └── TestModel.c♯ ├── src └── Csml │ ├── Parser │ ├── Nodes │ │ ├── Expressions │ │ │ ├── NotNode.cs │ │ │ ├── OrNode.cs │ │ │ ├── AddNode.cs │ │ │ ├── AndNode.cs │ │ │ ├── XorNode.cs │ │ │ ├── DivideNode.cs │ │ │ ├── EqualsNode.cs │ │ │ ├── AssignmentNode.cs │ │ │ ├── BitwiseAndNode.cs │ │ │ ├── BitwiseNotNode.cs │ │ │ ├── BitwiseOrNode.cs │ │ │ ├── ExpressionNode.cs │ │ │ ├── LeftShiftNode.cs │ │ │ ├── LessThanNode.cs │ │ │ ├── MultiplyNode.cs │ │ │ ├── NotEqualsNode.cs │ │ │ ├── RemainderNode.cs │ │ │ ├── RightShiftNode.cs │ │ │ ├── SubtractNode.cs │ │ │ ├── DecrementNode.cs │ │ │ ├── GreaterThanNode.cs │ │ │ ├── IncrementNode.cs │ │ │ ├── LessThanOrEqualNode.cs │ │ │ ├── PrefixDecrementNode.cs │ │ │ ├── PrefixIncrementNode.cs │ │ │ ├── GreaterThanOrEqualNode.cs │ │ │ ├── UnsignedRightShiftNode.cs │ │ │ ├── ValueNode.cs │ │ │ ├── AwaitNode.cs │ │ │ ├── UnaryValueExpressionNode.cs │ │ │ ├── UnaryExpressionNode.cs │ │ │ ├── NewNode.cs │ │ │ └── BinaryExpressionNode.cs │ │ ├── Members │ │ │ ├── ConstructorNode.cs │ │ │ ├── PropertyGetterAccessor.cs │ │ │ ├── ArgumentNode.cs │ │ │ ├── PropertySetterAccessor.cs │ │ │ ├── EnumValue.cs │ │ │ ├── ParameterModifier.cs │ │ │ ├── ParameterNode.cs │ │ │ ├── MethodBaseNode.cs │ │ │ ├── FieldNode.cs │ │ │ ├── MemberNode.cs │ │ │ ├── PropertyNode.cs │ │ │ └── MethodNode.cs │ │ ├── Statements │ │ │ ├── BlockNode.cs │ │ │ ├── DefaultNode.cs │ │ │ ├── ThrowNode.cs │ │ │ ├── BreakNode.cs │ │ │ ├── ElseIfNode.cs │ │ │ ├── ContinueNode.cs │ │ │ ├── ElseNode.cs │ │ │ ├── TryNode.cs │ │ │ ├── CaseNode.cs │ │ │ ├── FinallyNode.cs │ │ │ ├── ReturnNode.cs │ │ │ ├── WhileNode.cs │ │ │ ├── CatchNode.cs │ │ │ ├── SwitchNode.cs │ │ │ ├── IfNode.cs │ │ │ ├── ForEachNode.cs │ │ │ ├── CallNode.cs │ │ │ ├── VariableNode.cs │ │ │ ├── ForNode.cs │ │ │ ├── StatementContainerNode.cs │ │ │ └── ExpressionStatementNode.cs │ │ ├── Types │ │ │ ├── InheritanceNode.cs │ │ │ ├── InterfaceNode.cs │ │ │ ├── ClassNode.cs │ │ │ ├── UsingDirectiveNode.cs │ │ │ ├── StructNode.cs │ │ │ ├── EnumNode.cs │ │ │ ├── NamespaceNode.cs │ │ │ └── TypeNode.cs │ │ ├── CsmlNode.cs │ │ ├── BaseNode.cs │ │ └── AccessModifier.cs │ ├── CsmlConstants.cs │ ├── CsmlParseResult.cs │ ├── CsmlParseError.cs │ ├── ObjectValidator.cs │ └── CsmlParser.cs │ ├── AssemblyInfo.cs │ ├── AnalyzerReleases.Shipped.md │ ├── Generator │ └── SyntaxBuilders │ │ ├── Statements │ │ ├── BreakBuilder.cs │ │ ├── ContinueBuilder.cs │ │ ├── ThrowBuilder.cs │ │ ├── ReturnBuilder.cs │ │ ├── WhileBuilder.cs │ │ ├── ForEachBuilder.cs │ │ ├── ArgumentListBuilder.cs │ │ ├── ForBuilder.cs │ │ ├── VariableBuilder.cs │ │ ├── CallBuilder.cs │ │ ├── SwitchBuilder.cs │ │ ├── IfBuilder.cs │ │ └── TryBuilder.cs │ │ ├── CsmlBuilder.cs │ │ ├── UsingDirectiveBuilder.cs │ │ ├── NamespaceBuilder.cs │ │ ├── Members │ │ ├── ParameterBuilder.cs │ │ └── ConstructorBuilder.cs │ │ └── BlockBuilder.cs │ ├── Exceptions │ ├── UnknownCsmlElementException.cs │ ├── UnknownCsmlAttributeException.cs │ ├── UnexpectedCsmlPermutationException.cs │ ├── CsmlParseException.cs │ └── InvalidAccessorException.cs │ ├── GlobalUsings.cs │ ├── AnalyzerReleases.Unshipped.md │ ├── Csml.csproj │ └── Workarounds.cs ├── tests └── CsmlTests │ ├── GlobalUsings.cs │ ├── Statements │ ├── BreakTests.cs │ ├── ContinueTests.cs │ ├── WhileTests.cs │ ├── SwitchTests.cs │ ├── ThrowTests.cs │ └── ForEachTests.cs │ ├── CsmlSyntaxWrapper.cs │ ├── Expressions │ ├── AwaitTests.cs │ ├── ValueTests.cs │ ├── AssignmentTests.cs │ ├── NewTests.cs │ └── BinaryExpressionTests.cs │ ├── CsmlTests.csproj │ ├── Types │ ├── InheritanceTests.cs │ ├── StructRefTests.cs │ └── StructReadOnlyTests.cs │ ├── FileExtensionTests.cs │ ├── Members │ ├── InterfaceMethodTests.cs │ ├── FieldRefTests.cs │ ├── FieldConstTests.cs │ ├── FieldStaticTests.cs │ ├── FieldReadOnlyTests.cs │ ├── MethodAsyncTests.cs │ ├── MethodStaticTests.cs │ ├── MethodVirtualTests.cs │ ├── MethodAbstractTests.cs │ └── MethodOverrideTests.cs │ ├── NamespaceTests.cs │ ├── UsingDirectiveTests.cs │ └── Helpers │ └── CompilationHelper.cs ├── documentation ├── types │ ├── property-getter-accessor.md │ ├── property-setter-accessor.md │ ├── access-modifiers.md │ ├── parameter-modifier.md │ └── expressions.md └── tags │ ├── break.md │ ├── default.md │ ├── continue.md │ ├── return.md │ ├── decrement.md │ ├── increment.md │ ├── prefix-decrement.md │ ├── prefix-increment.md │ ├── value.md │ ├── throw.md │ ├── inheritance.md │ ├── not.md │ ├── argument.md │ ├── await.md │ ├── try.md │ ├── bitwise-not.md │ ├── csml.md │ ├── new.md │ ├── using-directive.md │ ├── case.md │ ├── add.md │ ├── divide.md │ ├── equals.md │ ├── or.md │ ├── and.md │ ├── less-than.md │ ├── multiply.md │ ├── subtract.md │ ├── left-shift.md │ ├── not-equals.md │ ├── xor.md │ ├── remainder.md │ ├── right-shift.md │ ├── assignment.md │ ├── greater-than.md │ ├── bitwise-or.md │ ├── bitwise-and.md │ ├── less-than-or-equal.md │ ├── parameter.md │ ├── greater-than-or-equal.md │ ├── unsigned-right-shift.md │ ├── call.md │ ├── enum-value.md │ ├── for-each.md │ ├── finally.md │ ├── variable.md │ ├── while.md │ ├── else.md │ ├── catch.md │ ├── enum.md │ ├── interface.md │ ├── switch.md │ ├── if.md │ ├── constructor.md │ ├── else-if.md │ ├── namespace.md │ ├── field.md │ ├── for.md │ ├── property.md │ ├── class.md │ ├── method.md │ ├── struct.md │ └── block.md ├── .github ├── dependabot.yml └── workflows │ └── dotnet.yml └── LICENSE /demos/FizzBuzz/Program.cs: -------------------------------------------------------------------------------- 1 | using Demo; 2 | 3 | FizzBuzz.Run(); 4 | -------------------------------------------------------------------------------- /demos/HelloWorld/README.md: -------------------------------------------------------------------------------- 1 | # HelloWorld 2 | 3 | This project is a simple "*Hello, World!*" written in C♯ML. 4 | -------------------------------------------------------------------------------- /demos/Sandbox/Program.cs: -------------------------------------------------------------------------------- 1 | using Sandbox; 2 | 3 | MyClass myClass = new MyClass(); 4 | myClass.MyMethod(); 5 | -------------------------------------------------------------------------------- /demos/Sandbox/README.md: -------------------------------------------------------------------------------- 1 | # Sandbox 2 | 3 | This project is intended to be a sandbox for playing around with C♯ML. 4 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/NotNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class NotNode : UnaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/OrNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class OrNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/AddNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class AddNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/AndNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class AndNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/XorNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class XorNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/ConstructorNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | public class ConstructorNode : MethodBaseNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/BlockNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class BlockNode : StatementContainerNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/DivideNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class DivideNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/EqualsNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class EqualsNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/DefaultNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class DefaultNode : StatementContainerNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ThrowNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class ThrowNode : ExpressionStatementNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /demos/WebAPI/WebAPI.http: -------------------------------------------------------------------------------- 1 | @WebAPI_HostAddress = http://localhost:5178 2 | 3 | GET {{WebAPI_HostAddress}}/double?input=7 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/AssignmentNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class AssignmentNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/BitwiseAndNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class BitwiseAndNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/BitwiseNotNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class BitwiseNotNode : UnaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/BitwiseOrNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class BitwiseOrNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/ExpressionNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public abstract class ExpressionNode : BaseNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/LeftShiftNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class LeftShiftNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/LessThanNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class LessThanNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/MultiplyNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class MultiplyNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/NotEqualsNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class NotEqualsNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/RemainderNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class RemainderNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/RightShiftNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class RightShiftNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/SubtractNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class SubtractNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/DecrementNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class DecrementNode : UnaryValueExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/GreaterThanNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class GreaterThanNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/IncrementNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class IncrementNode : UnaryValueExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/LessThanOrEqualNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class LessThanOrEqualNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/PrefixDecrementNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class PrefixDecrementNode : UnaryValueExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/PrefixIncrementNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class PrefixIncrementNode : UnaryValueExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | // Exposes internal types as public for the testing project. 4 | [assembly: InternalsVisibleTo("CsmlTests")] 5 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/GreaterThanOrEqualNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class GreaterThanOrEqualNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/UnsignedRightShiftNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class UnsignedRightShiftNode : BinaryExpressionNode 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /demos/WebAPI/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Csml/AnalyzerReleases.Shipped.md: -------------------------------------------------------------------------------- 1 | ; Shipped analyzer releases 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | -------------------------------------------------------------------------------- /demos/WebAPI/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/BreakNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents a break statement. 5 | /// 6 | public class BreakNode : BaseNode 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/InheritanceNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | public class InheritanceNode : BaseNode 4 | { 5 | [XmlAttribute("Type")] 6 | public required string Type { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /demos/FizzBuzz/README.md: -------------------------------------------------------------------------------- 1 | # FizzBuzz 2 | 3 | This project is a C♯ML implementation of the game [Fizz Buzz](https://en.wikipedia.org/wiki/Fizz_buzz). 4 | 5 | This project also demonstrates interoperability between C♯ML and C#. 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ElseIfNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents an else if statement. 5 | /// 6 | public class ElseIfNode : IfNode 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/ValueNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class ValueNode : ExpressionNode 4 | { 5 | [XmlAttribute("Value")] 6 | public required string Value { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ContinueNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents a continue statement. 5 | /// 6 | public class ContinueNode : BaseNode 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ElseNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents an else statement. 5 | /// 6 | public class ElseNode : StatementContainerNode 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/TryNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class TryNode : BaseNode 4 | { 5 | [XmlElement("Statements")] 6 | public required BlockNode Statements { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/CaseNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class CaseNode : StatementContainerNode 4 | { 5 | [XmlAttribute("Value")] 6 | public required string Value { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/FinallyNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class FinallyNode : BaseNode 4 | { 5 | [XmlElement("Statements")] 6 | public required BlockNode Statements { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/AwaitNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class AwaitNode : ExpressionNode 4 | { 5 | [XmlElement("Expression")] 6 | public required ExpressionStatementNode Expression { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/InterfaceNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Represents an interface declaration. 5 | /// 6 | [XmlType("Interface")] 7 | public class InterfaceNode : TypeNode 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/UnaryValueExpressionNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public abstract class UnaryValueExpressionNode : ExpressionNode 4 | { 5 | [XmlAttribute("Target")] 6 | public required string Target { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/BreakBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal class BreakBuilder 4 | { 5 | public static BreakStatementSyntax Build() 6 | { 7 | return SF.BreakStatement(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Csml/Parser/CsmlConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser; 2 | 3 | /// 4 | /// Contains general constant- and static values. 5 | /// 6 | internal static class CsmlConstants 7 | { 8 | public const string LineNumberMetadataAttribute = "__LineNumber"; 9 | } 10 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/UnaryExpressionNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public abstract class UnaryExpressionNode : ExpressionNode 4 | { 5 | [XmlElement("Expression")] 6 | public required ExpressionStatementNode Expression { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/ContinueBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal class ContinueBuilder 4 | { 5 | public static ContinueStatementSyntax Build() 6 | { 7 | return SF.ContinueStatement(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demos/WebAPI/README.md: -------------------------------------------------------------------------------- 1 | # WebAPI 2 | 3 | This project is a .NET Web API, with service interfaces, service classes, and model classes all written in C♯ML. 4 | 5 | This project demonstrates that C♯ML can fully substitute traditional C#, including in web-based applications which utilize dependency injection. 6 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/PropertyGetterAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Defines the valid values of a property getter. 5 | /// 6 | public enum PropertyGetterAccessor 7 | { 8 | Unset, 9 | 10 | [XmlEnum("Get")] 11 | Get 12 | } 13 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ReturnNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents a return statement. 5 | /// 6 | public class ReturnNode : BaseNode 7 | { 8 | [XmlAttribute("Value")] 9 | public string? Value { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/ClassNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Represents a class declaration. 5 | /// 6 | [XmlType("Class")] 7 | public class ClassNode : TypeNode 8 | { 9 | [XmlAttribute("Static")] 10 | public bool Static { get; init; } 11 | } 12 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/NewNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public class NewNode : ExpressionNode 4 | { 5 | [XmlAttribute("Type")] 6 | public required string Type { get; init; } 7 | 8 | [XmlElement("Argument")] 9 | public ArgumentNode[]? Arguments { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/UsingDirectiveNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Represents a using directive. 5 | /// 6 | public class UsingDirectiveNode : BaseNode 7 | { 8 | [XmlAttribute("Namespace")] 9 | public required string Namespace { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/ThrowBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal class ThrowBuilder 4 | { 5 | public static ThrowStatementSyntax Build(ThrowNode node) 6 | { 7 | return SF.ThrowStatement(ExpressionBuilder.Build(node.Expression)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/ArgumentNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Represents an argument provided to a method invocation. 5 | /// 6 | public class ArgumentNode : BaseNode 7 | { 8 | [XmlAttribute("Value")] 9 | public required string Value { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Csml/Parser/CsmlParseResult.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser; 2 | 3 | /// 4 | /// DTO which contains the C♯ML parse result, as well as any potential errors. 5 | /// 6 | /// 7 | /// 8 | public record CsmlParseResult(CsmlNode? Result, List Errors); 9 | -------------------------------------------------------------------------------- /src/Csml/Exceptions/UnknownCsmlElementException.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Exceptions; 2 | 3 | public class UnknownCsmlElementException : CsmlParseException 4 | { 5 | public UnknownCsmlElementException(int? LineNumber, string ElementName) 6 | : base(CsmlDiagnostics.UnexpectedElement, LineNumber, [ElementName]) 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/CsmlTests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.CodeAnalysis; 2 | global using Microsoft.CodeAnalysis.CSharp; 3 | global using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | global using System.Collections.Immutable; 5 | global using static CsmlTests.Helpers.CompilationHelper; 6 | global using static CsmlTests.Helpers.SyntaxNodeDescendantExtensions; 7 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/PropertySetterAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Defines the valid values of a property setter. 5 | /// 6 | public enum PropertySetterAccessor 7 | { 8 | Unset, 9 | 10 | [XmlEnum("Set")] 11 | Set, 12 | 13 | [XmlEnum("Init")] 14 | Init 15 | } 16 | -------------------------------------------------------------------------------- /demos/Sandbox/MyClass.c♯: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Csml/Parser/CsmlParseError.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser; 2 | 3 | /// 4 | /// Describes a C♯ML parsing error. 5 | /// 6 | /// 7 | /// 8 | /// 9 | public record CsmlParseError(DiagnosticDescriptor Descriptor, int? LineNumber, params string[] Arguments); 10 | -------------------------------------------------------------------------------- /documentation/types/property-getter-accessor.md: -------------------------------------------------------------------------------- 1 | # Property getter accessor 2 | 3 | ## Description 4 | 5 | Represents the various accessors for property getters. 6 | 7 | ## Values 8 | 9 | | Value | C# equivalent | 10 | |---|---| 11 | | Get | [`get`](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties#the-get-accessor) | 12 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Expressions/BinaryExpressionNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Expressions; 2 | 3 | public abstract class BinaryExpressionNode : ExpressionNode 4 | { 5 | [XmlElement("Left")] 6 | public required ExpressionStatementNode Left { get; init; } 7 | 8 | [XmlElement("Right")] 9 | public required ExpressionStatementNode Right { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/WhileNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class WhileNode : BaseNode 4 | { 5 | [XmlElement("Condition", typeof(ExpressionStatementNode))] 6 | public required ExpressionStatementNode Condition { get; init; } 7 | 8 | [XmlElement("Statements")] 9 | public required BlockNode Statements { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /documentation/tags/break.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents the `break` keyword. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | None. 14 | 15 | ## C# equivalent 16 | 17 | The `break` keyword. 18 | 19 | ## Example 20 | 21 | ### C♯ML 22 | 23 | ```xml 24 | 25 | ``` 26 | 27 | ### C# 28 | 29 | ```csharp 30 | break 31 | ``` 32 | -------------------------------------------------------------------------------- /src/Csml/Exceptions/UnknownCsmlAttributeException.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Csml.Exceptions; 3 | 4 | public class UnknownCsmlAttributeException : CsmlParseException 5 | { 6 | public UnknownCsmlAttributeException(DiagnosticDescriptor Descriptor, int? LineNumber, string AttributeName) 7 | : base(CsmlDiagnostics.UnexpectedAttribute, LineNumber, [AttributeName]) 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /documentation/tags/default.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents the `default` keyword. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | None. 14 | 15 | ## C# equivalent 16 | 17 | The `default` keyword. 18 | 19 | ## Example 20 | 21 | ### C♯ML 22 | 23 | ```xml 24 | 25 | ``` 26 | 27 | ### C# 28 | 29 | ```csharp 30 | default 31 | ``` 32 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/CatchNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class CatchNode : BaseNode 4 | { 5 | [XmlAttribute("Type")] 6 | public string? Type { get; init; } 7 | 8 | [XmlAttribute("Name")] 9 | public string? Name { get; init; } 10 | 11 | [XmlElement("Statements")] 12 | public required BlockNode Statements { get; init; } 13 | } 14 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/SwitchNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | public class SwitchNode : BaseNode 4 | { 5 | [XmlAttribute("Value")] 6 | public required string Value { get; init; } 7 | 8 | [XmlElement("Case", typeof(CaseNode))] 9 | [XmlElement("Default", typeof(DefaultNode))] 10 | public StatementContainerNode[]? Cases { get; init; } 11 | } 12 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/StructNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Represents a struct declaration. 5 | /// 6 | [XmlType("Struct")] 7 | public class StructNode : TypeNode 8 | { 9 | [XmlAttribute("ReadOnly")] 10 | public bool ReadOnly { get; set; } 11 | 12 | [XmlAttribute("Ref")] 13 | public bool Ref { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /documentation/tags/continue.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents the `continue` keyword. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | None. 14 | 15 | ## C# equivalent 16 | 17 | The `continue` keyword. 18 | 19 | ## Example 20 | 21 | ### C♯ML 22 | 23 | ```xml 24 | 25 | ``` 26 | 27 | ### C# 28 | 29 | ```csharp 30 | continue 31 | ``` 32 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/EnumValue.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Represents a value of an enum. 5 | /// 6 | [XmlType("EnumValue")] 7 | public class EnumValue : BaseNode 8 | { 9 | [XmlAttribute("Name")] 10 | public required string Name { get; init; } 11 | 12 | [XmlAttribute("Value")] 13 | public string? Value { get; init; } 14 | } 15 | -------------------------------------------------------------------------------- /src/Csml/Exceptions/UnexpectedCsmlPermutationException.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Exceptions; 2 | 3 | public class UnexpectedCsmlPermutationException : CsmlParseException 4 | { 5 | public UnexpectedCsmlPermutationException(int? LineNumber, string unexpectedTypeName, string baseTypeName) 6 | : base(CsmlDiagnostics.UnexpectedPermutation, LineNumber, [unexpectedTypeName, baseTypeName]) 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Csml/Exceptions/CsmlParseException.cs: -------------------------------------------------------------------------------- 1 | using Csml.Parser; 2 | 3 | namespace Csml.Exceptions; 4 | 5 | public class CsmlParseException : Exception 6 | { 7 | public CsmlParseError ParseError { get; } 8 | 9 | public CsmlParseException(DiagnosticDescriptor Descriptor, int? LineNumber, string[] Arguments) 10 | { 11 | ParseError = new CsmlParseError(Descriptor, LineNumber, Arguments); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /demos/WebAPI/Program.cs: -------------------------------------------------------------------------------- 1 | using WebAPI.Services.Abstractions; 2 | using WebAPI.Services.Implementations; 3 | 4 | WebApplicationBuilder builder = WebApplication.CreateBuilder(args); 5 | builder.Services.AddScoped(); 6 | 7 | WebApplication app = builder.Build(); 8 | 9 | app.MapGet("/double", 10 | (int input, ITestService testService) 11 | => testService.Double(input)); 12 | 13 | app.Run(); 14 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/IfNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents an if statement. 5 | /// 6 | public class IfNode : BaseNode 7 | { 8 | [XmlElement("Expression")] 9 | public required ExpressionStatementNode Expression { get; init; } 10 | 11 | [XmlElement("Statements")] 12 | public required BlockNode Statements { get; init; } 13 | } 14 | -------------------------------------------------------------------------------- /demos/WebAPI/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "http": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": false, 8 | "applicationUrl": "http://localhost:5178", 9 | "environmentVariables": { 10 | "ASPNETCORE_ENVIRONMENT": "Development" 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/ReturnBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class ReturnBuilder 4 | { 5 | public static ReturnStatementSyntax Build(ReturnNode node) 6 | { 7 | if (node.Value == null) 8 | { 9 | return SF.ReturnStatement(); 10 | } 11 | 12 | return SF.ReturnStatement(SF.IdentifierName(node.Value)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/CsmlNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes; 2 | 3 | /// 4 | /// The root node of a C♯ML source file. 5 | /// 6 | [XmlRoot(ElementName = "Csml", IsNullable = false)] 7 | public class CsmlNode : BaseNode 8 | { 9 | [XmlElement("UsingDirective")] 10 | public UsingDirectiveNode[]? UsingDirectives { get; init; } 11 | 12 | [XmlElement("Namespace")] 13 | public NamespaceNode[]? Namespaces { get; init; } 14 | } 15 | -------------------------------------------------------------------------------- /demos/WebAPI/Services/Abstractions/ITestService.c♯: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/ParameterModifier.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Defines the valid values of a reference parameter. 5 | /// 6 | public enum ParameterModifier 7 | { 8 | Unset, 9 | 10 | [XmlEnum("Ref")] 11 | Ref, 12 | 13 | [XmlEnum("Out")] 14 | Out, 15 | 16 | [XmlEnum("RefReadonly")] 17 | RefReadonly, 18 | 19 | [XmlEnum("In")] 20 | In, 21 | 22 | [XmlEnum("Params")] 23 | Params 24 | } 25 | -------------------------------------------------------------------------------- /demos/HelloWorld/Program.c♯: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/ParameterNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | public class ParameterNode : BaseNode 4 | { 5 | [XmlAttribute("Type")] 6 | public required string Type { get; init; } 7 | 8 | [XmlAttribute("Name")] 9 | public required string Name { get; init; } 10 | 11 | [XmlAttribute("Default")] 12 | public string? Default { get; init; } 13 | 14 | [XmlAttribute("Modifier")] 15 | public ParameterModifier Modifier { get; init; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/EnumNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Represents an enum declaration. 5 | /// 6 | [XmlType("Enum")] 7 | public class EnumNode : BaseNode 8 | { 9 | [XmlAttribute("Name")] 10 | public required string Name { get; init; } 11 | 12 | [XmlAttribute("Access")] 13 | public AccessModifier Access { get; init; } 14 | 15 | [XmlElement("EnumValue")] 16 | public EnumValue[]? Values { get; init; } 17 | } 18 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/WhileBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class WhileBuilder 4 | { 5 | public static WhileStatementSyntax Build(WhileNode whileNode) 6 | { 7 | ExpressionSyntax condition = ExpressionBuilder.Build(whileNode.Condition.Expression); 8 | BlockSyntax block = BlockBuilder.Build(whileNode.Statements.Statements); 9 | 10 | return SF.WhileStatement(condition, block); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Csml/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Csml.Exceptions; 2 | global using Csml.Generator; 3 | global using Csml.Parser.Nodes; 4 | global using Csml.Parser.Nodes.Members; 5 | global using Csml.Parser.Nodes.Statements; 6 | global using Csml.Parser.Nodes.Types; 7 | global using Microsoft.CodeAnalysis; 8 | global using Microsoft.CodeAnalysis.CSharp; 9 | global using Microsoft.CodeAnalysis.CSharp.Syntax; 10 | global using System.Xml.Serialization; 11 | global using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; 12 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/MethodBaseNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | public abstract class MethodBaseNode : BaseNode 4 | { 5 | [XmlAttribute("Access")] 6 | public AccessModifier Access { get; init; } 7 | 8 | [XmlAttribute("Static")] 9 | public bool Static { get; init; } 10 | 11 | [XmlElement("Parameter")] 12 | public ParameterNode[]? Parameters { get; init; } 13 | 14 | [XmlElement("Statements")] 15 | public BlockNode? Statements { get; init; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ForEachNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents a foreach statement. 5 | /// 6 | public class ForEachNode : StatementContainerNode 7 | { 8 | [XmlAttribute("Type")] 9 | public required string Type { get; init; } 10 | 11 | [XmlAttribute("Name")] 12 | public required string Name { get; init; } 13 | 14 | [XmlAttribute("Collection")] 15 | public required string Collection { get; init; } 16 | } 17 | -------------------------------------------------------------------------------- /documentation/types/property-setter-accessor.md: -------------------------------------------------------------------------------- 1 | # Property setter accessor 2 | 3 | ## Description 4 | 5 | Represents the various accessors for property setters. 6 | 7 | ## Values 8 | 9 | | Value | C# equivalent | 10 | |---|---| 11 | | Set | [`set`](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties#the-set-accessor) | 12 | | Init | [`init`](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties#the-init-accessor) | 13 | -------------------------------------------------------------------------------- /documentation/tags/return.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `return` statement. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Value` | `string` | *Nothing* | No | The value to be returned. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `return` keyword. 20 | 21 | ## Example 22 | 23 | ```xml 24 | 25 | ``` 26 | 27 | ### C# 28 | 29 | ```csharp 30 | return 123; 31 | ``` 32 | -------------------------------------------------------------------------------- /src/Csml/Exceptions/InvalidAccessorException.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Exceptions; 2 | 3 | public class InvalidAccessorException : Exception 4 | { 5 | public int LineNumber { get; } 6 | 7 | public AccessModifier AccessModifiers { get; } 8 | 9 | public string Target { get; } 10 | 11 | public InvalidAccessorException(int lineNumber, AccessModifier accessModifiers, string target) 12 | { 13 | LineNumber = lineNumber; 14 | AccessModifiers = accessModifiers; 15 | Target = target; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/ForEachBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal class ForEachBuilder 4 | { 5 | public static ForEachStatementSyntax Build(ForEachNode node) 6 | { 7 | BlockSyntax block = BlockBuilder.Build(node.Statements); 8 | 9 | return SF.ForEachStatement( 10 | SF.IdentifierName(node.Type), 11 | SF.Identifier(node.Name), 12 | SF.IdentifierName(node.Collection), 13 | block); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/FieldNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Represents a field. 5 | /// 6 | [XmlType("Field")] 7 | public class FieldNode : MemberNode 8 | { 9 | [XmlAttribute("Const")] 10 | public bool Const { get; set; } 11 | 12 | [XmlAttribute("ReadOnly")] 13 | public bool ReadOnly { get; set; } 14 | 15 | [XmlAttribute("Ref")] 16 | public bool Ref { get; set; } 17 | 18 | [XmlAttribute("Static")] 19 | public bool Static { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /documentation/types/access-modifiers.md: -------------------------------------------------------------------------------- 1 | # Access modifiers 2 | 3 | ## Description 4 | 5 | Represents the various [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers). 6 | 7 | ## Values 8 | 9 | | Value | C# equivalent | 10 | |---|---| 11 | | Public | `public` | 12 | | Private | `private` | 13 | | Protected | `protected` | 14 | | Internal | `internal` | 15 | | ProtectedInternal | `protected internal` | 16 | | PrivateProtected | `private protected` | 17 | | File | `file` | 18 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/BaseNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes; 2 | 3 | /// 4 | /// The base CSML node type which all other node types inherit from. 5 | /// 6 | public abstract class BaseNode 7 | { 8 | /// 9 | /// Metadata field specifying the line number corresponding to the current node. 10 | /// Used to allow diagnostics to specify a concrete line number. 11 | /// 12 | [XmlAttribute(CsmlConstants.LineNumberMetadataAttribute)] 13 | public int LineNumber { get; init; } 14 | } 15 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/CallNode.cs: -------------------------------------------------------------------------------- 1 | using Csml.Parser.Nodes.Expressions; 2 | 3 | namespace Csml.Parser.Nodes.Statements; 4 | 5 | /// 6 | /// Represents a method invocation statement. 7 | /// 8 | public class CallNode : ExpressionNode 9 | { 10 | [XmlAttribute("Target")] 11 | public string? Target { get; init; } 12 | 13 | [XmlAttribute("Method")] 14 | public required string Method { get; init; } 15 | 16 | [XmlElement("Argument")] 17 | public ArgumentNode[]? Arguments { get; init; } 18 | } 19 | -------------------------------------------------------------------------------- /demos/Sandbox/Sandbox.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demos/FizzBuzz/FizzBuzz.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demos/HelloWorld/HelloWorld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/MemberNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Base class representing an type member. 5 | /// 6 | public abstract class MemberNode : BaseNode 7 | { 8 | [XmlAttribute("Name")] 9 | public required string Name { get; init; } 10 | 11 | [XmlAttribute("Type")] 12 | public required string Type { get; init; } 13 | 14 | [XmlAttribute("Value")] 15 | public string? Value { get; init; } 16 | 17 | [XmlAttribute("Access")] 18 | public AccessModifier Access { get; init; } 19 | } 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /documentation/tags/decrement.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a decrement operation (postfix) on `Target`. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Target` | `string` | *None* | Yes | The target of the operation. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `--` operator (postfix). 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | ``` 28 | 29 | ### C# 30 | 31 | ```csharp 32 | number-- 33 | ``` 34 | -------------------------------------------------------------------------------- /documentation/tags/increment.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a increment operation (postfix) on `Target`. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Target` | `string` | *None* | Yes | The target of the operation. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `++` operator (postfix). 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | ``` 28 | 29 | ### C# 30 | 31 | ```csharp 32 | number++ 33 | ``` 34 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/VariableNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents a variable declaration statement. 5 | /// 6 | public class VariableNode : BaseNode 7 | { 8 | [XmlAttribute("Const")] 9 | public bool Const { get; init; } 10 | 11 | [XmlAttribute("Name")] 12 | public required string Name { get; init; } 13 | 14 | [XmlAttribute("Type")] 15 | public required string Type { get; init; } 16 | 17 | [XmlElement("Expression")] 18 | public ExpressionStatementNode? Expression { get; init; } 19 | } 20 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/ArgumentListBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class ArgumentListBuilder 4 | { 5 | public static ArgumentListSyntax BuildArgumentList(ArgumentNode[] argumentNodes) 6 | { 7 | ArgumentListSyntax argumentList = SF.ArgumentList(); 8 | 9 | foreach (ArgumentNode argument in argumentNodes) 10 | { 11 | argumentList = argumentList.AddArguments(SF.Argument(SF.IdentifierName(argument.Value))); 12 | } 13 | 14 | return argumentList; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /documentation/tags/prefix-decrement.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a decrement operation (prefix) on `Target`. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Target` | `string` | *None* | Yes | The target of the operation. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `--` operator (prefix). 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | ``` 28 | 29 | ### C# 30 | 31 | ```csharp 32 | --number 33 | ``` 34 | -------------------------------------------------------------------------------- /documentation/tags/prefix-increment.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a increment operation (prefix) on `Target`. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Target` | `string` | *None* | Yes | The target of the operation. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `++` operator (prefix). 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | ``` 28 | 29 | ### C# 30 | 31 | ```csharp 32 | ++number 33 | ``` 34 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/AccessModifier.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes; 2 | 3 | /// 4 | /// Defines the valid values of access modifiers. 5 | /// 6 | public enum AccessModifier 7 | { 8 | Unset, 9 | 10 | [XmlEnum("Public")] 11 | Public, 12 | 13 | [XmlEnum("Private")] 14 | Private, 15 | 16 | [XmlEnum("Protected")] 17 | Protected, 18 | 19 | [XmlEnum("Internal")] 20 | Internal, 21 | 22 | [XmlEnum("ProtectedInternal")] 23 | ProtectedInternal, 24 | 25 | [XmlEnum("PrivateProtected")] 26 | PrivateProtected, 27 | 28 | [XmlEnum("File")] 29 | File 30 | } 31 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/PropertyNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Represents a property. 5 | /// 6 | [XmlType("Property")] 7 | public class PropertyNode : MemberNode 8 | { 9 | [XmlAttribute("Getter")] 10 | public PropertyGetterAccessor Getter { get; init; } 11 | 12 | [XmlAttribute("Setter")] 13 | public PropertySetterAccessor Setter { get; init; } 14 | 15 | [XmlAttribute("GetterAccess")] 16 | public AccessModifier GetterAccess { get; init; } 17 | 18 | [XmlAttribute("SetterAccess")] 19 | public AccessModifier SetterAccess { get; init; } 20 | } 21 | -------------------------------------------------------------------------------- /documentation/tags/value.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Refers to a value or an object. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The value. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | A literal value, or the name of a variable. 20 | 21 | ## Example 22 | 23 | ```xml 24 | 25 | 26 | 27 | 28 | 29 | ``` 30 | 31 | ### C# 32 | 33 | ```csharp 34 | int number = 123; 35 | ``` 36 | -------------------------------------------------------------------------------- /documentation/tags/throw.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs `throw` on ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The contained expression. | 16 | 17 | ## C# equivalent 18 | 19 | The `throw` keyword. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | ``` 30 | 31 | ### C# 32 | 33 | ```csharp 34 | throw new MyException(); 35 | ``` 36 | -------------------------------------------------------------------------------- /documentation/tags/inheritance.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Specifies a base class or interface implementation. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The name of the type. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `:` keyword and an type name. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | ``` 30 | 31 | ### C# 32 | 33 | ```csharp 34 | class MyClass : IDisposable 35 | { 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/CsmlBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders; 2 | 3 | internal static class CsmlBuilder 4 | { 5 | public static CompilationUnitSyntax Build(CsmlNode node) 6 | { 7 | CompilationUnitSyntax comp = SF.CompilationUnit(); 8 | 9 | SyntaxList usingList = UsingDirectiveBuilder.BuildMultiple(node.UsingDirectives); 10 | SyntaxList namespaceList = NamespaceBuilder.BuildMultiple(node.Namespaces); 11 | 12 | return comp 13 | .WithUsings(usingList) 14 | .WithMembers(namespaceList) 15 | .NormalizeWhitespace(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /demos/WebAPI/WebAPI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /documentation/tags/not.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a logical NOT operation on ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The contained expression. | 16 | 17 | ## C# equivalent 18 | 19 | The `!` operator. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | ### C# 34 | 35 | ```csharp 36 | !hasValue 37 | ``` 38 | -------------------------------------------------------------------------------- /documentation/tags/argument.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an argument being provided to a method invocation or object constructor. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Value` | `string` | *None* | Yes | The value of the argument. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | A method- or constructor argument. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | ``` 30 | 31 | ### C# 32 | 33 | ```csharp 34 | System.Console.WriteLine(123); 35 | ``` 36 | -------------------------------------------------------------------------------- /documentation/tags/await.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs `` in an `await` expression. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The contained expression. | 16 | 17 | ## C# equivalent 18 | 19 | The `await` keyword. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | ### C# 34 | 35 | ```csharp 36 | await myTask 37 | ``` 38 | -------------------------------------------------------------------------------- /documentation/tags/try.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `try` statement. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the try-statement. | 16 | 17 | ## C# equivalent 18 | 19 | The `try` keyword. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | ### C# 34 | 35 | ```csharp 36 | try 37 | { 38 | DoWork(); 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /tests/CsmlTests/Statements/BreakTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Statements; 2 | 3 | public class BreakTests 4 | { 5 | [Fact] 6 | public void BreakTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | """; 12 | 13 | // Act 14 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 15 | 16 | // Assert 17 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 18 | { 19 | Assert.Fail(); 20 | return; 21 | } 22 | 23 | Assert.True(methodDeclaration.Body?.GetChildNodes() is [BreakStatementSyntax]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Csml/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ; Unshipped analyzer release 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | ### New Rules 5 | 6 | Rule ID | Category | Severity | Notes 7 | --------|----------|----------|------- 8 | CSML0001 | CSML | Warning | CsmlDiagnostics 9 | CSML0002 | CSML | Error | CsmlDiagnostics 10 | CSML0003 | CSML | Error | CsmlDiagnostics 11 | CSML0004 | CSML | Error | CsmlDiagnostics 12 | CSML0005 | CSML | Error | CsmlDiagnostics 13 | CSML0006 | CSML | Error | CsmlDiagnostics 14 | CSML0007 | CSML | Error | CsmlDiagnostics 15 | CSML0008 | CSML | Error | CsmlDiagnostics 16 | CSML0009 | CSML | Error | CsmlDiagnostics -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Members/MethodNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Members; 2 | 3 | /// 4 | /// Represents a method. 5 | /// 6 | public class MethodNode : MethodBaseNode 7 | { 8 | [XmlAttribute("Name")] 9 | public required string Name { get; init; } 10 | 11 | [XmlAttribute("Return")] 12 | public required string Return { get; init; } 13 | 14 | [XmlAttribute("Async")] 15 | public bool Async { get; init; } 16 | 17 | [XmlAttribute("Abstract")] 18 | public bool Abstract { get; init; } 19 | 20 | [XmlAttribute("Virtual")] 21 | public bool Virtual { get; init; } 22 | 23 | [XmlAttribute("Override")] 24 | public bool Override { get; init; } 25 | } 26 | -------------------------------------------------------------------------------- /documentation/tags/bitwise-not.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a bitwise NOT operation on ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The contained expression. | 16 | 17 | ## C# equivalent 18 | 19 | The `~` operator. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | ### C# 34 | 35 | ```csharp 36 | ~myNumber 37 | ``` 38 | -------------------------------------------------------------------------------- /documentation/tags/csml.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents the root node of a C♯ML source file. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | Using directive | *None* | No | Yes | Using directives. | 16 | | `` | Namespace | *None* | No | Yes | Namespace declarations. | 17 | 18 | ## C# equivalent 19 | 20 | *No direct C# equivalent.* 21 | 22 | ## Example 23 | 24 | ```xml 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ForNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Statements; 2 | 3 | /// 4 | /// Represents a for statement. 5 | /// 6 | public class ForNode : BaseNode 7 | { 8 | [XmlElement("Variable", typeof(VariableNode))] 9 | public required VariableNode Variable { get; init; } 10 | 11 | [XmlElement("Condition", typeof(ExpressionStatementNode))] 12 | public required ExpressionStatementNode Condition { get; init; } 13 | 14 | [XmlElement("Iterator", typeof(ExpressionStatementNode))] 15 | public required ExpressionStatementNode Iterator { get; init; } 16 | 17 | [XmlElement("Statements")] 18 | public required BlockNode Statements { get; init; } 19 | } 20 | -------------------------------------------------------------------------------- /tests/CsmlTests/Statements/ContinueTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Statements; 2 | 3 | public class ContinueTests 4 | { 5 | [Fact] 6 | public void ContinueTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | """; 12 | 13 | // Act 14 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 15 | 16 | // Assert 17 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 18 | { 19 | Assert.Fail(); 20 | return; 21 | } 22 | 23 | Assert.True(methodDeclaration.Body?.GetChildNodes() is [ContinueStatementSyntax]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /documentation/tags/new.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Constructs a new object. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The type to be constructed. | 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | `` | [``](../tags/argument.md) | *None* | No | Yes | Constructor arguments. | 18 | 19 | ## C# equivalent 20 | 21 | The `new` keyword. 22 | 23 | ## Example 24 | 25 | ```xml 26 | 27 | 28 | 29 | ``` 30 | 31 | ### C# 32 | 33 | ```csharp 34 | new MyType(1) 35 | ``` 36 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v4 21 | with: 22 | dotnet-version: 9.0.x 23 | - name: Restore dependencies 24 | run: dotnet restore 25 | - name: Build 26 | run: dotnet build --no-restore 27 | - name: Test 28 | run: dotnet test --no-build --verbosity normal 29 | -------------------------------------------------------------------------------- /src/Csml/Csml.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 13.0 6 | enable 7 | enable 8 | true 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/ForBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class ForBuilder 4 | { 5 | public static ForStatementSyntax Build(ForNode node) 6 | { 7 | LocalDeclarationStatementSyntax variable = VariableBuilder.Build(node.Variable); 8 | ExpressionSyntax condition = ExpressionBuilder.Build(node.Condition.Expression); 9 | ExpressionSyntax incrementor = ExpressionBuilder.Build(node.Iterator.Expression); 10 | 11 | BlockSyntax block = BlockBuilder.Build(node.Statements.Statements); 12 | 13 | return SF.ForStatement(block) 14 | .WithDeclaration(variable.Declaration) 15 | .WithCondition(condition) 16 | .WithIncrementors([incrementor]); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/UsingDirectiveBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders; 2 | 3 | internal static class UsingDirectiveBuilder 4 | { 5 | public static SyntaxList BuildMultiple(UsingDirectiveNode[]? nodes) 6 | { 7 | SyntaxList usingList = SF.List(); 8 | 9 | if (nodes != null) 10 | { 11 | foreach (UsingDirectiveNode item in nodes) 12 | { 13 | usingList = usingList.Add(Build(item)); 14 | } 15 | } 16 | 17 | return usingList; 18 | } 19 | 20 | public static UsingDirectiveSyntax Build(UsingDirectiveNode node) 21 | { 22 | return SF.UsingDirective(SF.IdentifierName(node.Namespace)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/NamespaceNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Represents a namespace declaration. 5 | /// 6 | public class NamespaceNode : BaseNode 7 | { 8 | [XmlElement("Class", typeof(ClassNode))] 9 | [XmlElement("Struct", typeof(StructNode))] 10 | [XmlElement("Interface", typeof(InterfaceNode))] 11 | public TypeNode[]? Types { get; init; } 12 | 13 | [XmlAttribute("Name")] 14 | public required string Name { get; init; } 15 | 16 | [XmlElement("UsingDirective")] 17 | public UsingDirectiveNode[]? UsingDirectives { get; init; } 18 | 19 | [XmlElement("Namespace")] 20 | public NamespaceNode[]? Namespaces { get; init; } 21 | 22 | [XmlElement("Enum", typeof(EnumNode))] 23 | public EnumNode[]? Enums { get; init; } 24 | } 25 | -------------------------------------------------------------------------------- /documentation/tags/using-directive.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Declares a using directive. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Namespace` | `string` | *None* | Yes | The namespace of the using directive. | 12 | 13 | ## Elements 14 | 15 | None. 16 | 17 | ## C# equivalent 18 | 19 | The `using` keyword, in the context of using directives. 20 | 21 | ## Example 22 | 23 | ### C♯ML 24 | 25 | ```xml 26 | 27 | 28 | 29 | 30 | 31 | 32 | ``` 33 | 34 | ### C# 35 | 36 | ```csharp 37 | using System; 38 | 39 | namespace MyNamespace 40 | { 41 | using System.Text; 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /documentation/tags/case.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `case` in a `switch` statement. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Value` | `string` | *None* | Yes | The expression of the case. | 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | *Varies* | [Expressions](../types/expressions.md) | *None* | No | Yes | The statements contained within the case. | 18 | 19 | ## C# equivalent 20 | 21 | The `case` keyword. 22 | 23 | ## Example 24 | 25 | ### C♯ML 26 | 27 | ```xml 28 | 29 | 30 | 31 | 32 | ``` 33 | 34 | ### C# 35 | 36 | ```csharp 37 | case 1: 38 | DoWork(); 39 | break; 40 | ``` 41 | -------------------------------------------------------------------------------- /documentation/tags/add.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs an addition operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `+` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 1 + 2 41 | ``` 42 | -------------------------------------------------------------------------------- /src/Csml/Workarounds.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable IDE0130 // Namespace does not match folder structure 2 | #pragma warning disable IDE0290 // Use primary constructor 3 | #pragma warning disable IDE0060 // Remove unused parameter 4 | 5 | namespace System.Runtime.CompilerServices; 6 | 7 | /// 8 | /// Makes init working on .NET Standard 2.0. 9 | /// 10 | internal static class IsExternalInit 11 | { 12 | } 13 | 14 | /// 15 | /// Makes required work on .NET Standard 2.0. 16 | /// 17 | internal class RequiredMemberAttribute : Attribute 18 | { 19 | } 20 | 21 | /// 22 | /// Makes required work on .NET Standard 2.0. 23 | /// 24 | internal sealed class CompilerFeatureRequiredAttribute : Attribute 25 | { 26 | internal CompilerFeatureRequiredAttribute(string featureName) 27 | { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /documentation/tags/divide.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a division operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `*` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 4 / 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/equals.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs an equality comparison on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `==` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 == 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/or.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a logical OR operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `||` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | valueA || valueB 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/and.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a logical AND operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `&&` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | valueA && valueB 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/less-than.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a less-than comparison on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `<` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 < 3 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/multiply.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a multiplication operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `*` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 * 3 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/subtract.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a subtraction operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `-` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 - 1 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/left-shift.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a left shift-operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `<<` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 4 << 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/not-equals.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs an inequality comparison on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `!=` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 != 3 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/xor.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs an XOR operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `^` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | valueA ^ valueB 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/remainder.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a remainder/modulo operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `%` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 - 1 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/right-shift.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a right-shift operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `>>` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 4 >> 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/assignment.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Assigns a value to a variable, property, or field. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `=` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | number = 123; 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/greater-than.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs an greater-than comparison on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `>` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 3 > 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/bitwise-or.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a bitwise OR operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `|` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | numberA | numberB 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/bitwise-and.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a bitwise AND operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `&` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | numberA & numberB 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/less-than-or-equal.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a less-than-or-equal comparison on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `<=` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 2 <= 3 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/parameter.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a parameter of a method or a constructor. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The type of the parameter. | 12 | | `Name` | `string` | *None* | Yes | The name of the parameter. | 13 | | `Default` | `string` | *None* | No | The default value of the parameter. | 14 | | `Modifier` | [`ParameterModifier`](../types/parameter-modifier.md) | *None* | No | The modifiers of the parameter. | 15 | 16 | ## Elements 17 | 18 | None. 19 | 20 | ## C# equivalent 21 | 22 | The method- or constructor parameter. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | ``` 33 | 34 | ### C# 35 | 36 | ```csharp 37 | void MyMethod(int number) 38 | ``` 39 | -------------------------------------------------------------------------------- /documentation/tags/greater-than-or-equal.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs a greater-than-or-equal comparison on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `>=` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 3 >= 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/unsigned-right-shift.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Performs an unsigned right-shift operation on `` and ``. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The left-hand argument of the expression. | 17 | 18 | ## C# equivalent 19 | 20 | The `>>>` operator. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | 1 >>> 2 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/tags/call.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a method invocation. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Target` | `string` | *None* | No | The object or type to target the method invocation at. | 12 | | `Method` | `string` | *None* | Yes | The name of the method being invoked. | 13 | 14 | ## Elements 15 | 16 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 17 | |---|---|---|---|---|---| 18 | | `` | [``](./argument.md) | *None* | No | Yes | The arguments passed to the method invocation. | 19 | 20 | ## C# equivalent 21 | 22 | A method invocation. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | ``` 33 | 34 | ### C# 35 | 36 | ```csharp 37 | System.Console.WriteLine(123); 38 | ``` 39 | -------------------------------------------------------------------------------- /documentation/types/parameter-modifier.md: -------------------------------------------------------------------------------- 1 | # Access modifiers 2 | 3 | ## Description 4 | 5 | Represents the various modifiers that can be applied to method- and constructor parameters. 6 | 7 | ## Values 8 | 9 | | Value | C# equivalent | 10 | |---|---| 11 | | Ref | [`ref`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#ref-parameter-modifier) | 12 | | Out | [`out`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#out-parameter-modifier) | 13 | | RefReadonly | [`ref readonly`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#ref-readonly-modifier) | 14 | | In | [`in`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#in-parameter-modifier) | 15 | | Params | [`params`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#params-modifier) | 16 | -------------------------------------------------------------------------------- /documentation/tags/enum-value.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Defines a value in an enum. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Name` | `string` | *None* | Yes | The name of the enum value. | 12 | | `Value` | Number | *Implicitly determined* | No | The value of the enum value. | 13 | 14 | ## Elements 15 | 16 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 17 | |---|---|---|---|---|---| 18 | | `` | [``](../tags/enum-value.md) | *None* | No | Yes | The values of the enum. | 19 | 20 | ## C# equivalent 21 | 22 | The values of an `enum`. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | ### C# 37 | 38 | ```csharp 39 | enum MyEnum 40 | { 41 | A, 42 | B, 43 | C = 3 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /documentation/tags/for-each.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `foreach` statement. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The type of the values being iterated over. | 12 | | `Name` | `string` | *None* | Yes | The name of the current iterated value. | 13 | | `Collection` | `string` | *None* | Yes | The name of the collection that the foreach statement iterates over. | 14 | 15 | ## Elements 16 | 17 | None. 18 | 19 | ## C# equivalent 20 | 21 | The `foreach` keyword. 22 | 23 | ## Example 24 | 25 | ### C♯ML 26 | 27 | ```xml 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | foreach (int number in numbers) 41 | { 42 | int valA = number; 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /documentation/tags/finally.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an `finally` statement. 6 | 7 | Note: This tag must come after a [``](./try.md) or [``](./catch.md) tag. 8 | 9 | ## Attributes 10 | 11 | | Name | Type | Default | Mandatory | Description | 12 | |---|---|---|---|---| 13 | | `Type` | `string` | *None* | No | The exception type to catch. | 14 | | `Name` | `string` | *None* | No | The name of the caught exception. | 15 | 16 | ## Elements 17 | 18 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 19 | |---|---|---|---|---|---| 20 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the finally-statement. | 21 | 22 | ## C# equivalent 23 | 24 | The `finally` keyword. 25 | 26 | ## Example 27 | 28 | ### C♯ML 29 | 30 | ```xml 31 | 32 | 33 | 34 | 35 | 36 | ``` 37 | 38 | ### C# 39 | 40 | ```csharp 41 | finally 42 | { 43 | Dispose(); 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /tests/CsmlTests/CsmlSyntaxWrapper.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests; 2 | 3 | internal static class CsmlSyntaxWrapper 4 | { 5 | public static string WrapInClass(string markup) 6 | { 7 | return $""" 8 | 9 | 10 | 11 | {markup} 12 | 13 | 14 | 15 | """; 16 | } 17 | 18 | public static string WrapInMethod(string markup) 19 | { 20 | return $""" 21 | 22 | 23 | 24 | 25 | 26 | {markup} 27 | 28 | 29 | 30 | 31 | 32 | """; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demos/WebAPI/Models/TestModel.c♯: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /documentation/tags/variable.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Declares a variable. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Name` | `string` | *None* | Yes | The name of the variable. | 12 | | `Type` | `string` | *None* | Yes | The type of the variable. | 13 | | `Const` | `bool` | `false` | No | Defines the variable as [`const`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const). | 14 | 15 | ## Elements 16 | 17 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 18 | |---|---|---|---|---|---| 19 | | `` | [Expressions](../types/expressions.md) | *Uninitialized* | No | No | The expression defining the value of the variable. | 20 | 21 | ## C# equivalent 22 | 23 | A variable declaration. 24 | 25 | ## Example 26 | 27 | ```xml 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | ### C# 36 | 37 | ```csharp 38 | int number = 123; 39 | ``` 40 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/VariableBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal class VariableBuilder 4 | { 5 | public static LocalDeclarationStatementSyntax Build(VariableNode node) 6 | { 7 | VariableDeclaratorSyntax variableDeclarator = SF.VariableDeclarator(node.Name); 8 | 9 | if (node.Expression != null) 10 | { 11 | ExpressionSyntax valueExpression = ExpressionBuilder.Build(node.Expression.Expression); 12 | variableDeclarator = variableDeclarator.WithInitializer(SF.EqualsValueClause(valueExpression)); 13 | } 14 | 15 | VariableDeclarationSyntax variableDeclaration = SF.VariableDeclaration(SF.IdentifierName(node.Type), [variableDeclarator]); 16 | 17 | SyntaxTokenList tokenList = SF.TokenList(); 18 | 19 | if (node.Const) 20 | { 21 | tokenList = tokenList.Add(SF.Token(SyntaxKind.ConstKeyword)); 22 | } 23 | 24 | return SF.LocalDeclarationStatement(variableDeclaration) 25 | .WithModifiers(tokenList); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /documentation/tags/while.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `while` statement. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The condition of the while-statement. | 16 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the while-statement. | 17 | 18 | ## C# equivalent 19 | 20 | The `while` keyword. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | 44 | ### C# 45 | 46 | ```csharp 47 | while (i < 5) 48 | { 49 | i++; 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /documentation/tags/else.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an `else` statement. 6 | 7 | Note: This tag must come after an [``](./if.md) or [``](./else-if.md) tag. 8 | 9 | ## Attributes 10 | 11 | None. 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | `` | [Expression](../types/expressions.md) | *None* | Yes | No | The expression to be matched in order for the statements of the else-statement to be executed. | 18 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the else-statement. | 19 | 20 | ## C# equivalent 21 | 22 | The `else` keyword. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | ### C# 41 | 42 | ```csharp 43 | else 44 | { 45 | int valA = 3; 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 DevAndersen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /documentation/tags/catch.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an `catch` statement. 6 | 7 | Note: This tag must come after a [``](./try.md) tag. 8 | 9 | ## Attributes 10 | 11 | | Name | Type | Default | Mandatory | Description | 12 | |---|---|---|---|---| 13 | | `Type` | `string` | *None* | No | The exception type to catch. | 14 | | `Name` | `string` | *None* | No | The name of the caught exception. | 15 | 16 | ## Elements 17 | 18 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 19 | |---|---|---|---|---|---| 20 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the catch-statement. | 21 | 22 | ## C# equivalent 23 | 24 | The `catch` keyword. 25 | 26 | ## Example 27 | 28 | ### C♯ML 29 | 30 | ```xml 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | ### C# 41 | 42 | ```csharp 43 | catch (InvalidOperationException e) 44 | { 45 | HandleError(e); 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /documentation/tags/enum.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Declares an enum. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the enum. | 12 | | `Name` | `string` | *None* | Yes | The name of the enum. | 13 | 14 | ## Elements 15 | 16 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 17 | |---|---|---|---|---|---| 18 | | `` | [``](../tags/enum-value.md) | *None* | No | Yes | The values of the enum. | 19 | 20 | ## C# equivalent 21 | 22 | The `enum` keyword and an associated enum declaration. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | ### C# 37 | 38 | ```csharp 39 | enum MyEnum 40 | { 41 | A, 42 | B, 43 | C = 3 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /tests/CsmlTests/Expressions/AwaitTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Expressions; 2 | 3 | public class AwaitTests 4 | { 5 | [Fact] 6 | public void AwaitTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | """; 16 | 17 | // Act 18 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 19 | 20 | // Assert 21 | if (!output.FirstDescendant(out MethodDeclarationSyntax? awaitExpression)) 22 | { 23 | Assert.Fail(); 24 | return; 25 | } 26 | 27 | if (awaitExpression.Body?.Statements is not [LocalDeclarationStatementSyntax { Declaration: { } declaration }]) 28 | { 29 | Assert.Fail(); 30 | return; 31 | } 32 | 33 | Assert.True(declaration.Type is IdentifierNameSyntax { Identifier.Value: "await" }); 34 | Assert.True(declaration.Variables is [VariableDeclaratorSyntax { Identifier.Value: "task" }]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/CallBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal class CallBuilder 4 | { 5 | public static ExpressionStatementSyntax Build(CallNode node) 6 | { 7 | InvocationExpressionSyntax invocationExpression; 8 | 9 | if (node.Target != null && !string.IsNullOrWhiteSpace(node.Target)) 10 | { 11 | MemberAccessExpressionSyntax methodAccessExpression = SF.MemberAccessExpression( 12 | SyntaxKind.SimpleMemberAccessExpression, 13 | SF.IdentifierName(node.Target), 14 | SF.IdentifierName(node.Method)); 15 | 16 | invocationExpression = SF.InvocationExpression(methodAccessExpression); 17 | } 18 | else 19 | { 20 | invocationExpression = SF.InvocationExpression(SF.IdentifierName(node.Method)); 21 | } 22 | 23 | if (node.Arguments != null) 24 | { 25 | invocationExpression = invocationExpression.WithArgumentList(ArgumentListBuilder.BuildArgumentList(node.Arguments)); 26 | } 27 | 28 | return SF.ExpressionStatement(invocationExpression); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/SwitchBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class SwitchBuilder 4 | { 5 | public static SwitchStatementSyntax Build(SwitchNode switchNode) 6 | { 7 | SwitchStatementSyntax switchStatement = SF.SwitchStatement(SF.IdentifierName(switchNode.Value)); 8 | 9 | if (switchNode.Cases != null) 10 | { 11 | foreach (StatementContainerNode caseNode in switchNode.Cases) 12 | { 13 | switchStatement = switchStatement.AddSections(BuildCase(caseNode)); 14 | } 15 | } 16 | 17 | return switchStatement; 18 | } 19 | 20 | private static SwitchSectionSyntax BuildCase(StatementContainerNode node) 21 | { 22 | SwitchLabelSyntax label = node switch 23 | { 24 | CaseNode caseNode => SF.CaseSwitchLabel(SF.IdentifierName(caseNode.Value)), 25 | DefaultNode => SF.DefaultSwitchLabel(), 26 | _ => throw new NotImplementedException() // Todo: Throw appropriate exception. 27 | }; 28 | 29 | BlockSyntax block = BlockBuilder.Build(node.Statements); 30 | return SF.SwitchSection([label], [block]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /documentation/tags/interface.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Declares an interface. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the interface. | 12 | | `Name` | `string` | *None* | Yes | The name of the interface. | 13 | 14 | ## Elements 15 | 16 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 17 | |---|---|---|---|---|---| 18 | | `` | [``](../tags/method.md) | *None* | No | Yes | Method declarations. | 19 | | `` | [``](../tags/property.md) | *None* | No | Yes | Property declarations. | 20 | 21 | ## C# equivalent 22 | 23 | The `interface` keyword and an associated interface declaration. 24 | 25 | ## Example 26 | 27 | ### C♯ML 28 | 29 | ```xml 30 | 31 | 32 | 33 | ``` 34 | 35 | ### C# 36 | 37 | ```csharp 38 | public interface IMyInterface 39 | { 40 | void DoStuff(); 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /tests/CsmlTests/CsmlTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | false 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /documentation/tags/switch.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `switch` statement. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Value` | `string` | *None* | Yes | The name of the value being switched over. | 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | `` | [Expressions](./case.md) | *None* | No | Yes | A `case` within the switch-statement. | 18 | | `` | [Expressions](./default.md) | *None* | No | Yes | A `default` case within the switch-statement. | 19 | 20 | ## C# equivalent 21 | 22 | The `switch` keyword. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ``` 41 | 42 | ### C# 43 | 44 | ```csharp 45 | switch (myNumber) 46 | { 47 | case 1: 48 | { 49 | break; 50 | } 51 | 52 | case 2: 53 | { 54 | break; 55 | } 56 | 57 | default: 58 | { 59 | break; 60 | } 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /documentation/tags/if.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an `if` statement. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [Expression](../types/expressions.md) | *None* | Yes | No | The expression to be matched in order for the statements of the if-statement to be executed. | 16 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the if-statement. | 17 | 18 | ## C# equivalent 19 | 20 | The `case` keyword. 21 | 22 | ## Example 23 | 24 | ### C♯ML 25 | 26 | ```xml 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ``` 47 | 48 | ### C# 49 | 50 | ```csharp 51 | if (1 < 2) 52 | { 53 | int valA = 1; 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Types/TypeNode.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Parser.Nodes.Types; 2 | 3 | /// 4 | /// Base class represents a type declaration (class, struct, or interface). 5 | /// 6 | /// 7 | /// Enumeration types are defined via . 8 | /// 9 | public abstract class TypeNode : BaseNode 10 | { 11 | [XmlAttribute("Name")] 12 | public required string Name { get; init; } 13 | 14 | [XmlAttribute("Access")] 15 | public AccessModifier Access { get; init; } 16 | 17 | [XmlElement("Field", typeof(FieldNode))] 18 | [XmlElement("Property", typeof(PropertyNode))] 19 | public MemberNode[]? Members { get; init; } 20 | 21 | [XmlElement("Class", typeof(ClassNode))] 22 | [XmlElement("Struct", typeof(StructNode))] 23 | [XmlElement("Interface", typeof(InterfaceNode))] 24 | public TypeNode[]? Types { get; init; } 25 | 26 | [XmlElement("Enum", typeof(EnumNode))] 27 | public EnumNode[]? Enums { get; init; } 28 | 29 | [XmlElement("Method")] 30 | public MethodNode[]? Methods { get; init; } 31 | 32 | [XmlElement("Inheritance")] 33 | public InheritanceNode[]? BaseTypes { get; init; } 34 | 35 | [XmlElement("Constructor")] 36 | public ConstructorNode[]? Constructors { get; init; } 37 | } 38 | -------------------------------------------------------------------------------- /documentation/tags/constructor.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an constructor declaration. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the constructor. | 12 | | `Static` | `bool` | `false` | No | Marks the constructor as static. | 13 | 14 | ## Elements 15 | 16 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 17 | |---|---|---|---|---|---| 18 | | `` | [``](./block.md) | *None* | No | Yes | The parameters of the constructor. | 19 | | `` | [``](./block.md) | *None* | No | No | The statements contained within the constructor. | 20 | 21 | ## C# equivalent 22 | 23 | A constructor method. 24 | 25 | ## Example 26 | 27 | ### C♯ML 28 | 29 | ```xml 30 | 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | ### C# 38 | 39 | ```csharp 40 | class MyClass 41 | { 42 | public MyClass(int number) 43 | { 44 | } 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /tests/CsmlTests/Statements/WhileTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Statements; 2 | 3 | public class WhileTests 4 | { 5 | [Fact] 6 | public void WhileTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | """; 26 | 27 | // Act 28 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 29 | 30 | // Assert 31 | if (!output.FirstDescendant(out WhileStatementSyntax? whileStatement)) 32 | { 33 | Assert.Fail(); 34 | return; 35 | } 36 | 37 | Assert.True(whileStatement.Condition is BinaryExpressionSyntax { RawKind: (int)SyntaxKind.LessThanExpression }); 38 | Assert.True(whileStatement.Statement is BlockSyntax { Statements.Count: 1 }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/IfBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class IfBuilder 4 | { 5 | public static IfStatementSyntax Build(IfNode node, IEnumerable chainedNodes) 6 | { 7 | ExpressionSyntax condition = ExpressionBuilder.Build(node.Expression.Expression); 8 | 9 | BlockSyntax block = BlockBuilder.Build(node.Statements.Statements); 10 | IfStatementSyntax ifStatement = SF.IfStatement(condition, block); 11 | 12 | ifStatement = BuildElseChain(ifStatement, chainedNodes); 13 | 14 | return ifStatement; 15 | } 16 | 17 | private static IfStatementSyntax BuildElseChain(IfStatementSyntax ifStatement, IEnumerable chainedNodes) 18 | { 19 | BaseNode firstNode = chainedNodes.FirstOrDefault(); 20 | 21 | if (firstNode is ElseIfNode elseIfNode) 22 | { 23 | ElseClauseSyntax elseClause = SF.ElseClause(Build(elseIfNode, chainedNodes.Skip(1))); 24 | ifStatement = ifStatement.WithElse(elseClause); 25 | } 26 | else if (firstNode is ElseNode elseNode) 27 | { 28 | BlockSyntax block = BlockBuilder.Build(elseNode.Statements); 29 | ifStatement = ifStatement.WithElse(SF.ElseClause(block)); 30 | } 31 | 32 | return ifStatement; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/CsmlTests/Expressions/ValueTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Expressions; 2 | 3 | public class ValueTests 4 | { 5 | [Fact] 6 | public void ValueTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | """; 16 | 17 | // Act 18 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 19 | 20 | // Assert 21 | if (!output.FirstDescendant(out LocalDeclarationStatementSyntax? declaration)) 22 | { 23 | Assert.Fail(); 24 | return; 25 | } 26 | 27 | if (declaration.Declaration.Variables is not [VariableDeclaratorSyntax declarator]) 28 | { 29 | Assert.Fail(); 30 | return; 31 | } 32 | 33 | Assert.True(declaration.Declaration.Type is PredefinedTypeSyntax { Keyword.Value: "int" }); 34 | Assert.Equal("number", declarator.Identifier.Text); 35 | Assert.True(declarator.Initializer?.Value is LiteralExpressionSyntax { RawKind: (int)SyntaxKind.NumericLiteralExpression }); 36 | Assert.True(declarator.Initializer?.Value is LiteralExpressionSyntax { Token.Value: 123 }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /demos/WebAPI/Services/Implementations/TestService.c♯: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /documentation/tags/else-if.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an `else if` statement. 6 | 7 | Note: This tag must come after an [``](./if.md) tag. 8 | 9 | ## Attributes 10 | 11 | None. 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | `` | [Expression](../types/expressions.md) | *None* | Yes | No | The expression to be matched in order for the statements of the else-if-statement to be executed. | 18 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the else-if-statement. | 19 | 20 | ## C# equivalent 21 | 22 | An `else if` statement. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | 50 | ### C# 51 | 52 | ```csharp 53 | else if (4 != 2) 54 | { 55 | int valA = 2; 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /documentation/types/expressions.md: -------------------------------------------------------------------------------- 1 | # Expressions 2 | 3 | ## Description 4 | 5 | Represents various kinds of expressions. 6 | 7 | ## Values 8 | 9 | - [``](../tags/add.md) 10 | - [``](../tags/and.md) 11 | - [``](../tags/assignment.md) 12 | - [``](../tags/await.md) 13 | - [``](../tags/bitwise-and.md) 14 | - [``](../tags/bitwise-not.md) 15 | - [``](../tags/bitwise-or.md) 16 | - [``](../tags/call.md) 17 | - [``](../tags/decrement.md) 18 | - [``](../tags/divide.md) 19 | - [``](../tags/equals.md) 20 | - [``](../tags/greater-than.md) 21 | - [``](../tags/greater-than-or-equal.md) 22 | - [``](../tags/increment.md) 23 | - [``](../tags/left-shift.md) 24 | - [``](../tags/less-than.md) 25 | - [``](../tags/less-than-or-equal.md) 26 | - [``](../tags/multiply.md) 27 | - [``](../tags/new.md) 28 | - [``](../tags/not.md) 29 | - [``](../tags/not-equals.md) 30 | - [``](../tags/or.md) 31 | - [``](../tags/prefix-decrement.md) 32 | - [``](../tags/prefix-increment.md) 33 | - [``](../tags/remainder.md) 34 | - [``](../tags/right-shift.md) 35 | - [``](../tags/subtract.md) 36 | - [``](../tags/unsigned-right-shift.md) 37 | - [``](../tags/value.md) 38 | - [``](../tags/xor.md) 39 | -------------------------------------------------------------------------------- /tests/CsmlTests/Expressions/AssignmentTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Expressions; 2 | 3 | public class AssignmentTests 4 | { 5 | [Fact] 6 | public void AssignmentTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out ExpressionStatementSyntax? expressionStatement)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | if (expressionStatement.Expression is not AssignmentExpressionSyntax assignment) 31 | { 32 | Assert.Fail(); 33 | return; 34 | } 35 | 36 | if (assignment.Right is not LiteralExpressionSyntax rightExpression) 37 | { 38 | Assert.Fail(); 39 | return; 40 | } 41 | 42 | Assert.True(assignment.Left is IdentifierNameSyntax { Identifier.Value: "number" }); 43 | Assert.Equal(SyntaxKind.NumericLiteralExpression, rightExpression.Kind()); 44 | Assert.Equal(123, rightExpression.Token.Value); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /documentation/tags/namespace.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a namespace declaration. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Name` | `string` | *None* | Yes | The name of the namespace. | 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | `` | [``](../tags/class.md) | *None* | No | Yes | Class declarations. | 18 | | `` | [``](../tags/enum.md) | *None* | No | Yes | Enum declarations. | 19 | | `` | [``](../tags/namespace.md) | *None* | No | Yes | Namespace declarations. | 20 | | `` | [``](../tags/interface.md) | *None* | No | Yes | declarations. | 21 | | `` | [``](../tags/struct.md) | *None* | No | Yes | declarations. | 22 | | `` | [``](../tags/using-directive.md) | *None* | No | Yes | Using directives. | 23 | 24 | ## C# equivalent 25 | 26 | The `namespace` keyword and an associated namespace declaration. 27 | 28 | ## Example 29 | 30 | ```xml 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ``` 41 | 42 | ### C# 43 | 44 | ```csharp 45 | namespace MyNamespace 46 | { 47 | class MyClass 48 | { 49 | } 50 | 51 | interface IMyInterface 52 | { 53 | } 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/StatementContainerNode.cs: -------------------------------------------------------------------------------- 1 | using Csml.Parser.Nodes.Expressions; 2 | 3 | namespace Csml.Parser.Nodes.Statements; 4 | 5 | /// 6 | /// Base class representing a node that can contain statements as child nodes. 7 | /// 8 | public abstract class StatementContainerNode : BaseNode 9 | { 10 | [XmlElement("Assignment", typeof(AssignmentNode))] 11 | [XmlElement("Await", typeof(AwaitNode))] 12 | [XmlElement("Break", typeof(BreakNode))] 13 | [XmlElement("Call", typeof(CallNode))] 14 | [XmlElement("Catch", typeof(CatchNode))] 15 | [XmlElement("Continue", typeof(ContinueNode))] 16 | [XmlElement("Decrement", typeof(DecrementNode))] 17 | [XmlElement("Else", typeof(ElseNode))] 18 | [XmlElement("ElseIf", typeof(ElseIfNode))] 19 | [XmlElement("For", typeof(ForNode))] 20 | [XmlElement("ForEach", typeof(ForEachNode))] 21 | [XmlElement("Finally", typeof(FinallyNode))] 22 | [XmlElement("If", typeof(IfNode))] 23 | [XmlElement("Increment", typeof(IncrementNode))] 24 | [XmlElement("New", typeof(NewNode))] 25 | [XmlElement("PrefixDecrement", typeof(PrefixDecrementNode))] 26 | [XmlElement("PrefixIncrement", typeof(PrefixIncrementNode))] 27 | [XmlElement("Return", typeof(ReturnNode))] 28 | [XmlElement("Throw", typeof(ThrowNode))] 29 | [XmlElement("Try", typeof(TryNode))] 30 | [XmlElement("Variable", typeof(VariableNode))] 31 | [XmlElement("Switch", typeof(SwitchNode))] 32 | [XmlElement("While", typeof(WhileNode))] 33 | public BaseNode[]? Statements { get; init; } 34 | } 35 | -------------------------------------------------------------------------------- /tests/CsmlTests/Statements/SwitchTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Statements; 2 | 3 | public class SwitchTests 4 | { 5 | [Fact] 6 | public void SwitchTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | """; 22 | 23 | // Act 24 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 25 | 26 | // Assert 27 | if (!output.FirstDescendant(out SwitchStatementSyntax? switchStatement)) 28 | { 29 | Assert.Fail(); 30 | return; 31 | } 32 | 33 | if (switchStatement.Sections is not [SwitchSectionSyntax case1, SwitchSectionSyntax case2, SwitchSectionSyntax case3]) 34 | { 35 | Assert.Fail(); 36 | return; 37 | } 38 | 39 | Assert.True(switchStatement.Expression is IdentifierNameSyntax { Identifier.Value: "myNumber" }); 40 | 41 | Assert.True(case1.Labels is [CaseSwitchLabelSyntax { Value: LiteralExpressionSyntax { Token.Value: 1 } }]); 42 | Assert.True(case2.Labels is [CaseSwitchLabelSyntax { Value: LiteralExpressionSyntax { Token.Value: 2 } }]); 43 | Assert.True(case3.Labels is [DefaultSwitchLabelSyntax]); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /documentation/tags/field.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a field. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The type of the field. | 12 | | `Name` | `string` | *None* | Yes | The name of the field. | 13 | | `Value` | `string` | *None* | No | The initial value of the field. | 14 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the field. | 15 | | `Const` | `bool` | `false` | No | Marks the field as [`const`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const). | 16 | | `ReadOnly` | `bool` | `false` | No | Marks the field as [`readonly`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly). | 17 | | `Ref` | `bool` | `false` | No | Marks the field as [`ref`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/declarations#reference-variables). | 18 | | `Static` | `bool` | `false` | No | Marks the field as [`static`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/static). | 19 | 20 | ## Elements 21 | 22 | None. 23 | 24 | ## C# equivalent 25 | 26 | A field declaration. 27 | 28 | ## Example 29 | 30 | ### C♯ML 31 | 32 | ```xml 33 | 34 | 35 | 36 | ``` 37 | 38 | ### C# 39 | 40 | ```csharp 41 | class MyClass 42 | { 43 | int myField; 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/NamespaceBuilder.cs: -------------------------------------------------------------------------------- 1 | using Csml.Generator.SyntaxBuilders.Types; 2 | 3 | namespace Csml.Generator.SyntaxBuilders; 4 | 5 | internal static class NamespaceBuilder 6 | { 7 | public static SyntaxList BuildMultiple(NamespaceNode[]? nodes) 8 | { 9 | SyntaxList namespaceList = SF.List(); 10 | 11 | if (nodes != null) 12 | { 13 | foreach (NamespaceNode item in nodes) 14 | { 15 | namespaceList = namespaceList.Add(Build(item)); 16 | } 17 | } 18 | 19 | return namespaceList; 20 | } 21 | 22 | public static NamespaceDeclarationSyntax Build(NamespaceNode node) 23 | { 24 | NamespaceDeclarationSyntax syntax = SF.NamespaceDeclaration(SF.IdentifierName(node.Name)); 25 | SyntaxList list = SF.List(); 26 | 27 | SyntaxList usingList = UsingDirectiveBuilder.BuildMultiple(node.UsingDirectives); 28 | SyntaxList typeList = TypeBuilder.BuildMultiple(node.Types, node); 29 | SyntaxList enumList = EnumBuilder.BuildMultiple(node.Enums, node); 30 | 31 | SyntaxList namespaceList = BuildMultiple(node.Namespaces); 32 | list = list 33 | .AddRange(namespaceList) 34 | .AddRange(typeList) 35 | .AddRange(enumList); 36 | 37 | return syntax 38 | .WithUsings(usingList) 39 | .WithMembers(list); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/CsmlTests/Statements/ThrowTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Statements; 2 | 3 | public class ThrowTests 4 | { 5 | [Fact] 6 | public void Throw_NewException() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | """; 14 | 15 | // Act 16 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 17 | 18 | // Assert 19 | if (!output.FirstDescendant(out ThrowStatementSyntax? throwStatement)) 20 | { 21 | Assert.Fail(); 22 | return; 23 | } 24 | 25 | Assert.True(throwStatement.Expression is ObjectCreationExpressionSyntax); 26 | } 27 | 28 | [Fact] 29 | public void Throw_ExceptionVariable() 30 | { 31 | // Arrange 32 | string csml = """ 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | """; 42 | 43 | // Act 44 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 45 | 46 | // Assert 47 | if (!output.FirstDescendant(out ThrowStatementSyntax? throwStatement)) 48 | { 49 | Assert.Fail(); 50 | return; 51 | } 52 | 53 | Assert.True(throwStatement.Expression is IdentifierNameSyntax); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/CsmlTests/Statements/ForEachTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Statements; 2 | 3 | public class ForEachTests 4 | { 5 | [Fact] 6 | public void ForEachTest() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | """; 18 | 19 | // Act 20 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 21 | 22 | // Assert 23 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 24 | { 25 | Assert.Fail(); 26 | return; 27 | } 28 | 29 | if (methodDeclaration.GetChildNodes() is not [.., BlockSyntax blockSyntax]) 30 | { 31 | Assert.Fail(); 32 | return; 33 | } 34 | 35 | if (blockSyntax.GetChildNodes() is not [ForEachStatementSyntax forEachSyntax]) 36 | { 37 | Assert.Fail(); 38 | return; 39 | } 40 | 41 | Assert.True(forEachSyntax.Type is PredefinedTypeSyntax { Keyword.ValueText: "int" }); 42 | Assert.Equal("number", forEachSyntax.Identifier.ValueText); 43 | Assert.True(forEachSyntax.Expression is IdentifierNameSyntax { Identifier.ValueText: "numbers" }); 44 | Assert.True(forEachSyntax.Statement is BlockSyntax { Statements: [LocalDeclarationStatementSyntax] }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /documentation/tags/for.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a `for` statement. 6 | 7 | ## Attributes 8 | 9 | None. 10 | 11 | ## Elements 12 | 13 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 14 | |---|---|---|---|---|---| 15 | | `` | [``](./variable.md) | *None* | Yes | No | The variable declaration of the for-statements's iterator. | 16 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The condition of the for-statement. | 17 | | `` | [Expressions](../types/expressions.md) | *None* | Yes | No | The incrementor of the for-statement. | 18 | | `` | [``](./block.md) | *None* | Yes | No | The statements contained within the for-statement. | 19 | 20 | ## C# equivalent 21 | 22 | The `for` keyword. 23 | 24 | ## Example 25 | 26 | ### C♯ML 27 | 28 | ```xml 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ``` 55 | 56 | ### C# 57 | 58 | ```csharp 59 | for (int i = 0; i < 10; i++) 60 | { 61 | System.Console.WriteLine(i); 62 | } 63 | ``` 64 | -------------------------------------------------------------------------------- /tests/CsmlTests/Types/InheritanceTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Types; 2 | 3 | public class InheritanceTests 4 | { 5 | [Fact] 6 | public void Inheritance_HasNoInheritance_HasNoBaseList() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | """; 17 | 18 | // Act 19 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 20 | 21 | // Assert 22 | if (!output.FirstDescendant(out ClassDeclarationSyntax? classDeclaration)) 23 | { 24 | Assert.Fail(); 25 | return; 26 | } 27 | 28 | Assert.Null(classDeclaration.BaseList); 29 | } 30 | 31 | [Fact] 32 | public void Inheritance_HasInheritance_HasBaseList() 33 | { 34 | // Arrange 35 | string csml = """ 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | """; 44 | 45 | // Act 46 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 47 | 48 | // Assert 49 | if (!output.FirstDescendant(out ClassDeclarationSyntax? classDeclaration)) 50 | { 51 | Assert.Fail(); 52 | return; 53 | } 54 | 55 | Assert.True(classDeclaration.BaseList?.Types is [ 56 | SimpleBaseTypeSyntax { Type: IdentifierNameSyntax { Identifier.Text: "IDisposable" } } 57 | ]); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /documentation/tags/property.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a property. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Type` | `string` | *None* | Yes | The type of the property. | 12 | | `Name` | `string` | *None* | Yes | The name of the property. | 13 | | `Value` | `string` | *None* | No | The initial value of the property. | 14 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the property. | 15 | | `Getter` | [Property getter accessor](../types/property-getter-accessor.md) | *Context dependent* | No | The accessor for the property getter. | 16 | | `GetterAccess` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the getter. | 17 | | `Setter` | [Property setter accessor](../types/property-setter-accessor.md) | *Context dependent* | No | The accessor for the property setter. | 18 | | `SetterAccess` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the setter. | 19 | 20 | ## Elements 21 | 22 | None. 23 | 24 | ## C# equivalent 25 | 26 | A property declaration. 27 | 28 | ## Example 29 | 30 | ### C♯ML 31 | 32 | ```xml 33 | 34 | 35 | 36 | ``` 37 | 38 | ### C# 39 | 40 | ```csharp 41 | class MyClass 42 | { 43 | int MyProperty { get; set; } 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /src/Csml/Parser/ObjectValidator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace Csml.Parser; 6 | 7 | /// 8 | /// Contains logic for validating the state of objects. 9 | /// 10 | public static class ObjectValidator 11 | { 12 | /// 13 | /// Ensures that all reference type properties on marked as required have a non-null value. 14 | /// 15 | /// 16 | /// 17 | public static void Validate(object obj, List results) 18 | { 19 | Type type = obj.GetType(); 20 | if (obj is not BaseNode node) 21 | { 22 | return; 23 | } 24 | 25 | foreach (PropertyInfo property in type.GetProperties()) 26 | { 27 | object? propertyValue = property.GetValue(node); 28 | 29 | RequiredMemberAttribute? requiredAttribute = property.GetCustomAttribute(); 30 | if (requiredAttribute != null && property.PropertyType.IsClass && propertyValue == null) 31 | { 32 | results.Add(new CsmlParseError(CsmlDiagnostics.MissingRequiredProperty, node.LineNumber, property.Name)); 33 | } 34 | 35 | if (propertyValue != null) 36 | { 37 | if (propertyValue is IEnumerable enumerable) 38 | { 39 | foreach (object enumeratedValue in enumerable) 40 | { 41 | Validate(enumeratedValue, results); 42 | } 43 | } 44 | else 45 | { 46 | Validate(propertyValue, results); 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Csml/Parser/Nodes/Statements/ExpressionStatementNode.cs: -------------------------------------------------------------------------------- 1 | using Csml.Parser.Nodes.Expressions; 2 | 3 | namespace Csml.Parser.Nodes.Statements; 4 | 5 | public class ExpressionStatementNode : BaseNode 6 | { 7 | [XmlElement("Add", typeof(AddNode))] 8 | [XmlElement("And", typeof(AndNode))] 9 | [XmlElement("Assignment", typeof(AssignmentNode))] 10 | [XmlElement("Await", typeof(AwaitNode))] 11 | [XmlElement("BitwiseAnd", typeof(BitwiseAndNode))] 12 | [XmlElement("BitwiseNot", typeof(BitwiseNotNode))] 13 | [XmlElement("BitwiseOr", typeof(BitwiseOrNode))] 14 | [XmlElement("Call", typeof(CallNode))] 15 | [XmlElement("Decrement", typeof(DecrementNode))] 16 | [XmlElement("Divide", typeof(DivideNode))] 17 | [XmlElement("Equals", typeof(EqualsNode))] 18 | [XmlElement("GreaterThan", typeof(GreaterThanNode))] 19 | [XmlElement("GreaterThanOrEqual", typeof(GreaterThanOrEqualNode))] 20 | [XmlElement("Increment", typeof(IncrementNode))] 21 | [XmlElement("LeftShift", typeof(LeftShiftNode))] 22 | [XmlElement("LessThan", typeof(LessThanNode))] 23 | [XmlElement("LessThanOrEqual", typeof(LessThanOrEqualNode))] 24 | [XmlElement("Multiply", typeof(MultiplyNode))] 25 | [XmlElement("New", typeof(NewNode))] 26 | [XmlElement("Not", typeof(NotNode))] 27 | [XmlElement("NotEquals", typeof(NotEqualsNode))] 28 | [XmlElement("Or", typeof(OrNode))] 29 | [XmlElement("PrefixDecrement", typeof(PrefixDecrementNode))] 30 | [XmlElement("PrefixIncrement", typeof(PrefixIncrementNode))] 31 | [XmlElement("Remainder", typeof(RemainderNode))] 32 | [XmlElement("RightShift", typeof(RightShiftNode))] 33 | [XmlElement("Subtract", typeof(SubtractNode))] 34 | [XmlElement("UnsignedRightShift", typeof(UnsignedRightShiftNode))] 35 | [XmlElement("Value", typeof(ValueNode))] 36 | [XmlElement("Xor", typeof(XorNode))] 37 | public required ExpressionNode Expression { get; init; } 38 | } 39 | -------------------------------------------------------------------------------- /documentation/tags/class.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Declares a class. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the class. | 12 | | `Name` | `string` | *None* | Yes | The name of the class. | 13 | | `Static` | `bool` | `false` | No | Marks the class as static. | 14 | 15 | ## Elements 16 | 17 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 18 | |---|---|---|---|---|---| 19 | | `` | [``](../tags/class.md) | *None* | No | Yes | Nested class declarations. | 20 | | `` | [``](../tags/constructor.md) | *None* | No | Yes | Constructors. | 21 | | `` | [``](../tags/enum.md) | *None* | No | Yes | Nested enum declarations. | 22 | | `` | [``](../tags/field.md) | *None* | No | Yes | Field declarations. | 23 | | `` | [``](../tags/inheritance.md) | *None* | No | Yes | Class- and interface inheritence. | 24 | | `` | [``](../tags/interface.md) | *None* | No | Yes | Nested interface declarations. | 25 | | `` | [``](../tags/method.md) | *None* | No | Yes | Method declarations. | 26 | | `` | [``](../tags/property.md) | *None* | No | Yes | Property declarations. | 27 | | `` | [``](../tags/struct.md) | *None* | No | Yes | Nested struct declarations. | 28 | 29 | ## C# equivalent 30 | 31 | The `class` keyword and an associated class declaration. 32 | 33 | ## Example 34 | 35 | ### C♯ML 36 | 37 | ```xml 38 | 39 | 40 | ``` 41 | 42 | ### C# 43 | 44 | ```csharp 45 | public static class MyClass 46 | { 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Members/ParameterBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Members; 2 | 3 | internal static class ParameterBuilder 4 | { 5 | public static ParameterListSyntax BuildMultiple(ParameterNode[] parameters) 6 | { 7 | SeparatedSyntaxList parameterList = SF.SeparatedList(); 8 | 9 | foreach (ParameterNode parameter in parameters) 10 | { 11 | parameterList = parameterList.Add(BuildParameter(parameter)); 12 | } 13 | 14 | return SF.ParameterList(parameterList); 15 | } 16 | 17 | public static ParameterSyntax BuildParameter(ParameterNode parameterNode) 18 | { 19 | ParameterSyntax parameter = SF 20 | .Parameter(SF.Identifier(parameterNode.Name)) 21 | .WithType(SF.IdentifierName(parameterNode.Type)); 22 | 23 | if (parameterNode.Default != null && !string.IsNullOrWhiteSpace(parameterNode.Default)) 24 | { 25 | EqualsValueClauseSyntax defaultClause = SF.EqualsValueClause(SF.IdentifierName(parameterNode.Default)); 26 | parameter = parameter.WithDefault(defaultClause); 27 | } 28 | 29 | SyntaxKind[] accessModifiers = parameterNode.Modifier switch 30 | { 31 | ParameterModifier.Ref => [SyntaxKind.RefKeyword], 32 | ParameterModifier.Out => [SyntaxKind.OutKeyword], 33 | ParameterModifier.RefReadonly => [SyntaxKind.ReadOnlyKeyword, SyntaxKind.RefKeyword], 34 | ParameterModifier.In => [SyntaxKind.InKeyword], 35 | ParameterModifier.Params => [SyntaxKind.ParamsKeyword], 36 | _ => [], 37 | }; 38 | 39 | SyntaxTokenList modifierTokenList = SF.TokenList(); 40 | 41 | foreach (SyntaxKind accessModifier in accessModifiers) 42 | { 43 | modifierTokenList = modifierTokenList.Add(SF.Token(accessModifier)); 44 | } 45 | 46 | return parameter 47 | .WithModifiers(modifierTokenList); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Statements/TryBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Statements; 2 | 3 | internal static class TryBuilder 4 | { 5 | public static TryStatementSyntax Build(TryNode tryNode, IEnumerable chainedNodes) 6 | { 7 | BlockSyntax block = BlockBuilder.Build(tryNode.Statements.Statements); 8 | SyntaxList catchClauseList = SF.List(); 9 | FinallyClauseSyntax? finallyClause = null; 10 | 11 | foreach (BaseNode chainedNode in chainedNodes) 12 | { 13 | if (chainedNode is CatchNode catchNode) 14 | { 15 | catchClauseList = catchClauseList.Add(BuildCatchClause(catchNode)); 16 | } 17 | else if (chainedNode is FinallyNode finallyNode) 18 | { 19 | finallyClause = BuildFinallyClause(finallyNode); 20 | } 21 | } 22 | 23 | return SF.TryStatement(block, catchClauseList, finallyClause); 24 | } 25 | 26 | private static CatchClauseSyntax BuildCatchClause(CatchNode catchNode) 27 | { 28 | BlockSyntax block = BlockBuilder.Build(catchNode.Statements.Statements); 29 | CatchClauseSyntax catchClause = SF.CatchClause().WithBlock(block); 30 | 31 | if (catchNode.Type != null && !string.IsNullOrWhiteSpace(catchNode.Type)) 32 | { 33 | CatchDeclarationSyntax declaration = SF.CatchDeclaration(SF.IdentifierName(catchNode.Type)); 34 | 35 | if (catchNode.Name != null && !string.IsNullOrWhiteSpace(catchNode.Name)) 36 | { 37 | declaration = declaration.WithIdentifier(SF.Identifier(catchNode.Name)); 38 | } 39 | 40 | catchClause = catchClause.WithDeclaration(declaration); 41 | } 42 | 43 | return catchClause; 44 | } 45 | 46 | private static FinallyClauseSyntax BuildFinallyClause(FinallyNode finallyNode) 47 | { 48 | return SF.FinallyClause(BlockBuilder.Build(finallyNode.Statements.Statements)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /documentation/tags/method.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents an method declaration. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the constructor. | 12 | | `Static` | `bool` | `false` | No | Marks the constructor as static. | 13 | | `Name` | `string` | *None* | Yes | The name of the method. | 14 | | `Return` | `string` | *None* | Yes | The return type of the method. | 15 | | `Async` | `bool` | `false` | No | Marks the method as [`async`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async). | 16 | | `Abstract` | `bool` | `false` | No | Marks the method as [`abstract`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract). | 17 | | `Virtual` | `bool` | `false` | No | Marks the method as [`virtual`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual). | 18 | | `Override` | `bool` | `false` | No | Marks the method as [`override`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override). | 19 | 20 | ## Elements 21 | 22 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 23 | |---|---|---|---|---|---| 24 | | `` | [``](./block.md) | *None* | No | Yes | The parameters of the constructor. | 25 | | `` | [``](./block.md) | *None* | No | No | The statements contained within the constructor. | 26 | 27 | ## C# equivalent 28 | 29 | A method. 30 | 31 | ## Example 32 | 33 | ### C♯ML 34 | 35 | ```xml 36 | 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | 44 | ### C# 45 | 46 | ```csharp 47 | public int MyMethod(int number) 48 | { 49 | return i; 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /tests/CsmlTests/FileExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using Csml.Generator; 2 | 3 | namespace CsmlTests; 4 | 5 | public class FileExtensionTests 6 | { 7 | [Fact] 8 | public void PreferredFileExtension_CompileSucceedsWithoutDiagnostics() 9 | { 10 | // Arrange 11 | string csml = """ 12 | 13 | 14 | 15 | 16 | """; 17 | 18 | // Act 19 | SyntaxNode[] output = Compile(csml, out ImmutableArray diagnostics, "Test.c♯"); 20 | 21 | // Assert 22 | Assert.Empty(diagnostics); 23 | Assert.True(output is [NamespaceDeclarationSyntax]); 24 | } 25 | 26 | [Theory] 27 | [InlineData(".c#")] 28 | [InlineData(".csml")] 29 | public void NotPreferredFileExtension_CompileSucceedsWithDiagnostic(string fileExtension) 30 | { 31 | // Arrange 32 | string csml = """ 33 | 34 | 35 | 36 | 37 | """; 38 | 39 | // Act 40 | SyntaxNode[] output = Compile(csml, out ImmutableArray diagnostics, $"Test{fileExtension}"); 41 | 42 | // Assert 43 | Assert.True(diagnostics is [Diagnostic { Id: CsmlDiagnostics.NotPreferredFileExtensionId }]); 44 | Assert.True(output is [NamespaceDeclarationSyntax]); 45 | } 46 | 47 | [Theory] 48 | [InlineData(".cs")] 49 | [InlineData("")] 50 | public void UnexpectedFileExtension_CompileSkippedWithoutDiagnostic(string fileExtension) 51 | { 52 | // Arrange 53 | string csml = """ 54 | 55 | 56 | 57 | 58 | """; 59 | 60 | // Act 61 | SyntaxNode[] output = Compile(csml, out ImmutableArray diagnostics, $"Test{fileExtension}"); 62 | 63 | // Assert 64 | Assert.Empty(diagnostics); 65 | Assert.Empty(output); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /documentation/tags/struct.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Declares a struct. 6 | 7 | ## Attributes 8 | 9 | | Name | Type | Default | Mandatory | Description | 10 | |---|---|---|---|---| 11 | | `Access` | [Access modifiers](../types/access-modifiers.md) | *Context dependent* | No | The [access modifiers](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers) of the struct. | 12 | | `Name` | `string` | *None* | Yes | The name of the struct. | 13 | | `ReadOnly` | `bool` | `false` | No | Marks the struct as [`readonly`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#readonly-struct). | 14 | | `Ref` | `bool` | `false` | No | Marks the struct as [`ref`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/ref-struct). | 15 | 16 | ## Elements 17 | 18 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 19 | |---|---|---|---|---|---| 20 | | `` | [``](../tags/class.md) | *None* | No | Yes | Nested class declarations. | 21 | | `` | [``](../tags/constructor.md) | *None* | No | Yes | Constructors. | 22 | | `` | [``](../tags/enum.md) | *None* | No | Yes | Nested enum declarations. | 23 | | `` | [``](../tags/field.md) | *None* | No | Yes | Field declarations. | 24 | | `` | [``](../tags/inheritance.md) | *None* | No | Yes | Class- and interface inheritence. | 25 | | `` | [``](../tags/interface.md) | *None* | No | Yes | Nested interface declarations. | 26 | | `` | [``](../tags/method.md) | *None* | No | Yes | Method declarations. | 27 | | `` | [``](../tags/property.md) | *None* | No | Yes | Property declarations. | 28 | | `` | [``](../tags/struct.md) | *None* | No | Yes | Nested struct declarations. | 29 | 30 | ## C# equivalent 31 | 32 | The `struct` keyword and an associated struct declaration. 33 | 34 | ## Example 35 | 36 | ### C♯ML 37 | 38 | ```xml 39 | 40 | 41 | ``` 42 | 43 | ### C# 44 | 45 | ```csharp 46 | internal struct MyStruct 47 | { 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/InterfaceMethodTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class InterfaceMethodTests 4 | { 5 | [Fact] 6 | public void MethodOnInterface_NoDefaultImplementation_MethodHasNoBody() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | Assert.Null(methodDeclaration.Body); 31 | } 32 | 33 | [Fact] 34 | public void MethodOnInterface_HasDefaultImplementation_MethodHasBody() 35 | { 36 | // Arrange 37 | string csml = """ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | """; 54 | 55 | // Act 56 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 57 | 58 | // Assert 59 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 60 | { 61 | Assert.Fail(); 62 | return; 63 | } 64 | 65 | Assert.NotNull(methodDeclaration.Body); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /documentation/tags/block.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | ## Description 4 | 5 | Represents a block of statements. 6 | 7 | Note: `` tags will normally have a different name, e.g. `` in the case of [``](./if.md). 8 | 9 | ## Attributes 10 | 11 | None. 12 | 13 | ## Elements 14 | 15 | | Name | Type | Default | Mandatory | Multiple allowed | Description | 16 | |---|---|---|---|---|---| 17 | | `` | [``](./assignment.md) | *None* | No | Yes | | 18 | | `` | [``](./await.md) | *None* | No | Yes | | 19 | | `` | [``](./break.md) | *None* | No | Yes | | 20 | | `` | [``](./call.md) | *None* | No | Yes | | 21 | | `` | [``](./catch.md) | *None* | No | Yes | | 22 | | `` | [``](./continue.md) | *None* | No | Yes | | 23 | | `` | [``](./decrement.md) | *None* | No | Yes | | 24 | | `` | [``](./else.md) | *None* | No | Yes | | 25 | | `` | [``](./else-if.md) | *None* | No | Yes | | 26 | | `` | [``](./for.md) | *None* | No | Yes | | 27 | | `` | [``](./for-each.md) | *None* | No | Yes | | 28 | | `` | [``](./finally.md) | *None* | No | Yes | | 29 | | `` | [``](./if.md) | *None* | No | Yes | | 30 | | `` | [``](./increment.md) | *None* | No | Yes | | 31 | | `` | [``](./new.md) | *None* | No | Yes | | 32 | | `` | [``](./prefix-decrement.md) | *None* | No | Yes | | 33 | | `` | [``](./prefix-increment.md) | *None* | No | Yes | | 34 | | `` | [``](./return.md) | *None* | No | Yes | | 35 | | `` | [``](./throw.md) | *None* | No | Yes | | 36 | | `` | [``](./try.md) | *None* | No | Yes | | 37 | | `` | [``](./variable.md) | *None* | No | Yes | | 38 | | `` | [``](./switch.md) | *None* | No | Yes | | 39 | | `` | [``](./while.md) | *None* | No | Yes | | 40 | 41 | ## C# equivalent 42 | 43 | A block of statements. 44 | 45 | ## Example 46 | 47 | ### C♯ML 48 | 49 | ```xml 50 | 51 | 52 | 53 | 54 | ``` 55 | 56 | ### C# 57 | 58 | ```csharp 59 | MethodA(); 60 | MethodB(); 61 | ``` 62 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/Members/ConstructorBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Csml.Generator.SyntaxBuilders.Members; 2 | 3 | internal static class ConstructorBuilder 4 | { 5 | public static SyntaxList BuildMultiple(ConstructorNode[]? nodes, TypeNode parentType) 6 | { 7 | SyntaxList methodList = SF.List(); 8 | 9 | if (nodes != null) 10 | { 11 | foreach (ConstructorNode item in nodes) 12 | { 13 | methodList = methodList.Add(Build(item, parentType)); 14 | } 15 | } 16 | 17 | return methodList; 18 | } 19 | 20 | public static ConstructorDeclarationSyntax Build(ConstructorNode constructorNode, TypeNode parentType) 21 | { 22 | SyntaxKind[] accessModifiers = constructorNode.Access switch 23 | { 24 | AccessModifier.Public => [SyntaxKind.PublicKeyword], 25 | AccessModifier.Private => [SyntaxKind.PrivateKeyword], 26 | AccessModifier.Protected => [SyntaxKind.ProtectedKeyword], 27 | AccessModifier.Internal => [SyntaxKind.InternalKeyword], 28 | AccessModifier.ProtectedInternal => [SyntaxKind.ProtectedKeyword, SyntaxKind.InternalKeyword], 29 | AccessModifier.PrivateProtected => [SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword], 30 | AccessModifier.File => throw new InvalidAccessorException(constructorNode.LineNumber, constructorNode.Access, "constructor"), 31 | _ => [SyntaxKind.PrivateKeyword], 32 | }; 33 | 34 | SyntaxTokenList tokenList = SF.TokenList(); 35 | 36 | foreach (SyntaxKind accessModifier in accessModifiers) 37 | { 38 | tokenList = tokenList.Add(SF.Token(accessModifier)); 39 | } 40 | BlockSyntax block = BlockBuilder.Build(constructorNode.Statements?.Statements); 41 | 42 | ConstructorDeclarationSyntax constructorDeclaration = SF.ConstructorDeclaration(parentType.Name); 43 | 44 | if (constructorNode.Parameters != null) 45 | { 46 | constructorDeclaration = constructorDeclaration.WithParameterList( 47 | ParameterBuilder.BuildMultiple(constructorNode.Parameters)); 48 | } 49 | 50 | return constructorDeclaration 51 | .WithModifiers(tokenList) 52 | .WithBody(block); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/CsmlTests/Expressions/NewTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Expressions; 2 | 3 | public class NewTests 4 | { 5 | [Fact] 6 | public void New_WithoutArguments_HasNoArguments() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | """; 12 | 13 | // Act 14 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 15 | 16 | // Assert 17 | if (!output.FirstDescendant(out ObjectCreationExpressionSyntax? expression)) 18 | { 19 | Assert.Fail(); 20 | return; 21 | } 22 | 23 | Assert.True(expression.Type is IdentifierNameSyntax { Identifier.Value: "MyType" }); 24 | Assert.True(expression.ArgumentList is { Arguments: [] }); 25 | } 26 | 27 | [Fact] 28 | public void New_WithArgument_HasArgument() 29 | { 30 | // Arrange 31 | string csml = """ 32 | 33 | 34 | 35 | """; 36 | 37 | // Act 38 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 39 | 40 | // Assert 41 | if (!output.FirstDescendant(out ObjectCreationExpressionSyntax? expression)) 42 | { 43 | Assert.Fail(); 44 | return; 45 | } 46 | 47 | Assert.True(expression.Type is IdentifierNameSyntax { Identifier.Value: "MyType" }); 48 | Assert.True(expression.ArgumentList is { Arguments: [ArgumentSyntax] }); 49 | } 50 | 51 | [Fact] 52 | public void New_WithArguments_HasArguments() 53 | { 54 | // Arrange 55 | string csml = """ 56 | 57 | 58 | 59 | 60 | """; 61 | 62 | // Act 63 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 64 | 65 | // Assert 66 | if (!output.FirstDescendant(out ObjectCreationExpressionSyntax? expression)) 67 | { 68 | Assert.Fail(); 69 | return; 70 | } 71 | 72 | Assert.True(expression.Type is IdentifierNameSyntax { Identifier.Value: "MyType" }); 73 | Assert.True(expression.ArgumentList is { Arguments: [ArgumentSyntax, ArgumentSyntax] }); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Csml/Parser/CsmlParser.cs: -------------------------------------------------------------------------------- 1 | using System.Xml; 2 | using System.Xml.Linq; 3 | 4 | namespace Csml.Parser; 5 | 6 | /// 7 | /// Parser to read C♯ML as . 8 | /// 9 | internal static class CsmlParser 10 | { 11 | public static CsmlParseResult Parse(string xml) 12 | { 13 | List errors = []; 14 | 15 | Type baseNodeType = typeof(BaseNode); 16 | Type[] validNodes = baseNodeType.Assembly 17 | .GetTypes() 18 | .Where(x => !x.IsAbstract && x.IsSubclassOf(baseNodeType)) 19 | .ToArray(); 20 | 21 | XmlSerializer serializer = new XmlSerializer(typeof(CsmlNode), validNodes); 22 | serializer.UnknownElement += (s, e) => 23 | { 24 | errors.Add(new CsmlParseError(CsmlDiagnostics.UnexpectedElement, e.LineNumber, e.Element.Name)); 25 | }; 26 | 27 | serializer.UnknownAttribute += (s, e) => 28 | { 29 | errors.Add(new CsmlParseError(CsmlDiagnostics.UnexpectedAttribute, e.LineNumber, e.Attr.Name)); 30 | }; 31 | 32 | serializer.UnreferencedObject += (s, e) => 33 | { 34 | errors.Add(new CsmlParseError(CsmlDiagnostics.ParseError, null, $"Unreferenced object {e.UnreferencedObject}")); 35 | }; 36 | 37 | CsmlNode? parsedResult = null; 38 | try 39 | { 40 | XDocument xdoc = XDocument.Parse(xml, LoadOptions.SetLineInfo); 41 | foreach (XElement? element in xdoc.Descendants()) 42 | { 43 | IXmlLineInfo lineInfo = element; 44 | element.SetAttributeValue(CsmlConstants.LineNumberMetadataAttribute, lineInfo.LineNumber); 45 | } 46 | 47 | using XmlReader reader = xdoc.CreateReader(); 48 | parsedResult = serializer.Deserialize(reader) as CsmlNode; 49 | 50 | if (parsedResult != null) 51 | { 52 | ObjectValidator.Validate(parsedResult, errors); 53 | } 54 | } 55 | catch (XmlException xmlException) 56 | { 57 | errors.Add(new CsmlParseError(CsmlDiagnostics.XmlParseException, xmlException.LineNumber, xmlException.Message)); 58 | } 59 | catch (Exception exception) 60 | { 61 | errors.Add(new CsmlParseError(CsmlDiagnostics.UnexpectedParseException, null, exception.GetType().Name, exception.Message)); 62 | } 63 | 64 | return new CsmlParseResult(parsedResult, errors); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/CsmlTests/Types/StructRefTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Types; 2 | 3 | public class StructRefTests 4 | { 5 | [Fact] 6 | public void Ref_NotSpecified_IsNotConst() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | """; 17 | 18 | // Act 19 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 20 | 21 | // Assert 22 | if (!output.FirstDescendant(out StructDeclarationSyntax? structDeclaration)) 23 | { 24 | Assert.Fail(); 25 | return; 26 | } 27 | 28 | Assert.True(structDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.InternalKeyword }]); 29 | } 30 | 31 | [Fact] 32 | public void Ref_True_IsConst() 33 | { 34 | // Arrange 35 | string csml = """ 36 | 37 | 38 | 39 | 40 | 41 | 42 | """; 43 | 44 | // Act 45 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 46 | 47 | // Assert 48 | if (!output.FirstDescendant(out StructDeclarationSyntax? structDeclaration)) 49 | { 50 | Assert.Fail(); 51 | return; 52 | } 53 | 54 | Assert.True(structDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.InternalKeyword }, SyntaxToken { RawKind: (int)SyntaxKind.RefKeyword }]); 55 | } 56 | 57 | [Fact] 58 | public void Ref_False_IsNotConst() 59 | { 60 | // Arrange 61 | string csml = """ 62 | 63 | 64 | 65 | 66 | 67 | 68 | """; 69 | 70 | // Act 71 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 72 | 73 | // Assert 74 | if (!output.FirstDescendant(out StructDeclarationSyntax? structDeclaration)) 75 | { 76 | Assert.Fail(); 77 | return; 78 | } 79 | 80 | Assert.True(structDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.InternalKeyword }]); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/FieldRefTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class FieldRefTests 4 | { 5 | [Fact] 6 | public void Ref_NotSpecified_IsNotConst() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | """; 18 | 19 | // Act 20 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 21 | 22 | // Assert 23 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 24 | { 25 | Assert.Fail(); 26 | return; 27 | } 28 | 29 | Assert.IsNotType(fieldDeclaration.Declaration.Type); 30 | } 31 | 32 | [Fact] 33 | public void Ref_True_IsConst() 34 | { 35 | // Arrange 36 | string csml = """ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | """; 45 | 46 | // Act 47 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 48 | 49 | // Assert 50 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 51 | { 52 | Assert.Fail(); 53 | return; 54 | } 55 | 56 | Assert.IsType(fieldDeclaration.Declaration.Type); 57 | } 58 | 59 | [Fact] 60 | public void Ref_False_IsNotConst() 61 | { 62 | // Arrange 63 | string csml = """ 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | """; 72 | 73 | // Act 74 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 75 | 76 | // Assert 77 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 78 | { 79 | Assert.Fail(); 80 | return; 81 | } 82 | 83 | Assert.IsNotType(fieldDeclaration.Declaration.Type); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/CsmlTests/Types/StructReadOnlyTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Types; 2 | 3 | public class StructReadOnlyTests 4 | { 5 | [Fact] 6 | public void ReadOnly_NotSpecified_IsNotConst() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | """; 17 | 18 | // Act 19 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 20 | 21 | // Assert 22 | if (!output.FirstDescendant(out StructDeclarationSyntax? structDeclaration)) 23 | { 24 | Assert.Fail(); 25 | return; 26 | } 27 | 28 | Assert.True(structDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.InternalKeyword }]); 29 | } 30 | 31 | [Fact] 32 | public void ReadOnly_True_IsConst() 33 | { 34 | // Arrange 35 | string csml = """ 36 | 37 | 38 | 39 | 40 | 41 | 42 | """; 43 | 44 | // Act 45 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 46 | 47 | // Assert 48 | if (!output.FirstDescendant(out StructDeclarationSyntax? structDeclaration)) 49 | { 50 | Assert.Fail(); 51 | return; 52 | } 53 | 54 | Assert.True(structDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.InternalKeyword }, SyntaxToken { RawKind: (int)SyntaxKind.ReadOnlyKeyword }]); 55 | } 56 | 57 | [Fact] 58 | public void ReadOnly_False_IsNotConst() 59 | { 60 | // Arrange 61 | string csml = """ 62 | 63 | 64 | 65 | 66 | 67 | 68 | """; 69 | 70 | // Act 71 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 72 | 73 | // Assert 74 | if (!output.FirstDescendant(out StructDeclarationSyntax? structDeclaration)) 75 | { 76 | Assert.Fail(); 77 | return; 78 | } 79 | 80 | Assert.True(structDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.InternalKeyword }]); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/CsmlTests/NamespaceTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests; 2 | 3 | public class NamespaceTests 4 | { 5 | [Fact] 6 | public void Single_ExectedName() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | """; 14 | 15 | // Act 16 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 17 | 18 | // Assert 19 | if (output is not [NamespaceDeclarationSyntax namespaceDeclaration]) 20 | { 21 | Assert.Fail(); 22 | return; 23 | } 24 | 25 | Assert.Equal("MyNamespace", namespaceDeclaration.Name.ToString()); 26 | } 27 | 28 | [Fact] 29 | public void Multiple_ExectedNames() 30 | { 31 | // Arrange 32 | string csml = """ 33 | 34 | 35 | 36 | 37 | """; 38 | 39 | // Act 40 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 41 | 42 | // Assert 43 | if (output is not [NamespaceDeclarationSyntax namespaceDeclaration1, NamespaceDeclarationSyntax namespaceDeclaration2]) 44 | { 45 | Assert.Fail(); 46 | return; 47 | } 48 | 49 | Assert.Equal("MyNamespace1", namespaceDeclaration1.Name.ToString()); 50 | Assert.Equal("MyNamespace2", namespaceDeclaration2.Name.ToString()); 51 | } 52 | 53 | [Fact] 54 | public void Nested_ExectedNames() 55 | { 56 | // Arrange 57 | string csml = """ 58 | 59 | 60 | 61 | 62 | 63 | """; 64 | 65 | // Act 66 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 67 | 68 | // Assert 69 | if (output is not [NamespaceDeclarationSyntax namespaceDeclaration1]) 70 | { 71 | Assert.Fail(); 72 | return; 73 | } 74 | 75 | SyntaxNode[] nested = namespaceDeclaration1.GetChildNodes(); 76 | if (nested is not [IdentifierNameSyntax, NamespaceDeclarationSyntax namespaceDeclaration2]) 77 | { 78 | Assert.Fail(); 79 | return; 80 | } 81 | 82 | Assert.Equal("MyNamespace1", namespaceDeclaration1.Name.ToString()); 83 | Assert.Equal("MyNamespace2", namespaceDeclaration2.Name.ToString()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/FieldConstTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class FieldConstTests 4 | { 5 | [Fact] 6 | public void Const_NotSpecified_IsNotConst() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | """; 18 | 19 | // Act 20 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 21 | 22 | // Assert 23 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 24 | { 25 | Assert.Fail(); 26 | return; 27 | } 28 | 29 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }]); 30 | } 31 | 32 | [Fact] 33 | public void Const_True_IsConst() 34 | { 35 | // Arrange 36 | string csml = """ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | """; 45 | 46 | // Act 47 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 48 | 49 | // Assert 50 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 51 | { 52 | Assert.Fail(); 53 | return; 54 | } 55 | 56 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }, SyntaxToken { RawKind: (int)SyntaxKind.ConstKeyword }]); 57 | } 58 | 59 | [Fact] 60 | public void Const_False_IsNotConst() 61 | { 62 | // Arrange 63 | string csml = """ 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | """; 72 | 73 | // Act 74 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 75 | 76 | // Assert 77 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 78 | { 79 | Assert.Fail(); 80 | return; 81 | } 82 | 83 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }]); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/FieldStaticTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class FieldStaticTests 4 | { 5 | [Fact] 6 | public void Static_NotSpecified_IsNotConst() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | """; 18 | 19 | // Act 20 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 21 | 22 | // Assert 23 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 24 | { 25 | Assert.Fail(); 26 | return; 27 | } 28 | 29 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }]); 30 | } 31 | 32 | [Fact] 33 | public void Static_True_IsConst() 34 | { 35 | // Arrange 36 | string csml = """ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | """; 45 | 46 | // Act 47 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 48 | 49 | // Assert 50 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 51 | { 52 | Assert.Fail(); 53 | return; 54 | } 55 | 56 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }, SyntaxToken { RawKind: (int)SyntaxKind.StaticKeyword }]); 57 | } 58 | 59 | [Fact] 60 | public void Static_False_IsNotConst() 61 | { 62 | // Arrange 63 | string csml = """ 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | """; 72 | 73 | // Act 74 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 75 | 76 | // Assert 77 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 78 | { 79 | Assert.Fail(); 80 | return; 81 | } 82 | 83 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }]); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/FieldReadOnlyTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class FieldReadOnlyTests 4 | { 5 | [Fact] 6 | public void ReadOnly_NotSpecified_IsNotConst() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | """; 18 | 19 | // Act 20 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 21 | 22 | // Assert 23 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 24 | { 25 | Assert.Fail(); 26 | return; 27 | } 28 | 29 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }]); 30 | } 31 | 32 | [Fact] 33 | public void ReadOnly_True_IsConst() 34 | { 35 | // Arrange 36 | string csml = """ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | """; 45 | 46 | // Act 47 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 48 | 49 | // Assert 50 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 51 | { 52 | Assert.Fail(); 53 | return; 54 | } 55 | 56 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }, SyntaxToken { RawKind: (int)SyntaxKind.ReadOnlyKeyword }]); 57 | } 58 | 59 | [Fact] 60 | public void ReadOnly_False_IsNotConst() 61 | { 62 | // Arrange 63 | string csml = """ 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | """; 72 | 73 | // Act 74 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 75 | 76 | // Assert 77 | if (!output.FirstDescendant(out FieldDeclarationSyntax? fieldDeclaration)) 78 | { 79 | Assert.Fail(); 80 | return; 81 | } 82 | 83 | Assert.True(fieldDeclaration.Modifiers is [SyntaxToken { RawKind: (int)SyntaxKind.PrivateKeyword }]); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/MethodAsyncTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class MethodAsyncTests 4 | { 5 | [Fact] 6 | public void Async_Unspecified_IsNotAsync() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.AsyncKeyword)); 31 | } 32 | 33 | [Fact] 34 | public void Async_True_IsAsync() 35 | { 36 | // Arrange 37 | string csml = """ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | """; 47 | 48 | // Act 49 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 50 | 51 | // Assert 52 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 53 | { 54 | Assert.Fail(); 55 | return; 56 | } 57 | 58 | Assert.Contains(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.AsyncKeyword)); 59 | } 60 | 61 | [Fact] 62 | public void Async_False_IsNotAsync() 63 | { 64 | // Arrange 65 | string csml = """ 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | """; 75 | 76 | // Act 77 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 78 | 79 | // Assert 80 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 81 | { 82 | Assert.Fail(); 83 | return; 84 | } 85 | 86 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.AsyncKeyword)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/MethodStaticTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class MethodStaticTests 4 | { 5 | [Fact] 6 | public void Static_Unspecified_IsNotStatic() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.StaticKeyword)); 31 | } 32 | 33 | [Fact] 34 | public void Static_True_IsStatic() 35 | { 36 | // Arrange 37 | string csml = """ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | """; 47 | 48 | // Act 49 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 50 | 51 | // Assert 52 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 53 | { 54 | Assert.Fail(); 55 | return; 56 | } 57 | 58 | Assert.Contains(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.StaticKeyword)); 59 | } 60 | 61 | [Fact] 62 | public void Static_False_IsNotStatic() 63 | { 64 | // Arrange 65 | string csml = """ 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | """; 75 | 76 | // Act 77 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 78 | 79 | // Assert 80 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 81 | { 82 | Assert.Fail(); 83 | return; 84 | } 85 | 86 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.StaticKeyword)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/CsmlTests/Expressions/BinaryExpressionTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Expressions; 2 | 3 | public class BinaryExpressionTests 4 | { 5 | [Theory] 6 | [InlineData("Add", SyntaxKind.AddExpression)] 7 | [InlineData("Subtract", SyntaxKind.SubtractExpression)] 8 | [InlineData("Multiply", SyntaxKind.MultiplyExpression)] 9 | [InlineData("Divide", SyntaxKind.DivideExpression)] 10 | [InlineData("Remainder", SyntaxKind.ModuloExpression)] 11 | [InlineData("Equals", SyntaxKind.EqualsExpression)] 12 | [InlineData("NotEquals", SyntaxKind.NotEqualsExpression)] 13 | [InlineData("LessThan", SyntaxKind.LessThanExpression)] 14 | [InlineData("LessThanOrEqual", SyntaxKind.LessThanOrEqualExpression)] 15 | [InlineData("GreaterThan", SyntaxKind.GreaterThanExpression)] 16 | [InlineData("GreaterThanOrEqual", SyntaxKind.GreaterThanOrEqualExpression)] 17 | [InlineData("Or", SyntaxKind.LogicalOrExpression)] 18 | [InlineData("And", SyntaxKind.LogicalAndExpression)] 19 | [InlineData("BitwiseOr", SyntaxKind.BitwiseOrExpression)] 20 | [InlineData("BitwiseAnd", SyntaxKind.BitwiseAndExpression)] 21 | [InlineData("Xor", SyntaxKind.ExclusiveOrExpression)] 22 | [InlineData("LeftShift", SyntaxKind.LeftShiftExpression)] 23 | [InlineData("RightShift", SyntaxKind.RightShiftExpression)] 24 | [InlineData("UnsignedRightShift", SyntaxKind.UnsignedRightShiftExpression)] 25 | public void Tag_ExpectedSyntaxKind(string tag, SyntaxKind kind) 26 | { 27 | // Arrange 28 | string csml = $""" 29 | 30 | 31 | <{tag}> 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | """; 42 | 43 | // Act 44 | SyntaxNode[] output = AssertCompileNoDiagnostics(CsmlSyntaxWrapper.WrapInMethod(csml)); 45 | 46 | // Assert 47 | if (!output.FirstDescendant(out BinaryExpressionSyntax? expression)) 48 | { 49 | Assert.Fail(); 50 | return; 51 | } 52 | 53 | Assert.Equal(kind, expression.Kind()); 54 | Assert.True(expression.Left is LiteralExpressionSyntax 55 | { 56 | RawKind: (int)SyntaxKind.NumericLiteralExpression, 57 | Token.Value: 1 58 | }); 59 | Assert.True(expression.Right is LiteralExpressionSyntax 60 | { 61 | RawKind: (int)SyntaxKind.NumericLiteralExpression, 62 | Token.Value: 2 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/MethodVirtualTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class MethodVirtualTests 4 | { 5 | [Fact] 6 | public void Virtual_Unspecified_IsNotVirtual() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.VirtualKeyword)); 31 | } 32 | 33 | [Fact] 34 | public void Virtual_True_IsVirtual() 35 | { 36 | // Arrange 37 | string csml = """ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | """; 47 | 48 | // Act 49 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 50 | 51 | // Assert 52 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 53 | { 54 | Assert.Fail(); 55 | return; 56 | } 57 | 58 | Assert.Contains(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.VirtualKeyword)); 59 | } 60 | 61 | [Fact] 62 | public void Virtual_False_IsNotVirtual() 63 | { 64 | // Arrange 65 | string csml = """ 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | """; 75 | 76 | // Act 77 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 78 | 79 | // Assert 80 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 81 | { 82 | Assert.Fail(); 83 | return; 84 | } 85 | 86 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.VirtualKeyword)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/MethodAbstractTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class MethodAbstractTests 4 | { 5 | [Fact] 6 | public void Abstract_Unspecified_IsNotAbstract() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.AbstractKeyword)); 31 | } 32 | 33 | [Fact] 34 | public void Abstract_True_IsAbstract() 35 | { 36 | // Arrange 37 | string csml = """ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | """; 47 | 48 | // Act 49 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 50 | 51 | // Assert 52 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 53 | { 54 | Assert.Fail(); 55 | return; 56 | } 57 | 58 | Assert.Contains(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.AbstractKeyword)); 59 | } 60 | 61 | [Fact] 62 | public void Abstract_False_IsNotAbstract() 63 | { 64 | // Arrange 65 | string csml = """ 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | """; 75 | 76 | // Act 77 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 78 | 79 | // Assert 80 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 81 | { 82 | Assert.Fail(); 83 | return; 84 | } 85 | 86 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.AbstractKeyword)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/CsmlTests/Members/MethodOverrideTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests.Members; 2 | 3 | public class MethodOverrideTests 4 | { 5 | [Fact] 6 | public void Override_Unspecified_IsNotOverride() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | """; 19 | 20 | // Act 21 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 22 | 23 | // Assert 24 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 25 | { 26 | Assert.Fail(); 27 | return; 28 | } 29 | 30 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.OverrideKeyword)); 31 | } 32 | 33 | [Fact] 34 | public void Override_True_IsOverride() 35 | { 36 | // Arrange 37 | string csml = """ 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | """; 47 | 48 | // Act 49 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 50 | 51 | // Assert 52 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 53 | { 54 | Assert.Fail(); 55 | return; 56 | } 57 | 58 | Assert.Contains(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.OverrideKeyword)); 59 | } 60 | 61 | [Fact] 62 | public void Override_False_IsNotOverride() 63 | { 64 | // Arrange 65 | string csml = """ 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | """; 75 | 76 | // Act 77 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 78 | 79 | // Assert 80 | if (!output.FirstDescendant(out MethodDeclarationSyntax? methodDeclaration)) 81 | { 82 | Assert.Fail(); 83 | return; 84 | } 85 | 86 | Assert.DoesNotContain(methodDeclaration.Modifiers, x => x.IsKind(SyntaxKind.OverrideKeyword)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/CsmlTests/UsingDirectiveTests.cs: -------------------------------------------------------------------------------- 1 | namespace CsmlTests; 2 | 3 | public class UsingDirectiveTests 4 | { 5 | [Fact] 6 | public void Single_ExectedName() 7 | { 8 | // Arrange 9 | string csml = """ 10 | 11 | 12 | 13 | 14 | """; 15 | 16 | // Act 17 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 18 | 19 | // Assert 20 | if (output is not [UsingDirectiveSyntax usingDirective, NamespaceDeclarationSyntax]) 21 | { 22 | Assert.Fail(); 23 | return; 24 | } 25 | 26 | Assert.Equal("System", usingDirective.Name?.ToString()); 27 | } 28 | 29 | [Fact] 30 | public void Multiple_ExectedNames() 31 | { 32 | // Arrange 33 | string csml = """ 34 | 35 | 36 | 37 | 38 | 39 | """; 40 | 41 | // Act 42 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 43 | 44 | // Assert 45 | if (output is not [UsingDirectiveSyntax usingDirective1, UsingDirectiveSyntax usingDirective2, NamespaceDeclarationSyntax]) 46 | { 47 | Assert.Fail(); 48 | return; 49 | } 50 | 51 | Assert.Equal("System", usingDirective1.Name?.ToString()); 52 | Assert.Equal("System.Text", usingDirective2.Name?.ToString()); 53 | } 54 | [Fact] 55 | public void InsideNamespace_ExectedNames() 56 | { 57 | // Arrange 58 | string csml = """ 59 | 60 | 61 | 62 | 63 | 64 | 65 | """; 66 | 67 | // Act 68 | SyntaxNode[] output = AssertCompileNoDiagnostics(csml); 69 | 70 | // Assert 71 | if (output is not [UsingDirectiveSyntax usingDirective1, NamespaceDeclarationSyntax namespaceDeclaration]) 72 | { 73 | Assert.Fail(); 74 | return; 75 | } 76 | 77 | SyntaxNode[] nested = namespaceDeclaration.GetChildNodes(); 78 | if (nested is not [IdentifierNameSyntax, UsingDirectiveSyntax usingDirective2]) 79 | { 80 | Assert.Fail(); 81 | return; 82 | } 83 | 84 | Assert.Equal("System", usingDirective1.Name?.ToString()); 85 | Assert.Equal("System.Text", usingDirective2.Name?.ToString()); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/CsmlTests/Helpers/CompilationHelper.cs: -------------------------------------------------------------------------------- 1 | using Csml.Generator; 2 | using Microsoft.CodeAnalysis.Text; 3 | using System.Reflection; 4 | 5 | namespace CsmlTests.Helpers; 6 | 7 | internal static class CompilationHelper 8 | { 9 | /// 10 | /// Compiles , and asserts that no diagnostics were emitted. 11 | /// 12 | /// 13 | /// 14 | public static SyntaxNode[] AssertCompileNoDiagnostics(string csml) 15 | { 16 | SyntaxNode[] output = Compile(csml, out ImmutableArray diagnostics, null); 17 | Assert.Empty(diagnostics); 18 | return output; 19 | } 20 | 21 | /// 22 | /// Compiles , returning the compiled result and any potential . 23 | /// 24 | /// 25 | /// 26 | /// 27 | /// 28 | public static SyntaxNode[] Compile( 29 | string csml, 30 | out ImmutableArray diagnostics, 31 | string? fileName = null) 32 | { 33 | Compilation compilationInput = CSharpCompilation.Create(null, 34 | [], 35 | [MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location)], 36 | new CSharpCompilationOptions(OutputKind.ConsoleApplication)); 37 | 38 | FakeAdditionalText fake = new FakeAdditionalText(csml, fileName); 39 | CsmlGenerator generator = new CsmlGenerator(); 40 | 41 | GeneratorDriver driver = CSharpGeneratorDriver 42 | .Create(generator) 43 | .AddAdditionalTexts([fake]); 44 | 45 | driver.RunGeneratorsAndUpdateCompilation( 46 | compilationInput, 47 | out Compilation compilationOutput, 48 | out diagnostics); 49 | 50 | if (compilationOutput.SyntaxTrees.FirstOrDefault()?.GetRoot() is CompilationUnitSyntax unit) 51 | { 52 | return unit.GetChildNodes(); 53 | } 54 | 55 | return []; 56 | } 57 | 58 | /// 59 | /// Fake for an . 60 | /// 61 | private class FakeAdditionalText : AdditionalText 62 | { 63 | private readonly string _text; 64 | private readonly string _path; 65 | 66 | public override string Path => _path; 67 | 68 | public FakeAdditionalText(string text, string? fileName = null) 69 | { 70 | _text = text; 71 | _path = fileName ?? $"SourceFile.c♯"; 72 | } 73 | 74 | public override SourceText? GetText(CancellationToken cancellationToken = default) 75 | { 76 | return SourceText.From(_text); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Csml/Generator/SyntaxBuilders/BlockBuilder.cs: -------------------------------------------------------------------------------- 1 | using Csml.Generator.SyntaxBuilders.Statements; 2 | using Csml.Parser.Nodes.Expressions; 3 | 4 | namespace Csml.Generator.SyntaxBuilders; 5 | 6 | internal class BlockBuilder 7 | { 8 | public static BlockSyntax Build(BaseNode[]? nodes) 9 | { 10 | BlockSyntax block = SF.Block(); 11 | 12 | if (nodes == null) 13 | { 14 | return block; 15 | } 16 | 17 | if (nodes?.Length > 0) 18 | { 19 | for (int i = 0; i < nodes.Length; i++) 20 | { 21 | BaseNode statementNode = nodes[i]; 22 | BaseNode[] chainedNodes = []; 23 | 24 | if (statementNode is IfNode) 25 | { 26 | chainedNodes = nodes 27 | .Skip(i + 1) 28 | .TakeWhile(x => x is ElseIfNode or ElseNode) 29 | .ToArray(); 30 | 31 | i += chainedNodes.Length; 32 | } 33 | else if (statementNode is TryNode) 34 | { 35 | chainedNodes = nodes 36 | .Skip(i + 1) 37 | .TakeWhile(x => x is CatchNode or FinallyNode) 38 | .ToArray(); 39 | 40 | i += chainedNodes.Length; 41 | } 42 | 43 | StatementSyntax statementSyntax = statementNode switch 44 | { 45 | ReturnNode returnNode => ReturnBuilder.Build(returnNode), 46 | VariableNode variableNode => VariableBuilder.Build(variableNode), 47 | CallNode callNode => CallBuilder.Build(callNode), 48 | BreakNode breakNode => BreakBuilder.Build(), 49 | ContinueNode continueNode => ContinueBuilder.Build(), 50 | IfNode ifNode => IfBuilder.Build(ifNode, chainedNodes), 51 | ForNode forNode => ForBuilder.Build(forNode), 52 | ForEachNode forEachNode => ForEachBuilder.Build(forEachNode), 53 | ExpressionNode expressionNode => SF.ExpressionStatement(ExpressionBuilder.Build(expressionNode)), 54 | ThrowNode throwNode => ThrowBuilder.Build(throwNode), 55 | TryNode tryNode => TryBuilder.Build(tryNode, chainedNodes), 56 | SwitchNode switchNode => SwitchBuilder.Build(switchNode), 57 | WhileNode whileNode => WhileBuilder.Build(whileNode), 58 | _ => throw new UnknownCsmlElementException( 59 | statementNode.LineNumber, 60 | statementNode.GetType().Name) 61 | }; 62 | 63 | block = block.AddStatements(statementSyntax); 64 | } 65 | } 66 | 67 | return block; 68 | } 69 | } 70 | --------------------------------------------------------------------------------