From f3adfaebe4e9085e6433ad3ff4543888651d82bf Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 1 Nov 2025 10:26:20 +0100 Subject: [PATCH 01/53] Apply core JASS library rewrite from vjass branch This commit brings in the complete Roslyn-style syntax tree architecture for JASS from the vjass branch. This is a major architectural upgrade that provides: - Immutable syntax trees with full trivia support (whitespace, comments) - Strongly-typed syntax kinds (447+ JassSyntaxKind values) - Complete tree navigation (GetChild*/GetDescendant* methods) - Code formatting via NormalizeWhitespace() - Fluent builder API for programmatic code generation - Enhanced parser with better error handling - Performance optimizations Key changes: - New base classes: JassSyntaxNode, JassSyntaxToken, JassSyntaxTrivia - Parser refactored from Parser/ to JassParser/ directory - Converted from interfaces (IExpressionSyntax, etc.) to base classes - Added normalizer system for code formatting - Added syntax rewriter for code transformations - Updated all renderers and renamers Note: This introduces build errors due to missing War3Net.CodeAnalysis changes that will be applied in the next commit. --- .../Builders/JassCompilationUnitBuilder.cs | 96 +++ .../JassFunctionDeclarationBuilder.cs | 32 + .../Builders/JassGlobalsDeclarationBuilder.cs | 43 ++ .../Builders/JassIfStatementBuilder.cs | 92 +++ .../Builders/JassLoopStatementBuilder.cs | 34 ++ .../JassStatementListSyntaxBuilder.cs | 99 ++++ .../Builders/JassSyntaxBuilder.cs | 51 ++ .../BinaryOperatorTypeExtensions.cs | 37 -- .../Extensions/ExpressionSyntaxExtensions.cs | 106 ---- .../Extensions/ImmutableArrayExtensions.cs | 80 +++ .../JassCompilationUnitSyntaxExtensions.cs} | 10 +- .../JassExpressionSyntaxExtensions.cs | 209 +++++++ ...istOrEmptyParameterListSyntaxExtensions.cs | 33 ++ ...ensions.cs => JassSyntaxNodeExtensions.cs} | 10 +- .../Extensions/JassSyntaxTokenExtensions.cs | 164 +++++ .../Extensions/JassTypeSyntaxExtensions.cs | 32 + ...riableOrArrayDeclaratorSyntaxExtensions.cs | 48 ++ .../Extensions/ObjectExtensions.cs | 37 ++ .../Extensions/ParserExtensions.cs | 48 +- .../SeparatedSyntaxListExtensions.cs | 120 ++++ .../Extensions/SyntaxNodeExtensions.cs | 193 ++++++ .../Extensions/TypeExtensions.cs | 32 +- .../Extensions/UnaryOperatorTypeExtensions.cs | 28 - src/War3Net.CodeAnalysis.Jass/JassParser.cs | 273 ++++----- .../JassParser/ArgumentListParser.cs | 33 ++ .../JassParser/BinaryOperatorParser.cs | 109 ++++ .../JassParser/CallStatementParser.cs | 36 ++ .../CharacterLiteralExpressionParser.cs | 17 +- .../JassParser/CompilationUnitParser.cs | 35 ++ .../JassParser/DebugStatementParser.cs | 40 ++ .../DecimalLiteralExpressionParser.cs | 10 +- .../JassParser/ElementAccessClauseParser.cs | 33 ++ .../ElseIfClauseDeclaratorParser.cs | 34 ++ .../JassParser/EqualsValueClauseParser.cs | 31 + .../JassParser/ExitStatementParser.cs | 33 ++ .../JassParser/ExpressionParser.cs | 68 +++ .../FourCCLiteralExpressionParser.cs | 11 +- .../JassParser/FunctionDeclarationParser.cs | 37 ++ .../JassParser/FunctionDeclaratorParser.cs | 42 ++ .../GlobalConstantDeclarationParser.cs | 39 ++ .../JassParser/GlobalDeclarationParser.cs | 27 + .../GlobalVariableDeclarationParser.cs | 29 + .../JassParser/GlobalsDeclarationParser.cs | 35 ++ .../HexadecimalLiteralExpressionParser.cs | 29 + .../IdentifierNameParser.cs | 17 +- .../JassParser/IfClauseDeclaratorParser.cs | 34 ++ .../JassParser/IfStatementParser.cs | 45 ++ ...LocalVariableDeclarationStatementParser.cs | 33 ++ .../JassParser/LoopStatementParser.cs | 35 ++ .../NativeFunctionDeclarationParser.cs | 42 ++ .../OctalLiteralExpressionParser.cs | 10 +- .../JassParser/ParameterListParser.cs | 41 ++ .../{Parser => JassParser}/ParameterParser.cs | 9 +- .../ParenthesizedExpressionParser.cs | 33 ++ .../JassParser/RealLiteralExpressionParser.cs | 32 + .../JassParser/ReturnClauseParser.cs | 31 + .../JassParser/ReturnStatementParser.cs | 33 ++ .../JassParser/SetStatementParser.cs | 39 ++ .../JassParser/StatementParser.cs | 54 ++ .../StringLiteralExpressionParser.cs | 17 +- .../JassParser/SyntaxTriviaListParser.cs | 63 ++ .../JassParser/SyntaxTriviaParser.cs | 50 ++ .../JassParser/TopLevelDeclarationParser.cs | 41 ++ .../JassParser/TypeDeclarationParser.cs | 38 ++ .../JassParser/TypeParser.cs | 51 ++ .../JassParser/UnaryOperatorParser.cs | 46 ++ .../VariableOrArrayDeclaratorParser.cs | 47 ++ src/War3Net.CodeAnalysis.Jass/JassRenamer.cs | 10 +- src/War3Net.CodeAnalysis.Jass/JassRenderer.cs | 16 +- src/War3Net.CodeAnalysis.Jass/JassSymbol.cs | 69 ++- .../JassSyntaxFactory.cs | 122 ++-- .../JassSyntaxFacts.cs | 18 +- .../JassSyntaxKind.cs | 447 ++++++++++++++ .../JassSyntaxKindFacts.cs | 340 +++++++++++ .../JassSyntaxNormalizer.cs | 52 ++ .../Normalizer/ArgumentListNormalizer.cs | 24 + .../Normalizer/ArrayDeclaratorNormalizer.cs | 24 + .../Normalizer/BinaryExpressionNormalizer.cs | 24 + .../Normalizer/CallStatementNormalizer.cs | 26 + .../Normalizer/CompilationUnitNormalizer.cs | 30 + .../Normalizer/DebugStatementNormalizer.cs | 24 + .../ElementAccessClauseNormalizer.cs | 32 + .../ElementAccessExpressionNormalizer.cs | 24 + .../Normalizer/ElseClauseNormalizer.cs | 32 + .../ElseIfClauseDeclaratorNormalizer.cs | 24 + .../Normalizer/ElseIfClauseNormalizer.cs | 24 + .../EmptyParameterListNormalizer.cs | 24 + .../Normalizer/EqualsValueClauseNormalizer.cs | 32 + .../Normalizer/ExitStatementNormalizer.cs | 26 + .../FunctionDeclarationNormalizer.cs | 24 + .../FunctionDeclaratorNormalizer.cs | 27 + .../FunctionReferenceExpressionNormalizer.cs | 24 + .../GlobalConstantDeclarationNormalizer.cs | 26 + .../GlobalVariableDeclarationNormalizer.cs | 26 + .../GlobalsDeclarationNormalizer.cs | 24 + .../Normalizer/IdentifierNameNormalizer.cs | 44 ++ .../IfClauseDeclaratorNormalizer.cs | 24 + .../Normalizer/IfClauseNormalizer.cs | 24 + .../Normalizer/IfStatementNormalizer.cs | 24 + .../InvocationExpressionNormalizer.cs | 24 + .../Normalizer/LiteralExpressionNormalizer.cs | 24 + ...lVariableDeclarationStatementNormalizer.cs | 26 + .../Normalizer/LoopStatementNormalizer.cs | 24 + .../NativeFunctionDeclarationNormalizer.cs | 26 + .../Normalizer/ParameterListNormalizer.cs | 24 + .../Normalizer/ParameterNormalizer.cs | 24 + .../ParenthesizedExpressionNormalizer.cs | 24 + .../Normalizer/PredefinedTypeNormalizer.cs | 24 + .../Normalizer/ReturnClauseNormalizer.cs | 24 + .../Normalizer/ReturnStatementNormalizer.cs | 26 + .../Normalizer/SetStatementNormalizer.cs | 26 + .../Normalizer/SyntaxTokenNormalizer.cs | 116 ++++ .../Normalizer/SyntaxTriviaListNormalizer.cs | 202 +++++++ .../Normalizer/TypeDeclarationNormalizer.cs | 26 + .../Normalizer/UnaryExpressionNormalizer.cs | 24 + .../VariableDeclaratorNormalizer.cs | 24 + .../Parser/ArgumentListParser.cs | 26 - .../Parser/ArrayReferenceExpressionParser.cs | 28 - .../Parser/BinaryOperatorParser.cs | 95 --- .../Parser/BooleanLiteralExpressionParser.cs | 22 - .../Parser/CallStatementParser.cs | 26 - .../Parser/CommentParser.cs | 28 - .../Parser/CompilationUnitParser.cs | 30 - .../Parser/ConstantDeclarationParser.cs | 31 - .../Parser/DebugCustomScriptActionParser.cs | 34 -- .../Parser/DebugStatementParser.cs | 35 -- .../Parser/DeclarationLineParser.cs | 35 -- .../Parser/DeclarationParser.cs | 37 -- .../Parser/ElseClauseParser.cs | 26 - .../Parser/ElseCustomScriptActionParser.cs | 21 - .../Parser/ElseIfClauseParser.cs | 30 - .../Parser/ElseIfCustomScriptActionParser.cs | 24 - .../Parser/EmptyParser.cs | 29 - .../EndFunctionCustomScriptActionParser.cs | 21 - .../EndGlobalsCustomScriptActionParser.cs | 21 - .../Parser/EndIfCustomScriptActionParser.cs | 21 - .../Parser/EndLoopCustomScriptActionParser.cs | 21 - .../Parser/EndOfLineParser.cs | 21 - .../Parser/EqualsValueClauseParser.cs | 24 - .../Parser/ExitStatementParser.cs | 24 - .../Parser/ExpressionParser.cs | 62 -- .../FunctionCustomScriptActionParser.cs | 24 - .../Parser/FunctionDeclarationParser.cs | 30 - .../Parser/FunctionDeclaratorParser.cs | 31 - .../FunctionReferenceExpressionParser.cs | 25 - .../Parser/GlobalDeclarationListParser.cs | 27 - .../Parser/GlobalDeclarationParser.cs | 31 - .../Parser/GlobalLineParser.cs | 33 -- .../Parser/GlobalsCustomScriptActionParser.cs | 21 - .../HexadecimalLiteralExpressionParser.cs | 25 - .../Parser/IfCustomScriptActionParser.cs | 24 - .../Parser/IfStatementParser.cs | 35 -- .../Parser/InvocationExpressionParser.cs | 27 - ...LocalVariableDeclarationStatementParser.cs | 24 - .../Parser/LoopCustomScriptActionParser.cs | 21 - .../Parser/LoopStatementParser.cs | 26 - .../Parser/NativeFunctionDeclarationParser.cs | 26 - .../Parser/NewLineParser.cs | 23 - .../Parser/NullLiteralExpressionParser.cs | 22 - .../Parser/ParameterListParser.cs | 26 - .../Parser/ParenthesizedExpressionParser.cs | 25 - .../Parser/RealLiteralExpressionParser.cs | 36 -- .../Parser/ReturnStatementParser.cs | 24 - .../Parser/SetStatementParser.cs | 31 - .../Parser/StatementLineParser.cs | 52 -- .../Parser/StatementListParser.cs | 26 - .../Parser/StatementParser.cs | 54 -- .../Parser/TypeDeclarationParser.cs | 26 - .../Parser/TypeParser.cs | 33 -- .../Parser/UnaryOperatorParser.cs | 41 -- .../Parser/VariableDeclarationParser.cs | 28 - .../Parser/VariableDeclaratorParser.cs | 36 -- .../VariableReferenceExpressionParser.cs | 23 - .../Parser/WhitespaceParser.cs | 21 - .../Parsers/IdentifierExpressionParser.cs | 147 +++++ .../Renamer/ArgumentListRenamer.cs | 54 +- .../Renamer/ArrayDeclaratorRenamer.cs | 3 +- .../ArrayReferenceExpressionRenamer.cs | 32 - .../Renamer/BinaryExpressionRenamer.cs | 4 +- .../Renamer/CallStatementRenamer.cs | 23 +- .../Renamer/CompilationUnitRenamer.cs | 44 +- .../Renamer/DebugStatementRenamer.cs | 7 +- .../Renamer/DeclarationRenamer.cs | 4 +- .../Renamer/ElementAccessClauseRenamer.cs | 33 ++ .../Renamer/ElementAccessExpressionRenamer.cs | 32 + .../Renamer/ElseClauseRenamer.cs | 7 +- .../Renamer/ElseIfClauseDeclaratorRenamer.cs | 32 + .../Renamer/ElseIfClauseListRenamer.cs | 52 ++ .../Renamer/ElseIfClauseRenamer.cs | 8 +- .../Renamer/EqualsValueClauseRenamer.cs | 5 +- .../Renamer/ExitStatementRenamer.cs | 7 +- .../Renamer/ExpressionRenamer.cs | 6 +- .../Renamer/FunctionDeclarationRenamer.cs | 12 +- .../Renamer/FunctionDeclaratorRenamer.cs | 4 +- .../FunctionReferenceExpressionRenamer.cs | 7 +- .../GlobalConstantDeclarationRenamer.cs | 34 ++ .../Renamer/GlobalDeclarationListRenamer.cs | 45 -- .../Renamer/GlobalDeclarationRenamer.cs | 21 +- .../GlobalVariableDeclarationRenamer.cs | 28 + .../Renamer/GlobalsDeclarationRenamer.cs | 56 ++ .../Renamer/IdentifierNameRenamer.cs | 30 +- .../Renamer/IfClauseDeclaratorRenamer.cs | 32 + .../Renamer/IfClauseRenamer.cs | 32 + .../Renamer/IfStatementRenamer.cs | 32 +- .../Renamer/InvocationExpressionRenamer.cs | 6 +- ...ocalVariableDeclarationStatementRenamer.cs | 12 +- .../Renamer/LoopStatementRenamer.cs | 10 +- .../NativeFunctionDeclarationRenamer.cs | 12 +- .../Renamer/ParenthesizedExpressionRenamer.cs | 8 +- .../Renamer/ReturnStatementRenamer.cs | 7 +- .../Renamer/SetStatementRenamer.cs | 7 +- .../Renamer/StatementListRenamer.cs | 45 +- .../Renamer/StatementRenamer.cs | 2 +- .../Renamer/SyntaxTokenRenamer.cs | 56 ++ .../Renamer/UnaryExpressionRenamer.cs | 4 +- .../Renamer/VariableDeclaratorRenamer.cs | 13 +- .../VariableOrArrayDeclaratorRenamer.cs | 27 + .../VariableReferenceExpressionRenamer.cs | 28 - .../Renderer/ArgumentListRenderer.cs | 17 +- .../Renderer/ArrayDeclaratorRenderer.cs | 4 +- .../ArrayReferenceExpressionRenderer.cs | 22 - .../Renderer/BinaryExpressionRenderer.cs | 5 +- .../Renderer/CallStatementRenderer.cs | 7 +- .../Renderer/CompilationUnitRenderer.cs | 3 +- .../Renderer/DebugStatementRenderer.cs | 3 +- .../DecimalLiteralExpressionRenderer.cs | 19 - .../Renderer/DeclarationLineRenderer.cs | 31 - .../Renderer/ElementAccessClauseRenderer.cs | 21 + ....cs => ElementAccessExpressionRenderer.cs} | 8 +- .../Renderer/ElseClauseRenderer.cs | 4 +- ...r.cs => ElseIfClauseDeclaratorRenderer.cs} | 11 +- .../Renderer/ElseIfClauseRenderer.cs | 6 +- .../ElseIfCustomScriptActionRenderer.cs | 23 - .../Renderer/EmptyParameterListRenderer.cs | 21 + .../EndFunctionCustomScriptActionRenderer.cs | 20 - .../EndGlobalsCustomScriptActionRenderer.cs | 20 - .../Renderer/EqualsValueClauseRenderer.cs | 3 +- .../Renderer/ExitStatementRenderer.cs | 3 +- .../Renderer/ExpressionRenderer.cs | 16 +- .../FourCCLiteralExpressionRenderer.cs | 19 - .../FunctionCustomScriptActionRenderer.cs | 21 - .../Renderer/FunctionDeclarationRenderer.cs | 6 +- .../Renderer/FunctionDeclaratorRenderer.cs | 14 +- .../FunctionReferenceExpressionRenderer.cs | 3 +- .../GlobalConstantDeclarationRenderer.cs | 25 + .../Renderer/GlobalDeclarationRenderer.cs | 12 +- ...s => GlobalVariableDeclarationRenderer.cs} | 7 +- .../GlobalsCustomScriptActionRenderer.cs | 20 - ...derer.cs => GlobalsDeclarationRenderer.cs} | 11 +- .../HexadecimalLiteralExpressionRenderer.cs | 19 - .../Renderer/IdentifierNameRenderer.cs | 2 +- .../Renderer/IfClauseDeclaratorRenderer.cs | 23 + ...tActionRenderer.cs => IfClauseRenderer.cs} | 9 +- .../Renderer/IfCustomScriptActionRenderer.cs | 22 - .../Renderer/IfStatementRenderer.cs | 9 +- .../Renderer/InvocationExpressionRenderer.cs | 4 +- ...nderer.cs => LiteralExpressionRenderer.cs} | 5 +- ...calVariableDeclarationStatementRenderer.cs | 3 +- .../Renderer/LoopStatementRenderer.cs | 6 +- .../NativeFunctionDeclarationRenderer.cs | 15 +- .../Renderer/NullLiteralExpressionRenderer.cs | 19 - .../OctalLiteralExpressionRenderer.cs | 19 - ...ameterListOrEmptyParameterListRenderer.cs} | 12 +- .../Renderer/ParameterListRenderer.cs | 21 +- .../Renderer/ParameterRenderer.cs | 2 +- .../ParenthesizedExpressionRenderer.cs | 4 +- ...tRenderer.cs => PredefinedTypeRenderer.cs} | 6 +- .../Renderer/RealLiteralExpressionRenderer.cs | 19 - ...ionRenderer.cs => ReturnClauseRenderer.cs} | 8 +- .../Renderer/ReturnStatementRenderer.cs | 9 +- .../Renderer/SetStatementRenderer.cs | 11 +- .../Renderer/StatementLineRenderer.cs | 40 -- .../Renderer/StatementListRenderer.cs | 7 +- .../Renderer/StatementRenderer.cs | 4 +- .../StringLiteralExpressionRenderer.cs | 19 - ...tionRenderer.cs => SyntaxTokenRenderer.cs} | 9 +- ...enderer.cs => SyntaxTriviaListRenderer.cs} | 9 +- .../Renderer/SyntaxTriviaRenderer.cs | 57 ++ ...erer.cs => TopLevelDeclarationRenderer.cs} | 9 +- .../Renderer/TypeDeclarationRenderer.cs | 7 +- .../Renderer/TypeRenderer.cs | 10 +- .../Renderer/UnaryExpressionRenderer.cs | 10 +- .../Renderer/VariableDeclaratorRenderer.cs | 17 +- .../VariableOrArrayDeclaratorRenderer.cs | 27 + .../Syntax/BinaryOperatorType.cs | 25 - .../Syntax/IDeclarationLineSyntax.cs | 15 - .../Syntax/IExpressionSyntax.cs | 15 - .../Syntax/IGlobalDeclarationSyntax.cs | 15 - .../Syntax/IGlobalLineSyntax.cs | 15 - .../Syntax/IInvocationSyntax.cs | 16 - .../Syntax/IMemberDeclarationSyntax.cs | 15 - .../Syntax/IScopedDeclarationSyntax.cs | 15 - .../Syntax/IScopedGlobalDeclarationSyntax.cs | 15 - .../Syntax/IStatementLineSyntax.cs | 15 - .../Syntax/IStatementSyntax.cs | 15 - .../Syntax/ITopLevelDeclarationSyntax.cs | 15 - .../Syntax/IVariableDeclaratorSyntax.cs | 18 - .../Syntax/JassArgumentListSyntax.cs | 121 +++- .../Syntax/JassArrayDeclaratorSyntax.cs | 120 +++- .../JassArrayReferenceExpressionSyntax.cs | 31 - .../Syntax/JassBinaryExpressionSyntax.cs | 123 +++- .../JassBooleanLiteralExpressionSyntax.cs | 30 - .../Syntax/JassCallStatementSyntax.cs | 123 +++- .../JassCharacterLiteralExpressionSyntax.cs | 27 - .../Syntax/JassCommentSyntax.cs | 77 --- .../Syntax/JassCompilationUnitSyntax.cs | 102 +++- .../Syntax/JassDebugCustomScriptAction.cs | 29 - .../Syntax/JassDebugStatementSyntax.cs | 93 ++- .../JassDecimalLiteralExpressionSyntax.cs | 29 - .../Syntax/JassElementAccessClauseSyntax.cs | 121 ++++ .../JassElementAccessExpressionSyntax.cs | 123 ++++ .../Syntax/JassElseClauseSyntax.cs | 106 +++- .../Syntax/JassElseCustomScriptAction.cs | 22 - .../JassElseIfClauseDeclaratorSyntax.cs | 121 ++++ .../Syntax/JassElseIfClauseSyntax.cs | 128 +++- .../Syntax/JassElseIfCustomScriptAction.cs | 27 - .../Syntax/JassEmptyParameterListSyntax.cs | 99 ++++ .../Syntax/JassEmptySyntax.cs | 38 -- .../JassEndFunctionCustomScriptAction.cs | 22 - .../JassEndGlobalsCustomScriptAction.cs | 22 - .../Syntax/JassEndIfCustomScriptAction.cs | 22 - .../Syntax/JassEndLoopCustomScriptAction.cs | 22 - .../Syntax/JassEqualsValueClauseSyntax.cs | 95 ++- .../Syntax/JassExitStatementSyntax.cs | 93 ++- .../Syntax/JassExpressionSyntax.cs | 16 + .../JassFourCCLiteralExpressionSyntax.cs | 29 - .../Syntax/JassFunctionCustomScriptAction.cs | 27 - .../Syntax/JassFunctionDeclarationSyntax.cs | 132 ++++- .../Syntax/JassFunctionDeclaratorSyntax.cs | 191 +++++- .../JassFunctionReferenceExpressionSyntax.cs | 93 ++- .../JassGlobalConstantDeclarationSyntax.cs | 162 +++++ .../Syntax/JassGlobalDeclarationListSyntax.cs | 30 - .../Syntax/JassGlobalDeclarationSyntax.cs | 23 +- .../JassGlobalVariableDeclarationSyntax.cs | 91 +++ .../Syntax/JassGlobalsCustomScriptAction.cs | 22 - .../Syntax/JassGlobalsDeclarationSyntax.cs | 124 ++++ .../JassHexadecimalLiteralExpressionSyntax.cs | 29 - .../Syntax/JassIdentifierNameSyntax.cs | 72 ++- .../Syntax/JassIfClauseDeclaratorSyntax.cs | 121 ++++ .../Syntax/JassIfClauseSyntax.cs | 137 +++++ .../Syntax/JassIfCustomScriptAction.cs | 27 - .../Syntax/JassIfStatementSyntax.cs | 176 +++++- .../Syntax/JassInvocationExpressionSyntax.cs | 110 +++- .../Syntax/JassLiteralExpressionSyntax.cs | 83 +++ ...LocalVariableDeclarationStatementSyntax.cs | 93 ++- .../Syntax/JassLoopCustomScriptAction.cs | 22 - .../Syntax/JassLoopStatementSyntax.cs | 111 +++- .../JassNativeFunctionDeclarationSyntax.cs | 189 +++++- .../Syntax/JassNullLiteralExpressionSyntax.cs | 22 - .../JassOctalLiteralExpressionSyntax.cs | 29 - ...ParameterListOrEmptyParameterListSyntax.cs | 16 + .../Syntax/JassParameterListSyntax.cs | 105 +++- .../Syntax/JassParameterSyntax.cs | 108 +++- .../JassParenthesizedExpressionSyntax.cs | 106 +++- .../Syntax/JassPredefinedTypeSyntax.cs | 91 +++ .../Syntax/JassRealLiteralExpressionSyntax.cs | 69 --- .../Syntax/JassReturnClauseSyntax.cs | 108 ++++ .../Syntax/JassReturnStatementSyntax.cs | 120 +++- .../Syntax/JassSetStatementSyntax.cs | 171 +++++- .../Syntax/JassStatementListSyntax.cs | 31 - .../Syntax/JassStatementSyntax.cs | 16 + .../JassStringLiteralExpressionSyntax.cs | 29 - .../Syntax/JassSyntaxNode.cs | 49 ++ .../Syntax/JassSyntaxNodeOrToken.cs | 139 +++++ .../Syntax/JassSyntaxToken.cs | 63 ++ .../Syntax/JassSyntaxTrivia.cs | 45 ++ .../Syntax/JassSyntaxTriviaList.cs | 37 ++ .../Syntax/JassTopLevelDeclarationSyntax.cs | 16 + .../Syntax/JassTypeDeclarationSyntax.cs | 134 ++++- .../Syntax/JassTypeSyntax.cs | 27 +- .../Syntax/JassUnaryExpressionSyntax.cs | 97 ++- .../Syntax/JassVariableDeclaratorSyntax.cs | 161 ++++- .../JassVariableOrArrayDeclaratorSyntax.cs | 16 + .../JassVariableReferenceExpressionSyntax.cs | 27 - .../Syntax/UnaryOperatorType.cs | 16 - .../SyntaxFactory/ArgumentListFactory.cs | 29 +- .../SyntaxFactory/ArrayDeclaratorFactory.cs | 56 ++ .../ArrayReferenceExpressionFactory.cs | 21 - .../SyntaxFactory/BinaryExpressionFactory.cs | 94 ++- .../SyntaxFactory/CallStatementFactory.cs | 52 +- .../SyntaxFactory/CompilationUnitFactory.cs | 28 +- .../SyntaxFactory/DebugStatementFactory.cs | 36 ++ .../ElementAccessClauseFactory.cs | 33 ++ .../ElementAccessExpressionFactory.cs | 42 ++ .../SyntaxFactory/ElseClauseFactory.cs | 47 ++ .../ElseIfClauseDeclaratorFactory.cs | 33 ++ .../SyntaxFactory/ElseIfClauseFactory.cs | 59 ++ .../SyntaxFactory/EqualsValueClauseFactory.cs | 30 + .../SyntaxFactory/ExitStatementFactory.cs | 15 +- .../FourCCLiteralExpressionFactory.cs | 20 - .../FunctionDeclarationFactory.cs | 33 +- .../FunctionDeclaratorFactory.cs | 549 ++++++++++++++++- .../FunctionReferenceExpressionFactory.cs | 20 +- .../GlobalConstantDeclarationFactory.cs | 97 +++ .../SyntaxFactory/GlobalDeclarationFactory.cs | 39 -- .../GlobalVariableDeclarationFactory.cs | 155 +++++ .../GlobalsDeclarationFactory.cs | 52 ++ .../SyntaxFactory/IdentifierNameFactory.cs | 46 ++ .../IfClauseDeclaratorFactory.cs | 33 ++ .../SyntaxFactory/IfClauseFactory.cs | 59 ++ .../SyntaxFactory/IfStatementFactory.cs | 156 ++++- .../InvocationExpressionFactory.cs | 36 +- .../SyntaxFactory/LiteralExpressionFactory.cs | 77 ++- ...ocalVariableDeclarationStatementFactory.cs | 157 ++++- .../SyntaxFactory/LoopStatementFactory.cs | 36 +- .../NativeFunctionDeclarationFactory.cs | 561 ++++++++++++++++++ .../SyntaxFactory/ParameterFactory.cs | 21 + .../SyntaxFactory/ParameterListFactory.cs | 46 +- .../ParenthesizedExpressionFactory.cs | 18 +- .../SyntaxFactory/PredefinedTypeFactory.cs | 27 + .../SyntaxFactory/ReturnClauseFactory.cs | 30 + .../SyntaxFactory/ReturnStatementFactory.cs | 30 + .../SeparatedSyntaxListFactory.cs | 58 ++ .../SyntaxFactory/SetStatementFactory.cs | 103 +++- .../SyntaxFactory/StatementListFactory.cs | 27 - .../SyntaxFactory/SyntaxTokenFactory.cs | 83 +++ .../SyntaxFactory/SyntaxTriviaFactory.cs | 81 +++ .../SyntaxFactory/SyntaxTriviaListFactory.cs | 49 ++ .../SyntaxFactory/TypeDeclarationFactory.cs | 62 ++ .../SyntaxFactory/UnaryExpressionFactory.cs | 28 +- .../VariableDeclaratorFactory.cs | 110 ++++ .../SyntaxFactory/VariableReferenceFactory.cs | 19 - .../SyntaxRewriter/ArgumentListRewriter.cs | 35 ++ .../SyntaxRewriter/ArrayDeclaratorRewriter.cs | 35 ++ .../BinaryExpressionRewriter.cs | 35 ++ .../SyntaxRewriter/CallStatementRewriter.cs | 35 ++ .../SyntaxRewriter/CompilationUnitRewriter.cs | 33 ++ .../SyntaxRewriter/DebugStatementRewriter.cs | 33 ++ .../SyntaxRewriter/DeclarationListRewriter.cs | 51 ++ .../ElementAccessClauseRewriter.cs | 43 ++ .../ElementAccessExpressionRewriter.cs | 33 ++ .../SyntaxRewriter/ElseClauseRewriter.cs | 41 ++ .../ElseIfClauseDeclaratorRewriter.cs | 35 ++ .../ElseIfClauseListRewriter.cs | 50 ++ .../SyntaxRewriter/ElseIfClauseRewriter.cs | 33 ++ .../EmptyParameterListRewriter.cs | 33 ++ .../EqualsValueClauseRewriter.cs | 41 ++ .../SyntaxRewriter/ExitStatementRewriter.cs | 33 ++ .../SyntaxRewriter/ExpressionRewriter.cs | 40 ++ .../FunctionDeclarationRewriter.cs | 35 ++ .../FunctionDeclaratorRewriter.cs | 39 ++ .../FunctionReferenceExpressionRewriter.cs | 33 ++ .../GlobalConstantDeclarationRewriter.cs | 37 ++ .../GlobalDeclarationListRewriter.cs | 50 ++ .../GlobalDeclarationRewriter.cs | 26 + .../GlobalVariableDeclarationRewriter.cs | 29 + .../GlobalsDeclarationRewriter.cs | 35 ++ .../SyntaxRewriter/IdentifierNameRewriter.cs | 59 ++ .../IfClauseDeclaratorRewriter.cs | 35 ++ .../SyntaxRewriter/IfClauseRewriter.cs | 33 ++ .../SyntaxRewriter/IfStatementRewriter.cs | 37 ++ .../InvocationExpressionRewriter.cs | 33 ++ .../LiteralExpressionRewriter.cs | 29 + ...calVariableDeclarationStatementRewriter.cs | 33 ++ .../SyntaxRewriter/LoopStatementRewriter.cs | 35 ++ .../NativeFunctionDeclarationRewriter.cs | 39 ++ ...rameterListOrEmptyParameterListRewriter.cs | 26 + .../SyntaxRewriter/ParameterListRewriter.cs | 33 ++ .../SyntaxRewriter/ParameterRewriter.cs | 33 ++ .../ParenthesizedExpressionRewriter.cs | 35 ++ .../SyntaxRewriter/PredefinedTypeRewriter.cs | 29 + .../SyntaxRewriter/ReturnClauseRewriter.cs | 33 ++ .../SyntaxRewriter/ReturnStatementRewriter.cs | 33 ++ .../SeparatedArgumentListRewriter.cs | 70 +++ .../SeparatedParameterListRewriter.cs | 70 +++ .../SyntaxRewriter/SetStatementRewriter.cs | 37 ++ .../SyntaxRewriter/StatementListRewriter.cs | 50 ++ .../SyntaxRewriter/StatementRewriter.cs | 32 + .../SyntaxRewriter/SyntaxTokenRewriter.cs | 43 ++ .../SyntaxTriviaListRewriter.cs | 32 + .../TopLevelDeclarationRewriter.cs | 28 + .../SyntaxRewriter/TypeDeclarationRewriter.cs | 37 ++ .../SyntaxRewriter/TypeRewriter.cs | 26 + .../SyntaxRewriter/UnaryExpressionRewriter.cs | 33 ++ .../VariableDeclaratorRewriter.cs | 35 ++ .../VariableOrArrayDeclaratorRewriter.cs | 26 + .../War3Net.CodeAnalysis.Jass.csproj | 4 +- 477 files changed, 16574 insertions(+), 4604 deletions(-) create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassCompilationUnitBuilder.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassFunctionDeclarationBuilder.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassGlobalsDeclarationBuilder.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassIfStatementBuilder.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassLoopStatementBuilder.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassStatementListSyntaxBuilder.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Builders/JassSyntaxBuilder.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/BinaryOperatorTypeExtensions.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/ExpressionSyntaxExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/ImmutableArrayExtensions.cs rename src/War3Net.CodeAnalysis.Jass/{Renderer/VariableReferenceExpressionRenderer.cs => Extensions/JassCompilationUnitSyntaxExtensions.cs} (50%) create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs rename src/War3Net.CodeAnalysis.Jass/Extensions/{EquatableExtensions.cs => JassSyntaxNodeExtensions.cs} (51%) create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/JassTypeSyntaxExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/JassVariableOrArrayDeclaratorSyntaxExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/ObjectExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/UnaryOperatorTypeExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ArgumentListParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/BinaryOperatorParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/CallStatementParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/CharacterLiteralExpressionParser.cs (53%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/CompilationUnitParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/DecimalLiteralExpressionParser.cs (52%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ElementAccessClauseParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ElseIfClauseDeclaratorParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/EqualsValueClauseParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ExitStatementParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ExpressionParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/FourCCLiteralExpressionParser.cs (51%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclaratorParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/GlobalConstantDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/GlobalDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/GlobalVariableDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/GlobalsDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/HexadecimalLiteralExpressionParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/IdentifierNameParser.cs (59%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/IfClauseDeclaratorParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/IfStatementParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/LocalVariableDeclarationStatementParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/LoopStatementParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/NativeFunctionDeclarationParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/OctalLiteralExpressionParser.cs (53%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ParameterListParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/ParameterParser.cs (65%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ParenthesizedExpressionParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/RealLiteralExpressionParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ReturnClauseParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/ReturnStatementParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/SetStatementParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs rename src/War3Net.CodeAnalysis.Jass/{Parser => JassParser}/StringLiteralExpressionParser.cs (55%) create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/TopLevelDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/TypeDeclarationParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/TypeParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/UnaryOperatorParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassParser/VariableOrArrayDeclaratorParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ArgumentListNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ArrayDeclaratorNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/BinaryExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/CompilationUnitNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/DebugStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessClauseNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ElseClauseNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseDeclaratorNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/EmptyParameterListNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/EqualsValueClauseNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclarationNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionReferenceExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalsDeclarationNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/IdentifierNameNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseDeclaratorNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/IfStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/InvocationExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/LiteralExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/LoopStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterListNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ParenthesizedExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/PredefinedTypeNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnClauseNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/UnaryExpressionNormalizer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Normalizer/VariableDeclaratorNormalizer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ArgumentListParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ArrayReferenceExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/BinaryOperatorParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/BooleanLiteralExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/CallStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/CommentParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/CompilationUnitParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ConstantDeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/DebugCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/DebugStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/DeclarationLineParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/DeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ElseClauseParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ElseCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ElseIfClauseParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ElseIfCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EmptyParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EndFunctionCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EndGlobalsCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EndIfCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EndLoopCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EndOfLineParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/EqualsValueClauseParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ExitStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/FunctionCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclaratorParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/FunctionReferenceExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationListParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/GlobalLineParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/GlobalsCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/HexadecimalLiteralExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/IfCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/IfStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/InvocationExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/LocalVariableDeclarationStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/LoopCustomScriptActionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/LoopStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/NativeFunctionDeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/NewLineParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/NullLiteralExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ParameterListParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ParenthesizedExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/RealLiteralExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/ReturnStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/SetStatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/StatementLineParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/StatementListParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/StatementParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/TypeDeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/TypeParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/UnaryOperatorParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclarationParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclaratorParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/VariableReferenceExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Parser/WhitespaceParser.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Parsers/IdentifierExpressionParser.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/ArrayReferenceExpressionRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessClauseRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessExpressionRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseDeclaratorRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseListRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/GlobalConstantDeclarationRenamer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationListRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/GlobalVariableDeclarationRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/GlobalsDeclarationRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseDeclaratorRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/SyntaxTokenRenamer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/VariableOrArrayDeclaratorRenamer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renamer/VariableReferenceExpressionRenamer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/ArrayReferenceExpressionRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/DecimalLiteralExpressionRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationLineRenderer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessClauseRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{EndIfCustomScriptActionRenderer.cs => ElementAccessExpressionRenderer.cs} (61%) rename src/War3Net.CodeAnalysis.Jass/Renderer/{LoopCustomScriptActionRenderer.cs => ElseIfClauseDeclaratorRenderer.cs} (55%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfCustomScriptActionRenderer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/EmptyParameterListRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/EndFunctionCustomScriptActionRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/EndGlobalsCustomScriptActionRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/FourCCLiteralExpressionRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/FunctionCustomScriptActionRenderer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/GlobalConstantDeclarationRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{EndLoopCustomScriptActionRenderer.cs => GlobalVariableDeclarationRenderer.cs} (67%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsCustomScriptActionRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{GlobalDeclarationListRenderer.cs => GlobalsDeclarationRenderer.cs} (61%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/HexadecimalLiteralExpressionRenderer.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseDeclaratorRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{ElseCustomScriptActionRenderer.cs => IfClauseRenderer.cs} (69%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/IfCustomScriptActionRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{EmptyRenderer.cs => LiteralExpressionRenderer.cs} (69%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/NullLiteralExpressionRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/OctalLiteralExpressionRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{GlobalLineRenderer.cs => ParameterListOrEmptyParameterListRenderer.cs} (52%) rename src/War3Net.CodeAnalysis.Jass/Renderer/{CommentRenderer.cs => PredefinedTypeRenderer.cs} (71%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/RealLiteralExpressionRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{CharacterLiteralExpressionRenderer.cs => ReturnClauseRenderer.cs} (63%) delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/StatementLineRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/StringLiteralExpressionRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{DebugCustomScriptActionRenderer.cs => SyntaxTokenRenderer.cs} (63%) rename src/War3Net.CodeAnalysis.Jass/Renderer/{BooleanLiteralExpressionRenderer.cs => SyntaxTriviaListRenderer.cs} (64%) create mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs rename src/War3Net.CodeAnalysis.Jass/Renderer/{DeclarationRenderer.cs => TopLevelDeclarationRenderer.cs} (65%) create mode 100644 src/War3Net.CodeAnalysis.Jass/Renderer/VariableOrArrayDeclaratorRenderer.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/BinaryOperatorType.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IDeclarationLineSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalLineSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IInvocationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IMemberDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IScopedDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IScopedGlobalDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IStatementLineSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IStatementSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/ITopLevelDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/IVariableDeclaratorSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayReferenceExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassBooleanLiteralExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassCharacterLiteralExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassCommentSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugCustomScriptAction.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassDecimalLiteralExpressionSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessClauseSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassElseCustomScriptAction.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseDeclaratorSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfCustomScriptAction.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptyParameterListSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptySyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassEndFunctionCustomScriptAction.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassEndGlobalsCustomScriptAction.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassEndIfCustomScriptAction.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassEndLoopCustomScriptAction.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassFourCCLiteralExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionCustomScriptAction.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalConstantDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationListSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalVariableDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsCustomScriptAction.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsDeclarationSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassHexadecimalLiteralExpressionSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseDeclaratorSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassIfCustomScriptAction.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassLiteralExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopCustomScriptAction.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassNullLiteralExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassOctalLiteralExpressionSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListOrEmptyParameterListSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassPredefinedTypeSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassRealLiteralExpressionSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnClauseSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementListSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassStringLiteralExpressionSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassTopLevelDeclarationSyntax.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableOrArrayDeclaratorSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableReferenceExpressionSyntax.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/Syntax/UnaryOperatorType.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayDeclaratorFactory.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayReferenceExpressionFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessClauseFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessExpressionFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseClauseFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseDeclaratorFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/EqualsValueClauseFactory.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FourCCLiteralExpressionFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalConstantDeclarationFactory.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalDeclarationFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalVariableDeclarationFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalsDeclarationFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IdentifierNameFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseDeclaratorFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/NativeFunctionDeclarationFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/PredefinedTypeFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnClauseFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnStatementFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SeparatedSyntaxListFactory.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/StatementListFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/TypeDeclarationFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableDeclaratorFactory.cs delete mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableReferenceFactory.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArgumentListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArrayDeclaratorRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/BinaryExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CallStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CompilationUnitRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DebugStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DeclarationListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessClauseRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseClauseRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseDeclaratorRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EmptyParameterListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EqualsValueClauseRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExitStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclaratorRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionReferenceExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalConstantDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalVariableDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalsDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IdentifierNameRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseDeclaratorRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/InvocationExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LiteralExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LocalVariableDeclarationStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LoopStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/NativeFunctionDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListOrEmptyParameterListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParenthesizedExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/PredefinedTypeRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnClauseRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedArgumentListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedParameterListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SetStatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTokenRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTriviaListRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TopLevelDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeDeclarationRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/UnaryExpressionRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableDeclaratorRewriter.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableOrArrayDeclaratorRewriter.cs diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassCompilationUnitBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassCompilationUnitBuilder.cs new file mode 100644 index 00000000..6f067dd0 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassCompilationUnitBuilder.cs @@ -0,0 +1,96 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public class JassCompilationUnitBuilder : JassSyntaxBuilder + { + private readonly ImmutableArray.Builder _declarationsBuilder; + + private JassGlobalsDeclarationBuilder? _globalsDeclarationBuilder; + private JassFunctionDeclarationBuilder? _functionDeclarationBuilder; + + public JassCompilationUnitBuilder() + { + _declarationsBuilder = ImmutableArray.CreateBuilder(); + } + + public JassCompilationUnitSyntax ToCompilationUnit(JassSyntaxToken endOfFileToken) + { + if (_globalsDeclarationBuilder is not null || + _functionDeclarationBuilder is not null) + { + throw new InvalidOperationException(); + } + + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(endOfFileToken, JassSyntaxKind.EndOfFileToken); + + return new JassCompilationUnitSyntax( + _declarationsBuilder.ToImmutable(), + endOfFileToken.PrependLeadingTrivia(BuildTriviaList())); + } + + public void AddDeclaration(JassTopLevelDeclarationSyntax declaration) + { + if (_globalsDeclarationBuilder is not null || + _functionDeclarationBuilder is not null) + { + throw new InvalidOperationException(); + } + + _declarationsBuilder.Add(declaration.PrependLeadingTrivia(BuildTriviaList())); + } + + public JassGlobalsDeclarationBuilder BeginGlobalsDeclaration(JassSyntaxToken globalsToken) + { + if (_functionDeclarationBuilder is not null) + { + throw new InvalidOperationException(); + } + + return _globalsDeclarationBuilder = new JassGlobalsDeclarationBuilder(globalsToken.PrependLeadingTrivia(BuildTriviaList())); + } + + public void EndGlobalsDeclaration(JassSyntaxToken endGlobalsToken) + { + if (_globalsDeclarationBuilder is null) + { + throw new InvalidOperationException(); + } + + _declarationsBuilder.Add(_globalsDeclarationBuilder.ToGlobalsDeclaration(endGlobalsToken)); + _globalsDeclarationBuilder = null; + } + + public JassFunctionDeclarationBuilder BeginFunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator) + { + if (_globalsDeclarationBuilder is not null) + { + throw new InvalidOperationException(); + } + + return _functionDeclarationBuilder = new JassFunctionDeclarationBuilder(functionDeclarator.PrependLeadingTrivia(BuildTriviaList())); + } + + public void EndFunctionDeclaration(JassSyntaxToken endFunctionToken) + { + if (_functionDeclarationBuilder is null) + { + throw new InvalidOperationException(); + } + + _declarationsBuilder.Add(_functionDeclarationBuilder.ToFunctionDeclaration(endFunctionToken)); + _functionDeclarationBuilder = null; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassFunctionDeclarationBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassFunctionDeclarationBuilder.cs new file mode 100644 index 00000000..8a1ece30 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassFunctionDeclarationBuilder.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public class JassFunctionDeclarationBuilder : JassStatementListSyntaxBuilder + { + private readonly JassFunctionDeclaratorSyntax _functionDeclarator; + + public JassFunctionDeclarationBuilder(JassFunctionDeclaratorSyntax functionDeclarator) + { + _functionDeclarator = functionDeclarator; + } + + public JassFunctionDeclarationSyntax ToFunctionDeclaration(JassSyntaxToken endFunctionToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(endFunctionToken, JassSyntaxKind.EndFunctionKeyword); + + return new JassFunctionDeclarationSyntax( + _functionDeclarator, + BuildStatementList(), + endFunctionToken.PrependLeadingTrivia(BuildTriviaList())); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassGlobalsDeclarationBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassGlobalsDeclarationBuilder.cs new file mode 100644 index 00000000..db826265 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassGlobalsDeclarationBuilder.cs @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public class JassGlobalsDeclarationBuilder : JassSyntaxBuilder + { + private readonly ImmutableArray.Builder _globalDeclarationsBuilder; + private readonly JassSyntaxToken _globalsToken; + + public JassGlobalsDeclarationBuilder(JassSyntaxToken globalsToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(globalsToken, JassSyntaxKind.GlobalsKeyword); + + _globalDeclarationsBuilder = ImmutableArray.CreateBuilder(); + _globalsToken = globalsToken; + } + + public JassGlobalsDeclarationSyntax ToGlobalsDeclaration(JassSyntaxToken endGlobalsToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(endGlobalsToken, JassSyntaxKind.EndGlobalsKeyword); + + return new JassGlobalsDeclarationSyntax( + _globalsToken, + _globalDeclarationsBuilder.ToImmutable(), + endGlobalsToken.PrependLeadingTrivia(BuildTriviaList())); + } + + public void AddGlobalDeclaration(JassGlobalDeclarationSyntax globalDeclaration) + { + _globalDeclarationsBuilder.Add(globalDeclaration.PrependLeadingTrivia(BuildTriviaList())); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassIfStatementBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassIfStatementBuilder.cs new file mode 100644 index 00000000..3205180c --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassIfStatementBuilder.cs @@ -0,0 +1,92 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public class JassIfStatementBuilder : JassStatementListSyntaxBuilder + { + private readonly ImmutableArray.Builder _elseIfClausesBuilder; + private readonly JassIfClauseDeclaratorSyntax _ifClauseDeclarator; + + private JassIfClauseSyntax? _ifClause; + private JassElseIfClauseDeclaratorSyntax? _elseIfClauseDeclarator; + private JassSyntaxToken? _elseToken; + private JassElseClauseSyntax? _elseClause; + + public JassIfStatementBuilder(JassIfClauseDeclaratorSyntax ifClauseDeclarator) + { + _elseIfClausesBuilder = ImmutableArray.CreateBuilder(); + _ifClauseDeclarator = ifClauseDeclarator; + } + + public JassIfStatementSyntax ToIfStatement(JassSyntaxToken endIfToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(endIfToken, JassSyntaxKind.EndIfKeyword); + + EndCurrentClause(); + + return new JassIfStatementSyntax( + _ifClause, + _elseIfClausesBuilder.ToImmutable(), + _elseClause, + endIfToken); + } + + public void BeginElseIfClause(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator) + { + EndCurrentClause(); + if (_elseClause is not null) + { + throw new InvalidOperationException(); + } + + _elseIfClauseDeclarator = elseIfClauseDeclarator.PrependLeadingTrivia(BuildTriviaList()); + } + + public void BeginElseClause(JassSyntaxToken elseToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(elseToken, JassSyntaxKind.ElseKeyword); + + EndCurrentClause(); + if (_elseClause is not null) + { + throw new InvalidOperationException(); + } + + _elseIfClauseDeclarator = null; + _elseToken = elseToken.PrependLeadingTrivia(BuildTriviaList()); + } + + [MemberNotNull(nameof(_ifClause))] + private void EndCurrentClause() + { + if (_ifClause is null) + { + _ifClause = new JassIfClauseSyntax(_ifClauseDeclarator, BuildStatementList()); + } + else if (_elseIfClauseDeclarator is not null) + { + _elseIfClausesBuilder.Add(new JassElseIfClauseSyntax(_elseIfClauseDeclarator, BuildStatementList())); + } + else if (_elseToken is not null) + { + _elseClause = new JassElseClauseSyntax(_elseToken, BuildStatementList()); + } + else + { + throw new InvalidOperationException(); + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassLoopStatementBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassLoopStatementBuilder.cs new file mode 100644 index 00000000..f39e32f1 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassLoopStatementBuilder.cs @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public class JassLoopStatementBuilder : JassStatementListSyntaxBuilder + { + private readonly JassSyntaxToken _loopToken; + + public JassLoopStatementBuilder(JassSyntaxToken loopToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(loopToken, JassSyntaxKind.LoopKeyword); + + _loopToken = loopToken; + } + + public JassLoopStatementSyntax ToLoopStatement(JassSyntaxToken endLoopToken) + { + JassSyntaxFactory.ThrowHelper.ThrowIfInvalidToken(endLoopToken, JassSyntaxKind.EndLoopKeyword); + + return new JassLoopStatementSyntax( + _loopToken, + BuildStatementList(), + endLoopToken.PrependLeadingTrivia(BuildTriviaList())); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassStatementListSyntaxBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassStatementListSyntaxBuilder.cs new file mode 100644 index 00000000..ec427949 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassStatementListSyntaxBuilder.cs @@ -0,0 +1,99 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public abstract class JassStatementListSyntaxBuilder : JassSyntaxBuilder + { + private readonly ImmutableArray.Builder _statementsBuilder; + + private JassIfStatementBuilder? _ifStatementBuilder; + private JassLoopStatementBuilder? _loopStatementBuilder; + + public JassStatementListSyntaxBuilder() + { + _statementsBuilder = ImmutableArray.CreateBuilder(); + } + + public void AddStatement(JassStatementSyntax statement) + { + if (_ifStatementBuilder is not null || + _loopStatementBuilder is not null) + { + throw new InvalidOperationException(); + } + + _statementsBuilder.Add(statement.PrependLeadingTrivia(BuildTriviaList())); + } + + public JassIfStatementBuilder BeginIfStatement(JassIfClauseDeclaratorSyntax ifClauseDeclarator) + { + if (_loopStatementBuilder is not null) + { + throw new InvalidOperationException(); + } + + return _ifStatementBuilder = new JassIfStatementBuilder(ifClauseDeclarator.PrependLeadingTrivia(BuildTriviaList())); + } + + public void EndIfStatement(JassSyntaxToken endifToken) + { + if (_ifStatementBuilder is null) + { + throw new InvalidOperationException(); + } + + _statementsBuilder.Add(_ifStatementBuilder.ToIfStatement(endifToken)); + _ifStatementBuilder = null; + } + + public JassLoopStatementBuilder BeginLoopStatement(JassSyntaxToken loopToken) + { + if (_ifStatementBuilder is not null) + { + throw new InvalidOperationException(); + } + + return _loopStatementBuilder = new JassLoopStatementBuilder(loopToken.PrependLeadingTrivia(BuildTriviaList())); + } + + public void EndLoopStatement(JassSyntaxToken endLoopToken) + { + if (_loopStatementBuilder is null) + { + throw new InvalidOperationException(); + } + + _statementsBuilder.Add(_loopStatementBuilder.ToLoopStatement(endLoopToken)); + _loopStatementBuilder = null; + } + + protected ImmutableArray BuildStatementList() + { + if (_ifStatementBuilder is not null || + _loopStatementBuilder is not null) + { + throw new InvalidOperationException(); + } + + if (_statementsBuilder.Count == 0) + { + return ImmutableArray.Empty; + } + + var result = _statementsBuilder.ToImmutable(); + _statementsBuilder.Clear(); + return result; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Builders/JassSyntaxBuilder.cs b/src/War3Net.CodeAnalysis.Jass/Builders/JassSyntaxBuilder.cs new file mode 100644 index 00000000..93fb64ac --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Builders/JassSyntaxBuilder.cs @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Builders +{ + public abstract class JassSyntaxBuilder + { + private readonly ImmutableArray.Builder _triviaBuilder; + + public JassSyntaxBuilder() + { + _triviaBuilder = ImmutableArray.CreateBuilder(); + } + + public void AddTrivia(JassSyntaxTrivia trivia) + { + _triviaBuilder.Add(trivia); + } + + public void AddTrivia(params JassSyntaxTrivia[] trivia) + { + _triviaBuilder.AddRange(trivia); + } + + public void AddTrivia(IEnumerable trivia) + { + _triviaBuilder.AddRange(trivia); + } + + protected JassSyntaxTriviaList BuildTriviaList() + { + if (_triviaBuilder.Count == 0) + { + return JassSyntaxTriviaList.Empty; + } + + var result = new JassSyntaxTriviaList(_triviaBuilder.ToImmutable()); + _triviaBuilder.Clear(); + return result; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/BinaryOperatorTypeExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/BinaryOperatorTypeExtensions.cs deleted file mode 100644 index df09cfa6..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/BinaryOperatorTypeExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.ComponentModel; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass.Extensions -{ - public static class BinaryOperatorTypeExtensions - { - public static string GetSymbol(this BinaryOperatorType binaryOperator) - { - return binaryOperator switch - { - BinaryOperatorType.Add => $"{JassSymbol.PlusSign}", - BinaryOperatorType.Subtract => $"{JassSymbol.MinusSign}", - BinaryOperatorType.Multiplication => $"{JassSymbol.Asterisk}", - BinaryOperatorType.Division => $"{JassSymbol.Slash}", - BinaryOperatorType.GreaterThan => $"{JassSymbol.GreaterThanSign}", - BinaryOperatorType.LessThan => $"{JassSymbol.LessThanSign}", - BinaryOperatorType.Equals => $"{JassSymbol.EqualsSign}{JassSymbol.EqualsSign}", - BinaryOperatorType.NotEquals => $"{JassSymbol.ExclamationMark}{JassSymbol.EqualsSign}", - BinaryOperatorType.GreaterOrEqual => $"{JassSymbol.GreaterThanSign}{JassSymbol.EqualsSign}", - BinaryOperatorType.LessOrEqual => $"{JassSymbol.LessThanSign}{JassSymbol.EqualsSign}", - BinaryOperatorType.And => JassKeyword.And, - BinaryOperatorType.Or => JassKeyword.Or, - - _ => throw new InvalidEnumArgumentException(nameof(binaryOperator), (int)binaryOperator, typeof(BinaryOperatorType)), - }; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/ExpressionSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/ExpressionSyntaxExtensions.cs deleted file mode 100644 index 620a3cc1..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/ExpressionSyntaxExtensions.cs +++ /dev/null @@ -1,106 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; -using System.Globalization; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass.Extensions -{ - public static class ExpressionSyntaxExtensions - { - public static IExpressionSyntax Deparenthesize(this IExpressionSyntax expression) - { - while (expression is JassParenthesizedExpressionSyntax parenthesizedExpression) - { - expression = parenthesizedExpression.Expression; - } - - return expression; - } - - public static bool TryGetIntegerExpressionValue(this IExpressionSyntax expression, out int value) - { - switch (expression) - { - case JassDecimalLiteralExpressionSyntax decimalLiteralExpression: - value = decimalLiteralExpression.Value; - return true; - - case JassOctalLiteralExpressionSyntax octalLiteralExpression: - value = octalLiteralExpression.Value; - return true; - - case JassFourCCLiteralExpressionSyntax fourCCLiteralExpression: - value = fourCCLiteralExpression.Value; - return true; - - case JassUnaryExpressionSyntax unaryExpression: - return int.TryParse(unaryExpression.ToString(), out value); - - case JassHexadecimalLiteralExpressionSyntax hexLiteralExpression: - value = hexLiteralExpression.Value; - return true; - - default: - value = default; - return false; - } - } - - public static bool TryGetPlayerIdExpressionValue(this IExpressionSyntax expression, int maxPlayerSlots, out int value) - { - if (expression is JassVariableReferenceExpressionSyntax variableReferenceExpression) - { - if (string.Equals(variableReferenceExpression.IdentifierName.Name, "PLAYER_NEUTRAL_AGGRESSIVE", StringComparison.Ordinal)) - { - value = maxPlayerSlots; - return true; - } - else if (string.Equals(variableReferenceExpression.IdentifierName.Name, "PLAYER_NEUTRAL_PASSIVE", StringComparison.Ordinal)) - { - value = maxPlayerSlots + 3; - return true; - } - else - { - value = default; - return false; - } - } - else - { - return expression.TryGetIntegerExpressionValue(out value); - } - } - - public static bool TryGetRealExpressionValue(this IExpressionSyntax expression, out float value) - { - if (expression.TryGetIntegerExpressionValue(out var intValue)) - { - value = intValue; - return true; - } - - if (expression is JassRealLiteralExpressionSyntax realLiteralExpression && - float.TryParse(realLiteralExpression.ToString(), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) - { - return true; - } - - if (expression is JassUnaryExpressionSyntax unaryExpression && - float.TryParse(unaryExpression.ToString(), NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) - { - return true; - } - - value = default; - return false; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/ImmutableArrayExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/ImmutableArrayExtensions.cs new file mode 100644 index 00000000..34476122 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/ImmutableArrayExtensions.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Text; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class ImmutableArrayExtensions + { + public static bool IsEquivalentTo(this ImmutableArray array, ImmutableArray other) + where TSyntaxNode : JassSyntaxNode + { + if (array.Length != other.Length) + { + return false; + } + + for (var i = 0; i < array.Length; i++) + { + if (!array[i].IsEquivalentTo(other[i])) + { + return false; + } + } + + return true; + } + + public static void WriteTo(this ImmutableArray array, TextWriter writer) + where TSyntaxNode : JassSyntaxNode + { + for (var i = 0; i < array.Length; i++) + { + array[i].WriteTo(writer); + } + } + + public static IEnumerable GetDescendantNodes(this ImmutableArray array) + where TSyntaxNode : JassSyntaxNode + { + return array.SelectMany(item => item.GetDescendantNodes()); + } + + public static IEnumerable GetDescendantTokens(this ImmutableArray array) + where TSyntaxNode : JassSyntaxNode + { + return array.SelectMany(item => item.GetDescendantTokens()); + } + + public static IEnumerable GetDescendantNodesAndTokens(this ImmutableArray array) + where TSyntaxNode : JassSyntaxNode + { + return array.SelectMany(item => item.GetDescendantNodesAndTokens()); + } + + internal static ImmutableArray ReplaceFirstItem(this ImmutableArray array, T newItem) + { + var builder = array.ToBuilder(); + builder[0] = newItem; + return builder.ToImmutable(); + } + + internal static ImmutableArray ReplaceLastItem(this ImmutableArray array, T newItem) + { + var builder = array.ToBuilder(); + builder[^1] = newItem; + return builder.ToImmutable(); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/VariableReferenceExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassCompilationUnitSyntaxExtensions.cs similarity index 50% rename from src/War3Net.CodeAnalysis.Jass/Renderer/VariableReferenceExpressionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Extensions/JassCompilationUnitSyntaxExtensions.cs index 8f048ec5..dc64fc7e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/VariableReferenceExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassCompilationUnitSyntaxExtensions.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -7,13 +7,13 @@ using War3Net.CodeAnalysis.Jass.Syntax; -namespace War3Net.CodeAnalysis.Jass +namespace War3Net.CodeAnalysis.Jass.Extensions { - public partial class JassRenderer + public static class JassCompilationUnitSyntaxExtensions { - public void Render(JassVariableReferenceExpressionSyntax variableReferenceExpressionSyntax) + public static JassCompilationUnitSyntax NormalizeWhitespace(this JassCompilationUnitSyntax compilationUnit) { - Render(variableReferenceExpressionSyntax.IdentifierName); + return new JassSyntaxNormalizer().NormalizeWhitespace(compilationUnit); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs new file mode 100644 index 00000000..1183caf5 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs @@ -0,0 +1,209 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class JassExpressionSyntaxExtensions + { + public static JassExpressionSyntax Deparenthesize(this JassExpressionSyntax expression) + { + while (expression is JassParenthesizedExpressionSyntax parenthesizedExpression) + { + expression = parenthesizedExpression.Expression; + } + + return expression; + } + + public static bool TryGetBooleanExpressionValue(this JassExpressionSyntax expression, out bool value) + { + if (expression is JassLiteralExpressionSyntax literalExpression) + { + switch (literalExpression.Token.SyntaxKind) + { + case JassSyntaxKind.TrueKeyword: + value = true; + return true; + + case JassSyntaxKind.FalseKeyword: + value = false; + return true; + } + } + + value = default; + return false; + } + + public static bool TryGetCharacterExpressionValue(this JassExpressionSyntax expression, out char value) + { + if (expression is JassLiteralExpressionSyntax literalExpression && + literalExpression.Token.SyntaxKind == JassSyntaxKind.CharacterLiteralToken) + { + value = literalExpression.Token.Text[1]; + return true; + } + + value = default; + return false; + } + + public static bool TryGetIdentifierNameValue(this JassExpressionSyntax expression, [NotNullWhen(true)] out string? value) + { + if (expression is JassIdentifierNameSyntax identifierName) + { + value = identifierName.Token.Text; + return true; + } + + value = null; + return false; + } + + public static bool TryGetIntegerExpressionValue(this JassExpressionSyntax expression, out int value) + { + if (expression is JassLiteralExpressionSyntax literalExpression) + { + switch (literalExpression.Token.SyntaxKind) + { + case JassSyntaxKind.DecimalLiteralToken: + value = int.Parse(literalExpression.Token.Text, CultureInfo.InvariantCulture); + return true; + + case JassSyntaxKind.HexadecimalLiteralToken: + value = Convert.ToInt32(literalExpression.Token.Text.StartsWith(JassSymbol.DollarChar) ? literalExpression.Token.Text[1..] : literalExpression.Token.Text[2..], 16); + return true; + + case JassSyntaxKind.OctalLiteralToken: + value = Convert.ToInt32(literalExpression.Token.Text, 8); + return true; + + case JassSyntaxKind.FourCCLiteralToken: + value = literalExpression.Token.Text[1..^1].FromJassRawcode(); + return true; + + default: + value = default; + return false; + } + } + else if (expression is JassUnaryExpressionSyntax unaryExpression) + { + switch (unaryExpression.OperatorToken.SyntaxKind) + { + case JassSyntaxKind.PlusToken: + return unaryExpression.Expression.TryGetIntegerExpressionValue(out value); + + case JassSyntaxKind.MinusToken: + if (unaryExpression.Expression.TryGetIntegerExpressionValue(out var result)) + { + value = -result; + return true; + } + + break; + + default: + value = default; + return false; + } + } + + value = default; + return false; + } + + public static bool TryGetPlayerIdExpressionValue(this JassExpressionSyntax expression, int maxPlayerSlots, out int value) + { + if (expression is JassIdentifierNameSyntax identifierName) + { + if (string.Equals(identifierName.Token.Text, "PLAYER_NEUTRAL_AGGRESSIVE", StringComparison.Ordinal)) + { + value = maxPlayerSlots; + return true; + } + else if (string.Equals(identifierName.Token.Text, "PLAYER_NEUTRAL_PASSIVE", StringComparison.Ordinal)) + { + value = maxPlayerSlots + 3; + return true; + } + else + { + value = default; + return false; + } + } + else + { + return expression.TryGetIntegerExpressionValue(out value); + } + } + + public static bool TryGetRealExpressionValue(this JassExpressionSyntax expression, out float value) + { + if (expression.TryGetIntegerExpressionValue(out var intValue)) + { + value = intValue; + return true; + } + + if (expression is JassLiteralExpressionSyntax literalExpression && + float.TryParse(literalExpression.Token.Text, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) + { + return true; + } + + if (expression is JassUnaryExpressionSyntax unaryExpression && + float.TryParse(unaryExpression.ToString(), NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out value)) + { + return true; + } + + value = default; + return false; + } + + public static bool TryGetStringExpressionValue(this JassExpressionSyntax expression, out string? value) + { + if (expression is JassLiteralExpressionSyntax literalExpression) + { + switch (literalExpression.Token.SyntaxKind) + { + case JassSyntaxKind.StringLiteralToken: + value = literalExpression.Token.Text[1..^1]; + return true; + + case JassSyntaxKind.NullKeyword: + value = null; + return true; + } + } + + value = null; + return false; + } + + public static bool TryGetNotNullStringExpressionValue(this JassExpressionSyntax expression, [NotNullWhen(true)] out string? value) + { + if (expression is JassLiteralExpressionSyntax literalExpression && + literalExpression.Token.SyntaxKind == JassSyntaxKind.StringLiteralToken) + { + value = literalExpression.Token.Text[1..^1]; + return true; + } + + value = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs new file mode 100644 index 00000000..2d06dd08 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class JassParameterListOrEmptyParameterListSyntaxExtensions + { + public static ImmutableArray GetParameters(this JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) + { + if (parameterListOrEmptyParameterList is JassParameterListSyntax parameterList) + { + return parameterList.ParameterList.Items; + } + else if (parameterListOrEmptyParameterList is JassEmptyParameterListSyntax) + { + return ImmutableArray.Empty; + } + else + { + throw new ArgumentException("Unknown parameter list type.", nameof(parameterListOrEmptyParameterList)); + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/EquatableExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxNodeExtensions.cs similarity index 51% rename from src/War3Net.CodeAnalysis.Jass/Extensions/EquatableExtensions.cs rename to src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxNodeExtensions.cs index 8fa626bb..cd3b1edb 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/EquatableExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxNodeExtensions.cs @@ -1,19 +1,19 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // // ------------------------------------------------------------------------------ -using System; +using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass.Extensions { - public static class EquatableExtensions + public static class JassSyntaxNodeExtensions { - public static bool NullableEquals(this IEquatable? objA, T? objB) + public static bool NullableEquivalentTo(this JassSyntaxNode? objA, JassSyntaxNode? objB) { - return ReferenceEquals(objA, objB) || objA?.Equals(objB) == true; + return ReferenceEquals(objA, objB) || objA?.IsEquivalentTo(objB) == true; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs new file mode 100644 index 00000000..8d5327a1 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs @@ -0,0 +1,164 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class JassSyntaxTokenExtensions + { + public static JassSyntaxToken WithLeadingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) + { + return new JassSyntaxToken(triviaList, token.SyntaxKind, token.Text, token.TrailingTrivia); + } + + public static JassSyntaxToken WithTrailingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) + { + return new JassSyntaxToken(token.LeadingTrivia, token.SyntaxKind, token.Text, triviaList); + } + + public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) + { + return token.WithLeadingTrivia(AppendTriviaToList(token.LeadingTrivia.Trivia, trivia)); + } + + public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList.Trivia)); + } + + public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); + } + + public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, IEnumerable triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); + } + + public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); + } + + public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) + { + return token.WithLeadingTrivia(PrependTriviaToList(trivia, token.LeadingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(triviaList.Trivia, token.LeadingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, IEnumerable triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) + { + return token.WithLeadingTrivia(ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); + } + + public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) + { + return token.WithTrailingTrivia(AppendTriviaToList(token.TrailingTrivia.Trivia, trivia)); + } + + public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList.Trivia)); + } + + public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); + } + + public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, IEnumerable triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); + } + + public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); + } + + public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) + { + return token.WithTrailingTrivia(PrependTriviaToList(trivia, token.TrailingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(triviaList.Trivia, token.TrailingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, IEnumerable triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); + } + + public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) + { + return token.WithTrailingTrivia(ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); + } + + internal static bool NullableEquals(this JassSyntaxToken? objA, JassSyntaxToken? objB) + { + return (objA is null) == (objB is null); + } + + private static JassSyntaxTriviaList AppendTriviaToList(ImmutableArray triviaList, JassSyntaxTrivia trivia) + { + var builder = ImmutableArray.CreateBuilder(triviaList.Length + 1); + builder.AddRange(triviaList); + builder.Add(trivia); + return new JassSyntaxTriviaList(builder.MoveToImmutable()); + } + + private static JassSyntaxTriviaList PrependTriviaToList(JassSyntaxTrivia trivia, ImmutableArray triviaList) + { + var builder = ImmutableArray.CreateBuilder(triviaList.Length + 1); + builder.Add(trivia); + builder.AddRange(triviaList); + return new JassSyntaxTriviaList(builder.MoveToImmutable()); + } + + private static JassSyntaxTriviaList ConcatTriviaLists(ImmutableArray firstList, ImmutableArray secondList) + { + var builder = ImmutableArray.CreateBuilder(firstList.Length + secondList.Length); + builder.AddRange(firstList); + builder.AddRange(secondList); + return new JassSyntaxTriviaList(builder.MoveToImmutable()); + } + + private static JassSyntaxTriviaList ConcatTriviaLists(IEnumerable firstList, IEnumerable secondList) + { + var builder = ImmutableArray.CreateBuilder(); + builder.AddRange(firstList); + builder.AddRange(secondList); + return new JassSyntaxTriviaList(builder.ToImmutable()); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassTypeSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassTypeSyntaxExtensions.cs new file mode 100644 index 00000000..394bd979 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassTypeSyntaxExtensions.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class JassTypeSyntaxExtensions + { + public static JassSyntaxToken GetToken(this JassTypeSyntax type) + { + if (type is JassIdentifierNameSyntax identifierName) + { + return identifierName.Token; + } + else if (type is JassPredefinedTypeSyntax predefinedType) + { + return predefinedType.Token; + } + else + { + throw new ArgumentException("Unknown type.", nameof(type)); + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassVariableOrArrayDeclaratorSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassVariableOrArrayDeclaratorSyntaxExtensions.cs new file mode 100644 index 00000000..d217bb0e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassVariableOrArrayDeclaratorSyntaxExtensions.cs @@ -0,0 +1,48 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class JassVariableOrArrayDeclaratorSyntaxExtensions + { + public static JassIdentifierNameSyntax GetIdentifierName(this JassVariableOrArrayDeclaratorSyntax declarator) + { + if (declarator is JassVariableDeclaratorSyntax variableDeclarator) + { + return variableDeclarator.IdentifierName; + } + else if (declarator is JassArrayDeclaratorSyntax arrayDeclarator) + { + return arrayDeclarator.IdentifierName; + } + else + { + throw new ArgumentException("Unknown declarator type.", nameof(declarator)); + } + } + + public static JassTypeSyntax GetVariableType(this JassVariableOrArrayDeclaratorSyntax declarator) + { + if (declarator is JassVariableDeclaratorSyntax variableDeclarator) + { + return variableDeclarator.Type; + } + else if (declarator is JassArrayDeclaratorSyntax arrayDeclarator) + { + return arrayDeclarator.Type; + } + else + { + throw new ArgumentException("Unknown declarator type.", nameof(declarator)); + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/ObjectExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/ObjectExtensions.cs new file mode 100644 index 00000000..fd9db04a --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/ObjectExtensions.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + internal static class ObjectExtensions + { + internal static string Optional(this object? obj) + { + return obj?.ToString() ?? string.Empty; + } + + internal static string OptionalPrefixed(this object? obj, string prefix = " ") + { + if (obj is null) + { + return string.Empty; + } + + return $"{prefix}{obj}"; + } + + internal static string OptionalSuffixed(this object? obj, string suffix = " ") + { + if (obj is null) + { + return string.Empty; + } + + return $"{obj}{suffix}"; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/ParserExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/ParserExtensions.cs index 3ef55e85..c475619b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/ParserExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/ParserExtensions.cs @@ -11,20 +11,56 @@ using War3Net.CodeAnalysis.Jass.Syntax; +using static Pidgin.Parser; + namespace War3Net.CodeAnalysis.Jass.Extensions { internal static class ParserExtensions { - internal static Parser> Prefix( - this Parser parser) + internal static Parser> Prefix( + this Parser operatorTokenParser) + { + return operatorTokenParser.Select>(operatorToken => expression => new JassUnaryExpressionSyntax( + operatorToken, + expression)); + } + + internal static Parser> Infix( + this Parser operatorTokenParser) + { + return operatorTokenParser.Select>(operatorToken => (left, right) => new JassBinaryExpressionSyntax( + left, + operatorToken, + right)); + } + + internal static Parser AsToken( + this Parser tokenSymbolParser, + Parser trailingTriviaParser, + JassSyntaxKind syntaxKind, + string symbol) { - return parser.Select>(@operator => expression => new JassUnaryExpressionSyntax(@operator, expression)); + return Map( + (_, trailingTrivia) => new JassSyntaxToken( + syntaxKind, + symbol, + trailingTrivia), + tokenSymbolParser, + trailingTriviaParser); } - internal static Parser> Infix( - this Parser parser) + internal static Parser AsToken( + this Parser tokenTextParser, + Parser trailingTriviaParser, + JassSyntaxKind syntaxKind) { - return parser.Select>(@operator => (left, right) => new JassBinaryExpressionSyntax(@operator, left, right)); + return Map( + (text, trailingTrivia) => new JassSyntaxToken( + syntaxKind, + text, + trailingTrivia), + tokenTextParser, + trailingTriviaParser); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs new file mode 100644 index 00000000..13ad1a5c --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs @@ -0,0 +1,120 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class SeparatedSyntaxListExtensions + { + public static bool IsEquivalentTo(this SeparatedSyntaxList list, SeparatedSyntaxList other) + where TSyntaxNode : JassSyntaxNode + { + return list.Items.IsEquivalentTo(other.Items); + } + + public static void WriteTo(this SeparatedSyntaxList list, TextWriter writer) + where TSyntaxNode : JassSyntaxNode + { + if (list.Items.IsEmpty) + { + return; + } + + list.Items[0].WriteTo(writer); + for (var i = 1; i < list.Items.Length; i++) + { + list.Separators[i - 1].WriteTo(writer); + list.Items[i].WriteTo(writer); + } + } + + public static IEnumerable GetChildNodesAndTokens(this SeparatedSyntaxList list) + where TSyntaxNode : JassSyntaxNode + { + if (list.Items.IsEmpty) + { + yield break; + } + + yield return list.Items[0]; + for (var i = 1; i < list.Items.Length; i++) + { + yield return list.Separators[i - 1]; + yield return list.Items[i]; + } + } + + public static IEnumerable GetDescendantNodes(this SeparatedSyntaxList list) + where TSyntaxNode : JassSyntaxNode + { + return list.Items.SelectMany(syntaxNode => syntaxNode.GetDescendantNodes()); + } + + public static IEnumerable GetDescendantTokens(this SeparatedSyntaxList list) + where TSyntaxNode : JassSyntaxNode + { + if (list.Items.IsEmpty) + { + yield break; + } + + foreach (var descendant in list.Items[0].GetDescendantTokens()) + { + yield return descendant; + } + + for (var i = 1; i < list.Items.Length; i++) + { + yield return list.Separators[i - 1]; + foreach (var descendant in list.Items[i].GetDescendantTokens()) + { + yield return descendant; + } + } + } + + public static IEnumerable GetDescendantNodesAndTokens(this SeparatedSyntaxList list) + where TSyntaxNode : JassSyntaxNode + { + if (list.Items.IsEmpty) + { + yield break; + } + + foreach (var descendant in list.Items[0].GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + for (var i = 1; i < list.Items.Length; i++) + { + yield return list.Separators[i - 1]; + foreach (var descendant in list.Items[i].GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + } + + internal static SeparatedSyntaxList ReplaceFirstItem(this SeparatedSyntaxList list, TItem newItem) + { + var items = list.Items.ReplaceFirstItem(newItem); + return SeparatedSyntaxList.Create(items, list.Separators); + } + + internal static SeparatedSyntaxList ReplaceLastItem(this SeparatedSyntaxList list, TItem newItem) + { + var items = list.Items.ReplaceLastItem(newItem); + return SeparatedSyntaxList.Create(items, list.Separators); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs new file mode 100644 index 00000000..eabb9c59 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs @@ -0,0 +1,193 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class SyntaxNodeExtensions + { + public static TSyntaxNode WithLeadingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.WithLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode WithTrailingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.WithTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode AppendLeadingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTrivia trivia) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.AppendLeadingTrivia(trivia); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode AppendLeadingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.AppendLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode AppendLeadingTrivia(this TSyntaxNode syntaxNode, params JassSyntaxTrivia[] triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.AppendLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode AppendLeadingTrivia(this TSyntaxNode syntaxNode, IEnumerable triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.AppendLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode AppendLeadingTrivia(this TSyntaxNode syntaxNode, ImmutableArray triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.AppendLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode PrependLeadingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTrivia trivia) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.PrependLeadingTrivia(trivia); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode PrependLeadingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.PrependLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode PrependLeadingTrivia(this TSyntaxNode syntaxNode, params JassSyntaxTrivia[] triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.PrependLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode PrependLeadingTrivia(this TSyntaxNode syntaxNode, IEnumerable triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.PrependLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode PrependLeadingTrivia(this TSyntaxNode syntaxNode, ImmutableArray triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetFirstToken(); + var newToken = oldToken.PrependLeadingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceFirstToken(newToken); + } + + public static TSyntaxNode AppendTrailingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTrivia trivia) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.AppendTrailingTrivia(trivia); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode AppendTrailingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.AppendTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode AppendTrailingTrivia(this TSyntaxNode syntaxNode, params JassSyntaxTrivia[] triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.AppendTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode AppendTrailingTrivia(this TSyntaxNode syntaxNode, IEnumerable triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.AppendTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode AppendTrailingTrivia(this TSyntaxNode syntaxNode, ImmutableArray triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.AppendTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode PrependTrailingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTrivia trivia) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.PrependTrailingTrivia(trivia); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode PrependTrailingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.PrependTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode PrependTrailingTrivia(this TSyntaxNode syntaxNode, params JassSyntaxTrivia[] triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.PrependTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode PrependTrailingTrivia(this TSyntaxNode syntaxNode, IEnumerable triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.PrependTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + + public static TSyntaxNode PrependTrailingTrivia(this TSyntaxNode syntaxNode, ImmutableArray triviaList) + where TSyntaxNode : JassSyntaxNode + { + var oldToken = syntaxNode.GetLastToken(); + var newToken = oldToken.PrependTrailingTrivia(triviaList); + return (TSyntaxNode)syntaxNode.ReplaceLastToken(newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/TypeExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/TypeExtensions.cs index 27ef3515..d3fa07e2 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/TypeExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/TypeExtensions.cs @@ -19,22 +19,22 @@ public static JassTypeSyntax ToJassType(this Type type) var typeCode = Type.GetTypeCode(type); return typeCode switch { - TypeCode.Empty => JassTypeSyntax.Nothing, - TypeCode.Object => JassTypeSyntax.Handle, - TypeCode.Boolean => JassTypeSyntax.Boolean, - TypeCode.Char => JassTypeSyntax.Integer, - TypeCode.SByte => JassTypeSyntax.Integer, - TypeCode.Byte => JassTypeSyntax.Integer, - TypeCode.Int16 => JassTypeSyntax.Integer, - TypeCode.UInt16 => JassTypeSyntax.Integer, - TypeCode.Int32 => JassTypeSyntax.Integer, - TypeCode.UInt32 => JassTypeSyntax.Integer, - TypeCode.Int64 => JassTypeSyntax.Integer, - TypeCode.UInt64 => JassTypeSyntax.Integer, - TypeCode.Single => JassTypeSyntax.Real, - TypeCode.Double => JassTypeSyntax.Real, - TypeCode.Decimal => JassTypeSyntax.Real, - TypeCode.String => JassTypeSyntax.String, + TypeCode.Empty => JassPredefinedTypeSyntax.Nothing, + TypeCode.Object => JassPredefinedTypeSyntax.Handle, + TypeCode.Boolean => JassPredefinedTypeSyntax.Boolean, + TypeCode.Char => JassPredefinedTypeSyntax.Integer, + TypeCode.SByte => JassPredefinedTypeSyntax.Integer, + TypeCode.Byte => JassPredefinedTypeSyntax.Integer, + TypeCode.Int16 => JassPredefinedTypeSyntax.Integer, + TypeCode.UInt16 => JassPredefinedTypeSyntax.Integer, + TypeCode.Int32 => JassPredefinedTypeSyntax.Integer, + TypeCode.UInt32 => JassPredefinedTypeSyntax.Integer, + TypeCode.Int64 => JassPredefinedTypeSyntax.Integer, + TypeCode.UInt64 => JassPredefinedTypeSyntax.Integer, + TypeCode.Single => JassPredefinedTypeSyntax.Real, + TypeCode.Double => JassPredefinedTypeSyntax.Real, + TypeCode.Decimal => JassPredefinedTypeSyntax.Real, + TypeCode.String => JassPredefinedTypeSyntax.String, _ => throw new InvalidEnumArgumentException(nameof(typeCode), (int)typeCode, typeof(TypeCode)), }; diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/UnaryOperatorTypeExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/UnaryOperatorTypeExtensions.cs deleted file mode 100644 index 66dc6e8a..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/UnaryOperatorTypeExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.ComponentModel; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass.Extensions -{ - public static class UnaryOperatorTypeExtensions - { - public static string GetSymbol(this UnaryOperatorType unaryOperator) - { - return unaryOperator switch - { - UnaryOperatorType.Plus => $"{JassSymbol.PlusSign}", - UnaryOperatorType.Minus => $"{JassSymbol.MinusSign}", - UnaryOperatorType.Not => JassKeyword.Not, - - _ => throw new InvalidEnumArgumentException(nameof(unaryOperator), (int)unaryOperator, typeof(UnaryOperatorType)), - }; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser.cs index f1e678af..f5deed47 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System; + using Pidgin; using War3Net.CodeAnalysis.Jass.Syntax; @@ -19,191 +21,166 @@ internal partial class JassParser private static readonly JassParser _parser = new JassParser(); private readonly Parser _argumentListParser; - private readonly Parser _binaryOperatorParser; - private readonly Parser _commentParser; + private readonly Parser _binaryOperatorParser; private readonly Parser _compilationUnitParser; - private readonly Parser _declarationParser; - private readonly Parser _declarationLineParser; - private readonly Parser _expressionParser; - private readonly Parser _functionDeclarationParser; - private readonly Parser _globalDeclarationParser; - private readonly Parser _globalLineParser; + private readonly Parser _expressionParser; + private readonly Parser _globalDeclarationParser; private readonly Parser _identifierNameParser; - private readonly Parser _parameterListParser; - private readonly Parser _statementParser; - private readonly Parser _statementLineParser; + private readonly Parser _leadingTriviaListParser; + private readonly Parser _parameterListParser; + private readonly Parser _statementParser; + private readonly Parser _topLevelDeclarationParser; + private readonly Parser _trailingTriviaListParser; private readonly Parser _typeParser; - private readonly Parser _unaryOperatorParser; + private readonly Parser _unaryOperatorParser; private JassParser() { - var whitespaceParser = GetWhitespaceParser(); - var identifierNameParser = GetIdentifierNameParser(whitespaceParser); - var typeParser = GetTypeParser(identifierNameParser, whitespaceParser); - var expressionParser = GetExpressionParser(whitespaceParser, identifierNameParser); - var equalsValueClauseParser = GetEqualsValueClauseParser(whitespaceParser, expressionParser); - - var argumentListParser = GetArgumentListParser(whitespaceParser, expressionParser); - var parameterListParser = GetParameterListParser(whitespaceParser, GetParameterParser(identifierNameParser, typeParser)); - var functionDeclaratorParser = GetFunctionDeclaratorParser(identifierNameParser, parameterListParser, typeParser, whitespaceParser); - var variableDeclaratorParser = GetVariableDeclaratorParser(equalsValueClauseParser, identifierNameParser, typeParser, whitespaceParser); - - var commentStringParser = GetCommentStringParser(); - var newLineParser = GetNewLineParser(whitespaceParser); - var endOfLineParser = GetEndOfLineParser(commentStringParser, newLineParser); - var emptyParser = GetEmptyParser(); - var emptyLineParser = GetEmptyLineParser(); - var commentParser = GetCommentParser(commentStringParser); - - var setStatementParser = GetSetStatementParser(whitespaceParser, expressionParser, equalsValueClauseParser, identifierNameParser); - var callStatementParser = GetCallStatementParser(whitespaceParser, argumentListParser, identifierNameParser); - var exitStatementParser = GetExitStatementParser(expressionParser, whitespaceParser); - var localVariableDeclarationStatementParser = GetLocalVariableDeclarationStatementParser(variableDeclaratorParser, whitespaceParser); - var returnStatementParser = GetReturnStatementParser(expressionParser, whitespaceParser); + var whitespaceTriviaParser = GetWhitespaceTriviaParser(); + var newlineTriviaParser = GetNewlineTriviaParser(); + var singleNewlineTriviaParser = GetSingleNewlineTriviaParser(); + var singleLineCommentTriviaParser = GetSingleLineCommentTriviaParser(); + + var simpleTriviaListParser = GetSimpleTriviaListParser( + whitespaceTriviaParser); + + var leadingTriviaListParser = GetLeadingTriviaListParser( + whitespaceTriviaParser, + newlineTriviaParser, + singleLineCommentTriviaParser); + + var trailingTriviaListParser = GetTrailingTriviaListParser( + whitespaceTriviaParser, + singleNewlineTriviaParser, + singleLineCommentTriviaParser); + + var identifierParser = GetIdentifierParser(); + var identifierNameParser = GetIdentifierNameParser(identifierParser, simpleTriviaListParser); + var typeParser = GetTypeParser(identifierParser, simpleTriviaListParser); + + var expressionParser = GetExpressionParser(identifierParser, identifierNameParser, simpleTriviaListParser); + var equalsValueClauseParser = GetEqualsValueClauseParser(simpleTriviaListParser, expressionParser); + + var parameterParser = GetParameterParser(identifierNameParser, typeParser); + var parameterListParser = GetParameterListParser(simpleTriviaListParser, parameterParser); + var argumentListParser = GetArgumentListParser(simpleTriviaListParser, expressionParser); + var returnClauseParser = GetReturnClauseParser(typeParser, simpleTriviaListParser); + var functionDeclaratorParser = GetFunctionDeclaratorParser(identifierNameParser, parameterListParser, returnClauseParser, simpleTriviaListParser, trailingTriviaListParser); + var variableOrArrayDeclaratorParser = GetVariableOrArrayDeclaratorParser(equalsValueClauseParser, identifierNameParser, typeParser, simpleTriviaListParser); + var elementAccessClauseParser = GetElementAccessClauseParser(simpleTriviaListParser, expressionParser); + + var setStatementParser = GetSetStatementParser(identifierNameParser, elementAccessClauseParser, equalsValueClauseParser, simpleTriviaListParser, trailingTriviaListParser); + var callStatementParser = GetCallStatementParser(identifierNameParser, argumentListParser, simpleTriviaListParser, trailingTriviaListParser); + var exitStatementParser = GetExitStatementParser(expressionParser, simpleTriviaListParser, trailingTriviaListParser); + var localVariableDeclarationStatementParser = GetLocalVariableDeclarationStatementParser(variableOrArrayDeclaratorParser, simpleTriviaListParser, trailingTriviaListParser); + var returnStatementParser = GetReturnStatementParser(expressionParser, simpleTriviaListParser, trailingTriviaListParser); + + var ifClauseDeclaratorParser = GetIfClauseDeclaratorParser(expressionParser, simpleTriviaListParser, trailingTriviaListParser); + var elseIfClauseDeclaratorParser = GetElseIfClauseDeclaratorParser(expressionParser, simpleTriviaListParser, trailingTriviaListParser); var statementParser = GetStatementParser( - emptyParser, - commentParser, localVariableDeclarationStatementParser, exitStatementParser, returnStatementParser, setStatementParser, callStatementParser, - expressionParser, - whitespaceParser, - endOfLineParser); - - var statementLineParser = GetStatementLineParser( - emptyLineParser, - commentParser, - localVariableDeclarationStatementParser, - setStatementParser, - callStatementParser, - exitStatementParser, - returnStatementParser, - expressionParser, - whitespaceParser); + ifClauseDeclaratorParser, + elseIfClauseDeclaratorParser, + simpleTriviaListParser, + leadingTriviaListParser, + trailingTriviaListParser); - var constantDeclarationParser = GetConstantDeclarationParser( + var globalConstantDeclarationParser = GetGlobalConstantDeclarationParser( equalsValueClauseParser, identifierNameParser, typeParser, - whitespaceParser); + simpleTriviaListParser, + trailingTriviaListParser); - var variableDeclarationParser = GetVariableDeclarationParser( - equalsValueClauseParser, - identifierNameParser, - typeParser, - whitespaceParser); + var globalVariableDeclarationParser = GetGlobalVariableDeclarationParser( + variableOrArrayDeclaratorParser, + trailingTriviaListParser); var globalDeclarationParser = GetGlobalDeclarationParser( - emptyParser, - commentParser, - constantDeclarationParser, - variableDeclarationParser); - - var globalLineParser = GetGlobalLineParser( - emptyLineParser, - commentParser, - constantDeclarationParser, - variableDeclarationParser, - whitespaceParser); - - var statementListParser = GetStatementListParser( - statementParser, - endOfLineParser); + globalConstantDeclarationParser, + globalVariableDeclarationParser); var functionDeclarationParser = GetFunctionDeclarationParser( functionDeclaratorParser, - statementListParser, - whitespaceParser, - endOfLineParser); + statementParser, + leadingTriviaListParser, + trailingTriviaListParser); var typeDeclarationParser = GetTypeDeclarationParser( identifierNameParser, typeParser, - whitespaceParser); + simpleTriviaListParser, + trailingTriviaListParser); var nativeFunctionDeclarationParser = GetNativeFunctionDeclarationParser( - functionDeclaratorParser, - whitespaceParser); + identifierNameParser, + parameterListParser, + returnClauseParser, + simpleTriviaListParser, + trailingTriviaListParser); - var declarationParser = GetDeclarationParser( - emptyParser, - commentParser, + var topLevelDeclarationParser = GetTopLevelDeclarationParser( typeDeclarationParser, nativeFunctionDeclarationParser, functionDeclarationParser, - globalDeclarationParser.Before(endOfLineParser), - whitespaceParser, - endOfLineParser); - - var declarationLineParser = GetDeclarationLineParser( - emptyLineParser, - commentParser, - typeDeclarationParser, - nativeFunctionDeclarationParser, - functionDeclaratorParser, - whitespaceParser); + globalDeclarationParser, + simpleTriviaListParser, + leadingTriviaListParser, + trailingTriviaListParser); var compilationUnitParser = GetCompilationUnitParser( - declarationParser, - commentStringParser, - newLineParser); + topLevelDeclarationParser, + leadingTriviaListParser); - Parser Create(Parser parser) => whitespaceParser.Then(parser).Before(End); + Parser Create(Parser parser) => simpleTriviaListParser.Then(parser).Before(End); _argumentListParser = Create(argumentListParser); - _binaryOperatorParser = Create(GetBinaryOperatorParser(whitespaceParser)); - _commentParser = Create(commentParser); + _binaryOperatorParser = Create(GetBinaryOperatorParser(simpleTriviaListParser)); _compilationUnitParser = Create(compilationUnitParser); - _declarationParser = Create(declarationParser); - _declarationLineParser = Create(declarationLineParser); _expressionParser = Create(expressionParser); - _functionDeclarationParser = Create(functionDeclarationParser); _globalDeclarationParser = Create(globalDeclarationParser); - _globalLineParser = Create(globalLineParser); _identifierNameParser = Create(identifierNameParser); + _leadingTriviaListParser = leadingTriviaListParser.Before(End); _parameterListParser = Create(parameterListParser); _statementParser = Create(statementParser); - _statementLineParser = Create(statementLineParser.Before(commentStringParser.Optional())); + _topLevelDeclarationParser = Create(topLevelDeclarationParser); + _trailingTriviaListParser = trailingTriviaListParser.Before(End); _typeParser = Create(typeParser); - _unaryOperatorParser = Create(GetUnaryOperatorParser(whitespaceParser)); + _unaryOperatorParser = Create(GetUnaryOperatorParser(simpleTriviaListParser)); } internal static JassParser Instance => _parser; internal Parser ArgumentListParser => _argumentListParser; - internal Parser BinaryOperatorParser => _binaryOperatorParser; - - internal Parser CommentParser => _commentParser; + internal Parser BinaryOperatorParser => _binaryOperatorParser; internal Parser CompilationUnitParser => _compilationUnitParser; - internal Parser DeclarationParser => _declarationParser; - - internal Parser DeclarationLineParser => _declarationLineParser; - - internal Parser ExpressionParser => _expressionParser; + internal Parser ExpressionParser => _expressionParser; - internal Parser FunctionDeclarationParser => _functionDeclarationParser; + internal Parser GlobalDeclarationParser => _globalDeclarationParser; - internal Parser GlobalDeclarationParser => _globalDeclarationParser; + internal Parser IdentifierNameParser => _identifierNameParser; - internal Parser GlobalLineParser => _globalLineParser; + internal Parser LeadingTriviaListParser => _leadingTriviaListParser; - internal Parser IdentifierNameParser => _identifierNameParser; + internal Parser ParameterListParser => _parameterListParser; - internal Parser ParameterListParser => _parameterListParser; + internal Parser StatementParser => _statementParser; - internal Parser StatementParser => _statementParser; + internal Parser TopLevelDeclarationParser => _topLevelDeclarationParser; - internal Parser StatementLineParser => _statementLineParser; + internal Parser TrailingTriviaListParser => _trailingTriviaListParser; internal Parser TypeParser => _typeParser; - internal Parser UnaryOperatorParser => _unaryOperatorParser; + internal Parser UnaryOperatorParser => _unaryOperatorParser; private static class Keyword { @@ -298,31 +275,35 @@ private static Parser GetKeywordParser(string keyword, Parser LineFeed = Char(JassSymbol.LineFeed); - internal static readonly Parser CarriageReturn = Char(JassSymbol.CarriageReturn); - internal static readonly Parser QuotationMark = Char(JassSymbol.QuotationMark); - internal static readonly Parser DollarSign = Char(JassSymbol.DollarSign); - internal static readonly Parser Apostrophe = Char(JassSymbol.Apostrophe); - internal static readonly Parser LeftParenthesis = Char(JassSymbol.LeftParenthesis); - internal static readonly Parser RightParenthesis = Char(JassSymbol.RightParenthesis); - internal static readonly Parser Asterisk = Char(JassSymbol.Asterisk); - internal static readonly Parser PlusSign = Char(JassSymbol.PlusSign); - internal static readonly Parser Comma = Char(JassSymbol.Comma); - internal static readonly Parser MinusSign = Char(JassSymbol.MinusSign); - internal static readonly Parser FullStop = Char(JassSymbol.FullStop); - internal static readonly Parser Slash = Char(JassSymbol.Slash); - internal static readonly Parser Zero = Char(JassSymbol.Zero); - internal static readonly Parser LessThanSign = Char(JassSymbol.LessThanSign); - internal static readonly Parser EqualsSign = Char(JassSymbol.EqualsSign); - internal static readonly Parser GreaterThanSign = Char(JassSymbol.GreaterThanSign); - internal static readonly Parser LeftSquareBracket = Char(JassSymbol.LeftSquareBracket); - internal static readonly Parser RightSquareBracket = Char(JassSymbol.RightSquareBracket); - internal static readonly Parser X = CIChar(JassSymbol.X); - - internal static readonly Parser EqualsEquals = String($"{JassSymbol.EqualsSign}{JassSymbol.EqualsSign}"); - internal static readonly Parser LessOrEquals = String($"{JassSymbol.LessThanSign}{JassSymbol.EqualsSign}"); - internal static readonly Parser GreaterOrEquals = String($"{JassSymbol.GreaterThanSign}{JassSymbol.EqualsSign}"); - internal static readonly Parser NotEquals = String($"{JassSymbol.ExclamationMark}{JassSymbol.EqualsSign}"); + internal static readonly Parser LineFeed = Char(JassSymbol.LineFeedChar); + internal static readonly Parser CarriageReturn = Char(JassSymbol.CarriageReturnChar); + internal static readonly Parser DoubleQuote = Char(JassSymbol.DoubleQuoteChar); + internal static readonly Parser Dollar = Char(JassSymbol.DollarChar); + internal static readonly Parser SingleQuote = Char(JassSymbol.SingleQuoteChar); + internal static readonly Parser OpenParen = Char(JassSymbol.OpenParenChar); + internal static readonly Parser CloseParen = Char(JassSymbol.CloseParenChar); + internal static readonly Parser Asterisk = Char(JassSymbol.AsteriskChar); + internal static readonly Parser Plus = Char(JassSymbol.PlusChar); + internal static readonly Parser Comma = Char(JassSymbol.CommaChar); + internal static readonly Parser Minus = Char(JassSymbol.MinusChar); + internal static readonly Parser Dot = Char(JassSymbol.DotChar); + internal static readonly Parser Slash = Char(JassSymbol.SlashChar); + internal static readonly Parser Zero = Char(JassSymbol.ZeroChar); + internal static readonly Parser LessThan = Char(JassSymbol.LessThanChar); + internal static new readonly Parser Equals = Char(JassSymbol.EqualsChar); + internal static readonly Parser GreaterThan = Char(JassSymbol.GreaterThanChar); + internal static readonly Parser OpenBracket = Char(JassSymbol.OpenBracketChar); + internal static readonly Parser CloseBracket = Char(JassSymbol.CloseBracketChar); + internal static readonly Parser X = CIChar(JassSymbol.XChar); + + internal static readonly Parser CarriageReturnLineFeed = String(JassSymbol.CarriageReturnLineFeed); + internal static readonly Parser CarriageReturnString = String(JassSymbol.CarriageReturn); + internal static readonly Parser LineFeedString = String(JassSymbol.LineFeed); + internal static readonly Parser EqualsEquals = String(JassSymbol.EqualsEquals); + internal static readonly Parser LessThanEquals = String(JassSymbol.LessThanEquals); + internal static readonly Parser GreaterThanEquals = String(JassSymbol.GreaterThanEquals); + internal static readonly Parser ExclamationEquals = String(JassSymbol.ExclamationEquals); + internal static readonly Parser SlashSlash = String(JassSymbol.SlashSlash); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ArgumentListParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ArgumentListParser.cs new file mode 100644 index 00000000..9e90566d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ArgumentListParser.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetArgumentListParser( + Parser triviaParser, + Parser expressionParser) + { + return Map( + (openParenToken, argumentList, closeParenToken) => new JassArgumentListSyntax( + openParenToken, + argumentList, + closeParenToken), + Symbol.OpenParen.AsToken(triviaParser, JassSyntaxKind.OpenParenToken, JassSymbol.OpenParen), + expressionParser.SeparatedList(Symbol.Comma.AsToken(triviaParser, JassSyntaxKind.CommaToken, JassSymbol.Comma)), + Symbol.CloseParen.AsToken(triviaParser, JassSyntaxKind.CloseParenToken, JassSymbol.CloseParen)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/BinaryOperatorParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/BinaryOperatorParser.cs new file mode 100644 index 00000000..2e8d81f3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/BinaryOperatorParser.cs @@ -0,0 +1,109 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetBinaryOperatorParser( + Parser triviaParser) + { + return OneOf( + GetBinaryAddOperatorParser(triviaParser), + GetBinarySubtractOperatorParser(triviaParser), + GetBinaryMultiplicationOperatorParser(triviaParser), + GetBinaryDivisionOperatorParser(triviaParser), + GetBinaryGreaterOrEqualOperatorParser(triviaParser), + GetBinaryLessOrEqualOperatorParser(triviaParser), + GetBinaryEqualsOperatorParser(triviaParser), + GetBinaryNotEqualsOperatorParser(triviaParser), + GetBinaryGreaterThanOperatorParser(triviaParser), + GetBinaryLessThanOperatorParser(triviaParser), + GetBinaryAndOperatorParser(triviaParser), + GetBinaryOrOperatorParser(triviaParser)); + } + + internal static Parser GetBinaryAddOperatorParser( + Parser triviaParser) + { + return Symbol.Plus.AsToken(triviaParser, JassSyntaxKind.PlusToken, JassSymbol.Plus); + } + + internal static Parser GetBinarySubtractOperatorParser( + Parser triviaParser) + { + return Symbol.Minus.AsToken(triviaParser, JassSyntaxKind.MinusToken, JassSymbol.Minus); + } + + internal static Parser GetBinaryMultiplicationOperatorParser( + Parser triviaParser) + { + return Symbol.Asterisk.AsToken(triviaParser, JassSyntaxKind.AsteriskToken, JassSymbol.Asterisk); + } + + internal static Parser GetBinaryDivisionOperatorParser( + Parser triviaParser) + { + return Try(Symbol.Slash.Before(Not(Lookahead(Symbol.Slash)))).AsToken(triviaParser, JassSyntaxKind.SlashToken, JassSymbol.Slash); + } + + internal static Parser GetBinaryGreaterOrEqualOperatorParser( + Parser triviaParser) + { + return Try(Symbol.GreaterThanEquals).AsToken(triviaParser, JassSyntaxKind.GreaterThanEqualsToken); + } + + internal static Parser GetBinaryLessOrEqualOperatorParser( + Parser triviaParser) + { + return Try(Symbol.LessThanEquals).AsToken(triviaParser, JassSyntaxKind.LessThanEqualsToken); + } + + internal static Parser GetBinaryEqualsOperatorParser( + Parser triviaParser) + { + return Symbol.EqualsEquals.AsToken(triviaParser, JassSyntaxKind.EqualsEqualsToken); + } + + internal static Parser GetBinaryNotEqualsOperatorParser( + Parser triviaParser) + { + return Symbol.ExclamationEquals.AsToken(triviaParser, JassSyntaxKind.ExclamationEqualsToken); + } + + internal static Parser GetBinaryGreaterThanOperatorParser( + Parser triviaParser) + { + return Symbol.GreaterThan.AsToken(triviaParser, JassSyntaxKind.GreaterThanToken, JassSymbol.GreaterThan); + } + + internal static Parser GetBinaryLessThanOperatorParser( + Parser triviaParser) + { + return Symbol.LessThan.AsToken(triviaParser, JassSyntaxKind.LessThanToken, JassSymbol.LessThan); + } + + internal static Parser GetBinaryAndOperatorParser( + Parser triviaParser) + { + return Keyword.And.AsToken(triviaParser, JassSyntaxKind.AndKeyword); + } + + internal static Parser GetBinaryOrOperatorParser( + Parser triviaParser) + { + return Keyword.Or.AsToken(triviaParser, JassSyntaxKind.OrKeyword); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/CallStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/CallStatementParser.cs new file mode 100644 index 00000000..fd86241f --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/CallStatementParser.cs @@ -0,0 +1,36 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetCallStatementParser( + Parser identifierNameParser, + Parser argumentListParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (callToken, identifierName, argumentList, trailingTrivia) => (JassStatementSyntax)new JassCallStatementSyntax( + callToken, + identifierName, + argumentList.AppendTrailingTrivia(trailingTrivia)), + Keyword.Call.AsToken(triviaParser, JassSyntaxKind.CallKeyword), + identifierNameParser, + argumentListParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/CharacterLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/CharacterLiteralExpressionParser.cs similarity index 53% rename from src/War3Net.CodeAnalysis.Jass/Parser/CharacterLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/CharacterLiteralExpressionParser.cs index e6e0d5b5..18afaaf2 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/CharacterLiteralExpressionParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/CharacterLiteralExpressionParser.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -15,11 +15,12 @@ namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser { - internal static Parser GetCharacterLiteralExpressionParser() + internal static Parser GetCharacterLiteralExpressionParser( + Parser triviaParser) { var escapeCharacterParser = OneOf( - Symbol.QuotationMark.ThenReturn(JassSymbol.QuotationMark), - Symbol.Apostrophe.ThenReturn(JassSymbol.Apostrophe), + Symbol.DoubleQuote, + Symbol.SingleQuote, Char('r').ThenReturn('\r'), Char('n').ThenReturn('\n'), Char('t').ThenReturn('\t'), @@ -27,8 +28,12 @@ internal static Parser GetCharacterLiteralExpressionPar Char('f').ThenReturn('\f'), Char('\\').ThenReturn('\\')); - return Try(Char('\\').Then(escapeCharacterParser).Or(AnyCharExcept(JassSymbol.Apostrophe)).Between(Symbol.Apostrophe)) - .Select(value => new JassCharacterLiteralExpressionSyntax(value)) + return Map( + (value, trivia) => (JassExpressionSyntax)new JassLiteralExpressionSyntax(new JassSyntaxToken(JassSyntaxKind.CharacterLiteralToken, $"'{value}'", trivia)), + Try(OneOf( + Char('\\').Then(escapeCharacterParser), + AnyCharExcept(JassSymbol.SingleQuoteChar)).Between(Symbol.SingleQuote)), + triviaParser) .Labelled("character literal"); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/CompilationUnitParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/CompilationUnitParser.cs new file mode 100644 index 00000000..b1685921 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/CompilationUnitParser.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetCompilationUnitParser( + Parser declarationParser, + Parser leadingTriviaParser) + { + return declarationParser.UntilWithLeading( + leadingTriviaParser, + leadingTriviaParser, + End, + (leadingTrivia, declaration) => declaration.WithLeadingTrivia(leadingTrivia), + (firstTrivia, declarations, lastTrivia, _) => new JassCompilationUnitSyntax( + declarations.ToImmutableArray(), + new JassSyntaxToken(lastTrivia, JassSyntaxKind.EndOfFileToken, string.Empty, JassSyntaxTriviaList.Empty)).WithLeadingTrivia(firstTrivia)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs new file mode 100644 index 00000000..5431dbda --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetDebugStatementParser( + Parser setStatementParser, + Parser callStatementParser, + Parser ifStatementParser, + Parser loopStatementParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (debugToken, statement, trailingTrivia) => (JassStatementSyntax)new JassDebugStatementSyntax( + debugToken, + statement.AppendTrailingTrivia(trailingTrivia)), + Keyword.Debug.AsToken(triviaParser, JassSyntaxKind.DebugKeyword), + OneOf( + setStatementParser, + callStatementParser, + ifStatementParser, + loopStatementParser), + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/DecimalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/DecimalLiteralExpressionParser.cs similarity index 52% rename from src/War3Net.CodeAnalysis.Jass/Parser/DecimalLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/DecimalLiteralExpressionParser.cs index cdae40e6..69c4e3f8 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/DecimalLiteralExpressionParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/DecimalLiteralExpressionParser.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -7,6 +7,7 @@ using Pidgin; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; using static Pidgin.Parser; @@ -15,10 +16,13 @@ namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser { - internal static Parser GetDecimalLiteralExpressionParser() + internal static Parser GetDecimalLiteralExpressionParser( + Parser triviaParser) { return Try(UnsignedInt(10)) - .Select(value => new JassDecimalLiteralExpressionSyntax(value)) + .MapWithInput((s, _) => s.ToString()) + .AsToken(triviaParser, JassSyntaxKind.DecimalLiteralToken) + .Map(token => (JassExpressionSyntax)new JassLiteralExpressionSyntax(token)) .Labelled("decimal literal"); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ElementAccessClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ElementAccessClauseParser.cs new file mode 100644 index 00000000..8676021e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ElementAccessClauseParser.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetElementAccessClauseParser( + Parser triviaParser, + Parser expressionParser) + { + return Map( + (openBracketToken, expression, closeBracketToken) => new JassElementAccessClauseSyntax( + openBracketToken, + expression, + closeBracketToken), + Symbol.OpenBracket.AsToken(triviaParser, JassSyntaxKind.OpenBracketToken, JassSymbol.OpenBracket), + expressionParser, + Symbol.CloseBracket.AsToken(triviaParser, JassSyntaxKind.CloseBracketToken, JassSymbol.CloseBracket)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ElseIfClauseDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ElseIfClauseDeclaratorParser.cs new file mode 100644 index 00000000..2a5a8572 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ElseIfClauseDeclaratorParser.cs @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetElseIfClauseDeclaratorParser( + Parser expressionParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (elseIfToken, condition, thenToken) => new JassElseIfClauseDeclaratorSyntax( + elseIfToken, + condition, + thenToken), + Keyword.ElseIf.AsToken(triviaParser, JassSyntaxKind.ElseIfKeyword), + expressionParser, + Keyword.Then.AsToken(trailingTriviaParser, JassSyntaxKind.ThenKeyword)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/EqualsValueClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/EqualsValueClauseParser.cs new file mode 100644 index 00000000..f7f0514d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/EqualsValueClauseParser.cs @@ -0,0 +1,31 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetEqualsValueClauseParser( + Parser triviaParser, + Parser expressionParser) + { + return Map( + (equalsToken, expression) => new JassEqualsValueClauseSyntax( + equalsToken, + expression), + Symbol.Equals.AsToken(triviaParser, JassSyntaxKind.EqualsToken, JassSymbol.Equals), + expressionParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ExitStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ExitStatementParser.cs new file mode 100644 index 00000000..d63d5a70 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ExitStatementParser.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetExitStatementParser( + Parser expressionParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (exitWhenToken, expression, trailingTrivia) => (JassStatementSyntax)new JassExitStatementSyntax( + exitWhenToken, + expression.AppendTrailingTrivia(trailingTrivia)), + Keyword.ExitWhen.AsToken(triviaParser, JassSyntaxKind.ExitWhenKeyword), + expressionParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ExpressionParser.cs new file mode 100644 index 00000000..bbc21815 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ExpressionParser.cs @@ -0,0 +1,68 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; +using Pidgin.Expression; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Parsers; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetExpressionParser( + Parser identifierParser, + Parser identifierNameParser, + Parser triviaParser) + { + return Pidgin.Expression.ExpressionParser.Build( + expressionParser => + { + var argumentListParser = GetArgumentListParser(triviaParser, expressionParser); + var elementAccessClauseParser = GetElementAccessClauseParser(triviaParser, expressionParser); + + return (OneOf( + GetCharacterLiteralExpressionParser(triviaParser), + GetFourCCLiteralExpressionParser(triviaParser), + GetHexadecimalLiteralExpressionParser(triviaParser), + GetRealLiteralExpressionParser(triviaParser), + GetOctalLiteralExpressionParser(triviaParser), + GetDecimalLiteralExpressionParser(triviaParser), + GetStringLiteralExpressionParser(triviaParser), + new IdentifierExpressionParser( + identifierParser, + identifierNameParser, + argumentListParser, + elementAccessClauseParser, + triviaParser), + GetParenthesizedExpressionParser(triviaParser, expressionParser)), + new[] + { + // https://www.hiveworkshop.com/threads/precedence-in-jass.43500/#post-378439 + Operator.PrefixChainable(GetUnaryNotOperatorParser(triviaParser).Prefix()), + Operator.PrefixChainable(GetUnaryPlusOperatorParser(triviaParser).Prefix(), GetUnaryMinusOperatorParser(triviaParser).Prefix()), + Operator.InfixL(GetBinaryMultiplicationOperatorParser(triviaParser).Infix()) + .And(Operator.InfixL(GetBinaryDivisionOperatorParser(triviaParser).Infix())), + Operator.InfixL(GetBinaryAddOperatorParser(triviaParser).Infix()) + .And(Operator.InfixL(GetBinarySubtractOperatorParser(triviaParser).Infix())), + Operator.InfixL(GetBinaryGreaterOrEqualOperatorParser(triviaParser).Infix()) + .And(Operator.InfixL(GetBinaryLessOrEqualOperatorParser(triviaParser).Infix())) + .And(Operator.InfixL(GetBinaryEqualsOperatorParser(triviaParser).Infix())) + .And(Operator.InfixL(GetBinaryNotEqualsOperatorParser(triviaParser).Infix())) + .And(Operator.InfixL(GetBinaryGreaterThanOperatorParser(triviaParser).Infix())) + .And(Operator.InfixL(GetBinaryLessThanOperatorParser(triviaParser).Infix())), + Operator.InfixL(GetBinaryAndOperatorParser(triviaParser).Infix()) + .And(Operator.InfixL(GetBinaryOrOperatorParser(triviaParser).Infix())), + }); + }); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/FourCCLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/FourCCLiteralExpressionParser.cs similarity index 51% rename from src/War3Net.CodeAnalysis.Jass/Parser/FourCCLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/FourCCLiteralExpressionParser.cs index 0b3191c5..94b5cd84 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/FourCCLiteralExpressionParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/FourCCLiteralExpressionParser.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -16,11 +16,14 @@ namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser { - internal static Parser GetFourCCLiteralExpressionParser() + internal static Parser GetFourCCLiteralExpressionParser( + Parser triviaParser) { - return Symbol.Apostrophe.Then(AnyCharExcept(JassSymbol.Apostrophe).ManyString()).Before(Symbol.Apostrophe) + return Symbol.SingleQuote.Then(AnyCharExcept(JassSymbol.SingleQuoteChar).ManyString()).Before(Symbol.SingleQuote) .Assert(value => value.IsJassRawcode()) - .Select(value => new JassFourCCLiteralExpressionSyntax(value.FromJassRawcode())) + .MapWithInput((s, _) => s.ToString()) + .AsToken(triviaParser, JassSyntaxKind.FourCCLiteralToken) + .Map(token => (JassExpressionSyntax)new JassLiteralExpressionSyntax(token)) .Labelled("fourCC literal"); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclarationParser.cs new file mode 100644 index 00000000..b428ffd0 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclarationParser.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser, JassTopLevelDeclarationSyntax>> GetFunctionDeclarationParser( + Parser, JassFunctionDeclaratorSyntax>> functionDeclaratorParser, + Parser statementParser, + Parser leadingTriviaParser, + Parser trailingTriviaParser) + { + return statementParser.UntilWithLeading, JassFunctionDeclaratorSyntax>, JassStatementSyntax, JassSyntaxToken, Func, JassTopLevelDeclarationSyntax>>( + leadingTriviaParser, + functionDeclaratorParser, + Keyword.EndFunction.AsToken(trailingTriviaParser, JassSyntaxKind.EndFunctionKeyword), + (leadingTrivia, statement) => statement.WithLeadingTrivia(leadingTrivia), + (declaratorFunc, statements, leadingTrivia, endFunctionToken) => constantToken => new JassFunctionDeclarationSyntax( + declaratorFunc(constantToken), + statements.ToImmutableArray(), + endFunctionToken.WithLeadingTrivia(leadingTrivia))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclaratorParser.cs new file mode 100644 index 00000000..ec7ba2df --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclaratorParser.cs @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser, JassFunctionDeclaratorSyntax>> GetFunctionDeclaratorParser( + Parser identifierNameParser, + Parser parameterListParser, + Parser returnClauseParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map, JassFunctionDeclaratorSyntax>>( + (functionToken, identifierName, parameterList, returnClause, trailingTrivia) => constantToken => new JassFunctionDeclaratorSyntax( + constantToken.GetValueOrDefault(), + functionToken, + identifierName, + parameterList, + returnClause.AppendTrailingTrivia(trailingTrivia)), + Keyword.Function.AsToken(triviaParser, JassSyntaxKind.FunctionKeyword), + identifierNameParser, + parameterListParser, + returnClauseParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalConstantDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalConstantDeclarationParser.cs new file mode 100644 index 00000000..b7401b7b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalConstantDeclarationParser.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetGlobalConstantDeclarationParser( + Parser equalsValueClauseParser, + Parser identifierNameParser, + Parser typeParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (constantToken, type, identifierName, value, trailingTrivia) => (JassGlobalDeclarationSyntax)new JassGlobalConstantDeclarationSyntax( + constantToken, + type, + identifierName, + value.AppendTrailingTrivia(trailingTrivia)), + Keyword.Constant.AsToken(triviaParser, JassSyntaxKind.ConstantKeyword), + typeParser, + identifierNameParser, + equalsValueClauseParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalDeclarationParser.cs new file mode 100644 index 00000000..009143f6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalDeclarationParser.cs @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetGlobalDeclarationParser( + Parser globalConstantDeclarationParser, + Parser globalVariableDeclarationParser) + { + return OneOf( + globalConstantDeclarationParser, + globalVariableDeclarationParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalVariableDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalVariableDeclarationParser.cs new file mode 100644 index 00000000..dfa3bb4b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalVariableDeclarationParser.cs @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetGlobalVariableDeclarationParser( + Parser variableOrArrayDeclaratorParser, + Parser trailingTriviaParser) + { + return Map( + (declarator, trailingTrivia) => (JassGlobalDeclarationSyntax)new JassGlobalVariableDeclarationSyntax(declarator.AppendTrailingTrivia(trailingTrivia)), + variableOrArrayDeclaratorParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalsDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalsDeclarationParser.cs new file mode 100644 index 00000000..04413f9c --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalsDeclarationParser.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetGlobalsDeclarationParser( + Parser globalDeclarationParser, + Parser leadingTriviaParser, + Parser trailingTriviaParser) + { + return globalDeclarationParser.UntilWithLeading( + leadingTriviaParser, + Keyword.Globals.AsToken(trailingTriviaParser, JassSyntaxKind.GlobalsKeyword), + Keyword.EndGlobals.AsToken(trailingTriviaParser, JassSyntaxKind.EndGlobalsKeyword), + (leadingTrivia, global) => global.WithLeadingTrivia(leadingTrivia), + (globalsToken, globalDeclarations, leadingTrivia, endGlobalsToken) => (JassTopLevelDeclarationSyntax)new JassGlobalsDeclarationSyntax( + globalsToken, + globalDeclarations.ToImmutableArray(), + endGlobalsToken.WithLeadingTrivia(leadingTrivia))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/HexadecimalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/HexadecimalLiteralExpressionParser.cs new file mode 100644 index 00000000..bc4f86b9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/HexadecimalLiteralExpressionParser.cs @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetHexadecimalLiteralExpressionParser( + Parser triviaParser) + { + return Symbol.Dollar.Or(Try(Symbol.Zero.Then(Symbol.X))).Then(UnsignedInt(16)) + .MapWithInput((s, _) => s.ToString()) + .AsToken(triviaParser, JassSyntaxKind.HexadecimalLiteralToken) + .Map(token => (JassExpressionSyntax)new JassLiteralExpressionSyntax(token)) + .Labelled("hexadecimal literal"); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/IdentifierNameParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/IdentifierNameParser.cs similarity index 59% rename from src/War3Net.CodeAnalysis.Jass/Parser/IdentifierNameParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/IdentifierNameParser.cs index 6ad7e44b..9a93c30a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/IdentifierNameParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/IdentifierNameParser.cs @@ -7,6 +7,7 @@ using Pidgin; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; using static Pidgin.Parser; @@ -16,13 +17,19 @@ namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser { - internal static Parser GetIdentifierNameParser(Parser whitespaceParser) + internal static Parser GetIdentifierParser() { return Try(Token(c => char.IsLetterOrDigit(c) || c == '_').AtLeastOnceString().Assert(value => !char.IsDigit(value[0]))) - .Then(value => JassSyntaxFacts.IsValidIdentifier(value) && !JassKeyword.IsKeyword(value) - ? Return(new JassIdentifierNameSyntax(value)) - : Fail($"'{value}' is not a valid identifier name")) - .Before(whitespaceParser) + .Assert(JassSyntaxFacts.IsValidIdentifier, value => $"'{value}' is not a valid identifier name"); + } + + internal static Parser GetIdentifierNameParser( + Parser identifierParser, + Parser triviaParser) + { + return identifierParser + .AsToken(triviaParser, JassSyntaxKind.IdentifierToken) + .Map(token => new JassIdentifierNameSyntax(token)) .Labelled("identifier name"); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/IfClauseDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/IfClauseDeclaratorParser.cs new file mode 100644 index 00000000..89c446a4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/IfClauseDeclaratorParser.cs @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetIfClauseDeclaratorParser( + Parser expressionParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (ifToken, condition, thenToken) => new JassIfClauseDeclaratorSyntax( + ifToken, + condition, + thenToken), + Keyword.If.AsToken(triviaParser, JassSyntaxKind.IfKeyword), + expressionParser, + Keyword.Then.AsToken(trailingTriviaParser, JassSyntaxKind.ThenKeyword)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/IfStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/IfStatementParser.cs new file mode 100644 index 00000000..e5dc442d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/IfStatementParser.cs @@ -0,0 +1,45 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetIfStatementParser( + Parser statementParser, + Parser ifClauseDeclaratorParser, + Parser elseIfClauseDeclaratorParser, + Parser leadingTriviaParser, + Parser trailingTriviaParser) + { + return statementParser.IfThenElse( + leadingTriviaParser, + ifClauseDeclaratorParser, + elseIfClauseDeclaratorParser, + Keyword.Else.AsToken(trailingTriviaParser, JassSyntaxKind.ElseKeyword), + Keyword.EndIf.AsToken(trailingTriviaParser, JassSyntaxKind.EndIfKeyword), + (declarator, statements) => new JassIfClauseSyntax(declarator, statements.ToImmutableArray()), + (declarator, statements) => new JassElseIfClauseSyntax(declarator, statements.ToImmutableArray()), + (elseToken, statements) => new JassElseClauseSyntax(elseToken, statements.ToImmutableArray()), + (trivia, statement) => statement.WithLeadingTrivia(trivia), + (trivia, elseIfDeclarator) => elseIfDeclarator.WithLeadingTrivia(trivia), + (trivia, elseDeclarator) => elseDeclarator.WithLeadingTrivia(trivia), + (ifClause, elseIfClauses, elseClause, trivia, endIfToken) => (JassStatementSyntax)new JassIfStatementSyntax( + ifClause, + elseIfClauses.ToImmutableArray(), + elseClause, + endIfToken.WithLeadingTrivia(trivia))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/LocalVariableDeclarationStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/LocalVariableDeclarationStatementParser.cs new file mode 100644 index 00000000..0344445e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/LocalVariableDeclarationStatementParser.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetLocalVariableDeclarationStatementParser( + Parser variableOrArrayDeclaratorParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (localToken, declarator, trailingTrivia) => (JassStatementSyntax)new JassLocalVariableDeclarationStatementSyntax( + localToken, + declarator.AppendTrailingTrivia(trailingTrivia)), + Keyword.Local.AsToken(triviaParser, JassSyntaxKind.LocalKeyword), + variableOrArrayDeclaratorParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/LoopStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/LoopStatementParser.cs new file mode 100644 index 00000000..9b2fb2ef --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/LoopStatementParser.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetLoopStatementParser( + Parser statementParser, + Parser leadingTriviaParser, + Parser trailingTriviaParser) + { + return statementParser.UntilWithLeading( + leadingTriviaParser, + Keyword.Loop.AsToken(trailingTriviaParser, JassSyntaxKind.LoopKeyword), + Keyword.EndLoop.AsToken(trailingTriviaParser, JassSyntaxKind.EndLoopKeyword), + (leadingTrivia, statement) => statement.WithLeadingTrivia(leadingTrivia), + (loopToken, statements, leadingTrivia, endLoopToken) => (JassStatementSyntax)new JassLoopStatementSyntax( + loopToken, + statements.ToImmutableArray(), + endLoopToken.WithLeadingTrivia(leadingTrivia))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/NativeFunctionDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/NativeFunctionDeclarationParser.cs new file mode 100644 index 00000000..b2fbd75e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/NativeFunctionDeclarationParser.cs @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser, JassTopLevelDeclarationSyntax>> GetNativeFunctionDeclarationParser( + Parser identifierNameParser, + Parser parameterListParser, + Parser returnClauseParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map, JassTopLevelDeclarationSyntax>>( + (nativeToken, identifierName, parameterList, returnClause, trailingTrivia) => constantToken => new JassNativeFunctionDeclarationSyntax( + constantToken.GetValueOrDefault(), + nativeToken, + identifierName, + parameterList, + returnClause.AppendTrailingTrivia(trailingTrivia)), + Keyword.Native.AsToken(triviaParser, JassSyntaxKind.NativeKeyword), + identifierNameParser, + parameterListParser, + returnClauseParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/OctalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs similarity index 53% rename from src/War3Net.CodeAnalysis.Jass/Parser/OctalLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs index c09710b4..069ec685 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/OctalLiteralExpressionParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -7,6 +7,7 @@ using Pidgin; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; using static Pidgin.Parser; @@ -15,10 +16,13 @@ namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser { - internal static Parser GetOctalLiteralExpressionParser() + internal static Parser GetOctalLiteralExpressionParser( + Parser triviaParser) { return Try(Symbol.Zero.Then(UnsignedInt(8).Optional())) - .Select(value => new JassOctalLiteralExpressionSyntax(value.GetValueOrDefault())) + .MapWithInput((s, _) => s.ToString()) + .AsToken(triviaParser, JassSyntaxKind.OctalLiteralToken) + .Map(token => (JassExpressionSyntax)new JassLiteralExpressionSyntax(token)) .Labelled("octal literal"); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterListParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterListParser.cs new file mode 100644 index 00000000..f1a0c688 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterListParser.cs @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetParameterListParser( + Parser triviaParser, + Parser parameterParser) + { + return Map( + (takesToken, parameterListFunc) => parameterListFunc(takesToken), + Keyword.Takes.AsToken(triviaParser, JassSyntaxKind.TakesKeyword), + OneOf( + Map>( + (nothingToken) => takesToken => new JassEmptyParameterListSyntax( + takesToken, + nothingToken), + Keyword.Nothing.AsToken(triviaParser, JassSyntaxKind.NothingKeyword)), + Map, Func>( + (parameterList) => takesToken => new JassParameterListSyntax( + takesToken, + parameterList), + parameterParser.SeparatedList(Symbol.Comma.AsToken(triviaParser, JassSyntaxKind.CommaToken, JassSymbol.Comma))))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ParameterParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterParser.cs similarity index 65% rename from src/War3Net.CodeAnalysis.Jass/Parser/ParameterParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/ParameterParser.cs index 09c8c669..c94f0fe5 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ParameterParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterParser.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -9,6 +9,8 @@ using War3Net.CodeAnalysis.Jass.Syntax; +using static Pidgin.Parser; + namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser @@ -17,7 +19,10 @@ internal static Parser GetParameterParser( Parser identifierNameParser, Parser typeParser) { - return typeParser.Then(identifierNameParser, (type, id) => new JassParameterSyntax(type, id)); + return Map( + (type, identifierName) => new JassParameterSyntax(type, identifierName), + typeParser, + identifierNameParser.Labelled("parameter identifier name")); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ParenthesizedExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ParenthesizedExpressionParser.cs new file mode 100644 index 00000000..f55e5aa4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ParenthesizedExpressionParser.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetParenthesizedExpressionParser( + Parser triviaParser, + Parser expressionParser) + { + return Map( + (openParenToken, expression, closeParenToken) => (JassExpressionSyntax)new JassParenthesizedExpressionSyntax( + openParenToken, + expression, + closeParenToken), + Symbol.OpenParen.AsToken(triviaParser, JassSyntaxKind.OpenParenToken, JassSymbol.OpenParen), + expressionParser, + Symbol.CloseParen.AsToken(triviaParser, JassSyntaxKind.CloseParenToken, JassSymbol.CloseParen)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/RealLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/RealLiteralExpressionParser.cs new file mode 100644 index 00000000..982a42a6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/RealLiteralExpressionParser.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetRealLiteralExpressionParser( + Parser triviaParser) + { + return OneOf( + Try(Token(char.IsDigit).AtLeastOnce().Before(Symbol.Dot)).Then(Token(char.IsDigit).Many()), + Symbol.Dot.Then(Token(char.IsDigit).AtLeastOnce())) + .MapWithInput((s, _) => s.ToString()) + .AsToken(triviaParser, JassSyntaxKind.RealLiteralToken) + .Map(token => (JassExpressionSyntax)new JassLiteralExpressionSyntax(token)) + .Labelled("real literal"); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnClauseParser.cs new file mode 100644 index 00000000..b064cfcf --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnClauseParser.cs @@ -0,0 +1,31 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetReturnClauseParser( + Parser typeParser, + Parser triviaParser) + { + return Map( + (returnsToken, type) => new JassReturnClauseSyntax( + returnsToken, + type), + Keyword.Returns.AsToken(triviaParser, JassSyntaxKind.ReturnsKeyword), + typeParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnStatementParser.cs new file mode 100644 index 00000000..678774a9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnStatementParser.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetReturnStatementParser( + Parser expressionParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (returnToken, expression, trailingTrivia) => (JassStatementSyntax)new JassReturnStatementSyntax( + returnToken, + expression.GetValueOrDefault()).AppendTrailingTrivia(trailingTrivia), + Keyword.Return.AsToken(triviaParser, JassSyntaxKind.ReturnKeyword), + expressionParser.Optional(), + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SetStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/SetStatementParser.cs new file mode 100644 index 00000000..f1623cc9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/SetStatementParser.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetSetStatementParser( + Parser identifierNameParser, + Parser elementAccessClauseParser, + Parser equalsValueClauseParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (setToken, identifierName, elementAccessClause, value, trailingTrivia) => (JassStatementSyntax)new JassSetStatementSyntax( + setToken, + identifierName, + elementAccessClause.GetValueOrDefault(), + value.AppendTrailingTrivia(trailingTrivia)), + Keyword.Set.AsToken(triviaParser, JassSyntaxKind.SetKeyword), + identifierNameParser, + elementAccessClauseParser.Optional(), + equalsValueClauseParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs new file mode 100644 index 00000000..cd378a0e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetStatementParser( + Parser localVariableDeclarationStatementParser, + Parser exitStatementParser, + Parser returnStatementParser, + Parser setStatementParser, + Parser callStatementParser, + Parser ifClauseDeclaratorParser, + Parser elseIfClauseDeclaratorParser, + Parser triviaParser, + Parser leadingTriviaParser, + Parser trailingTriviaParser) + { + return Rec( + statementParser => + { + var ifStatementParser = GetIfStatementParser(statementParser, ifClauseDeclaratorParser, elseIfClauseDeclaratorParser, leadingTriviaParser, trailingTriviaParser); + var loopStatementParser = GetLoopStatementParser(statementParser, leadingTriviaParser, trailingTriviaParser); + + return OneOf( + localVariableDeclarationStatementParser, + setStatementParser, + callStatementParser, + ifStatementParser, + loopStatementParser, + exitStatementParser, + returnStatementParser, + GetDebugStatementParser( + setStatementParser, + callStatementParser, + ifStatementParser, + loopStatementParser, + triviaParser, + trailingTriviaParser)); + }); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/StringLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/StringLiteralExpressionParser.cs similarity index 55% rename from src/War3Net.CodeAnalysis.Jass/Parser/StringLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/JassParser/StringLiteralExpressionParser.cs index 926899aa..0780208e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Parser/StringLiteralExpressionParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/StringLiteralExpressionParser.cs @@ -16,11 +16,12 @@ namespace War3Net.CodeAnalysis.Jass { internal partial class JassParser { - internal static Parser GetStringLiteralExpressionParser() + internal static Parser GetStringLiteralExpressionParser( + Parser triviaParser) { var escapeSequenceParser = OneOf( - Symbol.QuotationMark.ThenReturn($"\\{JassSymbol.QuotationMark}"), - Symbol.Apostrophe.ThenReturn($"\\{JassSymbol.Apostrophe}"), + Symbol.DoubleQuote.ThenReturn($"\\{JassSymbol.DoubleQuoteChar}"), + Symbol.SingleQuote.ThenReturn($"\\{JassSymbol.SingleQuoteChar}"), Char('r').ThenReturn("\\r"), Char('n').ThenReturn("\\n"), Char('t').ThenReturn("\\t"), @@ -30,8 +31,14 @@ internal static Parser GetStringLiteralExpressionParser Any.Then(c => Fail($"\"\\{c}\" is not a valid escape sequence"))) .Labelled("escape sequence"); - return Char('\\').Then(escapeSequenceParser).Or(AnyCharExcept(JassSymbol.QuotationMark).Map(char.ToString)).ManyString().Between(Symbol.QuotationMark) - .Select(value => new JassStringLiteralExpressionSyntax(value)) + var stringLiteralParser = Char('\\').Then(escapeSequenceParser).Or(AnyCharExcept(JassSymbol.DoubleQuoteChar).Map(char.ToString)).ManyString().Between(Symbol.DoubleQuote) + .Labelled("string literal"); + + return Map( + (value, trivia) => (JassExpressionSyntax)new JassLiteralExpressionSyntax( + new JassSyntaxToken(JassSyntaxKind.StringLiteralToken, $"{JassSymbol.DoubleQuoteChar}{value}{JassSymbol.DoubleQuoteChar}", trivia)), + stringLiteralParser, + triviaParser) .Labelled("string literal"); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs new file mode 100644 index 00000000..b8bdd6db --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; +using System.Linq; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetSimpleTriviaListParser( + Parser whitespaceTriviaParser) + { + return OneOf( + whitespaceTriviaParser.Many().Select(trivia => new JassSyntaxTriviaList(trivia.ToImmutableArray())), + Return(JassSyntaxTriviaList.Empty)); + } + + internal static Parser GetLeadingTriviaListParser( + Parser whitespaceTriviaParser, + Parser newlineTriviaParser, + Parser singleLineCommentTriviaParser) + { + return OneOf( + OneOf( + whitespaceTriviaParser, + newlineTriviaParser, + singleLineCommentTriviaParser) + .Many() + .Select(trivia => new JassSyntaxTriviaList(trivia.ToImmutableArray())), + Return(JassSyntaxTriviaList.Empty)); + } + + internal static Parser GetTrailingTriviaListParser( + Parser whitespaceTriviaParser, + Parser singleNewlineTriviaParser, + Parser singleLineCommentTriviaParser) + { + return OneOf( + OneOf( + whitespaceTriviaParser, + singleLineCommentTriviaParser) + .Many() + .Then( + OneOf( + singleNewlineTriviaParser.Select(newline => Maybe.Just(newline)), + End.ThenReturn(Maybe.Nothing())), + (trivia, newline) => new JassSyntaxTriviaList((newline.HasValue ? trivia.Append(newline.Value) : trivia).ToImmutableArray())), + Return(JassSyntaxTriviaList.Empty)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs new file mode 100644 index 00000000..9fb076a6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetWhitespaceTriviaParser() + { + return Token(JassSyntaxFacts.IsWhitespaceCharacter) + .AtLeastOnceString() + .Select(whitespace => new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, whitespace)); + } + + internal static Parser GetNewlineTriviaParser() + { + return OneOf(Symbol.CarriageReturn, Symbol.LineFeed) + .AtLeastOnceString() + .Select(newline => new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, newline)); + } + + internal static Parser GetSingleNewlineTriviaParser() + { + return OneOf( + Try(Symbol.CarriageReturnLineFeed), + Symbol.CarriageReturnString, + Symbol.LineFeedString) + .Select(newline => new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, newline)); + } + + internal static Parser GetSingleLineCommentTriviaParser() + { + return Map( + (_, commentString) => new JassSyntaxTrivia(JassSyntaxKind.SingleLineCommentTrivia, $"{JassSymbol.SlashSlash}{commentString}"), + Try(Symbol.SlashSlash), + AnyCharExcept(JassSymbol.CarriageReturnChar, JassSymbol.LineFeedChar).ManyString()); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/TopLevelDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/TopLevelDeclarationParser.cs new file mode 100644 index 00000000..4587d124 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/TopLevelDeclarationParser.cs @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetTopLevelDeclarationParser( + Parser typeDeclarationParser, + Parser, JassTopLevelDeclarationSyntax>> nativeFunctionDeclarationParser, + Parser, JassTopLevelDeclarationSyntax>> functionDeclarationParser, + Parser globalDeclarationParser, + Parser triviaParser, + Parser leadingTriviaParser, + Parser trailingTriviaParser) + { + return OneOf( + typeDeclarationParser, + GetGlobalsDeclarationParser(globalDeclarationParser, leadingTriviaParser, trailingTriviaParser), + Map( + (constantToken, declarationFunc) => declarationFunc(constantToken), + Keyword.Constant.AsToken(triviaParser, JassSyntaxKind.ConstantKeyword).Optional(), + OneOf( + nativeFunctionDeclarationParser, + functionDeclarationParser))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/TypeDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/TypeDeclarationParser.cs new file mode 100644 index 00000000..127e30c0 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/TypeDeclarationParser.cs @@ -0,0 +1,38 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetTypeDeclarationParser( + Parser identifierNameParser, + Parser typeParser, + Parser triviaParser, + Parser trailingTriviaParser) + { + return Map( + (typeToken, identifierName, extendsToken, type, trailingTrivia) => (JassTopLevelDeclarationSyntax)new JassTypeDeclarationSyntax( + typeToken, + identifierName, + extendsToken, + type.AppendTrailingTrivia(trailingTrivia)), + Keyword.Type.AsToken(triviaParser, JassSyntaxKind.TypeKeyword), + identifierNameParser, + Keyword.Extends.AsToken(triviaParser, JassSyntaxKind.ExtendsKeyword), + typeParser, + trailingTriviaParser); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/TypeParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/TypeParser.cs new file mode 100644 index 00000000..30e316f1 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/TypeParser.cs @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + private static readonly Dictionary _predefinedTypeSyntaxKinds = GetPredefinedTypeSyntaxKinds(); + + internal static Parser GetTypeParser( + Parser identifierParser, + Parser triviaParser) + { + return Map( + (text, trivia) => new JassSyntaxToken( + _predefinedTypeSyntaxKinds.GetValueOrDefault(text, JassSyntaxKind.IdentifierToken), + text, + trivia), + identifierParser.Assert(JassSyntaxFacts.IsNotReservedKeyword), + triviaParser).Select(token => token.SyntaxKind == JassSyntaxKind.IdentifierToken + ? new JassIdentifierNameSyntax(token) + : new JassPredefinedTypeSyntax(token)); + } + + private static Dictionary GetPredefinedTypeSyntaxKinds() + { + return new Dictionary + { + { JassKeyword.Boolean, JassSyntaxKind.BooleanKeyword }, + { JassKeyword.Code, JassSyntaxKind.CodeKeyword }, + { JassKeyword.Handle, JassSyntaxKind.HandleKeyword }, + { JassKeyword.Integer, JassSyntaxKind.IntegerKeyword }, + { JassKeyword.Nothing, JassSyntaxKind.NothingKeyword }, + { JassKeyword.Real, JassSyntaxKind.RealKeyword }, + { JassKeyword.String, JassSyntaxKind.StringKeyword }, + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/UnaryOperatorParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/UnaryOperatorParser.cs new file mode 100644 index 00000000..7de241d4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/UnaryOperatorParser.cs @@ -0,0 +1,46 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetUnaryOperatorParser( + Parser triviaParser) + { + return OneOf( + GetUnaryPlusOperatorParser(triviaParser), + GetUnaryMinusOperatorParser(triviaParser), + GetUnaryNotOperatorParser(triviaParser)); + } + + internal static Parser GetUnaryPlusOperatorParser( + Parser triviaParser) + { + return Symbol.Plus.AsToken(triviaParser, JassSyntaxKind.PlusToken, JassSymbol.Plus); + } + + internal static Parser GetUnaryMinusOperatorParser( + Parser triviaParser) + { + return Symbol.Minus.AsToken(triviaParser, JassSyntaxKind.MinusToken, JassSymbol.Minus); + } + + internal static Parser GetUnaryNotOperatorParser( + Parser triviaParser) + { + return Keyword.Not.AsToken(triviaParser, JassSyntaxKind.NotKeyword); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/VariableOrArrayDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/VariableOrArrayDeclaratorParser.cs new file mode 100644 index 00000000..819c7169 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/VariableOrArrayDeclaratorParser.cs @@ -0,0 +1,47 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; + +using static Pidgin.Parser; + +namespace War3Net.CodeAnalysis.Jass +{ + internal partial class JassParser + { + internal static Parser GetVariableOrArrayDeclaratorParser( + Parser equalsValueClauseParser, + Parser identifierNameParser, + Parser typeParser, + Parser triviaParser) + { + return Map( + (type, declaratorFunc) => declaratorFunc(type), + typeParser, + OneOf( + Map>( + (arrayToken, identifierName) => type => new JassArrayDeclaratorSyntax( + type, + arrayToken, + identifierName), + Keyword.Array.AsToken(triviaParser, JassSyntaxKind.ArrayKeyword), + identifierNameParser), + Map, Func>( + (identifierName, value) => type => new JassVariableDeclaratorSyntax( + type, + identifierName, + value.GetValueOrDefault()), + identifierNameParser, + equalsValueClauseParser.Optional()))); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassRenamer.cs b/src/War3Net.CodeAnalysis.Jass/JassRenamer.cs index 8d435559..250494d7 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassRenamer.cs @@ -8,19 +8,17 @@ using System; using System.Collections.Generic; -using War3Net.CodeAnalysis.Jass.Syntax; - namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private readonly Dictionary _functionDeclarationRenames; - private readonly Dictionary _globalVariableRenames; + private readonly Dictionary _functionDeclarationRenames; + private readonly Dictionary _globalVariableRenames; private readonly HashSet _localVariableNames; public JassRenamer( - Dictionary functionDeclarationRenames, - Dictionary globalVariableRenames) + Dictionary functionDeclarationRenames, + Dictionary globalVariableRenames) { _functionDeclarationRenames = functionDeclarationRenames; _globalVariableRenames = globalVariableRenames; diff --git a/src/War3Net.CodeAnalysis.Jass/JassRenderer.cs b/src/War3Net.CodeAnalysis.Jass/JassRenderer.cs index 5ebd51c7..9d15b780 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassRenderer.cs @@ -5,11 +5,13 @@ // // ------------------------------------------------------------------------------ +using System; using System.IO; using System.Linq; namespace War3Net.CodeAnalysis.Jass { + [Obsolete("Use NormalizeWhitespace() and JassSyntaxNode.WriteTo()")] public partial class JassRenderer { private readonly TextWriter _writer; @@ -34,14 +36,12 @@ public JassRenderer(TextWriter writer, JassRendererOptions options) public void RenderNewLine() => WriteLine(); - private void Write(char c) + private void WriteSpace() { - if (!_currentLineIndented) + if (_currentLineIndented) { - WriteIndentation(); + _writer.Write(' '); } - - _writer.Write(c); } private void Write(string s) @@ -60,12 +60,6 @@ private void WriteLine() _currentLineIndented = false; } - private void WriteLine(string s) - { - Write(s); - WriteLine(); - } - private void WriteIndentation() { _currentLineIndented = true; diff --git a/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs b/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs index 8b116c9b..e6c68c79 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs @@ -11,26 +11,53 @@ namespace War3Net.CodeAnalysis.Jass { public static class JassSymbol { - public const char LineFeed = '\n'; - public const char CarriageReturn = '\r'; - public const char ExclamationMark = '!'; - public const char QuotationMark = '"'; - public const char DollarSign = '$'; - public const char Apostrophe = '\''; - public const char LeftParenthesis = '('; - public const char RightParenthesis = ')'; - public const char Asterisk = '*'; - public const char PlusSign = '+'; - public const char Comma = ','; - public const char MinusSign = '-'; - public const char FullStop = '.'; - public const char Slash = '/'; - public const char Zero = '0'; - public const char LessThanSign = '<'; - public const char EqualsSign = '='; - public const char GreaterThanSign = '>'; - public const char LeftSquareBracket = '['; - public const char RightSquareBracket = ']'; - public const char X = 'x'; + public const char LineFeedChar = '\n'; + public const char CarriageReturnChar = '\r'; + public const char ExclamationChar = '!'; + public const char DoubleQuoteChar = '"'; + public const char DollarChar = '$'; + public const char SingleQuoteChar = '\''; + public const char OpenParenChar = '('; + public const char CloseParenChar = ')'; + public const char AsteriskChar = '*'; + public const char PlusChar = '+'; + public const char CommaChar = ','; + public const char MinusChar = '-'; + public const char DotChar = '.'; + public const char SlashChar = '/'; + public const char ZeroChar = '0'; + public const char LessThanChar = '<'; + public const char EqualsChar = '='; + public const char GreaterThanChar = '>'; + public const char OpenBracketChar = '['; + public const char CloseBracketChar = ']'; + public const char XChar = 'x'; + public const char SpaceChar = ' '; + public const char TabChar = '\t'; + + public const string LineFeed = "\n"; + public const string CarriageReturn = "\r"; + public const string Dollar = "$"; + public const string OpenParen = "("; + public const string CloseParen = ")"; + public const string Asterisk = "*"; + public const string Plus = "+"; + public const string Comma = ","; + public const string Minus = "-"; + public const string Dot = "."; + public const string Slash = "/"; + public const string Zero = "0"; + public const string LessThan = "<"; + public new const string Equals = "="; + public const string GreaterThan = ">"; + public const string OpenBracket = "["; + public const string CloseBracket = "]"; + + public const string CarriageReturnLineFeed = "\r\n"; + public const string SlashSlash = "//"; + public const string ExclamationEquals = "!="; + public const string LessThanEquals = "<="; + public const string GreaterThanEquals = ">="; + public const string EqualsEquals = "=="; } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs index ace6c7d8..8f8e68f0 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs @@ -5,7 +5,10 @@ // // ------------------------------------------------------------------------------ +using System; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Pidgin; @@ -20,32 +23,17 @@ public static JassArgumentListSyntax ParseArgumentList(string argumentList) return JassParser.Instance.ArgumentListParser.ParseOrThrow(argumentList); } - public static BinaryOperatorType ParseBinaryOperator(string binaryOperator) + public static JassSyntaxToken ParseBinaryOperator(string binaryOperator) { return JassParser.Instance.BinaryOperatorParser.ParseOrThrow(binaryOperator); } - public static JassCommentSyntax ParseComment(string comment) - { - return JassParser.Instance.CommentParser.ParseOrThrow(comment); - } - public static JassCompilationUnitSyntax ParseCompilationUnit(string compilationUnit) { return JassParser.Instance.CompilationUnitParser.ParseOrThrow(compilationUnit); } - public static ITopLevelDeclarationSyntax ParseDeclaration(string declaration) - { - return JassParser.Instance.DeclarationParser.ParseOrThrow(declaration); - } - - public static IDeclarationLineSyntax ParseDeclarationLine(string declarationLine) - { - return JassParser.Instance.DeclarationLineParser.ParseOrThrow(declarationLine); - } - - public static IExpressionSyntax ParseExpression(string expression) + public static JassExpressionSyntax ParseExpression(string expression) { return JassParser.Instance.ExpressionParser.ParseOrThrow(expression); } @@ -55,34 +43,29 @@ public static JassFunctionDeclarationSyntax ParseFunctionDeclaration(string func return JassParser.Instance.FunctionDeclarationParser.ParseOrThrow(functionDeclaration); } - public static IGlobalDeclarationSyntax ParseGlobalDeclaration(string globalDeclaration) + public static JassGlobalDeclarationSyntax ParseGlobalDeclaration(string globalDeclaration) { return JassParser.Instance.GlobalDeclarationParser.ParseOrThrow(globalDeclaration); } - public static IGlobalLineSyntax ParseGlobalLine(string globalLine) - { - return JassParser.Instance.GlobalLineParser.ParseOrThrow(globalLine); - } - public static JassIdentifierNameSyntax ParseIdentifierName(string identifierName) { return JassParser.Instance.IdentifierNameParser.ParseOrThrow(identifierName); } - public static JassParameterListSyntax ParseParameterList(string parameterList) + public static JassParameterListOrEmptyParameterListSyntax ParseParameterList(string parameterList) { return JassParser.Instance.ParameterListParser.ParseOrThrow(parameterList); } - public static IStatementSyntax ParseStatement(string statement) + public static JassStatementSyntax ParseStatement(string statement) { return JassParser.Instance.StatementParser.ParseOrThrow(statement); } - public static IStatementLineSyntax ParseStatementLine(string statementLine) + public static JassTopLevelDeclarationSyntax ParseTopLevelDeclaration(string topLevelDeclaration) { - return JassParser.Instance.StatementLineParser.ParseOrThrow(statementLine); + return JassParser.Instance.TopLevelDeclarationParser.ParseOrThrow(topLevelDeclaration); } public static JassTypeSyntax ParseTypeName(string typeName) @@ -90,7 +73,7 @@ public static JassTypeSyntax ParseTypeName(string typeName) return JassParser.Instance.TypeParser.ParseOrThrow(typeName); } - public static UnaryOperatorType ParseUnaryOperator(string unaryOperator) + public static JassSyntaxToken ParseUnaryOperator(string unaryOperator) { return JassParser.Instance.UnaryOperatorParser.ParseOrThrow(unaryOperator); } @@ -100,32 +83,17 @@ public static bool TryParseArgumentList(string argumentList, [NotNullWhen(true)] return TryParse(argumentList, JassParser.Instance.ArgumentListParser, out result); } - public static bool TryParseBinaryOperator(string binaryOperator, [NotNullWhen(true)] out BinaryOperatorType? result) + public static bool TryParseBinaryOperator(string binaryOperator, [NotNullWhen(true)] out JassSyntaxToken? result) { return TryParse(binaryOperator, JassParser.Instance.BinaryOperatorParser, out result); } - public static bool TryParseComment(string comment, [NotNullWhen(true)] out JassCommentSyntax? result) - { - return TryParse(comment, JassParser.Instance.CommentParser, out result); - } - public static bool TryParseCompilationUnit(string compilationUnit, [NotNullWhen(true)] out JassCompilationUnitSyntax? result) { return TryParse(compilationUnit, JassParser.Instance.CompilationUnitParser, out result); } - public static bool TryParseDeclaration(string declaration, [NotNullWhen(true)] out ITopLevelDeclarationSyntax? result) - { - return TryParse(declaration, JassParser.Instance.DeclarationParser, out result); - } - - public static bool TryParseDeclarationLine(string declarationLine, [NotNullWhen(true)] out IDeclarationLineSyntax? result) - { - return TryParse(declarationLine, JassParser.Instance.DeclarationLineParser, out result); - } - - public static bool TryParseExpression(string expression, [NotNullWhen(true)] out IExpressionSyntax? result) + public static bool TryParseExpression(string expression, [NotNullWhen(true)] out JassExpressionSyntax? result) { return TryParse(expression, JassParser.Instance.ExpressionParser, out result); } @@ -135,34 +103,29 @@ public static bool TryParseFunctionDeclaration(string functionDeclaration, [NotN return TryParse(functionDeclaration, JassParser.Instance.FunctionDeclarationParser, out result); } - public static bool TryParseGlobalDeclaration(string globalDeclaration, [NotNullWhen(true)] out IGlobalDeclarationSyntax? result) + public static bool TryParseGlobalDeclaration(string globalDeclaration, [NotNullWhen(true)] out JassGlobalDeclarationSyntax? result) { return TryParse(globalDeclaration, JassParser.Instance.GlobalDeclarationParser, out result); } - public static bool TryParseGlobalLine(string globalLine, [NotNullWhen(true)] out IGlobalLineSyntax? result) - { - return TryParse(globalLine, JassParser.Instance.GlobalLineParser, out result); - } - public static bool TryParseIdentifierName(string identifierName, [NotNullWhen(true)] out JassIdentifierNameSyntax? result) { return TryParse(identifierName, JassParser.Instance.IdentifierNameParser, out result); } - public static bool TryParseParameterList(string parameterList, [NotNullWhen(true)] out JassParameterListSyntax? result) + public static bool TryParseParameterList(string parameterList, [NotNullWhen(true)] out JassParameterListOrEmptyParameterListSyntax? result) { return TryParse(parameterList, JassParser.Instance.ParameterListParser, out result); } - public static bool TryParseStatement(string statement, [NotNullWhen(true)] out IStatementSyntax? result) + public static bool TryParseStatement(string statement, [NotNullWhen(true)] out JassStatementSyntax? result) { return TryParse(statement, JassParser.Instance.StatementParser, out result); } - public static bool TryParseStatementLine(string statementLine, [NotNullWhen(true)] out IStatementLineSyntax? result) + public static bool TryParseTopLevelDeclaration(string topLevelDeclaration, [NotNullWhen(true)] out JassTopLevelDeclarationSyntax? result) { - return TryParse(statementLine, JassParser.Instance.StatementLineParser, out result); + return TryParse(topLevelDeclaration, JassParser.Instance.TopLevelDeclarationParser, out result); } public static bool TryParseTypeName(string typeName, [NotNullWhen(true)] out JassTypeSyntax? result) @@ -170,7 +133,7 @@ public static bool TryParseTypeName(string typeName, [NotNullWhen(true)] out Jas return TryParse(typeName, JassParser.Instance.TypeParser, out result); } - public static bool TryParseUnaryOperator(string unaryOperator, [NotNullWhen(true)] out UnaryOperatorType? result) + public static bool TryParseUnaryOperator(string unaryOperator, [NotNullWhen(true)] out JassSyntaxToken? result) { return TryParse(unaryOperator, JassParser.Instance.UnaryOperatorParser, out result); } @@ -202,5 +165,52 @@ private static bool TryParse(string input, Parser parser result = null; return false; } + + internal static class ThrowHelper + { + public static void ThrowIfInvalidToken(JassSyntaxToken token, JassSyntaxKind expectedSyntaxKind, [CallerArgumentExpression("token")] string? paramName = null) + { + if (token is null) + { + throw new ArgumentNullException(paramName); + } + + if (token.SyntaxKind != expectedSyntaxKind) + { + throw new ArgumentException("Invalid SyntaxKind.", paramName); + } + } + + public static void ThrowIfInvalidSeparatedSyntaxList(SeparatedSyntaxList separatedSyntaxList, JassSyntaxKind expectedSyntaxKind, [CallerArgumentExpression("separatedSyntaxList")] string? paramName = null) + { + if (separatedSyntaxList is null) + { + throw new ArgumentNullException(paramName); + } + + for (var i = 0; i < separatedSyntaxList.Items.Length; i++) + { + var item = separatedSyntaxList.Items[i]; + if (item is null) + { + throw new ArgumentException("Items in list may not be null.", paramName); + } + } + + for (var i = 0; i < separatedSyntaxList.Separators.Length; i++) + { + var separator = separatedSyntaxList.Separators[i]; + if (separator is null) + { + throw new ArgumentException("Separators in list may not be null.", paramName); + } + + if (separator.SyntaxKind != expectedSyntaxKind) + { + throw new ArgumentException("Invalid SyntaxKind.", paramName); + } + } + } + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs index b81f4592..2d753940 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs @@ -9,13 +9,18 @@ namespace War3Net.CodeAnalysis.Jass { - public static class JassSyntaxFacts + public static partial class JassSyntaxFacts { public static bool IsWhitespaceCharacter(char ch) { - return char.IsWhiteSpace(ch) - && ch != JassSymbol.CarriageReturn - && ch != JassSymbol.LineFeed; + return ch == JassSymbol.SpaceChar + || ch == JassSymbol.TabChar; + } + + public static bool IsNewlineCharacter(char ch) + { + return ch == JassSymbol.CarriageReturnChar + || ch == JassSymbol.LineFeedChar; } /// @@ -77,5 +82,10 @@ public static bool IsValidIdentifier([NotNullWhen(true)] string? name) return IsIdentifierEndCharacter(name[^1]); } + + internal static bool IsNotReservedKeyword(string? name) + { + return !IsReservedKeyword(GetSyntaxKind(name)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs new file mode 100644 index 00000000..e61446ef --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs @@ -0,0 +1,447 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public enum JassSyntaxKind + { + None = 0, + + /// Represents * token. + /// + AsteriskToken = 8199, + + /// Represents ( token. + /// + OpenParenToken = 8200, + + /// Represents ) token. + /// + CloseParenToken = 8201, + + /// Represents - token. + /// + MinusToken = 8202, + + /// Represents + token. + /// + PlusToken = 8203, + + /// Represents = token. + /// + EqualsToken = 8204, + + /// Represents [ token. + /// + OpenBracketToken = 8207, + + /// Represents ] token. + /// + CloseBracketToken = 8208, + + /// Represents < token. + /// + LessThanToken = 8215, + + /// Represents , token. + /// + CommaToken = 8216, + + /// Represents > token. + /// + GreaterThanToken = 8217, + + /// Represents / token. + /// + SlashToken = 8221, + + /// Represents != token. + /// + ExclamationEqualsToken = 8267, + + /// Represents == token. + /// + EqualsEqualsToken = 8268, + + /// Represents <= token. + /// + LessThanEqualsToken = 8270, + + /// Represents >= token. + /// + GreaterThanEqualsToken = 8273, + + /// Represents boolean keyword. + /// + BooleanKeyword = 8304, + + /// Represents integer keyword. + /// + IntegerKeyword = 8309, + + /// Represents real keyword. + /// + RealKeyword = 8314, + + /// Represents string keyword. + /// + StringKeyword = 8316, + + /// Represents nothing keyword. + /// + NothingKeyword = 8318, + + /// Represents handle keyword. + /// + HandleKeyword = 8319, + + /// Represents code keyword. + /// + CodeKeyword = 8320, + + /// Represents null keyword. + /// + NullKeyword = 8322, + + /// Represents true keyword. + /// + TrueKeyword = 8323, + + /// Represents false keyword. + /// + FalseKeyword = 8324, + + /// Represents if keyword. + /// + IfKeyword = 8325, + + /// Represents elseif keyword. + /// + ElseIfKeyword = 8326, + + /// Represents then keyword. + /// + ThenKeyword = 8327, + + /// Represents else keyword. + /// + ElseKeyword = 8328, + + /// Represents endif keyword. + /// + EndIfKeyword = 8329, + + /// Represents loop keyword. + /// + LoopKeyword = 8330, + + /// Represents exitwhen keyword. + /// + ExitWhenKeyword = 8339, + + /// Represents endloop keyword. + /// + EndLoopKeyword = 8340, + + /// Represents return keyword. + /// + ReturnKeyword = 8341, + + /// Represents call keyword. + /// + CallKeyword = 8342, + + /// Represents set keyword. + /// + SetKeyword = 8343, + + /// Represents local keyword. + /// + LocalKeyword = 8344, + + /// Represents debug keyword. + /// + DebugKeyword = 8345, + + /// Represents constant keyword. + /// + ConstantKeyword = 8350, + + /// Represents function keyword. + /// + FunctionKeyword = 8351, + + /// Represents takes keyword. + /// + TakesKeyword = 8352, + + /// Represents returns keyword. + /// + ReturnsKeyword = 8353, + + /// Represents endfunction keyword. + /// + EndFunctionKeyword = 8354, + + /// Represents native keyword. + /// + NativeKeyword = 8359, + + /// Represents extends keyword. + /// + ExtendsKeyword = 8371, + + /// Represents alias keyword. + /// + AliasKeyword = 8407, + + /// Represents array keyword. + /// + ArrayKeyword = 8408, + + /// Represents globals keyword. + /// + GlobalsKeyword = 8409, + + /// Represents endglobals keyword. + /// + EndGlobalsKeyword = 8410, + + /// Represents type keyword. + /// + TypeKeyword = 8411, + + /// Represents or keyword. + /// + OrKeyword = 8438, + + /// Represents and keyword. + /// + AndKeyword = 8439, + + /// Represents not keyword. + /// + NotKeyword = 8440, + + /// Represents the end of a file. + EndOfFileToken = 8496, + + IdentifierToken = 8508, + + RealLiteralToken = 8509, + CharacterLiteralToken = 8510, + StringLiteralToken = 8511, + DecimalLiteralToken = 8512, + HexadecimalLiteralToken = 8513, + OctalLiteralToken = 8514, + FourCCLiteralToken = 8515, + + NewlineTrivia = 8539, + WhitespaceTrivia = 8540, + SingleLineCommentTrivia = 8541, + + /// Represents . + IdentifierName = 8616, + + /// Represents . + PredefinedType = 8621, + + /// Represents . + ParenthesizedExpression = 8632, + + /// Represents . + FunctionReferenceExpression = 8633, + + /// Represents . + InvocationExpression = 8634, + + /// Represents . + ElementAccessExpression = 8635, + + /// Represents . + ArgumentList = 8636, + + /// Represents . + ElementAccessClause = 8637, + + /// Represents with as operator token kind. + AddExpression = 8668, + + /// Represents with as operator token kind. + SubtractExpression = 8669, + + /// Represents with as operator token kind. + MultiplyExpression = 8670, + + /// Represents with as operator token kind. + DivideExpression = 8671, + + /// Represents with as operator token kind. + LogicalOrExpression = 8675, + + /// Represents with as operator token kind. + LogicalAndExpression = 8676, + + /// Represents with as operator token kind. + EqualsExpression = 8680, + + /// Represents with as operator token kind. + NotEqualsExpression = 8681, + + /// Represents with as operator token kind. + LessThanExpression = 8682, + + /// Represents with as operator token kind. + LessThanOrEqualExpression = 8683, + + /// Represents with as operator token kind. + GreaterThanExpression = 8684, + + /// Represents with as operator token kind. + GreaterThanOrEqualExpression = 8685, + + /// Represents . + SetStatement = 8714, + + /// Represents with as operator token kind. + UnaryPlusExpression = 8730, + + /// Represents with as operator token kind. + UnaryMinusExpression = 8731, + + /// Represents with as operator token kind. + LogicalNotExpression = 8733, + + /// Represents with as token kind. + RealLiteralExpression = 8749, + + /// Represents with as token kind. + StringLiteralExpression = 8750, + + /// Represents with as token kind. + CharacterLiteralExpression = 8751, + + /// Represents with as token kind. + TrueLiteralExpression = 8752, + + /// Represents with as token kind. + FalseLiteralExpression = 8753, + + /// Represents with as token kind. + NullLiteralExpression = 8754, + + /// Represents with as token kind. + DecimalLiteralExpression = 8755, + + /// Represents with as token kind. + HexadecimalLiteralExpression = 8756, + + /// Represents with as token kind. + OctalLiteralExpression = 8757, + + /// Represents with as token kind. + FourCCLiteralExpression = 8758, + + /// Represents with as declarator kind. + LocalVariableDeclarationStatement = 8793, + + /// Represents with as declarator kind. + LocalArrayDeclarationStatement = 8794, + + /// Represents . + VariableDeclarator = 8795, + + /// Represents . + EqualsValueClause = 8796, + + /// Represents . + ArrayDeclarator = 8797, + + /// Represents . + ExitStatement = 8803, + + /// Represents . + ReturnStatement = 8805, + + /// Represents . + CallStatement = 8808, + + /// Represents . + LoopStatement = 8809, + + /// Represents . + IfStatement = 8819, + + /// Represents . + IfClause = 8820, + + /// Represents . + IfClauseDeclarator = 8821, + + /// Represents . + ElseIfClause = 8822, + + /// Represents . + ElseIfClauseDeclarator = 8823, + + /// Represents . + ElseClause = 8824, + + /// Represents with as statement kind. + DebugSetStatement = 8825, + + /// Represents with as statement kind. + DebugCallStatement = 8826, + + /// Represents with as statement kind. + DebugLoopStatement = 8827, + + /// Represents with as statement kind. + DebugIfStatement = 8828, + + /// Represents . + CompilationUnit = 8840, + + /// Represents . + TypeDeclaration = 8855, + + /// Represents . + NativeFunctionDeclaration = 8859, + + /// Represents . + FunctionDeclaration = 8875, + + /// Represents . + FunctionDeclarator = 8876, + + /// Represents . + ParameterList = 8906, + + /// Represents . + EmptyParameterList = 8907, + + /// Represents . + Parameter = 8908, + + /// Represents . + ReturnClause = 8909, + + /// Represents . + GlobalsDeclaration = 8911, + + /// Represents . + GlobalConstantDeclaration = 8912, + + /// Represents with as declarator kind. + GlobalVariableDeclaration = 8913, + + /// Represents with as declarator kind. + GlobalArrayDeclaration = 8914, + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs new file mode 100644 index 00000000..027f1cba --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs @@ -0,0 +1,340 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFacts + { + private static readonly Dictionary _defaultTokenText = GetDefaultTokenText(); + private static readonly Dictionary _textToKind = _defaultTokenText.ToDictionary(pair => pair.Value, pair => pair.Key, StringComparer.Ordinal); + + public static bool IsPunctuation(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.AsteriskToken && syntaxKind <= JassSyntaxKind.GreaterThanEqualsToken; + } + + public static bool IsKeyword(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.BooleanKeyword && syntaxKind <= JassSyntaxKind.NotKeyword; + } + + public static bool IsPredefinedTypeKeyword(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.BooleanKeyword && syntaxKind <= JassSyntaxKind.CodeKeyword; + } + + public static bool IsReservedKeyword(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.NullKeyword && syntaxKind <= JassSyntaxKind.NotKeyword; + } + + internal static bool IsLiteralToken(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.RealLiteralToken && syntaxKind <= JassSyntaxKind.FourCCLiteralToken; + } + + public static bool IsAnyToken(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.AsteriskToken && syntaxKind <= JassSyntaxKind.FourCCLiteralToken; + } + + public static bool IsTrivia(JassSyntaxKind syntaxKind) + { + return syntaxKind >= JassSyntaxKind.NewlineTrivia && syntaxKind <= JassSyntaxKind.SingleLineCommentTrivia; + } + + public static bool IsBinaryExpressionToken(JassSyntaxKind binaryOperatorTokenSyntaxKind) + { + return GetBinaryExpressionKind(binaryOperatorTokenSyntaxKind) != JassSyntaxKind.None; + } + + public static JassSyntaxKind GetBinaryExpressionKind(JassSyntaxKind binaryOperatorTokenSyntaxKind) + { + return binaryOperatorTokenSyntaxKind switch + { + JassSyntaxKind.PlusToken => JassSyntaxKind.AddExpression, + JassSyntaxKind.MinusToken => JassSyntaxKind.SubtractExpression, + JassSyntaxKind.AsteriskToken => JassSyntaxKind.MultiplyExpression, + JassSyntaxKind.SlashToken => JassSyntaxKind.DivideExpression, + JassSyntaxKind.OrKeyword => JassSyntaxKind.LogicalOrExpression, + JassSyntaxKind.AndKeyword => JassSyntaxKind.LogicalAndExpression, + JassSyntaxKind.EqualsEqualsToken => JassSyntaxKind.EqualsExpression, + JassSyntaxKind.ExclamationEqualsToken => JassSyntaxKind.NotEqualsExpression, + JassSyntaxKind.LessThanToken => JassSyntaxKind.LessThanExpression, + JassSyntaxKind.LessThanEqualsToken => JassSyntaxKind.LessThanOrEqualExpression, + JassSyntaxKind.GreaterThanToken => JassSyntaxKind.GreaterThanExpression, + JassSyntaxKind.GreaterThanEqualsToken => JassSyntaxKind.GreaterThanOrEqualExpression, + + _ => JassSyntaxKind.None, + }; + } + + public static bool IsLiteralExpressionToken(JassSyntaxKind literalExpressionTokenSyntaxKind) + { + return GetLiteralExpressionKind(literalExpressionTokenSyntaxKind) != JassSyntaxKind.None; + } + + public static JassSyntaxKind GetLiteralExpressionKind(JassSyntaxKind literalExpressionTokenSyntaxKind) + { + return literalExpressionTokenSyntaxKind switch + { + JassSyntaxKind.RealLiteralToken => JassSyntaxKind.RealLiteralExpression, + JassSyntaxKind.StringLiteralToken => JassSyntaxKind.StringLiteralExpression, + JassSyntaxKind.CharacterLiteralToken => JassSyntaxKind.CharacterLiteralExpression, + JassSyntaxKind.TrueKeyword => JassSyntaxKind.TrueLiteralExpression, + JassSyntaxKind.FalseKeyword => JassSyntaxKind.FalseLiteralExpression, + JassSyntaxKind.NullKeyword => JassSyntaxKind.NullLiteralExpression, + JassSyntaxKind.DecimalLiteralToken => JassSyntaxKind.DecimalLiteralExpression, + JassSyntaxKind.HexadecimalLiteralToken => JassSyntaxKind.HexadecimalLiteralExpression, + JassSyntaxKind.OctalLiteralToken => JassSyntaxKind.OctalLiteralExpression, + JassSyntaxKind.FourCCLiteralToken => JassSyntaxKind.FourCCLiteralExpression, + + _ => JassSyntaxKind.None, + }; + } + + public static bool IsUnaryExpressionToken(JassSyntaxKind unaryOperatorTokenSyntaxKind) + { + return GetUnaryExpressionKind(unaryOperatorTokenSyntaxKind) != JassSyntaxKind.None; + } + + public static JassSyntaxKind GetUnaryExpressionKind(JassSyntaxKind unaryOperatorTokenSyntaxKind) + { + return unaryOperatorTokenSyntaxKind switch + { + JassSyntaxKind.PlusToken => JassSyntaxKind.UnaryPlusExpression, + JassSyntaxKind.MinusToken => JassSyntaxKind.UnaryMinusExpression, + JassSyntaxKind.NotKeyword => JassSyntaxKind.LogicalNotExpression, + + _ => JassSyntaxKind.None, + }; + } + + public static bool IsDebugStatementNode(JassSyntaxKind statementSyntaxKind) + { + return GetDebugStatementKind(statementSyntaxKind) != JassSyntaxKind.None; + } + + public static JassSyntaxKind GetDebugStatementKind(JassSyntaxKind statementSyntaxKind) + { + return statementSyntaxKind switch + { + JassSyntaxKind.SetStatement => JassSyntaxKind.DebugSetStatement, + JassSyntaxKind.CallStatement => JassSyntaxKind.DebugCallStatement, + JassSyntaxKind.LoopStatement => JassSyntaxKind.DebugLoopStatement, + JassSyntaxKind.IfStatement => JassSyntaxKind.DebugIfStatement, + + _ => JassSyntaxKind.None, + }; + } + + public static JassSyntaxKind GetGlobalDeclarationKind(JassSyntaxKind declaratorSyntaxKind) + { + return declaratorSyntaxKind switch + { + JassSyntaxKind.VariableDeclarator => JassSyntaxKind.GlobalVariableDeclaration, + JassSyntaxKind.ArrayDeclarator => JassSyntaxKind.GlobalArrayDeclaration, + + _ => JassSyntaxKind.None, + }; + } + + public static JassSyntaxKind GetLocalDeclarationStatementKind(JassSyntaxKind declaratorSyntaxKind) + { + return declaratorSyntaxKind switch + { + JassSyntaxKind.VariableDeclarator => JassSyntaxKind.LocalVariableDeclarationStatement, + JassSyntaxKind.ArrayDeclarator => JassSyntaxKind.LocalArrayDeclarationStatement, + + _ => JassSyntaxKind.None, + }; + } + + public static IEnumerable GetPunctuationKinds() + { + yield return JassSyntaxKind.AsteriskToken; + yield return JassSyntaxKind.OpenParenToken; + yield return JassSyntaxKind.CloseParenToken; + yield return JassSyntaxKind.MinusToken; + yield return JassSyntaxKind.PlusToken; + yield return JassSyntaxKind.EqualsToken; + yield return JassSyntaxKind.OpenBracketToken; + yield return JassSyntaxKind.CloseBracketToken; + yield return JassSyntaxKind.LessThanToken; + yield return JassSyntaxKind.CommaToken; + yield return JassSyntaxKind.GreaterThanToken; + yield return JassSyntaxKind.SlashToken; + yield return JassSyntaxKind.ExclamationEqualsToken; + yield return JassSyntaxKind.EqualsEqualsToken; + yield return JassSyntaxKind.LessThanEqualsToken; + yield return JassSyntaxKind.GreaterThanEqualsToken; + } + + public static IEnumerable GetKeywordKinds() + { + yield return JassSyntaxKind.BooleanKeyword; + yield return JassSyntaxKind.IntegerKeyword; + yield return JassSyntaxKind.RealKeyword; + yield return JassSyntaxKind.StringKeyword; + yield return JassSyntaxKind.NothingKeyword; + yield return JassSyntaxKind.HandleKeyword; + yield return JassSyntaxKind.NullKeyword; + yield return JassSyntaxKind.TrueKeyword; + yield return JassSyntaxKind.FalseKeyword; + yield return JassSyntaxKind.IfKeyword; + yield return JassSyntaxKind.ElseIfKeyword; + yield return JassSyntaxKind.ThenKeyword; + yield return JassSyntaxKind.ElseKeyword; + yield return JassSyntaxKind.EndIfKeyword; + yield return JassSyntaxKind.LoopKeyword; + yield return JassSyntaxKind.ExitWhenKeyword; + yield return JassSyntaxKind.EndLoopKeyword; + yield return JassSyntaxKind.ReturnKeyword; + yield return JassSyntaxKind.CallKeyword; + yield return JassSyntaxKind.SetKeyword; + yield return JassSyntaxKind.LocalKeyword; + yield return JassSyntaxKind.DebugKeyword; + yield return JassSyntaxKind.ConstantKeyword; + yield return JassSyntaxKind.FunctionKeyword; + yield return JassSyntaxKind.TakesKeyword; + yield return JassSyntaxKind.ReturnsKeyword; + yield return JassSyntaxKind.EndFunctionKeyword; + yield return JassSyntaxKind.NativeKeyword; + yield return JassSyntaxKind.ExtendsKeyword; + yield return JassSyntaxKind.CodeKeyword; + yield return JassSyntaxKind.AliasKeyword; + yield return JassSyntaxKind.ArrayKeyword; + yield return JassSyntaxKind.GlobalsKeyword; + yield return JassSyntaxKind.EndGlobalsKeyword; + yield return JassSyntaxKind.TypeKeyword; + yield return JassSyntaxKind.OrKeyword; + yield return JassSyntaxKind.AndKeyword; + yield return JassSyntaxKind.NotKeyword; + } + + public static IEnumerable GetPredefinedTypeKeywordKinds() + { + yield return JassSyntaxKind.BooleanKeyword; + yield return JassSyntaxKind.IntegerKeyword; + yield return JassSyntaxKind.RealKeyword; + yield return JassSyntaxKind.StringKeyword; + yield return JassSyntaxKind.NothingKeyword; + yield return JassSyntaxKind.HandleKeyword; + yield return JassSyntaxKind.NullKeyword; + } + + public static IEnumerable GetReservedKeywordKinds() + { + yield return JassSyntaxKind.TrueKeyword; + yield return JassSyntaxKind.FalseKeyword; + yield return JassSyntaxKind.IfKeyword; + yield return JassSyntaxKind.ElseIfKeyword; + yield return JassSyntaxKind.ThenKeyword; + yield return JassSyntaxKind.ElseKeyword; + yield return JassSyntaxKind.EndIfKeyword; + yield return JassSyntaxKind.LoopKeyword; + yield return JassSyntaxKind.ExitWhenKeyword; + yield return JassSyntaxKind.EndLoopKeyword; + yield return JassSyntaxKind.ReturnKeyword; + yield return JassSyntaxKind.CallKeyword; + yield return JassSyntaxKind.SetKeyword; + yield return JassSyntaxKind.LocalKeyword; + yield return JassSyntaxKind.DebugKeyword; + yield return JassSyntaxKind.ConstantKeyword; + yield return JassSyntaxKind.FunctionKeyword; + yield return JassSyntaxKind.TakesKeyword; + yield return JassSyntaxKind.ReturnsKeyword; + yield return JassSyntaxKind.EndFunctionKeyword; + yield return JassSyntaxKind.NativeKeyword; + yield return JassSyntaxKind.ExtendsKeyword; + yield return JassSyntaxKind.CodeKeyword; + yield return JassSyntaxKind.AliasKeyword; + yield return JassSyntaxKind.ArrayKeyword; + yield return JassSyntaxKind.GlobalsKeyword; + yield return JassSyntaxKind.EndGlobalsKeyword; + yield return JassSyntaxKind.TypeKeyword; + yield return JassSyntaxKind.OrKeyword; + yield return JassSyntaxKind.AndKeyword; + yield return JassSyntaxKind.NotKeyword; + } + + public static string GetText(JassSyntaxKind syntaxKind) + { + return _defaultTokenText.GetValueOrDefault(syntaxKind, string.Empty); + } + + public static JassSyntaxKind GetSyntaxKind(string text) + { + return _textToKind.GetValueOrDefault(text, JassSyntaxKind.None); + } + + private static Dictionary GetDefaultTokenText() + { + return new Dictionary + { + { JassSyntaxKind.AsteriskToken, JassSymbol.Asterisk }, + { JassSyntaxKind.OpenParenToken, JassSymbol.OpenParen }, + { JassSyntaxKind.CloseParenToken, JassSymbol.CloseParen }, + { JassSyntaxKind.MinusToken, JassSymbol.Minus }, + { JassSyntaxKind.PlusToken, JassSymbol.Plus }, + { JassSyntaxKind.EqualsToken, JassSymbol.Equals }, + { JassSyntaxKind.OpenBracketToken, JassSymbol.OpenBracket }, + { JassSyntaxKind.CloseBracketToken, JassSymbol.CloseBracket }, + { JassSyntaxKind.LessThanToken, JassSymbol.LessThan }, + { JassSyntaxKind.CommaToken, JassSymbol.Comma }, + { JassSyntaxKind.GreaterThanToken, JassSymbol.GreaterThan }, + { JassSyntaxKind.SlashToken, JassSymbol.Slash }, + { JassSyntaxKind.ExclamationEqualsToken, JassSymbol.ExclamationEquals }, + { JassSyntaxKind.EqualsEqualsToken, JassSymbol.EqualsEquals }, + { JassSyntaxKind.LessThanEqualsToken, JassSymbol.LessThanEquals }, + { JassSyntaxKind.GreaterThanEqualsToken, JassSymbol.GreaterThanEquals }, + { JassSyntaxKind.BooleanKeyword, JassKeyword.Boolean }, + { JassSyntaxKind.IntegerKeyword, JassKeyword.Integer }, + { JassSyntaxKind.RealKeyword, JassKeyword.Real }, + { JassSyntaxKind.StringKeyword, JassKeyword.String }, + { JassSyntaxKind.NothingKeyword, JassKeyword.Nothing }, + { JassSyntaxKind.HandleKeyword, JassKeyword.Handle }, + { JassSyntaxKind.NullKeyword, JassKeyword.Null }, + { JassSyntaxKind.TrueKeyword, JassKeyword.True }, + { JassSyntaxKind.FalseKeyword, JassKeyword.False }, + { JassSyntaxKind.IfKeyword, JassKeyword.If }, + { JassSyntaxKind.ElseIfKeyword, JassKeyword.ElseIf }, + { JassSyntaxKind.ThenKeyword, JassKeyword.Then }, + { JassSyntaxKind.ElseKeyword, JassKeyword.Else }, + { JassSyntaxKind.EndIfKeyword, JassKeyword.EndIf }, + { JassSyntaxKind.LoopKeyword, JassKeyword.Loop }, + { JassSyntaxKind.ExitWhenKeyword, JassKeyword.ExitWhen }, + { JassSyntaxKind.EndLoopKeyword, JassKeyword.EndLoop }, + { JassSyntaxKind.ReturnKeyword, JassKeyword.Return }, + { JassSyntaxKind.CallKeyword, JassKeyword.Call }, + { JassSyntaxKind.SetKeyword, JassKeyword.Set }, + { JassSyntaxKind.LocalKeyword, JassKeyword.Local }, + { JassSyntaxKind.DebugKeyword, JassKeyword.Debug }, + { JassSyntaxKind.ConstantKeyword, JassKeyword.Constant }, + { JassSyntaxKind.FunctionKeyword, JassKeyword.Function }, + { JassSyntaxKind.TakesKeyword, JassKeyword.Takes }, + { JassSyntaxKind.ReturnsKeyword, JassKeyword.Returns }, + { JassSyntaxKind.EndFunctionKeyword, JassKeyword.EndFunction }, + { JassSyntaxKind.NativeKeyword, JassKeyword.Native }, + { JassSyntaxKind.ExtendsKeyword, JassKeyword.Extends }, + { JassSyntaxKind.CodeKeyword, JassKeyword.Code }, + { JassSyntaxKind.AliasKeyword, JassKeyword.Alias }, + { JassSyntaxKind.ArrayKeyword, JassKeyword.Array }, + { JassSyntaxKind.GlobalsKeyword, JassKeyword.Globals }, + { JassSyntaxKind.EndGlobalsKeyword, JassKeyword.EndGlobals }, + { JassSyntaxKind.TypeKeyword, JassKeyword.Type }, + { JassSyntaxKind.OrKeyword, JassKeyword.Or }, + { JassSyntaxKind.AndKeyword, JassKeyword.And }, + { JassSyntaxKind.NotKeyword, JassKeyword.Not }, + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs new file mode 100644 index 00000000..c8181419 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs @@ -0,0 +1,52 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + internal sealed partial class JassSyntaxNormalizer : JassSyntaxRewriter + { + private readonly List _nodes; + private readonly bool _addSpacesToOuterInvocation; + private readonly bool _trimComments; + private readonly string _indentationString; + + private JassSyntaxToken _previousToken; + private JassSyntaxToken _currentToken; + private JassSyntaxNode? _previousNode; + private JassSyntaxNode? _previousNodeParent; + private JassSyntaxNode? _previousNodeGrandParent; + + private int _currentLevelOfIndentation; + private bool _encounteredAnyTextOnCurrentLine; + private bool _requireNewlineTrivia; + + public JassSyntaxNormalizer( + bool addSpacesToOuterInvocation = true, + bool trimComments = false, + string indentationString = " ") + { + _nodes = new List(); + _addSpacesToOuterInvocation = addSpacesToOuterInvocation; + _trimComments = trimComments; + _indentationString = indentationString; + + _previousToken = new JassSyntaxToken(JassSyntaxTriviaList.Empty, JassSyntaxKind.None, string.Empty, JassSyntaxTriviaList.Empty); + _currentToken = _previousToken; + _previousNode = null; + _previousNodeParent = null; + _previousNodeGrandParent = null; + + _currentLevelOfIndentation = 0; + _encounteredAnyTextOnCurrentLine = false; + _requireNewlineTrivia = false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ArgumentListNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ArgumentListNormalizer.cs new file mode 100644 index 00000000..f33d8655 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ArgumentListNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteArgumentList(JassArgumentListSyntax argumentList, out JassArgumentListSyntax result) + { + _nodes.Add(argumentList); + var normalized = base.RewriteArgumentList(argumentList, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ArrayDeclaratorNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ArrayDeclaratorNormalizer.cs new file mode 100644 index 00000000..ddce3ede --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ArrayDeclaratorNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteArrayDeclarator(JassArrayDeclaratorSyntax arrayDeclarator, out JassVariableOrArrayDeclaratorSyntax result) + { + _nodes.Add(arrayDeclarator); + var normalized = base.RewriteArrayDeclarator(arrayDeclarator, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/BinaryExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/BinaryExpressionNormalizer.cs new file mode 100644 index 00000000..a53f9746 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/BinaryExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteBinaryExpression(JassBinaryExpressionSyntax binaryExpression, out JassExpressionSyntax result) + { + _nodes.Add(binaryExpression); + var normalized = base.RewriteBinaryExpression(binaryExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs new file mode 100644 index 00000000..630eb80d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteCallStatement(JassCallStatementSyntax callStatement, out JassStatementSyntax result) + { + _nodes.Add(callStatement); + var normalized = base.RewriteCallStatement(callStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/CompilationUnitNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/CompilationUnitNormalizer.cs new file mode 100644 index 00000000..9a2e079d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/CompilationUnitNormalizer.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + public JassCompilationUnitSyntax NormalizeWhitespace(JassCompilationUnitSyntax compilationUnit) + { + RewriteCompilationUnit(compilationUnit, out var result); + return result; + } + + /// + protected override bool RewriteCompilationUnit(JassCompilationUnitSyntax compilationUnit, out JassCompilationUnitSyntax result) + { + _nodes.Add(compilationUnit); + var normalized = base.RewriteCompilationUnit(compilationUnit, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/DebugStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/DebugStatementNormalizer.cs new file mode 100644 index 00000000..0f893ea0 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/DebugStatementNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteDebugStatement(JassDebugStatementSyntax debugStatement, out JassStatementSyntax result) + { + _nodes.Add(debugStatement); + var normalized = base.RewriteDebugStatement(debugStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessClauseNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessClauseNormalizer.cs new file mode 100644 index 00000000..813ff1ba --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessClauseNormalizer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteElementAccessClause(JassElementAccessClauseSyntax? elementAccessClause, [NotNullIfNotNull("elementAccessClause")] out JassElementAccessClauseSyntax? result) + { + if (elementAccessClause is null) + { + result = null; + return false; + } + + _nodes.Add(elementAccessClause); + var normalized = base.RewriteElementAccessClause(elementAccessClause, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessExpressionNormalizer.cs new file mode 100644 index 00000000..7371f438 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElementAccessExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteElementAccessExpression(JassElementAccessExpressionSyntax elementAccessExpression, out JassExpressionSyntax result) + { + _nodes.Add(elementAccessExpression); + var normalized = base.RewriteElementAccessExpression(elementAccessExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseClauseNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseClauseNormalizer.cs new file mode 100644 index 00000000..f241a55b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseClauseNormalizer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteElseClause(JassElseClauseSyntax? elseClause, [NotNullIfNotNull("elseClause")] out JassElseClauseSyntax? result) + { + if (elseClause is null) + { + result = null; + return false; + } + + _nodes.Add(elseClause); + var normalized = base.RewriteElseClause(elseClause, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseDeclaratorNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseDeclaratorNormalizer.cs new file mode 100644 index 00000000..9a0dd3c2 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseDeclaratorNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteElseIfClauseDeclarator(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, out JassElseIfClauseDeclaratorSyntax result) + { + _nodes.Add(elseIfClauseDeclarator); + var normalized = base.RewriteElseIfClauseDeclarator(elseIfClauseDeclarator, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseNormalizer.cs new file mode 100644 index 00000000..2e284252 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ElseIfClauseNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteElseIfClause(JassElseIfClauseSyntax elseIfClause, out JassElseIfClauseSyntax result) + { + _nodes.Add(elseIfClause); + var normalized = base.RewriteElseIfClause(elseIfClause, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/EmptyParameterListNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/EmptyParameterListNormalizer.cs new file mode 100644 index 00000000..b83f348c --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/EmptyParameterListNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteEmptyParameterList(JassEmptyParameterListSyntax emptyParameterList, out JassParameterListOrEmptyParameterListSyntax result) + { + _nodes.Add(emptyParameterList); + var normalized = base.RewriteEmptyParameterList(emptyParameterList, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/EqualsValueClauseNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/EqualsValueClauseNormalizer.cs new file mode 100644 index 00000000..801c31dc --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/EqualsValueClauseNormalizer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteEqualsValueClause(JassEqualsValueClauseSyntax? equalsValueClause, [NotNullIfNotNull("equalsValueClause")] out JassEqualsValueClauseSyntax? result) + { + if (equalsValueClause is null) + { + result = null; + return false; + } + + _nodes.Add(equalsValueClause); + var normalized = base.RewriteEqualsValueClause(equalsValueClause, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs new file mode 100644 index 00000000..235f25a5 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteExitStatement(JassExitStatementSyntax exitStatement, out JassStatementSyntax result) + { + _nodes.Add(exitStatement); + var normalized = base.RewriteExitStatement(exitStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclarationNormalizer.cs new file mode 100644 index 00000000..194a39eb --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclarationNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteFunctionDeclaration(JassFunctionDeclarationSyntax functionDeclaration, out JassTopLevelDeclarationSyntax result) + { + _nodes.Add(functionDeclaration); + var normalized = base.RewriteFunctionDeclaration(functionDeclaration, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs new file mode 100644 index 00000000..2cf5b09b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteFunctionDeclarator(JassFunctionDeclaratorSyntax functionDeclarator, out JassFunctionDeclaratorSyntax result) + { + _nodes.Add(functionDeclarator); + var normalized = base.RewriteFunctionDeclarator(functionDeclarator, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _currentLevelOfIndentation++; + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionReferenceExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionReferenceExpressionNormalizer.cs new file mode 100644 index 00000000..d5eed392 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionReferenceExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteFunctionReferenceExpression(JassFunctionReferenceExpressionSyntax functionReferenceExpression, out JassExpressionSyntax result) + { + _nodes.Add(functionReferenceExpression); + var normalized = base.RewriteFunctionReferenceExpression(functionReferenceExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs new file mode 100644 index 00000000..3cdfa911 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteGlobalConstantDeclaration(JassGlobalConstantDeclarationSyntax globalConstantDeclaration, out JassGlobalDeclarationSyntax result) + { + _nodes.Add(globalConstantDeclaration); + var normalized = base.RewriteGlobalConstantDeclaration(globalConstantDeclaration, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs new file mode 100644 index 00000000..b8e88144 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteGlobalVariableDeclaration(JassGlobalVariableDeclarationSyntax globalVariableDeclaration, out JassGlobalDeclarationSyntax result) + { + _nodes.Add(globalVariableDeclaration); + var normalized = base.RewriteGlobalVariableDeclaration(globalVariableDeclaration, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalsDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalsDeclarationNormalizer.cs new file mode 100644 index 00000000..cfb385d4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalsDeclarationNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteGlobalsDeclaration(JassGlobalsDeclarationSyntax globalsDeclaration, out JassTopLevelDeclarationSyntax result) + { + _nodes.Add(globalsDeclaration); + var normalized = base.RewriteGlobalsDeclaration(globalsDeclaration, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/IdentifierNameNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/IdentifierNameNormalizer.cs new file mode 100644 index 00000000..60338e59 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/IdentifierNameNormalizer.cs @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteIdentifierName(JassIdentifierNameSyntax identifierName, out JassIdentifierNameSyntax result) + { + _nodes.Add(identifierName); + var normalized = base.RewriteIdentifierName(identifierName, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + + /// + protected override bool RewriteIdentifierNameAsExpression(JassIdentifierNameSyntax identifierName, out JassExpressionSyntax result) + { + _nodes.Add(identifierName); + var normalized = base.RewriteIdentifierNameAsExpression(identifierName, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + + /// + protected override bool RewriteIdentifierNameAsType(JassIdentifierNameSyntax identifierName, out JassTypeSyntax result) + { + _nodes.Add(identifierName); + var normalized = base.RewriteIdentifierNameAsType(identifierName, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseDeclaratorNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseDeclaratorNormalizer.cs new file mode 100644 index 00000000..1a46828d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseDeclaratorNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteIfClauseDeclarator(JassIfClauseDeclaratorSyntax ifClauseDeclarator, out JassIfClauseDeclaratorSyntax result) + { + _nodes.Add(ifClauseDeclarator); + var normalized = base.RewriteIfClauseDeclarator(ifClauseDeclarator, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseNormalizer.cs new file mode 100644 index 00000000..40c2c78e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/IfClauseNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteIfClause(JassIfClauseSyntax ifClause, out JassIfClauseSyntax result) + { + _nodes.Add(ifClause); + var normalized = base.RewriteIfClause(ifClause, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/IfStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/IfStatementNormalizer.cs new file mode 100644 index 00000000..ffdb9233 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/IfStatementNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteIfStatement(JassIfStatementSyntax ifStatement, out JassStatementSyntax result) + { + _nodes.Add(ifStatement); + var normalized = base.RewriteIfStatement(ifStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/InvocationExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/InvocationExpressionNormalizer.cs new file mode 100644 index 00000000..db2818bd --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/InvocationExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteInvocationExpression(JassInvocationExpressionSyntax invocationExpression, out JassExpressionSyntax result) + { + _nodes.Add(invocationExpression); + var normalized = base.RewriteInvocationExpression(invocationExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/LiteralExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/LiteralExpressionNormalizer.cs new file mode 100644 index 00000000..32219209 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/LiteralExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteLiteralExpression(JassLiteralExpressionSyntax literalExpression, out JassExpressionSyntax result) + { + _nodes.Add(literalExpression); + var normalized = base.RewriteLiteralExpression(literalExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs new file mode 100644 index 00000000..53563600 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteLocalVariableDeclarationStatement(JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement, out JassStatementSyntax result) + { + _nodes.Add(localVariableDeclarationStatement); + var normalized = base.RewriteLocalVariableDeclarationStatement(localVariableDeclarationStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/LoopStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/LoopStatementNormalizer.cs new file mode 100644 index 00000000..3b48e1f9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/LoopStatementNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteLoopStatement(JassLoopStatementSyntax loopStatement, out JassStatementSyntax result) + { + _nodes.Add(loopStatement); + var normalized = base.RewriteLoopStatement(loopStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs new file mode 100644 index 00000000..ce580432 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteNativeFunctionDeclaration(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration, out JassTopLevelDeclarationSyntax result) + { + _nodes.Add(nativeFunctionDeclaration); + var normalized = base.RewriteNativeFunctionDeclaration(nativeFunctionDeclaration, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterListNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterListNormalizer.cs new file mode 100644 index 00000000..c034da41 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterListNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteParameterList(JassParameterListSyntax parameterList, out JassParameterListOrEmptyParameterListSyntax result) + { + _nodes.Add(parameterList); + var normalized = base.RewriteParameterList(parameterList, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterNormalizer.cs new file mode 100644 index 00000000..17198a68 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ParameterNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteParameter(JassParameterSyntax parameter, out JassParameterSyntax result) + { + _nodes.Add(parameter); + var normalized = base.RewriteParameter(parameter, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ParenthesizedExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ParenthesizedExpressionNormalizer.cs new file mode 100644 index 00000000..523a8cb8 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ParenthesizedExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteParenthesizedExpression(JassParenthesizedExpressionSyntax parenthesizedExpression, out JassExpressionSyntax result) + { + _nodes.Add(parenthesizedExpression); + var normalized = base.RewriteParenthesizedExpression(parenthesizedExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/PredefinedTypeNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/PredefinedTypeNormalizer.cs new file mode 100644 index 00000000..d638c3f6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/PredefinedTypeNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewritePredefinedType(JassPredefinedTypeSyntax predefinedType, out JassTypeSyntax result) + { + _nodes.Add(predefinedType); + var normalized = base.RewritePredefinedType(predefinedType, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnClauseNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnClauseNormalizer.cs new file mode 100644 index 00000000..640f5e12 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnClauseNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteReturnClause(JassReturnClauseSyntax returnClause, out JassReturnClauseSyntax result) + { + _nodes.Add(returnClause); + var normalized = base.RewriteReturnClause(returnClause, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs new file mode 100644 index 00000000..32083ebf --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteReturnStatement(JassReturnStatementSyntax returnStatement, out JassStatementSyntax result) + { + _nodes.Add(returnStatement); + var normalized = base.RewriteReturnStatement(returnStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs new file mode 100644 index 00000000..1fba3b99 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteSetStatement(JassSetStatementSyntax setStatement, out JassStatementSyntax result) + { + _nodes.Add(setStatement); + var normalized = base.RewriteSetStatement(setStatement, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs new file mode 100644 index 00000000..ec76c600 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs @@ -0,0 +1,116 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + private static readonly HashSet _increaseIndentationSyntaxKinds = GetIncreaseIndentationSyntaxKinds(); + private static readonly HashSet _decreaseIndentationSyntaxKinds = GetDecreaseIndentationSyntaxKinds(); + private static readonly HashSet _requireNewlineSyntaxKinds = GetRequireNewlineSyntaxKinds(); + + /// + protected override bool RewriteToken(JassSyntaxToken? token, [NotNullIfNotNull("token")] out JassSyntaxToken? result) + { + if (token is null) + { + result = null; + return false; + } + + _currentToken = token; + + if (_decreaseIndentationSyntaxKinds.Contains(_currentToken.SyntaxKind)) + { + _currentLevelOfIndentation--; + } + + var normalizedLeadingTrivia = RewriteLeadingTrivia(token.LeadingTrivia, out var leadingTrivia); + + if (_requireNewlineSyntaxKinds.Contains(_currentToken.SyntaxKind)) + { + _requireNewlineTrivia = true; + } + + if (_increaseIndentationSyntaxKinds.Contains(_currentToken.SyntaxKind)) + { + _currentLevelOfIndentation++; + } + + var normalizedTrailingTrivia = RewriteTrailingTrivia(token.TrailingTrivia, out var trailingTrivia); + + if (normalizedLeadingTrivia || normalizedTrailingTrivia) + { + result = new JassSyntaxToken( + leadingTrivia, + token.SyntaxKind, + token.Text, + trailingTrivia); + + _previousToken = result; + _previousNode = _nodes[^1]; + _previousNodeParent = _nodes.Count > 1 ? _nodes[^2] : null; + _previousNodeGrandParent = _nodes.Count > 2 ? _nodes[^3] : null; + + return true; + } + + result = token; + + _previousToken = token; + _previousNode = _nodes[^1]; + _previousNodeParent = _nodes.Count > 1 ? _nodes[^2] : null; + _previousNodeGrandParent = _nodes.Count > 2 ? _nodes[^3] : null; + + return false; + } + + private static HashSet GetIncreaseIndentationSyntaxKinds() + { + return new HashSet + { + JassSyntaxKind.ElseKeyword, + JassSyntaxKind.GlobalsKeyword, + JassSyntaxKind.LoopKeyword, + JassSyntaxKind.ThenKeyword, + }; + } + + private static HashSet GetDecreaseIndentationSyntaxKinds() + { + return new HashSet + { + JassSyntaxKind.ElseIfKeyword, + JassSyntaxKind.ElseKeyword, + JassSyntaxKind.EndFunctionKeyword, + JassSyntaxKind.EndGlobalsKeyword, + JassSyntaxKind.EndIfKeyword, + JassSyntaxKind.EndLoopKeyword, + }; + } + + private static HashSet GetRequireNewlineSyntaxKinds() + { + return new HashSet + { + JassSyntaxKind.ElseKeyword, + JassSyntaxKind.EndFunctionKeyword, + JassSyntaxKind.EndGlobalsKeyword, + JassSyntaxKind.EndIfKeyword, + JassSyntaxKind.EndLoopKeyword, + JassSyntaxKind.GlobalsKeyword, + JassSyntaxKind.LoopKeyword, + JassSyntaxKind.ThenKeyword, + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs new file mode 100644 index 00000000..a97efe3a --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs @@ -0,0 +1,202 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; +using System.Linq; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteLeadingTrivia(JassSyntaxTriviaList triviaList, out JassSyntaxTriviaList result) + { + var triviaBuilder = ImmutableArray.CreateBuilder(); + + if (_requireNewlineTrivia) + { + triviaBuilder.Add(JassSyntaxTrivia.Newline); + _encounteredAnyTextOnCurrentLine = false; + _requireNewlineTrivia = false; + } + + HandleExistingTrivia(triviaList, triviaBuilder); + + if (_encounteredAnyTextOnCurrentLine) + { + var requireSpace = true; + + if (_previousToken.SyntaxKind == JassSyntaxKind.OpenBracketToken || + _currentToken.SyntaxKind == JassSyntaxKind.OpenBracketToken || + _currentToken.SyntaxKind == JassSyntaxKind.CloseBracketToken || + _currentToken.SyntaxKind == JassSyntaxKind.CommaToken) + { + requireSpace = false; + } + else + { + var currentNode = _nodes[^1]; + if (currentNode is not null) + { + if (_currentToken.SyntaxKind == JassSyntaxKind.OpenParenToken) + { + requireSpace = currentNode.SyntaxKind == JassSyntaxKind.ParenthesizedExpression; + } + else if (_currentToken.SyntaxKind == JassSyntaxKind.CloseParenToken) + { + if (_addSpacesToOuterInvocation && + currentNode.SyntaxKind == JassSyntaxKind.ArgumentList && + _nodes.Count > 1) + { + var currentNodeParent = _nodes[^2]; + + if (currentNodeParent.SyntaxKind == JassSyntaxKind.CallStatement) + { + requireSpace = true; + } + else if (currentNodeParent.SyntaxKind == JassSyntaxKind.InvocationExpression && _nodes.Count > 2) + { + var currentNodeGrandParent = _nodes[^3]; + requireSpace = currentNodeGrandParent.SyntaxKind == JassSyntaxKind.EqualsValueClause; + } + else + { + requireSpace = false; + } + } + else + { + requireSpace = false; + } + } + } + + if (_previousNode is not null) + { + if (_previousNode.SyntaxKind == JassSyntaxKind.UnaryPlusExpression || + _previousNode.SyntaxKind == JassSyntaxKind.UnaryMinusExpression) + { + requireSpace = false; + } + else if (_previousToken.SyntaxKind == JassSyntaxKind.OpenParenToken) + { + if (_addSpacesToOuterInvocation && + _previousNode.SyntaxKind == JassSyntaxKind.ArgumentList && + _previousNodeParent is not null) + { + if (_previousNodeParent.SyntaxKind == JassSyntaxKind.CallStatement) + { + requireSpace = true; + if (_currentToken.SyntaxKind == JassSyntaxKind.CloseParenToken) + { + requireSpace = false; + triviaBuilder.Add(JassSyntaxFactory.WhitespaceTrivia(" ")); + } + } + else if (_previousNodeParent.SyntaxKind == JassSyntaxKind.InvocationExpression && + _previousNodeGrandParent is not null && + _previousNodeGrandParent.SyntaxKind == JassSyntaxKind.EqualsValueClause) + { + requireSpace = true; + if (_currentToken.SyntaxKind == JassSyntaxKind.CloseParenToken) + { + requireSpace = false; + triviaBuilder.Add(JassSyntaxFactory.WhitespaceTrivia(" ")); + } + } + else + { + requireSpace = false; + } + } + else + { + requireSpace = false; + } + } + } + } + + if (requireSpace) + { + triviaBuilder.Add(JassSyntaxTrivia.SingleSpace); + } + } + else if (!string.IsNullOrEmpty(_currentToken.Text)) + { + _encounteredAnyTextOnCurrentLine = true; + if (_currentLevelOfIndentation > 0) + { + triviaBuilder.Add(JassSyntaxFactory.WhitespaceTrivia(string.Concat(Enumerable.Repeat(_indentationString, _currentLevelOfIndentation)))); + } + } + + result = JassSyntaxFactory.SyntaxTriviaList(triviaBuilder.ToImmutable()); + return true; + } + + /// + protected override bool RewriteTrailingTrivia(JassSyntaxTriviaList triviaList, out JassSyntaxTriviaList result) + { + var triviaBuilder = ImmutableArray.CreateBuilder(); + + HandleExistingTrivia(triviaList, triviaBuilder); + + result = JassSyntaxFactory.SyntaxTriviaList(triviaBuilder.ToImmutable()); + return true; + } + + private void HandleExistingTrivia(JassSyntaxTriviaList triviaList, ImmutableArray.Builder triviaBuilder) + { + for (var i = 0; i < triviaList.Trivia.Length; i++) + { + var trivia = triviaList.Trivia[i]; + if (trivia.SyntaxKind == JassSyntaxKind.NewlineTrivia) + { + triviaBuilder.Add(trivia); + _encounteredAnyTextOnCurrentLine = false; + _requireNewlineTrivia = false; + } + else if (trivia.SyntaxKind == JassSyntaxKind.SingleLineCommentTrivia) + { + if (!_encounteredAnyTextOnCurrentLine) + { + _encounteredAnyTextOnCurrentLine = true; + if (_currentLevelOfIndentation > 0) + { + triviaBuilder.Add(JassSyntaxFactory.WhitespaceTrivia(string.Concat(Enumerable.Repeat(_indentationString, _currentLevelOfIndentation)))); + } + } + else if (_previousToken.TrailingTrivia.Trivia.IsEmpty || _previousToken.TrailingTrivia.Trivia[^1].SyntaxKind != JassSyntaxKind.WhitespaceTrivia) + { + triviaBuilder.Add(JassSyntaxTrivia.SingleSpace); + } + + if (_trimComments && char.IsWhiteSpace(trivia.Text[^1])) + { + triviaBuilder.Add(JassSyntaxFactory.SingleLineCommentTrivia(trivia.Text.TrimEnd())); + } + else + { + triviaBuilder.Add(trivia); + } + + _requireNewlineTrivia = true; + } + } + + if (_requireNewlineTrivia) + { + triviaBuilder.Add(JassSyntaxTrivia.Newline); + _encounteredAnyTextOnCurrentLine = false; + _requireNewlineTrivia = false; + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs new file mode 100644 index 00000000..ff54b325 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteTypeDeclaration(JassTypeDeclarationSyntax typeDeclaration, out JassTopLevelDeclarationSyntax result) + { + _nodes.Add(typeDeclaration); + var normalized = base.RewriteTypeDeclaration(typeDeclaration, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/UnaryExpressionNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/UnaryExpressionNormalizer.cs new file mode 100644 index 00000000..5b694104 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/UnaryExpressionNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteUnaryExpression(JassUnaryExpressionSyntax unaryExpression, out JassExpressionSyntax result) + { + _nodes.Add(unaryExpression); + var normalized = base.RewriteUnaryExpression(unaryExpression, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/VariableDeclaratorNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/VariableDeclaratorNormalizer.cs new file mode 100644 index 00000000..0b8d9b74 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/VariableDeclaratorNormalizer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + partial class JassSyntaxNormalizer + { + /// + protected override bool RewriteVariableDeclarator(JassVariableDeclaratorSyntax variableDeclarator, out JassVariableOrArrayDeclaratorSyntax result) + { + _nodes.Add(variableDeclarator); + var normalized = base.RewriteVariableDeclarator(variableDeclarator, out result); + _nodes.RemoveAt(_nodes.Count - 1); + + return normalized; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ArgumentListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ArgumentListParser.cs deleted file mode 100644 index 8115d92e..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ArgumentListParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetArgumentListParser( - Parser whitespaceParser, - Parser expressionParser) - { - return expressionParser.Separated(Symbol.Comma.Then(whitespaceParser)) - .Select(arguments => new JassArgumentListSyntax(arguments.ToImmutableArray())); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ArrayReferenceExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ArrayReferenceExpressionParser.cs deleted file mode 100644 index e50fce34..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ArrayReferenceExpressionParser.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetArrayReferenceExpressionParser( - Parser whitespaceParser, - Parser expressionParser, - Parser identifierNameParser) - { - return Try(identifierNameParser.Before(Symbol.LeftSquareBracket.Then(whitespaceParser))) - .Then(expressionParser, (id, indexer) => (IExpressionSyntax)new JassArrayReferenceExpressionSyntax(id, indexer)) - .Before(Symbol.RightSquareBracket.Then(whitespaceParser)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/BinaryOperatorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/BinaryOperatorParser.cs deleted file mode 100644 index 58960378..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/BinaryOperatorParser.cs +++ /dev/null @@ -1,95 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetBinaryOperatorParser(Parser whitespaceParser) - { - return OneOf( - GetBinaryAddOperatorParser(whitespaceParser), - GetBinarySubtractOperatorParser(whitespaceParser), - GetBinaryMultiplicationOperatorParser(whitespaceParser), - GetBinaryDivisionOperatorParser(whitespaceParser), - GetBinaryGreaterOrEqualOperatorParser(whitespaceParser), - GetBinaryLessOrEqualOperatorParser(whitespaceParser), - GetBinaryEqualsOperatorParser(whitespaceParser), - GetBinaryNotEqualsOperatorParser(whitespaceParser), - GetBinaryGreaterThanOperatorParser(whitespaceParser), - GetBinaryLessThanOperatorParser(whitespaceParser), - GetBinaryAndOperatorParser(whitespaceParser), - GetBinaryOrOperatorParser(whitespaceParser)); - } - - internal static Parser GetBinaryAddOperatorParser(Parser whitespaceParser) - { - return Symbol.PlusSign.Then(whitespaceParser).ThenReturn(BinaryOperatorType.Add); - } - - internal static Parser GetBinarySubtractOperatorParser(Parser whitespaceParser) - { - return Symbol.MinusSign.Then(whitespaceParser).ThenReturn(BinaryOperatorType.Subtract); - } - - internal static Parser GetBinaryMultiplicationOperatorParser(Parser whitespaceParser) - { - return Symbol.Asterisk.Then(whitespaceParser).ThenReturn(BinaryOperatorType.Multiplication); - } - - internal static Parser GetBinaryDivisionOperatorParser(Parser whitespaceParser) - { - return Try(Symbol.Slash.Then(Not(Lookahead(Symbol.Slash)))).Then(whitespaceParser).ThenReturn(BinaryOperatorType.Division); - } - - internal static Parser GetBinaryGreaterOrEqualOperatorParser(Parser whitespaceParser) - { - return Try(Symbol.GreaterOrEquals).Then(whitespaceParser).ThenReturn(BinaryOperatorType.GreaterOrEqual); - } - - internal static Parser GetBinaryLessOrEqualOperatorParser(Parser whitespaceParser) - { - return Try(Symbol.LessOrEquals).Then(whitespaceParser).ThenReturn(BinaryOperatorType.LessOrEqual); - } - - internal static Parser GetBinaryEqualsOperatorParser(Parser whitespaceParser) - { - return Symbol.EqualsEquals.Then(whitespaceParser).ThenReturn(BinaryOperatorType.Equals); - } - - internal static Parser GetBinaryNotEqualsOperatorParser(Parser whitespaceParser) - { - return Symbol.NotEquals.Then(whitespaceParser).ThenReturn(BinaryOperatorType.NotEquals); - } - - internal static Parser GetBinaryGreaterThanOperatorParser(Parser whitespaceParser) - { - return Symbol.GreaterThanSign.Then(whitespaceParser).ThenReturn(BinaryOperatorType.GreaterThan); - } - - internal static Parser GetBinaryLessThanOperatorParser(Parser whitespaceParser) - { - return Symbol.LessThanSign.Then(whitespaceParser).ThenReturn(BinaryOperatorType.LessThan); - } - - internal static Parser GetBinaryAndOperatorParser(Parser whitespaceParser) - { - return Keyword.And.Then(whitespaceParser).ThenReturn(BinaryOperatorType.And); - } - - internal static Parser GetBinaryOrOperatorParser(Parser whitespaceParser) - { - return Keyword.Or.Then(whitespaceParser).ThenReturn(BinaryOperatorType.Or); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/BooleanLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/BooleanLiteralExpressionParser.cs deleted file mode 100644 index 5f6578eb..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/BooleanLiteralExpressionParser.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetBooleanLiteralExpressionParser(Parser whitespaceParser) - { - return Keyword.True.Then(whitespaceParser).ThenReturn(JassBooleanLiteralExpressionSyntax.True) - .Or(Keyword.False.Then(whitespaceParser).ThenReturn(JassBooleanLiteralExpressionSyntax.False)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/CallStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/CallStatementParser.cs deleted file mode 100644 index 2de6885d..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/CallStatementParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetCallStatementParser( - Parser whitespaceParser, - Parser argumentListParser, - Parser identifierNameParser) - { - return Keyword.Call.Then(whitespaceParser).Then(identifierNameParser).Then( - Symbol.LeftParenthesis.Then(whitespaceParser).Then(argumentListParser).Before(Symbol.RightParenthesis.Then(whitespaceParser)), - (id, arguments) => new JassCallStatementSyntax(id, arguments)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/CommentParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/CommentParser.cs deleted file mode 100644 index a50b93a4..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/CommentParser.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetCommentStringParser() - { - return Try(String($"{JassSymbol.Slash}{JassSymbol.Slash}")).Then(AnyCharExcept(JassSymbol.CarriageReturn, JassSymbol.LineFeed).ManyString()); - } - - internal static Parser GetCommentParser(Parser commentStringParser) - { - return commentStringParser.Select(comment => new JassCommentSyntax(comment)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/CompilationUnitParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/CompilationUnitParser.cs deleted file mode 100644 index c4c6d01c..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/CompilationUnitParser.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetCompilationUnitParser( - Parser declarationParser, - Parser commentStringParser, - Parser newlineParser) - { - return declarationParser.Before(commentStringParser.Optional().Then(newlineParser.Or(Lookahead(End)))).Many() - .Select(declarations => new JassCompilationUnitSyntax(declarations.ToImmutableArray())); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ConstantDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ConstantDeclarationParser.cs deleted file mode 100644 index 83df7537..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ConstantDeclarationParser.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetConstantDeclarationParser( - Parser equalsValueClauseParser, - Parser identifierNameParser, - Parser typeParser, - Parser whitespaceParser) - { - return Map( - (type, id, value) => new JassGlobalDeclarationSyntax(new JassVariableDeclaratorSyntax(type, id, value)), - Keyword.Constant.Then(whitespaceParser).Then(typeParser), - identifierNameParser, - equalsValueClauseParser); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/DebugCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/DebugCustomScriptActionParser.cs deleted file mode 100644 index efc70cc3..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/DebugCustomScriptActionParser.cs +++ /dev/null @@ -1,34 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetDebugCustomScriptActionParser( - Parser setCustomScriptActionParser, - Parser callCustomScriptActionParser, - Parser ifCustomScriptActionParser, - Parser loopCustomScriptActionParser, - Parser whitespaceParser) - { - return Keyword.Debug.Then(whitespaceParser).Then( - OneOf( - setCustomScriptActionParser, - callCustomScriptActionParser, - ifCustomScriptActionParser) - .Select(action => new JassDebugCustomScriptAction(action)) - .Or(loopCustomScriptActionParser.ThenReturn(JassDebugCustomScriptAction.DebugLoop))); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/DebugStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/DebugStatementParser.cs deleted file mode 100644 index 72fb3a65..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/DebugStatementParser.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetDebugStatementParser( - Parser expressionParser, - Parser statementListParser, - Parser setStatementParser, - Parser callStatementParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Keyword.Debug.Then(whitespaceParser).Then( - OneOf( - setStatementParser, - callStatementParser, - GetIfStatementParser(expressionParser, statementListParser, whitespaceParser, endOfLineParser), - GetLoopStatementParser(statementListParser, whitespaceParser, endOfLineParser)) - .Select(statement => new JassDebugStatementSyntax(statement))); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/DeclarationLineParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/DeclarationLineParser.cs deleted file mode 100644 index f6077551..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/DeclarationLineParser.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetDeclarationLineParser( - Parser emptyLineParser, - Parser commentParser, - Parser typeDeclarationParser, - Parser nativeFunctionDeclarationParser, - Parser functionDeclaratorParser, - Parser whitespaceParser) - { - return OneOf( - emptyLineParser.Cast(), - commentParser.Cast(), - typeDeclarationParser.Cast(), - GetGlobalsCustomScriptActionParser(whitespaceParser), - nativeFunctionDeclarationParser.Cast(), - GetFunctionCustomScriptActionParser(functionDeclaratorParser, whitespaceParser)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/DeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/DeclarationParser.cs deleted file mode 100644 index 824ee5bf..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/DeclarationParser.cs +++ /dev/null @@ -1,37 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetDeclarationParser( - Parser emptyParser, - Parser commentParser, - Parser typeDeclarationParser, - Parser nativeFunctionDeclarationParser, - Parser functionDeclarationParser, - Parser globalDeclarationParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return OneOf( - emptyParser.Cast(), - commentParser.Cast(), - typeDeclarationParser.Cast(), - GetGlobalDeclarationListParser(globalDeclarationParser, whitespaceParser, endOfLineParser), - nativeFunctionDeclarationParser.Cast(), - functionDeclarationParser.Cast()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ElseClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ElseClauseParser.cs deleted file mode 100644 index 46d32d45..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ElseClauseParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetElseClauseParser( - Parser statementListParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Keyword.Else.Then(whitespaceParser).Before(endOfLineParser) - .Then(statementListParser) - .Select(statementList => new JassElseClauseSyntax(statementList)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ElseCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ElseCustomScriptActionParser.cs deleted file mode 100644 index 56d6a871..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ElseCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetElseCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.Else.Then(whitespaceParser).ThenReturn(JassElseCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfClauseParser.cs deleted file mode 100644 index cf5b35f2..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfClauseParser.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetElseIfClauseParser( - Parser expressionParser, - Parser statementListParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Map( - (condition, statementList) => new JassElseIfClauseSyntax(condition, statementList), - Keyword.ElseIf.Then(whitespaceParser).Then(expressionParser).Before(Keyword.Then.Then(whitespaceParser)).Before(endOfLineParser), - statementListParser); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfCustomScriptActionParser.cs deleted file mode 100644 index f0acde85..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfCustomScriptActionParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetElseIfCustomScriptActionParser( - Parser expressionParser, - Parser whitespaceParser) - { - return Keyword.ElseIf.Then(whitespaceParser).Then(expressionParser).Before(Keyword.Then.Then(whitespaceParser)) - .Select(expression => new JassElseIfCustomScriptAction(expression)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EmptyParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EmptyParser.cs deleted file mode 100644 index 33d4aa21..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EmptyParser.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEmptyParser() - { - return Lookahead(Symbol.CarriageReturn.Or(Symbol.LineFeed)).ThenReturn(JassEmptySyntax.Value); - } - - internal static Parser GetEmptyLineParser() - { - return Lookahead(End).ThenReturn(JassEmptySyntax.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EndFunctionCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EndFunctionCustomScriptActionParser.cs deleted file mode 100644 index 073c8569..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EndFunctionCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEndFunctionCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.EndFunction.Then(whitespaceParser).ThenReturn(JassEndFunctionCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EndGlobalsCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EndGlobalsCustomScriptActionParser.cs deleted file mode 100644 index 91b14ce0..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EndGlobalsCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEndGlobalsCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.EndGlobals.Then(whitespaceParser).ThenReturn(JassEndGlobalsCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EndIfCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EndIfCustomScriptActionParser.cs deleted file mode 100644 index aecfd4ee..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EndIfCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEndIfCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.EndIf.Then(whitespaceParser).ThenReturn(JassEndIfCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EndLoopCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EndLoopCustomScriptActionParser.cs deleted file mode 100644 index 236751ee..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EndLoopCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEndLoopCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.EndLoop.Then(whitespaceParser).ThenReturn(JassEndLoopCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EndOfLineParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EndOfLineParser.cs deleted file mode 100644 index cf683ed8..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EndOfLineParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEndOfLineParser( - Parser commentStringParser, - Parser newLineParser) - { - return commentStringParser.Optional().Then(newLineParser); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/EqualsValueClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EqualsValueClauseParser.cs deleted file mode 100644 index 10ea5d65..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/EqualsValueClauseParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetEqualsValueClauseParser( - Parser whitespaceParser, - Parser expressionParser) - { - return Symbol.EqualsSign.Then(whitespaceParser).Then(expressionParser) - .Select(expression => new JassEqualsValueClauseSyntax(expression)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ExitStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ExitStatementParser.cs deleted file mode 100644 index ea887726..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ExitStatementParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetExitStatementParser( - Parser expressionParser, - Parser whitespaceParser) - { - return Keyword.ExitWhen.Then(whitespaceParser).Then(expressionParser) - .Select(expression => new JassExitStatementSyntax(expression)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ExpressionParser.cs deleted file mode 100644 index 13f6ac8f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ExpressionParser.cs +++ /dev/null @@ -1,62 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; -using Pidgin.Expression; - -using War3Net.CodeAnalysis.Jass.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetExpressionParser( - Parser whitespaceParser, - Parser identifierNameParser) - { - return Pidgin.Expression.ExpressionParser.Build( - expressionParser => - ( - OneOf( - GetCharacterLiteralExpressionParser().Before(whitespaceParser), - GetFourCCLiteralExpressionParser().Before(whitespaceParser), - GetHexadecimalLiteralExpressionParser().Before(whitespaceParser), - GetRealLiteralExpressionParser().Before(whitespaceParser), - GetOctalLiteralExpressionParser().Before(whitespaceParser), - GetDecimalLiteralExpressionParser().Before(whitespaceParser), - GetBooleanLiteralExpressionParser(whitespaceParser), - GetStringLiteralExpressionParser().Before(whitespaceParser), - GetNullLiteralExpressionParser(whitespaceParser), - GetFunctionReferenceExpressionParser(identifierNameParser, whitespaceParser), - GetInvocationExpressionParser(whitespaceParser, expressionParser, identifierNameParser), - GetArrayReferenceExpressionParser(whitespaceParser, expressionParser, identifierNameParser), - GetVariableReferenceExpressionParser(identifierNameParser), - GetParenthesizedExpressionParser(whitespaceParser, expressionParser)), - new[] - { - // https://www.hiveworkshop.com/threads/precedence-in-jass.43500/#post-378439 - Operator.PrefixChainable(GetUnaryNotOperatorParser(whitespaceParser).Prefix()), - Operator.PrefixChainable(GetUnaryPlusOperatorParser(whitespaceParser).Prefix(), GetUnaryMinusOperatorParser(whitespaceParser).Prefix()), - Operator.InfixL(GetBinaryMultiplicationOperatorParser(whitespaceParser).Infix()) - .And(Operator.InfixL(GetBinaryDivisionOperatorParser(whitespaceParser).Infix())), - Operator.InfixL(GetBinaryAddOperatorParser(whitespaceParser).Infix()) - .And(Operator.InfixL(GetBinarySubtractOperatorParser(whitespaceParser).Infix())), - Operator.InfixL(GetBinaryGreaterOrEqualOperatorParser(whitespaceParser).Infix()) - .And(Operator.InfixL(GetBinaryLessOrEqualOperatorParser(whitespaceParser).Infix())) - .And(Operator.InfixL(GetBinaryEqualsOperatorParser(whitespaceParser).Infix())) - .And(Operator.InfixL(GetBinaryNotEqualsOperatorParser(whitespaceParser).Infix())) - .And(Operator.InfixL(GetBinaryGreaterThanOperatorParser(whitespaceParser).Infix())) - .And(Operator.InfixL(GetBinaryLessThanOperatorParser(whitespaceParser).Infix())), - Operator.InfixL(GetBinaryAndOperatorParser(whitespaceParser).Infix()) - .And(Operator.InfixL(GetBinaryOrOperatorParser(whitespaceParser).Infix())), - })); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FunctionCustomScriptActionParser.cs deleted file mode 100644 index 987aa31f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionCustomScriptActionParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetFunctionCustomScriptActionParser( - Parser functionDeclaratorParser, - Parser whitespaceParser) - { - return Keyword.Function.Then(whitespaceParser).Then(functionDeclaratorParser) - .Select(functionDeclarator => new JassFunctionCustomScriptAction(functionDeclarator)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclarationParser.cs deleted file mode 100644 index 55bc8a43..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclarationParser.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetFunctionDeclarationParser( - Parser functionDeclaratorParser, - Parser statementListParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Map( - (declarator, body) => new JassFunctionDeclarationSyntax(declarator, body), - Keyword.Constant.Then(whitespaceParser).Optional().Then(Keyword.Function.Then(whitespaceParser)).Then(functionDeclaratorParser).Before(endOfLineParser), - statementListParser.Before(Keyword.EndFunction.Then(whitespaceParser))); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclaratorParser.cs deleted file mode 100644 index 6fffffee..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclaratorParser.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetFunctionDeclaratorParser( - Parser identifierNameParser, - Parser parameterListParser, - Parser typeParser, - Parser whitespaceParser) - { - return Map( - (id, parameterList, returnType) => new JassFunctionDeclaratorSyntax(id, parameterList, returnType), - identifierNameParser, - Keyword.Takes.Then(whitespaceParser).Then(Keyword.Nothing.Then(whitespaceParser).ThenReturn(JassParameterListSyntax.Empty).Or(parameterListParser)), - Keyword.Returns.Then(whitespaceParser).Then(Keyword.Nothing.Then(whitespaceParser).ThenReturn(JassTypeSyntax.Nothing).Or(typeParser))); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionReferenceExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FunctionReferenceExpressionParser.cs deleted file mode 100644 index 340b4860..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/FunctionReferenceExpressionParser.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetFunctionReferenceExpressionParser( - Parser identifierNameParser, - Parser whitespaceParser) - { - return Keyword.Function.Then(whitespaceParser).Then(identifierNameParser) - .Select(name => new JassFunctionReferenceExpressionSyntax(name)) - .Labelled("function reference"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationListParser.cs deleted file mode 100644 index d1287aa7..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationListParser.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetGlobalDeclarationListParser( - Parser globalDeclarationParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Keyword.Globals.Then(whitespaceParser).Then(endOfLineParser).Then(globalDeclarationParser.Many()).Before(Keyword.EndGlobals.Then(whitespaceParser)) - .Select(globals => new JassGlobalDeclarationListSyntax(globals.ToImmutableArray())); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationParser.cs deleted file mode 100644 index 80a43d75..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationParser.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetGlobalDeclarationParser( - Parser emptyParser, - Parser commentParser, - Parser constantDeclarationParser, - Parser variableDeclarationParser) - { - return OneOf( - emptyParser.Cast(), - commentParser.Cast(), - constantDeclarationParser.Cast(), - variableDeclarationParser.Cast()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalLineParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalLineParser.cs deleted file mode 100644 index 0fbabc15..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalLineParser.cs +++ /dev/null @@ -1,33 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetGlobalLineParser( - Parser emptyLineParser, - Parser commentParser, - Parser constantDeclarationParser, - Parser variableDeclarationParser, - Parser whitespaceParser) - { - return OneOf( - emptyLineParser.Cast(), - commentParser.Cast(), - constantDeclarationParser.Cast(), - variableDeclarationParser.Cast(), - GetEndGlobalsCustomScriptActionParser(whitespaceParser)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalsCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalsCustomScriptActionParser.cs deleted file mode 100644 index 0b9d89c3..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/GlobalsCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetGlobalsCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.Globals.Then(whitespaceParser).ThenReturn(JassGlobalsCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/HexadecimalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/HexadecimalLiteralExpressionParser.cs deleted file mode 100644 index 561873b0..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/HexadecimalLiteralExpressionParser.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetHexadecimalLiteralExpressionParser() - { - return Symbol.DollarSign.Or(Try(Symbol.Zero.Then(Symbol.X))).Then(UnsignedInt(16)) - .Select(value => new JassHexadecimalLiteralExpressionSyntax(value)) - .Labelled("hexadecimal literal"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/IfCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/IfCustomScriptActionParser.cs deleted file mode 100644 index 5c98523f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/IfCustomScriptActionParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetIfCustomScriptActionParser( - Parser expressionParser, - Parser whitespaceParser) - { - return Keyword.If.Then(whitespaceParser).Then(expressionParser).Before(Keyword.Then.Then(whitespaceParser)) - .Select(expression => new JassIfCustomScriptAction(expression)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/IfStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/IfStatementParser.cs deleted file mode 100644 index c0237f29..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/IfStatementParser.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetIfStatementParser( - Parser expressionParser, - Parser statementListParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Map( - (condition, statementList, elseIfClauses, elseClause, _) => (IStatementSyntax)new JassIfStatementSyntax(condition, statementList, elseIfClauses.ToImmutableArray(), elseClause.GetValueOrDefault()), - Keyword.If.Then(whitespaceParser).Then(expressionParser).Before(Keyword.Then.Then(whitespaceParser)).Before(endOfLineParser), - statementListParser, - GetElseIfClauseParser(expressionParser, statementListParser, whitespaceParser, endOfLineParser).Many(), - GetElseClauseParser(statementListParser, whitespaceParser, endOfLineParser).Optional(), - Keyword.EndIf.Then(whitespaceParser)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/InvocationExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/InvocationExpressionParser.cs deleted file mode 100644 index a1057e65..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/InvocationExpressionParser.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetInvocationExpressionParser( - Parser whitespaceParser, - Parser expressionParser, - Parser identifierNameParser) - { - return Try(identifierNameParser.Before(Symbol.LeftParenthesis.Then(whitespaceParser))) - .Then(GetArgumentListParser(whitespaceParser, expressionParser).Before(Symbol.RightParenthesis.Then(whitespaceParser)), (id, arguments) => (IExpressionSyntax)new JassInvocationExpressionSyntax(id, arguments)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/LocalVariableDeclarationStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/LocalVariableDeclarationStatementParser.cs deleted file mode 100644 index eef1310e..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/LocalVariableDeclarationStatementParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetLocalVariableDeclarationStatementParser( - Parser variableDeclaratorParser, - Parser whitespaceParser) - { - return Keyword.Local.Then(whitespaceParser).Then(variableDeclaratorParser) - .Select(declarator => new JassLocalVariableDeclarationStatementSyntax(declarator)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/LoopCustomScriptActionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/LoopCustomScriptActionParser.cs deleted file mode 100644 index 79b9f337..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/LoopCustomScriptActionParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetLoopCustomScriptActionParser(Parser whitespaceParser) - { - return Keyword.Loop.Then(whitespaceParser).ThenReturn(JassLoopCustomScriptAction.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/LoopStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/LoopStatementParser.cs deleted file mode 100644 index 52f6b53f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/LoopStatementParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetLoopStatementParser( - Parser statementListParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - return Keyword.Loop.Then(whitespaceParser).Then(endOfLineParser) - .Then(statementListParser).Before(Keyword.EndLoop.Then(whitespaceParser)) - .Select(statementList => new JassLoopStatementSyntax(statementList)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/NativeFunctionDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/NativeFunctionDeclarationParser.cs deleted file mode 100644 index 1d23d8d4..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/NativeFunctionDeclarationParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetNativeFunctionDeclarationParser( - Parser functionDeclaratorParser, - Parser whitespaceParser) - { - return Try(Keyword.Constant.Then(whitespaceParser).Optional().Then(Keyword.Native.Then(whitespaceParser))).Then(functionDeclaratorParser) - .Select(functionDeclaration => new JassNativeFunctionDeclarationSyntax(functionDeclaration)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/NewLineParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/NewLineParser.cs deleted file mode 100644 index e8a4a927..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/NewLineParser.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetNewLineParser(Parser whitespaceParser) - { - return OneOf( - Symbol.CarriageReturn.Before(Symbol.LineFeed.Optional()), - Symbol.LineFeed).Then(whitespaceParser).Labelled("newline"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/NullLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/NullLiteralExpressionParser.cs deleted file mode 100644 index b0b06978..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/NullLiteralExpressionParser.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetNullLiteralExpressionParser(Parser whitespaceParser) - { - return Keyword.Null.Then(whitespaceParser).ThenReturn(JassNullLiteralExpressionSyntax.Value) - .Labelled("null literal"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ParameterListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ParameterListParser.cs deleted file mode 100644 index 4c91f2a1..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ParameterListParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetParameterListParser( - Parser whitespaceParser, - Parser parameterParser) - { - return parameterParser.Separated(Symbol.Comma.Then(whitespaceParser)) - .Select(parameters => new JassParameterListSyntax(parameters.ToImmutableArray())); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ParenthesizedExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ParenthesizedExpressionParser.cs deleted file mode 100644 index b9709b13..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ParenthesizedExpressionParser.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetParenthesizedExpressionParser( - Parser whitespaceParser, - Parser expressionParser) - { - return Symbol.LeftParenthesis.Then(whitespaceParser).Then(expressionParser).Before(Symbol.RightParenthesis.Then(whitespaceParser)) - .Select(expression => new JassParenthesizedExpressionSyntax(expression)) - .Labelled("parenthesized expression"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/RealLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/RealLiteralExpressionParser.cs deleted file mode 100644 index c5cb8567..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/RealLiteralExpressionParser.cs +++ /dev/null @@ -1,36 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetRealLiteralExpressionParser() - { -#if true - return Try(Token(char.IsDigit).AtLeastOnceString().Before(Symbol.FullStop)) - .Then(Token(char.IsDigit).ManyString(), (intPart, fracPart) => (IExpressionSyntax)new JassRealLiteralExpressionSyntax(intPart, fracPart)) - .Or(Symbol.FullStop.Then(Token(char.IsDigit).AtLeastOnceString()) - .Select(fracPart => new JassRealLiteralExpressionSyntax($"{JassSymbol.Zero}", fracPart))) - .Labelled("real literal"); -#else - return Try(Token(char.IsDigit).AtLeastOnceString().Before(Symbol.FullStop)) - .Then(Token(char.IsDigit).ManyString(), (intPart, fracPart) => (IExpressionSyntax)new JassRealLiteralExpressionSyntax(float.Parse($"{intPart}{JassSymbol.FullStop}{fracPart}", CultureInfo.InvariantCulture))) - .Or(Symbol.FullStop.Then(Token(char.IsDigit).AtLeastOnceString()) - .Select(fracPart => new JassRealLiteralExpressionSyntax(float.Parse($"{JassSymbol.Zero}{JassSymbol.FullStop}{fracPart}", CultureInfo.InvariantCulture)))) - .Labelled("real literal"); -#endif - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/ReturnStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ReturnStatementParser.cs deleted file mode 100644 index 754b33ef..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/ReturnStatementParser.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetReturnStatementParser( - Parser expressionParser, - Parser whitespaceParser) - { - return Keyword.Return.Then(whitespaceParser).Then(expressionParser.Optional()) - .Select(expression => expression.HasValue ? new JassReturnStatementSyntax(expression.Value) : JassReturnStatementSyntax.Empty); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/SetStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/SetStatementParser.cs deleted file mode 100644 index 6493fdf1..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/SetStatementParser.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetSetStatementParser( - Parser whitespaceParser, - Parser expressionParser, - Parser equalsValueClauseParser, - Parser identifierNameParser) - { - return Map( - (id, indexer, equals) => new JassSetStatementSyntax(id, indexer.GetValueOrDefault(), equals), - Keyword.Set.Then(whitespaceParser).Then(identifierNameParser), - Symbol.LeftSquareBracket.Then(whitespaceParser).Then(expressionParser).Before(Symbol.RightSquareBracket.Then(whitespaceParser)).Optional(), - equalsValueClauseParser); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/StatementLineParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/StatementLineParser.cs deleted file mode 100644 index 07506f73..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/StatementLineParser.cs +++ /dev/null @@ -1,52 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetStatementLineParser( - Parser emptyLineParser, - Parser commentParser, - Parser localVariableDeclarationStatementParser, - Parser setCustomScriptActionParser, - Parser callCustomScriptActionParser, - Parser exitStatementParser, - Parser returnStatementParser, - Parser expressionParser, - Parser whitespaceParser) - { - var setParser = setCustomScriptActionParser.Cast(); - var callParser = callCustomScriptActionParser.Cast(); - var ifCustomScriptActionParser = GetIfCustomScriptActionParser(expressionParser, whitespaceParser); - var loopCustomScriptActionParser = GetLoopCustomScriptActionParser(whitespaceParser); - - return OneOf( - emptyLineParser.Cast(), - commentParser.Cast(), - localVariableDeclarationStatementParser.Cast(), - setParser, - callParser, - ifCustomScriptActionParser, - GetElseIfCustomScriptActionParser(expressionParser, whitespaceParser), - GetElseCustomScriptActionParser(whitespaceParser), - GetEndIfCustomScriptActionParser(whitespaceParser), - loopCustomScriptActionParser, - GetEndLoopCustomScriptActionParser(whitespaceParser), - exitStatementParser.Cast(), - returnStatementParser.Cast(), - GetEndFunctionCustomScriptActionParser(whitespaceParser), - GetDebugCustomScriptActionParser(setParser, callParser, ifCustomScriptActionParser, loopCustomScriptActionParser, whitespaceParser)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/StatementListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/StatementListParser.cs deleted file mode 100644 index 54585424..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/StatementListParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetStatementListParser( - Parser statementParser, - Parser endOfLineParser) - { - return statementParser.Before(endOfLineParser).Many() - .Select(statements => new JassStatementListSyntax(statements.ToImmutableArray())); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/StatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/StatementParser.cs deleted file mode 100644 index 0342ef4e..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/StatementParser.cs +++ /dev/null @@ -1,54 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetStatementParser( - Parser emptyParser, - Parser commentParser, - Parser localVariableDeclarationStatementParser, - Parser exitStatementParser, - Parser returnStatementParser, - Parser setStatementParser, - Parser callStatementParser, - Parser expressionParser, - Parser whitespaceParser, - Parser endOfLineParser) - { - var setParser = setStatementParser.Cast(); - var callParser = callStatementParser.Cast(); - - return Rec( - statementParser => - { - var statementListParser = GetStatementListParser( - statementParser, - endOfLineParser); - - return OneOf( - emptyParser.Cast(), - commentParser.Cast(), - localVariableDeclarationStatementParser.Cast(), - setParser, - callParser, - GetIfStatementParser(expressionParser, statementListParser, whitespaceParser, endOfLineParser), - GetLoopStatementParser(statementListParser, whitespaceParser, endOfLineParser), - exitStatementParser.Cast(), - returnStatementParser.Cast(), - GetDebugStatementParser(expressionParser, statementListParser, setParser, callParser, whitespaceParser, endOfLineParser)); - }); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/TypeDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/TypeDeclarationParser.cs deleted file mode 100644 index 2fc9e60c..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/TypeDeclarationParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetTypeDeclarationParser( - Parser identifierNameParser, - Parser typeParser, - Parser whitespaceParser) - { - return Keyword.Type.Then(whitespaceParser).Then(identifierNameParser).Then( - Keyword.Extends.Then(whitespaceParser).Then(typeParser), - (@new, @base) => new JassTypeDeclarationSyntax(@new, @base)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/TypeParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/TypeParser.cs deleted file mode 100644 index 7f39d22f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/TypeParser.cs +++ /dev/null @@ -1,33 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetTypeParser( - Parser identifierNameParser, - Parser whitespaceParser) - { - return OneOf( - Keyword.Code.Then(whitespaceParser).ThenReturn(JassTypeSyntax.Code), - Keyword.Handle.Then(whitespaceParser).ThenReturn(JassTypeSyntax.Handle), - Keyword.Integer.Then(whitespaceParser).ThenReturn(JassTypeSyntax.Integer), - Keyword.Real.Then(whitespaceParser).ThenReturn(JassTypeSyntax.Real), - Keyword.Boolean.Then(whitespaceParser).ThenReturn(JassTypeSyntax.Boolean), - Keyword.String.Then(whitespaceParser).ThenReturn(JassTypeSyntax.String), - identifierNameParser.Map(id => new JassTypeSyntax(id))) - .Labelled("type"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/UnaryOperatorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/UnaryOperatorParser.cs deleted file mode 100644 index e5dca025..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/UnaryOperatorParser.cs +++ /dev/null @@ -1,41 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetUnaryOperatorParser(Parser whitespaceParser) - { - return OneOf( - GetUnaryPlusOperatorParser(whitespaceParser), - GetUnaryMinusOperatorParser(whitespaceParser), - GetUnaryNotOperatorParser(whitespaceParser)); - } - - internal static Parser GetUnaryPlusOperatorParser(Parser whitespaceParser) - { - return Symbol.PlusSign.Then(whitespaceParser).ThenReturn(UnaryOperatorType.Plus); - } - - internal static Parser GetUnaryMinusOperatorParser(Parser whitespaceParser) - { - return Symbol.MinusSign.Then(whitespaceParser).ThenReturn(UnaryOperatorType.Minus); - } - - internal static Parser GetUnaryNotOperatorParser(Parser whitespaceParser) - { - return Keyword.Not.Then(whitespaceParser).ThenReturn(UnaryOperatorType.Not); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclarationParser.cs deleted file mode 100644 index f5d9a736..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclarationParser.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetVariableDeclarationParser( - Parser equalsValueClauseParser, - Parser identifierNameParser, - Parser typeParser, - Parser whitespaceParser) - { - return GetVariableDeclaratorParser(equalsValueClauseParser, identifierNameParser, Try(typeParser), whitespaceParser) - .Select(declarator => new JassGlobalDeclarationSyntax(declarator)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclaratorParser.cs deleted file mode 100644 index 6c23918b..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/VariableDeclaratorParser.cs +++ /dev/null @@ -1,36 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetVariableDeclaratorParser( - Parser equalsValueClauseParser, - Parser identifierNameParser, - Parser typeParser, - Parser whitespaceParser) - { - return OneOf( - Map( - (type, id) => (IVariableDeclaratorSyntax)new JassArrayDeclaratorSyntax(type, id), - Try(typeParser.Before(Keyword.Array)).Before(whitespaceParser), - identifierNameParser), - Map( - (type, id, value) => (IVariableDeclaratorSyntax)new JassVariableDeclaratorSyntax(type, id, value.GetValueOrDefault()), - typeParser, - identifierNameParser, - equalsValueClauseParser.Optional())); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/VariableReferenceExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/VariableReferenceExpressionParser.cs deleted file mode 100644 index 77197793..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/VariableReferenceExpressionParser.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetVariableReferenceExpressionParser(Parser identifierNameParser) - { - return identifierNameParser - .Select(name => new JassVariableReferenceExpressionSyntax(name)) - .Labelled("variable reference"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parser/WhitespaceParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/WhitespaceParser.cs deleted file mode 100644 index 538bf544..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Parser/WhitespaceParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Pidgin; - -using static Pidgin.Parser; - -namespace War3Net.CodeAnalysis.Jass -{ - internal partial class JassParser - { - internal static Parser GetWhitespaceParser() - { - return Token(JassSyntaxFacts.IsWhitespaceCharacter).SkipMany(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Parsers/IdentifierExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parsers/IdentifierExpressionParser.cs new file mode 100644 index 00000000..53f9f1bb --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Parsers/IdentifierExpressionParser.cs @@ -0,0 +1,147 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Parsers +{ + internal sealed class IdentifierExpressionParser : Parser + { + private static readonly Dictionary _keywordLiteralExpressionKinds = GetKeywordLiteralExpressionKinds(); + + private readonly Parser _identifierParser; + private readonly Parser _identifierNameParser; + private readonly Parser _argumentListParser; + private readonly Parser _elementAccessClauseParser; + private readonly Parser _triviaParser; + + public IdentifierExpressionParser( + Parser identifierParser, + Parser identifierNameParser, + Parser argumentListParser, + Parser elementAccessClauseParser, + Parser triviaParser) + { + _identifierParser = identifierParser; + _identifierNameParser = identifierNameParser; + _argumentListParser = argumentListParser; + _elementAccessClauseParser = elementAccessClauseParser; + _triviaParser = triviaParser; + } + + public override bool TryParse( + ref ParseState state, + ref PooledList> expecteds, + [MaybeNullWhen(false)] out JassExpressionSyntax result) + { + var childExpecteds = new PooledList>(state.Configuration.ArrayPoolProvider.GetArrayPool>()); + + if (!_identifierParser.TryParse(ref state, ref childExpecteds, out var identifierResult)) + { + expecteds.AddRange(childExpecteds.AsSpan()); + childExpecteds.Dispose(); + result = null; + return false; + } + + childExpecteds.Clear(); + + if (!_triviaParser.TryParse(ref state, ref childExpecteds, out var identifierTriviaResult)) + { + expecteds.AddRange(childExpecteds.AsSpan()); + childExpecteds.Dispose(); + result = null; + return false; + } + + childExpecteds.Clear(); + + if (_keywordLiteralExpressionKinds.TryGetValue(identifierResult, out var keywordLiteralExpressionKind)) + { + childExpecteds.Dispose(); + result = new JassLiteralExpressionSyntax(new JassSyntaxToken(keywordLiteralExpressionKind, identifierResult, identifierTriviaResult)); + return true; + } + + if (string.Equals(identifierResult, JassKeyword.Function, StringComparison.Ordinal)) + { + if (!_identifierNameParser.TryParse(ref state, ref childExpecteds, out var identifierNameResult)) + { + expecteds.AddRange(childExpecteds.AsSpan()); + childExpecteds.Dispose(); + result = null; + return false; + } + + childExpecteds.Dispose(); + result = new JassFunctionReferenceExpressionSyntax( + new JassSyntaxToken(JassSyntaxKind.FunctionKeyword, JassKeyword.Function, identifierTriviaResult), + identifierNameResult); + + return true; + } + + var identifierStartLoc = state.Location; + + if (_argumentListParser.TryParse(ref state, ref childExpecteds, out var argumentListResult)) + { + childExpecteds.Dispose(); + result = new JassInvocationExpressionSyntax( + new JassIdentifierNameSyntax(new JassSyntaxToken(JassSyntaxKind.IdentifierToken, identifierResult, identifierTriviaResult)), + argumentListResult); + + return true; + } + else if (state.Location > identifierStartLoc) + { + expecteds.AddRange(childExpecteds.AsSpan()); + childExpecteds.Dispose(); + result = null; + return false; + } + + childExpecteds.Clear(); + + if (_elementAccessClauseParser.TryParse(ref state, ref childExpecteds, out var elementAccessClauseResult)) + { + childExpecteds.Dispose(); + result = new JassElementAccessExpressionSyntax( + new JassIdentifierNameSyntax(new JassSyntaxToken(JassSyntaxKind.IdentifierToken, identifierResult, identifierTriviaResult)), + elementAccessClauseResult); + + return true; + } + else if (state.Location > identifierStartLoc) + { + expecteds.AddRange(childExpecteds.AsSpan()); + childExpecteds.Dispose(); + result = null; + return false; + } + + childExpecteds.Dispose(); + result = new JassIdentifierNameSyntax(new JassSyntaxToken(JassSyntaxKind.IdentifierToken, identifierResult, identifierTriviaResult)); + return true; + } + + private static Dictionary GetKeywordLiteralExpressionKinds() + { + return new Dictionary(StringComparer.Ordinal) + { + { JassKeyword.True, JassSyntaxKind.TrueKeyword }, + { JassKeyword.False, JassSyntaxKind.FalseKeyword }, + { JassKeyword.Null, JassSyntaxKind.NullKeyword }, + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ArgumentListRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ArgumentListRenamer.cs index 5bc8a01f..9e86f842 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ArgumentListRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ArgumentListRenamer.cs @@ -5,7 +5,6 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using War3Net.CodeAnalysis.Jass.Syntax; @@ -16,26 +15,45 @@ public partial class JassRenamer { private bool TryRenameArgumentList(JassArgumentListSyntax argumentList, [NotNullWhen(true)] out JassArgumentListSyntax? renamedArgumentList) { - var isRenamed = false; - - var argumentsBuilder = ImmutableArray.CreateBuilder(); - foreach (var argument in argumentList.Arguments) + for (var i = 0; i < argumentList.ArgumentList.Items.Length; i++) { - if (TryRenameExpression(argument, out var renamedArgument)) - { - argumentsBuilder.Add(renamedArgument); - isRenamed = true; - } - else + if (TryRenameExpression(argumentList.ArgumentList.Items[i], out var renamedArgument)) { - argumentsBuilder.Add(argument); - } - } + SeparatedSyntaxList.Builder argumentListBuilder; + if (i == 0) + { + argumentListBuilder = SeparatedSyntaxList.CreateBuilder(renamedArgument, argumentList.ArgumentList.Items.Length); + } + else + { + argumentListBuilder = SeparatedSyntaxList.CreateBuilder(argumentList.ArgumentList.Items[0], argumentList.ArgumentList.Items.Length); + for (var j = 0; j < i; j++) + { + argumentListBuilder.Add(argumentList.ArgumentList.Separators[j], argumentList.ArgumentList.Items[j + 1]); + } - if (isRenamed) - { - renamedArgumentList = new JassArgumentListSyntax(argumentsBuilder.ToImmutable()); - return true; + argumentListBuilder.Add(argumentList.ArgumentList.Separators[i - 1], renamedArgument); + } + + while (++i < argumentList.ArgumentList.Items.Length) + { + if (TryRenameExpression(argumentList.ArgumentList.Items[i], out renamedArgument)) + { + argumentListBuilder.Add(argumentList.ArgumentList.Separators[i - 1], renamedArgument); + } + else + { + argumentListBuilder.Add(argumentList.ArgumentList.Separators[i - 1], argumentList.ArgumentList.Items[i]); + } + } + + renamedArgumentList = new JassArgumentListSyntax( + argumentList.OpenParenToken, + argumentListBuilder.ToSeparatedSyntaxList(), + argumentList.CloseParenToken); + + return true; + } } renamedArgumentList = null; diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayDeclaratorRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayDeclaratorRenamer.cs index e6a0dfef..e3a42497 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayDeclaratorRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayDeclaratorRenamer.cs @@ -13,12 +13,13 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameArrayDeclarator(JassArrayDeclaratorSyntax arrayDeclarator, [NotNullWhen(true)] out IVariableDeclaratorSyntax? renamedArrayDeclarator) + private bool TryRenameArrayDeclarator(JassArrayDeclaratorSyntax arrayDeclarator, [NotNullWhen(true)] out JassVariableOrArrayDeclaratorSyntax? renamedArrayDeclarator) { if (TryRenameVariableIdentifierName(arrayDeclarator.IdentifierName, out var renamedIdentifierName)) { renamedArrayDeclarator = new JassArrayDeclaratorSyntax( arrayDeclarator.Type, + arrayDeclarator.ArrayToken, renamedIdentifierName); return true; diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayReferenceExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayReferenceExpressionRenamer.cs deleted file mode 100644 index d6a2a367..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ArrayReferenceExpressionRenamer.cs +++ /dev/null @@ -1,32 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Diagnostics.CodeAnalysis; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenamer - { - private bool TryRenameArrayReferenceExpression(JassArrayReferenceExpressionSyntax arrayReferenceExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedArrayReferenceExpression) - { - if (TryRenameVariableIdentifierName(arrayReferenceExpression.IdentifierName, out var renamedIdentifierName) | - TryRenameExpression(arrayReferenceExpression.Indexer, out var renamedIndexer)) - { - renamedArrayReferenceExpression = new JassArrayReferenceExpressionSyntax( - renamedIdentifierName ?? arrayReferenceExpression.IdentifierName, - renamedIndexer ?? arrayReferenceExpression.Indexer); - - return true; - } - - renamedArrayReferenceExpression = null; - return false; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/BinaryExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/BinaryExpressionRenamer.cs index 046f7c63..68016eb5 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/BinaryExpressionRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/BinaryExpressionRenamer.cs @@ -13,14 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameBinaryExpression(JassBinaryExpressionSyntax binaryExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedBinaryExpression) + private bool TryRenameBinaryExpression(JassBinaryExpressionSyntax binaryExpression, [NotNullWhen(true)] out JassExpressionSyntax? renamedBinaryExpression) { if (TryRenameExpression(binaryExpression.Left, out var renamedLeftExpression) | TryRenameExpression(binaryExpression.Right, out var renamedRightExpression)) { renamedBinaryExpression = new JassBinaryExpressionSyntax( - binaryExpression.Operator, renamedLeftExpression ?? binaryExpression.Left, + binaryExpression.OperatorToken, renamedRightExpression ?? binaryExpression.Right); return true; diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/CallStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/CallStatementRenamer.cs index 6186fe21..b2978eb1 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/CallStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/CallStatementRenamer.cs @@ -6,7 +6,6 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using War3Net.CodeAnalysis.Jass.Syntax; @@ -15,18 +14,23 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameCallStatement(JassCallStatementSyntax callStatement, [NotNullWhen(true)] out IStatementSyntax? renamedCallStatement) + private bool TryRenameCallStatement(JassCallStatementSyntax callStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedCallStatement) { if (RenameExecuteFuncArgument && - string.Equals(callStatement.IdentifierName.Name, "ExecuteFunc", StringComparison.Ordinal)) + string.Equals(callStatement.IdentifierName.Token.Text, "ExecuteFunc", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 1 && - callStatement.Arguments.Arguments[0] is JassStringLiteralExpressionSyntax stringLiteralExpression && - _functionDeclarationRenames.TryGetValue(stringLiteralExpression.Value, out var renamedValue)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 1 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassLiteralExpressionSyntax stringLiteralExpression && + stringLiteralExpression.Token.SyntaxKind == JassSyntaxKind.StringLiteralToken && + TryRenameFunctionIdentifierToken(stringLiteralExpression.Token, out var renamedToken)) { renamedCallStatement = new JassCallStatementSyntax( + callStatement.CallToken, callStatement.IdentifierName, - new JassArgumentListSyntax(new IExpressionSyntax[] { new JassStringLiteralExpressionSyntax(renamedValue.Name) }.ToImmutableArray())); + new JassArgumentListSyntax( + callStatement.ArgumentList.OpenParenToken, + SeparatedSyntaxList.Create(new JassLiteralExpressionSyntax(renamedToken)), + callStatement.ArgumentList.CloseParenToken)); return true; } @@ -36,11 +40,12 @@ callStatement.Arguments.Arguments[0] is JassStringLiteralExpressionSyntax string } if (TryRenameFunctionIdentifierName(callStatement.IdentifierName, out var renamedIdentifierName) | - TryRenameArgumentList(callStatement.Arguments, out var renamedArguments)) + TryRenameArgumentList(callStatement.ArgumentList, out var renamedArguments)) { renamedCallStatement = new JassCallStatementSyntax( + callStatement.CallToken, renamedIdentifierName ?? callStatement.IdentifierName, - renamedArguments ?? callStatement.Arguments); + renamedArguments ?? callStatement.ArgumentList); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/CompilationUnitRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/CompilationUnitRenamer.cs index 965e116c..4b0762f7 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/CompilationUnitRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/CompilationUnitRenamer.cs @@ -22,26 +22,36 @@ public bool TryRenameCompilationUnit(JassCompilationUnitSyntax compilationUnit, throw new ArgumentNullException(nameof(compilationUnit)); } - var isRenamed = false; - - var declarationsBuilder = ImmutableArray.CreateBuilder(); - foreach (var declaration in compilationUnit.Declarations) + for (var i = 0; i < compilationUnit.Declarations.Length; i++) { - if (TryRenameDeclaration(declaration, out var renamedDeclaration)) - { - declarationsBuilder.Add(renamedDeclaration); - isRenamed = true; - } - else + if (TryRenameDeclaration(compilationUnit.Declarations[i], out var renamedDeclaration)) { - declarationsBuilder.Add(declaration); - } - } + var builder = ImmutableArray.CreateBuilder(compilationUnit.Declarations.Length); + for (var j = 0; j < i; j++) + { + builder.Add(compilationUnit.Declarations[j]); + } - if (isRenamed) - { - renamedCompilationUnit = new JassCompilationUnitSyntax(declarationsBuilder.ToImmutable()); - return true; + builder.Add(renamedDeclaration); + + while (++i < compilationUnit.Declarations.Length) + { + if (TryRenameDeclaration(compilationUnit.Declarations[i], out renamedDeclaration)) + { + builder.Add(renamedDeclaration); + } + else + { + builder.Add(compilationUnit.Declarations[i]); + } + } + + renamedCompilationUnit = new JassCompilationUnitSyntax( + builder.ToImmutable(), + compilationUnit.EndOfFileToken); + + return true; + } } renamedCompilationUnit = null; diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/DebugStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/DebugStatementRenamer.cs index dfe20233..c8aed527 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/DebugStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/DebugStatementRenamer.cs @@ -13,11 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameDebugStatement(JassDebugStatementSyntax debugStatement, [NotNullWhen(true)] out IStatementSyntax? renamedDebugStatement) + private bool TryRenameDebugStatement(JassDebugStatementSyntax debugStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedDebugStatement) { if (TryRenameStatement(debugStatement.Statement, out var renamedStatement)) { - renamedDebugStatement = new JassDebugStatementSyntax(renamedStatement); + renamedDebugStatement = new JassDebugStatementSyntax( + debugStatement.DebugToken, + renamedStatement); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/DeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/DeclarationRenamer.cs index 7bf04034..2e2506c4 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/DeclarationRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/DeclarationRenamer.cs @@ -13,11 +13,11 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameDeclaration(ITopLevelDeclarationSyntax declaration, [NotNullWhen(true)] out ITopLevelDeclarationSyntax? renamedDeclaration) + private bool TryRenameDeclaration(JassTopLevelDeclarationSyntax declaration, [NotNullWhen(true)] out JassTopLevelDeclarationSyntax? renamedDeclaration) { return declaration switch { - JassGlobalDeclarationListSyntax globalDeclarationList => TryRenameGlobalDeclarationList(globalDeclarationList, out renamedDeclaration), + JassGlobalsDeclarationSyntax globalsDeclaration => TryRenameGlobalsDeclaration(globalsDeclaration, out renamedDeclaration), JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration => TryRenameNativeFunctionDeclaration(nativeFunctionDeclaration, out renamedDeclaration), JassFunctionDeclarationSyntax functionDeclaration => TryRenameFunctionDeclaration(functionDeclaration, out renamedDeclaration), diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessClauseRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessClauseRenamer.cs new file mode 100644 index 00000000..38bf81bf --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessClauseRenamer.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameElementAccessClause(JassElementAccessClauseSyntax? elementAccessClause, [NotNullWhen(true)] out JassElementAccessClauseSyntax? renamedElementAccessClause) + { + if (elementAccessClause is not null && + TryRenameExpression(elementAccessClause.Expression, out var renamedExpression)) + { + renamedElementAccessClause = new JassElementAccessClauseSyntax( + elementAccessClause.OpenBracketToken, + renamedExpression, + elementAccessClause.CloseBracketToken); + + return true; + } + + renamedElementAccessClause = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessExpressionRenamer.cs new file mode 100644 index 00000000..296176e3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ElementAccessExpressionRenamer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameElementAccessExpression(JassElementAccessExpressionSyntax elementAccessExpression, [NotNullWhen(true)] out JassExpressionSyntax? renamedElementAccessExpression) + { + if (TryRenameVariableIdentifierName(elementAccessExpression.IdentifierName, out var renamedIdentifierName) | + TryRenameElementAccessClause(elementAccessExpression.ElementAccessClause, out var renamedElementAccessClause)) + { + renamedElementAccessExpression = new JassElementAccessExpressionSyntax( + renamedIdentifierName ?? elementAccessExpression.IdentifierName, + renamedElementAccessClause ?? elementAccessExpression.ElementAccessClause); + + return true; + } + + renamedElementAccessExpression = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ElseClauseRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseClauseRenamer.cs index 586a0e14..e2cc3339 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ElseClauseRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseClauseRenamer.cs @@ -16,9 +16,12 @@ public partial class JassRenamer private bool TryRenameElseClause(JassElseClauseSyntax? elseClause, [NotNullWhen(true)] out JassElseClauseSyntax? renamedElseClause) { if (elseClause is not null && - TryRenameStatementList(elseClause.Body, out var renamedBody)) + TryRenameStatementList(elseClause.Statements, out var renamedStatements)) { - renamedElseClause = new JassElseClauseSyntax(renamedBody); + renamedElseClause = new JassElseClauseSyntax( + elseClause.ElseToken, + renamedStatements.Value); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseDeclaratorRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseDeclaratorRenamer.cs new file mode 100644 index 00000000..ee798102 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseDeclaratorRenamer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameElseIfClauseDeclarator(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, [NotNullWhen(true)] out JassElseIfClauseDeclaratorSyntax? renamedElseIfClauseDeclarator) + { + if (TryRenameExpression(elseIfClauseDeclarator.Condition, out var renamedCondition)) + { + renamedElseIfClauseDeclarator = new JassElseIfClauseDeclaratorSyntax( + elseIfClauseDeclarator.ElseIfToken, + renamedCondition, + elseIfClauseDeclarator.ThenToken); + + return true; + } + + renamedElseIfClauseDeclarator = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseListRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseListRenamer.cs new file mode 100644 index 00000000..f6241209 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseListRenamer.cs @@ -0,0 +1,52 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameElseIfClauseList(ImmutableArray elseIfClauses, [NotNullWhen(true)] out ImmutableArray? renamedElseIfClauses) + { + for (var i = 0; i < elseIfClauses.Length; i++) + { + if (TryRenameElseIfClause(elseIfClauses[i], out var renamedElseIfClause)) + { + var builder = ImmutableArray.CreateBuilder(elseIfClauses.Length); + for (var j = 0; j < i; j++) + { + builder.Add(elseIfClauses[j]); + } + + builder.Add(renamedElseIfClause); + + while (++i < elseIfClauses.Length) + { + if (TryRenameElseIfClause(elseIfClauses[i], out renamedElseIfClause)) + { + builder.Add(renamedElseIfClause); + } + else + { + builder.Add(elseIfClauses[i]); + } + } + + renamedElseIfClauses = builder.ToImmutable(); + return true; + } + } + + renamedElseIfClauses = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseRenamer.cs index 865f505d..8a4728c8 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ElseIfClauseRenamer.cs @@ -15,12 +15,12 @@ public partial class JassRenamer { private bool TryRenameElseIfClause(JassElseIfClauseSyntax elseIfClause, [NotNullWhen(true)] out JassElseIfClauseSyntax? renamedElseIfClause) { - if (TryRenameExpression(elseIfClause.Condition, out var renamedCondition) | - TryRenameStatementList(elseIfClause.Body, out var renamedBody)) + if (TryRenameElseIfClauseDeclarator(elseIfClause.ElseIfClauseDeclarator, out var renamedDeclarator) | + TryRenameStatementList(elseIfClause.Statements, out var renamedStatements)) { renamedElseIfClause = new JassElseIfClauseSyntax( - renamedCondition ?? elseIfClause.Condition, - renamedBody ?? elseIfClause.Body); + renamedDeclarator ?? elseIfClause.ElseIfClauseDeclarator, + renamedStatements ?? elseIfClause.Statements); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/EqualsValueClauseRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/EqualsValueClauseRenamer.cs index 2f341972..4204933b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/EqualsValueClauseRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/EqualsValueClauseRenamer.cs @@ -18,7 +18,10 @@ private bool TryRenameEqualsValueClause(JassEqualsValueClauseSyntax? equalsValue if (equalsValueClause is not null && TryRenameExpression(equalsValueClause.Expression, out var renamedExpression)) { - renamedEqualsValueClause = new JassEqualsValueClauseSyntax(renamedExpression); + renamedEqualsValueClause = new JassEqualsValueClauseSyntax( + equalsValueClause.EqualsToken, + renamedExpression); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ExitStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ExitStatementRenamer.cs index 4dd741f3..207234e2 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ExitStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ExitStatementRenamer.cs @@ -13,11 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameExitStatement(JassExitStatementSyntax exitStatement, [NotNullWhen(true)] out IStatementSyntax? renamedExitStatement) + private bool TryRenameExitStatement(JassExitStatementSyntax exitStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedExitStatement) { if (TryRenameExpression(exitStatement.Condition, out var renamedCondition)) { - renamedExitStatement = new JassExitStatementSyntax(renamedCondition); + renamedExitStatement = new JassExitStatementSyntax( + exitStatement.ExitWhenToken, + renamedCondition); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ExpressionRenamer.cs index f1257773..3cbb023d 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ExpressionRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ExpressionRenamer.cs @@ -13,14 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameExpression(IExpressionSyntax? expression, [NotNullWhen(true)] out IExpressionSyntax? renamedExpression) + private bool TryRenameExpression(JassExpressionSyntax? expression, [NotNullWhen(true)] out JassExpressionSyntax? renamedExpression) { return expression switch { JassFunctionReferenceExpressionSyntax functionReferenceExpression => TryRenameFunctionReferenceExpression(functionReferenceExpression, out renamedExpression), JassInvocationExpressionSyntax invocationExpression => TryRenameInvocationExpression(invocationExpression, out renamedExpression), - JassArrayReferenceExpressionSyntax arrayReferenceExpression => TryRenameArrayReferenceExpression(arrayReferenceExpression, out renamedExpression), - JassVariableReferenceExpressionSyntax variableReferenceExpression => TryRenameVariableReferenceExpression(variableReferenceExpression, out renamedExpression), + JassElementAccessExpressionSyntax elementAccessExpression => TryRenameElementAccessExpression(elementAccessExpression, out renamedExpression), + JassIdentifierNameSyntax identifierName => TryRenameIdentifierName(identifierName, out renamedExpression), JassParenthesizedExpressionSyntax parenthesizedExpression => TryRenameParenthesizedExpression(parenthesizedExpression, out renamedExpression), JassUnaryExpressionSyntax unaryExpression => TryRenameUnaryExpression(unaryExpression, out renamedExpression), JassBinaryExpressionSyntax binaryExpression => TryRenameBinaryExpression(binaryExpression, out renamedExpression), diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclarationRenamer.cs index fb3b056b..c567f378 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclarationRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclarationRenamer.cs @@ -7,27 +7,29 @@ using System.Diagnostics.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameFunctionDeclaration(JassFunctionDeclarationSyntax functionDeclaration, [NotNullWhen(true)] out ITopLevelDeclarationSyntax? renamedFunctionDeclaration) + private bool TryRenameFunctionDeclaration(JassFunctionDeclarationSyntax functionDeclaration, [NotNullWhen(true)] out JassTopLevelDeclarationSyntax? renamedFunctionDeclaration) { - foreach (var parameter in functionDeclaration.FunctionDeclarator.ParameterList.Parameters) + foreach (var parameter in functionDeclaration.FunctionDeclarator.ParameterList.GetParameters()) { - _localVariableNames.Add(parameter.IdentifierName.Name); + _localVariableNames.Add(parameter.IdentifierName.Token.Text); } if (TryRenameFunctionDeclarator(functionDeclaration.FunctionDeclarator, out var renamedFunctionDeclarator) | - TryRenameStatementList(functionDeclaration.Body, out var renamedBody)) + TryRenameStatementList(functionDeclaration.Statements, out var renamedStatements)) { _localVariableNames.Clear(); renamedFunctionDeclaration = new JassFunctionDeclarationSyntax( renamedFunctionDeclarator ?? functionDeclaration.FunctionDeclarator, - renamedBody ?? functionDeclaration.Body); + renamedStatements ?? functionDeclaration.Statements, + functionDeclaration.EndFunctionToken); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclaratorRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclaratorRenamer.cs index 013169b2..39735d0a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclaratorRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionDeclaratorRenamer.cs @@ -18,9 +18,11 @@ private bool TryRenameFunctionDeclarator(JassFunctionDeclaratorSyntax functionDe if (TryRenameFunctionIdentifierName(functionDeclarator.IdentifierName, out var renamedIdentifierName)) { renamedFunctionDeclarator = new JassFunctionDeclaratorSyntax( + functionDeclarator.ConstantToken, + functionDeclarator.FunctionToken, renamedIdentifierName, functionDeclarator.ParameterList, - functionDeclarator.ReturnType); + functionDeclarator.ReturnClause); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionReferenceExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionReferenceExpressionRenamer.cs index af8d7d8c..aea18ec5 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionReferenceExpressionRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/FunctionReferenceExpressionRenamer.cs @@ -13,11 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameFunctionReferenceExpression(JassFunctionReferenceExpressionSyntax functionReferenceExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedFunctionReferenceExpression) + private bool TryRenameFunctionReferenceExpression(JassFunctionReferenceExpressionSyntax functionReferenceExpression, [NotNullWhen(true)] out JassExpressionSyntax? renamedFunctionReferenceExpression) { if (TryRenameFunctionIdentifierName(functionReferenceExpression.IdentifierName, out var renamedIdentifierName)) { - renamedFunctionReferenceExpression = new JassFunctionReferenceExpressionSyntax(renamedIdentifierName); + renamedFunctionReferenceExpression = new JassFunctionReferenceExpressionSyntax( + functionReferenceExpression.FunctionToken, + renamedIdentifierName); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalConstantDeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalConstantDeclarationRenamer.cs new file mode 100644 index 00000000..ac26af4c --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalConstantDeclarationRenamer.cs @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameGlobalConstantDeclaration(JassGlobalConstantDeclarationSyntax globalConstantDeclaration, [NotNullWhen(true)] out JassGlobalDeclarationSyntax? renamedGlobalConstantDeclaration) + { + if (TryRenameVariableIdentifierName(globalConstantDeclaration.IdentifierName, out var renamedIdentifierName) | + TryRenameEqualsValueClause(globalConstantDeclaration.Value, out var renamedValue)) + { + renamedGlobalConstantDeclaration = new JassGlobalConstantDeclarationSyntax( + globalConstantDeclaration.ConstantToken, + globalConstantDeclaration.Type, + renamedIdentifierName ?? globalConstantDeclaration.IdentifierName, + renamedValue ?? globalConstantDeclaration.Value); + + return false; + } + + renamedGlobalConstantDeclaration = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationListRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationListRenamer.cs deleted file mode 100644 index 57877360..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationListRenamer.cs +++ /dev/null @@ -1,45 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenamer - { - private bool TryRenameGlobalDeclarationList(JassGlobalDeclarationListSyntax globalDeclarationList, [NotNullWhen(true)] out ITopLevelDeclarationSyntax? renamedGlobalDeclarationList) - { - var isRenamed = false; - - var declarationsBuilder = ImmutableArray.CreateBuilder(); - foreach (var declaration in globalDeclarationList.Globals) - { - if (TryRenameGlobalDeclaration(declaration, out var renamedDeclaration)) - { - declarationsBuilder.Add(renamedDeclaration); - isRenamed = true; - } - else - { - declarationsBuilder.Add(declaration); - } - } - - if (isRenamed) - { - renamedGlobalDeclarationList = new JassGlobalDeclarationListSyntax(declarationsBuilder.ToImmutable()); - return true; - } - - renamedGlobalDeclarationList = null; - return false; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationRenamer.cs index 67db7962..cdcb78c4 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalDeclarationRenamer.cs @@ -13,25 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameGlobalDeclaration(JassGlobalDeclarationSyntax globalDeclaration, [NotNullWhen(true)] out IGlobalDeclarationSyntax? renamedGlobalDeclaration) + private bool TryRenameGlobalDeclaration(JassGlobalDeclarationSyntax globalDeclaration, [NotNullWhen(true)] out JassGlobalDeclarationSyntax? renamedDeclaration) { - if (TryRenameVariableDeclarator(globalDeclaration.Declarator, out var renamedDeclarator)) + return globalDeclaration switch { - renamedGlobalDeclaration = new JassGlobalDeclarationSyntax(renamedDeclarator); - return true; - } + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => TryRenameGlobalConstantDeclaration(globalConstantDeclaration, out renamedDeclaration), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => TryRenameGlobalVariableDeclaration(globalVariableDeclaration, out renamedDeclaration), - renamedGlobalDeclaration = null; - return false; - } - - private bool TryRenameGlobalDeclaration(IGlobalDeclarationSyntax declaration, [NotNullWhen(true)] out IGlobalDeclarationSyntax? renamedDeclaration) - { - return declaration switch - { - JassGlobalDeclarationSyntax globalDeclaration => TryRenameGlobalDeclaration(globalDeclaration, out renamedDeclaration), - - _ => TryRenameDummy(declaration, out renamedDeclaration), + _ => TryRenameDummy(globalDeclaration, out renamedDeclaration), }; } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalVariableDeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalVariableDeclarationRenamer.cs new file mode 100644 index 00000000..fafdf7d9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalVariableDeclarationRenamer.cs @@ -0,0 +1,28 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameGlobalVariableDeclaration(JassGlobalVariableDeclarationSyntax globalVariableDeclaration, [NotNullWhen(true)] out JassGlobalDeclarationSyntax? renamedGlobalVariableDeclaration) + { + if (TryRenameVariableOrArrayDeclarator(globalVariableDeclaration.Declarator, out var renamedDeclarator)) + { + renamedGlobalVariableDeclaration = new JassGlobalVariableDeclarationSyntax(renamedDeclarator); + return true; + } + + renamedGlobalVariableDeclaration = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalsDeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalsDeclarationRenamer.cs new file mode 100644 index 00000000..a2d6c6e9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/GlobalsDeclarationRenamer.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameGlobalsDeclaration(JassGlobalsDeclarationSyntax globalsDeclaration, [NotNullWhen(true)] out JassTopLevelDeclarationSyntax? renamedGlobalsDeclaration) + { + for (var i = 0; i < globalsDeclaration.GlobalDeclarations.Length; i++) + { + if (TryRenameGlobalDeclaration(globalsDeclaration.GlobalDeclarations[i], out var renamedGlobal)) + { + var builder = ImmutableArray.CreateBuilder(globalsDeclaration.GlobalDeclarations.Length); + for (var j = 0; j < i; j++) + { + builder.Add(globalsDeclaration.GlobalDeclarations[j]); + } + + builder.Add(renamedGlobal); + + while (++i < globalsDeclaration.GlobalDeclarations.Length) + { + if (TryRenameGlobalDeclaration(globalsDeclaration.GlobalDeclarations[i], out renamedGlobal)) + { + builder.Add(renamedGlobal); + } + else + { + builder.Add(globalsDeclaration.GlobalDeclarations[i]); + } + } + + renamedGlobalsDeclaration = new JassGlobalsDeclarationSyntax( + globalsDeclaration.GlobalsToken, + builder.ToImmutable(), + globalsDeclaration.EndGlobalsToken); + + return true; + } + } + + renamedGlobalsDeclaration = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/IdentifierNameRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/IdentifierNameRenamer.cs index 3274cab6..7c7a6969 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/IdentifierNameRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/IdentifierNameRenamer.cs @@ -13,20 +13,40 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { + private bool TryRenameIdentifierName(JassIdentifierNameSyntax identifierName, [NotNullWhen(true)] out JassExpressionSyntax? renamedIdentifierName) + { + if (TryRenameVariableIdentifierToken(identifierName.Token, out var renamedToken)) + { + renamedIdentifierName = new JassIdentifierNameSyntax(renamedToken); + return true; + } + + renamedIdentifierName = null; + return false; + } + private bool TryRenameFunctionIdentifierName(JassIdentifierNameSyntax identifierName, [NotNullWhen(true)] out JassIdentifierNameSyntax? renamedIdentifierName) { - return _functionDeclarationRenames.TryGetValue(identifierName.Name, out renamedIdentifierName); + if (TryRenameFunctionIdentifierToken(identifierName.Token, out var renamedToken)) + { + renamedIdentifierName = new JassIdentifierNameSyntax(renamedToken); + return true; + } + + renamedIdentifierName = null; + return false; } private bool TryRenameVariableIdentifierName(JassIdentifierNameSyntax identifierName, [NotNullWhen(true)] out JassIdentifierNameSyntax? renamedIdentifierName) { - if (_localVariableNames.Contains(identifierName.Name)) + if (TryRenameVariableIdentifierToken(identifierName.Token, out var renamedToken)) { - renamedIdentifierName = null; - return false; + renamedIdentifierName = new JassIdentifierNameSyntax(renamedToken); + return true; } - return _globalVariableRenames.TryGetValue(identifierName.Name, out renamedIdentifierName); + renamedIdentifierName = null; + return false; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseDeclaratorRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseDeclaratorRenamer.cs new file mode 100644 index 00000000..a759dee8 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseDeclaratorRenamer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameIfClauseDeclarator(JassIfClauseDeclaratorSyntax ifClauseDeclarator, [NotNullWhen(true)] out JassIfClauseDeclaratorSyntax? renamedIfClauseDeclarator) + { + if (TryRenameExpression(ifClauseDeclarator.Condition, out var renamedCondition)) + { + renamedIfClauseDeclarator = new JassIfClauseDeclaratorSyntax( + ifClauseDeclarator.IfToken, + renamedCondition, + ifClauseDeclarator.ThenToken); + + return true; + } + + renamedIfClauseDeclarator = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseRenamer.cs new file mode 100644 index 00000000..f5e1b2df --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/IfClauseRenamer.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameIfClause(JassIfClauseSyntax ifClause, [NotNullWhen(true)] out JassIfClauseSyntax? renamedIfClause) + { + if (TryRenameIfClauseDeclarator(ifClause.IfClauseDeclarator, out var renamedDeclarator) | + TryRenameStatementList(ifClause.Statements, out var renamedStatements)) + { + renamedIfClause = new JassIfClauseSyntax( + renamedDeclarator ?? ifClause.IfClauseDeclarator, + renamedStatements ?? ifClause.Statements); + + return true; + } + + renamedIfClause = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/IfStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/IfStatementRenamer.cs index 75079d81..ae2f4759 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/IfStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/IfStatementRenamer.cs @@ -5,7 +5,6 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using War3Net.CodeAnalysis.Jass.Syntax; @@ -14,34 +13,17 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameIfStatement(JassIfStatementSyntax ifStatement, [NotNullWhen(true)] out IStatementSyntax? renamedIfStatement) + private bool TryRenameIfStatement(JassIfStatementSyntax ifStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedIfStatement) { - var isRenamed = false; - - var elseIfClausesBuilder = ImmutableArray.CreateBuilder(); - foreach (var elseIfClause in ifStatement.ElseIfClauses) - { - if (TryRenameElseIfClause(elseIfClause, out var renamedElseIfClause)) - { - elseIfClausesBuilder.Add(renamedElseIfClause); - isRenamed = true; - } - else - { - elseIfClausesBuilder.Add(elseIfClause); - } - } - - if (TryRenameExpression(ifStatement.Condition, out var renamedCondition) | - TryRenameStatementList(ifStatement.Body, out var renamedBody) | - isRenamed | + if (TryRenameIfClause(ifStatement.IfClause, out var renamedIfClause) | + TryRenameElseIfClauseList(ifStatement.ElseIfClauses, out var renamedElseIfClauses) | TryRenameElseClause(ifStatement.ElseClause, out var renamedElseClause)) { renamedIfStatement = new JassIfStatementSyntax( - renamedCondition ?? ifStatement.Condition, - renamedBody ?? ifStatement.Body, - isRenamed ? elseIfClausesBuilder.ToImmutable() : ifStatement.ElseIfClauses, - renamedElseClause ?? ifStatement.ElseClause); + renamedIfClause ?? ifStatement.IfClause, + renamedElseIfClauses ?? ifStatement.ElseIfClauses, + renamedElseClause ?? ifStatement.ElseClause, + ifStatement.EndIfToken); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/InvocationExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/InvocationExpressionRenamer.cs index de54d763..fb815921 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/InvocationExpressionRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/InvocationExpressionRenamer.cs @@ -13,14 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameInvocationExpression(JassInvocationExpressionSyntax invocationExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedInvocationExpression) + private bool TryRenameInvocationExpression(JassInvocationExpressionSyntax invocationExpression, [NotNullWhen(true)] out JassExpressionSyntax? renamedInvocationExpression) { if (TryRenameFunctionIdentifierName(invocationExpression.IdentifierName, out var renamedIdentifierName) | - TryRenameArgumentList(invocationExpression.Arguments, out var renamedArguments)) + TryRenameArgumentList(invocationExpression.ArgumentList, out var renamedArguments)) { renamedInvocationExpression = new JassInvocationExpressionSyntax( renamedIdentifierName ?? invocationExpression.IdentifierName, - renamedArguments ?? invocationExpression.Arguments); + renamedArguments ?? invocationExpression.ArgumentList); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/LocalVariableDeclarationStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/LocalVariableDeclarationStatementRenamer.cs index d8620672..ef526efb 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/LocalVariableDeclarationStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/LocalVariableDeclarationStatementRenamer.cs @@ -7,19 +7,23 @@ using System.Diagnostics.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameLocalVariableDeclarationStatement(JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement, [NotNullWhen(true)] out IStatementSyntax? renamedLocalVariableDeclarationStatement) + private bool TryRenameLocalVariableDeclarationStatement(JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedLocalVariableDeclarationStatement) { - _localVariableNames.Add(localVariableDeclarationStatement.Declarator.IdentifierName.Name); + _localVariableNames.Add(localVariableDeclarationStatement.Declarator.GetIdentifierName().Token.Text); - if (TryRenameVariableDeclarator(localVariableDeclarationStatement.Declarator, out var renamedDeclarator)) + if (TryRenameVariableOrArrayDeclarator(localVariableDeclarationStatement.Declarator, out var renamedDeclarator)) { - renamedLocalVariableDeclarationStatement = new JassLocalVariableDeclarationStatementSyntax(renamedDeclarator); + renamedLocalVariableDeclarationStatement = new JassLocalVariableDeclarationStatementSyntax( + localVariableDeclarationStatement.LocalToken, + renamedDeclarator); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/LoopStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/LoopStatementRenamer.cs index a11b1498..28b301e4 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/LoopStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/LoopStatementRenamer.cs @@ -13,11 +13,15 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameLoopStatement(JassLoopStatementSyntax loopStatement, [NotNullWhen(true)] out IStatementSyntax? renamedLoopStatement) + private bool TryRenameLoopStatement(JassLoopStatementSyntax loopStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedLoopStatement) { - if (TryRenameStatementList(loopStatement.Body, out var renamedBody)) + if (TryRenameStatementList(loopStatement.Statements, out var renamedStatements)) { - renamedLoopStatement = new JassLoopStatementSyntax(renamedBody); + renamedLoopStatement = new JassLoopStatementSyntax( + loopStatement.LoopToken, + renamedStatements.Value, + loopStatement.EndLoopToken); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/NativeFunctionDeclarationRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/NativeFunctionDeclarationRenamer.cs index b42567eb..bdce7da1 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/NativeFunctionDeclarationRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/NativeFunctionDeclarationRenamer.cs @@ -13,11 +13,17 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameNativeFunctionDeclaration(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration, [NotNullWhen(true)] out ITopLevelDeclarationSyntax? renamedNativeFunctionDeclaration) + private bool TryRenameNativeFunctionDeclaration(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration, [NotNullWhen(true)] out JassTopLevelDeclarationSyntax? renamedNativeFunctionDeclaration) { - if (TryRenameFunctionDeclarator(nativeFunctionDeclaration.FunctionDeclarator, out var renamedFunctionDeclarator)) + if (TryRenameFunctionIdentifierName(nativeFunctionDeclaration.IdentifierName, out var renamedIdentifierName)) { - renamedNativeFunctionDeclaration = new JassNativeFunctionDeclarationSyntax(renamedFunctionDeclarator); + renamedNativeFunctionDeclaration = new JassNativeFunctionDeclarationSyntax( + nativeFunctionDeclaration.ConstantToken, + nativeFunctionDeclaration.NativeToken, + renamedIdentifierName, + nativeFunctionDeclaration.ParameterList, + nativeFunctionDeclaration.ReturnClause); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ParenthesizedExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ParenthesizedExpressionRenamer.cs index 8495df89..70f2f4ec 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ParenthesizedExpressionRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ParenthesizedExpressionRenamer.cs @@ -13,11 +13,15 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameParenthesizedExpression(JassParenthesizedExpressionSyntax parenthesizedExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedParenthesizedExpression) + private bool TryRenameParenthesizedExpression(JassParenthesizedExpressionSyntax parenthesizedExpression, [NotNullWhen(true)] out JassExpressionSyntax? renamedParenthesizedExpression) { if (TryRenameExpression(parenthesizedExpression.Expression, out var renamedExpression)) { - renamedParenthesizedExpression = new JassParenthesizedExpressionSyntax(renamedExpression); + renamedParenthesizedExpression = new JassParenthesizedExpressionSyntax( + parenthesizedExpression.OpenParenToken, + renamedExpression, + parenthesizedExpression.CloseParenToken); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/ReturnStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/ReturnStatementRenamer.cs index 516084c8..d6423c18 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/ReturnStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/ReturnStatementRenamer.cs @@ -13,11 +13,14 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameReturnStatement(JassReturnStatementSyntax returnStatement, [NotNullWhen(true)] out IStatementSyntax? renamedReturnStatement) + private bool TryRenameReturnStatement(JassReturnStatementSyntax returnStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedReturnStatement) { if (TryRenameExpression(returnStatement.Value, out var renamedValue)) { - renamedReturnStatement = new JassReturnStatementSyntax(renamedValue); + renamedReturnStatement = new JassReturnStatementSyntax( + returnStatement.ReturnToken, + renamedValue); + return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/SetStatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/SetStatementRenamer.cs index b3c5237a..804b0068 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/SetStatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/SetStatementRenamer.cs @@ -13,15 +13,16 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameSetStatement(JassSetStatementSyntax setStatement, [NotNullWhen(true)] out IStatementSyntax? renamedSetStatement) + private bool TryRenameSetStatement(JassSetStatementSyntax setStatement, [NotNullWhen(true)] out JassStatementSyntax? renamedSetStatement) { if (TryRenameVariableIdentifierName(setStatement.IdentifierName, out var renamedIdentifierName) | - TryRenameExpression(setStatement.Indexer, out var renamedIndexer) | + TryRenameElementAccessClause(setStatement.ElementAccessClause, out var renamedElementAccessClause) | TryRenameEqualsValueClause(setStatement.Value, out var renamedValue)) { renamedSetStatement = new JassSetStatementSyntax( + setStatement.SetToken, renamedIdentifierName ?? setStatement.IdentifierName, - renamedIndexer ?? setStatement.Indexer, + renamedElementAccessClause ?? setStatement.ElementAccessClause, renamedValue ?? setStatement.Value); return true; diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/StatementListRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/StatementListRenamer.cs index df75e9fb..a15553ef 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/StatementListRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/StatementListRenamer.cs @@ -14,31 +14,38 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameStatementList(JassStatementListSyntax statementList, [NotNullWhen(true)] out JassStatementListSyntax? renamedStatementList) + private bool TryRenameStatementList(ImmutableArray statements, [NotNullWhen(true)] out ImmutableArray? renamedStatements) { - var isRenamed = false; - - var statementsBuilder = ImmutableArray.CreateBuilder(); - foreach (var statement in statementList.Statements) + for (var i = 0; i < statements.Length; i++) { - if (TryRenameStatement(statement, out var renamedStatement)) - { - statementsBuilder.Add(renamedStatement); - isRenamed = true; - } - else + if (TryRenameStatement(statements[i], out var renamedStatement)) { - statementsBuilder.Add(statement); - } - } + var builder = ImmutableArray.CreateBuilder(statements.Length); + for (var j = 0; j < i; j++) + { + builder.Add(statements[j]); + } - if (isRenamed) - { - renamedStatementList = new JassStatementListSyntax(statementsBuilder.ToImmutable()); - return true; + builder.Add(renamedStatement); + + while (++i < statements.Length) + { + if (TryRenameStatement(statements[i], out renamedStatement)) + { + builder.Add(renamedStatement); + } + else + { + builder.Add(statements[i]); + } + } + + renamedStatements = builder.ToImmutable(); + return true; + } } - renamedStatementList = null; + renamedStatements = null; return false; } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/StatementRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/StatementRenamer.cs index 1e784336..a5b32e7a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/StatementRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/StatementRenamer.cs @@ -13,7 +13,7 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameStatement(IStatementSyntax statement, [NotNullWhen(true)] out IStatementSyntax? renamedStatement) + private bool TryRenameStatement(JassStatementSyntax statement, [NotNullWhen(true)] out JassStatementSyntax? renamedStatement) { return statement switch { diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/SyntaxTokenRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/SyntaxTokenRenamer.cs new file mode 100644 index 00000000..ce2c6cd4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/SyntaxTokenRenamer.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameFunctionIdentifierToken(JassSyntaxToken token, [NotNullWhen(true)] out JassSyntaxToken? renamedToken) + { + if (_functionDeclarationRenames.TryGetValue(token.Text, out var newName)) + { + renamedToken = new JassSyntaxToken( + token.LeadingTrivia, + token.SyntaxKind, + newName, + token.TrailingTrivia); + + return true; + } + + renamedToken = null; + return false; + } + + private bool TryRenameVariableIdentifierToken(JassSyntaxToken token, [NotNullWhen(true)] out JassSyntaxToken? renamedToken) + { + if (_localVariableNames.Contains(token.Text)) + { + renamedToken = null; + return false; + } + + if (_globalVariableRenames.TryGetValue(token.Text, out var newName)) + { + renamedToken = new JassSyntaxToken( + token.LeadingTrivia, + token.SyntaxKind, + newName, + token.TrailingTrivia); + + return true; + } + + renamedToken = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/UnaryExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/UnaryExpressionRenamer.cs index 52d8618c..d195cb0b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/UnaryExpressionRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/UnaryExpressionRenamer.cs @@ -13,12 +13,12 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameUnaryExpression(JassUnaryExpressionSyntax unaryExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedUnaryExpression) + private bool TryRenameUnaryExpression(JassUnaryExpressionSyntax unaryExpression, [NotNullWhen(true)] out JassExpressionSyntax? renamedUnaryExpression) { if (TryRenameExpression(unaryExpression.Expression, out var renamedExpression)) { renamedUnaryExpression = new JassUnaryExpressionSyntax( - unaryExpression.Operator, + unaryExpression.OperatorToken, renamedExpression); return true; diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/VariableDeclaratorRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/VariableDeclaratorRenamer.cs index 84fc44b5..1b51c14d 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/VariableDeclaratorRenamer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/VariableDeclaratorRenamer.cs @@ -13,18 +13,7 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenamer { - private bool TryRenameVariableDeclarator(IVariableDeclaratorSyntax declarator, [NotNullWhen(true)] out IVariableDeclaratorSyntax? renamedDeclarator) - { - return declarator switch - { - JassArrayDeclaratorSyntax arrayDeclarator => TryRenameArrayDeclarator(arrayDeclarator, out renamedDeclarator), - JassVariableDeclaratorSyntax variableDeclarator => TryRenameVariableDeclarator(variableDeclarator, out renamedDeclarator), - - _ => TryRenameDummy(declarator, out renamedDeclarator), - }; - } - - private bool TryRenameVariableDeclarator(JassVariableDeclaratorSyntax variableDeclarator, [NotNullWhen(true)] out IVariableDeclaratorSyntax? renamedVariableDeclarator) + private bool TryRenameVariableDeclarator(JassVariableDeclaratorSyntax variableDeclarator, [NotNullWhen(true)] out JassVariableOrArrayDeclaratorSyntax? renamedVariableDeclarator) { if (TryRenameVariableIdentifierName(variableDeclarator.IdentifierName, out var renamedIdentifierName) | TryRenameEqualsValueClause(variableDeclarator.Value, out var renamedValue)) diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/VariableOrArrayDeclaratorRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/VariableOrArrayDeclaratorRenamer.cs new file mode 100644 index 00000000..14e11d42 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renamer/VariableOrArrayDeclaratorRenamer.cs @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenamer + { + private bool TryRenameVariableOrArrayDeclarator(JassVariableOrArrayDeclaratorSyntax declarator, [NotNullWhen(true)] out JassVariableOrArrayDeclaratorSyntax? renamedDeclarator) + { + return declarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => TryRenameArrayDeclarator(arrayDeclarator, out renamedDeclarator), + JassVariableDeclaratorSyntax variableDeclarator => TryRenameVariableDeclarator(variableDeclarator, out renamedDeclarator), + + _ => TryRenameDummy(declarator, out renamedDeclarator), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renamer/VariableReferenceExpressionRenamer.cs b/src/War3Net.CodeAnalysis.Jass/Renamer/VariableReferenceExpressionRenamer.cs deleted file mode 100644 index b39ddfd9..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renamer/VariableReferenceExpressionRenamer.cs +++ /dev/null @@ -1,28 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Diagnostics.CodeAnalysis; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenamer - { - private bool TryRenameVariableReferenceExpression(JassVariableReferenceExpressionSyntax variableReferenceExpression, [NotNullWhen(true)] out IExpressionSyntax? renamedVariableReferenceExpression) - { - if (TryRenameVariableIdentifierName(variableReferenceExpression.IdentifierName, out var renamedIdentifierName)) - { - renamedVariableReferenceExpression = new JassVariableReferenceExpressionSyntax(renamedIdentifierName); - return true; - } - - renamedVariableReferenceExpression = null; - return false; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ArgumentListRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ArgumentListRenderer.cs index b31a3f77..f4a602aa 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ArgumentListRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ArgumentListRenderer.cs @@ -5,8 +5,6 @@ // // ------------------------------------------------------------------------------ -using System.Linq; - using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -15,15 +13,20 @@ public partial class JassRenderer { public void Render(JassArgumentListSyntax argumentList) { - if (argumentList.Arguments.Any()) + Render(argumentList.OpenParenToken); + + if (!argumentList.ArgumentList.Items.IsEmpty) { - Render(argumentList.Arguments.First()); - foreach (var argument in argumentList.Arguments.Skip(1)) + Render(argumentList.ArgumentList.Items[0]); + for (var i = 1; i < argumentList.ArgumentList.Items.Length; i++) { - Write($"{JassSymbol.Comma} "); - Render(argument); + Render(argumentList.ArgumentList.Separators[i - 1]); + WriteSpace(); + Render(argumentList.ArgumentList.Items[i]); } } + + Render(argumentList.CloseParenToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayDeclaratorRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayDeclaratorRenderer.cs index 0ef1ba53..6d1964ef 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayDeclaratorRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayDeclaratorRenderer.cs @@ -14,7 +14,9 @@ public partial class JassRenderer public void Render(JassArrayDeclaratorSyntax arrayDeclarator) { Render(arrayDeclarator.Type); - Write($" {JassKeyword.Array} "); + WriteSpace(); + Render(arrayDeclarator.ArrayToken); + WriteSpace(); Render(arrayDeclarator.IdentifierName); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayReferenceExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayReferenceExpressionRenderer.cs deleted file mode 100644 index 8997e33f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ArrayReferenceExpressionRenderer.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassArrayReferenceExpressionSyntax arrayReferenceExpression) - { - Render(arrayReferenceExpression.IdentifierName); - Write(JassSymbol.LeftSquareBracket); - Render(arrayReferenceExpression.Indexer); - Write(JassSymbol.RightSquareBracket); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/BinaryExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/BinaryExpressionRenderer.cs index 3fed0971..e780749a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/BinaryExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/BinaryExpressionRenderer.cs @@ -5,7 +5,6 @@ // // ------------------------------------------------------------------------------ -using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -15,7 +14,9 @@ public partial class JassRenderer public void Render(JassBinaryExpressionSyntax binaryExpression) { Render(binaryExpression.Left); - Write($" {binaryExpression.Operator.GetSymbol()} "); + WriteSpace(); + Render(binaryExpression.OperatorToken); + WriteSpace(); Render(binaryExpression.Right); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/CallStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/CallStatementRenderer.cs index 4190deac..623ac6e0 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/CallStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/CallStatementRenderer.cs @@ -13,11 +13,10 @@ public partial class JassRenderer { public void Render(JassCallStatementSyntax callStatement) { - Write($"{JassKeyword.Call} "); + Render(callStatement.CallToken); + WriteSpace(); Render(callStatement.IdentifierName); - Write(JassSymbol.LeftParenthesis); - Render(callStatement.Arguments); - Write(JassSymbol.RightParenthesis); + Render(callStatement.ArgumentList); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/CompilationUnitRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/CompilationUnitRenderer.cs index 6f81b0e5..379880cd 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/CompilationUnitRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/CompilationUnitRenderer.cs @@ -16,8 +16,9 @@ public void Render(JassCompilationUnitSyntax compilationUnit) foreach (var declaration in compilationUnit.Declarations) { Render(declaration); - WriteLine(); } + + Render(compilationUnit.EndOfFileToken.LeadingTrivia); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/DebugStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/DebugStatementRenderer.cs index 28050239..783e645a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/DebugStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/DebugStatementRenderer.cs @@ -13,7 +13,8 @@ public partial class JassRenderer { public void Render(JassDebugStatementSyntax debugStatement) { - Write($"{JassKeyword.Debug} "); + Render(debugStatement.DebugToken); + WriteSpace(); Render(debugStatement.Statement); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/DecimalLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/DecimalLiteralExpressionRenderer.cs deleted file mode 100644 index 4d6f7640..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/DecimalLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassDecimalLiteralExpressionSyntax decimalLiteralExpression) - { - Write(decimalLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationLineRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationLineRenderer.cs deleted file mode 100644 index 4f6a0eac..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationLineRenderer.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(IDeclarationLineSyntax declarationLine) - { - switch (declarationLine) - { - case JassEmptySyntax empty: Render(empty); break; - case JassCommentSyntax comment: Render(comment); break; - case JassFunctionCustomScriptAction functionDeclaration: Render(functionDeclaration); break; - case JassGlobalsCustomScriptAction globalsDeclaration: Render(globalsDeclaration); break; - case JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration: Render(nativeFunctionDeclaration); break; - case JassTypeDeclarationSyntax typeDeclaration: Render(typeDeclaration); break; - - default: throw new NotSupportedException(); - } - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessClauseRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessClauseRenderer.cs new file mode 100644 index 00000000..639cf834 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessClauseRenderer.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenderer + { + public void Render(JassElementAccessClauseSyntax elementAccessClause) + { + Render(elementAccessClause.OpenBracketToken); + Render(elementAccessClause.Expression); + Render(elementAccessClause.CloseBracketToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EndIfCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessExpressionRenderer.cs similarity index 61% rename from src/War3Net.CodeAnalysis.Jass/Renderer/EndIfCustomScriptActionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessExpressionRenderer.cs index 079ee90f..424c671f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/EndIfCustomScriptActionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ElementAccessExpressionRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,10 +11,10 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassEndIfCustomScriptAction endIfCustomScriptAction) + public void Render(JassElementAccessExpressionSyntax elementAccessExpression) { - Outdent(); - Write(JassKeyword.EndIf); + Render(elementAccessExpression.IdentifierName); + Render(elementAccessExpression.ElementAccessClause); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseClauseRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseClauseRenderer.cs index d38f3814..6f717958 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseClauseRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseClauseRenderer.cs @@ -13,9 +13,9 @@ public partial class JassRenderer { public void Render(JassElseClauseSyntax elseClause) { - WriteLine(JassKeyword.Else); + Render(elseClause.ElseToken); Indent(); - Render(elseClause.Body); + Render(elseClause.Statements); Outdent(); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/LoopCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseDeclaratorRenderer.cs similarity index 55% rename from src/War3Net.CodeAnalysis.Jass/Renderer/LoopCustomScriptActionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseDeclaratorRenderer.cs index 3f2918fb..f5d5883c 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/LoopCustomScriptActionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseDeclaratorRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,10 +11,13 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassLoopCustomScriptAction loopCustomScriptAction) + public void Render(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator) { - Write(JassKeyword.Loop); - Indent(); + Render(elseIfClauseDeclarator.ElseIfToken); + WriteSpace(); + Render(elseIfClauseDeclarator.Condition); + WriteSpace(); + Render(elseIfClauseDeclarator.ThenToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseRenderer.cs index c8c9d6f5..5082e577 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfClauseRenderer.cs @@ -13,11 +13,9 @@ public partial class JassRenderer { public void Render(JassElseIfClauseSyntax elseIfClause) { - Write($"{JassKeyword.ElseIf} "); - Render(elseIfClause.Condition); - WriteLine($" {JassKeyword.Then}"); + Render(elseIfClause.ElseIfClauseDeclarator); Indent(); - Render(elseIfClause.Body); + Render(elseIfClause.Statements); Outdent(); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfCustomScriptActionRenderer.cs deleted file mode 100644 index ba041053..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseIfCustomScriptActionRenderer.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassElseIfCustomScriptAction elseIfCustomScriptAction) - { - Outdent(); - Write($"{JassKeyword.ElseIf} "); - Render(elseIfCustomScriptAction.Condition); - Write($" {JassKeyword.Then}"); - Indent(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EmptyParameterListRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/EmptyParameterListRenderer.cs new file mode 100644 index 00000000..ece2e7f2 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/EmptyParameterListRenderer.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenderer + { + public void Render(JassEmptyParameterListSyntax emptyParameterList) + { + Render(emptyParameterList.TakesToken); + WriteSpace(); + Render(emptyParameterList.NothingToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EndFunctionCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/EndFunctionCustomScriptActionRenderer.cs deleted file mode 100644 index 6015b488..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/EndFunctionCustomScriptActionRenderer.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassEndFunctionCustomScriptAction endFunctionCustomScriptAction) - { - Outdent(); - Write(JassKeyword.EndFunction); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EndGlobalsCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/EndGlobalsCustomScriptActionRenderer.cs deleted file mode 100644 index 87b4117a..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/EndGlobalsCustomScriptActionRenderer.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassEndGlobalsCustomScriptAction endGlobalsCustomScriptAction) - { - Outdent(); - Write(JassKeyword.EndGlobals); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EqualsValueClauseRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/EqualsValueClauseRenderer.cs index 1a4d256a..942426d9 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/EqualsValueClauseRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/EqualsValueClauseRenderer.cs @@ -13,7 +13,8 @@ public partial class JassRenderer { public void Render(JassEqualsValueClauseSyntax equalsValueClause) { - Write($"{JassSymbol.EqualsSign} "); + Render(equalsValueClause.EqualsToken); + WriteSpace(); Render(equalsValueClause.Expression); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ExitStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ExitStatementRenderer.cs index cc90c5ad..0d914f59 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ExitStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ExitStatementRenderer.cs @@ -13,7 +13,8 @@ public partial class JassRenderer { public void Render(JassExitStatementSyntax exitStatement) { - Write($"{JassKeyword.ExitWhen} "); + Render(exitStatement.ExitWhenToken); + WriteSpace(); Render(exitStatement.Condition); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ExpressionRenderer.cs index 6b9907ea..84caefde 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ExpressionRenderer.cs @@ -13,23 +13,15 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(IExpressionSyntax expression) + public void Render(JassExpressionSyntax expression) { switch (expression) { - case JassCharacterLiteralExpressionSyntax characterLiteralExpression: Render(characterLiteralExpression); break; - case JassFourCCLiteralExpressionSyntax fourCCLiteralExpression: Render(fourCCLiteralExpression); break; - case JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression: Render(hexadecimalLiteralExpression); break; - case JassRealLiteralExpressionSyntax realLiteralExpression: Render(realLiteralExpression); break; - case JassOctalLiteralExpressionSyntax octalLiteralExpression: Render(octalLiteralExpression); break; - case JassDecimalLiteralExpressionSyntax decimalLiteralExpression: Render(decimalLiteralExpression); break; - case JassBooleanLiteralExpressionSyntax booleanLiteralExpression: Render(booleanLiteralExpression); break; - case JassStringLiteralExpressionSyntax stringLiteralExpression: Render(stringLiteralExpression); break; - case JassNullLiteralExpressionSyntax nullLiteralExpression: Render(nullLiteralExpression); break; + case JassLiteralExpressionSyntax literalExpression: Render(literalExpression); break; case JassFunctionReferenceExpressionSyntax functionReferenceExpression: Render(functionReferenceExpression); break; case JassInvocationExpressionSyntax invocationExpression: Render(invocationExpression); break; - case JassArrayReferenceExpressionSyntax arrayReferenceExpression: Render(arrayReferenceExpression); break; - case JassVariableReferenceExpressionSyntax variableReferenceExpression: Render(variableReferenceExpression); break; + case JassElementAccessExpressionSyntax elementAccessExpression: Render(elementAccessExpression); break; + case JassIdentifierNameSyntax identifierName: Render(identifierName); break; case JassParenthesizedExpressionSyntax parenthesizedExpression: Render(parenthesizedExpression); break; case JassUnaryExpressionSyntax unaryExpression: Render(unaryExpression); break; case JassBinaryExpressionSyntax binaryExpression: Render(binaryExpression); break; diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/FourCCLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/FourCCLiteralExpressionRenderer.cs deleted file mode 100644 index 27976c6c..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/FourCCLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassFourCCLiteralExpressionSyntax fourCCLiteralExpression) - { - Write(fourCCLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionCustomScriptActionRenderer.cs deleted file mode 100644 index 402a0ea6..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionCustomScriptActionRenderer.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassFunctionCustomScriptAction functionCustomScriptAction) - { - Write($"{JassKeyword.Function} "); - Render(functionCustomScriptAction.FunctionDeclarator); - Indent(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclarationRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclarationRenderer.cs index faf01ffa..a155b43e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclarationRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclarationRenderer.cs @@ -13,13 +13,11 @@ public partial class JassRenderer { public void Render(JassFunctionDeclarationSyntax functionDeclaration) { - Write($"{JassKeyword.Function} "); Render(functionDeclaration.FunctionDeclarator); - WriteLine(); Indent(); - Render(functionDeclaration.Body); + Render(functionDeclaration.Statements); Outdent(); - Write(JassKeyword.EndFunction); + Render(functionDeclaration.EndFunctionToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclaratorRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclaratorRenderer.cs index ba19279a..7c714d33 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclaratorRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionDeclaratorRenderer.cs @@ -13,11 +13,19 @@ public partial class JassRenderer { public void Render(JassFunctionDeclaratorSyntax functionDeclarator) { + if (functionDeclarator.ConstantToken is not null) + { + Render(functionDeclarator.ConstantToken); + WriteSpace(); + } + + Render(functionDeclarator.FunctionToken); + WriteSpace(); Render(functionDeclarator.IdentifierName); - Write($" {JassKeyword.Takes} "); + WriteSpace(); Render(functionDeclarator.ParameterList); - Write($" {JassKeyword.Returns} "); - Render(functionDeclarator.ReturnType); + WriteSpace(); + Render(functionDeclarator.ReturnClause); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionReferenceExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionReferenceExpressionRenderer.cs index 4c867aca..0293900a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionReferenceExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/FunctionReferenceExpressionRenderer.cs @@ -13,7 +13,8 @@ public partial class JassRenderer { public void Render(JassFunctionReferenceExpressionSyntax functionReferenceExpression) { - Write($"{JassKeyword.Function} "); + Render(functionReferenceExpression.FunctionToken); + WriteSpace(); Render(functionReferenceExpression.IdentifierName); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalConstantDeclarationRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalConstantDeclarationRenderer.cs new file mode 100644 index 00000000..284b4cea --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalConstantDeclarationRenderer.cs @@ -0,0 +1,25 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenderer + { + public void Render(JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + { + Render(globalConstantDeclaration.ConstantToken); + WriteSpace(); + Render(globalConstantDeclaration.Type); + WriteSpace(); + Render(globalConstantDeclaration.IdentifierName); + WriteSpace(); + Render(globalConstantDeclaration.Value); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationRenderer.cs index 0b670e56..a3fdd710 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationRenderer.cs @@ -15,16 +15,10 @@ public partial class JassRenderer { public void Render(JassGlobalDeclarationSyntax globalDeclaration) { - Render(globalDeclaration.Declarator); - } - - public void Render(IGlobalDeclarationSyntax declaration) - { - switch (declaration) + switch (globalDeclaration) { - case JassEmptySyntax empty: Render(empty); break; - case JassCommentSyntax comment: Render(comment); break; - case JassGlobalDeclarationSyntax globalDeclaration: Render(globalDeclaration); break; + case JassGlobalConstantDeclarationSyntax globalConstantDeclaration: Render(globalConstantDeclaration); break; + case JassGlobalVariableDeclarationSyntax globalVariableDeclaration: Render(globalVariableDeclaration); break; default: throw new NotSupportedException(); } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EndLoopCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalVariableDeclarationRenderer.cs similarity index 67% rename from src/War3Net.CodeAnalysis.Jass/Renderer/EndLoopCustomScriptActionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/GlobalVariableDeclarationRenderer.cs index 976eaae6..47226d1b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/EndLoopCustomScriptActionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalVariableDeclarationRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,10 +11,9 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassEndLoopCustomScriptAction endLoopCustomScriptAction) + public void Render(JassGlobalVariableDeclarationSyntax globalVariableDeclaration) { - Outdent(); - Write(JassKeyword.EndLoop); + Render(globalVariableDeclaration.Declarator); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsCustomScriptActionRenderer.cs deleted file mode 100644 index 23cadf12..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsCustomScriptActionRenderer.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassGlobalsCustomScriptAction globalsCustomScriptAction) - { - Write(JassKeyword.Globals); - Indent(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationListRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsDeclarationRenderer.cs similarity index 61% rename from src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationListRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsDeclarationRenderer.cs index fb53997a..4d2d0652 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalDeclarationListRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalsDeclarationRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,19 +11,18 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassGlobalDeclarationListSyntax globalDeclarationList) + public void Render(JassGlobalsDeclarationSyntax globalsDeclaration) { - WriteLine(JassKeyword.Globals); + Render(globalsDeclaration.GlobalsToken); Indent(); - foreach (var globalDeclaration in globalDeclarationList.Globals) + foreach (var globalDeclaration in globalsDeclaration.GlobalDeclarations) { Render(globalDeclaration); - WriteLine(); } Outdent(); - Write(JassKeyword.EndGlobals); + Render(globalsDeclaration.EndGlobalsToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/HexadecimalLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/HexadecimalLiteralExpressionRenderer.cs deleted file mode 100644 index 39461542..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/HexadecimalLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression) - { - Write(hexadecimalLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/IdentifierNameRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/IdentifierNameRenderer.cs index f45b94c1..5669bf3f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/IdentifierNameRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/IdentifierNameRenderer.cs @@ -13,7 +13,7 @@ public partial class JassRenderer { public void Render(JassIdentifierNameSyntax identifierName) { - Write(identifierName.Name); + Render(identifierName.Token); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseDeclaratorRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseDeclaratorRenderer.cs new file mode 100644 index 00000000..8021fe0e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseDeclaratorRenderer.cs @@ -0,0 +1,23 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenderer + { + public void Render(JassIfClauseDeclaratorSyntax ifClauseDeclarator) + { + Render(ifClauseDeclarator.IfToken); + WriteSpace(); + Render(ifClauseDeclarator.Condition); + WriteSpace(); + Render(ifClauseDeclarator.ThenToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseRenderer.cs similarity index 69% rename from src/War3Net.CodeAnalysis.Jass/Renderer/ElseCustomScriptActionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseRenderer.cs index 5b711ee3..1821b0ef 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ElseCustomScriptActionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/IfClauseRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,11 +11,12 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassElseCustomScriptAction elseCustomScriptAction) + public void Render(JassIfClauseSyntax ifClause) { - Outdent(); - Write(JassKeyword.Else); + Render(ifClause.IfClauseDeclarator); Indent(); + Render(ifClause.Statements); + Outdent(); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/IfCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/IfCustomScriptActionRenderer.cs deleted file mode 100644 index 0739e01f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/IfCustomScriptActionRenderer.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassIfCustomScriptAction ifCustomScriptAction) - { - Write($"{JassKeyword.If} "); - Render(ifCustomScriptAction.Condition); - Write($" {JassKeyword.Then}"); - Indent(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/IfStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/IfStatementRenderer.cs index 0a3fbbf8..66386a5c 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/IfStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/IfStatementRenderer.cs @@ -13,12 +13,7 @@ public partial class JassRenderer { public void Render(JassIfStatementSyntax ifStatement) { - Write($"{JassKeyword.If} "); - Render(ifStatement.Condition); - WriteLine($" {JassKeyword.Then}"); - Indent(); - Render(ifStatement.Body); - Outdent(); + Render(ifStatement.IfClause); foreach (var elseIfClause in ifStatement.ElseIfClauses) { @@ -30,7 +25,7 @@ public void Render(JassIfStatementSyntax ifStatement) Render(ifStatement.ElseClause); } - Write(JassKeyword.EndIf); + Render(ifStatement.EndIfToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/InvocationExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/InvocationExpressionRenderer.cs index 3c905037..78c52ca0 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/InvocationExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/InvocationExpressionRenderer.cs @@ -14,9 +14,7 @@ public partial class JassRenderer public void Render(JassInvocationExpressionSyntax invocationExpression) { Render(invocationExpression.IdentifierName); - Write(JassSymbol.LeftParenthesis); - Render(invocationExpression.Arguments); - Write(JassSymbol.RightParenthesis); + Render(invocationExpression.ArgumentList); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/EmptyRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/LiteralExpressionRenderer.cs similarity index 69% rename from src/War3Net.CodeAnalysis.Jass/Renderer/EmptyRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/LiteralExpressionRenderer.cs index e90414d4..861a66d6 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/EmptyRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/LiteralExpressionRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,8 +11,9 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassEmptySyntax empty) + public void Render(JassLiteralExpressionSyntax literalExpression) { + Render(literalExpression.Token); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/LocalVariableDeclarationStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/LocalVariableDeclarationStatementRenderer.cs index 485852c5..bf4358ec 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/LocalVariableDeclarationStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/LocalVariableDeclarationStatementRenderer.cs @@ -13,7 +13,8 @@ public partial class JassRenderer { public void Render(JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement) { - Write($"{JassKeyword.Local} "); + Render(localVariableDeclarationStatement.LocalToken); + WriteSpace(); Render(localVariableDeclarationStatement.Declarator); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/LoopStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/LoopStatementRenderer.cs index 0a2825b2..007b1137 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/LoopStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/LoopStatementRenderer.cs @@ -13,11 +13,11 @@ public partial class JassRenderer { public void Render(JassLoopStatementSyntax loopStatement) { - WriteLine(JassKeyword.Loop); + Render(loopStatement.LoopToken); Indent(); - Render(loopStatement.Body); + Render(loopStatement.Statements); Outdent(); - Write(JassKeyword.EndLoop); + Render(loopStatement.EndLoopToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/NativeFunctionDeclarationRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/NativeFunctionDeclarationRenderer.cs index 462e3156..6a37d49a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/NativeFunctionDeclarationRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/NativeFunctionDeclarationRenderer.cs @@ -13,8 +13,19 @@ public partial class JassRenderer { public void Render(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration) { - Write($"{JassKeyword.Native} "); - Render(nativeFunctionDeclaration.FunctionDeclarator); + if (nativeFunctionDeclaration.ConstantToken is not null) + { + Render(nativeFunctionDeclaration.ConstantToken); + WriteSpace(); + } + + Render(nativeFunctionDeclaration.NativeToken); + WriteSpace(); + Render(nativeFunctionDeclaration.IdentifierName); + WriteSpace(); + Render(nativeFunctionDeclaration.ParameterList); + WriteSpace(); + Render(nativeFunctionDeclaration.ReturnClause); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/NullLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/NullLiteralExpressionRenderer.cs deleted file mode 100644 index cf49415d..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/NullLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassNullLiteralExpressionSyntax nullLiteralExpression) - { - Write(JassKeyword.Null); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/OctalLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/OctalLiteralExpressionRenderer.cs deleted file mode 100644 index 8002c613..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/OctalLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassOctalLiteralExpressionSyntax octalLiteralExpression) - { - Write(octalLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalLineRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListOrEmptyParameterListRenderer.cs similarity index 52% rename from src/War3Net.CodeAnalysis.Jass/Renderer/GlobalLineRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListOrEmptyParameterListRenderer.cs index f1b6c7a6..90fecb5b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/GlobalLineRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListOrEmptyParameterListRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -13,14 +13,12 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(IGlobalLineSyntax globalLine) + public void Render(JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) { - switch (globalLine) + switch (parameterListOrEmptyParameterList) { - case JassEmptySyntax empty: Render(empty); break; - case JassCommentSyntax comment: Render(comment); break; - case JassGlobalDeclarationSyntax globalDeclaration: Render(globalDeclaration); break; - case JassEndGlobalsCustomScriptAction endGlobals: Render(endGlobals); break; + case JassParameterListSyntax parameterList: Render(parameterList); break; + case JassEmptyParameterListSyntax emptyParameterList: Render(emptyParameterList); break; default: throw new NotSupportedException(); } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListRenderer.cs index b9116b73..6bc840ce 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterListRenderer.cs @@ -5,8 +5,6 @@ // // ------------------------------------------------------------------------------ -using System.Linq; - using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -15,18 +13,15 @@ public partial class JassRenderer { public void Render(JassParameterListSyntax parameterList) { - if (parameterList.Parameters.Any()) - { - Render(parameterList.Parameters.First()); - foreach (var parameter in parameterList.Parameters.Skip(1)) - { - Write($"{JassSymbol.Comma} "); - Render(parameter); - } - } - else + Render(parameterList.TakesToken); + WriteSpace(); + + Render(parameterList.ParameterList.Items[0]); + for (var i = 1; i < parameterList.ParameterList.Items.Length; i++) { - Render(JassTypeSyntax.Nothing); + Render(parameterList.ParameterList.Separators[i - 1]); + WriteSpace(); + Render(parameterList.ParameterList.Items[i]); } } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterRenderer.cs index c4519850..d1885b1e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ParameterRenderer.cs @@ -14,7 +14,7 @@ public partial class JassRenderer public void Render(JassParameterSyntax parameter) { Render(parameter.Type); - Write(' '); + WriteSpace(); Render(parameter.IdentifierName); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ParenthesizedExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ParenthesizedExpressionRenderer.cs index b25c776b..3ae0c383 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ParenthesizedExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ParenthesizedExpressionRenderer.cs @@ -13,9 +13,9 @@ public partial class JassRenderer { public void Render(JassParenthesizedExpressionSyntax parenthesizedExpression) { - Write(JassSymbol.LeftParenthesis); + Render(parenthesizedExpression.OpenParenToken); Render(parenthesizedExpression.Expression); - Write(JassSymbol.RightParenthesis); + Render(parenthesizedExpression.CloseParenToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/CommentRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/PredefinedTypeRenderer.cs similarity index 71% rename from src/War3Net.CodeAnalysis.Jass/Renderer/CommentRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/PredefinedTypeRenderer.cs index 4c2f0288..2af47e57 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/CommentRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/PredefinedTypeRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,9 +11,9 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassCommentSyntax comment) + public void Render(JassPredefinedTypeSyntax predefinedType) { - Write(comment.ToString()); + Render(predefinedType.Token); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/RealLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/RealLiteralExpressionRenderer.cs deleted file mode 100644 index 50c3e977..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/RealLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassRealLiteralExpressionSyntax realLiteralExpression) - { - Write(realLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/CharacterLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ReturnClauseRenderer.cs similarity index 63% rename from src/War3Net.CodeAnalysis.Jass/Renderer/CharacterLiteralExpressionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/ReturnClauseRenderer.cs index 32de6c83..087a941f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/CharacterLiteralExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ReturnClauseRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,9 +11,11 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassCharacterLiteralExpressionSyntax characterLiteralExpression) + public void Render(JassReturnClauseSyntax returnClause) { - Write(characterLiteralExpression.ToString()); + Render(returnClause.ReturnsToken); + WriteSpace(); + Render(returnClause.ReturnType); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/ReturnStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/ReturnStatementRenderer.cs index 7cd13752..62bcc8b6 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/ReturnStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/ReturnStatementRenderer.cs @@ -13,13 +13,10 @@ public partial class JassRenderer { public void Render(JassReturnStatementSyntax returnStatement) { - if (returnStatement.Value is null) + Render(returnStatement.ReturnToken); + if (returnStatement.Value is not null) { - Write(JassKeyword.Return); - } - else - { - Write($"{JassKeyword.Return} "); + WriteSpace(); Render(returnStatement.Value); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/SetStatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/SetStatementRenderer.cs index 6fc94969..66e79e7b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/SetStatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/SetStatementRenderer.cs @@ -13,17 +13,16 @@ public partial class JassRenderer { public void Render(JassSetStatementSyntax setStatement) { - Write($"{JassKeyword.Set} "); + Render(setStatement.SetToken); + WriteSpace(); Render(setStatement.IdentifierName); - if (setStatement.Indexer is not null) + if (setStatement.ElementAccessClause is not null) { - Write(JassSymbol.LeftSquareBracket); - Render(setStatement.Indexer); - Write(JassSymbol.RightSquareBracket); + Render(setStatement.ElementAccessClause); } - Write(' '); + WriteSpace(); Render(setStatement.Value); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/StatementLineRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/StatementLineRenderer.cs deleted file mode 100644 index 148e1a9a..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/StatementLineRenderer.cs +++ /dev/null @@ -1,40 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(IStatementLineSyntax statementLine) - { - switch (statementLine) - { - case JassEmptySyntax empty: Render(empty); break; - case JassCommentSyntax comment: Render(comment); break; - case JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement: Render(localVariableDeclarationStatement); break; - case JassSetStatementSyntax setStatement: Render(setStatement); break; - case JassCallStatementSyntax callStatement: Render(callStatement); break; - case JassIfCustomScriptAction ifCustomScriptAction: Render(ifCustomScriptAction); break; - case JassElseIfCustomScriptAction elseIfCustomScriptAction: Render(elseIfCustomScriptAction); break; - case JassElseCustomScriptAction elseCustomScriptAction: Render(elseCustomScriptAction); break; - case JassEndIfCustomScriptAction endIfCustomScriptAction: Render(endIfCustomScriptAction); break; - case JassLoopCustomScriptAction loopCustomScriptAction: Render(loopCustomScriptAction); break; - case JassEndLoopCustomScriptAction endLoopCustomScriptAction: Render(endLoopCustomScriptAction); break; - case JassExitStatementSyntax exitStatement: Render(exitStatement); break; - case JassReturnStatementSyntax returnStatement: Render(returnStatement); break; - case JassEndFunctionCustomScriptAction functionCustomScriptAction: Render(functionCustomScriptAction); break; - case JassDebugCustomScriptAction debugCustomScriptAction: Render(debugCustomScriptAction); break; - - default: throw new NotSupportedException(); - } - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/StatementListRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/StatementListRenderer.cs index 5fc880d9..ed32fe10 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/StatementListRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/StatementListRenderer.cs @@ -5,18 +5,19 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Immutable; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassStatementListSyntax statementList) + public void Render(ImmutableArray statementList) { - foreach (var statement in statementList.Statements) + foreach (var statement in statementList) { Render(statement); - WriteLine(); } } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/StatementRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/StatementRenderer.cs index 44f15bca..3e15c508 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/StatementRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/StatementRenderer.cs @@ -13,12 +13,10 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(IStatementSyntax statement) + public void Render(JassStatementSyntax statement) { switch (statement) { - case JassEmptySyntax empty: Render(empty); break; - case JassCommentSyntax comment: Render(comment); break; case JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement: Render(localVariableDeclarationStatement); break; case JassSetStatementSyntax setStatement: Render(setStatement); break; case JassCallStatementSyntax callStatement: Render(callStatement); break; diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/StringLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/StringLiteralExpressionRenderer.cs deleted file mode 100644 index 12b54766..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/StringLiteralExpressionRenderer.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public partial class JassRenderer - { - public void Render(JassStringLiteralExpressionSyntax stringLiteralExpression) - { - Write(stringLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/DebugCustomScriptActionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTokenRenderer.cs similarity index 63% rename from src/War3Net.CodeAnalysis.Jass/Renderer/DebugCustomScriptActionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTokenRenderer.cs index 0f8bda0a..b9c5a298 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/DebugCustomScriptActionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTokenRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,10 +11,11 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassDebugCustomScriptAction debugCustomScriptAction) + public void Render(JassSyntaxToken syntaxToken) { - Write($"{JassKeyword.Debug} "); - Render(debugCustomScriptAction.Action); + Render(syntaxToken.LeadingTrivia); + Write(syntaxToken.Text); + Render(syntaxToken.TrailingTrivia); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/BooleanLiteralExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaListRenderer.cs similarity index 64% rename from src/War3Net.CodeAnalysis.Jass/Renderer/BooleanLiteralExpressionRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaListRenderer.cs index a632e34f..e2268f02 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/BooleanLiteralExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaListRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -11,9 +11,12 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(JassBooleanLiteralExpressionSyntax booleanLiteralExpression) + public void Render(JassSyntaxTriviaList triviaList) { - Write(booleanLiteralExpression.ToString()); + foreach (var trivia in triviaList.Trivia) + { + Render(trivia); + } } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs new file mode 100644 index 00000000..c05aa805 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs @@ -0,0 +1,57 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenderer + { + public void Render(JassSyntaxTrivia trivia) + { + if (trivia.SyntaxKind == JassSyntaxKind.SingleLineCommentTrivia) + { + WriteSpace(); + Write(trivia.Text.TrimEnd()); + } + else if (trivia.SyntaxKind == JassSyntaxKind.NewlineTrivia) + { + var lines = 0; + var isCarriageReturn = false; + for (var i = 0; i < trivia.Text.Length; i++) + { + if (trivia.Text[i] == '\r') + { + if (isCarriageReturn) + { + lines++; + } + else + { + isCarriageReturn = true; + } + } + else + { + lines++; + isCarriageReturn = false; + } + } + + if (isCarriageReturn) + { + lines++; + } + + for (var i = 0; i < lines; i++) + { + WriteLine(); + } + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/TopLevelDeclarationRenderer.cs similarity index 65% rename from src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationRenderer.cs rename to src/War3Net.CodeAnalysis.Jass/Renderer/TopLevelDeclarationRenderer.cs index e7bd31e0..b1f65444 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/DeclarationRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/TopLevelDeclarationRenderer.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -13,15 +13,12 @@ namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(ITopLevelDeclarationSyntax declaration) + public void Render(JassTopLevelDeclarationSyntax declaration) { switch (declaration) { - case JassEmptySyntax empty: Render(empty); break; - case JassCommentSyntax comment: Render(comment); break; case JassTypeDeclarationSyntax typeDeclaration: Render(typeDeclaration); break; - case JassGlobalDeclarationListSyntax globalDeclarationList: Render(globalDeclarationList); break; - case JassGlobalDeclarationSyntax globalDeclaration: Render(globalDeclaration); break; + case JassGlobalsDeclarationSyntax globalsDeclaration: Render(globalsDeclaration); break; case JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration: Render(nativeFunctionDeclaration); break; case JassFunctionDeclarationSyntax functionDeclaration: Render(functionDeclaration); break; diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/TypeDeclarationRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/TypeDeclarationRenderer.cs index 15efad05..b50856f3 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/TypeDeclarationRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/TypeDeclarationRenderer.cs @@ -13,9 +13,12 @@ public partial class JassRenderer { public void Render(JassTypeDeclarationSyntax typeDeclaration) { - Write($"{JassKeyword.Type} "); + Render(typeDeclaration.TypeToken); + WriteSpace(); Render(typeDeclaration.IdentifierName); - Write($" {JassKeyword.Extends} "); + WriteSpace(); + Render(typeDeclaration.ExtendsToken); + WriteSpace(); Render(typeDeclaration.BaseType); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/TypeRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/TypeRenderer.cs index 4dee306d..d889d72e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/TypeRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/TypeRenderer.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -13,7 +15,13 @@ public partial class JassRenderer { public void Render(JassTypeSyntax type) { - Render(type.TypeName); + switch (type) + { + case JassIdentifierNameSyntax identifierName: Render(identifierName); break; + case JassPredefinedTypeSyntax predefinedType: Render(predefinedType); break; + + default: throw new NotSupportedException(); + } } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs index 7b478ce5..8ea7d4fd 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs @@ -5,7 +5,6 @@ // // ------------------------------------------------------------------------------ -using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -14,13 +13,10 @@ public partial class JassRenderer { public void Render(JassUnaryExpressionSyntax unaryExpression) { - if (unaryExpression.Operator == UnaryOperatorType.Not) + Render(unaryExpression.OperatorToken); + if (unaryExpression.OperatorToken.SyntaxKind == JassSyntaxKind.NotKeyword) { - Write($"{unaryExpression.Operator.GetSymbol()} "); - } - else - { - Write(unaryExpression.Operator.GetSymbol()); + WriteSpace(); } Render(unaryExpression.Expression); diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/VariableDeclaratorRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/VariableDeclaratorRenderer.cs index 45723f0e..14cc8620 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/VariableDeclaratorRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/VariableDeclaratorRenderer.cs @@ -5,34 +5,21 @@ // // ------------------------------------------------------------------------------ -using System; - using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public partial class JassRenderer { - public void Render(IVariableDeclaratorSyntax declarator) - { - switch (declarator) - { - case JassArrayDeclaratorSyntax arrayDeclarator: Render(arrayDeclarator); break; - case JassVariableDeclaratorSyntax variableDeclarator: Render(variableDeclarator); break; - - default: throw new NotSupportedException(); - } - } - public void Render(JassVariableDeclaratorSyntax variableDeclarator) { Render(variableDeclarator.Type); - Write(' '); + WriteSpace(); Render(variableDeclarator.IdentifierName); if (variableDeclarator.Value is not null) { - Write(' '); + WriteSpace(); Render(variableDeclarator.Value); } } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/VariableOrArrayDeclaratorRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/VariableOrArrayDeclaratorRenderer.cs new file mode 100644 index 00000000..0536c926 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/VariableOrArrayDeclaratorRenderer.cs @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public partial class JassRenderer + { + public void Render(JassVariableOrArrayDeclaratorSyntax declarator) + { + switch (declarator) + { + case JassArrayDeclaratorSyntax arrayDeclarator: Render(arrayDeclarator); break; + case JassVariableDeclaratorSyntax variableDeclarator: Render(variableDeclarator); break; + + default: throw new NotSupportedException(); + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/BinaryOperatorType.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/BinaryOperatorType.cs deleted file mode 100644 index d0bf2ffe..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/BinaryOperatorType.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public enum BinaryOperatorType - { - Add, - Subtract, - Multiplication, - Division, - GreaterThan, - LessThan, - Equals, - NotEquals, - GreaterOrEqual, - LessOrEqual, - And, - Or, - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IDeclarationLineSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IDeclarationLineSyntax.cs deleted file mode 100644 index ff4111ca..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IDeclarationLineSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IDeclarationLineSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IExpressionSyntax.cs deleted file mode 100644 index 4c015ece..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IExpressionSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IExpressionSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalDeclarationSyntax.cs deleted file mode 100644 index 685ac3e3..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalDeclarationSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IGlobalDeclarationSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalLineSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalLineSyntax.cs deleted file mode 100644 index 221f11c9..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IGlobalLineSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IGlobalLineSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IInvocationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IInvocationSyntax.cs deleted file mode 100644 index 39d087a4..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IInvocationSyntax.cs +++ /dev/null @@ -1,16 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IInvocationSyntax - { - public JassIdentifierNameSyntax IdentifierName { get; init; } - - public JassArgumentListSyntax Arguments { get; init; } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IMemberDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IMemberDeclarationSyntax.cs deleted file mode 100644 index 953e24a4..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IMemberDeclarationSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IMemberDeclarationSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IScopedDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IScopedDeclarationSyntax.cs deleted file mode 100644 index 5b3b67ac..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IScopedDeclarationSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IScopedDeclarationSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IScopedGlobalDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IScopedGlobalDeclarationSyntax.cs deleted file mode 100644 index 6ac2795f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IScopedGlobalDeclarationSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IScopedGlobalDeclarationSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IStatementLineSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IStatementLineSyntax.cs deleted file mode 100644 index 6e5a531f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IStatementLineSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IStatementLineSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IStatementSyntax.cs deleted file mode 100644 index b618f868..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IStatementSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IStatementSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/ITopLevelDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/ITopLevelDeclarationSyntax.cs deleted file mode 100644 index 70abd3ed..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/ITopLevelDeclarationSyntax.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface ITopLevelDeclarationSyntax : IEquatable - { - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/IVariableDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/IVariableDeclaratorSyntax.cs deleted file mode 100644 index 455f261d..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/IVariableDeclaratorSyntax.cs +++ /dev/null @@ -1,18 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public interface IVariableDeclaratorSyntax : IEquatable - { - JassTypeSyntax Type { get; init; } - - JassIdentifierNameSyntax IdentifierName { get; init; } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassArgumentListSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassArgumentListSyntax.cs index 7f5d431a..2972903f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassArgumentListSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassArgumentListSyntax.cs @@ -5,27 +5,126 @@ // // ------------------------------------------------------------------------------ -using System; -using System.Collections.Immutable; -using System.Linq; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassArgumentListSyntax : IEquatable + public class JassArgumentListSyntax : JassSyntaxNode { - public JassArgumentListSyntax(ImmutableArray arguments) + public static readonly JassArgumentListSyntax Empty = new( + new JassSyntaxToken(JassSyntaxKind.OpenParenToken, JassSymbol.OpenParen, JassSyntaxTriviaList.Empty), + SeparatedSyntaxList.Empty, + new JassSyntaxToken(JassSyntaxKind.CloseParenToken, JassSymbol.CloseParen, JassSyntaxTriviaList.Empty)); + + internal JassArgumentListSyntax( + JassSyntaxToken openParenToken, + SeparatedSyntaxList argumentList, + JassSyntaxToken closeParenToken) + { + OpenParenToken = openParenToken; + ArgumentList = argumentList; + CloseParenToken = closeParenToken; + } + + public JassSyntaxToken OpenParenToken { get; } + + public SeparatedSyntaxList ArgumentList { get; } + + public JassSyntaxToken CloseParenToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ArgumentList; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassArgumentListSyntax argumentList + && ArgumentList.IsEquivalentTo(argumentList.ArgumentList); + } + + public override void WriteTo(TextWriter writer) + { + OpenParenToken.WriteTo(writer); + ArgumentList.WriteTo(writer); + CloseParenToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + return ArgumentList.Items; + } + + public override IEnumerable GetChildTokens() + { + yield return OpenParenToken; + foreach (var child in ArgumentList.Separators) + { + yield return child; + } + + yield return CloseParenToken; + } + + public override IEnumerable GetChildNodesAndTokens() { - Arguments = arguments; + yield return OpenParenToken; + foreach (var child in ArgumentList.GetChildNodesAndTokens()) + { + yield return child; + } + + yield return CloseParenToken; } - public ImmutableArray Arguments { get; init; } + public override IEnumerable GetDescendantNodes() + { + return ArgumentList.GetDescendantNodes(); + } - public bool Equals(JassArgumentListSyntax? other) + public override IEnumerable GetDescendantTokens() { - return other is not null - && Arguments.SequenceEqual(other.Arguments); + yield return OpenParenToken; + foreach (var descendant in ArgumentList.GetDescendantTokens()) + { + yield return descendant; + } + + yield return CloseParenToken; } - public override string ToString() => string.Join($"{JassSymbol.Comma} ", Arguments); + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return OpenParenToken; + foreach (var descendant in ArgumentList.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return CloseParenToken; + } + + public override string ToString() => $"{OpenParenToken}{ArgumentList}{CloseParenToken}"; + + public override JassSyntaxToken GetFirstToken() => OpenParenToken; + + public override JassSyntaxToken GetLastToken() => CloseParenToken; + + protected internal override JassArgumentListSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassArgumentListSyntax( + newToken, + ArgumentList, + CloseParenToken); + } + + protected internal override JassArgumentListSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassArgumentListSyntax( + OpenParenToken, + ArgumentList, + newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayDeclaratorSyntax.cs index ed4d9c6e..ce8cc2a7 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayDeclaratorSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayDeclaratorSyntax.cs @@ -5,27 +5,131 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassArrayDeclaratorSyntax : IVariableDeclaratorSyntax + public class JassArrayDeclaratorSyntax : JassVariableOrArrayDeclaratorSyntax { - public JassArrayDeclaratorSyntax(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + internal JassArrayDeclaratorSyntax( + JassTypeSyntax type, + JassSyntaxToken arrayToken, + JassIdentifierNameSyntax identifierName) { Type = type; + ArrayToken = arrayToken; IdentifierName = identifierName; } - public JassTypeSyntax Type { get; init; } + public JassTypeSyntax Type { get; } + + public JassSyntaxToken ArrayToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ArrayDeclarator; - public bool Equals(IVariableDeclaratorSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassArrayDeclaratorSyntax arrayDeclarator - && Type.Equals(arrayDeclarator.Type) - && IdentifierName.Equals(arrayDeclarator.IdentifierName); + && Type.IsEquivalentTo(arrayDeclarator.Type) + && IdentifierName.IsEquivalentTo(arrayDeclarator.IdentifierName); + } + + public override void WriteTo(TextWriter writer) + { + Type.WriteTo(writer); + ArrayToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Type; + yield return IdentifierName; + } + + public override IEnumerable GetChildTokens() + { + yield return ArrayToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Type; + yield return ArrayToken; + yield return IdentifierName; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Type; + foreach (var descendant in Type.GetDescendantNodes()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{Type} {JassKeyword.Array} {IdentifierName}"; + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in Type.GetDescendantTokens()) + { + yield return descendant; + } + + yield return ArrayToken; + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Type; + foreach (var descendant in Type.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ArrayToken; + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{Type} {ArrayToken} {IdentifierName}"; + + public override JassSyntaxToken GetFirstToken() => Type.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => IdentifierName.GetLastToken(); + + protected internal override JassArrayDeclaratorSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassArrayDeclaratorSyntax( + Type.ReplaceFirstToken(newToken), + ArrayToken, + IdentifierName); + } + + protected internal override JassArrayDeclaratorSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassArrayDeclaratorSyntax( + Type, + ArrayToken, + IdentifierName.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayReferenceExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayReferenceExpressionSyntax.cs deleted file mode 100644 index da61f525..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassArrayReferenceExpressionSyntax.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassArrayReferenceExpressionSyntax : IExpressionSyntax - { - public JassArrayReferenceExpressionSyntax(JassIdentifierNameSyntax identifierName, IExpressionSyntax indexer) - { - IdentifierName = identifierName; - Indexer = indexer; - } - - public JassIdentifierNameSyntax IdentifierName { get; init; } - - public IExpressionSyntax Indexer { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassArrayReferenceExpressionSyntax arrayReferenceExpression - && IdentifierName.Equals(arrayReferenceExpression.IdentifierName) - && Indexer.Equals(arrayReferenceExpression.Indexer); - } - - public override string ToString() => $"{IdentifierName}{JassSymbol.LeftSquareBracket}{Indexer}{JassSymbol.RightSquareBracket}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassBinaryExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassBinaryExpressionSyntax.cs index 3bc5517f..fe0df0f5 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassBinaryExpressionSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassBinaryExpressionSyntax.cs @@ -5,33 +5,132 @@ // // ------------------------------------------------------------------------------ -using War3Net.CodeAnalysis.Jass.Extensions; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassBinaryExpressionSyntax : IExpressionSyntax + public class JassBinaryExpressionSyntax : JassExpressionSyntax { - public JassBinaryExpressionSyntax(BinaryOperatorType @operator, IExpressionSyntax left, IExpressionSyntax right) + internal JassBinaryExpressionSyntax( + JassExpressionSyntax left, + JassSyntaxToken operatorToken, + JassExpressionSyntax right) { - Operator = @operator; Left = left; + OperatorToken = operatorToken; Right = right; } - public BinaryOperatorType Operator { get; init; } + public JassExpressionSyntax Left { get; } - public IExpressionSyntax Left { get; init; } + public JassSyntaxToken OperatorToken { get; } - public IExpressionSyntax Right { get; init; } + public JassExpressionSyntax Right { get; } - public bool Equals(IExpressionSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxFacts.GetBinaryExpressionKind(OperatorToken.SyntaxKind); + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassBinaryExpressionSyntax binaryExpression - && Operator == binaryExpression.Operator - && Left.Equals(binaryExpression.Left) - && Right.Equals(binaryExpression.Right); + && Left.IsEquivalentTo(binaryExpression.Left) + && OperatorToken.IsEquivalentTo(binaryExpression.OperatorToken) + && Right.IsEquivalentTo(binaryExpression.Right); + } + + public override void WriteTo(TextWriter writer) + { + Left.WriteTo(writer); + OperatorToken.WriteTo(writer); + Right.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Left; + yield return Right; + } + + public override IEnumerable GetChildTokens() + { + yield return OperatorToken; } - public override string ToString() => $"{Left} {Operator.GetSymbol()} {Right}"; + public override IEnumerable GetChildNodesAndTokens() + { + yield return Left; + yield return OperatorToken; + yield return Right; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Left; + foreach (var descendant in Left.GetDescendantNodes()) + { + yield return descendant; + } + + yield return Right; + foreach (var descendant in Right.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in Left.GetDescendantTokens()) + { + yield return descendant; + } + + yield return OperatorToken; + + foreach (var descendant in Right.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Left; + foreach (var descendant in Left.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return OperatorToken; + + yield return Right; + foreach (var descendant in Right.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{Left} {OperatorToken} {Right}"; + + public override JassSyntaxToken GetFirstToken() => Left.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => Right.GetLastToken(); + + protected internal override JassBinaryExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassBinaryExpressionSyntax( + Left.ReplaceFirstToken(newToken), + OperatorToken, + Right); + } + + protected internal override JassBinaryExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassBinaryExpressionSyntax( + Left, + OperatorToken, + Right.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassBooleanLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassBooleanLiteralExpressionSyntax.cs deleted file mode 100644 index 90569d5d..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassBooleanLiteralExpressionSyntax.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassBooleanLiteralExpressionSyntax : IExpressionSyntax - { - public static readonly JassBooleanLiteralExpressionSyntax True = new JassBooleanLiteralExpressionSyntax(true); - public static readonly JassBooleanLiteralExpressionSyntax False = new JassBooleanLiteralExpressionSyntax(false); - - private JassBooleanLiteralExpressionSyntax(bool value) - { - Value = value; - } - - public bool Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassBooleanLiteralExpressionSyntax booleanLiteralExpression - && Value == booleanLiteralExpression.Value; - } - - public override string ToString() => Value ? JassKeyword.True : JassKeyword.False; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCallStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassCallStatementSyntax.cs index 8d42270f..990b905d 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCallStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassCallStatementSyntax.cs @@ -5,34 +5,131 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassCallStatementSyntax : IStatementSyntax, IStatementLineSyntax, IInvocationSyntax + public class JassCallStatementSyntax : JassStatementSyntax { - public JassCallStatementSyntax(JassIdentifierNameSyntax identifierName, JassArgumentListSyntax arguments) + internal JassCallStatementSyntax( + JassSyntaxToken callToken, + JassIdentifierNameSyntax identifierName, + JassArgumentListSyntax argumentList) { + CallToken = callToken; IdentifierName = identifierName; - Arguments = arguments; + ArgumentList = argumentList; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassSyntaxToken CallToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassArgumentListSyntax ArgumentList { get; } - public JassArgumentListSyntax Arguments { get; init; } + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.CallStatement; - public bool Equals(IStatementSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassCallStatementSyntax callStatement - && IdentifierName.Equals(callStatement.IdentifierName) - && Arguments.Equals(callStatement.Arguments); + && IdentifierName.IsEquivalentTo(callStatement.IdentifierName) + && ArgumentList.IsEquivalentTo(callStatement.ArgumentList); } - public bool Equals(IStatementLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassCallStatementSyntax callStatement - && IdentifierName.Equals(callStatement.IdentifierName) - && Arguments.Equals(callStatement.Arguments); + CallToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + ArgumentList.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + yield return ArgumentList; + } + + public override IEnumerable GetChildTokens() + { + yield return CallToken; } - public override string ToString() => $"{JassKeyword.Call} {IdentifierName}{JassSymbol.LeftParenthesis}{Arguments}{JassSymbol.RightParenthesis}"; + public override IEnumerable GetChildNodesAndTokens() + { + yield return CallToken; + yield return IdentifierName; + yield return ArgumentList; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + yield return ArgumentList; + foreach (var descendant in ArgumentList.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return CallToken; + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ArgumentList.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return CallToken; + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ArgumentList; + foreach (var descendant in ArgumentList.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{CallToken} {IdentifierName}{ArgumentList}"; + + public override JassSyntaxToken GetFirstToken() => CallToken; + + public override JassSyntaxToken GetLastToken() => ArgumentList.GetLastToken(); + + protected internal override JassCallStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassCallStatementSyntax( + newToken, + IdentifierName, + ArgumentList); + } + + protected internal override JassCallStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassCallStatementSyntax( + CallToken, + IdentifierName, + ArgumentList.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCharacterLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassCharacterLiteralExpressionSyntax.cs deleted file mode 100644 index 52d5461c..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCharacterLiteralExpressionSyntax.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassCharacterLiteralExpressionSyntax : IExpressionSyntax - { - public JassCharacterLiteralExpressionSyntax(char value) - { - Value = value; - } - - public char Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassCharacterLiteralExpressionSyntax characterLiteralExpression - && Value == characterLiteralExpression.Value; - } - - public override string ToString() => $"{JassSymbol.Apostrophe}{Value}{JassSymbol.Apostrophe}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCommentSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassCommentSyntax.cs deleted file mode 100644 index 9a048603..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCommentSyntax.cs +++ /dev/null @@ -1,77 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassCommentSyntax : ITopLevelDeclarationSyntax, IScopedDeclarationSyntax, IGlobalDeclarationSyntax, IScopedGlobalDeclarationSyntax, IMemberDeclarationSyntax, IStatementSyntax, IDeclarationLineSyntax, IGlobalLineSyntax, IStatementLineSyntax - { - public JassCommentSyntax(string comment) - { - Comment = comment; - } - - public string Comment { get; init; } - - public bool Equals(ITopLevelDeclarationSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IScopedDeclarationSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IGlobalDeclarationSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IScopedGlobalDeclarationSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IMemberDeclarationSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IStatementSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IDeclarationLineSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IGlobalLineSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public bool Equals(IStatementLineSyntax? other) - { - return other is JassCommentSyntax comment - && string.Equals(Comment, comment.Comment, StringComparison.Ordinal); - } - - public override string ToString() => $"{JassSymbol.Slash}{JassSymbol.Slash}{Comment}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCompilationUnitSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassCompilationUnitSyntax.cs index 0c1e458b..b4b43c3d 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassCompilationUnitSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassCompilationUnitSyntax.cs @@ -5,27 +5,111 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassCompilationUnitSyntax : IEquatable + public class JassCompilationUnitSyntax : JassSyntaxNode { - public JassCompilationUnitSyntax(ImmutableArray declarations) + internal JassCompilationUnitSyntax( + ImmutableArray declarations, + JassSyntaxToken endOfFileToken) { Declarations = declarations; + EndOfFileToken = endOfFileToken; + } + + public ImmutableArray Declarations { get; } + + public JassSyntaxToken EndOfFileToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.CompilationUnit; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassCompilationUnitSyntax compilationUnit + && Declarations.IsEquivalentTo(compilationUnit.Declarations); + } + + public override void WriteTo(TextWriter writer) + { + Declarations.WriteTo(writer); + EndOfFileToken.WriteTo(writer); } - public ImmutableArray Declarations { get; init; } + public override IEnumerable GetChildNodes() + { + return Declarations; + } - public bool Equals(JassCompilationUnitSyntax? other) + public override IEnumerable GetChildTokens() { - return other is not null - && Declarations.SequenceEqual(other.Declarations); + yield return EndOfFileToken; } - public override string ToString() => $"<{base.ToString()}> [{Declarations.Length}]"; + public override IEnumerable GetChildNodesAndTokens() + { + foreach (var child in Declarations) + { + yield return child; + } + + yield return EndOfFileToken; + } + + public override IEnumerable GetDescendantNodes() + { + return Declarations.GetDescendantNodes(); + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in Declarations.GetDescendantTokens()) + { + yield return descendant; + } + + yield return EndOfFileToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + foreach (var descendant in Declarations.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return EndOfFileToken; + } + + public override JassSyntaxToken GetFirstToken() => Declarations.IsEmpty ? EndOfFileToken : Declarations[0].GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => EndOfFileToken; + + protected internal override JassCompilationUnitSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + if (!Declarations.IsEmpty) + { + return new JassCompilationUnitSyntax( + Declarations.ReplaceFirstItem(Declarations[0].ReplaceFirstToken(newToken)), + EndOfFileToken); + } + + return new JassCompilationUnitSyntax( + Declarations, + newToken); + } + + protected internal override JassCompilationUnitSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassCompilationUnitSyntax( + Declarations, + newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugCustomScriptAction.cs deleted file mode 100644 index 1d46f2ea..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugCustomScriptAction.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassDebugCustomScriptAction : IStatementLineSyntax - { - public static readonly JassDebugCustomScriptAction DebugLoop = new JassDebugCustomScriptAction(JassLoopCustomScriptAction.Value); - - public JassDebugCustomScriptAction(IStatementLineSyntax action) - { - Action = action; - } - - public IStatementLineSyntax Action { get; init; } - - public bool Equals(IStatementLineSyntax? other) - { - return other is JassDebugCustomScriptAction debug - && Action.Equals(debug.Action); - } - - public override string ToString() => $"{JassKeyword.Debug} {Action}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugStatementSyntax.cs index a403a987..db60586f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassDebugStatementSyntax.cs @@ -5,23 +5,104 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassDebugStatementSyntax : IStatementSyntax + public class JassDebugStatementSyntax : JassStatementSyntax { - public JassDebugStatementSyntax(IStatementSyntax statement) + internal JassDebugStatementSyntax( + JassSyntaxToken debugToken, + JassStatementSyntax statement) { + DebugToken = debugToken; Statement = statement; } - public IStatementSyntax Statement { get; init; } + public JassSyntaxToken DebugToken { get; } + + public JassStatementSyntax Statement { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxFacts.GetDebugStatementKind(Statement.SyntaxKind); - public bool Equals(IStatementSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassDebugStatementSyntax debugStatement - && Statement.Equals(debugStatement.Statement); + && Statement.IsEquivalentTo(debugStatement.Statement); + } + + public override void WriteTo(TextWriter writer) + { + DebugToken.WriteTo(writer); + Statement.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Statement; + } + + public override IEnumerable GetChildTokens() + { + yield return DebugToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return DebugToken; + yield return Statement; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Statement; + foreach (var descendant in Statement.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return DebugToken; + + foreach (var descendant in Statement.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return DebugToken; + + yield return Statement; + foreach (var descendant in Statement.GetDescendantNodesAndTokens()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.Debug} {Statement}"; + public override string ToString() => $"{DebugToken} {Statement}"; + + public override JassSyntaxToken GetFirstToken() => DebugToken; + + public override JassSyntaxToken GetLastToken() => Statement.GetLastToken(); + + protected internal override JassDebugStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassDebugStatementSyntax( + newToken, + Statement); + } + + protected internal override JassDebugStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassDebugStatementSyntax( + DebugToken, + Statement.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassDecimalLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassDecimalLiteralExpressionSyntax.cs deleted file mode 100644 index 2f5a6b36..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassDecimalLiteralExpressionSyntax.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Globalization; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassDecimalLiteralExpressionSyntax : IExpressionSyntax - { - public JassDecimalLiteralExpressionSyntax(int value) - { - Value = value; - } - - public int Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassDecimalLiteralExpressionSyntax decimalLiteralExpression - && Value == decimalLiteralExpression.Value; - } - - public override string ToString() => Value.ToString(CultureInfo.InvariantCulture); - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessClauseSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessClauseSyntax.cs new file mode 100644 index 00000000..39c619ba --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessClauseSyntax.cs @@ -0,0 +1,121 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassElementAccessClauseSyntax : JassSyntaxNode + { + internal JassElementAccessClauseSyntax( + JassSyntaxToken openBracketToken, + JassExpressionSyntax expression, + JassSyntaxToken closeBracketToken) + { + OpenBracketToken = openBracketToken; + Expression = expression; + CloseBracketToken = closeBracketToken; + } + + public JassSyntaxToken OpenBracketToken { get; } + + public JassExpressionSyntax Expression { get; } + + public JassSyntaxToken CloseBracketToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ElementAccessClause; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassElementAccessClauseSyntax elementAccessClause + && Expression.IsEquivalentTo(elementAccessClause.Expression); + } + + public override void WriteTo(TextWriter writer) + { + OpenBracketToken.WriteTo(writer); + Expression.WriteTo(writer); + CloseBracketToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Expression; + } + + public override IEnumerable GetChildTokens() + { + yield return OpenBracketToken; + yield return CloseBracketToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return OpenBracketToken; + yield return Expression; + yield return CloseBracketToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return OpenBracketToken; + + foreach (var descendant in Expression.GetDescendantTokens()) + { + yield return descendant; + } + + yield return CloseBracketToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return OpenBracketToken; + + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return CloseBracketToken; + } + + public override string ToString() => $"{OpenBracketToken}{Expression}{CloseBracketToken}"; + + public override JassSyntaxToken GetFirstToken() => OpenBracketToken; + + public override JassSyntaxToken GetLastToken() => CloseBracketToken; + + protected internal override JassElementAccessClauseSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassElementAccessClauseSyntax( + newToken, + Expression, + CloseBracketToken); + } + + protected internal override JassElementAccessClauseSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassElementAccessClauseSyntax( + OpenBracketToken, + Expression, + newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessExpressionSyntax.cs new file mode 100644 index 00000000..0ab5dc72 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElementAccessExpressionSyntax.cs @@ -0,0 +1,123 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassElementAccessExpressionSyntax : JassExpressionSyntax + { + internal JassElementAccessExpressionSyntax( + JassIdentifierNameSyntax identifierName, + JassElementAccessClauseSyntax elementAccessClause) + { + IdentifierName = identifierName; + ElementAccessClause = elementAccessClause; + } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassElementAccessClauseSyntax ElementAccessClause { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ElementAccessExpression; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassElementAccessExpressionSyntax elementAccessExpression + && IdentifierName.IsEquivalentTo(elementAccessExpression.IdentifierName) + && ElementAccessClause.IsEquivalentTo(elementAccessExpression.ElementAccessClause); + } + + public override void WriteTo(TextWriter writer) + { + IdentifierName.WriteTo(writer); + ElementAccessClause.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + yield return ElementAccessClause; + } + + public override IEnumerable GetChildTokens() + { + yield break; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return IdentifierName; + yield return ElementAccessClause; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + yield return ElementAccessClause; + foreach (var descendant in ElementAccessClause.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ElementAccessClause.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ElementAccessClause; + foreach (var descendant in ElementAccessClause.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{IdentifierName}{ElementAccessClause}"; + + public override JassSyntaxToken GetFirstToken() => IdentifierName.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => ElementAccessClause.GetLastToken(); + + protected internal override JassElementAccessExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassElementAccessExpressionSyntax( + IdentifierName.ReplaceFirstToken(newToken), + ElementAccessClause); + } + + protected internal override JassElementAccessExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassElementAccessExpressionSyntax( + IdentifierName, + ElementAccessClause.ReplaceLastToken(newToken)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseClauseSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseClauseSyntax.cs index 46e279d1..e30ad577 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseClauseSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseClauseSyntax.cs @@ -5,25 +5,113 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassElseClauseSyntax : IEquatable + public class JassElseClauseSyntax : JassSyntaxNode { - public JassElseClauseSyntax(JassStatementListSyntax body) + internal JassElseClauseSyntax( + JassSyntaxToken elseToken, + ImmutableArray statements) + { + ElseToken = elseToken; + Statements = statements; + } + + public JassSyntaxToken ElseToken { get; } + + public ImmutableArray Statements { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ElseClause; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassElseClauseSyntax elseClause + && Statements.IsEquivalentTo(elseClause.Statements); + } + + public override void WriteTo(TextWriter writer) + { + ElseToken.WriteTo(writer); + Statements.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + return Statements; + } + + public override IEnumerable GetChildTokens() + { + yield return ElseToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return ElseToken; + + foreach (var child in Statements) + { + yield return child; + } + } + + public override IEnumerable GetDescendantNodes() + { + return Statements.GetDescendantNodes(); + } + + public override IEnumerable GetDescendantTokens() + { + yield return ElseToken; + + foreach (var descendant in Statements.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() { - Body = body; + yield return ElseToken; + + foreach (var descendant in Statements.GetDescendantNodesAndTokens()) + { + yield return descendant; + } } - public JassStatementListSyntax Body { get; init; } + public override string ToString() => $"{ElseToken} [...]"; + + public override JassSyntaxToken GetFirstToken() => ElseToken; - public bool Equals(JassElseClauseSyntax? other) + public override JassSyntaxToken GetLastToken() => Statements.IsEmpty ? ElseToken : Statements[^1].GetLastToken(); + + protected internal override JassElseClauseSyntax ReplaceFirstToken(JassSyntaxToken newToken) { - return other is not null - && Body.Equals(other.Body); + return new JassElseClauseSyntax( + newToken, + Statements); } - public override string ToString() => $"{JassKeyword.Else} [{Body.Statements.Length}]"; + protected internal override JassElseClauseSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + if (!Statements.IsEmpty) + { + return new JassElseClauseSyntax( + ElseToken, + Statements.ReplaceLastItem(Statements[^1].ReplaceLastToken(newToken))); + } + + return new JassElseClauseSyntax( + newToken, + Statements); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseCustomScriptAction.cs deleted file mode 100644 index 4e6b693a..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassElseCustomScriptAction : IStatementLineSyntax - { - public static readonly JassElseCustomScriptAction Value = new JassElseCustomScriptAction(); - - private JassElseCustomScriptAction() - { - } - - public bool Equals(IStatementLineSyntax? other) => other is JassElseCustomScriptAction; - - public override string ToString() => JassKeyword.Else; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseDeclaratorSyntax.cs new file mode 100644 index 00000000..b73553e6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseDeclaratorSyntax.cs @@ -0,0 +1,121 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassElseIfClauseDeclaratorSyntax : JassSyntaxNode + { + internal JassElseIfClauseDeclaratorSyntax( + JassSyntaxToken elseIfToken, + JassExpressionSyntax condition, + JassSyntaxToken thenToken) + { + ElseIfToken = elseIfToken; + Condition = condition; + ThenToken = thenToken; + } + + public JassSyntaxToken ElseIfToken { get; } + + public JassExpressionSyntax Condition { get; } + + public JassSyntaxToken ThenToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ElseIfClauseDeclarator; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator + && Condition.IsEquivalentTo(elseIfClauseDeclarator.Condition); + } + + public override void WriteTo(TextWriter writer) + { + ElseIfToken.WriteTo(writer); + Condition.WriteTo(writer); + ThenToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Condition; + } + + public override IEnumerable GetChildTokens() + { + yield return ElseIfToken; + yield return ThenToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return ElseIfToken; + yield return Condition; + yield return ThenToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Condition; + foreach (var descendant in Condition.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return ElseIfToken; + + foreach (var descendant in Condition.GetDescendantTokens()) + { + yield return descendant; + } + + yield return ThenToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return ElseIfToken; + + yield return Condition; + foreach (var descendant in Condition.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ThenToken; + } + + public override string ToString() => $"{ElseIfToken} {Condition} {ThenToken}"; + + public override JassSyntaxToken GetFirstToken() => ElseIfToken; + + public override JassSyntaxToken GetLastToken() => ThenToken; + + protected internal override JassElseIfClauseDeclaratorSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassElseIfClauseDeclaratorSyntax( + newToken, + Condition, + ThenToken); + } + + protected internal override JassElseIfClauseDeclaratorSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassElseIfClauseDeclaratorSyntax( + ElseIfToken, + Condition, + newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseSyntax.cs index d5393202..2293687b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfClauseSyntax.cs @@ -5,29 +5,133 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassElseIfClauseSyntax : IEquatable + public class JassElseIfClauseSyntax : JassSyntaxNode { - public JassElseIfClauseSyntax(IExpressionSyntax condition, JassStatementListSyntax body) + internal JassElseIfClauseSyntax( + JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, + ImmutableArray statements) + { + ElseIfClauseDeclarator = elseIfClauseDeclarator; + Statements = statements; + } + + public JassElseIfClauseDeclaratorSyntax ElseIfClauseDeclarator { get; } + + public ImmutableArray Statements { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ElseIfClause; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassElseIfClauseSyntax elseIfClause + && ElseIfClauseDeclarator.IsEquivalentTo(elseIfClause.ElseIfClauseDeclarator) + && Statements.IsEquivalentTo(elseIfClause.Statements); + } + + public override void WriteTo(TextWriter writer) { - Condition = condition; - Body = body; + ElseIfClauseDeclarator.WriteTo(writer); + Statements.WriteTo(writer); } - public IExpressionSyntax Condition { get; init; } + public override IEnumerable GetChildNodes() + { + yield return ElseIfClauseDeclarator; + foreach (var child in Statements) + { + yield return child; + } + } - public JassStatementListSyntax Body { get; init; } + public override IEnumerable GetChildTokens() + { + yield break; + } - public bool Equals(JassElseIfClauseSyntax? other) + public override IEnumerable GetChildNodesAndTokens() { - return other is not null - && Condition.Equals(other.Condition) - && Body.Equals(other.Body); + yield return ElseIfClauseDeclarator; + foreach (var child in Statements) + { + yield return child; + } + } + + public override IEnumerable GetDescendantNodes() + { + yield return ElseIfClauseDeclarator; + foreach (var descendant in ElseIfClauseDeclarator.GetDescendantNodes()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.ElseIf} {Condition} {JassKeyword.Then} [{Body.Statements.Length}]"; + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in ElseIfClauseDeclarator.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return ElseIfClauseDeclarator; + foreach (var descendant in ElseIfClauseDeclarator.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{ElseIfClauseDeclarator} [...]"; + + public override JassSyntaxToken GetFirstToken() => ElseIfClauseDeclarator.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => Statements.IsEmpty ? ElseIfClauseDeclarator.GetLastToken() : Statements[^1].GetLastToken(); + + protected internal override JassElseIfClauseSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassElseIfClauseSyntax( + ElseIfClauseDeclarator.ReplaceFirstToken(newToken), + Statements); + } + + protected internal override JassElseIfClauseSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + if (!Statements.IsEmpty) + { + return new JassElseIfClauseSyntax( + ElseIfClauseDeclarator, + Statements.ReplaceLastItem(Statements[^1].ReplaceLastToken(newToken))); + } + + return new JassElseIfClauseSyntax( + ElseIfClauseDeclarator.ReplaceLastToken(newToken), + Statements); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfCustomScriptAction.cs deleted file mode 100644 index 2aa2b35f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassElseIfCustomScriptAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassElseIfCustomScriptAction : IStatementLineSyntax - { - public JassElseIfCustomScriptAction(IExpressionSyntax condition) - { - Condition = condition; - } - - public IExpressionSyntax Condition { get; init; } - - public bool Equals(IStatementLineSyntax? other) - { - return other is JassElseIfCustomScriptAction elseIf - && Condition.Equals(elseIf.Condition); - } - - public override string ToString() => $"{JassKeyword.ElseIf} {Condition} {JassKeyword.Then}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptyParameterListSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptyParameterListSyntax.cs new file mode 100644 index 00000000..9d86eb93 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptyParameterListSyntax.cs @@ -0,0 +1,99 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassEmptyParameterListSyntax : JassParameterListOrEmptyParameterListSyntax + { + public static readonly JassEmptyParameterListSyntax Value = new( + new JassSyntaxToken(JassSyntaxKind.TakesKeyword, JassKeyword.Takes, JassSyntaxTriviaList.SingleSpace), + new JassSyntaxToken(JassSyntaxKind.NothingKeyword, JassKeyword.Nothing, JassSyntaxTriviaList.SingleSpace)); + + internal JassEmptyParameterListSyntax( + JassSyntaxToken takesToken, + JassSyntaxToken nothingToken) + { + TakesToken = takesToken; + NothingToken = nothingToken; + } + + public JassSyntaxToken TakesToken { get; } + + public JassSyntaxToken NothingToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.EmptyParameterList; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassEmptyParameterListSyntax; + } + + public override void WriteTo(TextWriter writer) + { + TakesToken.WriteTo(writer); + NothingToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield break; + } + + public override IEnumerable GetChildTokens() + { + yield return TakesToken; + yield return NothingToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return TakesToken; + yield return NothingToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield break; + } + + public override IEnumerable GetDescendantTokens() + { + yield return TakesToken; + yield return NothingToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return TakesToken; + yield return NothingToken; + } + + public override string ToString() => $"{TakesToken} {NothingToken}"; + + public override JassSyntaxToken GetFirstToken() => TakesToken; + + public override JassSyntaxToken GetLastToken() => NothingToken; + + protected internal override JassEmptyParameterListSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassEmptyParameterListSyntax( + newToken, + NothingToken); + } + + protected internal override JassEmptyParameterListSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassEmptyParameterListSyntax( + TakesToken, + newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptySyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptySyntax.cs deleted file mode 100644 index 5b13cec4..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEmptySyntax.cs +++ /dev/null @@ -1,38 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassEmptySyntax : ITopLevelDeclarationSyntax, IScopedDeclarationSyntax, IGlobalDeclarationSyntax, IScopedGlobalDeclarationSyntax, IMemberDeclarationSyntax, IStatementSyntax, IDeclarationLineSyntax, IGlobalLineSyntax, IStatementLineSyntax - { - public static readonly JassEmptySyntax Value = new JassEmptySyntax(); - - private JassEmptySyntax() - { - } - - public bool Equals(ITopLevelDeclarationSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IScopedDeclarationSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IGlobalDeclarationSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IScopedGlobalDeclarationSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IMemberDeclarationSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IStatementSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IDeclarationLineSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IGlobalLineSyntax? other) => other is JassEmptySyntax; - - public bool Equals(IStatementLineSyntax? other) => other is JassEmptySyntax; - - public override string ToString() => string.Empty; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndFunctionCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndFunctionCustomScriptAction.cs deleted file mode 100644 index b5ddffec..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndFunctionCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassEndFunctionCustomScriptAction : IStatementLineSyntax - { - public static readonly JassEndFunctionCustomScriptAction Value = new JassEndFunctionCustomScriptAction(); - - private JassEndFunctionCustomScriptAction() - { - } - - public bool Equals(IStatementLineSyntax? other) => other is JassEndFunctionCustomScriptAction; - - public override string ToString() => JassKeyword.EndFunction; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndGlobalsCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndGlobalsCustomScriptAction.cs deleted file mode 100644 index dbf1de22..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndGlobalsCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassEndGlobalsCustomScriptAction : IGlobalLineSyntax - { - public static readonly JassEndGlobalsCustomScriptAction Value = new JassEndGlobalsCustomScriptAction(); - - private JassEndGlobalsCustomScriptAction() - { - } - - public bool Equals(IGlobalLineSyntax? other) => other is JassEndGlobalsCustomScriptAction; - - public override string ToString() => JassKeyword.EndGlobals; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndIfCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndIfCustomScriptAction.cs deleted file mode 100644 index c27ed66c..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndIfCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassEndIfCustomScriptAction : IStatementLineSyntax - { - public static readonly JassEndIfCustomScriptAction Value = new JassEndIfCustomScriptAction(); - - private JassEndIfCustomScriptAction() - { - } - - public bool Equals(IStatementLineSyntax? other) => other is JassEndIfCustomScriptAction; - - public override string ToString() => JassKeyword.EndIf; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndLoopCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndLoopCustomScriptAction.cs deleted file mode 100644 index 4c293da2..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEndLoopCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassEndLoopCustomScriptAction : IStatementLineSyntax - { - public static readonly JassEndLoopCustomScriptAction Value = new JassEndLoopCustomScriptAction(); - - private JassEndLoopCustomScriptAction() - { - } - - public bool Equals(IStatementLineSyntax? other) => other is JassEndLoopCustomScriptAction; - - public override string ToString() => JassKeyword.EndLoop; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEqualsValueClauseSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEqualsValueClauseSyntax.cs index 5601ff8c..90dd4960 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassEqualsValueClauseSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassEqualsValueClauseSyntax.cs @@ -5,25 +5,104 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassEqualsValueClauseSyntax : IEquatable + public class JassEqualsValueClauseSyntax : JassSyntaxNode { - public JassEqualsValueClauseSyntax(IExpressionSyntax expression) + internal JassEqualsValueClauseSyntax( + JassSyntaxToken equalsToken, + JassExpressionSyntax expression) { + EqualsToken = equalsToken; Expression = expression; } - public IExpressionSyntax Expression { get; init; } + public JassSyntaxToken EqualsToken { get; } - public bool Equals(JassEqualsValueClauseSyntax? other) + public JassExpressionSyntax Expression { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.EqualsValueClause; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassEqualsValueClauseSyntax equalsValueClause + && Expression.IsEquivalentTo(equalsValueClause.Expression); + } + + public override void WriteTo(TextWriter writer) + { + EqualsToken.WriteTo(writer); + Expression.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Expression; + } + + public override IEnumerable GetChildTokens() + { + yield return EqualsToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return EqualsToken; + yield return Expression; + } + + public override IEnumerable GetDescendantNodes() { - return other is not null - && Expression.Equals(other.Expression); + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{JassSymbol.EqualsSign} {Expression}"; + public override IEnumerable GetDescendantTokens() + { + yield return EqualsToken; + + foreach (var descendant in Expression.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return EqualsToken; + + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{EqualsToken} {Expression}"; + + public override JassSyntaxToken GetFirstToken() => EqualsToken; + + public override JassSyntaxToken GetLastToken() => Expression.GetLastToken(); + + protected internal override JassEqualsValueClauseSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassEqualsValueClauseSyntax( + newToken, + Expression); + } + + protected internal override JassEqualsValueClauseSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassEqualsValueClauseSyntax( + EqualsToken, + Expression.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassExitStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassExitStatementSyntax.cs index 0ce16e9f..9b78fbd4 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassExitStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassExitStatementSyntax.cs @@ -5,29 +5,104 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassExitStatementSyntax : IStatementSyntax, IStatementLineSyntax + public class JassExitStatementSyntax : JassStatementSyntax { - public JassExitStatementSyntax(IExpressionSyntax condition) + internal JassExitStatementSyntax( + JassSyntaxToken exitWhenToken, + JassExpressionSyntax condition) { + ExitWhenToken = exitWhenToken; Condition = condition; } - public IExpressionSyntax Condition { get; init; } + public JassSyntaxToken ExitWhenToken { get; } + + public JassExpressionSyntax Condition { get; } - public bool Equals(IStatementSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ExitStatement; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassExitStatementSyntax exitStatement - && Condition.Equals(exitStatement.Condition); + && Condition.IsEquivalentTo(exitStatement.Condition); } - public bool Equals(IStatementLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassExitStatementSyntax exitStatement - && Condition.Equals(exitStatement.Condition); + ExitWhenToken.WriteTo(writer); + Condition.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Condition; + } + + public override IEnumerable GetChildTokens() + { + yield return ExitWhenToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return ExitWhenToken; + yield return Condition; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Condition; + foreach (var descendant in Condition.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.ExitWhen} {Condition}"; + public override IEnumerable GetDescendantTokens() + { + yield return ExitWhenToken; + + foreach (var descendant in Condition.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return ExitWhenToken; + + yield return Condition; + foreach (var descendant in Condition.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{ExitWhenToken} {Condition}"; + + public override JassSyntaxToken GetFirstToken() => ExitWhenToken; + + public override JassSyntaxToken GetLastToken() => Condition.GetLastToken(); + + protected internal override JassExitStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassExitStatementSyntax( + newToken, + Condition); + } + + protected internal override JassExitStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassExitStatementSyntax( + ExitWhenToken, + Condition.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassExpressionSyntax.cs new file mode 100644 index 00000000..c24943a9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassExpressionSyntax.cs @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public abstract class JassExpressionSyntax : JassSyntaxNode + { + protected internal override abstract JassExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken); + + protected internal override abstract JassExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFourCCLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFourCCLiteralExpressionSyntax.cs deleted file mode 100644 index 55031196..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFourCCLiteralExpressionSyntax.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Extensions; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassFourCCLiteralExpressionSyntax : IExpressionSyntax - { - public JassFourCCLiteralExpressionSyntax(int value) - { - Value = value; - } - - public int Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassFourCCLiteralExpressionSyntax fourCCLiteralExpression - && Value == fourCCLiteralExpression.Value; - } - - public override string ToString() => $"{JassSymbol.Apostrophe}{Value.ToJassRawcode()}{JassSymbol.Apostrophe}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionCustomScriptAction.cs deleted file mode 100644 index 139210ee..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionCustomScriptAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassFunctionCustomScriptAction : IDeclarationLineSyntax - { - public JassFunctionCustomScriptAction(JassFunctionDeclaratorSyntax functionDeclarator) - { - FunctionDeclarator = functionDeclarator; - } - - public JassFunctionDeclaratorSyntax FunctionDeclarator { get; init; } - - public bool Equals(IDeclarationLineSyntax? other) - { - return other is JassFunctionCustomScriptAction function - && FunctionDeclarator.Equals(function.FunctionDeclarator); - } - - public override string ToString() => $"{JassKeyword.Function} {FunctionDeclarator}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclarationSyntax.cs index a0f9a8e7..b00c1a2b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclarationSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclarationSyntax.cs @@ -5,27 +5,141 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassFunctionDeclarationSyntax : ITopLevelDeclarationSyntax + public class JassFunctionDeclarationSyntax : JassTopLevelDeclarationSyntax { - public JassFunctionDeclarationSyntax(JassFunctionDeclaratorSyntax functionDeclarator, JassStatementListSyntax body) + internal JassFunctionDeclarationSyntax( + JassFunctionDeclaratorSyntax functionDeclarator, + ImmutableArray statements, + JassSyntaxToken endFunctionToken) { FunctionDeclarator = functionDeclarator; - Body = body; + Statements = statements; + EndFunctionToken = endFunctionToken; } - public JassFunctionDeclaratorSyntax FunctionDeclarator { get; init; } + public JassFunctionDeclaratorSyntax FunctionDeclarator { get; } + + public ImmutableArray Statements { get; } - public JassStatementListSyntax Body { get; init; } + public JassSyntaxToken EndFunctionToken { get; } - public bool Equals(ITopLevelDeclarationSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.FunctionDeclaration; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassFunctionDeclarationSyntax functionDeclaration - && FunctionDeclarator.Equals(functionDeclaration.FunctionDeclarator) - && Body.Equals(functionDeclaration.Body); + && FunctionDeclarator.IsEquivalentTo(functionDeclaration.FunctionDeclarator) + && Statements.IsEquivalentTo(functionDeclaration.Statements); + } + + public override void WriteTo(TextWriter writer) + { + FunctionDeclarator.WriteTo(writer); + Statements.WriteTo(writer); + EndFunctionToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return FunctionDeclarator; + + foreach (var child in Statements) + { + yield return child; + } } - public override string ToString() => $"{FunctionDeclarator} [{Body.Statements.Length}]"; + public override IEnumerable GetChildTokens() + { + yield return EndFunctionToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return FunctionDeclarator; + + foreach (var child in Statements) + { + yield return child; + } + + yield return EndFunctionToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield return FunctionDeclarator; + foreach (var descendant in FunctionDeclarator.GetDescendantNodes()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in FunctionDeclarator.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantTokens()) + { + yield return descendant; + } + + yield return EndFunctionToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return FunctionDeclarator; + foreach (var descendant in FunctionDeclarator.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return EndFunctionToken; + } + + public override string ToString() => $"{FunctionDeclarator} [...]"; + + public override JassSyntaxToken GetFirstToken() => FunctionDeclarator.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => EndFunctionToken; + + protected internal override JassFunctionDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassFunctionDeclarationSyntax( + FunctionDeclarator.ReplaceFirstToken(newToken), + Statements, + EndFunctionToken); + } + + protected internal override JassFunctionDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassFunctionDeclarationSyntax( + FunctionDeclarator, + Statements, + newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclaratorSyntax.cs index 4abf03fa..d9abc2a0 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclaratorSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionDeclaratorSyntax.cs @@ -5,33 +5,198 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassFunctionDeclaratorSyntax : IEquatable + public class JassFunctionDeclaratorSyntax : JassSyntaxNode { - public JassFunctionDeclaratorSyntax(JassIdentifierNameSyntax identifierName, JassParameterListSyntax parameterList, JassTypeSyntax returnType) + internal JassFunctionDeclaratorSyntax( + JassSyntaxToken? constantToken, + JassSyntaxToken functionToken, + JassIdentifierNameSyntax identifierName, + JassParameterListOrEmptyParameterListSyntax parameterList, + JassReturnClauseSyntax returnClause) { + ConstantToken = constantToken; + FunctionToken = functionToken; IdentifierName = identifierName; ParameterList = parameterList; - ReturnType = returnType; + ReturnClause = returnClause; + } + + public JassSyntaxToken? ConstantToken { get; } + + public JassSyntaxToken FunctionToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassParameterListOrEmptyParameterListSyntax ParameterList { get; } + + public JassReturnClauseSyntax ReturnClause { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.FunctionDeclarator; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassFunctionDeclaratorSyntax functionDeclarator + && ConstantToken.NullableEquals(functionDeclarator.ConstantToken) + && IdentifierName.IsEquivalentTo(functionDeclarator.IdentifierName) + && ParameterList.IsEquivalentTo(functionDeclarator.ParameterList) + && ReturnClause.IsEquivalentTo(functionDeclarator.ReturnClause); + } + + public override void WriteTo(TextWriter writer) + { + ConstantToken?.WriteTo(writer); + FunctionToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + ParameterList.WriteTo(writer); + ReturnClause.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + yield return ParameterList; + yield return ReturnClause; + } + + public override IEnumerable GetChildTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return FunctionToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return FunctionToken; + yield return IdentifierName; + yield return ParameterList; + yield return ReturnClause; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } - public JassParameterListSyntax ParameterList { get; init; } + yield return ParameterList; + foreach (var descendant in ParameterList.GetDescendantNodes()) + { + yield return descendant; + } - public JassTypeSyntax ReturnType { get; init; } + yield return ReturnClause; + foreach (var descendant in ReturnClause.GetDescendantNodes()) + { + yield return descendant; + } + } - public bool Equals(JassFunctionDeclaratorSyntax? other) + public override IEnumerable GetDescendantTokens() { - return other is not null - && IdentifierName.Equals(other.IdentifierName) - && ParameterList.Equals(other.ParameterList) - && ReturnType.Equals(other.ReturnType); + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return FunctionToken; + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ParameterList.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ReturnClause.GetDescendantTokens()) + { + yield return descendant; + } } - public override string ToString() => $"{IdentifierName} {JassKeyword.Takes} {ParameterList} {JassKeyword.Returns} {ReturnType}"; + public override IEnumerable GetDescendantNodesAndTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return FunctionToken; + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ParameterList; + foreach (var descendant in ParameterList.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ReturnClause; + foreach (var descendant in ReturnClause.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{ConstantToken.OptionalSuffixed()}{FunctionToken} {IdentifierName} {ParameterList} {ReturnClause}"; + + public override JassSyntaxToken GetFirstToken() => ConstantToken ?? FunctionToken; + + public override JassSyntaxToken GetLastToken() => ReturnClause.GetLastToken(); + + protected internal override JassFunctionDeclaratorSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + if (ConstantToken is not null) + { + return new JassFunctionDeclaratorSyntax( + newToken, + FunctionToken, + IdentifierName, + ParameterList, + ReturnClause); + } + + return new JassFunctionDeclaratorSyntax( + null, + newToken, + IdentifierName, + ParameterList, + ReturnClause); + } + + protected internal override JassFunctionDeclaratorSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassFunctionDeclaratorSyntax( + ConstantToken, + FunctionToken, + IdentifierName, + ParameterList, + ReturnClause.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionReferenceExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionReferenceExpressionSyntax.cs index 55104b34..87373a22 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionReferenceExpressionSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassFunctionReferenceExpressionSyntax.cs @@ -5,23 +5,104 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassFunctionReferenceExpressionSyntax : IExpressionSyntax + public class JassFunctionReferenceExpressionSyntax : JassExpressionSyntax { - public JassFunctionReferenceExpressionSyntax(JassIdentifierNameSyntax identifierName) + internal JassFunctionReferenceExpressionSyntax( + JassSyntaxToken functionToken, + JassIdentifierNameSyntax identifierName) { + FunctionToken = functionToken; IdentifierName = identifierName; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassSyntaxToken FunctionToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.FunctionReferenceExpression; - public bool Equals(IExpressionSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassFunctionReferenceExpressionSyntax functionReferenceExpression - && IdentifierName.Equals(functionReferenceExpression.IdentifierName); + && IdentifierName.IsEquivalentTo(functionReferenceExpression.IdentifierName); + } + + public override void WriteTo(TextWriter writer) + { + FunctionToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + } + + public override IEnumerable GetChildTokens() + { + yield return FunctionToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return FunctionToken; + yield return IdentifierName; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return FunctionToken; + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return FunctionToken; + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.Function} {IdentifierName}"; + public override string ToString() => $"{FunctionToken} {IdentifierName}"; + + public override JassSyntaxToken GetFirstToken() => FunctionToken; + + public override JassSyntaxToken GetLastToken() => IdentifierName.GetLastToken(); + + protected internal override JassFunctionReferenceExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassFunctionReferenceExpressionSyntax( + newToken, + IdentifierName); + } + + protected internal override JassFunctionReferenceExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassFunctionReferenceExpressionSyntax( + FunctionToken, + IdentifierName.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalConstantDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalConstantDeclarationSyntax.cs new file mode 100644 index 00000000..09644177 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalConstantDeclarationSyntax.cs @@ -0,0 +1,162 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassGlobalConstantDeclarationSyntax : JassGlobalDeclarationSyntax + { + internal JassGlobalConstantDeclarationSyntax( + JassSyntaxToken constantToken, + JassTypeSyntax type, + JassIdentifierNameSyntax identifierName, + JassEqualsValueClauseSyntax value) + { + ConstantToken = constantToken; + Type = type; + IdentifierName = identifierName; + Value = value; + } + + public JassSyntaxToken ConstantToken { get; } + + public JassTypeSyntax Type { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassEqualsValueClauseSyntax Value { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.GlobalConstantDeclaration; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassGlobalConstantDeclarationSyntax globalConstantDeclaration + && Type.IsEquivalentTo(globalConstantDeclaration.Type) + && IdentifierName.IsEquivalentTo(globalConstantDeclaration.IdentifierName) + && Value.IsEquivalentTo(globalConstantDeclaration.Value); + } + + public override void WriteTo(TextWriter writer) + { + ConstantToken.WriteTo(writer); + Type.WriteTo(writer); + IdentifierName.WriteTo(writer); + Value.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Type; + yield return IdentifierName; + yield return Value; + } + + public override IEnumerable GetChildTokens() + { + yield return ConstantToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return ConstantToken; + yield return Type; + yield return IdentifierName; + yield return Value; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Type; + foreach (var descendant in Type.GetDescendantNodes()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + yield return Value; + foreach (var descendant in Value.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return ConstantToken; + + foreach (var descendant in Type.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in Value.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return ConstantToken; + + yield return Type; + foreach (var descendant in Type.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return Value; + foreach (var descendant in Value.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{ConstantToken} {Type} {IdentifierName} {Value}"; + + public override JassSyntaxToken GetFirstToken() => ConstantToken; + + public override JassSyntaxToken GetLastToken() => Value.GetLastToken(); + + protected internal override JassGlobalConstantDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassGlobalConstantDeclarationSyntax( + newToken, + Type, + IdentifierName, + Value); + } + + protected internal override JassGlobalConstantDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassGlobalConstantDeclarationSyntax( + ConstantToken, + Type, + IdentifierName, + Value.ReplaceLastToken(newToken)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationListSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationListSyntax.cs deleted file mode 100644 index 3474a5ac..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationListSyntax.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Immutable; -using System.Linq; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassGlobalDeclarationListSyntax : ITopLevelDeclarationSyntax - { - public JassGlobalDeclarationListSyntax(ImmutableArray globals) - { - Globals = globals; - } - - public ImmutableArray Globals { get; init; } - - public bool Equals(ITopLevelDeclarationSyntax? other) - { - return other is JassGlobalDeclarationListSyntax globalDeclarationList - && Globals.SequenceEqual(globalDeclarationList.Globals); - } - - public override string ToString() => $"{JassKeyword.Globals} [{Globals.Length}]"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationSyntax.cs index 3d432e0b..249f6ba8 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalDeclarationSyntax.cs @@ -7,27 +7,10 @@ namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassGlobalDeclarationSyntax : IGlobalDeclarationSyntax, IGlobalLineSyntax + public abstract class JassGlobalDeclarationSyntax : JassSyntaxNode { - public JassGlobalDeclarationSyntax(IVariableDeclaratorSyntax declarator) - { - Declarator = declarator; - } + protected internal override abstract JassGlobalDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken); - public IVariableDeclaratorSyntax Declarator { get; init; } - - public bool Equals(IGlobalDeclarationSyntax? other) - { - return other is JassGlobalDeclarationSyntax globalDeclaration - && Declarator.Equals(globalDeclaration.Declarator); - } - - public bool Equals(IGlobalLineSyntax? other) - { - return other is JassGlobalDeclarationSyntax globalDeclaration - && Declarator.Equals(globalDeclaration.Declarator); - } - - public override string ToString() => Declarator.ToString(); + protected internal override abstract JassGlobalDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken); } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalVariableDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalVariableDeclarationSyntax.cs new file mode 100644 index 00000000..b185463e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalVariableDeclarationSyntax.cs @@ -0,0 +1,91 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassGlobalVariableDeclarationSyntax : JassGlobalDeclarationSyntax + { + internal JassGlobalVariableDeclarationSyntax( + JassVariableOrArrayDeclaratorSyntax declarator) + { + Declarator = declarator; + } + + public JassVariableOrArrayDeclaratorSyntax Declarator { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxFacts.GetGlobalDeclarationKind(Declarator.SyntaxKind); + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassGlobalVariableDeclarationSyntax globalVariableDeclaration + && Declarator.IsEquivalentTo(globalVariableDeclaration.Declarator); + } + + public override void WriteTo(TextWriter writer) + { + Declarator.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Declarator; + } + + public override IEnumerable GetChildTokens() + { + yield break; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Declarator; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Declarator; + foreach (var descendant in Declarator.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + return Declarator.GetDescendantTokens(); + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Declarator; + foreach (var descendant in Declarator.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => Declarator.ToString(); + + public override JassSyntaxToken GetFirstToken() => Declarator.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => Declarator.GetLastToken(); + + protected internal override JassGlobalVariableDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassGlobalVariableDeclarationSyntax(Declarator.ReplaceFirstToken(newToken)); + } + + protected internal override JassGlobalVariableDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassGlobalVariableDeclarationSyntax(Declarator.ReplaceLastToken(newToken)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsCustomScriptAction.cs deleted file mode 100644 index 1b4331ba..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassGlobalsCustomScriptAction : IDeclarationLineSyntax - { - public static readonly JassGlobalsCustomScriptAction Value = new JassGlobalsCustomScriptAction(); - - private JassGlobalsCustomScriptAction() - { - } - - public bool Equals(IDeclarationLineSyntax? other) => other is JassGlobalsCustomScriptAction; - - public override string ToString() => JassKeyword.Globals; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsDeclarationSyntax.cs new file mode 100644 index 00000000..5933385e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassGlobalsDeclarationSyntax.cs @@ -0,0 +1,124 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassGlobalsDeclarationSyntax : JassTopLevelDeclarationSyntax + { + internal JassGlobalsDeclarationSyntax( + JassSyntaxToken globalsToken, + ImmutableArray globalDeclarations, + JassSyntaxToken endGlobalsToken) + { + GlobalsToken = globalsToken; + GlobalDeclarations = globalDeclarations; + EndGlobalsToken = endGlobalsToken; + } + + public JassSyntaxToken GlobalsToken { get; } + + public ImmutableArray GlobalDeclarations { get; } + + public JassSyntaxToken EndGlobalsToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.GlobalsDeclaration; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassGlobalsDeclarationSyntax globalsDeclaration + && GlobalDeclarations.IsEquivalentTo(globalsDeclaration.GlobalDeclarations); + } + + public override void WriteTo(TextWriter writer) + { + GlobalsToken.WriteTo(writer); + GlobalDeclarations.WriteTo(writer); + EndGlobalsToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + return GlobalDeclarations; + } + + public override IEnumerable GetChildTokens() + { + yield return GlobalsToken; + yield return EndGlobalsToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return GlobalsToken; + + foreach (var child in GlobalDeclarations) + { + yield return child; + } + + yield return EndGlobalsToken; + } + + public override IEnumerable GetDescendantNodes() + { + return GlobalDeclarations.GetDescendantNodes(); + } + + public override IEnumerable GetDescendantTokens() + { + yield return GlobalsToken; + + foreach (var descendant in GlobalDeclarations.GetDescendantTokens()) + { + yield return descendant; + } + + yield return EndGlobalsToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return GlobalsToken; + + foreach (var descendant in GlobalDeclarations.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return EndGlobalsToken; + } + + public override string ToString() => $"{GlobalsToken} [...]"; + + public override JassSyntaxToken GetFirstToken() => GlobalsToken; + + public override JassSyntaxToken GetLastToken() => EndGlobalsToken; + + protected internal override JassGlobalsDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassGlobalsDeclarationSyntax( + newToken, + GlobalDeclarations, + EndGlobalsToken); + } + + protected internal override JassGlobalsDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassGlobalsDeclarationSyntax( + GlobalsToken, + GlobalDeclarations, + newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassHexadecimalLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassHexadecimalLiteralExpressionSyntax.cs deleted file mode 100644 index d3a88dab..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassHexadecimalLiteralExpressionSyntax.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassHexadecimalLiteralExpressionSyntax : IExpressionSyntax - { - public JassHexadecimalLiteralExpressionSyntax(int value) - { - Value = value; - } - - public int Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression - && Value == hexadecimalLiteralExpression.Value; - } - - public override string ToString() => $"{JassSymbol.Zero}{JassSymbol.X}" + Convert.ToString(Value, 16).ToUpperInvariant(); - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIdentifierNameSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIdentifierNameSyntax.cs index 8ca91e87..da06ba96 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIdentifierNameSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIdentifierNameSyntax.cs @@ -5,25 +5,79 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassIdentifierNameSyntax : IEquatable + public class JassIdentifierNameSyntax : JassTypeSyntax { - public JassIdentifierNameSyntax(string name) + internal JassIdentifierNameSyntax( + JassSyntaxToken token) { - Name = name; + Token = token; } - public string Name { get; init; } + public JassSyntaxToken Token { get; } - public virtual bool Equals(JassIdentifierNameSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.IdentifierName; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassIdentifierNameSyntax identifierName + && Token.IsEquivalentTo(identifierName.Token); + } + + public override void WriteTo(TextWriter writer) + { + Token.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield break; + } + + public override IEnumerable GetChildTokens() + { + yield return Token; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Token; + } + + public override IEnumerable GetDescendantNodes() + { + yield break; + } + + public override IEnumerable GetDescendantTokens() { - return other is not null - && string.Equals(Name, other.Name, StringComparison.Ordinal); + yield return Token; } - public override string ToString() => Name; + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Token; + } + + public override string ToString() => Token.ToString(); + + public override JassSyntaxToken GetFirstToken() => Token; + + public override JassSyntaxToken GetLastToken() => Token; + + protected internal override JassIdentifierNameSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassIdentifierNameSyntax(newToken); + } + + protected internal override JassIdentifierNameSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassIdentifierNameSyntax(newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseDeclaratorSyntax.cs new file mode 100644 index 00000000..73d815c7 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseDeclaratorSyntax.cs @@ -0,0 +1,121 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassIfClauseDeclaratorSyntax : JassSyntaxNode + { + internal JassIfClauseDeclaratorSyntax( + JassSyntaxToken ifToken, + JassExpressionSyntax condition, + JassSyntaxToken thenToken) + { + IfToken = ifToken; + Condition = condition; + ThenToken = thenToken; + } + + public JassSyntaxToken IfToken { get; } + + public JassExpressionSyntax Condition { get; } + + public JassSyntaxToken ThenToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.IfClauseDeclarator; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassIfClauseDeclaratorSyntax ifClauseDeclarator + && Condition.IsEquivalentTo(ifClauseDeclarator.Condition); + } + + public override void WriteTo(TextWriter writer) + { + IfToken.WriteTo(writer); + Condition.WriteTo(writer); + ThenToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Condition; + } + + public override IEnumerable GetChildTokens() + { + yield return IfToken; + yield return ThenToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return IfToken; + yield return Condition; + yield return ThenToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Condition; + foreach (var descendant in Condition.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return IfToken; + + foreach (var descendant in Condition.GetDescendantTokens()) + { + yield return descendant; + } + + yield return ThenToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return IfToken; + + yield return Condition; + foreach (var descendant in Condition.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ThenToken; + } + + public override string ToString() => $"{IfToken} {Condition} {ThenToken}"; + + public override JassSyntaxToken GetFirstToken() => IfToken; + + public override JassSyntaxToken GetLastToken() => ThenToken; + + protected internal override JassIfClauseDeclaratorSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassIfClauseDeclaratorSyntax( + newToken, + Condition, + ThenToken); + } + + protected internal override JassIfClauseDeclaratorSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassIfClauseDeclaratorSyntax( + IfToken, + Condition, + newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseSyntax.cs new file mode 100644 index 00000000..c27594a8 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfClauseSyntax.cs @@ -0,0 +1,137 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassIfClauseSyntax : JassSyntaxNode + { + internal JassIfClauseSyntax( + JassIfClauseDeclaratorSyntax ifClauseDeclarator, + ImmutableArray statements) + { + IfClauseDeclarator = ifClauseDeclarator; + Statements = statements; + } + + public JassIfClauseDeclaratorSyntax IfClauseDeclarator { get; } + + public ImmutableArray Statements { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.IfClause; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassIfClauseSyntax ifClause + && IfClauseDeclarator.IsEquivalentTo(ifClause.IfClauseDeclarator) + && Statements.IsEquivalentTo(ifClause.Statements); + } + + public override void WriteTo(TextWriter writer) + { + IfClauseDeclarator.WriteTo(writer); + Statements.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IfClauseDeclarator; + foreach (var child in Statements) + { + yield return child; + } + } + + public override IEnumerable GetChildTokens() + { + yield break; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return IfClauseDeclarator; + foreach (var child in Statements) + { + yield return child; + } + } + + public override IEnumerable GetDescendantNodes() + { + yield return IfClauseDeclarator; + foreach (var descendant in IfClauseDeclarator.GetDescendantNodes()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in IfClauseDeclarator.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return IfClauseDeclarator; + foreach (var descendant in IfClauseDeclarator.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + foreach (var descendant in Statements.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{IfClauseDeclarator} [...]"; + + public override JassSyntaxToken GetFirstToken() => IfClauseDeclarator.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => Statements.IsEmpty ? IfClauseDeclarator.GetLastToken() : Statements[^1].GetLastToken(); + + protected internal override JassIfClauseSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassIfClauseSyntax( + IfClauseDeclarator.ReplaceFirstToken(newToken), + Statements); + } + + protected internal override JassIfClauseSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + if (!Statements.IsEmpty) + { + return new JassIfClauseSyntax( + IfClauseDeclarator, + Statements.ReplaceLastItem(Statements[^1].ReplaceLastToken(newToken))); + } + + return new JassIfClauseSyntax( + IfClauseDeclarator.ReplaceLastToken(newToken), + Statements); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfCustomScriptAction.cs deleted file mode 100644 index a8e66c6d..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfCustomScriptAction.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassIfCustomScriptAction : IStatementLineSyntax - { - public JassIfCustomScriptAction(IExpressionSyntax condition) - { - Condition = condition; - } - - public IExpressionSyntax Condition { get; init; } - - public bool Equals(IStatementLineSyntax? other) - { - return other is JassIfCustomScriptAction @if - && Condition.Equals(@if.Condition); - } - - public override string ToString() => $"{JassKeyword.If} {Condition} {JassKeyword.Then}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfStatementSyntax.cs index 51aa2129..39ae4216 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassIfStatementSyntax.cs @@ -5,41 +5,185 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; +using System.Diagnostics.CodeAnalysis; +using System.IO; using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassIfStatementSyntax : IStatementSyntax + public class JassIfStatementSyntax : JassStatementSyntax { - public JassIfStatementSyntax(IExpressionSyntax condition, JassStatementListSyntax body, ImmutableArray elseIfClauses, JassElseClauseSyntax? elseClause) + internal JassIfStatementSyntax( + JassIfClauseSyntax ifClause, + ImmutableArray elseIfClauses, + JassElseClauseSyntax? elseClause, + JassSyntaxToken endIfToken) { - Condition = condition; - Body = body; + IfClause = ifClause; ElseIfClauses = elseIfClauses; ElseClause = elseClause; + EndIfToken = endIfToken; } - public IExpressionSyntax Condition { get; init; } + public JassIfClauseSyntax IfClause { get; } - public JassStatementListSyntax Body { get; init; } + public ImmutableArray ElseIfClauses { get; } - public ImmutableArray ElseIfClauses { get; init; } + public JassElseClauseSyntax? ElseClause { get; } - public JassElseClauseSyntax? ElseClause { get; init; } + public JassSyntaxToken EndIfToken { get; } - public bool Equals(IStatementSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.IfStatement; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassIfStatementSyntax ifStatement - && Condition.Equals(ifStatement.Condition) - && Body.Equals(ifStatement.Body) - && ElseIfClauses.SequenceEqual(ifStatement.ElseIfClauses) - && ElseClause.NullableEquals(ifStatement.ElseClause); + && IfClause.IsEquivalentTo(ifStatement.IfClause) + && ElseIfClauses.IsEquivalentTo(ifStatement.ElseIfClauses) + && ElseClause.NullableEquivalentTo(ifStatement.ElseClause); + } + + public override void WriteTo(TextWriter writer) + { + IfClause.WriteTo(writer); + ElseIfClauses.WriteTo(writer); + ElseClause?.WriteTo(writer); + EndIfToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IfClause; + + foreach (var child in ElseIfClauses) + { + yield return child; + } + + if (ElseClause is not null) + { + yield return ElseClause; + } + } + + public override IEnumerable GetChildTokens() + { + yield return EndIfToken; } - public override string ToString() => $"{JassKeyword.If} {Condition} {JassKeyword.Then} [{Body.Statements.Length}]"; + public override IEnumerable GetChildNodesAndTokens() + { + yield return IfClause; + + foreach (var child in ElseIfClauses) + { + yield return child; + } + + if (ElseClause is not null) + { + yield return ElseClause; + } + + yield return EndIfToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IfClause; + foreach (var descendant in IfClause.GetDescendantNodes()) + { + yield return descendant; + } + + foreach (var descendant in ElseIfClauses.GetDescendantNodes()) + { + yield return descendant; + } + + if (ElseClause is not null) + { + yield return ElseClause; + foreach (var descendant in ElseClause.GetDescendantNodes()) + { + yield return descendant; + } + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in IfClause.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ElseIfClauses.GetDescendantTokens()) + { + yield return descendant; + } + + if (ElseClause is not null) + { + foreach (var descendant in ElseClause.GetDescendantTokens()) + { + yield return descendant; + } + } + + yield return EndIfToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return IfClause; + foreach (var descendant in IfClause.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + foreach (var descendant in ElseIfClauses.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + if (ElseClause is not null) + { + yield return ElseClause; + foreach (var descendant in ElseClause.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + yield return EndIfToken; + } + + public override string ToString() => IfClause.ToString(); + + public override JassSyntaxToken GetFirstToken() => IfClause.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => EndIfToken; + + protected internal override JassIfStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassIfStatementSyntax( + IfClause.ReplaceFirstToken(newToken), + ElseIfClauses, + ElseClause, + EndIfToken); + } + + protected internal override JassIfStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassIfStatementSyntax( + IfClause, + ElseIfClauses, + ElseClause, + newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassInvocationExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassInvocationExpressionSyntax.cs index 8b6d1c91..7bde353e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassInvocationExpressionSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassInvocationExpressionSyntax.cs @@ -5,27 +5,119 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassInvocationExpressionSyntax : IExpressionSyntax, IInvocationSyntax + public class JassInvocationExpressionSyntax : JassExpressionSyntax { - public JassInvocationExpressionSyntax(JassIdentifierNameSyntax identifierName, JassArgumentListSyntax arguments) + internal JassInvocationExpressionSyntax( + JassIdentifierNameSyntax identifierName, + JassArgumentListSyntax argumentList) { IdentifierName = identifierName; - Arguments = arguments; + ArgumentList = argumentList; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassArgumentListSyntax ArgumentList { get; } - public JassArgumentListSyntax Arguments { get; init; } + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.InvocationExpression; - public bool Equals(IExpressionSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassInvocationExpressionSyntax invocationExpression - && IdentifierName.Equals(invocationExpression.IdentifierName) - && Arguments.Equals(invocationExpression.Arguments); + && IdentifierName.IsEquivalentTo(invocationExpression.IdentifierName) + && ArgumentList.IsEquivalentTo(invocationExpression.ArgumentList); + } + + public override void WriteTo(TextWriter writer) + { + IdentifierName.WriteTo(writer); + ArgumentList.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + yield return ArgumentList; + } + + public override IEnumerable GetChildTokens() + { + yield break; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return IdentifierName; + yield return ArgumentList; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + yield return ArgumentList; + foreach (var descendant in ArgumentList.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ArgumentList.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ArgumentList; + foreach (var descendant in ArgumentList.GetDescendantNodesAndTokens()) + { + yield return descendant; + } } - public override string ToString() => $"{IdentifierName}{JassSymbol.LeftParenthesis}{Arguments}{JassSymbol.RightParenthesis}"; + public override string ToString() => $"{IdentifierName}{ArgumentList}"; + + public override JassSyntaxToken GetFirstToken() => IdentifierName.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => ArgumentList.GetLastToken(); + + protected internal override JassInvocationExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassInvocationExpressionSyntax( + IdentifierName.ReplaceFirstToken(newToken), + ArgumentList); + } + + protected internal override JassInvocationExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassInvocationExpressionSyntax( + IdentifierName, + ArgumentList.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLiteralExpressionSyntax.cs new file mode 100644 index 00000000..eb043296 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLiteralExpressionSyntax.cs @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassLiteralExpressionSyntax : JassExpressionSyntax + { + internal JassLiteralExpressionSyntax( + JassSyntaxToken token) + { + Token = token; + } + + public JassSyntaxToken Token { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxFacts.GetLiteralExpressionKind(Token.SyntaxKind); + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassLiteralExpressionSyntax literalExpression + && Token.IsEquivalentTo(literalExpression.Token); + } + + public override void WriteTo(TextWriter writer) + { + Token.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield break; + } + + public override IEnumerable GetChildTokens() + { + yield return Token; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Token; + } + + public override IEnumerable GetDescendantNodes() + { + yield break; + } + + public override IEnumerable GetDescendantTokens() + { + yield return Token; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Token; + } + + public override string ToString() => Token.ToString(); + + public override JassSyntaxToken GetFirstToken() => Token; + + public override JassSyntaxToken GetLastToken() => Token; + + protected internal override JassLiteralExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassLiteralExpressionSyntax(newToken); + } + + protected internal override JassLiteralExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassLiteralExpressionSyntax(newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLocalVariableDeclarationStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLocalVariableDeclarationStatementSyntax.cs index ea62a8d3..71ef3738 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLocalVariableDeclarationStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLocalVariableDeclarationStatementSyntax.cs @@ -5,29 +5,104 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassLocalVariableDeclarationStatementSyntax : IStatementSyntax, IStatementLineSyntax + public class JassLocalVariableDeclarationStatementSyntax : JassStatementSyntax { - public JassLocalVariableDeclarationStatementSyntax(IVariableDeclaratorSyntax declarator) + internal JassLocalVariableDeclarationStatementSyntax( + JassSyntaxToken localToken, + JassVariableOrArrayDeclaratorSyntax declarator) { + LocalToken = localToken; Declarator = declarator; } - public IVariableDeclaratorSyntax Declarator { get; init; } + public JassSyntaxToken LocalToken { get; } + + public JassVariableOrArrayDeclaratorSyntax Declarator { get; } - public bool Equals(IStatementSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxFacts.GetLocalDeclarationStatementKind(Declarator.SyntaxKind); + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement - && Declarator.Equals(localVariableDeclarationStatement.Declarator); + && Declarator.IsEquivalentTo(localVariableDeclarationStatement.Declarator); } - public bool Equals(IStatementLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement - && Declarator.Equals(localVariableDeclarationStatement.Declarator); + LocalToken.WriteTo(writer); + Declarator.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Declarator; + } + + public override IEnumerable GetChildTokens() + { + yield return LocalToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return LocalToken; + yield return Declarator; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Declarator; + foreach (var descendant in Declarator.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.Local} {Declarator}"; + public override IEnumerable GetDescendantTokens() + { + yield return LocalToken; + + foreach (var descendant in Declarator.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return LocalToken; + + yield return Declarator; + foreach (var descendant in Declarator.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{LocalToken} {Declarator}"; + + public override JassSyntaxToken GetFirstToken() => LocalToken; + + public override JassSyntaxToken GetLastToken() => Declarator.GetLastToken(); + + protected internal override JassLocalVariableDeclarationStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassLocalVariableDeclarationStatementSyntax( + newToken, + Declarator); + } + + protected internal override JassLocalVariableDeclarationStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassLocalVariableDeclarationStatementSyntax( + LocalToken, + Declarator.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopCustomScriptAction.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopCustomScriptAction.cs deleted file mode 100644 index 8b621a3b..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopCustomScriptAction.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassLoopCustomScriptAction : IStatementLineSyntax - { - public static readonly JassLoopCustomScriptAction Value = new JassLoopCustomScriptAction(); - - private JassLoopCustomScriptAction() - { - } - - public bool Equals(IStatementLineSyntax? other) => other is JassLoopCustomScriptAction; - - public override string ToString() => JassKeyword.Loop; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopStatementSyntax.cs index b07bcc1e..6b471f86 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassLoopStatementSyntax.cs @@ -5,23 +5,120 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassLoopStatementSyntax : IStatementSyntax + public class JassLoopStatementSyntax : JassStatementSyntax { - public JassLoopStatementSyntax(JassStatementListSyntax body) + internal JassLoopStatementSyntax( + JassSyntaxToken loopToken, + ImmutableArray statements, + JassSyntaxToken endLoopToken) { - Body = body; + LoopToken = loopToken; + Statements = statements; + EndLoopToken = endLoopToken; } - public JassStatementListSyntax Body { get; init; } + public JassSyntaxToken LoopToken { get; } + + public ImmutableArray Statements { get; } + + public JassSyntaxToken EndLoopToken { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.LoopStatement; - public bool Equals(IStatementSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassLoopStatementSyntax loopStatement - && Body.Equals(loopStatement.Body); + && Statements.IsEquivalentTo(loopStatement.Statements); + } + + public override void WriteTo(TextWriter writer) + { + LoopToken.WriteTo(writer); + Statements.WriteTo(writer); + EndLoopToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + return Statements; + } + + public override IEnumerable GetChildTokens() + { + yield return LoopToken; + yield return EndLoopToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return LoopToken; + + foreach (var child in Statements) + { + yield return child; + } + + yield return EndLoopToken; + } + + public override IEnumerable GetDescendantNodes() + { + return Statements.GetDescendantNodes(); + } + + public override IEnumerable GetDescendantTokens() + { + yield return LoopToken; + + foreach (var descendant in Statements.GetDescendantTokens()) + { + yield return descendant; + } + + yield return EndLoopToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return LoopToken; + + foreach (var descendant in Statements.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return EndLoopToken; + } + + public override string ToString() => $"{LoopToken} [...]"; + + public override JassSyntaxToken GetFirstToken() => LoopToken; + + public override JassSyntaxToken GetLastToken() => EndLoopToken; + + protected internal override JassLoopStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassLoopStatementSyntax( + newToken, + Statements, + EndLoopToken); } - public override string ToString() => $"{JassKeyword.Loop} [{Body.Statements.Length}]"; + protected internal override JassLoopStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassLoopStatementSyntax( + LoopToken, + Statements, + newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassNativeFunctionDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassNativeFunctionDeclarationSyntax.cs index fa2ed743..1dcc5f26 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassNativeFunctionDeclarationSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassNativeFunctionDeclarationSyntax.cs @@ -5,29 +5,198 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassNativeFunctionDeclarationSyntax : ITopLevelDeclarationSyntax, IDeclarationLineSyntax + public class JassNativeFunctionDeclarationSyntax : JassTopLevelDeclarationSyntax { - public JassNativeFunctionDeclarationSyntax(JassFunctionDeclaratorSyntax functionDeclarator) + internal JassNativeFunctionDeclarationSyntax( + JassSyntaxToken? constantToken, + JassSyntaxToken nativeToken, + JassIdentifierNameSyntax identifierName, + JassParameterListOrEmptyParameterListSyntax parameterList, + JassReturnClauseSyntax returnClause) { - FunctionDeclarator = functionDeclarator; + ConstantToken = constantToken; + NativeToken = nativeToken; + IdentifierName = identifierName; + ParameterList = parameterList; + ReturnClause = returnClause; } - public JassFunctionDeclaratorSyntax FunctionDeclarator { get; init; } + public JassSyntaxToken? ConstantToken { get; } + + public JassSyntaxToken NativeToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassParameterListOrEmptyParameterListSyntax ParameterList { get; } + + public JassReturnClauseSyntax ReturnClause { get; } - public bool Equals(ITopLevelDeclarationSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.NativeFunctionDeclaration; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration - && FunctionDeclarator.Equals(nativeFunctionDeclaration.FunctionDeclarator); + && ConstantToken.NullableEquals(nativeFunctionDeclaration.ConstantToken) + && IdentifierName.IsEquivalentTo(nativeFunctionDeclaration.IdentifierName) + && ParameterList.IsEquivalentTo(nativeFunctionDeclaration.ParameterList) + && ReturnClause.IsEquivalentTo(nativeFunctionDeclaration.ReturnClause); } - public bool Equals(IDeclarationLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration - && FunctionDeclarator.Equals(nativeFunctionDeclaration.FunctionDeclarator); + ConstantToken?.WriteTo(writer); + NativeToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + ParameterList.WriteTo(writer); + ReturnClause.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + yield return ParameterList; + yield return ReturnClause; + } + + public override IEnumerable GetChildTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return NativeToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return NativeToken; + yield return IdentifierName; + yield return ParameterList; + yield return ReturnClause; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + yield return ParameterList; + foreach (var descendant in ParameterList.GetDescendantNodes()) + { + yield return descendant; + } + + yield return ReturnClause; + foreach (var descendant in ReturnClause.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.Native} {FunctionDeclarator}"; + public override IEnumerable GetDescendantTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return NativeToken; + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ParameterList.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in ReturnClause.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + if (ConstantToken is not null) + { + yield return ConstantToken; + } + + yield return NativeToken; + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ParameterList; + foreach (var descendant in ParameterList.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ReturnClause; + foreach (var descendant in ReturnClause.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{ConstantToken.OptionalSuffixed()}{NativeToken} {IdentifierName} {ParameterList} {ReturnClause}"; + + public override JassSyntaxToken GetFirstToken() => ConstantToken ?? NativeToken; + + public override JassSyntaxToken GetLastToken() => ReturnClause.GetLastToken(); + + protected internal override JassNativeFunctionDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + if (ConstantToken is not null) + { + return new JassNativeFunctionDeclarationSyntax( + newToken, + NativeToken, + IdentifierName, + ParameterList, + ReturnClause); + } + + return new JassNativeFunctionDeclarationSyntax( + null, + newToken, + IdentifierName, + ParameterList, + ReturnClause); + } + + protected internal override JassNativeFunctionDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassNativeFunctionDeclarationSyntax( + ConstantToken, + NativeToken, + IdentifierName, + ParameterList, + ReturnClause.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassNullLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassNullLiteralExpressionSyntax.cs deleted file mode 100644 index d130e7ee..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassNullLiteralExpressionSyntax.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassNullLiteralExpressionSyntax : IExpressionSyntax - { - public static readonly JassNullLiteralExpressionSyntax Value = new JassNullLiteralExpressionSyntax(); - - private JassNullLiteralExpressionSyntax() - { - } - - public bool Equals(IExpressionSyntax? other) => other is JassNullLiteralExpressionSyntax; - - public override string ToString() => JassKeyword.Null; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassOctalLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassOctalLiteralExpressionSyntax.cs deleted file mode 100644 index e2f2630f..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassOctalLiteralExpressionSyntax.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassOctalLiteralExpressionSyntax : IExpressionSyntax - { - public JassOctalLiteralExpressionSyntax(int value) - { - Value = value; - } - - public int Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassOctalLiteralExpressionSyntax octalLiteralExpression - && Value == octalLiteralExpression.Value; - } - - public override string ToString() => Value == 0 ? $"{JassSymbol.Zero}" : $"{JassSymbol.Zero}{Convert.ToString(Value, 8)}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListOrEmptyParameterListSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListOrEmptyParameterListSyntax.cs new file mode 100644 index 00000000..0c109518 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListOrEmptyParameterListSyntax.cs @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public abstract class JassParameterListOrEmptyParameterListSyntax : JassSyntaxNode + { + protected internal override abstract JassParameterListOrEmptyParameterListSyntax ReplaceFirstToken(JassSyntaxToken newToken); + + protected internal override abstract JassParameterListOrEmptyParameterListSyntax ReplaceLastToken(JassSyntaxToken newToken); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListSyntax.cs index 212b22d3..dd5a0f49 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterListSyntax.cs @@ -5,29 +5,110 @@ // // ------------------------------------------------------------------------------ -using System; -using System.Collections.Immutable; -using System.Linq; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassParameterListSyntax : IEquatable + public class JassParameterListSyntax : JassParameterListOrEmptyParameterListSyntax { - public static readonly JassParameterListSyntax Empty = new JassParameterListSyntax(ImmutableArray.Empty); + internal JassParameterListSyntax( + JassSyntaxToken takesToken, + SeparatedSyntaxList parameterList) + { + TakesToken = takesToken; + ParameterList = parameterList; + } + + public JassSyntaxToken TakesToken { get; } + + public SeparatedSyntaxList ParameterList { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ParameterList; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassParameterListSyntax parameterList + && ParameterList.IsEquivalentTo(parameterList.ParameterList); + } - public JassParameterListSyntax(ImmutableArray parameters) + public override void WriteTo(TextWriter writer) { - Parameters = parameters; + TakesToken.WriteTo(writer); + ParameterList.WriteTo(writer); } - public ImmutableArray Parameters { get; init; } + public override IEnumerable GetChildNodes() + { + return ParameterList.Items; + } - public bool Equals(JassParameterListSyntax? other) + public override IEnumerable GetChildTokens() { - return other is not null - && Parameters.SequenceEqual(other.Parameters); + yield return TakesToken; + + foreach (var child in ParameterList.Separators) + { + yield return child; + } } - public override string ToString() => Parameters.Any() ? string.Join($"{JassSymbol.Comma} ", Parameters) : JassKeyword.Nothing; + public override IEnumerable GetChildNodesAndTokens() + { + yield return TakesToken; + + foreach (var child in ParameterList.GetChildNodesAndTokens()) + { + yield return child; + } + } + + public override IEnumerable GetDescendantNodes() + { + return ParameterList.GetDescendantNodes(); + } + + public override IEnumerable GetDescendantTokens() + { + yield return TakesToken; + + foreach (var descendant in ParameterList.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return TakesToken; + + foreach (var descendant in ParameterList.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{TakesToken} {ParameterList}"; + + public override JassSyntaxToken GetFirstToken() => TakesToken; + + public override JassSyntaxToken GetLastToken() => ParameterList.Items[^1].GetLastToken(); + + protected internal override JassParameterListSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassParameterListSyntax( + newToken, + ParameterList); + } + + protected internal override JassParameterListSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassParameterListSyntax( + TakesToken, + ParameterList.ReplaceLastItem(ParameterList.Items[^1].ReplaceLastToken(newToken))); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterSyntax.cs index 054949d4..cd9db787 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParameterSyntax.cs @@ -5,29 +5,119 @@ // // ------------------------------------------------------------------------------ -using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassParameterSyntax : IEquatable + public class JassParameterSyntax : JassSyntaxNode { - public JassParameterSyntax(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + internal JassParameterSyntax( + JassTypeSyntax type, + JassIdentifierNameSyntax identifierName) { Type = type; IdentifierName = identifierName; } - public JassTypeSyntax Type { get; init; } + public JassTypeSyntax Type { get; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassIdentifierNameSyntax IdentifierName { get; } - public bool Equals(JassParameterSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.Parameter; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { - return other is not null - && Type.Equals(other.Type) - && IdentifierName.Equals(other.IdentifierName); + return other is JassParameterSyntax parameter + && Type.IsEquivalentTo(parameter.Type) + && IdentifierName.IsEquivalentTo(parameter.IdentifierName); + } + + public override void WriteTo(TextWriter writer) + { + Type.WriteTo(writer); + IdentifierName.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Type; + yield return IdentifierName; + } + + public override IEnumerable GetChildTokens() + { + yield break; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Type; + yield return IdentifierName; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Type; + foreach (var descendant in Type.GetDescendantNodes()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in Type.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Type; + foreach (var descendant in Type.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } } public override string ToString() => $"{Type} {IdentifierName}"; + + public override JassSyntaxToken GetFirstToken() => Type.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => IdentifierName.GetLastToken(); + + protected internal override JassParameterSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassParameterSyntax( + Type.ReplaceFirstToken(newToken), + IdentifierName); + } + + protected internal override JassParameterSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassParameterSyntax( + Type, + IdentifierName.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParenthesizedExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParenthesizedExpressionSyntax.cs index 3ea77c4b..651ba31e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassParenthesizedExpressionSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassParenthesizedExpressionSyntax.cs @@ -5,23 +5,117 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassParenthesizedExpressionSyntax : IExpressionSyntax + public class JassParenthesizedExpressionSyntax : JassExpressionSyntax { - public JassParenthesizedExpressionSyntax(IExpressionSyntax expression) + internal JassParenthesizedExpressionSyntax( + JassSyntaxToken openParenToken, + JassExpressionSyntax expression, + JassSyntaxToken closeParenToken) { + OpenParenToken = openParenToken; Expression = expression; + CloseParenToken = closeParenToken; } - public IExpressionSyntax Expression { get; init; } + public JassSyntaxToken OpenParenToken { get; } + + public JassExpressionSyntax Expression { get; } + + public JassSyntaxToken CloseParenToken { get; } - public bool Equals(IExpressionSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ParenthesizedExpression; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassParenthesizedExpressionSyntax parenthesizedExpression - && Expression.Equals(parenthesizedExpression.Expression); + && Expression.IsEquivalentTo(parenthesizedExpression.Expression); + } + + public override void WriteTo(TextWriter writer) + { + OpenParenToken.WriteTo(writer); + Expression.WriteTo(writer); + CloseParenToken.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Expression; + } + + public override IEnumerable GetChildTokens() + { + yield return OpenParenToken; + yield return CloseParenToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return OpenParenToken; + yield return Expression; + yield return CloseParenToken; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodes()) + { + yield return descendant; + } } - public override string ToString() => $"{JassSymbol.LeftParenthesis}{Expression}{JassSymbol.RightParenthesis}"; + public override IEnumerable GetDescendantTokens() + { + yield return OpenParenToken; + + foreach (var descendant in Expression.GetDescendantTokens()) + { + yield return descendant; + } + + yield return CloseParenToken; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return OpenParenToken; + + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return CloseParenToken; + } + + public override string ToString() => $"{OpenParenToken}{Expression}{CloseParenToken}"; + + public override JassSyntaxToken GetFirstToken() => OpenParenToken; + + public override JassSyntaxToken GetLastToken() => CloseParenToken; + + protected internal override JassParenthesizedExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassParenthesizedExpressionSyntax( + newToken, + Expression, + CloseParenToken); + } + + protected internal override JassParenthesizedExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassParenthesizedExpressionSyntax( + OpenParenToken, + Expression, + newToken); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassPredefinedTypeSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassPredefinedTypeSyntax.cs new file mode 100644 index 00000000..78d00ea5 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassPredefinedTypeSyntax.cs @@ -0,0 +1,91 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassPredefinedTypeSyntax : JassTypeSyntax + { + public static readonly JassPredefinedTypeSyntax Boolean = new(JassSyntaxFactory.Token(JassSyntaxKind.BooleanKeyword)); + public static readonly JassPredefinedTypeSyntax Code = new(JassSyntaxFactory.Token(JassSyntaxKind.CodeKeyword)); + public static readonly JassPredefinedTypeSyntax Handle = new(JassSyntaxFactory.Token(JassSyntaxKind.HandleKeyword)); + public static readonly JassPredefinedTypeSyntax Integer = new(JassSyntaxFactory.Token(JassSyntaxKind.IntegerKeyword)); + public static readonly JassPredefinedTypeSyntax Nothing = new(JassSyntaxFactory.Token(JassSyntaxKind.NothingKeyword)); + public static readonly JassPredefinedTypeSyntax Real = new(JassSyntaxFactory.Token(JassSyntaxKind.RealKeyword)); + public static readonly JassPredefinedTypeSyntax String = new(JassSyntaxFactory.Token(JassSyntaxKind.StringKeyword)); + + internal JassPredefinedTypeSyntax( + JassSyntaxToken token) + { + Token = token; + } + + public JassSyntaxToken Token { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.PredefinedType; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassPredefinedTypeSyntax predefinedType + && Token.IsEquivalentTo(predefinedType.Token); + } + + public override void WriteTo(TextWriter writer) + { + Token.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield break; + } + + public override IEnumerable GetChildTokens() + { + yield return Token; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Token; + } + + public override IEnumerable GetDescendantNodes() + { + yield break; + } + + public override IEnumerable GetDescendantTokens() + { + yield return Token; + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return Token; + } + + public override string ToString() => Token.ToString(); + + public override JassSyntaxToken GetFirstToken() => Token; + + public override JassSyntaxToken GetLastToken() => Token; + + protected internal override JassPredefinedTypeSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassPredefinedTypeSyntax(newToken); + } + + protected internal override JassPredefinedTypeSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassPredefinedTypeSyntax(newToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassRealLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassRealLiteralExpressionSyntax.cs deleted file mode 100644 index a16a06b0..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassRealLiteralExpressionSyntax.cs +++ /dev/null @@ -1,69 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; -using System.Globalization; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassRealLiteralExpressionSyntax : IExpressionSyntax - { -#if true - public JassRealLiteralExpressionSyntax(string intPart, string fracPart) - { - IntPart = intPart; - FracPart = fracPart; - } - - public string IntPart { get; init; } - - public string FracPart { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - if (other is JassRealLiteralExpressionSyntax realLiteralExpression && FracPart.Length == realLiteralExpression.FracPart.Length) - { - var left = float.Parse(ToString(), CultureInfo.InvariantCulture); - var right = float.Parse(realLiteralExpression.ToString(), CultureInfo.InvariantCulture); - - if (left == right) - { - return true; - } - - var difference = MathF.Abs(left - right); - var maxDifference = MathF.Pow(10, -FracPart.Length) * 1.01f; - return difference <= maxDifference; - } - - return false; - } - - public override string ToString() - { - return string.IsNullOrEmpty(FracPart) - ? $"{IntPart}{JassSymbol.FullStop}" - : $"{IntPart}{JassSymbol.FullStop}{FracPart}"; - } -#else - public JassRealLiteralExpressionSyntax(float value) - { - Value = value; - } - - public float Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassRealLiteralExpressionSyntax realLiteralExpression - && Value == realLiteralExpression.Value; - } - - public override string ToString() => Value.ToString(CultureInfo.InvariantCulture); -#endif - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnClauseSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnClauseSyntax.cs new file mode 100644 index 00000000..a330228d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnClauseSyntax.cs @@ -0,0 +1,108 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassReturnClauseSyntax : JassSyntaxNode + { + internal JassReturnClauseSyntax( + JassSyntaxToken returnsToken, + JassTypeSyntax returnType) + { + ReturnsToken = returnsToken; + ReturnType = returnType; + } + + public JassSyntaxToken ReturnsToken { get; } + + public JassTypeSyntax ReturnType { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ReturnClause; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) + { + return other is JassReturnClauseSyntax returnClause + && ReturnType.IsEquivalentTo(returnClause.ReturnType); + } + + public override void WriteTo(TextWriter writer) + { + ReturnsToken.WriteTo(writer); + ReturnType.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return ReturnType; + } + + public override IEnumerable GetChildTokens() + { + yield return ReturnsToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return ReturnsToken; + yield return ReturnType; + } + + public override IEnumerable GetDescendantNodes() + { + yield return ReturnType; + foreach (var descendant in ReturnType.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return ReturnsToken; + + foreach (var descendant in ReturnType.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return ReturnsToken; + + yield return ReturnType; + foreach (var descendant in ReturnType.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{ReturnsToken} {ReturnType}"; + + public override JassSyntaxToken GetFirstToken() => ReturnsToken; + + public override JassSyntaxToken GetLastToken() => ReturnType.GetLastToken(); + + protected internal override JassReturnClauseSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassReturnClauseSyntax( + newToken, + ReturnType); + } + + protected internal override JassReturnClauseSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassReturnClauseSyntax( + ReturnsToken, + ReturnType.ReplaceLastToken(newToken)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnStatementSyntax.cs index 4756f94f..7649a96a 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassReturnStatementSyntax.cs @@ -5,33 +5,133 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassReturnStatementSyntax : IStatementSyntax, IStatementLineSyntax + public class JassReturnStatementSyntax : JassStatementSyntax { - public static readonly JassReturnStatementSyntax Empty = new JassReturnStatementSyntax(null); + public static readonly JassReturnStatementSyntax Empty = new( + new JassSyntaxToken(JassSyntaxKind.ReturnKeyword, JassKeyword.Return, JassSyntaxTriviaList.Empty), + null); - public JassReturnStatementSyntax(IExpressionSyntax? value) + internal JassReturnStatementSyntax( + JassSyntaxToken returnToken, + JassExpressionSyntax? value) { + ReturnToken = returnToken; Value = value; } - public IExpressionSyntax? Value { get; init; } + public JassSyntaxToken ReturnToken { get; } + + public JassExpressionSyntax? Value { get; } + + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.ReturnStatement; - public bool Equals(IStatementSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassReturnStatementSyntax returnStatement - && Value.NullableEquals(returnStatement.Value); + && Value.NullableEquivalentTo(returnStatement.Value); } - public bool Equals(IStatementLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassReturnStatementSyntax returnStatement - && Value.NullableEquals(returnStatement.Value); + ReturnToken.WriteTo(writer); + Value?.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + if (Value is not null) + { + yield return Value; + } + } + + public override IEnumerable GetChildTokens() + { + yield return ReturnToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return ReturnToken; + + if (Value is not null) + { + yield return Value; + } + } + + public override IEnumerable GetDescendantNodes() + { + if (Value is not null) + { + yield return Value; + foreach (var descendant in Value.GetDescendantNodes()) + { + yield return descendant; + } + } } - public override string ToString() => Value is null ? JassKeyword.Return : $"{JassKeyword.Return} {Value}"; + public override IEnumerable GetDescendantTokens() + { + yield return ReturnToken; + + if (Value is not null) + { + foreach (var descendant in Value.GetDescendantTokens()) + { + yield return descendant; + } + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return ReturnToken; + + if (Value is not null) + { + yield return Value; + foreach (var descendant in Value.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + } + + public override string ToString() => $"{ReturnToken}{Value.OptionalPrefixed()}"; + + public override JassSyntaxToken GetFirstToken() => ReturnToken; + + public override JassSyntaxToken GetLastToken() => Value?.GetLastToken() ?? ReturnToken; + + protected internal override JassReturnStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassReturnStatementSyntax( + newToken, + Value); + } + + protected internal override JassReturnStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + if (Value is not null) + { + return new JassReturnStatementSyntax( + ReturnToken, + Value.ReplaceLastToken(newToken)); + } + + return new JassReturnStatementSyntax( + newToken, + null); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSetStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSetStatementSyntax.cs index 006dd56a..c466e80b 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSetStatementSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSetStatementSyntax.cs @@ -5,46 +5,179 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassSetStatementSyntax : IStatementSyntax, IStatementLineSyntax + public class JassSetStatementSyntax : JassStatementSyntax { - public JassSetStatementSyntax(JassIdentifierNameSyntax identifierName, IExpressionSyntax? indexer, JassEqualsValueClauseSyntax value) + internal JassSetStatementSyntax( + JassSyntaxToken setToken, + JassIdentifierNameSyntax identifierName, + JassElementAccessClauseSyntax? elementAccessClause, + JassEqualsValueClauseSyntax value) { + SetToken = setToken; IdentifierName = identifierName; - Indexer = indexer; + ElementAccessClause = elementAccessClause; Value = value; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassSyntaxToken SetToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassElementAccessClauseSyntax? ElementAccessClause { get; } - public IExpressionSyntax? Indexer { get; init; } + public JassEqualsValueClauseSyntax Value { get; } - public JassEqualsValueClauseSyntax Value { get; init; } + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.SetStatement; - public bool Equals(IStatementSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassSetStatementSyntax setStatement - && IdentifierName.Equals(setStatement.IdentifierName) - && Indexer.NullableEquals(setStatement.Indexer) - && Value.Equals(setStatement.Value); + && IdentifierName.IsEquivalentTo(setStatement.IdentifierName) + && ElementAccessClause.NullableEquivalentTo(setStatement.ElementAccessClause) + && Value.IsEquivalentTo(setStatement.Value); } - public bool Equals(IStatementLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassSetStatementSyntax setStatement - && IdentifierName.Equals(setStatement.IdentifierName) - && Indexer.NullableEquals(setStatement.Indexer) - && Value.Equals(setStatement.Value); + SetToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + ElementAccessClause?.WriteTo(writer); + Value.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + + if (ElementAccessClause is not null) + { + yield return ElementAccessClause; + } + + yield return Value; + } + + public override IEnumerable GetChildTokens() + { + yield return SetToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return SetToken; + yield return IdentifierName; + + if (ElementAccessClause is not null) + { + yield return ElementAccessClause; + } + + yield return Value; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + if (ElementAccessClause is not null) + { + yield return ElementAccessClause; + foreach (var descendant in ElementAccessClause.GetDescendantNodes()) + { + yield return descendant; + } + } + + yield return Value; + foreach (var descendant in Value.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return SetToken; + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + if (ElementAccessClause is not null) + { + foreach (var descendant in ElementAccessClause.GetDescendantTokens()) + { + yield return descendant; + } + } + + foreach (var descendant in Value.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return SetToken; + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + if (ElementAccessClause is not null) + { + yield return ElementAccessClause; + foreach (var descendant in ElementAccessClause.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + yield return Value; + foreach (var descendant in Value.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{SetToken} {IdentifierName}{ElementAccessClause.Optional()} {Value}"; + + public override JassSyntaxToken GetFirstToken() => SetToken; + + public override JassSyntaxToken GetLastToken() => Value.GetLastToken(); + + protected internal override JassSetStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassSetStatementSyntax( + newToken, + IdentifierName, + ElementAccessClause, + Value); } - public override string ToString() + protected internal override JassSetStatementSyntax ReplaceLastToken(JassSyntaxToken newToken) { - return Indexer is null - ? $"{JassKeyword.Set} {IdentifierName} {Value}" - : $"{JassKeyword.Set} {IdentifierName}{JassSymbol.LeftSquareBracket}{Indexer}{JassSymbol.RightSquareBracket} {Value}"; + return new JassSetStatementSyntax( + SetToken, + IdentifierName, + ElementAccessClause, + Value.ReplaceLastToken(newToken)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementListSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementListSyntax.cs deleted file mode 100644 index 4b73caac..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementListSyntax.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; -using System.Collections.Immutable; -using System.Linq; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassStatementListSyntax : IEquatable - { - public JassStatementListSyntax(ImmutableArray statements) - { - Statements = statements; - } - - public ImmutableArray Statements { get; init; } - - public bool Equals(JassStatementListSyntax? other) - { - return other is not null - && Statements.SequenceEqual(other.Statements); - } - - public override string ToString() => $"<{base.ToString()}> [{Statements.Length}]"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementSyntax.cs new file mode 100644 index 00000000..da32de14 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassStatementSyntax.cs @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public abstract class JassStatementSyntax : JassSyntaxNode + { + protected internal override abstract JassStatementSyntax ReplaceFirstToken(JassSyntaxToken newToken); + + protected internal override abstract JassStatementSyntax ReplaceLastToken(JassSyntaxToken newToken); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassStringLiteralExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassStringLiteralExpressionSyntax.cs deleted file mode 100644 index 5fdf9433..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassStringLiteralExpressionSyntax.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassStringLiteralExpressionSyntax : IExpressionSyntax - { - public JassStringLiteralExpressionSyntax(string value) - { - Value = value; - } - - public string Value { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassStringLiteralExpressionSyntax stringLiteralExpression - && string.Equals(Value, stringLiteralExpression.Value, StringComparison.Ordinal); - } - - public override string ToString() => $"{JassSymbol.QuotationMark}{Value}{JassSymbol.QuotationMark}"; - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs new file mode 100644 index 00000000..2bd531c9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public abstract class JassSyntaxNode + { + internal JassSyntaxNode() + { + } + + public abstract JassSyntaxKind SyntaxKind { get; } + + /// + /// Determines if two nodes are the same, disregarding trivia differences. + /// + public abstract bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other); + + public abstract void WriteTo(TextWriter writer); + + public abstract IEnumerable GetChildNodes(); + + public abstract IEnumerable GetChildTokens(); + + public abstract IEnumerable GetChildNodesAndTokens(); + + public abstract IEnumerable GetDescendantNodes(); + + public abstract IEnumerable GetDescendantTokens(); + + public abstract IEnumerable GetDescendantNodesAndTokens(); + + public abstract JassSyntaxToken GetFirstToken(); + + public abstract JassSyntaxToken GetLastToken(); + + protected internal abstract JassSyntaxNode ReplaceFirstToken(JassSyntaxToken newToken); + + protected internal abstract JassSyntaxNode ReplaceLastToken(JassSyntaxToken newToken); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs new file mode 100644 index 00000000..bbf4fed3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs @@ -0,0 +1,139 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + // Based on https://github.com/mcintyre321/OneOf/blob/master/OneOf/OneOfT1.generated.cs + public readonly struct JassSyntaxNodeOrToken + { + private readonly JassSyntaxNode? _node; + private readonly JassSyntaxToken? _token; + private readonly bool _isNode; + + private JassSyntaxNodeOrToken(JassSyntaxNode node) + { + if (node is null) + { + throw new ArgumentNullException(nameof(node)); + } + + _node = node; + _token = null; + _isNode = true; + } + + private JassSyntaxNodeOrToken(JassSyntaxToken token) + { + if (token is null) + { + throw new ArgumentNullException(nameof(token)); + } + + _node = null; + _token = token; + _isNode = false; + } + + public object Value => _isNode ? _node! : _token!; + + public bool IsNode => _isNode; + + public bool IsToken => !_isNode; + + public JassSyntaxNode AsNode => _node ?? throw new InvalidOperationException($"Cannot return as node, because result is token."); + + public JassSyntaxToken AsToken => _token ?? throw new InvalidOperationException($"Cannot return as token, because result is node."); + + public static implicit operator JassSyntaxNodeOrToken(JassSyntaxNode node) => new(node); + + public static implicit operator JassSyntaxNodeOrToken(JassSyntaxToken token) => new(token); + + public static JassSyntaxNodeOrToken FromJassSyntaxNode(JassSyntaxNode node) => node; + + public static JassSyntaxNodeOrToken FromJassSyntaxToken(JassSyntaxToken token) => token; + + public void Switch(Action? nodeFunc, Action? tokenFunc) + { + if (_isNode) + { + if (nodeFunc is null) + { + throw new ArgumentNullException(nameof(nodeFunc)); + } + + nodeFunc.Invoke(_node!); + } + else + { + if (tokenFunc is null) + { + throw new ArgumentNullException(nameof(tokenFunc)); + } + + tokenFunc.Invoke(_token!); + } + } + + public TResult Match(Func? nodeFunc, Func? tokenFunc) + { + if (_isNode) + { + if (nodeFunc is null) + { + throw new ArgumentNullException(nameof(nodeFunc)); + } + + return nodeFunc.Invoke(_node!); + } + else + { + if (tokenFunc is null) + { + throw new ArgumentNullException(nameof(tokenFunc)); + } + + return tokenFunc.Invoke(_token!); + } + } + + public bool TryGetNode([NotNullWhen(true)] out JassSyntaxNode? node) + { + node = _node; + return _isNode; + } + + public bool TryGetToken([NotNullWhen(true)] out JassSyntaxToken? token) + { + token = _token; + return !_isNode; + } + + public bool TryPickNode([NotNullWhen(true)] out JassSyntaxNode? node, [NotNullWhen(false)] out JassSyntaxToken? token) + { + node = _node; + token = _token; + return _isNode; + } + + public bool TryPickToken([NotNullWhen(true)] out JassSyntaxToken? token, [NotNullWhen(false)] out JassSyntaxNode? node) + { + node = _node; + token = _token; + return !_isNode; + } + + public override string ToString() + { + return _isNode + ? $"Node: {_node}" + : $"Token: {_token}"; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs new file mode 100644 index 00000000..77f4b5ca --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassSyntaxToken + { + internal JassSyntaxToken( + JassSyntaxKind syntaxKind, + string text, + JassSyntaxTriviaList trailingTrivia) + { + LeadingTrivia = JassSyntaxTriviaList.Empty; + SyntaxKind = syntaxKind; + Text = text; + TrailingTrivia = trailingTrivia; + } + + internal JassSyntaxToken( + JassSyntaxTriviaList leadingTrivia, + JassSyntaxKind syntaxKind, + string text, + JassSyntaxTriviaList trailingTrivia) + { + LeadingTrivia = leadingTrivia; + SyntaxKind = syntaxKind; + Text = text; + TrailingTrivia = trailingTrivia; + } + + public JassSyntaxTriviaList LeadingTrivia { get; } + + public JassSyntaxKind SyntaxKind { get; } + + public string Text { get; } + + public JassSyntaxTriviaList TrailingTrivia { get; } + + public bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxToken? other) + { + return other is not null + && SyntaxKind == other.SyntaxKind + && string.Equals(Text, other.Text, StringComparison.Ordinal); + } + + public void WriteTo(TextWriter writer) + { + LeadingTrivia.WriteTo(writer); + writer.Write(Text); + TrailingTrivia.WriteTo(writer); + } + + public override string ToString() => Text; + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs new file mode 100644 index 00000000..3d0fbe17 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs @@ -0,0 +1,45 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassSyntaxTrivia + { + public static readonly JassSyntaxTrivia SingleSpace = new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, " "); + public static readonly JassSyntaxTrivia Newline = new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, JassSymbol.CarriageReturnLineFeed); + + internal JassSyntaxTrivia( + JassSyntaxKind syntaxKind, + string text) + { + SyntaxKind = syntaxKind; + Text = text; + } + + public JassSyntaxKind SyntaxKind { get; } + + public string Text { get; } + + public bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxTrivia? other) + { + return other is not null + && SyntaxKind == other.SyntaxKind + && string.Equals(Text, other.Text, StringComparison.Ordinal); + } + + public void WriteTo(TextWriter writer) + { + writer.Write(Text); + } + + public override string ToString() => Text; + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs new file mode 100644 index 00000000..094c2624 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; +using System.IO; + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public class JassSyntaxTriviaList + { + public static readonly JassSyntaxTriviaList Empty = new(ImmutableArray.Empty); + public static readonly JassSyntaxTriviaList SingleSpace = new(ImmutableArray.Create(JassSyntaxTrivia.SingleSpace)); + public static readonly JassSyntaxTriviaList Newline = new(ImmutableArray.Create(JassSyntaxTrivia.Newline)); + + internal JassSyntaxTriviaList( + ImmutableArray trivia) + { + Trivia = trivia; + } + + public ImmutableArray Trivia { get; } + + public void WriteTo(TextWriter writer) + { + for (var i = 0; i < Trivia.Length; i++) + { + Trivia[i].WriteTo(writer); + } + } + + public override string ToString() => string.Concat(Trivia); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTopLevelDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTopLevelDeclarationSyntax.cs new file mode 100644 index 00000000..b8e8e156 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTopLevelDeclarationSyntax.cs @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public abstract class JassTopLevelDeclarationSyntax : JassSyntaxNode + { + protected internal override abstract JassTopLevelDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken); + + protected internal override abstract JassTopLevelDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs index 1bbc1481..7e89b4d0 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs @@ -5,34 +5,144 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassTypeDeclarationSyntax : ITopLevelDeclarationSyntax, IDeclarationLineSyntax + public class JassTypeDeclarationSyntax : JassTopLevelDeclarationSyntax { - public JassTypeDeclarationSyntax(JassIdentifierNameSyntax identifierName, JassTypeSyntax baseType) + internal JassTypeDeclarationSyntax( + JassSyntaxToken typeToken, + JassIdentifierNameSyntax identifierName, + JassSyntaxToken extendsToken, + JassTypeSyntax baseType) { + TypeToken = typeToken; IdentifierName = identifierName; + ExtendsToken = extendsToken; BaseType = baseType; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassSyntaxToken TypeToken { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } + + public JassSyntaxToken ExtendsToken { get; } - public JassTypeSyntax BaseType { get; init; } + public JassTypeSyntax BaseType { get; } - public bool Equals(ITopLevelDeclarationSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.TypeDeclaration; + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassTypeDeclarationSyntax typeDeclaration - && IdentifierName.Equals(typeDeclaration.IdentifierName) - && BaseType.Equals(typeDeclaration.BaseType); + && IdentifierName.IsEquivalentTo(typeDeclaration.IdentifierName) + && BaseType.IsEquivalentTo(typeDeclaration.BaseType); } - public bool Equals(IDeclarationLineSyntax? other) + public override void WriteTo(TextWriter writer) { - return other is JassTypeDeclarationSyntax typeDeclaration - && IdentifierName.Equals(typeDeclaration.IdentifierName) - && BaseType.Equals(typeDeclaration.BaseType); + TypeToken.WriteTo(writer); + IdentifierName.WriteTo(writer); + ExtendsToken.WriteTo(writer); + BaseType.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return IdentifierName; + yield return BaseType; + } + + public override IEnumerable GetChildTokens() + { + yield return TypeToken; + yield return ExtendsToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return TypeToken; + yield return IdentifierName; + yield return ExtendsToken; + yield return BaseType; + } + + public override IEnumerable GetDescendantNodes() + { + yield return IdentifierName; + foreach (var descendant in BaseType.GetDescendantNodes()) + { + yield return descendant; + } + + yield return BaseType; + foreach (var descendant in BaseType.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return TypeToken; + + foreach (var descendant in BaseType.GetDescendantTokens()) + { + yield return descendant; + } + + yield return ExtendsToken; + + foreach (var descendant in BaseType.GetDescendantTokens()) + { + yield return descendant; + } } - public override string ToString() => $"{JassKeyword.Type} {IdentifierName} {JassKeyword.Extends} {BaseType}"; + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return TypeToken; + + yield return IdentifierName; + foreach (var descendant in BaseType.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return ExtendsToken; + + yield return BaseType; + foreach (var descendant in BaseType.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{TypeToken} {IdentifierName} {ExtendsToken} {BaseType}"; + + public override JassSyntaxToken GetFirstToken() => TypeToken; + + public override JassSyntaxToken GetLastToken() => BaseType.GetLastToken(); + + protected internal override JassTypeDeclarationSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassTypeDeclarationSyntax( + newToken, + IdentifierName, + ExtendsToken, + BaseType); + } + + protected internal override JassTypeDeclarationSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + return new JassTypeDeclarationSyntax( + TypeToken, + IdentifierName, + ExtendsToken, + BaseType.ReplaceLastToken(newToken)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeSyntax.cs index 049c7dca..341459dc 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeSyntax.cs @@ -5,33 +5,12 @@ // // ------------------------------------------------------------------------------ -using System; - namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassTypeSyntax : IEquatable + public abstract class JassTypeSyntax : JassExpressionSyntax { - public static readonly JassTypeSyntax Boolean = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.Boolean)); - public static readonly JassTypeSyntax Code = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.Code)); - public static readonly JassTypeSyntax Handle = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.Handle)); - public static readonly JassTypeSyntax Integer = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.Integer)); - public static readonly JassTypeSyntax Nothing = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.Nothing)); - public static readonly JassTypeSyntax Real = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.Real)); - public static readonly JassTypeSyntax String = new JassTypeSyntax(new JassIdentifierNameSyntax(JassKeyword.String)); - - internal JassTypeSyntax(JassIdentifierNameSyntax typeName) - { - TypeName = typeName; - } - - public JassIdentifierNameSyntax TypeName { get; init; } - - public bool Equals(JassTypeSyntax? other) - { - return other is not null - && TypeName.Equals(other.TypeName); - } + protected internal override abstract JassTypeSyntax ReplaceFirstToken(JassSyntaxToken newToken); - public override string ToString() => TypeName.ToString(); + protected internal override abstract JassTypeSyntax ReplaceLastToken(JassSyntaxToken newToken); } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs index 0d60e508..e24f2305 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs @@ -5,34 +5,105 @@ // // ------------------------------------------------------------------------------ -using War3Net.CodeAnalysis.Jass.Extensions; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassUnaryExpressionSyntax : IExpressionSyntax + public class JassUnaryExpressionSyntax : JassExpressionSyntax { - public JassUnaryExpressionSyntax(UnaryOperatorType @operator, IExpressionSyntax expression) + internal JassUnaryExpressionSyntax( + JassSyntaxToken operatorToken, + JassExpressionSyntax expression) { - Operator = @operator; + OperatorToken = operatorToken; Expression = expression; } - public UnaryOperatorType Operator { get; init; } + public JassSyntaxToken OperatorToken { get; } - public IExpressionSyntax Expression { get; init; } + public JassExpressionSyntax Expression { get; } - public bool Equals(IExpressionSyntax? other) + public override JassSyntaxKind SyntaxKind => JassSyntaxFacts.GetUnaryExpressionKind(OperatorToken.SyntaxKind); + + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassUnaryExpressionSyntax unaryExpression - && Operator == unaryExpression.Operator - && Expression.Equals(unaryExpression.Expression); + && OperatorToken.IsEquivalentTo(unaryExpression.OperatorToken) + && Expression.IsEquivalentTo(unaryExpression.Expression); + } + + public override void WriteTo(TextWriter writer) + { + OperatorToken.WriteTo(writer); + Expression.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Expression; + } + + public override IEnumerable GetChildTokens() + { + yield return OperatorToken; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return OperatorToken; + yield return Expression; + } + + public override IEnumerable GetDescendantNodes() + { + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodes()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantTokens() + { + yield return OperatorToken; + + foreach (var descendant in Expression.GetDescendantTokens()) + { + yield return descendant; + } + } + + public override IEnumerable GetDescendantNodesAndTokens() + { + yield return OperatorToken; + + yield return Expression; + foreach (var descendant in Expression.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + + public override string ToString() => $"{OperatorToken}{(OperatorToken.SyntaxKind == JassSyntaxKind.NotKeyword ? " " : string.Empty)}{Expression}"; + + public override JassSyntaxToken GetFirstToken() => OperatorToken; + + public override JassSyntaxToken GetLastToken() => Expression.GetLastToken(); + + protected internal override JassUnaryExpressionSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassUnaryExpressionSyntax( + newToken, + Expression); } - public override string ToString() + protected internal override JassUnaryExpressionSyntax ReplaceLastToken(JassSyntaxToken newToken) { - return Operator == UnaryOperatorType.Not - ? $"{Operator.GetSymbol()} {Expression}" - : $"{Operator.GetSymbol()}{Expression}"; + return new JassUnaryExpressionSyntax( + OperatorToken, + Expression.ReplaceLastToken(newToken)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableDeclaratorSyntax.cs index 6d2e461d..bfba2660 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableDeclaratorSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableDeclaratorSyntax.cs @@ -5,38 +5,173 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; + using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.CodeAnalysis.Jass.Syntax { - public class JassVariableDeclaratorSyntax : IVariableDeclaratorSyntax + public class JassVariableDeclaratorSyntax : JassVariableOrArrayDeclaratorSyntax { - public JassVariableDeclaratorSyntax(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax? value) + internal JassVariableDeclaratorSyntax( + JassTypeSyntax type, + JassIdentifierNameSyntax identifierName, + JassEqualsValueClauseSyntax? value) { Type = type; IdentifierName = identifierName; Value = value; } - public JassTypeSyntax Type { get; init; } + public JassTypeSyntax Type { get; } + + public JassIdentifierNameSyntax IdentifierName { get; } - public JassIdentifierNameSyntax IdentifierName { get; init; } + public JassEqualsValueClauseSyntax? Value { get; } - public JassEqualsValueClauseSyntax? Value { get; init; } + public override JassSyntaxKind SyntaxKind => JassSyntaxKind.VariableDeclarator; - public bool Equals(IVariableDeclaratorSyntax? other) + public override bool IsEquivalentTo([NotNullWhen(true)] JassSyntaxNode? other) { return other is JassVariableDeclaratorSyntax variableDeclarator - && Type.Equals(variableDeclarator.Type) - && IdentifierName.Equals(variableDeclarator.IdentifierName) - && Value.NullableEquals(variableDeclarator.Value); + && Type.IsEquivalentTo(variableDeclarator.Type) + && IdentifierName.IsEquivalentTo(variableDeclarator.IdentifierName) + && Value.NullableEquivalentTo(variableDeclarator.Value); + } + + public override void WriteTo(TextWriter writer) + { + Type.WriteTo(writer); + IdentifierName.WriteTo(writer); + Value?.WriteTo(writer); + } + + public override IEnumerable GetChildNodes() + { + yield return Type; + yield return IdentifierName; + + if (Value is not null) + { + yield return Value; + } + } + + public override IEnumerable GetChildTokens() + { + yield break; + } + + public override IEnumerable GetChildNodesAndTokens() + { + yield return Type; + yield return IdentifierName; + + if (Value is not null) + { + yield return Value; + } + } + + public override IEnumerable GetDescendantNodes() + { + yield return Type; + foreach (var descendant in Type.GetDescendantNodes()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodes()) + { + yield return descendant; + } + + if (Value is not null) + { + yield return Value; + foreach (var descendant in Value.GetDescendantNodes()) + { + yield return descendant; + } + } + } + + public override IEnumerable GetDescendantTokens() + { + foreach (var descendant in Type.GetDescendantTokens()) + { + yield return descendant; + } + + foreach (var descendant in IdentifierName.GetDescendantTokens()) + { + yield return descendant; + } + + if (Value is not null) + { + foreach (var descendant in Value.GetDescendantTokens()) + { + yield return descendant; + } + } } - public override string ToString() + public override IEnumerable GetDescendantNodesAndTokens() { - return Value is null - ? $"{Type} {IdentifierName}" - : $"{Type} {IdentifierName} {Value}"; + yield return Type; + foreach (var descendant in Type.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + yield return IdentifierName; + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + + if (Value is not null) + { + yield return Value; + foreach (var descendant in Value.GetDescendantNodesAndTokens()) + { + yield return descendant; + } + } + } + + public override string ToString() => $"{Type} {IdentifierName}{Value.OptionalPrefixed()}"; + + public override JassSyntaxToken GetFirstToken() => Type.GetFirstToken(); + + public override JassSyntaxToken GetLastToken() => ((JassSyntaxNode?)Value ?? IdentifierName).GetLastToken(); + + protected internal override JassVariableDeclaratorSyntax ReplaceFirstToken(JassSyntaxToken newToken) + { + return new JassVariableDeclaratorSyntax( + Type.ReplaceFirstToken(newToken), + IdentifierName, + Value); + } + + protected internal override JassVariableDeclaratorSyntax ReplaceLastToken(JassSyntaxToken newToken) + { + if (Value is not null) + { + return new JassVariableDeclaratorSyntax( + Type, + IdentifierName, + Value.ReplaceLastToken(newToken)); + } + + return new JassVariableDeclaratorSyntax( + Type, + IdentifierName.ReplaceLastToken(newToken), + null); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableOrArrayDeclaratorSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableOrArrayDeclaratorSyntax.cs new file mode 100644 index 00000000..f85e3936 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableOrArrayDeclaratorSyntax.cs @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Syntax +{ + public abstract class JassVariableOrArrayDeclaratorSyntax : JassSyntaxNode + { + protected internal override abstract JassVariableOrArrayDeclaratorSyntax ReplaceFirstToken(JassSyntaxToken newToken); + + protected internal override abstract JassVariableOrArrayDeclaratorSyntax ReplaceLastToken(JassSyntaxToken newToken); + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableReferenceExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableReferenceExpressionSyntax.cs deleted file mode 100644 index a95e523c..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassVariableReferenceExpressionSyntax.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public class JassVariableReferenceExpressionSyntax : IExpressionSyntax - { - public JassVariableReferenceExpressionSyntax(JassIdentifierNameSyntax identifierName) - { - IdentifierName = identifierName; - } - - public JassIdentifierNameSyntax IdentifierName { get; init; } - - public bool Equals(IExpressionSyntax? other) - { - return other is JassVariableReferenceExpressionSyntax variableReferenceExpression - && IdentifierName.Equals(variableReferenceExpression.IdentifierName); - } - - public override string ToString() => IdentifierName.ToString(); - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/UnaryOperatorType.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/UnaryOperatorType.cs deleted file mode 100644 index 05d4cdab..00000000 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/UnaryOperatorType.cs +++ /dev/null @@ -1,16 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.CodeAnalysis.Jass.Syntax -{ - public enum UnaryOperatorType - { - Plus, - Minus, - Not, - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArgumentListFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArgumentListFactory.cs index 90d00a7f..d4e5baf1 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArgumentListFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArgumentListFactory.cs @@ -5,7 +5,7 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Immutable; +using System.Collections.Generic; using War3Net.CodeAnalysis.Jass.Syntax; @@ -13,9 +13,32 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassArgumentListSyntax ArgumentList(params IExpressionSyntax[] arguments) + public static JassArgumentListSyntax ArgumentList(params JassExpressionSyntax[] arguments) { - return new JassArgumentListSyntax(arguments.ToImmutableArray()); + return new JassArgumentListSyntax( + Token(JassSyntaxKind.OpenParenToken), + SeparatedSyntaxList(JassSyntaxKind.CommaToken, arguments), + Token(JassSyntaxKind.CloseParenToken)); + } + + public static JassArgumentListSyntax ArgumentList(IEnumerable arguments) + { + return new JassArgumentListSyntax( + Token(JassSyntaxKind.OpenParenToken), + SeparatedSyntaxList(JassSyntaxKind.CommaToken, arguments), + Token(JassSyntaxKind.CloseParenToken)); + } + + public static JassArgumentListSyntax ArgumentList(JassSyntaxToken openParenToken, SeparatedSyntaxList argumentList, JassSyntaxToken closeParenToken) + { + ThrowHelper.ThrowIfInvalidToken(openParenToken, JassSyntaxKind.OpenParenToken); + ThrowHelper.ThrowIfInvalidSeparatedSyntaxList(argumentList, JassSyntaxKind.CommaToken); + ThrowHelper.ThrowIfInvalidToken(closeParenToken, JassSyntaxKind.CloseParenToken); + + return new JassArgumentListSyntax( + openParenToken, + argumentList, + closeParenToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayDeclaratorFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayDeclaratorFactory.cs new file mode 100644 index 00000000..98c7e596 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayDeclaratorFactory.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassArrayDeclaratorSyntax ArrayDeclarator(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassArrayDeclaratorSyntax( + type, + Token(JassSyntaxKind.ArrayKeyword), + identifierName); + } + + public static JassArrayDeclaratorSyntax ArrayDeclarator(JassTypeSyntax type, string name) + { + return new JassArrayDeclaratorSyntax( + type, + Token(JassSyntaxKind.ArrayKeyword), + ParseIdentifierName(name)); + } + + public static JassArrayDeclaratorSyntax ArrayDeclarator(string type, JassIdentifierNameSyntax identifierName) + { + return new JassArrayDeclaratorSyntax( + ParseTypeName(type), + Token(JassSyntaxKind.ArrayKeyword), + identifierName); + } + + public static JassArrayDeclaratorSyntax ArrayDeclarator(string type, string name) + { + return new JassArrayDeclaratorSyntax( + ParseTypeName(type), + Token(JassSyntaxKind.ArrayKeyword), + ParseIdentifierName(name)); + } + + public static JassArrayDeclaratorSyntax ArrayDeclarator(JassTypeSyntax type, JassSyntaxToken arrayToken, JassIdentifierNameSyntax identifierName) + { + ThrowHelper.ThrowIfInvalidToken(arrayToken, JassSyntaxKind.ArrayKeyword); + + return new JassArrayDeclaratorSyntax( + type, + arrayToken, + identifierName); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayReferenceExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayReferenceExpressionFactory.cs deleted file mode 100644 index 288ef0f8..00000000 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ArrayReferenceExpressionFactory.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public static partial class JassSyntaxFactory - { - public static JassArrayReferenceExpressionSyntax ArrayReferenceExpression(string name, IExpressionSyntax indexer) - { - return new JassArrayReferenceExpressionSyntax( - ParseIdentifierName(name), - indexer); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs index 40de143d..bec4a8bc 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs @@ -11,69 +11,111 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassBinaryExpressionSyntax BinaryAdditionExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryAdditionExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.Add, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.PlusToken), + right); } - public static JassBinaryExpressionSyntax BinarySubtractionExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinarySubtractionExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.Subtract, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.MinusToken), + right); } - public static JassBinaryExpressionSyntax BinaryMultiplicationExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryMultiplicationExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.Multiplication, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.AsteriskToken), + right); } - public static JassBinaryExpressionSyntax BinaryDivisionExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryDivisionExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.Division, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.SlashToken), + right); } - public static JassBinaryExpressionSyntax BinaryGreaterThanExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryGreaterThanExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.GreaterThan, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.GreaterThanToken), + right); } - public static JassBinaryExpressionSyntax BinaryLessThanExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryLessThanExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.LessThan, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.LessThanToken), + right); } - public static JassBinaryExpressionSyntax BinaryEqualsExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryEqualsExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.Equals, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.EqualsEqualsToken), + right); } - public static JassBinaryExpressionSyntax BinaryNotEqualsExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryNotEqualsExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.NotEquals, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.ExclamationEqualsToken), + right); } - public static JassBinaryExpressionSyntax BinaryGreaterOrEqualExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryGreaterOrEqualExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.GreaterOrEqual, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.GreaterThanEqualsToken), + right); } - public static JassBinaryExpressionSyntax BinaryLessOrEqualExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryLessOrEqualExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.LessOrEqual, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.LessThanEqualsToken), + right); } - public static JassBinaryExpressionSyntax BinaryAndExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryAndExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.And, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.AndKeyword), + right); } - public static JassBinaryExpressionSyntax BinaryOrExpression(IExpressionSyntax left, IExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryOrExpression(JassExpressionSyntax left, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(BinaryOperatorType.Or, left, right); + return new JassBinaryExpressionSyntax( + left, + Token(JassSyntaxKind.OrKeyword), + right); } - public static JassBinaryExpressionSyntax BinaryExpression(IExpressionSyntax left, IExpressionSyntax right, BinaryOperatorType @operator) + public static JassBinaryExpressionSyntax BinaryExpression(JassExpressionSyntax left, JassSyntaxToken operatorToken, JassExpressionSyntax right) { - return new JassBinaryExpressionSyntax(@operator, left, right); + // Token validation + JassSyntaxFacts.GetBinaryExpressionKind(operatorToken.SyntaxKind); + + return new JassBinaryExpressionSyntax( + left, + operatorToken, + right); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CallStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CallStatementFactory.cs index c686a230..a653a435 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CallStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CallStatementFactory.cs @@ -5,24 +5,70 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassCallStatementSyntax CallStatement(string name, JassArgumentListSyntax arguments) + public static JassCallStatementSyntax CallStatement(JassIdentifierNameSyntax identifierName, JassArgumentListSyntax argumentList) + { + return new JassCallStatementSyntax( + Token(JassSyntaxKind.CallKeyword), + identifierName, + argumentList); + } + + public static JassCallStatementSyntax CallStatement(JassIdentifierNameSyntax identifierName, params JassExpressionSyntax[] arguments) + { + return new JassCallStatementSyntax( + Token(JassSyntaxKind.CallKeyword), + identifierName, + ArgumentList(arguments)); + } + + public static JassCallStatementSyntax CallStatement(JassIdentifierNameSyntax identifierName, IEnumerable arguments) + { + return new JassCallStatementSyntax( + Token(JassSyntaxKind.CallKeyword), + identifierName, + ArgumentList(arguments)); + } + + public static JassCallStatementSyntax CallStatement(string name, JassArgumentListSyntax argumentList) { return new JassCallStatementSyntax( + Token(JassSyntaxKind.CallKeyword), ParseIdentifierName(name), - arguments); + argumentList); } - public static JassCallStatementSyntax CallStatement(string name, params IExpressionSyntax[] arguments) + public static JassCallStatementSyntax CallStatement(string name, params JassExpressionSyntax[] arguments) { return new JassCallStatementSyntax( + Token(JassSyntaxKind.CallKeyword), ParseIdentifierName(name), ArgumentList(arguments)); } + + public static JassCallStatementSyntax CallStatement(string name, IEnumerable arguments) + { + return new JassCallStatementSyntax( + Token(JassSyntaxKind.CallKeyword), + ParseIdentifierName(name), + ArgumentList(arguments)); + } + + public static JassCallStatementSyntax CallStatement(JassSyntaxToken callToken, JassIdentifierNameSyntax identifierName, JassArgumentListSyntax argumentList) + { + ThrowHelper.ThrowIfInvalidToken(callToken, JassSyntaxKind.CallKeyword); + + return new JassCallStatementSyntax( + callToken, + identifierName, + argumentList); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CompilationUnitFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CompilationUnitFactory.cs index e0717321..fbbe6c81 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CompilationUnitFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/CompilationUnitFactory.cs @@ -14,14 +14,34 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassCompilationUnitSyntax CompilationUnit(IEnumerable declarations) + public static JassCompilationUnitSyntax CompilationUnit(params JassTopLevelDeclarationSyntax[] declarations) { - return new JassCompilationUnitSyntax(declarations.ToImmutableArray()); + return new JassCompilationUnitSyntax( + declarations.ToImmutableArray(), + Token(JassSyntaxKind.EndOfFileToken)); } - public static JassCompilationUnitSyntax CompilationUnit(params ITopLevelDeclarationSyntax[] declarations) + public static JassCompilationUnitSyntax CompilationUnit(IEnumerable declarations) { - return new JassCompilationUnitSyntax(declarations.ToImmutableArray()); + return new JassCompilationUnitSyntax( + declarations.ToImmutableArray(), + Token(JassSyntaxKind.EndOfFileToken)); + } + + public static JassCompilationUnitSyntax CompilationUnit(ImmutableArray declarations) + { + return new JassCompilationUnitSyntax( + declarations, + Token(JassSyntaxKind.EndOfFileToken)); + } + + public static JassCompilationUnitSyntax CompilationUnit(ImmutableArray declarations, JassSyntaxToken endOfFileToken) + { + ThrowHelper.ThrowIfInvalidToken(endOfFileToken, JassSyntaxKind.EndOfFileToken); + + return new JassCompilationUnitSyntax( + declarations, + endOfFileToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs new file mode 100644 index 00000000..0791f0f2 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs @@ -0,0 +1,36 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassDebugStatementSyntax DebugStatement(JassStatementSyntax statement) + { + // Statement validation + JassSyntaxFacts.GetDebugStatementKind(statement.SyntaxKind); + + return new JassDebugStatementSyntax( + Token(JassSyntaxKind.DebugKeyword), + statement); + } + + public static JassDebugStatementSyntax DebugStatement(JassSyntaxToken debugToken, JassStatementSyntax statement) + { + ThrowHelper.ThrowIfInvalidToken(debugToken, JassSyntaxKind.DebugKeyword); + + // Statement validation + JassSyntaxFacts.GetDebugStatementKind(statement.SyntaxKind); + + return new JassDebugStatementSyntax( + debugToken, + statement); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessClauseFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessClauseFactory.cs new file mode 100644 index 00000000..d7225466 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessClauseFactory.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassElementAccessClauseSyntax ElementAccessClause(JassExpressionSyntax expression) + { + return new JassElementAccessClauseSyntax( + Token(JassSyntaxKind.OpenBracketToken), + expression, + Token(JassSyntaxKind.CloseBracketToken)); + } + + public static JassElementAccessClauseSyntax ElementAccessClause(JassSyntaxToken openBracketToken, JassExpressionSyntax expression, JassSyntaxToken closeBracketToken) + { + ThrowHelper.ThrowIfInvalidToken(openBracketToken, JassSyntaxKind.OpenBracketToken); + ThrowHelper.ThrowIfInvalidToken(closeBracketToken, JassSyntaxKind.CloseBracketToken); + + return new JassElementAccessClauseSyntax( + openBracketToken, + expression, + closeBracketToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessExpressionFactory.cs new file mode 100644 index 00000000..1aab3e9f --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElementAccessExpressionFactory.cs @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassElementAccessExpressionSyntax ElementAccessExpression(JassIdentifierNameSyntax identifierName, JassElementAccessClauseSyntax elementAccessClause) + { + return new JassElementAccessExpressionSyntax( + identifierName, + elementAccessClause); + } + + public static JassElementAccessExpressionSyntax ElementAccessExpression(JassIdentifierNameSyntax identifierName, JassExpressionSyntax elementAccessClauseExpression) + { + return new JassElementAccessExpressionSyntax( + identifierName, + ElementAccessClause(elementAccessClauseExpression)); + } + + public static JassElementAccessExpressionSyntax ElementAccessExpression(string name, JassElementAccessClauseSyntax elementAccessClause) + { + return new JassElementAccessExpressionSyntax( + ParseIdentifierName(name), + elementAccessClause); + } + + public static JassElementAccessExpressionSyntax ElementAccessExpression(string name, JassExpressionSyntax elementAccessClauseExpression) + { + return new JassElementAccessExpressionSyntax( + ParseIdentifierName(name), + ElementAccessClause(elementAccessClauseExpression)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseClauseFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseClauseFactory.cs new file mode 100644 index 00000000..31b4fba8 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseClauseFactory.cs @@ -0,0 +1,47 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassElseClauseSyntax ElseClause(params JassStatementSyntax[] statements) + { + return new JassElseClauseSyntax( + Token(JassSyntaxKind.ElseKeyword), + statements.ToImmutableArray()); + } + + public static JassElseClauseSyntax ElseClause(IEnumerable statements) + { + return new JassElseClauseSyntax( + Token(JassSyntaxKind.ElseKeyword), + statements.ToImmutableArray()); + } + + public static JassElseClauseSyntax ElseClause(ImmutableArray statements) + { + return new JassElseClauseSyntax( + Token(JassSyntaxKind.ElseKeyword), + statements); + } + + public static JassElseClauseSyntax ElseClause(JassSyntaxToken elseToken, ImmutableArray statements) + { + ThrowHelper.ThrowIfInvalidToken(elseToken, JassSyntaxKind.ElseKeyword); + + return new JassElseClauseSyntax( + elseToken, + statements); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseDeclaratorFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseDeclaratorFactory.cs new file mode 100644 index 00000000..488db1b1 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseDeclaratorFactory.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassElseIfClauseDeclaratorSyntax ElseIfClauseDeclarator(JassExpressionSyntax condition) + { + return new JassElseIfClauseDeclaratorSyntax( + Token(JassSyntaxKind.ElseIfKeyword), + condition, + Token(JassSyntaxKind.ThenKeyword)); + } + + public static JassElseIfClauseDeclaratorSyntax ElseIfClauseDeclarator(JassSyntaxToken elseIfToken, JassExpressionSyntax condition, JassSyntaxToken thenToken) + { + ThrowHelper.ThrowIfInvalidToken(elseIfToken, JassSyntaxKind.ElseIfKeyword); + ThrowHelper.ThrowIfInvalidToken(thenToken, JassSyntaxKind.ThenKeyword); + + return new JassElseIfClauseDeclaratorSyntax( + elseIfToken, + condition, + thenToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseFactory.cs new file mode 100644 index 00000000..50110c1a --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ElseIfClauseFactory.cs @@ -0,0 +1,59 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassElseIfClauseSyntax ElseIfClause(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, params JassStatementSyntax[] statements) + { + return new JassElseIfClauseSyntax( + elseIfClauseDeclarator, + statements.ToImmutableArray()); + } + + public static JassElseIfClauseSyntax ElseIfClause(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, IEnumerable statements) + { + return new JassElseIfClauseSyntax( + elseIfClauseDeclarator, + statements.ToImmutableArray()); + } + + public static JassElseIfClauseSyntax ElseIfClause(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, ImmutableArray statements) + { + return new JassElseIfClauseSyntax( + elseIfClauseDeclarator, + statements); + } + + public static JassElseIfClauseSyntax ElseIfClause(JassExpressionSyntax condition, params JassStatementSyntax[] statements) + { + return new JassElseIfClauseSyntax( + ElseIfClauseDeclarator(condition), + statements.ToImmutableArray()); + } + + public static JassElseIfClauseSyntax ElseIfClause(JassExpressionSyntax condition, IEnumerable statements) + { + return new JassElseIfClauseSyntax( + ElseIfClauseDeclarator(condition), + statements.ToImmutableArray()); + } + + public static JassElseIfClauseSyntax ElseIfClause(JassExpressionSyntax condition, ImmutableArray statements) + { + return new JassElseIfClauseSyntax( + ElseIfClauseDeclarator(condition), + statements); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/EqualsValueClauseFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/EqualsValueClauseFactory.cs new file mode 100644 index 00000000..9a8f2ea3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/EqualsValueClauseFactory.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassEqualsValueClauseSyntax EqualsValueClause(JassExpressionSyntax expression) + { + return new JassEqualsValueClauseSyntax( + Token(JassSyntaxKind.EqualsToken), + expression); + } + + public static JassEqualsValueClauseSyntax EqualsValueClause(JassSyntaxToken equalsToken, JassExpressionSyntax expression) + { + ThrowHelper.ThrowIfInvalidToken(equalsToken, JassSyntaxKind.EqualsToken); + + return new JassEqualsValueClauseSyntax( + equalsToken, + expression); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ExitStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ExitStatementFactory.cs index ec2d6eb7..e8e66d87 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ExitStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ExitStatementFactory.cs @@ -11,9 +11,20 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassExitStatementSyntax ExitStatement(IExpressionSyntax expression) + public static JassExitStatementSyntax ExitStatement(JassExpressionSyntax expression) { - return new JassExitStatementSyntax(expression); + return new JassExitStatementSyntax( + Token(JassSyntaxKind.ExitWhenKeyword), + expression); + } + + public static JassExitStatementSyntax ExitStatement(JassSyntaxToken exitWhenToken, JassExpressionSyntax expression) + { + ThrowHelper.ThrowIfInvalidToken(exitWhenToken, JassSyntaxKind.ExitWhenKeyword); + + return new JassExitStatementSyntax( + exitWhenToken, + expression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FourCCLiteralExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FourCCLiteralExpressionFactory.cs deleted file mode 100644 index 1e8f1081..00000000 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FourCCLiteralExpressionFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public static partial class JassSyntaxFactory - { - public static JassFourCCLiteralExpressionSyntax FourCCLiteralExpression(int value) - { - return new JassFourCCLiteralExpressionSyntax(value.InvertEndianness()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclarationFactory.cs index cfe71fd4..fae99904 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclarationFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclarationFactory.cs @@ -6,6 +6,7 @@ // ------------------------------------------------------------------------------ using System.Collections.Generic; +using System.Collections.Immutable; using War3Net.CodeAnalysis.Jass.Syntax; @@ -13,14 +14,38 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassFunctionDeclarationSyntax FunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator, IEnumerable statements) + public static JassFunctionDeclarationSyntax FunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator, params JassStatementSyntax[] statements) { - return new JassFunctionDeclarationSyntax(functionDeclarator, StatementList(statements)); + return new JassFunctionDeclarationSyntax( + functionDeclarator, + statements.ToImmutableArray(), + Token(JassSyntaxKind.EndFunctionKeyword)); } - public static JassFunctionDeclarationSyntax FunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator, params IStatementSyntax[] statements) + public static JassFunctionDeclarationSyntax FunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator, IEnumerable statements) { - return new JassFunctionDeclarationSyntax(functionDeclarator, StatementList(statements)); + return new JassFunctionDeclarationSyntax( + functionDeclarator, + statements.ToImmutableArray(), + Token(JassSyntaxKind.EndFunctionKeyword)); + } + + public static JassFunctionDeclarationSyntax FunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator, ImmutableArray statements) + { + return new JassFunctionDeclarationSyntax( + functionDeclarator, + statements, + Token(JassSyntaxKind.EndFunctionKeyword)); + } + + public static JassFunctionDeclarationSyntax FunctionDeclaration(JassFunctionDeclaratorSyntax functionDeclarator, ImmutableArray statements, JassSyntaxToken endFunctionToken) + { + ThrowHelper.ThrowIfInvalidToken(endFunctionToken, JassSyntaxKind.EndFunctionKeyword); + + return new JassFunctionDeclarationSyntax( + functionDeclarator, + statements, + endFunctionToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclaratorFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclaratorFactory.cs index f4e18cc1..8c7bd54f 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclaratorFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionDeclaratorFactory.cs @@ -5,26 +5,567 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name) { return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassReturnClauseSyntax returnClause) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassTypeSyntax returnType) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, string returnType) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + parameterList, + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + parameterList, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + parameterList, + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, string returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(string name, string returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax FunctionDeclarator(JassSyntaxToken functionToken, JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + ThrowHelper.ThrowIfInvalidToken(functionToken, JassSyntaxKind.FunctionKeyword); + + return new JassFunctionDeclaratorSyntax( + null, + functionToken, + identifierName, + parameterList, + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassReturnClauseSyntax returnClause) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassTypeSyntax returnType) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, string returnType) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + parameterList, + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + parameterList, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassIdentifierNameSyntax identifierName, string returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + parameterList, + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), ParseIdentifierName(name), - JassParameterListSyntax.Empty, - JassTypeSyntax.Nothing); + parameterList, + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, string returnType, params JassParameterSyntax[] parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(string name, string returnType, IEnumerable parameters) + { + return new JassFunctionDeclaratorSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassFunctionDeclaratorSyntax ConstantFunctionDeclarator(JassSyntaxToken constantToken, JassSyntaxToken functionToken, JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + ThrowHelper.ThrowIfInvalidToken(constantToken, JassSyntaxKind.ConstantKeyword); + ThrowHelper.ThrowIfInvalidToken(functionToken, JassSyntaxKind.FunctionKeyword); + + return new JassFunctionDeclaratorSyntax( + constantToken, + functionToken, + identifierName, + parameterList, + ReturnClause(returnType)); } public static JassFunctionDeclaratorSyntax ConditionFunctionDeclarator(string name) { return new JassFunctionDeclaratorSyntax( + null, + Token(JassSyntaxKind.FunctionKeyword), ParseIdentifierName(name), - JassParameterListSyntax.Empty, - JassTypeSyntax.Boolean); + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Boolean)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionReferenceExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionReferenceExpressionFactory.cs index 7c2469da..dc8a6140 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionReferenceExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/FunctionReferenceExpressionFactory.cs @@ -11,9 +11,27 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { + public static JassFunctionReferenceExpressionSyntax FunctionReferenceExpression(JassIdentifierNameSyntax identifierName) + { + return new JassFunctionReferenceExpressionSyntax( + Token(JassSyntaxKind.FunctionKeyword), + identifierName); + } + public static JassFunctionReferenceExpressionSyntax FunctionReferenceExpression(string name) { - return new JassFunctionReferenceExpressionSyntax(ParseIdentifierName(name)); + return new JassFunctionReferenceExpressionSyntax( + Token(JassSyntaxKind.FunctionKeyword), + ParseIdentifierName(name)); + } + + public static JassFunctionReferenceExpressionSyntax FunctionReferenceExpression(JassSyntaxToken functionToken, JassIdentifierNameSyntax identifierName) + { + ThrowHelper.ThrowIfInvalidToken(functionToken, JassSyntaxKind.FunctionKeyword); + + return new JassFunctionReferenceExpressionSyntax( + functionToken, + identifierName); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalConstantDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalConstantDeclarationFactory.cs new file mode 100644 index 00000000..17f37fea --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalConstantDeclarationFactory.cs @@ -0,0 +1,97 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + type, + identifierName, + value); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + type, + identifierName, + EqualsValueClause(value)); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(JassTypeSyntax type, string name, JassEqualsValueClauseSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + type, + ParseIdentifierName(name), + value); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(JassTypeSyntax type, string name, JassExpressionSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + type, + ParseIdentifierName(name), + EqualsValueClause(value)); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(string type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + ParseTypeName(type), + identifierName, + value); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(string type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + ParseTypeName(type), + identifierName, + EqualsValueClause(value)); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(string type, string name, JassEqualsValueClauseSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + ParseTypeName(type), + ParseIdentifierName(name), + value); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(string type, string name, JassExpressionSyntax value) + { + return new JassGlobalConstantDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + ParseTypeName(type), + ParseIdentifierName(name), + EqualsValueClause(value)); + } + + public static JassGlobalConstantDeclarationSyntax GlobalConstantDeclaration(JassSyntaxToken constantToken, JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + ThrowHelper.ThrowIfInvalidToken(constantToken, JassSyntaxKind.ConstantKeyword); + + return new JassGlobalConstantDeclarationSyntax( + constantToken, + type, + identifierName, + value); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalDeclarationFactory.cs deleted file mode 100644 index 30037a70..00000000 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalDeclarationFactory.cs +++ /dev/null @@ -1,39 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public static partial class JassSyntaxFactory - { - public static JassGlobalDeclarationSyntax GlobalDeclaration(JassTypeSyntax type, string name) - { - return new JassGlobalDeclarationSyntax( - new JassVariableDeclaratorSyntax( - type, - ParseIdentifierName(name), - null)); - } - - public static JassGlobalDeclarationSyntax GlobalDeclaration(JassTypeSyntax type, string name, IExpressionSyntax value) - { - return new JassGlobalDeclarationSyntax( - new JassVariableDeclaratorSyntax( - type, - ParseIdentifierName(name), - new JassEqualsValueClauseSyntax(value))); - } - - public static JassGlobalDeclarationSyntax GlobalArrayDeclaration(JassTypeSyntax type, string name) - { - return new JassGlobalDeclarationSyntax( - new JassArrayDeclaratorSyntax( - type, ParseIdentifierName(name))); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalVariableDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalVariableDeclarationFactory.cs new file mode 100644 index 00000000..b5934b8f --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalVariableDeclarationFactory.cs @@ -0,0 +1,155 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + type, + identifierName)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(JassTypeSyntax type, string name) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + type, + ParseIdentifierName(name))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(string type, JassIdentifierNameSyntax identifierName) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + ParseTypeName(type), + identifierName)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(string type, string name) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + ParseTypeName(type), + ParseIdentifierName(name))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + type, + identifierName, + value)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + type, + identifierName, + EqualsValueClause(value))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(JassTypeSyntax type, string name, JassEqualsValueClauseSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + type, + ParseIdentifierName(name), + value)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(JassTypeSyntax type, string name, JassExpressionSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + type, + ParseIdentifierName(name), + EqualsValueClause(value))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(string type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + ParseTypeName(type), + identifierName, + value)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(string type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + ParseTypeName(type), + identifierName, + EqualsValueClause(value))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(string type, string name, JassEqualsValueClauseSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + ParseTypeName(type), + ParseIdentifierName(name), + value)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration(string type, string name, JassExpressionSyntax value) + { + return new JassGlobalVariableDeclarationSyntax( + VariableDeclarator( + ParseTypeName(type), + ParseIdentifierName(name), + EqualsValueClause(value))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalArrayDeclaration(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassGlobalVariableDeclarationSyntax( + ArrayDeclarator( + type, + identifierName)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalArrayDeclaration(JassTypeSyntax type, string name) + { + return new JassGlobalVariableDeclarationSyntax( + ArrayDeclarator( + type, + ParseIdentifierName(name))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalArrayDeclaration(string type, JassIdentifierNameSyntax identifierName) + { + return new JassGlobalVariableDeclarationSyntax( + ArrayDeclarator( + ParseTypeName(type), + identifierName)); + } + + public static JassGlobalVariableDeclarationSyntax GlobalArrayDeclaration(string type, string name) + { + return new JassGlobalVariableDeclarationSyntax( + ArrayDeclarator( + ParseTypeName(type), + ParseIdentifierName(name))); + } + + public static JassGlobalVariableDeclarationSyntax GlobalDeclaration(JassVariableOrArrayDeclaratorSyntax declarator) + { + return new JassGlobalVariableDeclarationSyntax(declarator); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalsDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalsDeclarationFactory.cs new file mode 100644 index 00000000..d56ea85f --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/GlobalsDeclarationFactory.cs @@ -0,0 +1,52 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassGlobalsDeclarationSyntax GlobalsDeclaration(params JassGlobalDeclarationSyntax[] globalDeclarations) + { + return new JassGlobalsDeclarationSyntax( + Token(JassSyntaxKind.GlobalsKeyword), + globalDeclarations.ToImmutableArray(), + Token(JassSyntaxKind.EndGlobalsKeyword)); + } + + public static JassGlobalsDeclarationSyntax GlobalsDeclaration(IEnumerable globalDeclarations) + { + return new JassGlobalsDeclarationSyntax( + Token(JassSyntaxKind.GlobalsKeyword), + globalDeclarations.ToImmutableArray(), + Token(JassSyntaxKind.EndGlobalsKeyword)); + } + + public static JassGlobalsDeclarationSyntax GlobalsDeclaration(ImmutableArray globalDeclarations) + { + return new JassGlobalsDeclarationSyntax( + Token(JassSyntaxKind.GlobalsKeyword), + globalDeclarations, + Token(JassSyntaxKind.EndGlobalsKeyword)); + } + + public static JassGlobalsDeclarationSyntax GlobalsDeclaration(JassSyntaxToken globalsToken, ImmutableArray globalDeclarations, JassSyntaxToken endGlobalsToken) + { + ThrowHelper.ThrowIfInvalidToken(globalsToken, JassSyntaxKind.GlobalsKeyword); + ThrowHelper.ThrowIfInvalidToken(endGlobalsToken, JassSyntaxKind.EndGlobalsKeyword); + + return new JassGlobalsDeclarationSyntax( + globalsToken, + globalDeclarations, + endGlobalsToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IdentifierNameFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IdentifierNameFactory.cs new file mode 100644 index 00000000..65fa8099 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IdentifierNameFactory.cs @@ -0,0 +1,46 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassIdentifierNameSyntax IdentifierName(JassSyntaxToken identifier) + { + if (identifier.SyntaxKind != JassSyntaxKind.IdentifierToken) + { + throw new ArgumentException("The token's syntax kind must be 'IdentifierToken'.", nameof(identifier)); + } + + return new JassIdentifierNameSyntax(identifier); + } + + public static JassIdentifierNameSyntax IdentifierName(string identifierName) + { + return new JassIdentifierNameSyntax(Identifier(identifierName)); + } + + public static JassSyntaxToken Identifier(string text) + { + return Identifier(JassSyntaxTriviaList.Empty, text, JassSyntaxTriviaList.Empty); + } + + public static JassSyntaxToken Identifier(JassSyntaxTriviaList leadingTrivia, string text, JassSyntaxTriviaList trailingTrivia) + { + if (!JassSyntaxFacts.IsValidIdentifier(text)) + { + throw new ArgumentException($"'{text}' is not a valid identifier.", nameof(text)); + } + + return new JassSyntaxToken(leadingTrivia, JassSyntaxKind.IdentifierToken, text, trailingTrivia); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseDeclaratorFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseDeclaratorFactory.cs new file mode 100644 index 00000000..f716a427 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseDeclaratorFactory.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassIfClauseDeclaratorSyntax IfClauseDeclarator(JassExpressionSyntax condition) + { + return new JassIfClauseDeclaratorSyntax( + Token(JassSyntaxKind.IfKeyword), + condition, + Token(JassSyntaxKind.ThenKeyword)); + } + + public static JassIfClauseDeclaratorSyntax IfClauseDeclarator(JassSyntaxToken ifToken, JassExpressionSyntax condition, JassSyntaxToken thenToken) + { + ThrowHelper.ThrowIfInvalidToken(ifToken, JassSyntaxKind.IfKeyword); + ThrowHelper.ThrowIfInvalidToken(thenToken, JassSyntaxKind.ThenKeyword); + + return new JassIfClauseDeclaratorSyntax( + ifToken, + condition, + thenToken); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseFactory.cs new file mode 100644 index 00000000..8f694457 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfClauseFactory.cs @@ -0,0 +1,59 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassIfClauseSyntax IfClause(JassExpressionSyntax condition, params JassStatementSyntax[] statements) + { + return new JassIfClauseSyntax( + IfClauseDeclarator(condition), + statements.ToImmutableArray()); + } + + public static JassIfClauseSyntax IfClause(JassExpressionSyntax condition, IEnumerable statements) + { + return new JassIfClauseSyntax( + IfClauseDeclarator(condition), + statements.ToImmutableArray()); + } + + public static JassIfClauseSyntax IfClause(JassExpressionSyntax condition, ImmutableArray statements) + { + return new JassIfClauseSyntax( + IfClauseDeclarator(condition), + statements); + } + + public static JassIfClauseSyntax IfClause(JassIfClauseDeclaratorSyntax ifClauseDeclarator, params JassStatementSyntax[] statements) + { + return new JassIfClauseSyntax( + ifClauseDeclarator, + statements.ToImmutableArray()); + } + + public static JassIfClauseSyntax IfClause(JassIfClauseDeclaratorSyntax ifClauseDeclarator, IEnumerable statements) + { + return new JassIfClauseSyntax( + ifClauseDeclarator, + statements.ToImmutableArray()); + } + + public static JassIfClauseSyntax IfClause(JassIfClauseDeclaratorSyntax ifClauseDeclarator, ImmutableArray statements) + { + return new JassIfClauseSyntax( + ifClauseDeclarator, + statements); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfStatementFactory.cs index 20248c67..65f61974 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/IfStatementFactory.cs @@ -14,49 +14,159 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassIfStatementSyntax IfStatement(IExpressionSyntax condition, JassStatementListSyntax body) + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause) { return new JassIfStatementSyntax( - condition, - body, - ImmutableArray.Create(), - null); + ifClause, + ImmutableArray.Empty, + null, + Token(JassSyntaxKind.EndIfKeyword)); } - public static JassIfStatementSyntax IfStatement(IExpressionSyntax condition, params IStatementSyntax[] body) + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, params JassStatementSyntax[] statements) { return new JassIfStatementSyntax( - condition, - StatementList(body), - ImmutableArray.Create(), - null); + IfClause(condition, statements), + ImmutableArray.Empty, + null, + Token(JassSyntaxKind.EndIfKeyword)); } - public static JassIfStatementSyntax IfStatement(IExpressionSyntax condition, JassStatementListSyntax body, JassElseClauseSyntax elseClause) + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, IEnumerable statements) { return new JassIfStatementSyntax( - condition, - body, - ImmutableArray.Create(), - elseClause); + IfClause(condition, statements), + ImmutableArray.Empty, + null, + Token(JassSyntaxKind.EndIfKeyword)); } - public static JassIfStatementSyntax IfStatement(IExpressionSyntax condition, JassStatementListSyntax body, params JassElseIfClauseSyntax[] elseIfClauses) + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, ImmutableArray statements) { return new JassIfStatementSyntax( - condition, - body, + IfClause(condition, statements), + ImmutableArray.Empty, + null, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + ifClause, + ImmutableArray.Empty, + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, params JassElseIfClauseSyntax[] elseIfClauses) + { + return new JassIfStatementSyntax( + ifClause, + elseIfClauses.ToImmutableArray(), + null, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, IEnumerable elseIfClauses) + { + return new JassIfStatementSyntax( + ifClause, + elseIfClauses.ToImmutableArray(), + null, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, ImmutableArray elseIfClauses) + { + return new JassIfStatementSyntax( + ifClause, + elseIfClauses, + null, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, IEnumerable statements, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + IfClause(condition, statements), + ImmutableArray.Empty, + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, ImmutableArray statements, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + IfClause(condition, statements), + ImmutableArray.Empty, + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, IEnumerable elseIfClauses, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + ifClause, + elseIfClauses.ToImmutableArray(), + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, ImmutableArray elseIfClauses, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + ifClause, + elseIfClauses, + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, IEnumerable statements, IEnumerable elseIfClauses, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + IfClause(condition, statements), elseIfClauses.ToImmutableArray(), - null); + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); } - public static JassIfStatementSyntax IfStatement(IExpressionSyntax condition, JassStatementListSyntax body, IEnumerable elseIfClauses, JassElseClauseSyntax elseClause) + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, IEnumerable statements, ImmutableArray elseIfClauses, JassElseClauseSyntax? elseClause) { return new JassIfStatementSyntax( - condition, - body, + IfClause(condition, statements), + elseIfClauses, + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, ImmutableArray statements, IEnumerable elseIfClauses, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + IfClause(condition, statements), elseIfClauses.ToImmutableArray(), - elseClause); + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassExpressionSyntax condition, ImmutableArray statements, ImmutableArray elseIfClauses, JassElseClauseSyntax? elseClause) + { + return new JassIfStatementSyntax( + IfClause(condition, statements), + elseIfClauses, + elseClause, + Token(JassSyntaxKind.EndIfKeyword)); + } + + public static JassIfStatementSyntax IfStatement(JassIfClauseSyntax ifClause, ImmutableArray elseIfClauses, JassElseClauseSyntax? elseClause, JassSyntaxToken endIfToken) + { + ThrowHelper.ThrowIfInvalidToken(endIfToken, JassSyntaxKind.EndIfKeyword); + + return new JassIfStatementSyntax( + ifClause, + elseIfClauses, + elseClause, + endIfToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/InvocationExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/InvocationExpressionFactory.cs index a3f71bb3..ea41eaf6 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/InvocationExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/InvocationExpressionFactory.cs @@ -5,20 +5,50 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassInvocationExpressionSyntax InvocationExpression(string name, JassArgumentListSyntax arguments) + public static JassInvocationExpressionSyntax InvocationExpression(JassIdentifierNameSyntax identifierName, JassArgumentListSyntax argumentList) + { + return new JassInvocationExpressionSyntax( + identifierName, + argumentList); + } + + public static JassInvocationExpressionSyntax InvocationExpression(JassIdentifierNameSyntax identifierName, params JassExpressionSyntax[] arguments) + { + return new JassInvocationExpressionSyntax( + identifierName, + ArgumentList(arguments)); + } + + public static JassInvocationExpressionSyntax InvocationExpression(JassIdentifierNameSyntax identifierName, IEnumerable arguments) + { + return new JassInvocationExpressionSyntax( + identifierName, + ArgumentList(arguments)); + } + + public static JassInvocationExpressionSyntax InvocationExpression(string name, JassArgumentListSyntax argumentList) + { + return new JassInvocationExpressionSyntax( + ParseIdentifierName(name), + argumentList); + } + + public static JassInvocationExpressionSyntax InvocationExpression(string name, params JassExpressionSyntax[] arguments) { return new JassInvocationExpressionSyntax( ParseIdentifierName(name), - arguments); + ArgumentList(arguments)); } - public static JassInvocationExpressionSyntax InvocationExpression(string name, params IExpressionSyntax[] arguments) + public static JassInvocationExpressionSyntax InvocationExpression(string name, IEnumerable arguments) { return new JassInvocationExpressionSyntax( ParseIdentifierName(name), diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LiteralExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LiteralExpressionFactory.cs index ea47df9e..d28e8afa 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LiteralExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LiteralExpressionFactory.cs @@ -5,53 +5,84 @@ // // ------------------------------------------------------------------------------ +using System; using System.Globalization; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static IExpressionSyntax LiteralExpression(string? value) + public static JassSyntaxToken Literal(string? value) { - return value is null ? JassNullLiteralExpressionSyntax.Value : new JassStringLiteralExpressionSyntax(value); + return Literal(JassSyntaxTriviaList.Empty, value, JassSyntaxTriviaList.Empty); } - public static IExpressionSyntax LiteralExpression(int value) + public static JassSyntaxToken Literal(JassSyntaxTriviaList leadingTrivia, string? value, JassSyntaxTriviaList trailingTrivia) { - if (value == 0) - { - return new JassOctalLiteralExpressionSyntax(0); - } + return value is null + ? Token(leadingTrivia, JassSyntaxKind.NullKeyword, trailingTrivia) + : Token(leadingTrivia, JassSyntaxKind.StringLiteralToken, $"\"{value}\"", trailingTrivia); + } - if (value < 0) - { - return UnaryMinusExpression(new JassDecimalLiteralExpressionSyntax(-value)); - } + public static JassSyntaxToken Literal(int value) + { + return Literal(JassSyntaxTriviaList.Empty, value, JassSyntaxTriviaList.Empty); + } - return new JassDecimalLiteralExpressionSyntax(value); + public static JassSyntaxToken Literal(JassSyntaxTriviaList leadingTrivia, int value, JassSyntaxTriviaList trailingTrivia) + { + return Token(leadingTrivia, JassSyntaxKind.DecimalLiteralToken, value.ToString(CultureInfo.InvariantCulture), trailingTrivia); } - public static IExpressionSyntax LiteralExpression(float value, int precision = 1) + public static JassSyntaxToken Literal(float value, int precision = 1) { - var valueAsString = value.ToString($"F{precision}", CultureInfo.InvariantCulture).Split('.', 2); - if (precision == 0 && valueAsString.Length == 1) - { - valueAsString = new string[] { valueAsString[0], string.Empty }; - } + return Literal(JassSyntaxTriviaList.Empty, value, precision, JassSyntaxTriviaList.Empty); + } - if (valueAsString[0].StartsWith('-')) + public static JassSyntaxToken Literal(JassSyntaxTriviaList leadingTrivia, float value, int precision, JassSyntaxTriviaList trailingTrivia) + { + var valueAsString = value.ToString($"F{precision}", CultureInfo.InvariantCulture); + if (precision == 0) { - return UnaryMinusExpression(new JassRealLiteralExpressionSyntax(valueAsString[0].TrimStart('-'), valueAsString[1])); + valueAsString += JassSymbol.Dot; } - return new JassRealLiteralExpressionSyntax(valueAsString[0], valueAsString[1]); + return Token(leadingTrivia, JassSyntaxKind.RealLiteralToken, valueAsString, trailingTrivia); } - public static IExpressionSyntax LiteralExpression(bool value) + public static JassSyntaxToken Literal(bool value) { - return value ? JassBooleanLiteralExpressionSyntax.True : JassBooleanLiteralExpressionSyntax.False; + return Literal(JassSyntaxTriviaList.Empty, value, JassSyntaxTriviaList.Empty); + } + + public static JassSyntaxToken Literal(JassSyntaxTriviaList leadingTrivia, bool value, JassSyntaxTriviaList trailingTrivia) + { + return value + ? Token(leadingTrivia, JassSyntaxKind.TrueKeyword, JassKeyword.True, trailingTrivia) + : Token(leadingTrivia, JassSyntaxKind.FalseKeyword, JassKeyword.False, trailingTrivia); + } + + public static JassSyntaxToken FourCCLiteral(int value) + { + return FourCCLiteral(JassSyntaxTriviaList.Empty, value, JassSyntaxTriviaList.Empty); + } + + public static JassSyntaxToken FourCCLiteral(JassSyntaxTriviaList leadingTrivia, int value, JassSyntaxTriviaList trailingTrivia) + { + return Token(leadingTrivia, JassSyntaxKind.FourCCLiteralToken, $"'{value.ToJassRawcode()}'", trailingTrivia); + } + + public static JassExpressionSyntax LiteralExpression(JassSyntaxToken token) + { + if (!JassSyntaxFacts.IsLiteralExpressionToken(token.SyntaxKind)) + { + throw new ArgumentException("Token kind must be a literal.", nameof(token)); + } + + return new JassLiteralExpressionSyntax(token); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LocalVariableDeclarationStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LocalVariableDeclarationStatementFactory.cs index 309c2413..d50c271e 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LocalVariableDeclarationStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LocalVariableDeclarationStatementFactory.cs @@ -11,29 +11,172 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassSyntaxToken localToken, JassVariableOrArrayDeclaratorSyntax declarator) + { + ThrowHelper.ThrowIfInvalidToken(localToken, JassSyntaxKind.LocalKeyword); + + return new JassLocalVariableDeclarationStatementSyntax( + localToken, + declarator); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + type, + identifierName)); + } + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, string name) { return new JassLocalVariableDeclarationStatementSyntax( - new JassVariableDeclaratorSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + type, + ParseIdentifierName(name))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(string type, JassIdentifierNameSyntax identifierName) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + ParseTypeName(type), + identifierName)); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(string type, string name) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + ParseTypeName(type), + ParseIdentifierName(name))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + type, + identifierName, + value)); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + type, + identifierName, + EqualsValueClause(value))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, string name, JassEqualsValueClauseSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( type, ParseIdentifierName(name), - null)); + value)); } - public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, string name, IExpressionSyntax value) + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(JassTypeSyntax type, string name, JassExpressionSyntax value) { return new JassLocalVariableDeclarationStatementSyntax( - new JassVariableDeclaratorSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( type, ParseIdentifierName(name), - new JassEqualsValueClauseSyntax(value))); + EqualsValueClause(value))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(string type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + ParseTypeName(type), + identifierName, + value)); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(string type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + ParseTypeName(type), + identifierName, + EqualsValueClause(value))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(string type, string name, JassEqualsValueClauseSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + ParseTypeName(type), + ParseIdentifierName(name), + value)); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalVariableDeclarationStatement(string type, string name, JassExpressionSyntax value) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + VariableDeclarator( + ParseTypeName(type), + ParseIdentifierName(name), + EqualsValueClause(value))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalArrayDeclarationStatement(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + ArrayDeclarator( + type, + identifierName)); } public static JassLocalVariableDeclarationStatementSyntax LocalArrayDeclarationStatement(JassTypeSyntax type, string name) { return new JassLocalVariableDeclarationStatementSyntax( - new JassArrayDeclaratorSyntax( - type, ParseIdentifierName(name))); + Token(JassSyntaxKind.LocalKeyword), + ArrayDeclarator( + type, + ParseIdentifierName(name))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalArrayDeclarationStatement(string type, JassIdentifierNameSyntax identifierName) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + ArrayDeclarator( + ParseTypeName(type), + identifierName)); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalArrayDeclarationStatement(string type, string name) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + ArrayDeclarator( + ParseTypeName(type), + ParseIdentifierName(name))); + } + + public static JassLocalVariableDeclarationStatementSyntax LocalDeclarationStatement(JassVariableOrArrayDeclaratorSyntax declarator) + { + return new JassLocalVariableDeclarationStatementSyntax( + Token(JassSyntaxKind.LocalKeyword), + declarator); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LoopStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LoopStatementFactory.cs index 491edae3..3b0bf847 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LoopStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/LoopStatementFactory.cs @@ -5,20 +5,48 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Collections.Immutable; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassLoopStatementSyntax LoopStatement(JassStatementListSyntax body) + public static JassLoopStatementSyntax LoopStatement(params JassStatementSyntax[] statements) + { + return new JassLoopStatementSyntax( + Token(JassSyntaxKind.LoopKeyword), + statements.ToImmutableArray(), + Token(JassSyntaxKind.EndLoopKeyword)); + } + + public static JassLoopStatementSyntax LoopStatement(IEnumerable statements) { - return new JassLoopStatementSyntax(body); + return new JassLoopStatementSyntax( + Token(JassSyntaxKind.LoopKeyword), + statements.ToImmutableArray(), + Token(JassSyntaxKind.EndLoopKeyword)); } - public static JassLoopStatementSyntax LoopStatement(params IStatementSyntax[] body) + public static JassLoopStatementSyntax LoopStatement(ImmutableArray statements) { - return new JassLoopStatementSyntax(StatementList(body)); + return new JassLoopStatementSyntax( + Token(JassSyntaxKind.LoopKeyword), + statements, + Token(JassSyntaxKind.EndLoopKeyword)); + } + + public static JassLoopStatementSyntax LoopStatement(JassSyntaxToken loopToken, ImmutableArray statements, JassSyntaxToken endLoopToken) + { + ThrowHelper.ThrowIfInvalidToken(loopToken, JassSyntaxKind.LoopKeyword); + ThrowHelper.ThrowIfInvalidToken(endLoopToken, JassSyntaxKind.EndLoopKeyword); + + return new JassLoopStatementSyntax( + loopToken, + statements, + endLoopToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/NativeFunctionDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/NativeFunctionDeclarationFactory.cs new file mode 100644 index 00000000..5f6e3805 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/NativeFunctionDeclarationFactory.cs @@ -0,0 +1,561 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassTypeSyntax returnType) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, string returnType) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + parameterList, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + parameterList, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + parameterList, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, string returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(string name, string returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + null, + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax NativeFunctionDeclaration(JassSyntaxToken nativeToken, JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + ThrowHelper.ThrowIfInvalidToken(nativeToken, JassSyntaxKind.NativeKeyword); + + return new JassNativeFunctionDeclarationSyntax( + null, + nativeToken, + identifierName, + parameterList, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(JassPredefinedTypeSyntax.Nothing)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassTypeSyntax returnType) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, string returnType) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + JassEmptyParameterListSyntax.Value, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + parameterList, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + parameterList, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassIdentifierNameSyntax identifierName, string returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + identifierName, + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + parameterList, + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassReturnClauseSyntax returnClause, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + returnClause); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassTypeSyntax returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassTypeSyntax returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, JassTypeSyntax returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(returnType)); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, string returnType, JassParameterListOrEmptyParameterListSyntax parameterList) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + parameterList, + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, string returnType, params JassParameterSyntax[] parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(string name, string returnType, IEnumerable parameters) + { + return new JassNativeFunctionDeclarationSyntax( + Token(JassSyntaxKind.ConstantKeyword), + Token(JassSyntaxKind.NativeKeyword), + ParseIdentifierName(name), + ParameterList(parameters), + ReturnClause(ParseTypeName(returnType))); + } + + public static JassNativeFunctionDeclarationSyntax ConstantNativeFunctionDeclaration(JassSyntaxToken constantToken, JassSyntaxToken nativeToken, JassIdentifierNameSyntax identifierName, JassReturnClauseSyntax returnClause, JassParameterListOrEmptyParameterListSyntax parameterList) + { + ThrowHelper.ThrowIfInvalidToken(constantToken, JassSyntaxKind.ConstantKeyword); + ThrowHelper.ThrowIfInvalidToken(nativeToken, JassSyntaxKind.NativeKeyword); + + return new JassNativeFunctionDeclarationSyntax( + constantToken, + nativeToken, + identifierName, + parameterList, + returnClause); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterFactory.cs index b8c9ebbd..9efceeca 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterFactory.cs @@ -11,6 +11,27 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { + public static JassParameterSyntax Parameter(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassParameterSyntax( + type, + identifierName); + } + + public static JassParameterSyntax Parameter(JassTypeSyntax type, string name) + { + return new JassParameterSyntax( + type, + ParseIdentifierName(name)); + } + + public static JassParameterSyntax Parameter(string type, JassIdentifierNameSyntax identifierName) + { + return new JassParameterSyntax( + ParseTypeName(type), + identifierName); + } + public static JassParameterSyntax Parameter(string type, string name) { return new JassParameterSyntax( diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterListFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterListFactory.cs index e3ff5a83..9847482b 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterListFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParameterListFactory.cs @@ -5,7 +5,8 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Immutable; +using System.Collections.Generic; +using System.Linq; using War3Net.CodeAnalysis.Jass.Syntax; @@ -13,9 +14,48 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassParameterListSyntax ParameterList(params JassParameterSyntax[] parameters) + public static JassParameterListOrEmptyParameterListSyntax ParameterList(params JassParameterSyntax[] parameters) { - return new JassParameterListSyntax(parameters.ToImmutableArray()); + if (parameters.Length == 0) + { + return JassEmptyParameterListSyntax.Value; + } + + return new JassParameterListSyntax( + Token(JassSyntaxKind.TakesKeyword), + SeparatedSyntaxList(JassSyntaxKind.CommaToken, parameters)); + } + + public static JassParameterListOrEmptyParameterListSyntax ParameterList(IEnumerable parameters) + { + if (!parameters.Any()) + { + return JassEmptyParameterListSyntax.Value; + } + + return new JassParameterListSyntax( + Token(JassSyntaxKind.TakesKeyword), + SeparatedSyntaxList(JassSyntaxKind.CommaToken, parameters)); + } + + public static JassParameterListSyntax ParameterList(JassSyntaxToken takesToken, SeparatedSyntaxList parameterList) + { + ThrowHelper.ThrowIfInvalidToken(takesToken, JassSyntaxKind.TakesKeyword); + ThrowHelper.ThrowIfInvalidSeparatedSyntaxList(parameterList, JassSyntaxKind.CommaToken); + + return new JassParameterListSyntax( + takesToken, + parameterList); + } + + public static JassEmptyParameterListSyntax EmptyParameterList(JassSyntaxToken takesToken, JassSyntaxToken nothingToken) + { + ThrowHelper.ThrowIfInvalidToken(takesToken, JassSyntaxKind.TakesKeyword); + ThrowHelper.ThrowIfInvalidToken(nothingToken, JassSyntaxKind.NothingKeyword); + + return new JassEmptyParameterListSyntax( + takesToken, + nothingToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParenthesizedExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParenthesizedExpressionFactory.cs index fa282891..240b583a 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParenthesizedExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ParenthesizedExpressionFactory.cs @@ -11,9 +11,23 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassParenthesizedExpressionSyntax ParenthesizedExpression(IExpressionSyntax expression) + public static JassParenthesizedExpressionSyntax ParenthesizedExpression(JassExpressionSyntax expression) { - return new JassParenthesizedExpressionSyntax(expression); + return new JassParenthesizedExpressionSyntax( + Token(JassSyntaxKind.OpenParenToken), + expression, + Token(JassSyntaxKind.CloseParenToken)); + } + + public static JassParenthesizedExpressionSyntax ParenthesizedExpression(JassSyntaxToken openParenToken, JassExpressionSyntax expression, JassSyntaxToken closeParenToken) + { + ThrowHelper.ThrowIfInvalidToken(openParenToken, JassSyntaxKind.OpenParenToken); + ThrowHelper.ThrowIfInvalidToken(closeParenToken, JassSyntaxKind.CloseParenToken); + + return new JassParenthesizedExpressionSyntax( + openParenToken, + expression, + closeParenToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/PredefinedTypeFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/PredefinedTypeFactory.cs new file mode 100644 index 00000000..99b4aada --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/PredefinedTypeFactory.cs @@ -0,0 +1,27 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Linq; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassPredefinedTypeSyntax PredefinedType(JassSyntaxToken keyword) + { + if (!JassSyntaxFacts.IsPredefinedTypeKeyword(keyword.SyntaxKind)) + { + throw new ArgumentException($"The token's syntax kind must be one of: [ {string.Join(", ", JassSyntaxFacts.GetPredefinedTypeKeywordKinds().Select(predefinedType => $"'{predefinedType}'"))} ].", nameof(keyword)); + } + + return new JassPredefinedTypeSyntax(keyword); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnClauseFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnClauseFactory.cs new file mode 100644 index 00000000..58bd86e5 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnClauseFactory.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassReturnClauseSyntax ReturnClause(JassTypeSyntax returnType) + { + return new JassReturnClauseSyntax( + Token(JassSyntaxKind.ReturnsKeyword), + returnType); + } + + public static JassReturnClauseSyntax ReturnClause(JassSyntaxToken returnsToken, JassTypeSyntax returnType) + { + ThrowHelper.ThrowIfInvalidToken(returnsToken, JassSyntaxKind.ReturnsKeyword); + + return new JassReturnClauseSyntax( + returnsToken, + returnType); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnStatementFactory.cs new file mode 100644 index 00000000..dbc81024 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/ReturnStatementFactory.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassReturnStatementSyntax ReturnStatement(JassExpressionSyntax expression) + { + return new JassReturnStatementSyntax( + Token(JassSyntaxKind.ReturnKeyword), + expression); + } + + public static JassReturnStatementSyntax ReturnStatement(JassSyntaxToken returnToken, JassExpressionSyntax expression) + { + ThrowHelper.ThrowIfInvalidToken(returnToken, JassSyntaxKind.ReturnKeyword); + + return new JassReturnStatementSyntax( + returnToken, + expression); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SeparatedSyntaxListFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SeparatedSyntaxListFactory.cs new file mode 100644 index 00000000..06e1aeb4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SeparatedSyntaxListFactory.cs @@ -0,0 +1,58 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static SeparatedSyntaxList SeparatedSyntaxList(JassSyntaxKind syntaxKind, params TItem[] items) + where TItem : JassSyntaxNode + { + if (items.Length == 0) + { + return SeparatedSyntaxList.Empty; + } + + var builder = SeparatedSyntaxList.CreateBuilder(items[0], items.Length); + for (var i = 1; i < items.Length; i++) + { + builder.Add(Token(syntaxKind), items[i]); + } + + return builder.ToSeparatedSyntaxList(); + } + + public static SeparatedSyntaxList SeparatedSyntaxList(JassSyntaxKind syntaxKind, IEnumerable items) + where TItem : JassSyntaxNode + { + var enumerator = items.GetEnumerator(); + if (!enumerator.MoveNext()) + { + return SeparatedSyntaxList.Empty; + } + + var builder = SeparatedSyntaxList.CreateBuilder(enumerator.Current); + while (enumerator.MoveNext()) + { + builder.Add(Token(syntaxKind), enumerator.Current); + } + + return builder.ToSeparatedSyntaxList(); + } + + public static SeparatedSyntaxList SeparatedSyntaxList(ImmutableArray items, ImmutableArray separators) + where TItem : JassSyntaxNode + { + return SeparatedSyntaxList.Create(items, separators); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SetStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SetStatementFactory.cs index 4189a8be..ec5c40e0 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SetStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SetStatementFactory.cs @@ -11,35 +11,122 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassSetStatementSyntax SetStatement(string name, IExpressionSyntax value) + public static JassSetStatementSyntax SetStatement(JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax value) { return new JassSetStatementSyntax( - ParseIdentifierName(name), + Token(JassSyntaxKind.SetKeyword), + identifierName, + null, + value); + } + + public static JassSetStatementSyntax SetStatement(JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + identifierName, null, - new JassEqualsValueClauseSyntax(value)); + EqualsValueClause(value)); } public static JassSetStatementSyntax SetStatement(string name, JassEqualsValueClauseSyntax value) { return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + ParseIdentifierName(name), + null, + value); + } + + public static JassSetStatementSyntax SetStatement(string name, JassExpressionSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), ParseIdentifierName(name), null, + EqualsValueClause(value)); + } + + public static JassSetStatementSyntax SetStatement(JassIdentifierNameSyntax identifierName, JassElementAccessClauseSyntax elementAccessClause, JassEqualsValueClauseSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + identifierName, + elementAccessClause, + value); + } + + public static JassSetStatementSyntax SetStatement(JassIdentifierNameSyntax identifierName, JassElementAccessClauseSyntax elementAccessClause, JassExpressionSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + identifierName, + elementAccessClause, + EqualsValueClause(value)); + } + + public static JassSetStatementSyntax SetStatement(JassIdentifierNameSyntax identifierName, JassExpressionSyntax elementAccessExpression, JassEqualsValueClauseSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + identifierName, + ElementAccessClause(elementAccessExpression), + value); + } + + public static JassSetStatementSyntax SetStatement(JassIdentifierNameSyntax identifierName, JassExpressionSyntax elementAccessExpression, JassExpressionSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + identifierName, + ElementAccessClause(elementAccessExpression), + EqualsValueClause(value)); + } + + public static JassSetStatementSyntax SetStatement(string name, JassElementAccessClauseSyntax elementAccessClause, JassEqualsValueClauseSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + ParseIdentifierName(name), + elementAccessClause, value); } - public static JassSetStatementSyntax SetStatement(string name, IExpressionSyntax indexer, IExpressionSyntax value) + public static JassSetStatementSyntax SetStatement(string name, JassElementAccessClauseSyntax elementAccessClause, JassExpressionSyntax value) + { + return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), + ParseIdentifierName(name), + elementAccessClause, + EqualsValueClause(value)); + } + + public static JassSetStatementSyntax SetStatement(string name, JassExpressionSyntax elementAccessExpression, JassEqualsValueClauseSyntax value) { return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), ParseIdentifierName(name), - indexer, - new JassEqualsValueClauseSyntax(value)); + ElementAccessClause(elementAccessExpression), + value); } - public static JassSetStatementSyntax SetStatement(string name, IExpressionSyntax indexer, JassEqualsValueClauseSyntax value) + public static JassSetStatementSyntax SetStatement(string name, JassExpressionSyntax elementAccessExpression, JassExpressionSyntax value) { return new JassSetStatementSyntax( + Token(JassSyntaxKind.SetKeyword), ParseIdentifierName(name), - indexer, + ElementAccessClause(elementAccessExpression), + EqualsValueClause(value)); + } + + public static JassSetStatementSyntax SetStatement(JassSyntaxToken setToken, JassIdentifierNameSyntax identifierName, JassElementAccessClauseSyntax? elementAccessClause, JassEqualsValueClauseSyntax value) + { + ThrowHelper.ThrowIfInvalidToken(setToken, JassSyntaxKind.SetKeyword); + + return new JassSetStatementSyntax( + setToken, + identifierName, + elementAccessClause, value); } } diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/StatementListFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/StatementListFactory.cs deleted file mode 100644 index 41499e43..00000000 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/StatementListFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Generic; -using System.Collections.Immutable; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public static partial class JassSyntaxFactory - { - public static JassStatementListSyntax StatementList(IEnumerable statements) - { - return new JassStatementListSyntax(statements.ToImmutableArray()); - } - - public static JassStatementListSyntax StatementList(params IStatementSyntax[] statements) - { - return new JassStatementListSyntax(statements.ToImmutableArray()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs new file mode 100644 index 00000000..d6d21fc7 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.ComponentModel; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + private static readonly Dictionary _defaultTokens = new(); + + public static JassSyntaxToken Token(JassSyntaxKind syntaxKind) + { + if (_defaultTokens.TryGetValue(syntaxKind, out var token)) + { + return token; + } + + var text = JassSyntaxFacts.GetText(syntaxKind); + if (text.Length == 0 && syntaxKind != JassSyntaxKind.EndOfFileToken) + { + throw new InvalidEnumArgumentException(nameof(syntaxKind), (int)syntaxKind, typeof(JassSyntaxKind)); + } + + token = new JassSyntaxToken(JassSyntaxTriviaList.Empty, syntaxKind, text, JassSyntaxTriviaList.Empty); + _defaultTokens.Add(syntaxKind, token); + return token; + } + + public static JassSyntaxToken Token(JassSyntaxTriviaList leadingTrivia, JassSyntaxKind syntaxKind) + { + return Token(leadingTrivia, syntaxKind, JassSyntaxTriviaList.Empty); + } + + public static JassSyntaxToken Token(JassSyntaxKind syntaxKind, JassSyntaxTriviaList trailingTrivia) + { + return Token(JassSyntaxTriviaList.Empty, syntaxKind, trailingTrivia); + } + + public static JassSyntaxToken Token(JassSyntaxKind syntaxKind, string text) + { + return Token(JassSyntaxTriviaList.Empty, syntaxKind, text, JassSyntaxTriviaList.Empty); + } + + public static JassSyntaxToken Token(JassSyntaxTriviaList leadingTrivia, JassSyntaxKind syntaxKind, JassSyntaxTriviaList trailingTrivia) + { + var text = JassSyntaxFacts.GetText(syntaxKind); + if (text.Length == 0 && syntaxKind != JassSyntaxKind.EndOfFileToken) + { + throw new InvalidEnumArgumentException(nameof(syntaxKind), (int)syntaxKind, typeof(JassSyntaxKind)); + } + + return new JassSyntaxToken(leadingTrivia, syntaxKind, text, trailingTrivia); + } + + public static JassSyntaxToken Token(JassSyntaxTriviaList leadingTrivia, JassSyntaxKind syntaxKind, string text, JassSyntaxTriviaList trailingTrivia) + { + var defaultText = JassSyntaxFacts.GetText(syntaxKind); + if (defaultText.Length == 0 && syntaxKind != JassSyntaxKind.EndOfFileToken) + { + var syntaxKindForText = JassSyntaxFacts.GetSyntaxKind(text); + if (syntaxKindForText != JassSyntaxKind.None) + { + throw new ArgumentException($"Text '{text}' is not valid for a token of type '{syntaxKind}', because this text is reserved for tokens of type '{syntaxKindForText}'.", nameof(text)); + } + } + else if (!string.Equals(text, defaultText, StringComparison.Ordinal)) + { + throw new ArgumentException($"Text '{text}' is not valid for a token of type '{syntaxKind}', because the text for this type must be '{defaultText}'.", nameof(text)); + } + + return new JassSyntaxToken(leadingTrivia, syntaxKind, text, trailingTrivia); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs new file mode 100644 index 00000000..7df57047 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs @@ -0,0 +1,81 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.ComponentModel; +using System.Globalization; +using System.Linq; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassSyntaxTrivia SyntaxTrivia(JassSyntaxKind syntaxKind, string text) + { + return syntaxKind switch + { + JassSyntaxKind.NewlineTrivia => NewlineTrivia(text), + JassSyntaxKind.WhitespaceTrivia => WhitespaceTrivia(text), + JassSyntaxKind.SingleLineCommentTrivia => SingleLineCommentTrivia(text), + + _ => throw new InvalidEnumArgumentException(nameof(syntaxKind), (int)syntaxKind, typeof(JassSyntaxKind)), + }; + } + + public static JassSyntaxTrivia NewlineTrivia(string text) + { + if (string.IsNullOrEmpty(text)) + { + throw new ArgumentNullException(nameof(text)); + } + + if (!text.All(c => c == JassSymbol.CarriageReturnChar || c == JassSymbol.LineFeedChar)) + { + throw new ArgumentException("Text may only contain '\\r' and '\\n' characters.", nameof(text)); + } + + return new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, text); + } + + public static JassSyntaxTrivia WhitespaceTrivia(string text) + { + if (string.IsNullOrEmpty(text)) + { + throw new ArgumentNullException(nameof(text)); + } + + if (!text.All(JassSyntaxFacts.IsWhitespaceCharacter)) + { + throw new ArgumentException("Text may only contain whitespace characters (excluding '\\r' and '\\n').", nameof(text)); + } + + return new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, text); + } + + public static JassSyntaxTrivia SingleLineCommentTrivia(string text) + { + if (string.IsNullOrEmpty(text)) + { + throw new ArgumentNullException(nameof(text)); + } + + if (!text.StartsWith(JassSymbol.SlashSlash, false, CultureInfo.InvariantCulture)) + { + throw new ArgumentException("Text must start with \"//\".", nameof(text)); + } + + if (text.Any(c => c == JassSymbol.CarriageReturnChar || c == JassSymbol.LineFeedChar)) + { + throw new ArgumentException("Text may not contain '\\r' or '\\n' characters.", nameof(text)); + } + + return new JassSyntaxTrivia(JassSyntaxKind.SingleLineCommentTrivia, text); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs new file mode 100644 index 00000000..319ad85b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.Collections.Immutable; + +using Pidgin; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassSyntaxTriviaList SyntaxTriviaList(JassSyntaxTrivia trivia) + { + return new JassSyntaxTriviaList(ImmutableArray.Create(trivia)); + } + + public static JassSyntaxTriviaList SyntaxTriviaList(params JassSyntaxTrivia[] trivia) + { + return new JassSyntaxTriviaList(trivia.ToImmutableArray()); + } + + public static JassSyntaxTriviaList SyntaxTriviaList(IEnumerable trivia) + { + return new JassSyntaxTriviaList(trivia.ToImmutableArray()); + } + + public static JassSyntaxTriviaList SyntaxTriviaList(ImmutableArray trivia) + { + return new JassSyntaxTriviaList(trivia); + } + + public static JassSyntaxTriviaList ParseLeadingTrivia(string text) + { + return JassParser.Instance.LeadingTriviaListParser.ParseOrThrow(text); + } + + public static JassSyntaxTriviaList ParseTrailingTrivia(string text) + { + return JassParser.Instance.TrailingTriviaListParser.ParseOrThrow(text); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/TypeDeclarationFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/TypeDeclarationFactory.cs new file mode 100644 index 00000000..449a9bfb --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/TypeDeclarationFactory.cs @@ -0,0 +1,62 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassTypeDeclarationSyntax TypeDeclaration(JassIdentifierNameSyntax identifierName, JassTypeSyntax baseType) + { + return new JassTypeDeclarationSyntax( + Token(JassSyntaxKind.TypeKeyword), + identifierName, + Token(JassSyntaxKind.ExtendsKeyword), + baseType); + } + + public static JassTypeDeclarationSyntax TypeDeclaration(JassIdentifierNameSyntax identifierName, string baseType) + { + return new JassTypeDeclarationSyntax( + Token(JassSyntaxKind.TypeKeyword), + identifierName, + Token(JassSyntaxKind.ExtendsKeyword), + ParseTypeName(baseType)); + } + + public static JassTypeDeclarationSyntax TypeDeclaration(string name, JassTypeSyntax baseType) + { + return new JassTypeDeclarationSyntax( + Token(JassSyntaxKind.TypeKeyword), + ParseIdentifierName(name), + Token(JassSyntaxKind.ExtendsKeyword), + baseType); + } + + public static JassTypeDeclarationSyntax TypeDeclaration(string name, string baseType) + { + return new JassTypeDeclarationSyntax( + Token(JassSyntaxKind.TypeKeyword), + ParseIdentifierName(name), + Token(JassSyntaxKind.ExtendsKeyword), + ParseTypeName(baseType)); + } + + public static JassTypeDeclarationSyntax TypeDeclaration(JassSyntaxToken typeToken, JassIdentifierNameSyntax identifierName, JassSyntaxToken extendsToken, JassTypeSyntax baseType) + { + ThrowHelper.ThrowIfInvalidToken(typeToken, JassSyntaxKind.TypeKeyword); + ThrowHelper.ThrowIfInvalidToken(extendsToken, JassSyntaxKind.ExtendsKeyword); + + return new JassTypeDeclarationSyntax( + typeToken, + identifierName, + extendsToken, + baseType); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs index 866406dc..48fa668e 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs @@ -11,19 +11,35 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassUnaryExpressionSyntax UnaryPlusExpression(IExpressionSyntax expression) + public static JassUnaryExpressionSyntax UnaryPlusExpression(JassExpressionSyntax expression) { - return new JassUnaryExpressionSyntax(UnaryOperatorType.Plus, expression); + return new JassUnaryExpressionSyntax( + Token(JassSyntaxKind.PlusToken), + expression); } - public static JassUnaryExpressionSyntax UnaryMinusExpression(IExpressionSyntax expression) + public static JassUnaryExpressionSyntax UnaryMinusExpression(JassExpressionSyntax expression) { - return new JassUnaryExpressionSyntax(UnaryOperatorType.Minus, expression); + return new JassUnaryExpressionSyntax( + Token(JassSyntaxKind.MinusToken), + expression); } - public static JassUnaryExpressionSyntax UnaryNotExpression(IExpressionSyntax expression) + public static JassUnaryExpressionSyntax UnaryNotExpression(JassExpressionSyntax expression) { - return new JassUnaryExpressionSyntax(UnaryOperatorType.Not, expression); + return new JassUnaryExpressionSyntax( + Token(JassSyntaxKind.NotKeyword), + expression); + } + + public static JassUnaryExpressionSyntax UnaryNotExpression(JassSyntaxToken operatorToken, JassExpressionSyntax expression) + { + // Token validation + JassSyntaxFacts.GetUnaryExpressionKind(operatorToken.SyntaxKind); + + return new JassUnaryExpressionSyntax( + operatorToken, + expression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableDeclaratorFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableDeclaratorFactory.cs new file mode 100644 index 00000000..365cbb1b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableDeclaratorFactory.cs @@ -0,0 +1,110 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public static partial class JassSyntaxFactory + { + public static JassVariableDeclaratorSyntax VariableDeclarator(JassTypeSyntax type, JassIdentifierNameSyntax identifierName) + { + return new JassVariableDeclaratorSyntax( + type, + identifierName, + null); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(JassTypeSyntax type, string name) + { + return new JassVariableDeclaratorSyntax( + type, + ParseIdentifierName(name), + null); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(string type, JassIdentifierNameSyntax identifierName) + { + return new JassVariableDeclaratorSyntax( + ParseTypeName(type), + identifierName, + null); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(string type, string name) + { + return new JassVariableDeclaratorSyntax( + ParseTypeName(type), + ParseIdentifierName(name), + null); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax? value) + { + return new JassVariableDeclaratorSyntax( + type, + identifierName, + value); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(JassTypeSyntax type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassVariableDeclaratorSyntax( + type, + identifierName, + EqualsValueClause(value)); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(JassTypeSyntax type, string name, JassEqualsValueClauseSyntax? value) + { + return new JassVariableDeclaratorSyntax( + type, + ParseIdentifierName(name), + value); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(JassTypeSyntax type, string name, JassExpressionSyntax value) + { + return new JassVariableDeclaratorSyntax( + type, + ParseIdentifierName(name), + EqualsValueClause(value)); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(string type, JassIdentifierNameSyntax identifierName, JassEqualsValueClauseSyntax? value) + { + return new JassVariableDeclaratorSyntax( + ParseTypeName(type), + identifierName, + value); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(string type, JassIdentifierNameSyntax identifierName, JassExpressionSyntax value) + { + return new JassVariableDeclaratorSyntax( + ParseTypeName(type), + identifierName, + EqualsValueClause(value)); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(string type, string name, JassEqualsValueClauseSyntax? value) + { + return new JassVariableDeclaratorSyntax( + ParseTypeName(type), + ParseIdentifierName(name), + value); + } + + public static JassVariableDeclaratorSyntax VariableDeclarator(string type, string name, JassExpressionSyntax value) + { + return new JassVariableDeclaratorSyntax( + ParseTypeName(type), + ParseIdentifierName(name), + EqualsValueClause(value)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableReferenceFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableReferenceFactory.cs deleted file mode 100644 index 5c5506b9..00000000 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/VariableReferenceFactory.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Jass -{ - public static partial class JassSyntaxFactory - { - public static JassVariableReferenceExpressionSyntax VariableReferenceExpression(string name) - { - return new JassVariableReferenceExpressionSyntax(ParseIdentifierName(name)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArgumentListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArgumentListRewriter.cs new file mode 100644 index 00000000..e6ec1963 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArgumentListRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteArgumentList(JassArgumentListSyntax argumentList, out JassArgumentListSyntax result) + { + if (RewriteToken(argumentList.OpenParenToken, out var openParenToken) | + RewriteSeparatedArgumentList(argumentList.ArgumentList, out var separatedArgumentList) | + RewriteToken(argumentList.CloseParenToken, out var closeParenToken)) + { + result = new JassArgumentListSyntax( + openParenToken, + separatedArgumentList, + closeParenToken); + + return true; + } + + result = argumentList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArrayDeclaratorRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArrayDeclaratorRewriter.cs new file mode 100644 index 00000000..a1360699 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ArrayDeclaratorRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteArrayDeclarator(JassArrayDeclaratorSyntax arrayDeclarator, out JassVariableOrArrayDeclaratorSyntax result) + { + if (RewriteType(arrayDeclarator.Type, out var type) | + RewriteToken(arrayDeclarator.ArrayToken, out var arrayToken) | + RewriteIdentifierName(arrayDeclarator.IdentifierName, out var identifierName)) + { + result = new JassArrayDeclaratorSyntax( + type, + arrayToken, + identifierName); + + return true; + } + + result = arrayDeclarator; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/BinaryExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/BinaryExpressionRewriter.cs new file mode 100644 index 00000000..d01be03a --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/BinaryExpressionRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteBinaryExpression(JassBinaryExpressionSyntax binaryExpression, out JassExpressionSyntax result) + { + if (RewriteExpression(binaryExpression.Left, out var left) | + RewriteToken(binaryExpression.OperatorToken, out var operatorToken) | + RewriteExpression(binaryExpression.Right, out var right)) + { + result = new JassBinaryExpressionSyntax( + left, + operatorToken, + right); + + return true; + } + + result = binaryExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CallStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CallStatementRewriter.cs new file mode 100644 index 00000000..b8465d08 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CallStatementRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteCallStatement(JassCallStatementSyntax callStatement, out JassStatementSyntax result) + { + if (RewriteToken(callStatement.CallToken, out var callToken) | + RewriteIdentifierName(callStatement.IdentifierName, out var identifierName) | + RewriteArgumentList(callStatement.ArgumentList, out var argumentList)) + { + result = new JassCallStatementSyntax( + callToken, + identifierName, + argumentList); + + return true; + } + + result = callStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CompilationUnitRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CompilationUnitRewriter.cs new file mode 100644 index 00000000..aa8accb7 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/CompilationUnitRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteCompilationUnit(JassCompilationUnitSyntax compilationUnit, out JassCompilationUnitSyntax result) + { + if (RewriteDeclarationList(compilationUnit.Declarations, out var declarations) | + RewriteToken(compilationUnit.EndOfFileToken, out var endOfFileToken)) + { + result = new JassCompilationUnitSyntax( + declarations, + endOfFileToken); + + return true; + } + + result = compilationUnit; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DebugStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DebugStatementRewriter.cs new file mode 100644 index 00000000..ed74be7e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DebugStatementRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteDebugStatement(JassDebugStatementSyntax debugStatement, out JassStatementSyntax result) + { + if (RewriteToken(debugStatement.DebugToken, out var debugToken) | + RewriteStatement(debugStatement.Statement, out var statement)) + { + result = new JassDebugStatementSyntax( + debugToken, + statement); + + return true; + } + + result = debugStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DeclarationListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DeclarationListRewriter.cs new file mode 100644 index 00000000..821e4525 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/DeclarationListRewriter.cs @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteDeclarationList(ImmutableArray declarationList, out ImmutableArray result) + { + if (declarationList.IsEmpty) + { + result = declarationList; + return false; + } + + for (var i = 0; i < declarationList.Length; i++) + { + if (RewriteTopLevelDeclaration(declarationList[i], out var declaration)) + { + var declarationListBuilder = declarationList.ToBuilder(); + declarationListBuilder[i] = declaration; + + while (++i < declarationList.Length) + { + if (RewriteTopLevelDeclaration(declarationList[i], out declaration)) + { + declarationListBuilder[i] = declaration; + } + } + + result = declarationListBuilder.ToImmutable(); + return true; + } + } + + result = declarationList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessClauseRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessClauseRewriter.cs new file mode 100644 index 00000000..ef07a3a7 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessClauseRewriter.cs @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteElementAccessClause(JassElementAccessClauseSyntax? elementAccessClause, [NotNullIfNotNull("elementAccessClause")] out JassElementAccessClauseSyntax? result) + { + if (elementAccessClause is null) + { + result = null; + return false; + } + + if (RewriteToken(elementAccessClause.OpenBracketToken, out var openBracketToken) | + RewriteExpression(elementAccessClause.Expression, out var expression) | + RewriteToken(elementAccessClause.CloseBracketToken, out var closeBracketToken)) + { + result = new JassElementAccessClauseSyntax( + openBracketToken, + expression, + closeBracketToken); + + return true; + } + + result = elementAccessClause; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessExpressionRewriter.cs new file mode 100644 index 00000000..c1852b2e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElementAccessExpressionRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteElementAccessExpression(JassElementAccessExpressionSyntax elementAccessExpression, out JassExpressionSyntax result) + { + if (RewriteIdentifierName(elementAccessExpression.IdentifierName, out var identifierName) | + RewriteElementAccessClause(elementAccessExpression.ElementAccessClause, out var elementAccessClause)) + { + result = new JassElementAccessExpressionSyntax( + identifierName, + elementAccessClause); + + return true; + } + + result = elementAccessExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseClauseRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseClauseRewriter.cs new file mode 100644 index 00000000..4f2f5faa --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseClauseRewriter.cs @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteElseClause(JassElseClauseSyntax? elseClause, [NotNullIfNotNull("elseClause")] out JassElseClauseSyntax? result) + { + if (elseClause is null) + { + result = null; + return false; + } + + if (RewriteToken(elseClause.ElseToken, out var elseToken) | + RewriteStatementList(elseClause.Statements, out var statements)) + { + result = new JassElseClauseSyntax( + elseToken, + statements); + + return true; + } + + result = elseClause; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseDeclaratorRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseDeclaratorRewriter.cs new file mode 100644 index 00000000..fdbe6e4b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseDeclaratorRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteElseIfClauseDeclarator(JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator, out JassElseIfClauseDeclaratorSyntax result) + { + if (RewriteToken(elseIfClauseDeclarator.ElseIfToken, out var elseIfToken) | + RewriteExpression(elseIfClauseDeclarator.Condition, out var condition) | + RewriteToken(elseIfClauseDeclarator.ThenToken, out var thenToken)) + { + result = new JassElseIfClauseDeclaratorSyntax( + elseIfToken, + condition, + thenToken); + + return true; + } + + result = elseIfClauseDeclarator; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseListRewriter.cs new file mode 100644 index 00000000..925f8a9c --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseListRewriter.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteElseIfClauseList(ImmutableArray elseIfClauseList, out ImmutableArray result) + { + if (elseIfClauseList.IsEmpty) + { + result = elseIfClauseList; + return false; + } + + for (var i = 0; i < elseIfClauseList.Length; i++) + { + if (RewriteElseIfClause(elseIfClauseList[i], out var elseIfClause)) + { + var elseIfClauseListBuilder = ImmutableArray.CreateBuilder(elseIfClauseList.Length); + elseIfClauseListBuilder.AddRange(elseIfClauseList, i); + elseIfClauseListBuilder.Add(elseIfClause); + + while (++i < elseIfClauseList.Length) + { + RewriteElseIfClause(elseIfClauseList[i], out elseIfClause); + elseIfClauseListBuilder.Add(elseIfClause); + } + + result = elseIfClauseListBuilder.ToImmutable(); + return true; + } + } + + result = elseIfClauseList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseRewriter.cs new file mode 100644 index 00000000..fbb55dc4 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ElseIfClauseRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteElseIfClause(JassElseIfClauseSyntax elseIfClause, out JassElseIfClauseSyntax result) + { + if (RewriteElseIfClauseDeclarator(elseIfClause.ElseIfClauseDeclarator, out var elseIfClauseDeclarator) | + RewriteStatementList(elseIfClause.Statements, out var statements)) + { + result = new JassElseIfClauseSyntax( + elseIfClauseDeclarator, + statements); + + return true; + } + + result = elseIfClause; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EmptyParameterListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EmptyParameterListRewriter.cs new file mode 100644 index 00000000..6596df43 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EmptyParameterListRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteEmptyParameterList(JassEmptyParameterListSyntax emptyParameterList, out JassParameterListOrEmptyParameterListSyntax result) + { + if (RewriteToken(emptyParameterList.TakesToken, out var takesToken) | + RewriteToken(emptyParameterList.NothingToken, out var nothingToken)) + { + result = new JassEmptyParameterListSyntax( + takesToken, + nothingToken); + + return true; + } + + result = emptyParameterList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EqualsValueClauseRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EqualsValueClauseRewriter.cs new file mode 100644 index 00000000..4a81a2dd --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/EqualsValueClauseRewriter.cs @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteEqualsValueClause(JassEqualsValueClauseSyntax? equalsValueClause, [NotNullIfNotNull("equalsValueClause")] out JassEqualsValueClauseSyntax? result) + { + if (equalsValueClause is null) + { + result = null; + return false; + } + + if (RewriteToken(equalsValueClause.EqualsToken, out var equalsToken) | + RewriteExpression(equalsValueClause.Expression, out var expression)) + { + result = new JassEqualsValueClauseSyntax( + equalsToken, + expression); + + return true; + } + + result = equalsValueClause; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExitStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExitStatementRewriter.cs new file mode 100644 index 00000000..b721f446 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExitStatementRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteExitStatement(JassExitStatementSyntax exitStatement, out JassStatementSyntax result) + { + if (RewriteToken(exitStatement.ExitWhenToken, out var exitWhenToken) | + RewriteExpression(exitStatement.Condition, out var condition)) + { + result = new JassExitStatementSyntax( + exitWhenToken, + condition); + + return true; + } + + result = exitStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExpressionRewriter.cs new file mode 100644 index 00000000..cde23ea9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ExpressionRewriter.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteExpression(JassExpressionSyntax? expression, [NotNullIfNotNull("expression")] out JassExpressionSyntax? result) + { + if (expression is null) + { + result = null; + return false; + } + + return expression switch + { + JassElementAccessExpressionSyntax elementAccessExpression => RewriteElementAccessExpression(elementAccessExpression, out result), + JassBinaryExpressionSyntax binaryExpression => RewriteBinaryExpression(binaryExpression, out result), + JassFunctionReferenceExpressionSyntax functionReferenceExpression => RewriteFunctionReferenceExpression(functionReferenceExpression, out result), + JassIdentifierNameSyntax identifierName => RewriteIdentifierNameAsExpression(identifierName, out result), + JassInvocationExpressionSyntax invocationExpression => RewriteInvocationExpression(invocationExpression, out result), + JassLiteralExpressionSyntax literalExpression => RewriteLiteralExpression(literalExpression, out result), + JassParenthesizedExpressionSyntax parenthesizedExpression => RewriteParenthesizedExpression(parenthesizedExpression, out result), + JassUnaryExpressionSyntax unaryExpression => RewriteUnaryExpression(unaryExpression, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclarationRewriter.cs new file mode 100644 index 00000000..ca5de1fa --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclarationRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteFunctionDeclaration(JassFunctionDeclarationSyntax functionDeclaration, out JassTopLevelDeclarationSyntax result) + { + if (RewriteFunctionDeclarator(functionDeclaration.FunctionDeclarator, out var functionDeclarator) | + RewriteStatementList(functionDeclaration.Statements, out var statements) | + RewriteToken(functionDeclaration.EndFunctionToken, out var endFunctionToken)) + { + result = new JassFunctionDeclarationSyntax( + functionDeclarator, + statements, + endFunctionToken); + + return true; + } + + result = functionDeclaration; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclaratorRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclaratorRewriter.cs new file mode 100644 index 00000000..87a44c9e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionDeclaratorRewriter.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteFunctionDeclarator(JassFunctionDeclaratorSyntax functionDeclarator, out JassFunctionDeclaratorSyntax result) + { + if (RewriteToken(functionDeclarator.ConstantToken, out var constantToken) | + RewriteToken(functionDeclarator.FunctionToken, out var functionToken) | + RewriteIdentifierName(functionDeclarator.IdentifierName, out var identifierName) | + RewriteParameterListOrEmptyParameterList(functionDeclarator.ParameterList, out var parameterList) | + RewriteReturnClause(functionDeclarator.ReturnClause, out var returnClause)) + { + result = new JassFunctionDeclaratorSyntax( + constantToken, + functionToken, + identifierName, + parameterList, + returnClause); + + return true; + } + + result = functionDeclarator; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionReferenceExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionReferenceExpressionRewriter.cs new file mode 100644 index 00000000..5cd136ab --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/FunctionReferenceExpressionRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteFunctionReferenceExpression(JassFunctionReferenceExpressionSyntax functionReferenceExpression, out JassExpressionSyntax result) + { + if (RewriteToken(functionReferenceExpression.FunctionToken, out var functionToken) | + RewriteIdentifierName(functionReferenceExpression.IdentifierName, out var identifierName)) + { + result = new JassFunctionReferenceExpressionSyntax( + functionToken, + identifierName); + + return true; + } + + result = functionReferenceExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalConstantDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalConstantDeclarationRewriter.cs new file mode 100644 index 00000000..81cc612b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalConstantDeclarationRewriter.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteGlobalConstantDeclaration(JassGlobalConstantDeclarationSyntax globalConstantDeclaration, out JassGlobalDeclarationSyntax result) + { + if (RewriteToken(globalConstantDeclaration.ConstantToken, out var constantToken) | + RewriteType(globalConstantDeclaration.Type, out var type) | + RewriteIdentifierName(globalConstantDeclaration.IdentifierName, out var identifierName) | + RewriteEqualsValueClause(globalConstantDeclaration.Value, out var value)) + { + result = new JassGlobalConstantDeclarationSyntax( + constantToken, + type, + identifierName, + value); + + return true; + } + + result = globalConstantDeclaration; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationListRewriter.cs new file mode 100644 index 00000000..6dc27dab --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationListRewriter.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteGlobalDeclarationList(ImmutableArray globalDeclarationList, out ImmutableArray result) + { + if (globalDeclarationList.IsEmpty) + { + result = globalDeclarationList; + return false; + } + + for (var i = 0; i < globalDeclarationList.Length; i++) + { + if (RewriteGlobalDeclaration(globalDeclarationList[i], out var globalDeclaration)) + { + var globalDeclarationListBuilder = ImmutableArray.CreateBuilder(globalDeclarationList.Length); + globalDeclarationListBuilder.AddRange(globalDeclarationList, i); + globalDeclarationListBuilder.Add(globalDeclaration); + + while (++i < globalDeclarationList.Length) + { + RewriteGlobalDeclaration(globalDeclarationList[i], out globalDeclaration); + globalDeclarationListBuilder.Add(globalDeclaration); + } + + result = globalDeclarationListBuilder.ToImmutable(); + return true; + } + } + + result = globalDeclarationList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationRewriter.cs new file mode 100644 index 00000000..9f05e40e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalDeclarationRewriter.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteGlobalDeclaration(JassGlobalDeclarationSyntax globalDeclaration, out JassGlobalDeclarationSyntax result) + { + return globalDeclaration switch + { + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => RewriteGlobalConstantDeclaration(globalConstantDeclaration, out result), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => RewriteGlobalVariableDeclaration(globalVariableDeclaration, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalVariableDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalVariableDeclarationRewriter.cs new file mode 100644 index 00000000..e474a0b0 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalVariableDeclarationRewriter.cs @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteGlobalVariableDeclaration(JassGlobalVariableDeclarationSyntax globalVariableDeclaration, out JassGlobalDeclarationSyntax result) + { + if (RewriteVariableOrArrayDeclarator(globalVariableDeclaration.Declarator, out var declarator)) + { + result = new JassGlobalVariableDeclarationSyntax(declarator); + return true; + } + + result = globalVariableDeclaration; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalsDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalsDeclarationRewriter.cs new file mode 100644 index 00000000..40650032 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/GlobalsDeclarationRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteGlobalsDeclaration(JassGlobalsDeclarationSyntax globalsDeclaration, out JassTopLevelDeclarationSyntax result) + { + if (RewriteToken(globalsDeclaration.GlobalsToken, out var globalsToken) | + RewriteGlobalDeclarationList(globalsDeclaration.GlobalDeclarations, out var globalDeclarations) | + RewriteToken(globalsDeclaration.EndGlobalsToken, out var endGlobalsToken)) + { + result = new JassGlobalsDeclarationSyntax( + globalsToken, + globalDeclarations, + endGlobalsToken); + + return true; + } + + result = globalsDeclaration; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IdentifierNameRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IdentifierNameRewriter.cs new file mode 100644 index 00000000..86018ba6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IdentifierNameRewriter.cs @@ -0,0 +1,59 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteIdentifierName(JassIdentifierNameSyntax identifierName, out JassIdentifierNameSyntax result) + { + if (RewriteToken(identifierName.Token, out var token)) + { + result = new JassIdentifierNameSyntax(token); + return true; + } + + result = identifierName; + return false; + } + + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteIdentifierNameAsExpression(JassIdentifierNameSyntax identifierName, out JassExpressionSyntax result) + { + if (RewriteToken(identifierName.Token, out var token)) + { + result = new JassIdentifierNameSyntax(token); + return true; + } + + result = identifierName; + return false; + } + + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteIdentifierNameAsType(JassIdentifierNameSyntax identifierName, out JassTypeSyntax result) + { + if (RewriteToken(identifierName.Token, out var token)) + { + result = new JassIdentifierNameSyntax(token); + return true; + } + + result = identifierName; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseDeclaratorRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseDeclaratorRewriter.cs new file mode 100644 index 00000000..c878c047 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseDeclaratorRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteIfClauseDeclarator(JassIfClauseDeclaratorSyntax ifClauseDeclarator, out JassIfClauseDeclaratorSyntax result) + { + if (RewriteToken(ifClauseDeclarator.IfToken, out var ifToken) | + RewriteExpression(ifClauseDeclarator.Condition, out var condition) | + RewriteToken(ifClauseDeclarator.ThenToken, out var thenToken)) + { + result = new JassIfClauseDeclaratorSyntax( + ifToken, + condition, + thenToken); + + return true; + } + + result = ifClauseDeclarator; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseRewriter.cs new file mode 100644 index 00000000..b0f1b9d3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfClauseRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteIfClause(JassIfClauseSyntax ifClause, out JassIfClauseSyntax result) + { + if (RewriteIfClauseDeclarator(ifClause.IfClauseDeclarator, out var ifClauseDeclarator) | + RewriteStatementList(ifClause.Statements, out var statements)) + { + result = new JassIfClauseSyntax( + ifClauseDeclarator, + statements); + + return true; + } + + result = ifClause; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfStatementRewriter.cs new file mode 100644 index 00000000..60e091c6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/IfStatementRewriter.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteIfStatement(JassIfStatementSyntax ifStatement, out JassStatementSyntax result) + { + if (RewriteIfClause(ifStatement.IfClause, out var ifClause) | + RewriteElseIfClauseList(ifStatement.ElseIfClauses, out var elseIfClauses) | + RewriteElseClause(ifStatement.ElseClause, out var elseClause) | + RewriteToken(ifStatement.EndIfToken, out var endIfToken)) + { + result = new JassIfStatementSyntax( + ifClause, + elseIfClauses, + elseClause, + endIfToken); + + return true; + } + + result = ifStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/InvocationExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/InvocationExpressionRewriter.cs new file mode 100644 index 00000000..836a517e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/InvocationExpressionRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteInvocationExpression(JassInvocationExpressionSyntax invocationExpression, out JassExpressionSyntax result) + { + if (RewriteIdentifierName(invocationExpression.IdentifierName, out var identifierName) | + RewriteArgumentList(invocationExpression.ArgumentList, out var argumentList)) + { + result = new JassInvocationExpressionSyntax( + identifierName, + argumentList); + + return true; + } + + result = invocationExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LiteralExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LiteralExpressionRewriter.cs new file mode 100644 index 00000000..3a850b3a --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LiteralExpressionRewriter.cs @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteLiteralExpression(JassLiteralExpressionSyntax literalExpression, out JassExpressionSyntax result) + { + if (RewriteToken(literalExpression.Token, out var token)) + { + result = new JassLiteralExpressionSyntax(token); + return true; + } + + result = literalExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LocalVariableDeclarationStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LocalVariableDeclarationStatementRewriter.cs new file mode 100644 index 00000000..6c2814e2 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LocalVariableDeclarationStatementRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteLocalVariableDeclarationStatement(JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement, out JassStatementSyntax result) + { + if (RewriteToken(localVariableDeclarationStatement.LocalToken, out var localToken) | + RewriteVariableOrArrayDeclarator(localVariableDeclarationStatement.Declarator, out var declarator)) + { + result = new JassLocalVariableDeclarationStatementSyntax( + localToken, + declarator); + + return true; + } + + result = localVariableDeclarationStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LoopStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LoopStatementRewriter.cs new file mode 100644 index 00000000..79640b1e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/LoopStatementRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteLoopStatement(JassLoopStatementSyntax loopStatement, out JassStatementSyntax result) + { + if (RewriteToken(loopStatement.LoopToken, out var loopToken) | + RewriteStatementList(loopStatement.Statements, out var statements) | + RewriteToken(loopStatement.EndLoopToken, out var endLoopToken)) + { + result = new JassLoopStatementSyntax( + loopToken, + statements, + endLoopToken); + + return true; + } + + result = loopStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/NativeFunctionDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/NativeFunctionDeclarationRewriter.cs new file mode 100644 index 00000000..f682ef89 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/NativeFunctionDeclarationRewriter.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteNativeFunctionDeclaration(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration, out JassTopLevelDeclarationSyntax result) + { + if (RewriteToken(nativeFunctionDeclaration.ConstantToken, out var constantToken) | + RewriteToken(nativeFunctionDeclaration.NativeToken, out var nativeToken) | + RewriteIdentifierName(nativeFunctionDeclaration.IdentifierName, out var identifierName) | + RewriteParameterListOrEmptyParameterList(nativeFunctionDeclaration.ParameterList, out var parameterList) | + RewriteReturnClause(nativeFunctionDeclaration.ReturnClause, out var returnClause)) + { + result = new JassNativeFunctionDeclarationSyntax( + constantToken, + nativeToken, + identifierName, + parameterList, + returnClause); + + return true; + } + + result = nativeFunctionDeclaration; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListOrEmptyParameterListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListOrEmptyParameterListRewriter.cs new file mode 100644 index 00000000..45caba94 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListOrEmptyParameterListRewriter.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteParameterListOrEmptyParameterList(JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList, out JassParameterListOrEmptyParameterListSyntax result) + { + return parameterListOrEmptyParameterList switch + { + JassEmptyParameterListSyntax emptyParameterList => RewriteEmptyParameterList(emptyParameterList, out result), + JassParameterListSyntax parameterList => RewriteParameterList(parameterList, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListRewriter.cs new file mode 100644 index 00000000..da872480 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterListRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteParameterList(JassParameterListSyntax parameterList, out JassParameterListOrEmptyParameterListSyntax result) + { + if (RewriteToken(parameterList.TakesToken, out var takesToken) | + RewriteSeparatedParameterList(parameterList.ParameterList, out var separatedParameterList)) + { + result = new JassParameterListSyntax( + takesToken, + separatedParameterList); + + return true; + } + + result = parameterList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterRewriter.cs new file mode 100644 index 00000000..271d24cf --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParameterRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteParameter(JassParameterSyntax parameter, out JassParameterSyntax result) + { + if (RewriteType(parameter.Type, out var type) | + RewriteIdentifierName(parameter.IdentifierName, out var identifierName)) + { + result = new JassParameterSyntax( + type, + identifierName); + + return true; + } + + result = parameter; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParenthesizedExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParenthesizedExpressionRewriter.cs new file mode 100644 index 00000000..ab12508f --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ParenthesizedExpressionRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteParenthesizedExpression(JassParenthesizedExpressionSyntax parenthesizedExpression, out JassExpressionSyntax result) + { + if (RewriteToken(parenthesizedExpression.OpenParenToken, out var openParenToken) | + RewriteExpression(parenthesizedExpression.Expression, out var expression) | + RewriteToken(parenthesizedExpression.CloseParenToken, out var closeParenToken)) + { + result = new JassParenthesizedExpressionSyntax( + openParenToken, + expression, + closeParenToken); + + return true; + } + + result = parenthesizedExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/PredefinedTypeRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/PredefinedTypeRewriter.cs new file mode 100644 index 00000000..37a8f463 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/PredefinedTypeRewriter.cs @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewritePredefinedType(JassPredefinedTypeSyntax predefinedType, out JassTypeSyntax result) + { + if (RewriteToken(predefinedType.Token, out var token)) + { + result = new JassPredefinedTypeSyntax(token); + return true; + } + + result = predefinedType; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnClauseRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnClauseRewriter.cs new file mode 100644 index 00000000..e7075f72 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnClauseRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteReturnClause(JassReturnClauseSyntax returnClause, out JassReturnClauseSyntax result) + { + if (RewriteToken(returnClause.ReturnsToken, out var returnsToken) | + RewriteType(returnClause.ReturnType, out var returnType)) + { + result = new JassReturnClauseSyntax( + returnsToken, + returnType); + + return true; + } + + result = returnClause; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnStatementRewriter.cs new file mode 100644 index 00000000..26072877 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/ReturnStatementRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteReturnStatement(JassReturnStatementSyntax returnStatement, out JassStatementSyntax result) + { + if (RewriteToken(returnStatement.ReturnToken, out var returnToken) | + RewriteExpression(returnStatement.Value, out var value)) + { + result = new JassReturnStatementSyntax( + returnToken, + value); + + return true; + } + + result = returnStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedArgumentListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedArgumentListRewriter.cs new file mode 100644 index 00000000..6bbbddf3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedArgumentListRewriter.cs @@ -0,0 +1,70 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteSeparatedArgumentList(SeparatedSyntaxList argumentList, out SeparatedSyntaxList result) + { + if (argumentList.IsEmpty) + { + result = argumentList; + return false; + } + + if (RewriteExpression(argumentList.Items[0], out var item)) + { + var argumentListBuilder = SeparatedSyntaxList.CreateBuilder(item, argumentList.Items.Length); + for (var i = 1; i < argumentList.Items.Length; i++) + { + RewriteToken(argumentList.Separators[i - 1], out var separator); + RewriteExpression(argumentList.Items[i], out item); + + argumentListBuilder.Add(separator, item); + } + + result = argumentListBuilder.ToSeparatedSyntaxList(); + return true; + } + + for (var i = 1; i < argumentList.Items.Length; i++) + { + if (RewriteToken(argumentList.Separators[i - 1], out var separator) | + RewriteExpression(argumentList.Items[i], out item)) + { + var argumentListBuilder = SeparatedSyntaxList.CreateBuilder(argumentList.Items[0], argumentList.Items.Length); + for (var j = 1; j < i; j++) + { + argumentListBuilder.Add(argumentList.Separators[j - 1], argumentList.Items[j]); + } + + argumentListBuilder.Add(separator, item); + + while (++i < argumentList.Items.Length) + { + RewriteToken(argumentList.Separators[i - 1], out separator); + RewriteExpression(argumentList.Items[i], out item); + + argumentListBuilder.Add(separator, item); + } + + result = argumentListBuilder.ToSeparatedSyntaxList(); + return true; + } + } + + result = argumentList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedParameterListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedParameterListRewriter.cs new file mode 100644 index 00000000..89b9e2cb --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SeparatedParameterListRewriter.cs @@ -0,0 +1,70 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteSeparatedParameterList(SeparatedSyntaxList parameterList, out SeparatedSyntaxList result) + { + if (parameterList.IsEmpty) + { + result = parameterList; + return false; + } + + if (RewriteParameter(parameterList.Items[0], out var item)) + { + var parameterListBuilder = SeparatedSyntaxList.CreateBuilder(item, parameterList.Items.Length); + for (var i = 1; i < parameterList.Items.Length; i++) + { + RewriteToken(parameterList.Separators[i - 1], out var separator); + RewriteParameter(parameterList.Items[i], out item); + + parameterListBuilder.Add(separator, item); + } + + result = parameterListBuilder.ToSeparatedSyntaxList(); + return true; + } + + for (var i = 1; i < parameterList.Items.Length; i++) + { + if (RewriteToken(parameterList.Separators[i - 1], out var separator) | + RewriteParameter(parameterList.Items[i], out item)) + { + var parameterListBuilder = SeparatedSyntaxList.CreateBuilder(parameterList.Items[0], parameterList.Items.Length); + for (var j = 1; j < i; j++) + { + parameterListBuilder.Add(parameterList.Separators[j - 1], parameterList.Items[j]); + } + + parameterListBuilder.Add(separator, item); + + while (++i < parameterList.Items.Length) + { + RewriteToken(parameterList.Separators[i - 1], out separator); + RewriteParameter(parameterList.Items[i], out item); + + parameterListBuilder.Add(separator, item); + } + + result = parameterListBuilder.ToSeparatedSyntaxList(); + return true; + } + } + + result = parameterList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SetStatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SetStatementRewriter.cs new file mode 100644 index 00000000..77c9aac9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SetStatementRewriter.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteSetStatement(JassSetStatementSyntax setStatement, out JassStatementSyntax result) + { + if (RewriteToken(setStatement.SetToken, out var setToken) | + RewriteIdentifierName(setStatement.IdentifierName, out var identifierName) | + RewriteElementAccessClause(setStatement.ElementAccessClause, out var elementAccessClause) | + RewriteEqualsValueClause(setStatement.Value, out var value)) + { + result = new JassSetStatementSyntax( + setToken, + identifierName, + elementAccessClause, + value); + + return true; + } + + result = setStatement; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementListRewriter.cs new file mode 100644 index 00000000..04af3aba --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementListRewriter.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Immutable; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteStatementList(ImmutableArray statementList, out ImmutableArray result) + { + if (statementList.IsEmpty) + { + result = statementList; + return false; + } + + for (var i = 0; i < statementList.Length; i++) + { + if (RewriteStatement(statementList[i], out var statement)) + { + var statementListBuilder = ImmutableArray.CreateBuilder(statementList.Length); + statementListBuilder.AddRange(statementList, i); + statementListBuilder.Add(statement); + + while (++i < statementList.Length) + { + RewriteStatement(statementList[i], out statement); + statementListBuilder.Add(statement); + } + + result = statementListBuilder.ToImmutable(); + return true; + } + } + + result = statementList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementRewriter.cs new file mode 100644 index 00000000..062acefc --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/StatementRewriter.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteStatement(JassStatementSyntax statement, out JassStatementSyntax result) + { + return statement switch + { + JassCallStatementSyntax callStatement => RewriteCallStatement(callStatement, out result), + JassDebugStatementSyntax debugStatement => RewriteDebugStatement(debugStatement, out result), + JassExitStatementSyntax exitStatement => RewriteExitStatement(exitStatement, out result), + JassIfStatementSyntax ifStatement => RewriteIfStatement(ifStatement, out result), + JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement => RewriteLocalVariableDeclarationStatement(localVariableDeclarationStatement, out result), + JassLoopStatementSyntax loopStatement => RewriteLoopStatement(loopStatement, out result), + JassReturnStatementSyntax returnStatement => RewriteReturnStatement(returnStatement, out result), + JassSetStatementSyntax setStatement => RewriteSetStatement(setStatement, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTokenRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTokenRewriter.cs new file mode 100644 index 00000000..1b23e03b --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTokenRewriter.cs @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Diagnostics.CodeAnalysis; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteToken(JassSyntaxToken? token, [NotNullIfNotNull("token")] out JassSyntaxToken? result) + { + if (token is null) + { + result = null; + return false; + } + + if (RewriteLeadingTrivia(token.LeadingTrivia, out var leadingTrivia) | + RewriteTrailingTrivia(token.TrailingTrivia, out var trailingTrivia)) + { + result = new JassSyntaxToken( + leadingTrivia, + token.SyntaxKind, + token.Text, + trailingTrivia); + + return true; + } + + result = token; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTriviaListRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTriviaListRewriter.cs new file mode 100644 index 00000000..bb7773d8 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/SyntaxTriviaListRewriter.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteLeadingTrivia(JassSyntaxTriviaList triviaList, out JassSyntaxTriviaList result) + { + result = triviaList; + return false; + } + + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteTrailingTrivia(JassSyntaxTriviaList triviaList, out JassSyntaxTriviaList result) + { + result = triviaList; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TopLevelDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TopLevelDeclarationRewriter.cs new file mode 100644 index 00000000..1693baa9 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TopLevelDeclarationRewriter.cs @@ -0,0 +1,28 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteTopLevelDeclaration(JassTopLevelDeclarationSyntax topLevelDeclaration, out JassTopLevelDeclarationSyntax result) + { + return topLevelDeclaration switch + { + JassFunctionDeclarationSyntax functionDeclaration => RewriteFunctionDeclaration(functionDeclaration, out result), + JassGlobalsDeclarationSyntax globalsDeclaration => RewriteGlobalsDeclaration(globalsDeclaration, out result), + JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration => RewriteNativeFunctionDeclaration(nativeFunctionDeclaration, out result), + JassTypeDeclarationSyntax typeDeclaration => RewriteTypeDeclaration(typeDeclaration, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeDeclarationRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeDeclarationRewriter.cs new file mode 100644 index 00000000..ff438385 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeDeclarationRewriter.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteTypeDeclaration(JassTypeDeclarationSyntax typeDeclaration, out JassTopLevelDeclarationSyntax result) + { + if (RewriteToken(typeDeclaration.TypeToken, out var typeToken) | + RewriteIdentifierName(typeDeclaration.IdentifierName, out var identifierName) | + RewriteToken(typeDeclaration.ExtendsToken, out var extendsToken) | + RewriteType(typeDeclaration.BaseType, out var baseType)) + { + result = new JassTypeDeclarationSyntax( + typeToken, + identifierName, + extendsToken, + baseType); + + return true; + } + + result = typeDeclaration; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeRewriter.cs new file mode 100644 index 00000000..35f990f3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/TypeRewriter.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteType(JassTypeSyntax type, out JassTypeSyntax result) + { + return type switch + { + JassIdentifierNameSyntax identifierName => RewriteIdentifierNameAsType(identifierName, out result), + JassPredefinedTypeSyntax predefinedType => RewritePredefinedType(predefinedType, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/UnaryExpressionRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/UnaryExpressionRewriter.cs new file mode 100644 index 00000000..1efac5c6 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/UnaryExpressionRewriter.cs @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteUnaryExpression(JassUnaryExpressionSyntax unaryExpression, out JassExpressionSyntax result) + { + if (RewriteToken(unaryExpression.OperatorToken, out var operatorToken) | + RewriteExpression(unaryExpression.Expression, out var expression)) + { + result = new JassUnaryExpressionSyntax( + operatorToken, + expression); + + return true; + } + + result = unaryExpression; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableDeclaratorRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableDeclaratorRewriter.cs new file mode 100644 index 00000000..58951625 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableDeclaratorRewriter.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteVariableDeclarator(JassVariableDeclaratorSyntax variableDeclarator, out JassVariableOrArrayDeclaratorSyntax result) + { + if (RewriteType(variableDeclarator.Type, out var type) | + RewriteIdentifierName(variableDeclarator.IdentifierName, out var identifierName) | + RewriteEqualsValueClause(variableDeclarator.Value, out var value)) + { + result = new JassVariableDeclaratorSyntax( + type, + identifierName, + value); + + return true; + } + + result = variableDeclarator; + return false; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableOrArrayDeclaratorRewriter.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableOrArrayDeclaratorRewriter.cs new file mode 100644 index 00000000..b50dda24 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxRewriter/VariableOrArrayDeclaratorRewriter.cs @@ -0,0 +1,26 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass +{ + public abstract partial class JassSyntaxRewriter + { + /// The to rewrite. + /// The rewritten , or the input if it wasn't rewritten. + /// if the was rewritten to , otherwise . + protected virtual bool RewriteVariableOrArrayDeclarator(JassVariableOrArrayDeclaratorSyntax variableOrArrayDeclarator, out JassVariableOrArrayDeclaratorSyntax result) + { + return variableOrArrayDeclarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => RewriteArrayDeclarator(arrayDeclarator, out result), + JassVariableDeclaratorSyntax variableDeclarator => RewriteVariableDeclarator(variableDeclarator, out result), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj b/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj index 6395a902..fc086c35 100644 --- a/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj +++ b/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj @@ -9,12 +9,12 @@ jass;warcraft3 - + - + From 01027f2ad9bec0bf8e1a3960f8fce5fef7ad2417 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 1 Nov 2025 10:34:13 +0100 Subject: [PATCH 02/53] Apply War3Net.CodeAnalysis changes from vjass branch This commit applies the necessary changes from the vjass branch to the War3Net.CodeAnalysis project to support the new JASS syntax system. Changes: - Added SeparatedSyntaxList.IsEmpty property - Added SeparatedSyntaxList.Create(item) method - Added SeparatedSyntaxList.CreateBuilder(item, capacity) overload - Added SeparatedSyntaxList.Builder(item, capacity) constructor - Updated IfThenElseParser, SeparatedParser, and UntilWithLeadingParser --- src/War3Net.CodeAnalysis/IfThenElseParser.cs | 12 +++++++++ src/War3Net.CodeAnalysis/SeparatedParser.cs | 9 +++++++ .../SeparatedSyntaxList.cs | 26 +++++++++++++++++++ .../UntilWithLeadingParser.cs | 4 +++ 4 files changed, 51 insertions(+) diff --git a/src/War3Net.CodeAnalysis/IfThenElseParser.cs b/src/War3Net.CodeAnalysis/IfThenElseParser.cs index 88c7ca61..30f7152c 100644 --- a/src/War3Net.CodeAnalysis/IfThenElseParser.cs +++ b/src/War3Net.CodeAnalysis/IfThenElseParser.cs @@ -185,6 +185,12 @@ public override bool TryParse( if (state.Location <= terminatorStartLoc) { + leadingExpecteds.Dispose(); + elseIfExpecteds.Dispose(); + elseExpecteds.Dispose(); + endIfExpecteds.Dispose(); + itemExpecteds.Dispose(); + throw new InvalidOperationException("IfThenElse() used with an elseif parser which consumed no input"); } @@ -252,6 +258,12 @@ public override bool TryParse( if (state.Location <= itemStartLoc) { + leadingExpecteds.Dispose(); + elseIfExpecteds.Dispose(); + elseExpecteds.Dispose(); + endIfExpecteds.Dispose(); + itemExpecteds.Dispose(); + throw new InvalidOperationException("IfThenElse() used with a parser which consumed no input"); } diff --git a/src/War3Net.CodeAnalysis/SeparatedParser.cs b/src/War3Net.CodeAnalysis/SeparatedParser.cs index c44183dc..3094bed4 100644 --- a/src/War3Net.CodeAnalysis/SeparatedParser.cs +++ b/src/War3Net.CodeAnalysis/SeparatedParser.cs @@ -30,8 +30,15 @@ public override bool TryParse( ref PooledList> expecteds, [MaybeNullWhen(false)] out SeparatedSyntaxList result) { + var startLoc = state.Location; if (!_itemParser.TryParse(ref state, ref expecteds, out var firstResult)) { + if (state.Location > startLoc) + { + result = null; + return false; + } + result = SeparatedSyntaxList.Empty; return true; } @@ -72,6 +79,8 @@ public override bool TryParse( if (state.Location <= itemStartLoc) { + childExpecteds.Dispose(); + throw new InvalidOperationException("Separated() used with a parser which consumed no input"); } diff --git a/src/War3Net.CodeAnalysis/SeparatedSyntaxList.cs b/src/War3Net.CodeAnalysis/SeparatedSyntaxList.cs index 0285eeb4..b01044df 100644 --- a/src/War3Net.CodeAnalysis/SeparatedSyntaxList.cs +++ b/src/War3Net.CodeAnalysis/SeparatedSyntaxList.cs @@ -34,6 +34,13 @@ private SeparatedSyntaxList(ImmutableArray items, ImmutableArray Separators => _separators; + public bool IsEmpty => _items.IsEmpty; + + public static SeparatedSyntaxList Create(TItem item) + { + return new SeparatedSyntaxList(ImmutableArray.Create(item), ImmutableArray.Empty); + } + public static SeparatedSyntaxList Create(ImmutableArray items, ImmutableArray separators) { if (items.IsEmpty) @@ -42,6 +49,8 @@ public static SeparatedSyntaxList Create(ImmutableArray(); } + internal Builder(TItem firstItem, int initialCapacity) + { + _itemBuilder = ImmutableArray.CreateBuilder(initialCapacity); + _itemBuilder.Add(firstItem); + _separatorBuilder = ImmutableArray.CreateBuilder(initialCapacity - 1); + } + public void Add(TSeparator separator, TItem item) { _itemBuilder.Add(item); diff --git a/src/War3Net.CodeAnalysis/UntilWithLeadingParser.cs b/src/War3Net.CodeAnalysis/UntilWithLeadingParser.cs index 7a15c3dc..35bd29a9 100644 --- a/src/War3Net.CodeAnalysis/UntilWithLeadingParser.cs +++ b/src/War3Net.CodeAnalysis/UntilWithLeadingParser.cs @@ -113,6 +113,10 @@ public override bool TryParse( if (state.Location <= itemStartLoc) { + leadingExpecteds.Dispose(); + closeExpecteds.Dispose(); + itemExpecteds.Dispose(); + throw new InvalidOperationException("UntilWithLeading() used with a parser which consumed no input"); } From 954314f5f58744292f7dfbbb3d7177bce0500c1a Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 1 Nov 2025 10:41:13 +0100 Subject: [PATCH 03/53] Add FunctionDeclarationParser and update test helpers Changes to War3Net.CodeAnalysis.Jass: - Added FunctionDeclarationParser property that throws NotImplementedException The new JASS syntax system doesn't support parsing function declarations in isolation (they require context for the optional 'constant' keyword). Users should use TopLevelDeclarationParser instead. Changes to War3Net.TestTools.UnitTesting: - Updated SyntaxAssert from vjass branch to use new base classes instead of removed interfaces (IExpressionSyntax, IStatementSyntax, etc.) - Changed from NullableEquals() to NullableEquivalentTo() extension method - Commented out methods for removed "Line" syntax types - Updated TestDataProvider with improved error handling All 127 JASS tests now pass. --- src/War3Net.CodeAnalysis.Jass/JassParser.cs | 2 + .../SyntaxAssert.cs | 148 +++++++++--------- .../TestDataProvider.cs | 4 + 3 files changed, 80 insertions(+), 74 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser.cs index f5deed47..59b215e7 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser.cs @@ -164,6 +164,8 @@ private JassParser() internal Parser ExpressionParser => _expressionParser; + internal Parser FunctionDeclarationParser => throw new NotImplementedException("FunctionDeclarationParser is not supported in the new syntax system. Use TopLevelDeclarationParser instead."); + internal Parser GlobalDeclarationParser => _globalDeclarationParser; internal Parser IdentifierNameParser => _identifierNameParser; diff --git a/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs b/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs index 841d519a..db5f81d9 100644 --- a/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs +++ b/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs @@ -22,55 +22,55 @@ public static class SyntaxAssert { public static void AreEqual(JassCompilationUnitSyntax? expected, JassCompilationUnitSyntax? actual) { - if (!expected.NullableEquals(actual)) + if (!expected.NullableEquivalentTo(actual)) { Assert.Fail("Compilation units are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); } } - public static void AreEqual(IDeclarationLineSyntax? expected, IDeclarationLineSyntax? actual) + //public static void AreEqual(IDeclarationLineSyntax? expected, IDeclarationLineSyntax? actual) + //{ + // if (!expected.NullableEquals(actual)) + // { + // Assert.Fail("Declaration lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); + // } + //} + + //public static void AreEqual(IGlobalLineSyntax? expected, IGlobalLineSyntax? actual) + //{ + // if (!expected.NullableEquals(actual)) + // { + // Assert.Fail("Global lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); + // } + //} + + //public static void AreEqual(IStatementLineSyntax? expected, IStatementLineSyntax? actual) + //{ + // if (!expected.NullableEquals(actual)) + // { + // Assert.Fail("Statement lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); + // } + //} + + public static void AreEqual(JassExpressionSyntax? expected, JassExpressionSyntax? actual) { - if (!expected.NullableEquals(actual)) - { - Assert.Fail("Declaration lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); - } - } - - public static void AreEqual(IGlobalLineSyntax? expected, IGlobalLineSyntax? actual) - { - if (!expected.NullableEquals(actual)) - { - Assert.Fail("Global lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); - } - } - - public static void AreEqual(IStatementLineSyntax? expected, IStatementLineSyntax? actual) - { - if (!expected.NullableEquals(actual)) - { - Assert.Fail("Statement lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); - } - } - - public static void AreEqual(IExpressionSyntax? expected, IExpressionSyntax? actual) - { - if (!expected.NullableEquals(actual)) + if (!expected.NullableEquivalentTo(actual)) { Assert.Fail("Expressions are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); } } - public static void AreEqual(ITopLevelDeclarationSyntax? expected, ITopLevelDeclarationSyntax? actual) + public static void AreEqual(JassTopLevelDeclarationSyntax? expected, JassTopLevelDeclarationSyntax? actual) { - if (!expected.NullableEquals(actual)) + if (!expected.NullableEquivalentTo(actual)) { Assert.Fail("Declarations are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); } } - public static void AreEqual(IStatementSyntax? expected, IStatementSyntax? actual) + public static void AreEqual(JassStatementSyntax? expected, JassStatementSyntax? actual) { - if (!expected.NullableEquals(actual)) + if (!expected.NullableEquivalentTo(actual)) { Assert.Fail("Statements are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); } @@ -78,55 +78,55 @@ public static void AreEqual(IStatementSyntax? expected, IStatementSyntax? actual public static void AreNotEqual(JassCompilationUnitSyntax? expected, JassCompilationUnitSyntax? actual) { - if (expected.NullableEquals(actual)) + if (expected.NullableEquivalentTo(actual)) { Assert.Fail($"Compilation units are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); } } - public static void AreNotEqual(IDeclarationLineSyntax? expected, IDeclarationLineSyntax? actual) - { - if (expected.NullableEquals(actual)) - { - Assert.Fail($"Declaration lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); - } - } - - public static void AreNotEqual(IGlobalLineSyntax? expected, IGlobalLineSyntax? actual) - { - if (expected.NullableEquals(actual)) - { - Assert.Fail($"Global lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); - } - } - - public static void AreNotEqual(IStatementLineSyntax? expected, IStatementLineSyntax? actual) - { - if (expected.NullableEquals(actual)) - { - Assert.Fail($"Statement lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); - } - } - - public static void AreNotEqual(ITopLevelDeclarationSyntax? expected, ITopLevelDeclarationSyntax? actual) + //public static void AreNotEqual(IDeclarationLineSyntax? expected, IDeclarationLineSyntax? actual) + //{ + // if (expected.NullableEquals(actual)) + // { + // Assert.Fail($"Declaration lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); + // } + //} + + //public static void AreNotEqual(IGlobalLineSyntax? expected, IGlobalLineSyntax? actual) + //{ + // if (expected.NullableEquals(actual)) + // { + // Assert.Fail($"Global lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); + // } + //} + + //public static void AreNotEqual(IStatementLineSyntax? expected, IStatementLineSyntax? actual) + //{ + // if (expected.NullableEquals(actual)) + // { + // Assert.Fail($"Statement lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); + // } + //} + + public static void AreNotEqual(JassTopLevelDeclarationSyntax? expected, JassTopLevelDeclarationSyntax? actual) { - if (expected.NullableEquals(actual)) + if (expected.NullableEquivalentTo(actual)) { Assert.Fail($"Declarations are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); } } - public static void AreNotEqual(IExpressionSyntax? expected, IExpressionSyntax? actual) + public static void AreNotEqual(JassExpressionSyntax? expected, JassExpressionSyntax? actual) { - if (expected.NullableEquals(actual)) + if (expected.NullableEquivalentTo(actual)) { Assert.Fail($"Expressions are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); } } - public static void AreNotEqual(IStatementSyntax? expected, IStatementSyntax? actual) + public static void AreNotEqual(JassStatementSyntax? expected, JassStatementSyntax? actual) { - if (expected.NullableEquals(actual)) + if (expected.NullableEquivalentTo(actual)) { Assert.Fail($"Statements are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); } @@ -168,7 +168,7 @@ private static string GetAssertFailedMessage(JassCompilationUnitSyntax? expected for (var i = 0; i < length; i++) { - if (!expected.Declarations[i].Equals(actual.Declarations[i])) + if (!expected.Declarations[i].IsEquivalentTo(actual.Declarations[i])) { if (messageParts.Count > 20) { @@ -187,32 +187,32 @@ private static string GetAssertFailedMessage(JassCompilationUnitSyntax? expected return GetAssertFailedMessage((object?)expected, actual); } - private static string GetAssertFailedMessage(ITopLevelDeclarationSyntax? expected, ITopLevelDeclarationSyntax? actual) + private static string GetAssertFailedMessage(JassTopLevelDeclarationSyntax? expected, JassTopLevelDeclarationSyntax? actual) { if (expected is JassFunctionDeclarationSyntax expectedFunctionDeclaration && actual is JassFunctionDeclarationSyntax actualFunctionDeclaration) { var messageParts = new List(); - if (!expectedFunctionDeclaration.FunctionDeclarator.Equals(actualFunctionDeclaration.FunctionDeclarator)) + if (!expectedFunctionDeclaration.FunctionDeclarator.IsEquivalentTo(actualFunctionDeclaration.FunctionDeclarator)) { messageParts.Add(GetAssertFailedMessage(expectedFunctionDeclaration.FunctionDeclarator, actualFunctionDeclaration.FunctionDeclarator)); } - var length = expectedFunctionDeclaration.Body.Statements.Length; - if (expectedFunctionDeclaration.Body.Statements.Length != actualFunctionDeclaration.Body.Statements.Length) + var length = expectedFunctionDeclaration.Statements.Length; + if (expectedFunctionDeclaration.Statements.Length != actualFunctionDeclaration.Statements.Length) { - messageParts.Add($"Expected: {expectedFunctionDeclaration.Body.Statements.Length} statements."); - messageParts.Add($" Actual: {actualFunctionDeclaration.Body.Statements.Length} statements."); + messageParts.Add($"Expected: {expectedFunctionDeclaration.Statements.Length} statements."); + messageParts.Add($" Actual: {actualFunctionDeclaration.Statements.Length} statements."); - if (expectedFunctionDeclaration.Body.Statements.Length > actualFunctionDeclaration.Body.Statements.Length) + if (expectedFunctionDeclaration.Statements.Length > actualFunctionDeclaration.Statements.Length) { - length = actualFunctionDeclaration.Body.Statements.Length; + length = actualFunctionDeclaration.Statements.Length; } } for (var i = 0; i < length; i++) { - if (!expectedFunctionDeclaration.Body.Statements[i].Equals(actualFunctionDeclaration.Body.Statements[i])) + if (!expectedFunctionDeclaration.Statements[i].IsEquivalentTo(actualFunctionDeclaration.Statements[i])) { if (messageParts.Count > 20) { @@ -221,7 +221,7 @@ private static string GetAssertFailedMessage(ITopLevelDeclarationSyntax? expecte } messageParts.Add($"Statement #{i + 1}:"); - messageParts.Add(GetAssertFailedMessage(expectedFunctionDeclaration.Body.Statements[i], actualFunctionDeclaration.Body.Statements[i])); + messageParts.Add(GetAssertFailedMessage(expectedFunctionDeclaration.Statements[i], actualFunctionDeclaration.Statements[i])); } } @@ -237,7 +237,7 @@ public static void ExpressionThrowsException(string expression) Assert.ThrowsException(() => message.String = GetExpressionDisplayString(JassSyntaxFactory.ParseExpression(expression)), "\r\n{0}", message); } - private static string GetExpressionDisplayString(IExpressionSyntax? expression) + private static string GetExpressionDisplayString(JassExpressionSyntax? expression) { if (expression is null) { diff --git a/tests/War3Net.TestTools.UnitTesting/TestDataProvider.cs b/tests/War3Net.TestTools.UnitTesting/TestDataProvider.cs index c199638f..2a5814a4 100644 --- a/tests/War3Net.TestTools.UnitTesting/TestDataProvider.cs +++ b/tests/War3Net.TestTools.UnitTesting/TestDataProvider.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +// #define ENABLE_WEB_CAPABILITIES + using System; using System.Collections.Generic; using System.IO; @@ -96,7 +98,9 @@ private static IEnumerable GetTestDataDirectories(params string[] direct } else { +#if ENABLE_WEB_CAPABILITIES DownloadTestData(directory); +#endif } } From 69018e77cd3c46046965e2c05a9a1c952f528327 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:26:02 +0100 Subject: [PATCH 04/53] Update JassToCSharpTranspiler and JassToLuaTranspiler to use new JASS syntax classes. --- .../JassToCSharp/ArgumentListTranspiler.cs | 2 +- .../JassToCSharp/ArrayDeclaratorTranspiler.cs | 2 +- .../BinaryExpressionTranspiler.cs | 22 +++- .../JassToCSharp/BinaryOperatorTranspiler.cs | 35 ------ .../BooleanLiteralExpressionTranspiler.cs | 22 ---- .../JassToCSharp/CallStatementTranspiler.cs | 4 +- .../CharacterLiteralExpressionTranspiler.cs | 22 ---- .../JassToCSharp/CommentTranspiler.cs | 22 ---- .../DecimalLiteralExpressionTranspiler.cs | 22 ---- .../JassToCSharp/DeclarationTranspiler.cs | 5 +- ...s => ElementAccessExpressionTranspiler.cs} | 8 +- .../JassToCSharp/ElseClauseTranspiler.cs | 4 +- .../JassToCSharp/ElseIfClauseTranspiler.cs | 6 +- .../JassToCSharp/EmptyTranspiler.cs | 22 ---- .../JassToCSharp/ExpressionTranspiler.cs | 16 +-- .../FourCCLiteralExpressionTranspiler.cs | 22 ---- .../FunctionDeclarationTranspiler.cs | 8 +- .../FunctionReferenceExpressionTranspiler.cs | 3 +- .../GlobalDeclarationTranspiler.cs | 45 +++++++- ...ler.cs => GlobalsDeclarationTranspiler.cs} | 11 +- .../HexadecimalLiteralExpressionTranspiler.cs | 22 ---- .../JassToCSharp/IdentifierNameTranspiler.cs | 34 +----- .../JassToCSharp/IfStatementTranspiler.cs | 4 +- .../InvocationExpressionTranspiler.cs | 4 +- .../LiteralExpressionTranspiler.cs | 78 +++++++++++++ .../JassToCSharp/LoopStatementTranspiler.cs | 4 +- .../NativeFunctionDeclarationTranspiler.cs | 6 +- .../NullLiteralExpressionTranspiler.cs | 22 ---- .../OctalLiteralExpressionTranspiler.cs | 22 ---- .../JassToCSharp/ParameterListTranspiler.cs | 11 +- .../JassToCSharp/ParameterTranspiler.cs | 2 +- .../RealLiteralExpressionTranspiler.cs | 25 ---- .../JassToCSharp/SetStatementTranspiler.cs | 8 +- .../JassToCSharp/StatementListTranspiler.cs | 24 ---- .../JassToCSharp/StatementTranspiler.cs | 4 +- .../StringLiteralExpressionTranspiler.cs | 23 ---- .../JassToCSharp/SyntaxTokenTranspiler.cs | 50 ++++++++ .../JassToCSharp/SyntaxTriviaTranspiler.cs | 36 ++++++ .../JassToCSharp/TypeDeclarationTranspiler.cs | 2 +- .../JassToCSharp/TypeTranspiler.cs | 50 +++----- .../JassToCSharp/UnaryExpressionTranspiler.cs | 13 ++- .../JassToCSharp/UnaryOperatorTranspiler.cs | 26 ----- .../VariableDeclaratorTranspiler.cs | 6 +- .../VariableReferenceExpressionTranspiler.cs | 22 ---- .../JassToLua/ArgumentListTranspiler.cs | 2 +- .../JassToLua/ArrayDeclaratorTranspiler.cs | 13 ++- .../JassToLua/BinaryExpressionTranspiler.cs | 44 ++++++- .../JassToLua/BinaryOperatorTranspiler.cs | 57 --------- .../BooleanLiteralExpressionTranspiler.cs | 25 ---- .../JassToLua/CallStatementTranspiler.cs | 4 +- .../CharacterLiteralExpressionTranspiler.cs | 23 ---- .../JassToLua/CommentTranspiler.cs | 21 ---- .../JassToLua/DeclarationTranspiler.cs | 9 +- ...s => ElementAccessExpressionTranspiler.cs} | 10 +- .../JassToLua/ElseClauseTranspiler.cs | 4 +- .../JassToLua/ElseIfClauseTranspiler.cs | 6 +- .../JassToLua/EmptyTranspiler.cs | 21 ---- .../JassToLua/ExpressionTranspiler.cs | 16 +-- .../FourCCLiteralExpressionTranspiler.cs | 23 ---- .../FunctionDeclarationTranspiler.cs | 6 +- .../JassToLua/FunctionDeclaratorTranspiler.cs | 2 +- .../FunctionReferenceExpressionTranspiler.cs | 4 +- .../GlobalDeclarationListTranspiler.cs | 35 ------ .../JassToLua/GlobalDeclarationTranspiler.cs | 21 +++- ...ler.cs => GlobalsDeclarationTranspiler.cs} | 11 +- .../HexadecimalLiteralExpressionTranspiler.cs | 23 ---- .../JassToLua/IdentifierNameTranspiler.cs | 41 +------ .../JassToLua/IfStatementTranspiler.cs | 4 +- .../InvocationExpressionTranspiler.cs | 4 +- .../JassToLua/LiteralExpressionTranspiler.cs | 109 ++++++++++++++++++ .../JassToLua/LoopStatementTranspiler.cs | 4 +- .../NullLiteralExpressionTranspiler.cs | 23 ---- .../OctalLiteralExpressionTranspiler.cs | 23 ---- .../JassToLua/ParameterListTranspiler.cs | 11 +- .../JassToLua/ParameterTranspiler.cs | 2 +- .../RealLiteralExpressionTranspiler.cs | 23 ---- .../JassToLua/SetStatementTranspiler.cs | 8 +- .../JassToLua/StatementListTranspiler.cs | 27 ----- .../JassToLua/StatementTranspiler.cs | 4 +- .../StringLiteralExpressionTranspiler.cs | 24 ---- .../JassToLua/SyntaxTokenTranspiler.cs | 57 +++++++++ .../JassToLua/UnaryExpressionTranspiler.cs | 13 ++- .../JassToLua/UnaryOperatorTranspiler.cs | 26 ----- .../JassToLua/VariableDeclaratorTranspiler.cs | 4 +- .../VariableReferenceExpressionTranspiler.cs | 23 ---- .../JassToLuaTranspiler.cs | 34 ++++-- 86 files changed, 656 insertions(+), 989 deletions(-) delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryOperatorTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BooleanLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CharacterLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CommentTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DecimalLiteralExpressionTranspiler.cs rename src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/{ArrayReferenceExpressionTranspiler.cs => ElementAccessExpressionTranspiler.cs} (63%) delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EmptyTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FourCCLiteralExpressionTranspiler.cs rename src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/{GlobalDeclarationListTranspiler.cs => GlobalsDeclarationTranspiler.cs} (62%) delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/HexadecimalLiteralExpressionTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NullLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/OctalLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/RealLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementListTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StringLiteralExpressionTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryOperatorTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableReferenceExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryOperatorTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/BooleanLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/CharacterLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/CommentTranspiler.cs rename src/War3Net.CodeAnalysis.Transpilers/JassToLua/{ArrayReferenceExpressionTranspiler.cs => ElementAccessExpressionTranspiler.cs} (54%) delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/EmptyTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/FourCCLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationListTranspiler.cs rename src/War3Net.CodeAnalysis.Transpilers/JassToLua/{DecimalLiteralExpressionTranspiler.cs => GlobalsDeclarationTranspiler.cs} (60%) delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/HexadecimalLiteralExpressionTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/NullLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/OctalLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/RealLiteralExpressionTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementListTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/StringLiteralExpressionTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/SyntaxTokenTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryOperatorTranspiler.cs delete mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableReferenceExpressionTranspiler.cs diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs index 6ca47f3e..a2b2fd46 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs @@ -18,7 +18,7 @@ public partial class JassToCSharpTranspiler { public ArgumentListSyntax Transpile(JassArgumentListSyntax argumentList) { - return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argumentList.Arguments.Select(argument => SyntaxFactory.Argument(Transpile(argument))))); + return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argumentList.ArgumentList.Items.Select(argument => SyntaxFactory.Argument(Transpile(argument))))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs index b0b9dfbb..e409499e 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs @@ -20,7 +20,7 @@ private VariableDeclarationSyntax Transpile(JassArrayDeclaratorSyntax arrayDecla return SyntaxFactory.VariableDeclaration( SyntaxFactory.ArrayType(type), SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(arrayDeclarator.IdentifierName), + Transpile(arrayDeclarator.IdentifierName.Token), null, SyntaxFactory.EqualsValueClause(SyntaxFactory.ArrayCreationExpression(SyntaxFactory.ArrayType(type)))))); } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs index 11b9b1f6..b6782363 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -17,9 +18,28 @@ public partial class JassToCSharpTranspiler public ExpressionSyntax Transpile(JassBinaryExpressionSyntax binaryExpression) { return SyntaxFactory.BinaryExpression( - Transpile(binaryExpression.Operator), + TranspileBinaryExpressionKind(binaryExpression.SyntaxKind), Transpile(binaryExpression.Left), Transpile(binaryExpression.Right)); } + + public SyntaxKind TranspileBinaryExpressionKind(JassSyntaxKind expressionKind) + { + return expressionKind switch + { + JassSyntaxKind.AddExpression => SyntaxKind.AddExpression, + JassSyntaxKind.SubtractExpression => SyntaxKind.SubtractExpression, + JassSyntaxKind.MultiplyExpression => SyntaxKind.MultiplyExpression, + JassSyntaxKind.DivideExpression => SyntaxKind.DivideExpression, + JassSyntaxKind.GreaterThanExpression => SyntaxKind.GreaterThanExpression, + JassSyntaxKind.LessThanExpression => SyntaxKind.LessThanExpression, + JassSyntaxKind.EqualsExpression => SyntaxKind.EqualsExpression, + JassSyntaxKind.NotEqualsExpression => SyntaxKind.NotEqualsExpression, + JassSyntaxKind.GreaterThanOrEqualExpression => SyntaxKind.GreaterThanOrEqualExpression, + JassSyntaxKind.LessThanOrEqualExpression => SyntaxKind.LessThanOrEqualExpression, + JassSyntaxKind.LogicalAndExpression => SyntaxKind.LogicalAndExpression, + JassSyntaxKind.LogicalOrExpression => SyntaxKind.LogicalOrExpression, + }; + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryOperatorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryOperatorTranspiler.cs deleted file mode 100644 index 1af69edb..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryOperatorTranspiler.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public SyntaxKind Transpile(BinaryOperatorType binaryOperator) - { - return binaryOperator switch - { - BinaryOperatorType.Add => SyntaxKind.AddExpression, - BinaryOperatorType.Subtract => SyntaxKind.SubtractExpression, - BinaryOperatorType.Multiplication => SyntaxKind.MultiplyExpression, - BinaryOperatorType.Division => SyntaxKind.DivideExpression, - BinaryOperatorType.GreaterThan => SyntaxKind.GreaterThanExpression, - BinaryOperatorType.LessThan => SyntaxKind.LessThanExpression, - BinaryOperatorType.Equals => SyntaxKind.EqualsExpression, - BinaryOperatorType.NotEquals => SyntaxKind.NotEqualsExpression, - BinaryOperatorType.GreaterOrEqual => SyntaxKind.GreaterThanOrEqualExpression, - BinaryOperatorType.LessOrEqual => SyntaxKind.LessThanOrEqualExpression, - BinaryOperatorType.And => SyntaxKind.LogicalAndExpression, - BinaryOperatorType.Or => SyntaxKind.LogicalOrExpression, - }; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BooleanLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BooleanLiteralExpressionTranspiler.cs deleted file mode 100644 index 59fa1a48..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BooleanLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassBooleanLiteralExpressionSyntax booleanLiteralExpression) - { - return SyntaxFactory.LiteralExpression(booleanLiteralExpression.Value ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs index 9f4f6c5c..95cd6996 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs @@ -17,8 +17,8 @@ public partial class JassToCSharpTranspiler public StatementSyntax Transpile(JassCallStatementSyntax callStatement) { return SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression( - SyntaxFactory.IdentifierName(Transpile(callStatement.IdentifierName)), - Transpile(callStatement.Arguments))); + Transpile(callStatement.IdentifierName), + Transpile(callStatement.ArgumentList))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CharacterLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CharacterLiteralExpressionTranspiler.cs deleted file mode 100644 index 46b391fc..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CharacterLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassCharacterLiteralExpressionSyntax characterLiteralExpression) - { - return SyntaxFactory.ParseExpression(characterLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CommentTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CommentTranspiler.cs deleted file mode 100644 index 05b60db4..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CommentTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public StatementSyntax Transpile(JassCommentSyntax comment) - { - return SyntaxFactory.ParseStatement(comment.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DecimalLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DecimalLiteralExpressionTranspiler.cs deleted file mode 100644 index 5bd6f5d2..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DecimalLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassDecimalLiteralExpressionSyntax decimalLiteralExpression) - { - return SyntaxFactory.ParseExpression(decimalLiteralExpression.Value.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DeclarationTranspiler.cs index 87a43b60..d624bfbf 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DeclarationTranspiler.cs @@ -16,13 +16,12 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public IEnumerable Transpile(ITopLevelDeclarationSyntax declaration) + public IEnumerable Transpile(JassTopLevelDeclarationSyntax declaration) { return declaration switch { JassTypeDeclarationSyntax typeDeclaration => new[] { Transpile(typeDeclaration) }, - JassGlobalDeclarationListSyntax globalDeclarationList => Transpile(globalDeclarationList), - JassGlobalDeclarationSyntax globalDeclaration => new[] { Transpile(globalDeclaration) }, + JassGlobalsDeclarationSyntax globalsDeclaration => Transpile(globalsDeclaration), JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration => new[] { Transpile(nativeFunctionDeclaration) }, JassFunctionDeclarationSyntax functionDeclaration => new[] { Transpile(functionDeclaration) }, _ => Array.Empty(), diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs similarity index 63% rename from src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayReferenceExpressionTranspiler.cs rename to src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs index 5792ddfb..2e21af53 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayReferenceExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -14,11 +14,11 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public ExpressionSyntax Transpile(JassArrayReferenceExpressionSyntax arrayReferenceExpression) + public ExpressionSyntax Transpile(JassElementAccessExpressionSyntax elementAccessExpression) { return SyntaxFactory.ElementAccessExpression( - SyntaxFactory.IdentifierName(Transpile(arrayReferenceExpression.IdentifierName)), - SyntaxFactory.BracketedArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(Transpile(arrayReferenceExpression.Indexer))))); + Transpile(elementAccessExpression.IdentifierName), + SyntaxFactory.BracketedArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(Transpile(elementAccessExpression.ElementAccessClause.Expression))))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs index 64cf7675..307af617 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -16,7 +18,7 @@ public partial class JassToCSharpTranspiler { public ElseClauseSyntax Transpile(JassElseClauseSyntax elseClause) { - return SyntaxFactory.ElseClause(SyntaxFactory.Block(Transpile(elseClause.Body))); + return SyntaxFactory.ElseClause(SyntaxFactory.Block(elseClause.Statements.Select(Transpile))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs index 172f5d04..b1ef2e73 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -18,8 +20,8 @@ public StatementSyntax Transpile(JassElseIfClauseSyntax elseIfClause, ElseClause { return SyntaxFactory.IfStatement( SyntaxFactory.List(), - Transpile(elseIfClause.Condition), - SyntaxFactory.Block(Transpile(elseIfClause.Body)), + Transpile(elseIfClause.ElseIfClauseDeclarator.Condition), + SyntaxFactory.Block(elseIfClause.Statements.Select(Transpile)), elseClause); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EmptyTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EmptyTranspiler.cs deleted file mode 100644 index bc7cd015..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EmptyTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public StatementSyntax Transpile(JassEmptySyntax empty) - { - return SyntaxFactory.EmptyStatement(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs index b1fc1d4c..eb0fee21 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs @@ -13,23 +13,15 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public ExpressionSyntax Transpile(IExpressionSyntax expression) + public ExpressionSyntax Transpile(JassExpressionSyntax expression) { return expression switch { - JassCharacterLiteralExpressionSyntax characterLiteralExpression => Transpile(characterLiteralExpression), - JassFourCCLiteralExpressionSyntax fourCCLiteralExpression => Transpile(fourCCLiteralExpression), - JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression => Transpile(hexadecimalLiteralExpression), - JassRealLiteralExpressionSyntax realLiteralExpression => Transpile(realLiteralExpression), - JassOctalLiteralExpressionSyntax octalLiteralExpression => Transpile(octalLiteralExpression), - JassDecimalLiteralExpressionSyntax decimalLiteralExpression => Transpile(decimalLiteralExpression), - JassBooleanLiteralExpressionSyntax booleanLiteralExpression => Transpile(booleanLiteralExpression), - JassStringLiteralExpressionSyntax stringLiteralExpression => Transpile(stringLiteralExpression), - JassNullLiteralExpressionSyntax nullLiteralExpression => Transpile(nullLiteralExpression), + JassLiteralExpressionSyntax literalExpression => Transpile(literalExpression), JassFunctionReferenceExpressionSyntax functionReferenceExpression => Transpile(functionReferenceExpression), JassInvocationExpressionSyntax invocationExpression => Transpile(invocationExpression), - JassArrayReferenceExpressionSyntax arrayReferenceExpression => Transpile(arrayReferenceExpression), - JassVariableReferenceExpressionSyntax variableReferenceExpression => Transpile(variableReferenceExpression), + JassElementAccessExpressionSyntax elementAccessExpression => Transpile(elementAccessExpression), + JassIdentifierNameSyntax identifierName => Transpile(identifierName), JassParenthesizedExpressionSyntax parenthesizedExpression => Transpile(parenthesizedExpression), JassUnaryExpressionSyntax unaryExpression => Transpile(unaryExpression), JassBinaryExpressionSyntax binaryExpression => Transpile(binaryExpression), diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FourCCLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FourCCLiteralExpressionTranspiler.cs deleted file mode 100644 index 4f642b20..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FourCCLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassFourCCLiteralExpressionSyntax fourCCLiteralExpression) - { - return SyntaxFactory.ParseExpression(fourCCLiteralExpression.Value.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs index 8932792a..b0e7d618 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -22,13 +24,13 @@ public MemberDeclarationSyntax Transpile(JassFunctionDeclarationSyntax functionD new SyntaxTokenList( SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)), - Transpile(functionDeclaration.FunctionDeclarator.ReturnType), + Transpile(functionDeclaration.FunctionDeclarator.ReturnClause.ReturnType), null, - Transpile(functionDeclaration.FunctionDeclarator.IdentifierName), + Transpile(functionDeclaration.FunctionDeclarator.IdentifierName.Token), null, SyntaxFactory.ParameterList(Transpile(functionDeclaration.FunctionDeclarator.ParameterList)), default, - SyntaxFactory.Block(Transpile(functionDeclaration.Body)), + SyntaxFactory.Block(functionDeclaration.Statements.Select(Transpile)), null); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs index 0c24b104..ae017432 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs @@ -5,7 +5,6 @@ // // ------------------------------------------------------------------------------ -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; @@ -16,7 +15,7 @@ public partial class JassToCSharpTranspiler { public ExpressionSyntax Transpile(JassFunctionReferenceExpressionSyntax functionReferenceExpression) { - return SyntaxFactory.IdentifierName(Transpile(functionReferenceExpression.IdentifierName)); + return Transpile(functionReferenceExpression.IdentifierName); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs index 6d27cc20..a2bbb5a5 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs @@ -17,18 +17,59 @@ namespace War3Net.CodeAnalysis.Transpilers public partial class JassToCSharpTranspiler { public MemberDeclarationSyntax Transpile(JassGlobalDeclarationSyntax globalDeclaration) + { + return globalDeclaration switch + { + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => Transpile(globalConstantDeclaration), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => Transpile(globalVariableDeclaration), + }; + } + + public MemberDeclarationSyntax Transpile(JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + { + var variableDeclaration = SyntaxFactory.VariableDeclaration( + Transpile(globalConstantDeclaration.Type), + SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( + Transpile(globalConstantDeclaration.IdentifierName.Token), + null, + Transpile(globalConstantDeclaration.Value)))); + + var declaration = SyntaxFactory.FieldDeclaration( + default, + new SyntaxTokenList( + SyntaxFactory.Token(SyntaxKind.PublicKeyword), + SyntaxFactory.Token(SyntaxKind.ConstKeyword)), + variableDeclaration); + + if (ApplyCSharpLuaTemplateAttribute) + { + var jassToLuaTranspiler = JassToLuaTranspiler ?? new JassToLuaTranspiler(); + + declaration = declaration.WithCSharpLuaTemplateAttribute(jassToLuaTranspiler.Transpile(globalConstantDeclaration.IdentifierName.Token)); + } + + return declaration; + } + + public MemberDeclarationSyntax Transpile(JassGlobalVariableDeclarationSyntax globalVariableDeclaration) { var declaration = SyntaxFactory.FieldDeclaration( default, new SyntaxTokenList( SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)), - Transpile(globalDeclaration.Declarator)); + Transpile(globalVariableDeclaration.Declarator)); if (ApplyCSharpLuaTemplateAttribute) { var jassToLuaTranspiler = JassToLuaTranspiler ?? new JassToLuaTranspiler(); - declaration = declaration.WithCSharpLuaTemplateAttribute(jassToLuaTranspiler.Transpile(globalDeclaration.Declarator.IdentifierName)); + var token = globalVariableDeclaration.Declarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => arrayDeclarator.IdentifierName.Token, + JassVariableDeclaratorSyntax variableDeclarator => variableDeclarator.IdentifierName.Token, + }; + + declaration = declaration.WithCSharpLuaTemplateAttribute(jassToLuaTranspiler.Transpile(token)); } return declaration; diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs similarity index 62% rename from src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationListTranspiler.cs rename to src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs index bf852ca7..8f6af9d0 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -15,14 +15,11 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public IEnumerable Transpile(JassGlobalDeclarationListSyntax globalDeclarationList) + public IEnumerable Transpile(JassGlobalsDeclarationSyntax globalsDeclaration) { - foreach (var declaration in globalDeclarationList.Globals) + foreach (var declaration in globalsDeclaration.GlobalDeclarations) { - if (declaration is JassGlobalDeclarationSyntax globalDeclaration) - { - yield return Transpile(globalDeclaration); - } + yield return Transpile(declaration); } } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/HexadecimalLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/HexadecimalLiteralExpressionTranspiler.cs deleted file mode 100644 index 1658d4f2..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/HexadecimalLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression) - { - return SyntaxFactory.ParseExpression(hexadecimalLiteralExpression.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs index c6dbd774..0497b969 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs @@ -5,12 +5,8 @@ // // ------------------------------------------------------------------------------ -using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; @@ -18,33 +14,9 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - private const string AntiReservedKeywordConflictPrefix = "@"; - - private static readonly Lazy> _reservedKeywords = new Lazy>(() => GetReservedKeywords().ToHashSet(StringComparer.Ordinal)); - - public SyntaxToken Transpile(JassIdentifierNameSyntax identifierName) - { - var text = _reservedKeywords.Value.Contains(identifierName.Name) - ? $"{AntiReservedKeywordConflictPrefix}{identifierName.Name}" - : identifierName.Name; - - return SyntaxFactory.Identifier( - SyntaxTriviaList.Empty, - SyntaxKind.IdentifierToken, - text, - identifierName.Name, - SyntaxTriviaList.Empty); - } - - private static IEnumerable GetReservedKeywords() + public IdentifierNameSyntax Transpile(JassIdentifierNameSyntax identifierName) { - foreach (SyntaxKind syntaxKind in Enum.GetValues(typeof(SyntaxKind))) - { - if (SyntaxFacts.IsReservedKeyword(syntaxKind)) - { - yield return SyntaxFactory.Token(syntaxKind).ValueText; - } - } + return SyntaxFactory.IdentifierName(Transpile(identifierName.Token)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs index eca96590..c03e54a2 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs @@ -31,8 +31,8 @@ public StatementSyntax Transpile(JassIfStatementSyntax ifStatement) return SyntaxFactory.IfStatement( SyntaxFactory.List(), - Transpile(ifStatement.Condition), - SyntaxFactory.Block(Transpile(ifStatement.Body)), + Transpile(ifStatement.IfClause.IfClauseDeclarator.Condition), + SyntaxFactory.Block(ifStatement.IfClause.Statements.Select(Transpile)), elseClause); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/InvocationExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/InvocationExpressionTranspiler.cs index e7cbe23e..51d4608e 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/InvocationExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/InvocationExpressionTranspiler.cs @@ -17,8 +17,8 @@ public partial class JassToCSharpTranspiler public ExpressionSyntax Transpile(JassInvocationExpressionSyntax invocationExpression) { return SyntaxFactory.InvocationExpression( - SyntaxFactory.IdentifierName(Transpile(invocationExpression.IdentifierName)), - Transpile(invocationExpression.Arguments)); + Transpile(invocationExpression.IdentifierName), + Transpile(invocationExpression.ArgumentList)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs new file mode 100644 index 00000000..aae1ad73 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs @@ -0,0 +1,78 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Globalization; + +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.Common.Extensions; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public ExpressionSyntax Transpile(JassLiteralExpressionSyntax literalExpression) + { + return literalExpression.SyntaxKind switch + { + JassSyntaxKind.TrueLiteralExpression => SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression), + JassSyntaxKind.FalseLiteralExpression => SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression), + JassSyntaxKind.NullLiteralExpression => SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression), + JassSyntaxKind.DecimalLiteralExpression => SyntaxFactory.ParseExpression(literalExpression.Token.Text), + JassSyntaxKind.OctalLiteralExpression => TranspileOctalLiteral(literalExpression), + JassSyntaxKind.HexadecimalLiteralExpression => TranspileHexadecimalLiteral(literalExpression), + JassSyntaxKind.FourCCLiteralExpression => TranspileFourCCLiteral(literalExpression), + JassSyntaxKind.CharacterLiteralExpression => TranspileCharacterLiteral(literalExpression), + JassSyntaxKind.RealLiteralExpression => TranspileRealLiteral(literalExpression), + JassSyntaxKind.StringLiteralExpression => TranspileStringLiteral(literalExpression), + }; + } + + private ExpressionSyntax TranspileOctalLiteral(JassLiteralExpressionSyntax literalExpression) + { + var text = Convert.ToInt32(literalExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture); + return SyntaxFactory.ParseExpression(text); + } + + private ExpressionSyntax TranspileHexadecimalLiteral(JassLiteralExpressionSyntax literalExpression) + { + var text = literalExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); + return SyntaxFactory.ParseExpression(text); + } + + private ExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax literalExpression) + { + var text = literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar).FromRawcode().ToString(CultureInfo.InvariantCulture); + return SyntaxFactory.ParseExpression(text); + } + + private ExpressionSyntax TranspileCharacterLiteral(JassLiteralExpressionSyntax literalExpression) + { + var text = ((int)char.Parse(literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar))).ToString(CultureInfo.InvariantCulture); + return SyntaxFactory.ParseExpression(text); + } + + private ExpressionSyntax TranspileRealLiteral(JassLiteralExpressionSyntax literalExpression) + { + var text = $"{literalExpression.Token.Text.TrimEnd(JassSymbol.DotChar)}f"; + return SyntaxFactory.ParseExpression(text); + } + + private ExpressionSyntax TranspileStringLiteral(JassLiteralExpressionSyntax literalExpression) + { + var text = literalExpression.Token.Text + .Replace(JassSymbol.CarriageReturn, @"\r", StringComparison.Ordinal) + .Replace(JassSymbol.LineFeed, @"\n", StringComparison.Ordinal); + + return SyntaxFactory.ParseExpression(text); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs index d323cd36..e72f15f3 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -18,7 +20,7 @@ public StatementSyntax Transpile(JassLoopStatementSyntax loopStatement) { return SyntaxFactory.WhileStatement( SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression), - SyntaxFactory.Block(Transpile(loopStatement.Body))); + SyntaxFactory.Block(loopStatement.Statements.Select(Transpile))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs index 7d1d9818..f2dcf8fa 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs @@ -23,11 +23,11 @@ public MemberDeclarationSyntax Transpile(JassNativeFunctionDeclarationSyntax nat SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.ExternKeyword)), - Transpile(nativeFunctionDeclaration.FunctionDeclarator.ReturnType), + Transpile(nativeFunctionDeclaration.ReturnClause.ReturnType), null, - Transpile(nativeFunctionDeclaration.FunctionDeclarator.IdentifierName), + Transpile(nativeFunctionDeclaration.IdentifierName.Token), null, - SyntaxFactory.ParameterList(Transpile(nativeFunctionDeclaration.FunctionDeclarator.ParameterList)), + SyntaxFactory.ParameterList(Transpile(nativeFunctionDeclaration.ParameterList)), default, null, null, diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NullLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NullLiteralExpressionTranspiler.cs deleted file mode 100644 index cfd8933d..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NullLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassNullLiteralExpressionSyntax nullLiteralExpression) - { - return SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/OctalLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/OctalLiteralExpressionTranspiler.cs deleted file mode 100644 index 907e0108..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/OctalLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassOctalLiteralExpressionSyntax octalLiteralExpression) - { - return SyntaxFactory.ParseExpression(octalLiteralExpression.Value.ToString()); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs index 5ac1aeba..100acab2 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs @@ -17,9 +17,18 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { + public SeparatedSyntaxList Transpile(JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) + { + return parameterListOrEmptyParameterList switch + { + JassParameterListSyntax parameterList => Transpile(parameterList), + JassEmptyParameterListSyntax => SyntaxFactory.SeparatedList(), + }; + } + public SeparatedSyntaxList Transpile(JassParameterListSyntax parameterList) { - return SyntaxFactory.SeparatedList(parameterList.Parameters.Select(Transpile)); + return SyntaxFactory.SeparatedList(parameterList.ParameterList.Items.Select(Transpile)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs index 95dce165..d50425dd 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs @@ -16,7 +16,7 @@ public partial class JassToCSharpTranspiler { public ParameterSyntax Transpile(JassParameterSyntax parameter) { - return SyntaxFactory.Parameter(Transpile(parameter.IdentifierName)) + return SyntaxFactory.Parameter(Transpile(parameter.IdentifierName.Token)) .WithType(Transpile(parameter.Type)); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/RealLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/RealLiteralExpressionTranspiler.cs deleted file mode 100644 index bb6f472e..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/RealLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassRealLiteralExpressionSyntax realLiteralExpression) - { - return SyntaxFactory.ParseExpression(string.IsNullOrEmpty(realLiteralExpression.FracPart) - ? $"{realLiteralExpression.IntPart}f" - : $"{realLiteralExpression.IntPart}{JassSymbol.FullStop}{realLiteralExpression.FracPart}f"); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs index c0e605ab..4d4a4483 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs @@ -16,11 +16,11 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassSetStatementSyntax setStatement) { - if (setStatement.Indexer is null) + if (setStatement.ElementAccessClause is null) { return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, - SyntaxFactory.IdentifierName(Transpile(setStatement.IdentifierName)), + Transpile(setStatement.IdentifierName), Transpile(setStatement.Value.Expression))); } else @@ -28,8 +28,8 @@ public StatementSyntax Transpile(JassSetStatementSyntax setStatement) return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.ElementAccessExpression( - SyntaxFactory.IdentifierName(Transpile(setStatement.IdentifierName)), - SyntaxFactory.BracketedArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(Transpile(setStatement.Indexer))))), + Transpile(setStatement.IdentifierName), + SyntaxFactory.BracketedArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(Transpile(setStatement.ElementAccessClause.Expression))))), Transpile(setStatement.Value.Expression))); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementListTranspiler.cs deleted file mode 100644 index ab8ee76b..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementListTranspiler.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public IEnumerable Transpile(JassStatementListSyntax statementList) - { - return statementList.Statements.Select(Transpile); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementTranspiler.cs index cf219ec4..e4ee6cea 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StatementTranspiler.cs @@ -13,12 +13,10 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public StatementSyntax Transpile(IStatementSyntax statement) + public StatementSyntax Transpile(JassStatementSyntax statement) { return statement switch { - JassEmptySyntax empty => Transpile(empty), - JassCommentSyntax comment => Transpile(comment), JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement => Transpile(localVariableDeclarationStatement), JassSetStatementSyntax setStatement => Transpile(setStatement), JassCallStatementSyntax callStatement => Transpile(callStatement), diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StringLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StringLiteralExpressionTranspiler.cs deleted file mode 100644 index fa5aac87..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/StringLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassStringLiteralExpressionSyntax stringLiteralExpression) - { - return SyntaxFactory.ParseExpression($"\"{stringLiteralExpression.Value.Replace($"{JassSymbol.CarriageReturn}", @"\r").Replace($"{JassSymbol.LineFeed}", @"\n")}\""); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs new file mode 100644 index 00000000..a8c70e5d --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Linq; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + private const string AntiReservedKeywordConflictPrefix = "@"; + + private static readonly Lazy> _reservedKeywords = new Lazy>(() => GetReservedKeywords().ToHashSet(StringComparer.Ordinal)); + + public SyntaxToken Transpile(JassSyntaxToken token) + { + var text = _reservedKeywords.Value.Contains(token.Text) + ? $"{AntiReservedKeywordConflictPrefix}{token.Text}" + : token.Text; + + return SyntaxFactory.Identifier( + Transpile(token.LeadingTrivia), + SyntaxKind.IdentifierToken, + text, + token.Text, + Transpile(token.TrailingTrivia)); + } + + private static IEnumerable GetReservedKeywords() + { + foreach (SyntaxKind syntaxKind in Enum.GetValues(typeof(SyntaxKind))) + { + if (SyntaxFacts.IsReservedKeyword(syntaxKind)) + { + yield return SyntaxFactory.Token(syntaxKind).Text; + } + } + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs new file mode 100644 index 00000000..e97e936e --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs @@ -0,0 +1,36 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Linq; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +using War3Net.CodeAnalysis.Jass; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public SyntaxTriviaList Transpile(JassSyntaxTriviaList triviaList) + { + return SyntaxFactory.TriviaList(triviaList.Trivia.Select(Transpile)); + } + + public SyntaxTrivia Transpile(JassSyntaxTrivia trivia) + { + return trivia.SyntaxKind switch + { + JassSyntaxKind.NewlineTrivia => SyntaxFactory.EndOfLine(trivia.Text), + JassSyntaxKind.WhitespaceTrivia => SyntaxFactory.Whitespace(trivia.Text), + JassSyntaxKind.SingleLineCommentTrivia => SyntaxFactory.Comment(trivia.Text), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs index 73bebdf4..4fad9e65 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs @@ -17,7 +17,7 @@ public partial class JassToCSharpTranspiler { public MemberDeclarationSyntax Transpile(JassTypeDeclarationSyntax typeDeclaration) { - var identifier = Transpile(typeDeclaration.IdentifierName); + var identifier = Transpile(typeDeclaration.IdentifierName.Token); var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.SimpleBaseType(Transpile(typeDeclaration.BaseType)))); return SyntaxFactory.ClassDeclaration( diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs index 4270efcc..48fd6509 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -18,42 +19,25 @@ public partial class JassToCSharpTranspiler { public TypeSyntax Transpile(JassTypeSyntax type) { - if (type.Equals(JassTypeSyntax.Boolean)) + return type switch { - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword)); - } - - if (type.Equals(JassTypeSyntax.Code)) - { - return SyntaxFactory.ParseTypeName(typeof(Action).FullName!); - } - - if (type.Equals(JassTypeSyntax.Handle)) - { - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ObjectKeyword)); - } - - if (type.Equals(JassTypeSyntax.Integer)) - { - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)); - } - - if (type.Equals(JassTypeSyntax.Nothing)) - { - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)); - } - - if (type.Equals(JassTypeSyntax.Real)) - { - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.FloatKeyword)); - } + JassIdentifierNameSyntax identifierName => SyntaxFactory.ParseTypeName(Transpile(identifierName.Token).Text), + JassPredefinedTypeSyntax predefinedType => Transpile(predefinedType), + }; + } - if (type.Equals(JassTypeSyntax.String)) + public TypeSyntax Transpile(JassPredefinedTypeSyntax type) + { + return type.SyntaxKind switch { - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)); - } - - return SyntaxFactory.ParseTypeName(Transpile(type.TypeName).Text); + JassSyntaxKind.BooleanKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword)), + JassSyntaxKind.CodeKeyword => SyntaxFactory.ParseTypeName(typeof(Action).FullName!), + JassSyntaxKind.HandleKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ObjectKeyword)), + JassSyntaxKind.IntegerKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)), + JassSyntaxKind.NothingKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), + JassSyntaxKind.RealKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.FloatKeyword)), + JassSyntaxKind.StringKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)), + }; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs index ff4fc253..ad55dc7c 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -17,8 +18,18 @@ public partial class JassToCSharpTranspiler public ExpressionSyntax Transpile(JassUnaryExpressionSyntax unaryExpression) { return SyntaxFactory.PrefixUnaryExpression( - Transpile(unaryExpression.Operator), + TranspileUnaryExpressionKind(unaryExpression.SyntaxKind), Transpile(unaryExpression.Expression)); } + + public SyntaxKind TranspileUnaryExpressionKind(JassSyntaxKind expressionKind) + { + return expressionKind switch + { + JassSyntaxKind.UnaryPlusExpression => SyntaxKind.UnaryPlusExpression, + JassSyntaxKind.UnaryMinusExpression => SyntaxKind.UnaryMinusExpression, + JassSyntaxKind.LogicalNotExpression => SyntaxKind.LogicalNotExpression, + }; + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryOperatorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryOperatorTranspiler.cs deleted file mode 100644 index b28cd0e8..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryOperatorTranspiler.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public SyntaxKind Transpile(UnaryOperatorType unaryOperator) - { - return unaryOperator switch - { - UnaryOperatorType.Plus => SyntaxKind.UnaryPlusExpression, - UnaryOperatorType.Minus => SyntaxKind.UnaryPlusExpression, - UnaryOperatorType.Not => SyntaxKind.LogicalNotExpression, - }; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs index 2d615e2f..1d4e36b6 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs @@ -14,7 +14,7 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public VariableDeclarationSyntax Transpile(IVariableDeclaratorSyntax declarator) + public VariableDeclarationSyntax Transpile(JassVariableOrArrayDeclaratorSyntax declarator) { return declarator switch { @@ -31,7 +31,7 @@ public VariableDeclarationSyntax Transpile(JassVariableDeclaratorSyntax variable return SyntaxFactory.VariableDeclaration( type, SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(variableDeclarator.IdentifierName), + Transpile(variableDeclarator.IdentifierName.Token), null, SyntaxFactory.EqualsValueClause(SyntaxFactory.DefaultExpression(type))))); } @@ -40,7 +40,7 @@ public VariableDeclarationSyntax Transpile(JassVariableDeclaratorSyntax variable return SyntaxFactory.VariableDeclaration( type, SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(variableDeclarator.IdentifierName), + Transpile(variableDeclarator.IdentifierName.Token), null, Transpile(variableDeclarator.Value)))); } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableReferenceExpressionTranspiler.cs deleted file mode 100644 index 65a66e24..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableReferenceExpressionTranspiler.cs +++ /dev/null @@ -1,22 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToCSharpTranspiler - { - public ExpressionSyntax Transpile(JassVariableReferenceExpressionSyntax variableReferenceExpression) - { - return SyntaxFactory.IdentifierName(Transpile(variableReferenceExpression.IdentifierName)); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArgumentListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArgumentListTranspiler.cs index c5d9b34e..b3d8fa63 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArgumentListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArgumentListTranspiler.cs @@ -18,7 +18,7 @@ public partial class JassToLuaTranspiler { public IEnumerable Transpile(JassArgumentListSyntax argumentList) { - return argumentList.Arguments.Select(argument => Transpile(argument, out _)); + return argumentList.ArgumentList.Items.Select(argument => Transpile(argument, out _)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs index 0df8d1b5..5b9fccd4 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs @@ -7,6 +7,7 @@ using CSharpLua.LuaAst; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -15,16 +16,16 @@ public partial class JassToLuaTranspiler { public LuaVariableDeclaratorSyntax Transpile(JassArrayDeclaratorSyntax arrayDeclarator) { - LuaExpressionSyntax expression = arrayDeclarator.Type switch + LuaExpressionSyntax expression = arrayDeclarator.Type.SyntaxKind switch { - JassTypeSyntax type when type.Equals(JassTypeSyntax.Integer) => new LuaInvocationExpressionSyntax("__jarray", "0"), - JassTypeSyntax type when type.Equals(JassTypeSyntax.Real) => new LuaInvocationExpressionSyntax("__jarray", "0.0"), - JassTypeSyntax type when type.Equals(JassTypeSyntax.String) => new LuaInvocationExpressionSyntax("__jarray", LuaStringLiteralExpressionSyntax.Empty), - JassTypeSyntax type when type.Equals(JassTypeSyntax.Boolean) => new LuaInvocationExpressionSyntax("__jarray", LuaIdentifierLiteralExpressionSyntax.False), + JassSyntaxKind.IntegerKeyword => new LuaInvocationExpressionSyntax("__jarray", "0"), + JassSyntaxKind.RealKeyword => new LuaInvocationExpressionSyntax("__jarray", "0.0"), + JassSyntaxKind.StringKeyword => new LuaInvocationExpressionSyntax("__jarray", LuaStringLiteralExpressionSyntax.Empty), + JassSyntaxKind.BooleanKeyword => new LuaInvocationExpressionSyntax("__jarray", LuaIdentifierLiteralExpressionSyntax.False), _ => new LuaTableExpression(), }; - return new LuaVariableDeclaratorSyntax(Transpile(arrayDeclarator.IdentifierName), expression); + return new LuaVariableDeclaratorSyntax(Transpile(arrayDeclarator.IdentifierName, out _), expression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs index 87bd8466..d90f14b1 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs @@ -7,6 +7,7 @@ using CSharpLua.LuaAst; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -18,7 +19,48 @@ public LuaExpressionSyntax Transpile(JassBinaryExpressionSyntax binaryExpression var left = Transpile(binaryExpression.Left, out var leftType); var right = Transpile(binaryExpression.Right, out var rightType); - return new LuaBinaryExpressionSyntax(left, Transpile(binaryExpression.Operator, leftType, rightType, out type), right); + return new LuaBinaryExpressionSyntax(left, TranspileBinaryExpressionKind(binaryExpression.SyntaxKind, leftType, rightType, out type), right); + } + + public string TranspileBinaryExpressionKind(JassSyntaxKind expressionKind, JassTypeSyntax left, JassTypeSyntax right, out JassTypeSyntax type) + { + switch (expressionKind) + { + case JassSyntaxKind.GreaterThanExpression: + case JassSyntaxKind.LessThanExpression: + case JassSyntaxKind.EqualsExpression: + case JassSyntaxKind.NotEqualsExpression: + case JassSyntaxKind.GreaterThanOrEqualExpression: + case JassSyntaxKind.LessThanOrEqualExpression: + case JassSyntaxKind.LogicalAndExpression: + case JassSyntaxKind.LogicalOrExpression: + type = JassPredefinedTypeSyntax.Boolean; + break; + + default: + type = left.Equals(JassPredefinedTypeSyntax.String) || right.Equals(JassPredefinedTypeSyntax.String) + ? JassPredefinedTypeSyntax.String + : left.Equals(JassPredefinedTypeSyntax.Real) || right.Equals(JassPredefinedTypeSyntax.Real) + ? JassPredefinedTypeSyntax.Real + : left; + break; + } + + return expressionKind switch + { + JassSyntaxKind.AddExpression => type.Equals(JassPredefinedTypeSyntax.String) ? LuaSyntaxNode.Tokens.Concatenation : LuaSyntaxNode.Tokens.Plus, + JassSyntaxKind.SubtractExpression => LuaSyntaxNode.Tokens.Sub, + JassSyntaxKind.MultiplyExpression => LuaSyntaxNode.Tokens.Multiply, + JassSyntaxKind.DivideExpression => type.Equals(JassPredefinedTypeSyntax.Integer) ? LuaSyntaxNode.Tokens.IntegerDiv : LuaSyntaxNode.Tokens.Div, + JassSyntaxKind.GreaterThanExpression => ">", + JassSyntaxKind.LessThanExpression => "<", + JassSyntaxKind.EqualsExpression => LuaSyntaxNode.Tokens.EqualsEquals, + JassSyntaxKind.NotEqualsExpression => LuaSyntaxNode.Tokens.NotEquals, + JassSyntaxKind.GreaterThanOrEqualExpression => ">=", + JassSyntaxKind.LessThanOrEqualExpression => "<=", + JassSyntaxKind.LogicalAndExpression => LuaSyntaxNode.Keyword.And, + JassSyntaxKind.LogicalOrExpression => LuaSyntaxNode.Keyword.Or, + }; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryOperatorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryOperatorTranspiler.cs deleted file mode 100644 index a8dcf716..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryOperatorTranspiler.cs +++ /dev/null @@ -1,57 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public string Transpile(BinaryOperatorType binaryOperator, JassTypeSyntax left, JassTypeSyntax right, out JassTypeSyntax type) - { - switch (binaryOperator) - { - case BinaryOperatorType.GreaterThan: - case BinaryOperatorType.LessThan: - case BinaryOperatorType.Equals: - case BinaryOperatorType.NotEquals: - case BinaryOperatorType.GreaterOrEqual: - case BinaryOperatorType.LessOrEqual: - case BinaryOperatorType.And: - case BinaryOperatorType.Or: - type = JassTypeSyntax.Boolean; - break; - - default: - type = left.Equals(JassTypeSyntax.String) || right.Equals(JassTypeSyntax.String) - ? JassTypeSyntax.String - : left.Equals(JassTypeSyntax.Real) || right.Equals(JassTypeSyntax.Real) - ? JassTypeSyntax.Real - : left; - break; - } - - return binaryOperator switch - { - BinaryOperatorType.Add => type.Equals(JassTypeSyntax.String) ? LuaSyntaxNode.Tokens.Concatenation : LuaSyntaxNode.Tokens.Plus, - BinaryOperatorType.Subtract => LuaSyntaxNode.Tokens.Sub, - BinaryOperatorType.Multiplication => LuaSyntaxNode.Tokens.Multiply, - BinaryOperatorType.Division => type.Equals(JassTypeSyntax.Integer) ? LuaSyntaxNode.Tokens.IntegerDiv : LuaSyntaxNode.Tokens.Div, - BinaryOperatorType.GreaterThan => ">", - BinaryOperatorType.LessThan => "<", - BinaryOperatorType.Equals => LuaSyntaxNode.Tokens.EqualsEquals, - BinaryOperatorType.NotEquals => LuaSyntaxNode.Tokens.NotEquals, - BinaryOperatorType.GreaterOrEqual => ">=", - BinaryOperatorType.LessOrEqual => "<=", - BinaryOperatorType.And => LuaSyntaxNode.Keyword.And, - BinaryOperatorType.Or => LuaSyntaxNode.Keyword.Or, - }; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BooleanLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BooleanLiteralExpressionTranspiler.cs deleted file mode 100644 index 693f0489..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BooleanLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassBooleanLiteralExpressionSyntax booleanLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Boolean; - - return booleanLiteralExpression.Value - ? LuaIdentifierLiteralExpressionSyntax.True - : LuaIdentifierLiteralExpressionSyntax.False; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs index 0f2324e0..0ceea5ec 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs @@ -15,7 +15,9 @@ public partial class JassToLuaTranspiler { public LuaStatementSyntax Transpile(JassCallStatementSyntax callStatement) { - return new LuaInvocationExpressionSyntax(Transpile(callStatement.IdentifierName), Transpile(callStatement.Arguments)); + return new LuaInvocationExpressionSyntax( + Transpile(callStatement.IdentifierName, out _), + Transpile(callStatement.ArgumentList)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CharacterLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CharacterLiteralExpressionTranspiler.cs deleted file mode 100644 index 1f2caa73..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CharacterLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassCharacterLiteralExpressionSyntax characterLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Integer; - - return new LuaCharacterLiteralExpression(characterLiteralExpression.Value); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CommentTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CommentTranspiler.cs deleted file mode 100644 index add5aefa..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CommentTranspiler.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaStatementSyntax Transpile(JassCommentSyntax comment) - { - return new LuaShortCommentStatement(comment.Comment); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/DeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/DeclarationTranspiler.cs index c1fcb93b..7f22f671 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/DeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/DeclarationTranspiler.cs @@ -16,19 +16,16 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - public IEnumerable Transpile(ITopLevelDeclarationSyntax declaration) + public IEnumerable Transpile(JassTopLevelDeclarationSyntax declaration) { if (declaration is JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration) { - RegisterFunctionReturnType(nativeFunctionDeclaration.FunctionDeclarator); + RegisterFunctionReturnType(nativeFunctionDeclaration); } return declaration switch { - JassEmptySyntax empty => IgnoreEmptyDeclarations ? Array.Empty() : new[] { Transpile(empty) }, - JassCommentSyntax comment => IgnoreComments ? Array.Empty() : new[] { Transpile(comment) }, - JassGlobalDeclarationListSyntax globalDeclarationList => Transpile(globalDeclarationList), - JassGlobalDeclarationSyntax globalDeclaration => new[] { Transpile(globalDeclaration) }, + JassGlobalsDeclarationSyntax globalsDeclaration => Transpile(globalsDeclaration), JassFunctionDeclarationSyntax functionDeclaration => IgnoreEmptyDeclarations && KeepFunctionsSeparated ? new[] { Transpile(functionDeclaration), LuaBlankLinesStatement.One } : new[] { Transpile(functionDeclaration) }, _ => Array.Empty(), }; diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs similarity index 54% rename from src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayReferenceExpressionTranspiler.cs rename to src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs index b36cf39b..e68bdf92 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayReferenceExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -13,13 +13,13 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - public LuaExpressionSyntax Transpile(JassArrayReferenceExpressionSyntax arrayReferenceExpression, out JassTypeSyntax type) + public LuaExpressionSyntax Transpile(JassElementAccessExpressionSyntax elementAccessExpression, out JassTypeSyntax type) { - type = GetVariableType(arrayReferenceExpression.IdentifierName); + type = GetVariableType(elementAccessExpression.IdentifierName); return new LuaTableIndexAccessExpressionSyntax( - Transpile(arrayReferenceExpression.IdentifierName), - Transpile(arrayReferenceExpression.Indexer, out _)); + Transpile(elementAccessExpression.IdentifierName, out _), + Transpile(elementAccessExpression.ElementAccessClause.Expression, out _)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseClauseTranspiler.cs index 5d06ca4f..26963faf 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseClauseTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass.Syntax; @@ -17,7 +19,7 @@ public LuaElseClauseSyntax Transpile(JassElseClauseSyntax elseClause) { var luaElseClause = new LuaElseClauseSyntax(); - luaElseClause.Body.Statements.AddRange(Transpile(elseClause.Body)); + luaElseClause.Body.Statements.AddRange(elseClause.Statements.Select(Transpile)); return luaElseClause; } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseIfClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseIfClauseTranspiler.cs index 888abeab..5f761af8 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseIfClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElseIfClauseTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass.Syntax; @@ -15,9 +17,9 @@ public partial class JassToLuaTranspiler { public LuaElseIfStatementSyntax Transpile(JassElseIfClauseSyntax elseIfClause) { - var elseifStatement = new LuaElseIfStatementSyntax(Transpile(elseIfClause.Condition, out _)); + var elseifStatement = new LuaElseIfStatementSyntax(Transpile(elseIfClause.ElseIfClauseDeclarator.Condition, out _)); - elseifStatement.Body.Statements.AddRange(Transpile(elseIfClause.Body)); + elseifStatement.Body.Statements.AddRange(elseIfClause.Statements.Select(Transpile)); return elseifStatement; } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/EmptyTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/EmptyTranspiler.cs deleted file mode 100644 index 9bf3c74f..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/EmptyTranspiler.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaStatementSyntax Transpile(JassEmptySyntax empty) - { - return LuaBlankLinesStatement.One; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ExpressionTranspiler.cs index 17b8211b..ddfdd176 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ExpressionTranspiler.cs @@ -13,23 +13,15 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - public LuaExpressionSyntax Transpile(IExpressionSyntax expression, out JassTypeSyntax type) + public LuaExpressionSyntax Transpile(JassExpressionSyntax expression, out JassTypeSyntax type) { return expression switch { - JassCharacterLiteralExpressionSyntax characterLiteralExpression => Transpile(characterLiteralExpression, out type), - JassFourCCLiteralExpressionSyntax fourCCLiteralExpression => Transpile(fourCCLiteralExpression, out type), - JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression => Transpile(hexadecimalLiteralExpression, out type), - JassRealLiteralExpressionSyntax realLiteralExpression => Transpile(realLiteralExpression, out type), - JassOctalLiteralExpressionSyntax octalLiteralExpression => Transpile(octalLiteralExpression, out type), - JassDecimalLiteralExpressionSyntax decimalLiteralExpression => Transpile(decimalLiteralExpression, out type), - JassBooleanLiteralExpressionSyntax booleanLiteralExpression => Transpile(booleanLiteralExpression, out type), - JassStringLiteralExpressionSyntax stringLiteralExpression => Transpile(stringLiteralExpression, out type), - JassNullLiteralExpressionSyntax nullLiteralExpression => Transpile(nullLiteralExpression, out type), + JassLiteralExpressionSyntax literalExpression => Transpile(literalExpression, out type), JassFunctionReferenceExpressionSyntax functionReferenceExpression => Transpile(functionReferenceExpression, out type), JassInvocationExpressionSyntax invocationExpression => Transpile(invocationExpression, out type), - JassArrayReferenceExpressionSyntax arrayReferenceExpression => Transpile(arrayReferenceExpression, out type), - JassVariableReferenceExpressionSyntax variableReferenceExpression => Transpile(variableReferenceExpression, out type), + JassElementAccessExpressionSyntax elementAccessExpression => Transpile(elementAccessExpression, out type), + JassIdentifierNameSyntax identifierName => Transpile(identifierName, out type), JassParenthesizedExpressionSyntax parenthesizedExpression => Transpile(parenthesizedExpression, out type), JassUnaryExpressionSyntax unaryExpression => Transpile(unaryExpression, out type), JassBinaryExpressionSyntax binaryExpression => Transpile(binaryExpression, out type), diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FourCCLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FourCCLiteralExpressionTranspiler.cs deleted file mode 100644 index df843861..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FourCCLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassFourCCLiteralExpressionSyntax fourCCLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Integer; - - return fourCCLiteralExpression.Value; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs index 6b1a9b10..c1605164 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass.Syntax; @@ -19,12 +21,12 @@ public LuaStatementSyntax Transpile(JassFunctionDeclarationSyntax functionDeclar var functionExpression = new LuaFunctionExpressionSyntax(); functionExpression.AddParameters(Transpile(functionDeclaration.FunctionDeclarator.ParameterList)); - functionExpression.Body.Statements.AddRange(Transpile(functionDeclaration.Body)); + functionExpression.Body.Statements.AddRange(functionDeclaration.Statements.Select(Transpile)); functionExpression.RenderAsFunctionDefinition = true; ClearLocalTypes(); - var luaFunctionDeclaration = new LuaVariableDeclaratorSyntax(Transpile(functionDeclaration.FunctionDeclarator.IdentifierName), functionExpression); + var luaFunctionDeclaration = new LuaVariableDeclaratorSyntax(Transpile(functionDeclaration.FunctionDeclarator.IdentifierName, out _), functionExpression); luaFunctionDeclaration.IsLocalDeclaration = false; var declaration = new LuaVariableListDeclarationSyntax(); diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs index f5a25c39..088c75e0 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs @@ -20,7 +20,7 @@ public LuaVariableDeclaratorSyntax Transpile(JassFunctionDeclaratorSyntax functi var functionExpression = new LuaFunctionExpressionSyntax(); functionExpression.AddParameters(Transpile(functionDeclarator.ParameterList)); - return new LuaVariableDeclaratorSyntax(Transpile(functionDeclarator.IdentifierName), functionExpression); + return new LuaVariableDeclaratorSyntax(Transpile(functionDeclarator.IdentifierName, out _), functionExpression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs index 1494e681..812cea09 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs @@ -15,9 +15,9 @@ public partial class JassToLuaTranspiler { public LuaExpressionSyntax Transpile(JassFunctionReferenceExpressionSyntax functionReferenceExpression, out JassTypeSyntax type) { - type = JassTypeSyntax.Code; + type = JassPredefinedTypeSyntax.Code; - return Transpile(functionReferenceExpression.IdentifierName); + return Transpile(functionReferenceExpression.IdentifierName, out _); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationListTranspiler.cs deleted file mode 100644 index 7e713df3..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationListTranspiler.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System; -using System.Collections.Generic; -using System.Linq; - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public IEnumerable Transpile(JassGlobalDeclarationListSyntax globalDeclarationList) - { - return globalDeclarationList.Globals - .Where(declaration => !(declaration is JassCommentSyntax && IgnoreComments)) - .Where(declaration => !(declaration is JassEmptySyntax && IgnoreEmptyDeclarations)) - .Select(declaration => declaration switch - { - JassEmptySyntax empty => Transpile(empty), - JassCommentSyntax comment => Transpile(comment), - JassGlobalDeclarationSyntax globalDeclaration => Transpile(globalDeclaration), - - _ => throw new NotSupportedException(), - }); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs index 791f2d10..0f92e933 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs @@ -15,7 +15,26 @@ public partial class JassToLuaTranspiler { public LuaStatementSyntax Transpile(JassGlobalDeclarationSyntax globalDeclaration) { - return Transpile(globalDeclaration.Declarator, false); + return globalDeclaration switch + { + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => Transpile(globalConstantDeclaration), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => Transpile(globalVariableDeclaration.Declarator, false), + }; + } + + public LuaStatementSyntax Transpile(JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + { + RegisterVariableType(globalConstantDeclaration); + + var expression = Transpile(globalConstantDeclaration.Value); + + var luaDeclarator = new LuaVariableDeclaratorSyntax(Transpile(globalConstantDeclaration.IdentifierName, out _), expression); + luaDeclarator.IsLocalDeclaration = false; + + var declaration = new LuaVariableListDeclarationSyntax(); + declaration.Variables.Add(luaDeclarator); + + return new LuaLocalDeclarationStatementSyntax(declaration); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/DecimalLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalsDeclarationTranspiler.cs similarity index 60% rename from src/War3Net.CodeAnalysis.Transpilers/JassToLua/DecimalLiteralExpressionTranspiler.cs rename to src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalsDeclarationTranspiler.cs index 8938eafe..f82c0fb9 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/DecimalLiteralExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalsDeclarationTranspiler.cs @@ -1,10 +1,13 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Linq; + using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass.Syntax; @@ -13,11 +16,9 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - public LuaExpressionSyntax Transpile(JassDecimalLiteralExpressionSyntax decimalLiteralExpression, out JassTypeSyntax type) + public IEnumerable Transpile(JassGlobalsDeclarationSyntax globalsDeclaration) { - type = JassTypeSyntax.Integer; - - return decimalLiteralExpression.Value; + return globalsDeclaration.GlobalDeclarations.Select(Transpile); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/HexadecimalLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/HexadecimalLiteralExpressionTranspiler.cs deleted file mode 100644 index c393015f..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/HexadecimalLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Integer; - - return hexadecimalLiteralExpression.ToString(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs index 1c2e2ede..ce163909 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs @@ -5,9 +5,7 @@ // // ------------------------------------------------------------------------------ -using System; -using System.Collections.Generic; -using System.Linq; +using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass.Syntax; @@ -15,41 +13,10 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - private const string AntiReservedKeywordConflictPrefix = "_"; - - private static readonly Lazy> _reservedKeywords = new Lazy>(() => GetLuaKeywords().ToHashSet(StringComparer.Ordinal)); - - public string Transpile(JassIdentifierNameSyntax identifierName) - { - return _reservedKeywords.Value.Contains(identifierName.Name) - ? $"{AntiReservedKeywordConflictPrefix}{identifierName.Name}" - : identifierName.Name; - } - - private static IEnumerable GetLuaKeywords() + public LuaIdentifierNameSyntax Transpile(JassIdentifierNameSyntax identifierName, out JassTypeSyntax type) { - yield return "and"; - yield return "break"; - yield return "do"; - yield return "else"; - yield return "elseif"; - yield return "end"; - yield return "false"; - yield return "for"; - yield return "function"; - yield return "goto"; - yield return "if"; - yield return "in"; - yield return "local"; - yield return "nil"; - yield return "not"; - yield return "or"; - yield return "repeat"; - yield return "return"; - yield return "then"; - yield return "true"; - yield return "until"; - yield return "while"; + type = GetVariableType(identifierName); + return identifierName.Token.Text; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IfStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IfStatementTranspiler.cs index fa07f463..e56b7d18 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IfStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IfStatementTranspiler.cs @@ -17,9 +17,9 @@ public partial class JassToLuaTranspiler { public LuaStatementSyntax Transpile(JassIfStatementSyntax ifStatement) { - var luaIfStatement = new LuaIfStatementSyntax(Transpile(ifStatement.Condition, out _)); + var luaIfStatement = new LuaIfStatementSyntax(Transpile(ifStatement.IfClause.IfClauseDeclarator.Condition, out _)); - luaIfStatement.Body.Statements.AddRange(Transpile(ifStatement.Body)); + luaIfStatement.Body.Statements.AddRange(ifStatement.IfClause.Statements.Select(Transpile)); luaIfStatement.ElseIfStatements.AddRange(ifStatement.ElseIfClauses.Select(Transpile)); luaIfStatement.Else = ifStatement.ElseClause is null ? null : Transpile(ifStatement.ElseClause); diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs index 14deb848..b9df11e8 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs @@ -17,9 +17,9 @@ public LuaExpressionSyntax Transpile(JassInvocationExpressionSyntax invocationEx { type = GetFunctionReturnType(invocationExpression.IdentifierName); - var luaInvocationExpression = new LuaInvocationExpressionSyntax(Transpile(invocationExpression.IdentifierName)); + var luaInvocationExpression = new LuaInvocationExpressionSyntax(Transpile(invocationExpression.IdentifierName, out _)); - luaInvocationExpression.AddArguments(Transpile(invocationExpression.Arguments)); + luaInvocationExpression.AddArguments(Transpile(invocationExpression.ArgumentList)); return luaInvocationExpression; } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs new file mode 100644 index 00000000..6d71338a --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs @@ -0,0 +1,109 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Globalization; + +using CSharpLua.LuaAst; + +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToLuaTranspiler + { + public LuaExpressionSyntax Transpile(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + return literalExpression.SyntaxKind switch + { + JassSyntaxKind.TrueLiteralExpression => TranspileTrueLiteral(out type), + JassSyntaxKind.FalseLiteralExpression => TranspileFalseLiteral(out type), + JassSyntaxKind.NullLiteralExpression => TranspileNullLiteral(out type), + JassSyntaxKind.DecimalLiteralExpression => TranspileDecimalLiteral(literalExpression, out type), + JassSyntaxKind.OctalLiteralExpression => TranspileOctalLiteral(literalExpression, out type), + JassSyntaxKind.HexadecimalLiteralExpression => TranspileHexadecimalLiteral(literalExpression, out type), + JassSyntaxKind.FourCCLiteralExpression => TranspileFourCCLiteral(literalExpression, out type), + JassSyntaxKind.CharacterLiteralExpression => TranspileCharacterLiteral(literalExpression, out type), + JassSyntaxKind.RealLiteralExpression => TranspileRealLiteral(literalExpression, out type), + JassSyntaxKind.StringLiteralExpression => TranspileStringLiteral(literalExpression, out type), + }; + } + + private LuaExpressionSyntax TranspileTrueLiteral(out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Boolean; + return new LuaIdentifierLiteralExpressionSyntax(LuaIdentifierNameSyntax.True); + } + + private LuaExpressionSyntax TranspileFalseLiteral(out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Boolean; + return new LuaIdentifierLiteralExpressionSyntax(LuaIdentifierNameSyntax.False); + } + + private LuaExpressionSyntax TranspileNullLiteral(out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Handle; + return new LuaIdentifierLiteralExpressionSyntax(LuaIdentifierNameSyntax.Nil); + } + + private LuaExpressionSyntax TranspileDecimalLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Integer; + return new LuaIdentifierLiteralExpressionSyntax(literalExpression.Token.Text); + } + + private LuaExpressionSyntax TranspileOctalLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Integer; + var text = Convert.ToInt32(literalExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture); + + return new LuaIdentifierLiteralExpressionSyntax(text); + } + + private LuaExpressionSyntax TranspileHexadecimalLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Integer; + var text = literalExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); + + return new LuaIdentifierLiteralExpressionSyntax(text); + } + + private LuaExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Integer; + var text = $"FourCC(\"{literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar)}\")"; + + return new LuaIdentifierLiteralExpressionSyntax(text); + } + + private LuaExpressionSyntax TranspileCharacterLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Integer; + var text = ((int)char.Parse(literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar))).ToString(CultureInfo.InvariantCulture); + + return new LuaIdentifierLiteralExpressionSyntax(text); + } + + private LuaExpressionSyntax TranspileRealLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.Real; + return new LuaIdentifierLiteralExpressionSyntax(literalExpression.Token.Text); + } + + private LuaExpressionSyntax TranspileStringLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) + { + type = JassPredefinedTypeSyntax.String; + var text = literalExpression.Token.Text + .Replace(JassSymbol.CarriageReturn, @"\r", StringComparison.Ordinal) + .Replace(JassSymbol.LineFeed, @"\n", StringComparison.Ordinal); + + return new LuaStringLiteralExpressionSyntax(text); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LoopStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LoopStatementTranspiler.cs index 4ef3db44..7929de22 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LoopStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LoopStatementTranspiler.cs @@ -5,6 +5,8 @@ // // ------------------------------------------------------------------------------ +using System.Linq; + using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass.Syntax; @@ -17,7 +19,7 @@ public LuaStatementSyntax Transpile(JassLoopStatementSyntax loopStatement) { var whileStatement = new LuaWhileStatementSyntax(LuaIdentifierLiteralExpressionSyntax.True); - whileStatement.Body.Statements.AddRange(Transpile(loopStatement.Body)); + whileStatement.Body.Statements.AddRange(loopStatement.Statements.Select(Transpile)); return whileStatement; } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/NullLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/NullLiteralExpressionTranspiler.cs deleted file mode 100644 index cb3874aa..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/NullLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassNullLiteralExpressionSyntax nullLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Handle; - - return LuaIdentifierLiteralExpressionSyntax.Nil; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/OctalLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/OctalLiteralExpressionTranspiler.cs deleted file mode 100644 index c3fa63cb..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/OctalLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassOctalLiteralExpressionSyntax octalLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Integer; - - return octalLiteralExpression.Value; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterListTranspiler.cs index 87cea536..19ae202f 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterListTranspiler.cs @@ -16,9 +16,18 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { + public IEnumerable Transpile(JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) + { + return parameterListOrEmptyParameterList switch + { + JassParameterListSyntax parameterList => Transpile(parameterList), + JassEmptyParameterListSyntax => Enumerable.Empty(), + }; + } + public IEnumerable Transpile(JassParameterListSyntax parameterList) { - return parameterList.Parameters.Select(Transpile); + return parameterList.ParameterList.Items.Select(Transpile); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs index 3e02401a..40e30e4c 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs @@ -17,7 +17,7 @@ public LuaIdentifierNameSyntax Transpile(JassParameterSyntax parameter) { RegisterLocalVariableType(parameter); - return Transpile(parameter.IdentifierName); + return Transpile(parameter.IdentifierName, out _); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/RealLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/RealLiteralExpressionTranspiler.cs deleted file mode 100644 index a5552c01..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/RealLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassRealLiteralExpressionSyntax realLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.Real; - - return realLiteralExpression.ToString(); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs index f4610fdc..3add4891 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs @@ -16,10 +16,10 @@ public partial class JassToLuaTranspiler public LuaStatementSyntax Transpile(JassSetStatementSyntax setStatement) { return new LuaAssignmentExpressionSyntax( - setStatement.Indexer is null - ? Transpile(setStatement.IdentifierName) - : new LuaTableIndexAccessExpressionSyntax(Transpile(setStatement.IdentifierName), Transpile(setStatement.Indexer, out _)), - Transpile(setStatement.Value)); + setStatement.ElementAccessClause is null + ? Transpile(setStatement.IdentifierName, out _) + : new LuaTableIndexAccessExpressionSyntax(Transpile(setStatement.IdentifierName, out _), Transpile(setStatement.ElementAccessClause.Expression, out _)), + Transpile(setStatement.Value.Expression, out _)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementListTranspiler.cs deleted file mode 100644 index f727aad1..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementListTranspiler.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using System.Collections.Generic; -using System.Linq; - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public IEnumerable Transpile(JassStatementListSyntax statementList) - { - return statementList.Statements - .Where(statement => !(statement is JassCommentSyntax && IgnoreComments)) - .Where(statement => !(statement is JassEmptySyntax && IgnoreEmptyStatements)) - .Select(Transpile); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementTranspiler.cs index 594455ba..8caea181 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StatementTranspiler.cs @@ -13,12 +13,10 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - public LuaStatementSyntax Transpile(IStatementSyntax statement) + public LuaStatementSyntax Transpile(JassStatementSyntax statement) { return statement switch { - JassEmptySyntax empty => Transpile(empty), - JassCommentSyntax comment => Transpile(comment), JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement => Transpile(localVariableDeclarationStatement), JassSetStatementSyntax setStatement => Transpile(setStatement), JassCallStatementSyntax callStatement => Transpile(callStatement), diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StringLiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StringLiteralExpressionTranspiler.cs deleted file mode 100644 index 030ab3a0..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/StringLiteralExpressionTranspiler.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassStringLiteralExpressionSyntax stringLiteralExpression, out JassTypeSyntax type) - { - type = JassTypeSyntax.String; - - return $"\"{stringLiteralExpression.Value.Replace($"{JassSymbol.CarriageReturn}", @"\r").Replace($"{JassSymbol.LineFeed}", @"\n")}\""; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SyntaxTokenTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SyntaxTokenTranspiler.cs new file mode 100644 index 00000000..7ebfcaa1 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SyntaxTokenTranspiler.cs @@ -0,0 +1,57 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Linq; + +using CSharpLua.LuaAst; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToLuaTranspiler + { + private const string AntiReservedKeywordConflictPrefix = "_"; + + private static readonly Lazy> _reservedKeywords = new Lazy>(() => GetLuaKeywords().ToHashSet(StringComparer.Ordinal)); + + public string Transpile(JassSyntaxToken token) + { + return _reservedKeywords.Value.Contains(token.Text) + ? $"{AntiReservedKeywordConflictPrefix}{token.Text}" + : token.Text; + } + + private static IEnumerable GetLuaKeywords() + { + yield return LuaSyntaxNode.Keyword.And; + yield return LuaSyntaxNode.Keyword.Break; + yield return LuaSyntaxNode.Keyword.Do; + yield return LuaSyntaxNode.Keyword.Else; + yield return LuaSyntaxNode.Keyword.ElseIf; + yield return LuaSyntaxNode.Keyword.End; + yield return LuaSyntaxNode.Keyword.False; + yield return LuaSyntaxNode.Keyword.For; + yield return LuaSyntaxNode.Keyword.Function; + yield return LuaSyntaxNode.Keyword.Goto; + yield return LuaSyntaxNode.Keyword.If; + yield return LuaSyntaxNode.Keyword.In; + yield return LuaSyntaxNode.Keyword.Local; + yield return LuaSyntaxNode.Keyword.Nil; + yield return LuaSyntaxNode.Keyword.Not; + yield return LuaSyntaxNode.Keyword.Or; + yield return LuaSyntaxNode.Keyword.Repeat; + yield return LuaSyntaxNode.Keyword.Return; + yield return LuaSyntaxNode.Keyword.Then; + yield return LuaSyntaxNode.Keyword.True; + yield return LuaSyntaxNode.Keyword.Until; + yield return LuaSyntaxNode.Keyword.While; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryExpressionTranspiler.cs index fb1de684..74ebcaa5 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryExpressionTranspiler.cs @@ -7,6 +7,7 @@ using CSharpLua.LuaAst; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -17,7 +18,17 @@ public LuaExpressionSyntax Transpile(JassUnaryExpressionSyntax unaryExpression, { return new LuaPrefixUnaryExpressionSyntax( Transpile(unaryExpression.Expression, out type), - Transpile(unaryExpression.Operator)); + TranspileUnaryExpressionKind(unaryExpression.SyntaxKind)); + } + + public string TranspileUnaryExpressionKind(JassSyntaxKind expressionKind) + { + return expressionKind switch + { + JassSyntaxKind.UnaryPlusExpression => LuaSyntaxNode.Tokens.Plus, + JassSyntaxKind.UnaryMinusExpression => LuaSyntaxNode.Tokens.Sub, + JassSyntaxKind.LogicalNotExpression => LuaSyntaxNode.Keyword.Not, + }; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryOperatorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryOperatorTranspiler.cs deleted file mode 100644 index 003cf001..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/UnaryOperatorTranspiler.cs +++ /dev/null @@ -1,26 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public string Transpile(UnaryOperatorType unaryOperator) - { - return unaryOperator switch - { - UnaryOperatorType.Plus => LuaSyntaxNode.Tokens.Plus, - UnaryOperatorType.Minus => LuaSyntaxNode.Tokens.Sub, - UnaryOperatorType.Not => LuaSyntaxNode.Keyword.Not, - }; - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs index adc090f5..77330504 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs @@ -13,7 +13,7 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { - public LuaLocalDeclarationStatementSyntax Transpile(IVariableDeclaratorSyntax declarator, bool isLocalDeclaration) + public LuaLocalDeclarationStatementSyntax Transpile(JassVariableOrArrayDeclaratorSyntax declarator, bool isLocalDeclaration) { RegisterVariableType(declarator, isLocalDeclaration); @@ -37,7 +37,7 @@ public LuaVariableDeclaratorSyntax Transpile(JassVariableDeclaratorSyntax variab ? LuaIdentifierLiteralExpressionSyntax.Nil : Transpile(variableDeclarator.Value); - return new LuaVariableDeclaratorSyntax(Transpile(variableDeclarator.IdentifierName), expression); + return new LuaVariableDeclaratorSyntax(Transpile(variableDeclarator.IdentifierName, out _), expression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableReferenceExpressionTranspiler.cs deleted file mode 100644 index 8f6791e8..00000000 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableReferenceExpressionTranspiler.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -using CSharpLua.LuaAst; - -using War3Net.CodeAnalysis.Jass.Syntax; - -namespace War3Net.CodeAnalysis.Transpilers -{ - public partial class JassToLuaTranspiler - { - public LuaExpressionSyntax Transpile(JassVariableReferenceExpressionSyntax variableReferenceExpression, out JassTypeSyntax type) - { - type = GetVariableType(variableReferenceExpression.IdentifierName); - - return Transpile(variableReferenceExpression.IdentifierName); - } - } -} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs index b15b4914..eda03c77 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs @@ -39,19 +39,19 @@ public void RegisterJassFile(JassCompilationUnitSyntax compilationUnit) { foreach (var declaration in compilationUnit.Declarations) { - if (declaration is JassGlobalDeclarationListSyntax globalDeclarationList) + if (declaration is JassGlobalsDeclarationSyntax globalsDeclaration) { - foreach (var global in globalDeclarationList.Globals) + foreach (var globalDeclaration in globalsDeclaration.GlobalDeclarations) { - if (global is JassGlobalDeclarationSyntax globalDeclaration) + if (globalDeclaration is JassGlobalVariableDeclarationSyntax globalVariableDeclaration) { - RegisterVariableType(globalDeclaration.Declarator, false); + RegisterVariableType(globalVariableDeclaration.Declarator, false); } } } else if (declaration is JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration) { - RegisterFunctionReturnType(nativeFunctionDeclaration.FunctionDeclarator); + RegisterFunctionReturnType(nativeFunctionDeclaration); } else if (declaration is JassFunctionDeclarationSyntax functionDeclaration) { @@ -87,33 +87,43 @@ internal void ClearLocalTypes() internal void RegisterFunctionReturnType(JassFunctionDeclaratorSyntax functionDeclarator) { - _functionReturnTypes.Add(functionDeclarator.IdentifierName.Name, functionDeclarator.ReturnType); + _functionReturnTypes.Add(functionDeclarator.IdentifierName.Token.Text, functionDeclarator.ReturnClause.ReturnType); } - private void RegisterVariableType(IVariableDeclaratorSyntax declarator, bool isLocalDeclaration) + internal void RegisterFunctionReturnType(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration) + { + _functionReturnTypes.Add(nativeFunctionDeclaration.IdentifierName.Token.Text, nativeFunctionDeclaration.ReturnClause.ReturnType); + } + + private void RegisterVariableType(JassVariableOrArrayDeclaratorSyntax declarator, bool isLocalDeclaration) { switch (declarator) { - case JassArrayDeclaratorSyntax arrayDeclarator: (isLocalDeclaration ? _localTypes : _globalTypes).Add(arrayDeclarator.IdentifierName.Name, arrayDeclarator.Type); break; - case JassVariableDeclaratorSyntax variableDeclarator: (isLocalDeclaration ? _localTypes : _globalTypes).Add(variableDeclarator.IdentifierName.Name, variableDeclarator.Type); break; + case JassArrayDeclaratorSyntax arrayDeclarator: (isLocalDeclaration ? _localTypes : _globalTypes).Add(arrayDeclarator.IdentifierName.Token.Text, arrayDeclarator.Type); break; + case JassVariableDeclaratorSyntax variableDeclarator: (isLocalDeclaration ? _localTypes : _globalTypes).Add(variableDeclarator.IdentifierName.Token.Text, variableDeclarator.Type); break; } } + private void RegisterVariableType(JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + { + _globalTypes.Add(globalConstantDeclaration.IdentifierName.Token.Text, globalConstantDeclaration.Type); + } + private void RegisterLocalVariableType(JassParameterSyntax parameter) { - _localTypes.Add(parameter.IdentifierName.Name, parameter.Type); + _localTypes.Add(parameter.IdentifierName.Token.Text, parameter.Type); } private JassTypeSyntax GetFunctionReturnType(JassIdentifierNameSyntax functionName) { - return _functionReturnTypes.TryGetValue(functionName.Name, out var type) + return _functionReturnTypes.TryGetValue(functionName.Token.Text, out var type) ? type : throw new KeyNotFoundException($"Function '{functionName}' could not be found."); } private JassTypeSyntax GetVariableType(JassIdentifierNameSyntax variableName) { - return (_localTypes.TryGetValue(variableName.Name, out var type) || _globalTypes.TryGetValue(variableName.Name, out type)) + return (_localTypes.TryGetValue(variableName.Token.Text, out var type) || _globalTypes.TryGetValue(variableName.Token.Text, out type)) ? type : throw new KeyNotFoundException($"Variable '{variableName}' could not be found."); } From af58f4bfe550ab62f0e44c8e196a6a62fd0cd104 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 8 Nov 2025 17:50:14 +0100 Subject: [PATCH 05/53] Fix JassToLuaTranspiler. --- .../JassToLua/ArrayDeclaratorTranspiler.cs | 2 +- .../JassToLua/CallStatementTranspiler.cs | 2 +- .../JassToLua/ElementAccessExpressionTranspiler.cs | 2 +- .../JassToLua/FunctionDeclarationTranspiler.cs | 2 +- .../JassToLua/FunctionDeclaratorTranspiler.cs | 2 +- .../JassToLua/FunctionReferenceExpressionTranspiler.cs | 2 +- .../JassToLua/GlobalDeclarationTranspiler.cs | 2 +- .../JassToLua/IdentifierNameTranspiler.cs | 5 +++++ .../JassToLua/InvocationExpressionTranspiler.cs | 2 +- .../JassToLua/ParameterTranspiler.cs | 2 +- .../JassToLua/SetStatementTranspiler.cs | 4 ++-- .../JassToLua/VariableDeclaratorTranspiler.cs | 2 +- .../JassToLuaTranspiler.cs | 10 ++++++++-- 13 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs index 5b9fccd4..ac5b558f 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs @@ -25,7 +25,7 @@ public LuaVariableDeclaratorSyntax Transpile(JassArrayDeclaratorSyntax arrayDecl _ => new LuaTableExpression(), }; - return new LuaVariableDeclaratorSyntax(Transpile(arrayDeclarator.IdentifierName, out _), expression); + return new LuaVariableDeclaratorSyntax(Transpile(arrayDeclarator.IdentifierName), expression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs index 0ceea5ec..2c4d6cd4 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/CallStatementTranspiler.cs @@ -16,7 +16,7 @@ public partial class JassToLuaTranspiler public LuaStatementSyntax Transpile(JassCallStatementSyntax callStatement) { return new LuaInvocationExpressionSyntax( - Transpile(callStatement.IdentifierName, out _), + Transpile(callStatement.IdentifierName), Transpile(callStatement.ArgumentList)); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs index e68bdf92..90eed86e 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ElementAccessExpressionTranspiler.cs @@ -18,7 +18,7 @@ public LuaExpressionSyntax Transpile(JassElementAccessExpressionSyntax elementAc type = GetVariableType(elementAccessExpression.IdentifierName); return new LuaTableIndexAccessExpressionSyntax( - Transpile(elementAccessExpression.IdentifierName, out _), + Transpile(elementAccessExpression.IdentifierName), Transpile(elementAccessExpression.ElementAccessClause.Expression, out _)); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs index c1605164..f0f53f6f 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclarationTranspiler.cs @@ -26,7 +26,7 @@ public LuaStatementSyntax Transpile(JassFunctionDeclarationSyntax functionDeclar ClearLocalTypes(); - var luaFunctionDeclaration = new LuaVariableDeclaratorSyntax(Transpile(functionDeclaration.FunctionDeclarator.IdentifierName, out _), functionExpression); + var luaFunctionDeclaration = new LuaVariableDeclaratorSyntax(Transpile(functionDeclaration.FunctionDeclarator.IdentifierName), functionExpression); luaFunctionDeclaration.IsLocalDeclaration = false; var declaration = new LuaVariableListDeclarationSyntax(); diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs index 088c75e0..f5a25c39 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionDeclaratorTranspiler.cs @@ -20,7 +20,7 @@ public LuaVariableDeclaratorSyntax Transpile(JassFunctionDeclaratorSyntax functi var functionExpression = new LuaFunctionExpressionSyntax(); functionExpression.AddParameters(Transpile(functionDeclarator.ParameterList)); - return new LuaVariableDeclaratorSyntax(Transpile(functionDeclarator.IdentifierName, out _), functionExpression); + return new LuaVariableDeclaratorSyntax(Transpile(functionDeclarator.IdentifierName), functionExpression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs index 812cea09..f000054f 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/FunctionReferenceExpressionTranspiler.cs @@ -17,7 +17,7 @@ public LuaExpressionSyntax Transpile(JassFunctionReferenceExpressionSyntax funct { type = JassPredefinedTypeSyntax.Code; - return Transpile(functionReferenceExpression.IdentifierName, out _); + return Transpile(functionReferenceExpression.IdentifierName); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs index 0f92e933..3c26fee2 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/GlobalDeclarationTranspiler.cs @@ -28,7 +28,7 @@ public LuaStatementSyntax Transpile(JassGlobalConstantDeclarationSyntax globalCo var expression = Transpile(globalConstantDeclaration.Value); - var luaDeclarator = new LuaVariableDeclaratorSyntax(Transpile(globalConstantDeclaration.IdentifierName, out _), expression); + var luaDeclarator = new LuaVariableDeclaratorSyntax(Transpile(globalConstantDeclaration.IdentifierName), expression); luaDeclarator.IsLocalDeclaration = false; var declaration = new LuaVariableListDeclarationSyntax(); diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs index ce163909..576e7fe3 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/IdentifierNameTranspiler.cs @@ -13,6 +13,11 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToLuaTranspiler { + public LuaIdentifierNameSyntax Transpile(JassIdentifierNameSyntax identifierName) + { + return identifierName.Token.Text; + } + public LuaIdentifierNameSyntax Transpile(JassIdentifierNameSyntax identifierName, out JassTypeSyntax type) { type = GetVariableType(identifierName); diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs index b9df11e8..c913743a 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/InvocationExpressionTranspiler.cs @@ -17,7 +17,7 @@ public LuaExpressionSyntax Transpile(JassInvocationExpressionSyntax invocationEx { type = GetFunctionReturnType(invocationExpression.IdentifierName); - var luaInvocationExpression = new LuaInvocationExpressionSyntax(Transpile(invocationExpression.IdentifierName, out _)); + var luaInvocationExpression = new LuaInvocationExpressionSyntax(Transpile(invocationExpression.IdentifierName)); luaInvocationExpression.AddArguments(Transpile(invocationExpression.ArgumentList)); diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs index 40e30e4c..3e02401a 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ParameterTranspiler.cs @@ -17,7 +17,7 @@ public LuaIdentifierNameSyntax Transpile(JassParameterSyntax parameter) { RegisterLocalVariableType(parameter); - return Transpile(parameter.IdentifierName, out _); + return Transpile(parameter.IdentifierName); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs index 3add4891..581374bd 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/SetStatementTranspiler.cs @@ -17,8 +17,8 @@ public LuaStatementSyntax Transpile(JassSetStatementSyntax setStatement) { return new LuaAssignmentExpressionSyntax( setStatement.ElementAccessClause is null - ? Transpile(setStatement.IdentifierName, out _) - : new LuaTableIndexAccessExpressionSyntax(Transpile(setStatement.IdentifierName, out _), Transpile(setStatement.ElementAccessClause.Expression, out _)), + ? Transpile(setStatement.IdentifierName) + : new LuaTableIndexAccessExpressionSyntax(Transpile(setStatement.IdentifierName), Transpile(setStatement.ElementAccessClause.Expression, out _)), Transpile(setStatement.Value.Expression, out _)); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs index 77330504..9cbf7017 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/VariableDeclaratorTranspiler.cs @@ -37,7 +37,7 @@ public LuaVariableDeclaratorSyntax Transpile(JassVariableDeclaratorSyntax variab ? LuaIdentifierLiteralExpressionSyntax.Nil : Transpile(variableDeclarator.Value); - return new LuaVariableDeclaratorSyntax(Transpile(variableDeclarator.IdentifierName, out _), expression); + return new LuaVariableDeclaratorSyntax(Transpile(variableDeclarator.IdentifierName), expression); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs index eda03c77..8421ce1f 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLuaTranspiler.cs @@ -43,9 +43,15 @@ public void RegisterJassFile(JassCompilationUnitSyntax compilationUnit) { foreach (var globalDeclaration in globalsDeclaration.GlobalDeclarations) { - if (globalDeclaration is JassGlobalVariableDeclarationSyntax globalVariableDeclaration) + switch (globalDeclaration) { - RegisterVariableType(globalVariableDeclaration.Declarator, false); + case JassGlobalConstantDeclarationSyntax globalConstantDeclaration: + RegisterVariableType(globalConstantDeclaration); + break; + + case JassGlobalVariableDeclarationSyntax globalVariableDeclaration: + RegisterVariableType(globalVariableDeclaration.Declarator, false); + break; } } } From f2065f394a169b66c66b651bc5683b4b2336f449 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:47:21 +0100 Subject: [PATCH 06/53] Fix DebugStatementParser incorrectly trying to parse trailing trivia twice. --- .../JassParser/DebugStatementParser.cs | 10 ++++------ .../JassParser/StatementParser.cs | 3 +-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs index 5431dbda..dbec8cd7 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs @@ -21,20 +21,18 @@ internal static Parser GetDebugStatementParser( Parser callStatementParser, Parser ifStatementParser, Parser loopStatementParser, - Parser triviaParser, - Parser trailingTriviaParser) + Parser triviaParser) { return Map( - (debugToken, statement, trailingTrivia) => (JassStatementSyntax)new JassDebugStatementSyntax( + (debugToken, statement) => (JassStatementSyntax)new JassDebugStatementSyntax( debugToken, - statement.AppendTrailingTrivia(trailingTrivia)), + statement), Keyword.Debug.AsToken(triviaParser, JassSyntaxKind.DebugKeyword), OneOf( setStatementParser, callStatementParser, ifStatementParser, - loopStatementParser), - trailingTriviaParser); + loopStatementParser)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs index cd378a0e..8b7c8f14 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs @@ -46,8 +46,7 @@ internal static Parser GetStatementParser( callStatementParser, ifStatementParser, loopStatementParser, - triviaParser, - trailingTriviaParser)); + triviaParser)); }); } } From 998b647a12921a4cec25fdeda16e20826b12326e Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:49:19 +0100 Subject: [PATCH 07/53] Add ToFullString() methods which include trivia. --- src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs | 7 +++++++ .../Syntax/JassSyntaxNodeOrToken.cs | 7 +++++++ src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs index 2bd531c9..46de4df2 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNode.cs @@ -45,5 +45,12 @@ internal JassSyntaxNode() protected internal abstract JassSyntaxNode ReplaceFirstToken(JassSyntaxToken newToken); protected internal abstract JassSyntaxNode ReplaceLastToken(JassSyntaxToken newToken); + + public string ToFullString() + { + using var writer = new StringWriter(); + WriteTo(writer); + return writer.ToString(); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs index bbf4fed3..a3eef98c 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxNodeOrToken.cs @@ -135,5 +135,12 @@ public override string ToString() ? $"Node: {_node}" : $"Token: {_token}"; } + + public string ToFullString() + { + return TryPickNode(out var node, out var token) + ? node.ToFullString() + : token.ToFullString(); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs index 77f4b5ca..697329cb 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxToken.cs @@ -59,5 +59,7 @@ public void WriteTo(TextWriter writer) } public override string ToString() => Text; + + public string ToFullString() => $"{LeadingTrivia}{Text}{TrailingTrivia}"; } } \ No newline at end of file From a5d4447b0b11036f8fc58fc74517ef6ef26f0703 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:57:16 +0100 Subject: [PATCH 08/53] Add some JASS extension methods for convenience. --- ...erListOrEmptyParameterListSyntaxExtensions.cs | 16 ++++++++++++++++ .../Extensions/SyntaxNodeExtensions.cs | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs index 2d06dd08..e5ceb4d8 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassParameterListOrEmptyParameterListSyntaxExtensions.cs @@ -14,6 +14,22 @@ namespace War3Net.CodeAnalysis.Jass.Extensions { public static class JassParameterListOrEmptyParameterListSyntaxExtensions { + public static JassSyntaxToken GetTakesToken(this JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) + { + if (parameterListOrEmptyParameterList is JassParameterListSyntax parameterList) + { + return parameterList.TakesToken; + } + else if (parameterListOrEmptyParameterList is JassEmptyParameterListSyntax emptyParameterList) + { + return emptyParameterList.TakesToken; + } + else + { + throw new ArgumentException("Unknown parameter list type.", nameof(parameterListOrEmptyParameterList)); + } + } + public static ImmutableArray GetParameters(this JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) { if (parameterListOrEmptyParameterList is JassParameterListSyntax parameterList) diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs index eabb9c59..537446d2 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/SyntaxNodeExtensions.cs @@ -14,6 +14,16 @@ namespace War3Net.CodeAnalysis.Jass.Extensions { public static class SyntaxNodeExtensions { + public static JassSyntaxTriviaList GetLeadingTrivia(this JassSyntaxNode syntaxNode) + { + return syntaxNode.GetFirstToken().LeadingTrivia; + } + + public static JassSyntaxTriviaList GetTrailingTrivia(this JassSyntaxNode syntaxNode) + { + return syntaxNode.GetLastToken().TrailingTrivia; + } + public static TSyntaxNode WithLeadingTrivia(this TSyntaxNode syntaxNode, JassSyntaxTriviaList triviaList) where TSyntaxNode : JassSyntaxNode { From 357c29da9a7d37b2a9b739559406701713e52a6e Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 16 Nov 2025 11:54:24 +0100 Subject: [PATCH 09/53] Support trivia in JassToCSharpTranspiler. --- .../Extensions/JassSyntaxTokenExtensions.cs | 72 +++----- .../JassSyntaxTriviaListExtensions.cs | 30 ++++ .../SeparatedSyntaxListExtensions.cs | 22 +++ src/War3Net.CodeAnalysis.Jass/JassSymbol.cs | 1 + .../Syntax/JassSyntaxTrivia.cs | 2 +- .../Syntax/JassUnaryExpressionSyntax.cs | 2 +- .../SyntaxFactory/SyntaxTriviaListFactory.cs | 100 +++++++++++ .../SeparatedSyntaxListExtensions.cs | 35 ++++ .../Extensions/SyntaxNodeExtensions.cs | 84 +++++++-- .../Extensions/SyntaxTokenExtensions.cs | 30 ++++ .../JassToCSharp/ArgumentListTranspiler.cs | 7 +- .../JassToCSharp/ArrayDeclaratorTranspiler.cs | 97 +++++++++- .../BinaryExpressionTranspiler.cs | 23 +-- .../JassToCSharp/CallStatementTranspiler.cs | 20 ++- .../JassToCSharp/DebugStatementTranspiler.cs | 38 +++- .../ElementAccessClauseTranspiler.cs | 25 +++ .../ElementAccessExpressionTranspiler.cs | 2 +- .../JassToCSharp/ElseClauseTranspiler.cs | 12 +- .../JassToCSharp/ElseIfClauseTranspiler.cs | 60 ++++++- .../EqualsValueClauseTranspiler.cs | 4 +- .../JassToCSharp/ExitStatementTranspiler.cs | 40 ++++- .../JassToCSharp/ExpressionTranspiler.cs | 6 + .../FunctionDeclarationTranspiler.cs | 35 +++- .../FunctionReferenceExpressionTranspiler.cs | 6 +- .../GlobalConstantDeclarationTranspiler.cs | 81 +++++++++ .../GlobalDeclarationTranspiler.cs | 72 +++----- .../GlobalVariableDeclarationTranspiler.cs | 73 ++++++++ .../GlobalsDeclarationTranspiler.cs | 31 +++- .../JassToCSharp/IdentifierNameTranspiler.cs | 73 +++++++- .../JassToCSharp/IfStatementTranspiler.cs | 68 ++++++- .../LiteralExpressionTranspiler.cs | 95 ++++++++-- ...lVariableDeclarationStatementTranspiler.cs | 21 ++- .../JassToCSharp/LoopStatementTranspiler.cs | 15 +- .../NativeFunctionDeclarationTranspiler.cs | 40 ++++- .../JassToCSharp/ParameterListTranspiler.cs | 54 +++++- .../JassToCSharp/ParameterTranspiler.cs | 8 +- .../ParenthesizedExpressionTranspiler.cs | 5 +- .../JassToCSharp/PredefinedTypeTranspiler.cs | 107 +++++++++++ .../JassToCSharp/ReturnStatementTranspiler.cs | 30 +++- .../JassToCSharp/SetStatementTranspiler.cs | 40 +++-- .../JassToCSharp/SyntaxKindTranspiler.cs | 87 +++++++++ .../JassToCSharp/SyntaxTokenTranspiler.cs | 168 +++++++++++++++++- .../JassToCSharp/SyntaxTriviaTranspiler.cs | 6 +- .../JassToCSharp/TypeDeclarationTranspiler.cs | 41 ++++- .../JassToCSharp/TypeTranspiler.cs | 95 ++++++++-- .../JassToCSharp/UnaryExpressionTranspiler.cs | 14 +- .../VariableDeclaratorTranspiler.cs | 81 ++++++--- .../VariableOrArrayDeclaratorTranspiler.cs | 64 +++++++ .../JassToCSharpTranspiler.cs | 114 ++++++++++++ 49 files changed, 1945 insertions(+), 291 deletions(-) create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTriviaListExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/Extensions/SeparatedSyntaxListExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxTokenExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessClauseTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalConstantDeclarationTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalVariableDeclarationTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/PredefinedTypeTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxKindTranspiler.cs create mode 100644 src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableOrArrayDeclaratorTranspiler.cs diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs index 8d5327a1..77be4596 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTokenExtensions.cs @@ -26,139 +26,107 @@ public static JassSyntaxToken WithTrailingTrivia(this JassSyntaxToken token, Jas public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) { - return token.WithLeadingTrivia(AppendTriviaToList(token.LeadingTrivia.Trivia, trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.AppendTriviaToList(token.LeadingTrivia.Trivia, trivia)); } public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList.Trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList.Trivia)); } public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); } public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, IEnumerable triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); } public static JassSyntaxToken AppendLeadingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.LeadingTrivia.Trivia, triviaList)); } public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) { - return token.WithLeadingTrivia(PrependTriviaToList(trivia, token.LeadingTrivia.Trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.PrependTriviaToList(trivia, token.LeadingTrivia.Trivia)); } public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(triviaList.Trivia, token.LeadingTrivia.Trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList.Trivia, token.LeadingTrivia.Trivia)); } public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); } public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, IEnumerable triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); } public static JassSyntaxToken PrependLeadingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) { - return token.WithLeadingTrivia(ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); + return token.WithLeadingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList, token.LeadingTrivia.Trivia)); } public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) { - return token.WithTrailingTrivia(AppendTriviaToList(token.TrailingTrivia.Trivia, trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.AppendTriviaToList(token.TrailingTrivia.Trivia, trivia)); } public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList.Trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList.Trivia)); } public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); } public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, IEnumerable triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); } public static JassSyntaxToken AppendTrailingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(token.TrailingTrivia.Trivia, triviaList)); } public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, JassSyntaxTrivia trivia) { - return token.WithTrailingTrivia(PrependTriviaToList(trivia, token.TrailingTrivia.Trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.PrependTriviaToList(trivia, token.TrailingTrivia.Trivia)); } public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, JassSyntaxTriviaList triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(triviaList.Trivia, token.TrailingTrivia.Trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList.Trivia, token.TrailingTrivia.Trivia)); } public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, params JassSyntaxTrivia[] triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); } public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, IEnumerable triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); } public static JassSyntaxToken PrependTrailingTrivia(this JassSyntaxToken token, ImmutableArray triviaList) { - return token.WithTrailingTrivia(ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); + return token.WithTrailingTrivia(JassSyntaxFactory.ConcatTriviaLists(triviaList, token.TrailingTrivia.Trivia)); } internal static bool NullableEquals(this JassSyntaxToken? objA, JassSyntaxToken? objB) { return (objA is null) == (objB is null); } - - private static JassSyntaxTriviaList AppendTriviaToList(ImmutableArray triviaList, JassSyntaxTrivia trivia) - { - var builder = ImmutableArray.CreateBuilder(triviaList.Length + 1); - builder.AddRange(triviaList); - builder.Add(trivia); - return new JassSyntaxTriviaList(builder.MoveToImmutable()); - } - - private static JassSyntaxTriviaList PrependTriviaToList(JassSyntaxTrivia trivia, ImmutableArray triviaList) - { - var builder = ImmutableArray.CreateBuilder(triviaList.Length + 1); - builder.Add(trivia); - builder.AddRange(triviaList); - return new JassSyntaxTriviaList(builder.MoveToImmutable()); - } - - private static JassSyntaxTriviaList ConcatTriviaLists(ImmutableArray firstList, ImmutableArray secondList) - { - var builder = ImmutableArray.CreateBuilder(firstList.Length + secondList.Length); - builder.AddRange(firstList); - builder.AddRange(secondList); - return new JassSyntaxTriviaList(builder.MoveToImmutable()); - } - - private static JassSyntaxTriviaList ConcatTriviaLists(IEnumerable firstList, IEnumerable secondList) - { - var builder = ImmutableArray.CreateBuilder(); - builder.AddRange(firstList); - builder.AddRange(secondList); - return new JassSyntaxTriviaList(builder.ToImmutable()); - } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTriviaListExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTriviaListExtensions.cs new file mode 100644 index 00000000..bdb1b469 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassSyntaxTriviaListExtensions.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class JassSyntaxTriviaListExtensions + { + public static string GetIndentationString(this JassSyntaxTriviaList triviaList) + { + if (triviaList.Trivia.IsEmpty) + { + return string.Empty; + } + + var lastTrivia = triviaList.Trivia[^1]; + if (lastTrivia.SyntaxKind != JassSyntaxKind.WhitespaceTrivia) + { + return string.Empty; + } + + return lastTrivia.Text; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs index 13ad1a5c..98178263 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/SeparatedSyntaxListExtensions.cs @@ -105,6 +105,28 @@ public static IEnumerable GetDescendantNodesAndTokens(this SeparatedSyntaxList list) + where TItem : JassSyntaxNode + { + if (list.IsEmpty) + { + return JassSyntaxTriviaList.Empty; + } + + return list.Items[0].GetLeadingTrivia(); + } + + public static JassSyntaxTriviaList GetTrailingTrivia(this SeparatedSyntaxList list) + where TItem : JassSyntaxNode + { + if (list.IsEmpty) + { + return JassSyntaxTriviaList.Empty; + } + + return list.Items[^1].GetTrailingTrivia(); + } + internal static SeparatedSyntaxList ReplaceFirstItem(this SeparatedSyntaxList list, TItem newItem) { var items = list.Items.ReplaceFirstItem(newItem); diff --git a/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs b/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs index e6c68c79..9d01c3ae 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSymbol.cs @@ -52,6 +52,7 @@ public static class JassSymbol public const string GreaterThan = ">"; public const string OpenBracket = "["; public const string CloseBracket = "]"; + public const string Space = " "; public const string CarriageReturnLineFeed = "\r\n"; public const string SlashSlash = "//"; diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs index 3d0fbe17..34a69923 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs @@ -13,7 +13,7 @@ namespace War3Net.CodeAnalysis.Jass.Syntax { public class JassSyntaxTrivia { - public static readonly JassSyntaxTrivia SingleSpace = new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, " "); + public static readonly JassSyntaxTrivia SingleSpace = new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, JassSymbol.Space); public static readonly JassSyntaxTrivia Newline = new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, JassSymbol.CarriageReturnLineFeed); internal JassSyntaxTrivia( diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs index e24f2305..c2bc38ed 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassUnaryExpressionSyntax.cs @@ -86,7 +86,7 @@ public override IEnumerable GetDescendantNodesAndTokens() } } - public override string ToString() => $"{OperatorToken}{(OperatorToken.SyntaxKind == JassSyntaxKind.NotKeyword ? " " : string.Empty)}{Expression}"; + public override string ToString() => $"{OperatorToken}{(OperatorToken.SyntaxKind == JassSyntaxKind.NotKeyword ? JassSymbol.Space : string.Empty)}{Expression}"; public override JassSyntaxToken GetFirstToken() => OperatorToken; diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs index 319ad85b..baaf46c0 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaListFactory.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using Pidgin; @@ -45,5 +46,104 @@ public static JassSyntaxTriviaList ParseTrailingTrivia(string text) { return JassParser.Instance.TrailingTriviaListParser.ParseOrThrow(text); } + + public static JassSyntaxTriviaList AppendTriviaToList(ImmutableArray triviaList, JassSyntaxTrivia trivia) + { + var builder = ImmutableArray.CreateBuilder(triviaList.Length + 1); + builder.AddRange(triviaList); + builder.Add(trivia); + return new JassSyntaxTriviaList(builder.MoveToImmutable()); + } + + public static JassSyntaxTriviaList PrependTriviaToList(JassSyntaxTrivia trivia, ImmutableArray triviaList) + { + var builder = ImmutableArray.CreateBuilder(triviaList.Length + 1); + builder.Add(trivia); + builder.AddRange(triviaList); + return new JassSyntaxTriviaList(builder.MoveToImmutable()); + } + + public static JassSyntaxTriviaList ConcatTriviaLists(ImmutableArray firstList, ImmutableArray secondList) + { + var builder = ImmutableArray.CreateBuilder(firstList.Length + secondList.Length); + builder.AddRange(firstList); + builder.AddRange(secondList); + return new JassSyntaxTriviaList(builder.MoveToImmutable()); + } + + public static JassSyntaxTriviaList ConcatTriviaLists(IEnumerable firstList, IEnumerable secondList) + { + var builder = ImmutableArray.CreateBuilder(); + builder.AddRange(firstList); + builder.AddRange(secondList); + return new JassSyntaxTriviaList(builder.ToImmutable()); + } + + public static JassSyntaxTriviaList ConcatTriviaLists(JassSyntaxTriviaList firstList, JassSyntaxTriviaList secondList) + { + return ConcatTriviaLists(firstList.Trivia, secondList.Trivia); + } + + public static JassSyntaxTriviaList ConcatTriviaLists(JassSyntaxTriviaList firstList, JassSyntaxTriviaList secondList, JassSyntaxTriviaList thirdList) + { + var builder = ImmutableArray.CreateBuilder( + firstList.Trivia.Length + + secondList.Trivia.Length + + thirdList.Trivia.Length); + + builder.AddRange(firstList.Trivia); + builder.AddRange(secondList.Trivia); + builder.AddRange(thirdList.Trivia); + + return SyntaxTriviaList(builder.MoveToImmutable()); + } + + public static JassSyntaxTriviaList MergeTriviaLists(JassSyntaxTriviaList firstList, JassSyntaxTriviaList secondList, JassSyntaxTriviaList thirdList) + { + return MergeTrivia(firstList.Trivia.Concat(secondList.Trivia).Concat(thirdList.Trivia).ToList()); + } + + public static JassSyntaxTriviaList MergeTrivia(List triviaList) + { + if (triviaList.Count == 0) + { + return JassSyntaxTriviaList.Empty; + } + + if (triviaList.Count == 1) + { + return SyntaxTriviaList(ImmutableArray.Create(triviaList[0])); + } + + var builder = ImmutableArray.CreateBuilder(); + var aggregatedList = new List(); + var kind = JassSyntaxKind.None; + + foreach (var trivia in triviaList) + { + if (trivia.SyntaxKind == kind) + { + aggregatedList.Add(trivia); + continue; + } + + if (aggregatedList.Count > 0) + { + builder.Add(SyntaxTrivia(kind, string.Concat(aggregatedList.Select(t => t.Text)))); + aggregatedList.Clear(); + } + + aggregatedList.Add(trivia); + kind = trivia.SyntaxKind; + } + + if (aggregatedList.Count > 0) + { + builder.Add(SyntaxTrivia(kind, string.Concat(aggregatedList.Select(t => t.Text)))); + aggregatedList.Clear(); + } + + return SyntaxTriviaList(builder.ToImmutable()); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/Extensions/SeparatedSyntaxListExtensions.cs b/src/War3Net.CodeAnalysis.Transpilers/Extensions/SeparatedSyntaxListExtensions.cs new file mode 100644 index 00000000..474a56b3 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/Extensions/SeparatedSyntaxListExtensions.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace War3Net.CodeAnalysis.Transpilers.Extensions +{ + public static class SeparatedSyntaxListExtensions + { + public static SeparatedSyntaxList WithoutTrivia(this SeparatedSyntaxList nodesAndTokens) + where TNode : SyntaxNode + { + if (nodesAndTokens.Count == 0) + { + return nodesAndTokens; + } + + if (nodesAndTokens.Count == 1) + { + return SyntaxFactory.SingletonSeparatedList(nodesAndTokens[0].WithoutTrivia()); + } + + var firstNode = nodesAndTokens[0]; + nodesAndTokens = nodesAndTokens.Replace(firstNode, firstNode.WithoutLeadingTrivia()); + var lastNode = nodesAndTokens[^1]; + nodesAndTokens = nodesAndTokens.Replace(lastNode, lastNode.WithoutTrailingTrivia()); + return nodesAndTokens; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxNodeExtensions.cs b/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxNodeExtensions.cs index ea990a5a..7a436a39 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxNodeExtensions.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxNodeExtensions.cs @@ -5,6 +5,9 @@ // // ------------------------------------------------------------------------------ +using System.Collections.Generic; +using System.Linq; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -13,27 +16,72 @@ namespace War3Net.CodeAnalysis.Transpilers.Extensions { public static class SyntaxNodeExtensions { + /// The amount of spaces that must be added (or removed) to keep the syntax aligned. + public static TSyntax WithAlignedWhitespace(this TSyntax node, int whitespaceDiff) + where TSyntax : SyntaxNode + { + if (whitespaceDiff == 0 || !node.HasTrailingTrivia) + { + return node; + } + + var trailingWhitespaceTrivia = node.GetTrailingTrivia()[0]; + if (!trailingWhitespaceTrivia.IsKind(SyntaxKind.WhitespaceTrivia)) + { + return node; + } + + if (trailingWhitespaceTrivia.Span.Length == 1 || + trailingWhitespaceTrivia.ToFullString().Any(c => c != ' ')) + { + return node; + } + + var newLength = trailingWhitespaceTrivia.Span.Length + whitespaceDiff; + if (newLength <= 0) + { + newLength = 1; + } + + return node.ReplaceTrivia(trailingWhitespaceTrivia, SyntaxFactory.Whitespace(new string(' ', newLength))); + } + public static TSyntax WithCSharpLuaTemplateAttribute(this TSyntax node, string template) where TSyntax : SyntaxNode { - return node.WithLeadingTrivia( - SyntaxFactory.Trivia( - SyntaxFactory.DocumentationCommentTrivia( - SyntaxKind.SingleLineDocumentationCommentTrivia, - SyntaxFactory.List(new XmlNodeSyntax[] - { - SyntaxFactory.XmlText( - SyntaxFactory.XmlTextLiteral( - SyntaxFactory.TriviaList( - SyntaxFactory.DocumentationCommentExterior("///")), - " ", - " ", - default)), - SyntaxFactory.XmlText( - $"@CSharpLua.Template = \"{template}\""), - SyntaxFactory.XmlText( - SyntaxFactory.XmlTextNewLine("\r\n", false)), - })))); + var newTrivia = SyntaxFactory.Trivia( + SyntaxFactory.DocumentationCommentTrivia( + SyntaxKind.SingleLineDocumentationCommentTrivia, + SyntaxFactory.List(new XmlNodeSyntax[] + { + SyntaxFactory.XmlText( + SyntaxFactory.XmlTextLiteral( + SyntaxFactory.TriviaList( + SyntaxFactory.DocumentationCommentExterior("///")), + " ", + " ", + default)), + SyntaxFactory.XmlText( + $"@CSharpLua.Template = \"{template}\""), + SyntaxFactory.XmlText( + SyntaxFactory.XmlTextNewLine("\r\n", false)), + }))); + + if (node.HasLeadingTrivia) + { + var newTriviaList = new List(2); + var leadingTrivia = node.GetLeadingTrivia(); + var lastLeadingTrivia = leadingTrivia[^1]; + if (lastLeadingTrivia.IsKind(SyntaxKind.WhitespaceTrivia)) + { + newTriviaList.Add(newTrivia); + newTriviaList.Add(lastLeadingTrivia); + } + + return node.InsertTriviaAfter(lastLeadingTrivia, newTriviaList); + } + + return node.WithLeadingTrivia(newTrivia); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxTokenExtensions.cs b/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxTokenExtensions.cs new file mode 100644 index 00000000..77687def --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/Extensions/SyntaxTokenExtensions.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace War3Net.CodeAnalysis.Transpilers.Extensions +{ + public static class SyntaxTokenExtensions + { + public static SyntaxToken WithSpace(this SyntaxToken token) + { + return token.WithTrailingTrivia(SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)); + } + + public static SyntaxToken WithoutLeadingTrivia(this SyntaxToken token) + { + return token.WithLeadingTrivia(SyntaxTriviaList.Empty); + } + + public static SyntaxToken WithoutTrailingTrivia(this SyntaxToken token) + { + return token.WithTrailingTrivia(SyntaxTriviaList.Empty); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs index a2b2fd46..5b1823d0 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArgumentListTranspiler.cs @@ -18,7 +18,12 @@ public partial class JassToCSharpTranspiler { public ArgumentListSyntax Transpile(JassArgumentListSyntax argumentList) { - return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argumentList.ArgumentList.Items.Select(argument => SyntaxFactory.Argument(Transpile(argument))))); + return SyntaxFactory.ArgumentList( + Transpile(SyntaxKind.OpenParenToken, argumentList.OpenParenToken), + SyntaxFactory.SeparatedList( + argumentList.ArgumentList.Items.Select(TranspileArgument), + argumentList.ArgumentList.Separators.Select(Transpile)), + Transpile(SyntaxKind.CloseParenToken, argumentList.CloseParenToken)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs index e409499e..b90a3443 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ArrayDeclaratorTranspiler.cs @@ -5,24 +5,107 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - private VariableDeclarationSyntax Transpile(JassArrayDeclaratorSyntax arrayDeclarator) + private VariableDeclarationSyntax Transpile( + JassArrayDeclaratorSyntax arrayDeclarator, + bool isGlobalDeclaration) { - var type = Transpile(arrayDeclarator.Type); + return Transpile( + arrayDeclarator.GetLeadingTrivia(), + arrayDeclarator, + arrayDeclarator.GetTrailingTrivia(), + isGlobalDeclaration); + } + + private VariableDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassArrayDeclaratorSyntax arrayDeclarator, + bool isGlobalDeclaration) + { + return Transpile( + leadingTrivia, + arrayDeclarator, + arrayDeclarator.GetTrailingTrivia(), + isGlobalDeclaration); + } + + private VariableDeclarationSyntax Transpile( + JassArrayDeclaratorSyntax arrayDeclarator, + JassSyntaxTriviaList trailingTrivia, + bool isGlobalDeclaration) + { + return Transpile( + arrayDeclarator.GetLeadingTrivia(), + arrayDeclarator, + trailingTrivia, + isGlobalDeclaration); + } + + private VariableDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassArrayDeclaratorSyntax arrayDeclarator, + JassSyntaxTriviaList trailingTrivia, + bool isGlobalDeclaration) + { + var typeNode = isGlobalDeclaration + ? TranspileAligned( + leadingTrivia, + arrayDeclarator.Type, + JassSyntaxFactory.MergeTriviaLists( + arrayDeclarator.Type.GetTrailingTrivia(), + arrayDeclarator.ArrayToken.LeadingTrivia, + arrayDeclarator.ArrayToken.TrailingTrivia), + isArray: true) + : Transpile( + leadingTrivia, + arrayDeclarator.Type, + MergeTrivia( + arrayDeclarator.Type.GetTrailingTrivia(), + arrayDeclarator.ArrayToken)); + + var arrayTrivia = typeNode.GetTrailingTrivia(); + + var arrayType = SyntaxFactory.ArrayType( + typeNode.WithoutTrailingTrivia(), + SyntaxFactory.SingletonList( + SyntaxFactory.ArrayRankSpecifier( + SyntaxFactory.Token(SyntaxKind.OpenBracketToken), + SyntaxFactory.SeparatedList(), + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.CloseBracketToken, + arrayTrivia)))); + return SyntaxFactory.VariableDeclaration( - SyntaxFactory.ArrayType(type), - SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(arrayDeclarator.IdentifierName.Token), - null, - SyntaxFactory.EqualsValueClause(SyntaxFactory.ArrayCreationExpression(SyntaxFactory.ArrayType(type)))))); + arrayType, + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.VariableDeclarator( + Transpile(arrayDeclarator.IdentifierName.Token, JassSyntaxTriviaList.SingleSpace), + null, + SyntaxFactory.EqualsValueClause( + TokenWithSpace(SyntaxKind.EqualsToken), + SyntaxFactory.ArrayCreationExpression( + TokenWithSpace(SyntaxKind.NewKeyword), + SyntaxFactory.ArrayType( + typeNode.WithoutTrivia(), + SyntaxFactory.SingletonList( + SyntaxFactory.ArrayRankSpecifier( + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.IdentifierName("JASS_MAX_ARRAY_SIZE"))))), + null))))) + .WithTrailingTrivia(Transpile(trailingTrivia)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs index b6782363..0e4d6790 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/BinaryExpressionTranspiler.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -20,26 +19,10 @@ public ExpressionSyntax Transpile(JassBinaryExpressionSyntax binaryExpression) return SyntaxFactory.BinaryExpression( TranspileBinaryExpressionKind(binaryExpression.SyntaxKind), Transpile(binaryExpression.Left), + Transpile( + TranspileBinaryOperatorKind(binaryExpression.OperatorToken.SyntaxKind), + binaryExpression.OperatorToken), Transpile(binaryExpression.Right)); } - - public SyntaxKind TranspileBinaryExpressionKind(JassSyntaxKind expressionKind) - { - return expressionKind switch - { - JassSyntaxKind.AddExpression => SyntaxKind.AddExpression, - JassSyntaxKind.SubtractExpression => SyntaxKind.SubtractExpression, - JassSyntaxKind.MultiplyExpression => SyntaxKind.MultiplyExpression, - JassSyntaxKind.DivideExpression => SyntaxKind.DivideExpression, - JassSyntaxKind.GreaterThanExpression => SyntaxKind.GreaterThanExpression, - JassSyntaxKind.LessThanExpression => SyntaxKind.LessThanExpression, - JassSyntaxKind.EqualsExpression => SyntaxKind.EqualsExpression, - JassSyntaxKind.NotEqualsExpression => SyntaxKind.NotEqualsExpression, - JassSyntaxKind.GreaterThanOrEqualExpression => SyntaxKind.GreaterThanOrEqualExpression, - JassSyntaxKind.LessThanOrEqualExpression => SyntaxKind.LessThanOrEqualExpression, - JassSyntaxKind.LogicalAndExpression => SyntaxKind.LogicalAndExpression, - JassSyntaxKind.LogicalOrExpression => SyntaxKind.LogicalOrExpression, - }; - } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs index 95cd6996..eea36b1b 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/CallStatementTranspiler.cs @@ -5,6 +5,7 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -16,9 +17,22 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassCallStatementSyntax callStatement) { - return SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression( - Transpile(callStatement.IdentifierName), - Transpile(callStatement.ArgumentList))); + var leadingTrivia = MergeTrivia( + callStatement.CallToken, + callStatement.IdentifierName.Token.LeadingTrivia); + + var invocationExpression = SyntaxFactory.InvocationExpression( + Transpile(leadingTrivia, callStatement.IdentifierName), + Transpile(callStatement.ArgumentList)); + + var trailingTrivia = invocationExpression.GetTrailingTrivia(); + + return SyntaxFactory.ExpressionStatement( + invocationExpression.WithoutTrailingTrivia(), + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.SemicolonToken, + trailingTrivia)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DebugStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DebugStatementTranspiler.cs index 3efccfc3..624e9777 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DebugStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/DebugStatementTranspiler.cs @@ -5,8 +5,11 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -15,7 +18,40 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassDebugStatementSyntax debugStatement) { - return Transpile(debugStatement.Statement); + var leadingTrivia = Transpile(debugStatement.DebugToken.LeadingTrivia); + var statement = Transpile(debugStatement.Statement); + + var ifDebugDirective = SyntaxFactory.Trivia( + SyntaxFactory.IfDirectiveTrivia( + SyntaxFactory.Token(SyntaxKind.HashToken), + Transpile(SyntaxKind.IfKeyword, debugStatement.DebugToken.TrailingTrivia), + SyntaxFactory.IdentifierName("DEBUG"), + SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), + isActive: true, + branchTaken: true, + conditionValue: true)); + + if (leadingTrivia.Count == 0 || leadingTrivia[^1].IsKind(SyntaxKind.EndOfLineTrivia)) + { + leadingTrivia = leadingTrivia.Add(ifDebugDirective); + leadingTrivia = leadingTrivia.Add(SyntaxFactory.CarriageReturnLineFeed); + } + else + { + leadingTrivia = leadingTrivia.Insert(leadingTrivia.Count - 1, ifDebugDirective); + leadingTrivia = leadingTrivia.Insert(leadingTrivia.Count - 1, SyntaxFactory.CarriageReturnLineFeed); + } + + leadingTrivia = leadingTrivia.AddRange(statement.GetLeadingTrivia()); + + var trailingTrivia = statement + .GetTrailingTrivia() + .Add(SyntaxFactory.Trivia(SyntaxFactory.EndIfDirectiveTrivia(isActive: true))) + .Add(SyntaxFactory.CarriageReturnLineFeed); + + return statement + .WithLeadingTrivia(leadingTrivia) + .WithTrailingTrivia(trailingTrivia); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessClauseTranspiler.cs new file mode 100644 index 00000000..4e6479fb --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessClauseTranspiler.cs @@ -0,0 +1,25 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public BracketedArgumentListSyntax Transpile(JassElementAccessClauseSyntax elementAccessClause) + { + return SyntaxFactory.BracketedArgumentList( + Transpile(SyntaxKind.OpenBracketToken, elementAccessClause.OpenBracketToken), + SyntaxFactory.SingletonSeparatedList(TranspileArgument(elementAccessClause.Expression)), + Transpile(SyntaxKind.CloseBracketToken, elementAccessClause.CloseBracketToken)); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs index 2e21af53..1e615526 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElementAccessExpressionTranspiler.cs @@ -18,7 +18,7 @@ public ExpressionSyntax Transpile(JassElementAccessExpressionSyntax elementAcces { return SyntaxFactory.ElementAccessExpression( Transpile(elementAccessExpression.IdentifierName), - SyntaxFactory.BracketedArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(Transpile(elementAccessExpression.ElementAccessClause.Expression))))); + Transpile(elementAccessExpression.ElementAccessClause)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs index 307af617..5f8e7b81 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseClauseTranspiler.cs @@ -7,6 +7,7 @@ using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -16,9 +17,16 @@ namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public ElseClauseSyntax Transpile(JassElseClauseSyntax elseClause) + public ElseClauseSyntax Transpile(JassElseClauseSyntax elseClause, JassSyntaxToken closingToken) { - return SyntaxFactory.ElseClause(SyntaxFactory.Block(elseClause.Statements.Select(Transpile))); + var elseBlock = SyntaxFactory.Block( + Transpile(SyntaxKind.OpenBraceToken, elseClause.ElseToken.TrailingTrivia), + SyntaxFactory.List(elseClause.Statements.Select(Transpile)), + Transpile(SyntaxKind.CloseBraceToken, closingToken)); + + return SyntaxFactory.ElseClause( + Token(SyntaxKind.ElseKeyword, SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + elseBlock); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs index b1ef2e73..48f17a66 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ElseIfClauseTranspiler.cs @@ -7,22 +7,70 @@ using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public StatementSyntax Transpile(JassElseIfClauseSyntax elseIfClause, ElseClauseSyntax? elseClause) + public StatementSyntax Transpile( + JassElseIfClauseSyntax elseIfClause, + ElseClauseSyntax? elseClause, + JassSyntaxToken closingToken) { - return SyntaxFactory.IfStatement( - SyntaxFactory.List(), - Transpile(elseIfClause.ElseIfClauseDeclarator.Condition), - SyntaxFactory.Block(elseIfClause.Statements.Select(Transpile)), - elseClause); + var closeBraceToken = Transpile(SyntaxKind.CloseBraceToken, closingToken); + if (elseClause is not null) + { + closeBraceToken = closeBraceToken.WithSpace(); + } + + var elseIfBlock = SyntaxFactory.Block( + Transpile(SyntaxKind.OpenBraceToken, elseIfClause.ElseIfClauseDeclarator.ThenToken), + SyntaxFactory.List(elseIfClause.Statements.Select(Transpile)), + closeBraceToken); + + if (elseIfClause.ElseIfClauseDeclarator.Condition is JassParenthesizedExpressionSyntax parenthesizedExpression) + { + return SyntaxFactory.IfStatement( + SyntaxFactory.List(), + Transpile(SyntaxKind.IfKeyword, elseIfClause.ElseIfClauseDeclarator.ElseIfToken.TrailingTrivia), + Transpile(SyntaxKind.OpenParenToken, parenthesizedExpression.OpenParenToken), + Transpile(parenthesizedExpression.Expression), + Transpile(SyntaxKind.CloseParenToken, parenthesizedExpression.CloseParenToken), + elseIfBlock, + elseClause); + } + else + { + var trailingTrivia = MergeTrivia( + elseIfClause.ElseIfClauseDeclarator.ElseIfToken.TrailingTrivia, + elseIfClause.ElseIfClauseDeclarator.Condition.GetLeadingTrivia()); + + var leadingTrivia = MergeTrivia( + elseIfClause.ElseIfClauseDeclarator.Condition.GetTrailingTrivia(), + elseIfClause.ElseIfClauseDeclarator.ThenToken.LeadingTrivia); + + return SyntaxFactory.IfStatement( + SyntaxFactory.List(), + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.IfKeyword, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + Transpile(SyntaxKind.OpenParenToken, trailingTrivia), + Transpile(elseIfClause.ElseIfClauseDeclarator.Condition).WithoutTrivia(), + SyntaxFactory.Token( + Transpile(leadingTrivia), + SyntaxKind.CloseParenToken, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + elseIfBlock, + elseClause); + } } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EqualsValueClauseTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EqualsValueClauseTranspiler.cs index c4e5340b..40932100 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EqualsValueClauseTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/EqualsValueClauseTranspiler.cs @@ -16,7 +16,9 @@ public partial class JassToCSharpTranspiler { public EqualsValueClauseSyntax Transpile(JassEqualsValueClauseSyntax equalsValueClause) { - return SyntaxFactory.EqualsValueClause(Transpile(equalsValueClause.Expression)); + return SyntaxFactory.EqualsValueClause( + Transpile(SyntaxKind.EqualsToken, equalsValueClause.EqualsToken), + Transpile(equalsValueClause.Expression)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExitStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExitStatementTranspiler.cs index 658fafa1..20acc919 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExitStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExitStatementTranspiler.cs @@ -5,10 +5,12 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { @@ -16,9 +18,41 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassExitStatementSyntax exitStatement) { - return SyntaxFactory.IfStatement( - Transpile(exitStatement.Condition), - SyntaxFactory.BreakStatement()); + if (exitStatement.Condition is JassParenthesizedExpressionSyntax parenthesizedExpression) + { + return SyntaxFactory.IfStatement( + Transpile(SyntaxKind.IfKeyword, exitStatement.ExitWhenToken), + Transpile(SyntaxKind.OpenParenToken, parenthesizedExpression.OpenParenToken), + Transpile(parenthesizedExpression.Expression), + Transpile( + parenthesizedExpression.CloseParenToken.LeadingTrivia, + SyntaxKind.CloseParenToken, + JassSyntaxTriviaList.SingleSpace), + SyntaxFactory.BreakStatement( + SyntaxFactory.Token(SyntaxKind.BreakKeyword), + Transpile(SyntaxKind.SemicolonToken, parenthesizedExpression.CloseParenToken.TrailingTrivia)), + null); + } + else + { + var expression = Transpile(exitStatement.Condition); + var trailingTrivia = expression.GetTrailingTrivia(); + + return SyntaxFactory.IfStatement( + Transpile(SyntaxKind.IfKeyword, exitStatement.ExitWhenToken), + SyntaxFactory.Token(SyntaxKind.OpenParenToken), + expression.WithoutTrailingTrivia(), + Token( + SyntaxKind.CloseParenToken, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + SyntaxFactory.BreakStatement( + SyntaxFactory.Token(SyntaxKind.BreakKeyword), + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.SemicolonToken, + trailingTrivia)), + null); + } } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs index eb0fee21..645806ef 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ExpressionTranspiler.cs @@ -5,6 +5,7 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; @@ -27,5 +28,10 @@ public ExpressionSyntax Transpile(JassExpressionSyntax expression) JassBinaryExpressionSyntax binaryExpression => Transpile(binaryExpression), }; } + + public ArgumentSyntax TranspileArgument(JassExpressionSyntax expression) + { + return SyntaxFactory.Argument(Transpile(expression)); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs index b0e7d618..9f06c6d8 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionDeclarationTranspiler.cs @@ -11,7 +11,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { @@ -19,18 +21,39 @@ public partial class JassToCSharpTranspiler { public MemberDeclarationSyntax Transpile(JassFunctionDeclarationSyntax functionDeclaration) { + var declarator = functionDeclaration.FunctionDeclarator; + + var firstToken = declarator.ConstantToken ?? declarator.FunctionToken; + var staticToken = declarator.ConstantToken is null + ? TokenWithSpace(SyntaxKind.StaticKeyword) + : Token(SyntaxKind.StaticKeyword, declarator.ConstantToken.TrailingTrivia); + + var functionNameToken = Transpile(declarator.IdentifierName.Token); + var discardTakesTokenLeadingTrivia = false; + if (IsSingleSpace(declarator.IdentifierName.Token.TrailingTrivia, declarator.ParameterList.GetTakesToken().LeadingTrivia)) + { + functionNameToken = functionNameToken.WithoutTrailingTrivia(); + discardTakesTokenLeadingTrivia = true; + } + return SyntaxFactory.MethodDeclaration( default, new SyntaxTokenList( - SyntaxFactory.Token(SyntaxKind.PublicKeyword), - SyntaxFactory.Token(SyntaxKind.StaticKeyword)), - Transpile(functionDeclaration.FunctionDeclarator.ReturnClause.ReturnType), + TokenWithSpace(firstToken.LeadingTrivia, SyntaxKind.PublicKeyword), + staticToken), + Transpile( + declarator.ConstantToken is null ? JassSyntaxTriviaList.Empty : declarator.FunctionToken.LeadingTrivia, + declarator.ReturnClause.ReturnType, + declarator.FunctionToken.TrailingTrivia), null, - Transpile(functionDeclaration.FunctionDeclarator.IdentifierName.Token), + functionNameToken, null, - SyntaxFactory.ParameterList(Transpile(functionDeclaration.FunctionDeclarator.ParameterList)), + Transpile(declarator.ParameterList, declarator.ReturnClause, discardTakesTokenLeadingTrivia), default, - SyntaxFactory.Block(functionDeclaration.Statements.Select(Transpile)), + SyntaxFactory.Block( + Transpile(SyntaxKind.OpenBraceToken, declarator.ReturnClause.ReturnType.GetToken()), + SyntaxFactory.List(functionDeclaration.Statements.Select(Transpile)), + Transpile(SyntaxKind.CloseBraceToken, functionDeclaration.EndFunctionToken)), null); } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs index ae017432..5bc7fcc2 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/FunctionReferenceExpressionTranspiler.cs @@ -15,7 +15,11 @@ public partial class JassToCSharpTranspiler { public ExpressionSyntax Transpile(JassFunctionReferenceExpressionSyntax functionReferenceExpression) { - return Transpile(functionReferenceExpression.IdentifierName); + var leadingTrivia = MergeTrivia( + functionReferenceExpression.FunctionToken, + functionReferenceExpression.IdentifierName.Token.LeadingTrivia); + + return Transpile(leadingTrivia, functionReferenceExpression.IdentifierName); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalConstantDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalConstantDeclarationTranspiler.cs new file mode 100644 index 00000000..d8d64c65 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalConstantDeclarationTranspiler.cs @@ -0,0 +1,81 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public MemberDeclarationSyntax Transpile( + JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + { + return Transpile( + globalConstantDeclaration.GetLeadingTrivia(), + globalConstantDeclaration, + globalConstantDeclaration.GetTrailingTrivia()); + } + + public MemberDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + { + return Transpile( + leadingTrivia, + globalConstantDeclaration, + globalConstantDeclaration.GetTrailingTrivia()); + } + + public MemberDeclarationSyntax Transpile( + JassGlobalConstantDeclarationSyntax globalConstantDeclaration, + JassSyntaxTriviaList trailingTrivia) + { + return Transpile( + globalConstantDeclaration.GetLeadingTrivia(), + globalConstantDeclaration, + trailingTrivia); + } + + public MemberDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassGlobalConstantDeclarationSyntax globalConstantDeclaration, + JassSyntaxTriviaList trailingTrivia) + { + var variableDeclaration = SyntaxFactory.VariableDeclaration( + TranspileAligned(globalConstantDeclaration.Type, isArray: false), + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.VariableDeclarator( + Transpile(globalConstantDeclaration.IdentifierName.Token), + null, + Transpile(globalConstantDeclaration.Value)))); + + var declaration = SyntaxFactory.FieldDeclaration( + default, + new SyntaxTokenList( + TokenWithSpace(leadingTrivia, SyntaxKind.PublicKeyword), + Transpile(SyntaxKind.ConstKeyword, globalConstantDeclaration.ConstantToken)), + variableDeclaration, + Transpile(SyntaxKind.SemicolonToken, globalConstantDeclaration.GetTrailingTrivia())); + + if (ApplyCSharpLuaTemplateAttribute) + { + var jassToLuaTranspiler = JassToLuaTranspiler ?? new JassToLuaTranspiler(); + + declaration = declaration.WithCSharpLuaTemplateAttribute( + jassToLuaTranspiler.Transpile(globalConstantDeclaration.IdentifierName.Token)); + } + + return declaration; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs index a2bbb5a5..cabbb3bc 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalDeclarationTranspiler.cs @@ -5,18 +5,16 @@ // // ------------------------------------------------------------------------------ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public MemberDeclarationSyntax Transpile(JassGlobalDeclarationSyntax globalDeclaration) + public MemberDeclarationSyntax Transpile( + JassGlobalDeclarationSyntax globalDeclaration) { return globalDeclaration switch { @@ -25,54 +23,38 @@ public MemberDeclarationSyntax Transpile(JassGlobalDeclarationSyntax globalDecla }; } - public MemberDeclarationSyntax Transpile(JassGlobalConstantDeclarationSyntax globalConstantDeclaration) + public MemberDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassGlobalDeclarationSyntax globalDeclaration) { - var variableDeclaration = SyntaxFactory.VariableDeclaration( - Transpile(globalConstantDeclaration.Type), - SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(globalConstantDeclaration.IdentifierName.Token), - null, - Transpile(globalConstantDeclaration.Value)))); - - var declaration = SyntaxFactory.FieldDeclaration( - default, - new SyntaxTokenList( - SyntaxFactory.Token(SyntaxKind.PublicKeyword), - SyntaxFactory.Token(SyntaxKind.ConstKeyword)), - variableDeclaration); - - if (ApplyCSharpLuaTemplateAttribute) + return globalDeclaration switch { - var jassToLuaTranspiler = JassToLuaTranspiler ?? new JassToLuaTranspiler(); - - declaration = declaration.WithCSharpLuaTemplateAttribute(jassToLuaTranspiler.Transpile(globalConstantDeclaration.IdentifierName.Token)); - } - - return declaration; + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => Transpile(leadingTrivia, globalConstantDeclaration), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => Transpile(leadingTrivia, globalVariableDeclaration), + }; } - public MemberDeclarationSyntax Transpile(JassGlobalVariableDeclarationSyntax globalVariableDeclaration) + public MemberDeclarationSyntax Transpile( + JassGlobalDeclarationSyntax globalDeclaration, + JassSyntaxTriviaList trailingTrivia) { - var declaration = SyntaxFactory.FieldDeclaration( - default, - new SyntaxTokenList( - SyntaxFactory.Token(SyntaxKind.PublicKeyword), - SyntaxFactory.Token(SyntaxKind.StaticKeyword)), - Transpile(globalVariableDeclaration.Declarator)); - - if (ApplyCSharpLuaTemplateAttribute) + return globalDeclaration switch { - var jassToLuaTranspiler = JassToLuaTranspiler ?? new JassToLuaTranspiler(); - var token = globalVariableDeclaration.Declarator switch - { - JassArrayDeclaratorSyntax arrayDeclarator => arrayDeclarator.IdentifierName.Token, - JassVariableDeclaratorSyntax variableDeclarator => variableDeclarator.IdentifierName.Token, - }; - - declaration = declaration.WithCSharpLuaTemplateAttribute(jassToLuaTranspiler.Transpile(token)); - } + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => Transpile(globalConstantDeclaration, trailingTrivia), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => Transpile(globalVariableDeclaration, trailingTrivia), + }; + } - return declaration; + public MemberDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassGlobalDeclarationSyntax globalDeclaration, + JassSyntaxTriviaList trailingTrivia) + { + return globalDeclaration switch + { + JassGlobalConstantDeclarationSyntax globalConstantDeclaration => Transpile(leadingTrivia, globalConstantDeclaration, trailingTrivia), + JassGlobalVariableDeclarationSyntax globalVariableDeclaration => Transpile(leadingTrivia, globalVariableDeclaration, trailingTrivia), + }; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalVariableDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalVariableDeclarationTranspiler.cs new file mode 100644 index 00000000..242923fd --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalVariableDeclarationTranspiler.cs @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using War3Net.CodeAnalysis.Jass.Extensions; +using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public MemberDeclarationSyntax Transpile( + JassGlobalVariableDeclarationSyntax globalVariableDeclaration) + { + return Transpile( + globalVariableDeclaration.GetLeadingTrivia(), + globalVariableDeclaration, + globalVariableDeclaration.GetTrailingTrivia()); + } + + public MemberDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassGlobalVariableDeclarationSyntax globalVariableDeclaration) + { + return Transpile( + leadingTrivia, + globalVariableDeclaration, + globalVariableDeclaration.GetTrailingTrivia()); + } + + public MemberDeclarationSyntax Transpile( + JassGlobalVariableDeclarationSyntax globalVariableDeclaration, + JassSyntaxTriviaList trailingTrivia) + { + return Transpile( + globalVariableDeclaration.GetLeadingTrivia(), + globalVariableDeclaration, + trailingTrivia); + } + + public MemberDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassGlobalVariableDeclarationSyntax globalVariableDeclaration, + JassSyntaxTriviaList trailingTrivia) + { + var declaration = SyntaxFactory.FieldDeclaration( + default, + new SyntaxTokenList( + TokenWithSpace(leadingTrivia, SyntaxKind.PublicKeyword), + TokenWithSpace(SyntaxKind.StaticKeyword)), + Transpile(globalVariableDeclaration.Declarator, isGlobalDeclaration: true).WithoutTrivia(), + Transpile(SyntaxKind.SemicolonToken, trailingTrivia)); + + if (ApplyCSharpLuaTemplateAttribute) + { + var jassToLuaTranspiler = JassToLuaTranspiler ?? new JassToLuaTranspiler(); + + declaration = declaration.WithCSharpLuaTemplateAttribute( + jassToLuaTranspiler.Transpile(globalVariableDeclaration.Declarator.GetIdentifierName().Token)); + } + + return declaration; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs index 8f6af9d0..9d7522f1 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/GlobalsDeclarationTranspiler.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -17,9 +18,35 @@ public partial class JassToCSharpTranspiler { public IEnumerable Transpile(JassGlobalsDeclarationSyntax globalsDeclaration) { - foreach (var declaration in globalsDeclaration.GlobalDeclarations) + var declarations = globalsDeclaration.GlobalDeclarations; + for (var i = 0; i < declarations.Length; i++) { - yield return Transpile(declaration); + if (i == 0) + { + if (i + 1 == declarations.Length) + { + yield return Transpile( + MergeTrivia(globalsDeclaration.GlobalsToken, declarations[i].GetLeadingTrivia()), + declarations[i], + MergeTrivia(declarations[i].GetTrailingTrivia(), globalsDeclaration.EndGlobalsToken)); + } + else + { + yield return Transpile( + MergeTrivia(globalsDeclaration.GlobalsToken, declarations[i].GetLeadingTrivia()), + declarations[i]); + } + } + else if (i + 1 == declarations.Length) + { + yield return Transpile( + declarations[i], + MergeTrivia(declarations[i].GetTrailingTrivia(), globalsDeclaration.EndGlobalsToken)); + } + else + { + yield return Transpile(declarations[i]); + } } } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs index 0497b969..9b253f77 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IdentifierNameTranspiler.cs @@ -9,14 +9,85 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public IdentifierNameSyntax Transpile(JassIdentifierNameSyntax identifierName) + public IdentifierNameSyntax Transpile( + JassIdentifierNameSyntax identifierName) { return SyntaxFactory.IdentifierName(Transpile(identifierName.Token)); } + + public IdentifierNameSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassIdentifierNameSyntax identifierName) + { + return SyntaxFactory.IdentifierName(Transpile(leadingTrivia, identifierName.Token)); + } + + public IdentifierNameSyntax Transpile( + JassIdentifierNameSyntax identifierName, + JassSyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.IdentifierName(Transpile(identifierName.Token, trailingTrivia)); + } + + public IdentifierNameSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassIdentifierNameSyntax identifierName, + JassSyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.IdentifierName(Transpile(leadingTrivia, identifierName.Token, trailingTrivia)); + } + + public IdentifierNameSyntax TranspileAligned( + JassIdentifierNameSyntax identifierName, + bool isArray) + { + return SyntaxFactory.IdentifierName(TranspileAligned(identifierName.Token, out var prefixAdded)) + .WithAlignedWhitespace(GetWhitespaceDiff(prefixAdded, isArray)); + } + + public IdentifierNameSyntax TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassIdentifierNameSyntax identifierName, + bool isArray) + { + return SyntaxFactory.IdentifierName(TranspileAligned(leadingTrivia, identifierName.Token, out var prefixAdded)) + .WithAlignedWhitespace(GetWhitespaceDiff(prefixAdded, isArray)); + } + + public IdentifierNameSyntax TranspileAligned( + JassIdentifierNameSyntax identifierName, + JassSyntaxTriviaList trailingTrivia, + bool isArray) + { + return SyntaxFactory.IdentifierName(TranspileAligned(identifierName.Token, trailingTrivia, out var prefixAdded)) + .WithAlignedWhitespace(GetWhitespaceDiff(prefixAdded, isArray)); + } + + public IdentifierNameSyntax TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassIdentifierNameSyntax identifierName, + JassSyntaxTriviaList trailingTrivia, + bool isArray) + { + return SyntaxFactory.IdentifierName(TranspileAligned(leadingTrivia, identifierName.Token, trailingTrivia, out var prefixAdded)) + .WithAlignedWhitespace(GetWhitespaceDiff(prefixAdded, isArray)); + } + + private int GetWhitespaceDiff(bool prefixAdded, bool isArray) + { + return prefixAdded + ? isArray + ? ArrayWhitespaceDiff + PrefixWhitespaceDiff + : PrefixWhitespaceDiff + : isArray + ? ArrayWhitespaceDiff + : 0; + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs index c03e54a2..463b460e 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/IfStatementTranspiler.cs @@ -7,10 +7,13 @@ using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { @@ -19,21 +22,72 @@ public partial class JassToCSharpTranspiler public StatementSyntax Transpile(JassIfStatementSyntax ifStatement) { ElseClauseSyntax? elseClause = null; + JassSyntaxToken closingToken = ifStatement.EndIfToken; + if (ifStatement.ElseClause is not null) { - elseClause = Transpile(ifStatement.ElseClause); + elseClause = Transpile(ifStatement.ElseClause, closingToken); + closingToken = ifStatement.ElseClause.ElseToken; } foreach (var elseIfClause in ifStatement.ElseIfClauses.Reverse()) { - elseClause = SyntaxFactory.ElseClause(Transpile(elseIfClause, elseClause)); + elseClause = SyntaxFactory.ElseClause( + Token( + SyntaxKind.ElseKeyword, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + Transpile(elseIfClause, elseClause, closingToken)); + + closingToken = elseIfClause.ElseIfClauseDeclarator.ElseIfToken; + } + + var closeBraceToken = Transpile(SyntaxKind.CloseBraceToken, closingToken); + if (elseClause is not null) + { + closeBraceToken = closeBraceToken.WithSpace(); + } + + var ifBlock = SyntaxFactory.Block( + Transpile(SyntaxKind.OpenBraceToken, ifStatement.IfClause.IfClauseDeclarator.ThenToken), + SyntaxFactory.List(ifStatement.IfClause.Statements.Select(Transpile)), + closeBraceToken); + + if (ifStatement.IfClause.IfClauseDeclarator.Condition is JassParenthesizedExpressionSyntax parenthesizedExpression) + { + return SyntaxFactory.IfStatement( + SyntaxFactory.List(), + Transpile(SyntaxKind.IfKeyword, ifStatement.IfClause.IfClauseDeclarator.IfToken), + Transpile(SyntaxKind.OpenParenToken, parenthesizedExpression.OpenParenToken), + Transpile(parenthesizedExpression.Expression), + Transpile(SyntaxKind.CloseParenToken, parenthesizedExpression.CloseParenToken), + ifBlock, + elseClause); } + else + { + var trailingTrivia = MergeTrivia( + ifStatement.IfClause.IfClauseDeclarator.IfToken.TrailingTrivia, + ifStatement.IfClause.IfClauseDeclarator.Condition.GetLeadingTrivia()); + + var leadingTrivia = MergeTrivia( + ifStatement.IfClause.IfClauseDeclarator.Condition.GetTrailingTrivia(), + ifStatement.IfClause.IfClauseDeclarator.ThenToken.LeadingTrivia); - return SyntaxFactory.IfStatement( - SyntaxFactory.List(), - Transpile(ifStatement.IfClause.IfClauseDeclarator.Condition), - SyntaxFactory.Block(ifStatement.IfClause.Statements.Select(Transpile)), - elseClause); + return SyntaxFactory.IfStatement( + SyntaxFactory.List(), + SyntaxFactory.Token( + Transpile(ifStatement.IfClause.IfClauseDeclarator.IfToken.LeadingTrivia), + SyntaxKind.IfKeyword, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + Transpile(SyntaxKind.OpenParenToken, trailingTrivia), + Transpile(ifStatement.IfClause.IfClauseDeclarator.Condition).WithoutTrivia(), + SyntaxFactory.Token( + Transpile(leadingTrivia), + SyntaxKind.CloseParenToken, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + ifBlock, + elseClause); + } } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs index aae1ad73..6616e173 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs @@ -23,10 +23,10 @@ public ExpressionSyntax Transpile(JassLiteralExpressionSyntax literalExpression) { return literalExpression.SyntaxKind switch { - JassSyntaxKind.TrueLiteralExpression => SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression), - JassSyntaxKind.FalseLiteralExpression => SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression), - JassSyntaxKind.NullLiteralExpression => SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression), - JassSyntaxKind.DecimalLiteralExpression => SyntaxFactory.ParseExpression(literalExpression.Token.Text), + JassSyntaxKind.TrueLiteralExpression => TranspileLiteral(SyntaxKind.TrueLiteralExpression, SyntaxKind.TrueKeyword, literalExpression.Token), + JassSyntaxKind.FalseLiteralExpression => TranspileLiteral(SyntaxKind.FalseLiteralExpression, SyntaxKind.FalseKeyword, literalExpression.Token), + JassSyntaxKind.NullLiteralExpression => TranspileLiteral(SyntaxKind.NullLiteralExpression, SyntaxKind.NullKeyword, literalExpression.Token), + JassSyntaxKind.DecimalLiteralExpression => TranspileDecimalLiteral(literalExpression), JassSyntaxKind.OctalLiteralExpression => TranspileOctalLiteral(literalExpression), JassSyntaxKind.HexadecimalLiteralExpression => TranspileHexadecimalLiteral(literalExpression), JassSyntaxKind.FourCCLiteralExpression => TranspileFourCCLiteral(literalExpression), @@ -36,34 +36,95 @@ public ExpressionSyntax Transpile(JassLiteralExpressionSyntax literalExpression) }; } + private ExpressionSyntax TranspileLiteral(SyntaxKind expressionKind, SyntaxKind tokenKind, JassSyntaxToken token) + { + return SyntaxFactory.LiteralExpression( + expressionKind, + Transpile(tokenKind, token)); + } + + private ExpressionSyntax TranspileDecimalLiteral(JassLiteralExpressionSyntax literalExpression) + { + var value = Convert.ToInt32(literalExpression.Token.Text, 10); + var text = value.ToString(CultureInfo.InvariantCulture); + + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + text, + value, + Transpile(literalExpression.Token.TrailingTrivia))); + } + private ExpressionSyntax TranspileOctalLiteral(JassLiteralExpressionSyntax literalExpression) { - var text = Convert.ToInt32(literalExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture); - return SyntaxFactory.ParseExpression(text); + var value = Convert.ToInt32(literalExpression.Token.Text, 8); + var text = value.ToString(CultureInfo.InvariantCulture); + + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + text, + value, + Transpile(literalExpression.Token.TrailingTrivia))); } private ExpressionSyntax TranspileHexadecimalLiteral(JassLiteralExpressionSyntax literalExpression) { var text = literalExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); - return SyntaxFactory.ParseExpression(text); + var value = Convert.ToInt32(text[2..], 16); + + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + text, + value, + Transpile(literalExpression.Token.TrailingTrivia))); } private ExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax literalExpression) { - var text = literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar).FromRawcode().ToString(CultureInfo.InvariantCulture); - return SyntaxFactory.ParseExpression(text); + var value = literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar).FromRawcode(); + var text = value.ToString(CultureInfo.InvariantCulture); + + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + text, + value, + Transpile(literalExpression.Token.TrailingTrivia))); } private ExpressionSyntax TranspileCharacterLiteral(JassLiteralExpressionSyntax literalExpression) { - var text = ((int)char.Parse(literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar))).ToString(CultureInfo.InvariantCulture); - return SyntaxFactory.ParseExpression(text); + var value = (int)char.Parse(literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar)); + var text = $"(int){literalExpression.Token.Text}"; + + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + text, + value, + Transpile(literalExpression.Token.TrailingTrivia))); } private ExpressionSyntax TranspileRealLiteral(JassLiteralExpressionSyntax literalExpression) { - var text = $"{literalExpression.Token.Text.TrimEnd(JassSymbol.DotChar)}f"; - return SyntaxFactory.ParseExpression(text); + var text = literalExpression.Token.Text.TrimEnd(JassSymbol.DotChar); + var value = float.Parse(text, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture); + + return SyntaxFactory.LiteralExpression( + SyntaxKind.NumericLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + $"{text}f", + value, + Transpile(literalExpression.Token.TrailingTrivia))); } private ExpressionSyntax TranspileStringLiteral(JassLiteralExpressionSyntax literalExpression) @@ -72,7 +133,13 @@ private ExpressionSyntax TranspileStringLiteral(JassLiteralExpressionSyntax lite .Replace(JassSymbol.CarriageReturn, @"\r", StringComparison.Ordinal) .Replace(JassSymbol.LineFeed, @"\n", StringComparison.Ordinal); - return SyntaxFactory.ParseExpression(text); + return SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, + SyntaxFactory.Literal( + Transpile(literalExpression.Token.LeadingTrivia), + text, + text, + Transpile(literalExpression.Token.TrailingTrivia))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LocalVariableDeclarationStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LocalVariableDeclarationStatementTranspiler.cs index 5af76cd6..4d9f0cc8 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LocalVariableDeclarationStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LocalVariableDeclarationStatementTranspiler.cs @@ -5,9 +5,11 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -16,7 +18,24 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement) { - return SyntaxFactory.LocalDeclarationStatement(Transpile(localVariableDeclarationStatement.Declarator)); + var leadingTrivia = MergeTrivia( + localVariableDeclarationStatement.LocalToken, + localVariableDeclarationStatement.Declarator.GetLeadingTrivia()); + + var declaration = Transpile( + leadingTrivia, + localVariableDeclarationStatement.Declarator, + isGlobalDeclaration: false); + + var trailingTrivia = declaration.GetTrailingTrivia(); + + return SyntaxFactory.LocalDeclarationStatement( + SyntaxFactory.TokenList(), + declaration.WithoutTrailingTrivia(), + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.SemicolonToken, + trailingTrivia)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs index e72f15f3..de9b4494 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LoopStatementTranspiler.cs @@ -7,6 +7,7 @@ using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -19,8 +20,20 @@ public partial class JassToCSharpTranspiler public StatementSyntax Transpile(JassLoopStatementSyntax loopStatement) { return SyntaxFactory.WhileStatement( + Transpile( + loopStatement.LoopToken.LeadingTrivia, + SyntaxKind.WhileKeyword, + JassSyntaxTriviaList.SingleSpace), + SyntaxFactory.Token(SyntaxKind.OpenParenToken), SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression), - SyntaxFactory.Block(loopStatement.Statements.Select(Transpile))); + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.CloseParenToken, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)), + SyntaxFactory.Block( + Transpile(SyntaxKind.OpenBraceToken, loopStatement.LoopToken.TrailingTrivia), + SyntaxFactory.List(loopStatement.Statements.Select(Transpile)), + Transpile(SyntaxKind.CloseBraceToken, loopStatement.EndLoopToken))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs index f2dcf8fa..29afcd19 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/NativeFunctionDeclarationTranspiler.cs @@ -9,7 +9,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { @@ -17,21 +19,45 @@ public partial class JassToCSharpTranspiler { public MemberDeclarationSyntax Transpile(JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration) { + var firstToken = nativeFunctionDeclaration.ConstantToken ?? nativeFunctionDeclaration.NativeToken; + var externToken = nativeFunctionDeclaration.ConstantToken is null + ? TokenWithSpace(SyntaxKind.ExternKeyword) + : Token(SyntaxKind.ExternKeyword, nativeFunctionDeclaration.ConstantToken.TrailingTrivia); + + var functionNameToken = Transpile(nativeFunctionDeclaration.IdentifierName.Token); + var discardTakesTokenLeadingTrivia = false; + if (IsSingleSpace(nativeFunctionDeclaration.IdentifierName.Token.TrailingTrivia, nativeFunctionDeclaration.ParameterList.GetTakesToken().LeadingTrivia)) + { + functionNameToken = functionNameToken.WithoutTrailingTrivia(); + discardTakesTokenLeadingTrivia = true; + } + + var parameterList = Transpile( + nativeFunctionDeclaration.ParameterList, + nativeFunctionDeclaration.ReturnClause, + discardTakesTokenLeadingTrivia); + return SyntaxFactory.MethodDeclaration( default, new SyntaxTokenList( - SyntaxFactory.Token(SyntaxKind.PublicKeyword), - SyntaxFactory.Token(SyntaxKind.StaticKeyword), - SyntaxFactory.Token(SyntaxKind.ExternKeyword)), - Transpile(nativeFunctionDeclaration.ReturnClause.ReturnType), + TokenWithSpace(firstToken.LeadingTrivia, SyntaxKind.PublicKeyword), + TokenWithSpace(SyntaxKind.StaticKeyword), + externToken), + Transpile( + nativeFunctionDeclaration.ConstantToken is null ? JassSyntaxTriviaList.Empty : nativeFunctionDeclaration.NativeToken.LeadingTrivia, + nativeFunctionDeclaration.ReturnClause.ReturnType, + nativeFunctionDeclaration.NativeToken.TrailingTrivia), null, - Transpile(nativeFunctionDeclaration.IdentifierName.Token), + functionNameToken, null, - SyntaxFactory.ParameterList(Transpile(nativeFunctionDeclaration.ParameterList)), + parameterList.WithoutTrailingTrivia(), default, null, null, - SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + SyntaxFactory.Token( + MergeTrivia(parameterList.GetTrailingTrivia(), Transpile(nativeFunctionDeclaration.ReturnClause.ReturnType.GetLeadingTrivia())), + SyntaxKind.SemicolonToken, + Transpile(nativeFunctionDeclaration.ReturnClause.ReturnType.GetTrailingTrivia()))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs index 100acab2..521974ce 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterListTranspiler.cs @@ -11,24 +11,68 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public SeparatedSyntaxList Transpile(JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList) + public ParameterListSyntax Transpile( + JassParameterListOrEmptyParameterListSyntax parameterListOrEmptyParameterList, + JassReturnClauseSyntax returnClause, + bool discardTakesTokenLeadingTrivia) { return parameterListOrEmptyParameterList switch { - JassParameterListSyntax parameterList => Transpile(parameterList), - JassEmptyParameterListSyntax => SyntaxFactory.SeparatedList(), + JassParameterListSyntax parameterList => Transpile(parameterList, returnClause, discardTakesTokenLeadingTrivia), + JassEmptyParameterListSyntax emptyParameterList => Transpile(emptyParameterList, returnClause, discardTakesTokenLeadingTrivia), }; } - public SeparatedSyntaxList Transpile(JassParameterListSyntax parameterList) + public ParameterListSyntax Transpile( + JassParameterListSyntax parameterList, + JassReturnClauseSyntax returnClause, + bool discardTakesTokenLeadingTrivia) { - return SyntaxFactory.SeparatedList(parameterList.ParameterList.Items.Select(Transpile)); + var openParenToken = Transpile( + discardTakesTokenLeadingTrivia ? JassSyntaxTriviaList.Empty : parameterList.TakesToken.LeadingTrivia, + SyntaxKind.OpenParenToken, + MergeTrivia(parameterList.TakesToken.TrailingTrivia, parameterList.GetLeadingTrivia())); + + var closeParenToken = Transpile( + MergeTrivia(parameterList.GetTrailingTrivia(), returnClause.ReturnsToken.LeadingTrivia), + SyntaxKind.CloseParenToken, + returnClause.ReturnsToken.TrailingTrivia); + + return SyntaxFactory.ParameterList( + openParenToken, + SyntaxFactory.SeparatedList( + parameterList.ParameterList.Items.Select(Transpile), + parameterList.ParameterList.Separators.Select(Transpile)).WithoutTrivia(), + closeParenToken); + } + + public ParameterListSyntax Transpile( + JassEmptyParameterListSyntax emptyParameterList, + JassReturnClauseSyntax returnClause, + bool discardTakesTokenLeadingTrivia) + { + var openParenToken = Transpile( + discardTakesTokenLeadingTrivia ? JassSyntaxTriviaList.Empty : emptyParameterList.TakesToken.LeadingTrivia, + SyntaxKind.OpenParenToken, + MergeTrivia(emptyParameterList.TakesToken.TrailingTrivia, emptyParameterList.NothingToken.LeadingTrivia)); + + var closeParenToken = Transpile( + MergeTrivia(emptyParameterList.NothingToken.TrailingTrivia, returnClause.ReturnsToken.LeadingTrivia), + SyntaxKind.CloseParenToken, + returnClause.ReturnsToken.TrailingTrivia); + + return SyntaxFactory.ParameterList( + openParenToken, + SyntaxFactory.SeparatedList(), + closeParenToken); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs index d50425dd..a1bef151 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParameterTranspiler.cs @@ -16,8 +16,12 @@ public partial class JassToCSharpTranspiler { public ParameterSyntax Transpile(JassParameterSyntax parameter) { - return SyntaxFactory.Parameter(Transpile(parameter.IdentifierName.Token)) - .WithType(Transpile(parameter.Type)); + return SyntaxFactory.Parameter( + default, + SyntaxFactory.TokenList(), + Transpile(parameter.Type), + Transpile(parameter.IdentifierName.Token), + null); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParenthesizedExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParenthesizedExpressionTranspiler.cs index b304d941..47b35100 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParenthesizedExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ParenthesizedExpressionTranspiler.cs @@ -16,7 +16,10 @@ public partial class JassToCSharpTranspiler { public ExpressionSyntax Transpile(JassParenthesizedExpressionSyntax parenthesizedExpression) { - return SyntaxFactory.ParenthesizedExpression(Transpile(parenthesizedExpression.Expression)); + return SyntaxFactory.ParenthesizedExpression( + Transpile(SyntaxKind.OpenParenToken, parenthesizedExpression.OpenParenToken), + Transpile(parenthesizedExpression.Expression), + Transpile(SyntaxKind.CloseParenToken, parenthesizedExpression.CloseParenToken)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/PredefinedTypeTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/PredefinedTypeTranspiler.cs new file mode 100644 index 00000000..5278f619 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/PredefinedTypeTranspiler.cs @@ -0,0 +1,107 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + private const string ActionTypeName = "System.Action"; + + public TypeSyntax Transpile( + JassPredefinedTypeSyntax type) + { + return type.Token.SyntaxKind == JassSyntaxKind.CodeKeyword + ? SyntaxFactory.IdentifierName(Transpile(ActionTypeName, type.Token)) + : SyntaxFactory.PredefinedType(Transpile(TranspileTypeKeyword(type.Token.SyntaxKind), type.Token)); + } + + public TypeSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassPredefinedTypeSyntax type) + { + return type.Token.SyntaxKind == JassSyntaxKind.CodeKeyword + ? SyntaxFactory.IdentifierName(Transpile(leadingTrivia, ActionTypeName, type.Token.TrailingTrivia)) + : SyntaxFactory.PredefinedType(Transpile(leadingTrivia, TranspileTypeKeyword(type.Token.SyntaxKind), type.Token.TrailingTrivia)); + } + + public TypeSyntax Transpile( + JassPredefinedTypeSyntax type, + JassSyntaxTriviaList trailingTrivia) + { + return type.Token.SyntaxKind == JassSyntaxKind.CodeKeyword + ? SyntaxFactory.IdentifierName(Transpile(type.Token.LeadingTrivia, ActionTypeName, trailingTrivia)) + : SyntaxFactory.PredefinedType(Transpile(type.Token.LeadingTrivia, TranspileTypeKeyword(type.Token.SyntaxKind), trailingTrivia)); + } + + public TypeSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassPredefinedTypeSyntax type, + JassSyntaxTriviaList trailingTrivia) + { + return type.Token.SyntaxKind == JassSyntaxKind.CodeKeyword + ? SyntaxFactory.IdentifierName(Transpile(leadingTrivia, ActionTypeName, trailingTrivia)) + : SyntaxFactory.PredefinedType(Transpile(leadingTrivia, TranspileTypeKeyword(type.Token.SyntaxKind), trailingTrivia)); + } + + public TypeSyntax TranspileAligned( + JassPredefinedTypeSyntax type, + bool isArray) + { + return Transpile(type) + .WithAlignedWhitespace(GetWhitespaceDiff(type.Token.SyntaxKind, isArray)); + } + + public TypeSyntax TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassPredefinedTypeSyntax type, + bool isArray) + { + return Transpile(leadingTrivia, type) + .WithAlignedWhitespace(GetWhitespaceDiff(type.Token.SyntaxKind, isArray)); + } + + public TypeSyntax TranspileAligned( + JassPredefinedTypeSyntax type, + JassSyntaxTriviaList trailingTrivia, + bool isArray) + { + return Transpile(type, trailingTrivia) + .WithAlignedWhitespace(GetWhitespaceDiff(type.Token.SyntaxKind, isArray)); + } + + public TypeSyntax TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassPredefinedTypeSyntax type, + JassSyntaxTriviaList trailingTrivia, + bool isArray) + { + return Transpile(leadingTrivia, type, trailingTrivia) + .WithAlignedWhitespace(GetWhitespaceDiff(type.Token.SyntaxKind, isArray)); + } + + private int GetWhitespaceDiff(JassSyntaxKind keyword, bool isArray) + { + return (isArray ? ArrayWhitespaceDiff : 0) + keyword switch + { + JassSyntaxKind.BooleanKeyword => 3, + JassSyntaxKind.CodeKeyword => -9, + JassSyntaxKind.HandleKeyword => 0, + JassSyntaxKind.IntegerKeyword => 4, + JassSyntaxKind.NothingKeyword => 3, + JassSyntaxKind.RealKeyword => -1, + JassSyntaxKind.StringKeyword => 0, + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ReturnStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ReturnStatementTranspiler.cs index e760e034..2cb21006 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ReturnStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/ReturnStatementTranspiler.cs @@ -5,10 +5,12 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { @@ -16,9 +18,31 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassReturnStatementSyntax returnStatement) { - return returnStatement.Value is null - ? SyntaxFactory.ReturnStatement() - : SyntaxFactory.ReturnStatement(Transpile(returnStatement.Value)); + var returnKeyword = Transpile(SyntaxKind.ReturnKeyword, returnStatement.ReturnToken); + + ExpressionSyntax? expression; + SyntaxTriviaList trailingTrivia; + + if (returnStatement.Value is null) + { + expression = null; + trailingTrivia = returnKeyword.TrailingTrivia; + returnKeyword = returnKeyword.WithoutTrailingTrivia(); + } + else + { + expression = Transpile(returnStatement.Value); + trailingTrivia = expression.GetTrailingTrivia(); + expression = expression.WithoutTrailingTrivia(); + } + + return SyntaxFactory.ReturnStatement( + returnKeyword, + expression, + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.SemicolonToken, + trailingTrivia)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs index 4d4a4483..11dc264e 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SetStatementTranspiler.cs @@ -5,9 +5,11 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -16,22 +18,28 @@ public partial class JassToCSharpTranspiler { public StatementSyntax Transpile(JassSetStatementSyntax setStatement) { - if (setStatement.ElementAccessClause is null) - { - return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( - SyntaxKind.SimpleAssignmentExpression, - Transpile(setStatement.IdentifierName), - Transpile(setStatement.Value.Expression))); - } - else - { - return SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( - SyntaxKind.SimpleAssignmentExpression, - SyntaxFactory.ElementAccessExpression( - Transpile(setStatement.IdentifierName), - SyntaxFactory.BracketedArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(Transpile(setStatement.ElementAccessClause.Expression))))), - Transpile(setStatement.Value.Expression))); - } + var leadingTrivia = MergeTrivia(setStatement.SetToken, setStatement.IdentifierName.GetLeadingTrivia()); + + ExpressionSyntax left = setStatement.ElementAccessClause is null + ? Transpile(leadingTrivia, setStatement.IdentifierName) + : SyntaxFactory.ElementAccessExpression( + Transpile(leadingTrivia, setStatement.IdentifierName), + Transpile(setStatement.ElementAccessClause)); + + var assignmentExpression = SyntaxFactory.AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + left, + Transpile(SyntaxKind.EqualsToken, setStatement.Value.EqualsToken), + Transpile(setStatement.Value.Expression)); + + var trailingTrivia = assignmentExpression.GetTrailingTrivia(); + + return SyntaxFactory.ExpressionStatement( + assignmentExpression.WithoutTrailingTrivia(), + SyntaxFactory.Token( + SyntaxTriviaList.Empty, + SyntaxKind.SemicolonToken, + trailingTrivia)); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxKindTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxKindTranspiler.cs new file mode 100644 index 00000000..966e19a2 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxKindTranspiler.cs @@ -0,0 +1,87 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis.CSharp; + +using War3Net.CodeAnalysis.Jass; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public SyntaxKind TranspileBinaryExpressionKind(JassSyntaxKind expressionKind) + { + return expressionKind switch + { + JassSyntaxKind.AddExpression => SyntaxKind.AddExpression, + JassSyntaxKind.SubtractExpression => SyntaxKind.SubtractExpression, + JassSyntaxKind.MultiplyExpression => SyntaxKind.MultiplyExpression, + JassSyntaxKind.DivideExpression => SyntaxKind.DivideExpression, + JassSyntaxKind.GreaterThanExpression => SyntaxKind.GreaterThanExpression, + JassSyntaxKind.LessThanExpression => SyntaxKind.LessThanExpression, + JassSyntaxKind.EqualsExpression => SyntaxKind.EqualsExpression, + JassSyntaxKind.NotEqualsExpression => SyntaxKind.NotEqualsExpression, + JassSyntaxKind.GreaterThanOrEqualExpression => SyntaxKind.GreaterThanOrEqualExpression, + JassSyntaxKind.LessThanOrEqualExpression => SyntaxKind.LessThanOrEqualExpression, + JassSyntaxKind.LogicalAndExpression => SyntaxKind.LogicalAndExpression, + JassSyntaxKind.LogicalOrExpression => SyntaxKind.LogicalOrExpression, + }; + } + + public SyntaxKind TranspileBinaryOperatorKind(JassSyntaxKind operatorKind) + { + return operatorKind switch + { + JassSyntaxKind.PlusToken => SyntaxKind.PlusToken, + JassSyntaxKind.MinusToken => SyntaxKind.MinusToken, + JassSyntaxKind.AsteriskToken => SyntaxKind.AsteriskToken, + JassSyntaxKind.SlashToken => SyntaxKind.SlashToken, + JassSyntaxKind.GreaterThanToken => SyntaxKind.GreaterThanToken, + JassSyntaxKind.LessThanToken => SyntaxKind.LessThanToken, + JassSyntaxKind.EqualsEqualsToken => SyntaxKind.EqualsEqualsToken, + JassSyntaxKind.ExclamationEqualsToken => SyntaxKind.ExclamationEqualsToken, + JassSyntaxKind.GreaterThanEqualsToken => SyntaxKind.GreaterThanEqualsToken, + JassSyntaxKind.LessThanEqualsToken => SyntaxKind.LessThanEqualsToken, + JassSyntaxKind.AndKeyword => SyntaxKind.AmpersandAmpersandToken, + JassSyntaxKind.OrKeyword => SyntaxKind.BarBarToken, + }; + } + + public SyntaxKind TranspileTypeKeyword(JassSyntaxKind keyword) + { + return keyword switch + { + JassSyntaxKind.BooleanKeyword => SyntaxKind.BoolKeyword, + JassSyntaxKind.HandleKeyword => SyntaxKind.ObjectKeyword, + JassSyntaxKind.IntegerKeyword => SyntaxKind.IntKeyword, + JassSyntaxKind.NothingKeyword => SyntaxKind.VoidKeyword, + JassSyntaxKind.RealKeyword => SyntaxKind.FloatKeyword, + JassSyntaxKind.StringKeyword => SyntaxKind.StringKeyword, + }; + } + + public SyntaxKind TranspileUnaryExpressionKind(JassSyntaxKind expressionKind) + { + return expressionKind switch + { + JassSyntaxKind.UnaryPlusExpression => SyntaxKind.UnaryPlusExpression, + JassSyntaxKind.UnaryMinusExpression => SyntaxKind.UnaryMinusExpression, + JassSyntaxKind.LogicalNotExpression => SyntaxKind.LogicalNotExpression, + }; + } + + public SyntaxKind TranspileUnaryOperatorKind(JassSyntaxKind operatorKind) + { + return operatorKind switch + { + JassSyntaxKind.PlusToken => SyntaxKind.PlusToken, + JassSyntaxKind.MinusToken => SyntaxKind.MinusToken, + JassSyntaxKind.NotKeyword => SyntaxKind.ExclamationToken, + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs index a8c70e5d..b2915db8 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTokenTranspiler.cs @@ -22,18 +22,172 @@ public partial class JassToCSharpTranspiler private static readonly Lazy> _reservedKeywords = new Lazy>(() => GetReservedKeywords().ToHashSet(StringComparer.Ordinal)); - public SyntaxToken Transpile(JassSyntaxToken token) + public string TranspileText( + string tokenText) { - var text = _reservedKeywords.Value.Contains(token.Text) - ? $"{AntiReservedKeywordConflictPrefix}{token.Text}" - : token.Text; + return _reservedKeywords.Value.Contains(tokenText) + ? $"{AntiReservedKeywordConflictPrefix}{tokenText}" + : tokenText; + } + + public string TranspileTextAligned( + string tokenText, + out bool prefixAdded) + { + prefixAdded = _reservedKeywords.Value.Contains(tokenText); + return prefixAdded + ? $"{AntiReservedKeywordConflictPrefix}{tokenText}" + : tokenText; + } + + public SyntaxToken Transpile( + JassSyntaxToken token) + { + return Transpile(token.LeadingTrivia, token, token.TrailingTrivia); + } + + public SyntaxToken Transpile( + JassSyntaxToken token, + JassSyntaxToken triviaFromToken) + { + return Transpile(triviaFromToken.LeadingTrivia, token, triviaFromToken.TrailingTrivia); + } + + public SyntaxToken Transpile( + JassSyntaxTriviaList leadingTrivia, + JassSyntaxToken token) + { + return Transpile(leadingTrivia, token, token.TrailingTrivia); + } + + public SyntaxToken Transpile( + JassSyntaxToken token, + JassSyntaxTriviaList trailingTrivia) + { + return Transpile(token.LeadingTrivia, token, trailingTrivia); + } + public SyntaxToken Transpile( + JassSyntaxTriviaList leadingTrivia, + JassSyntaxToken token, + JassSyntaxTriviaList trailingTrivia) + { return SyntaxFactory.Identifier( - Transpile(token.LeadingTrivia), + Transpile(leadingTrivia), SyntaxKind.IdentifierToken, - text, + TranspileText(token.Text), token.Text, - Transpile(token.TrailingTrivia)); + Transpile(trailingTrivia)); + } + + public SyntaxToken TranspileAligned( + JassSyntaxToken token, + out bool prefixAdded) + { + return TranspileAligned(token.LeadingTrivia, token, token.TrailingTrivia, out prefixAdded); + } + + public SyntaxToken TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassSyntaxToken token, + out bool prefixAdded) + { + return TranspileAligned(leadingTrivia, token, token.TrailingTrivia, out prefixAdded); + } + + public SyntaxToken TranspileAligned( + JassSyntaxToken token, + JassSyntaxTriviaList trailingTrivia, + out bool prefixAdded) + { + return TranspileAligned(token.LeadingTrivia, token, trailingTrivia, out prefixAdded); + } + + public SyntaxToken TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassSyntaxToken token, + JassSyntaxTriviaList trailingTrivia, + out bool prefixAdded) + { + return SyntaxFactory.Identifier( + Transpile(leadingTrivia), + SyntaxKind.IdentifierToken, + TranspileTextAligned(token.Text, out prefixAdded), + token.Text, + Transpile(trailingTrivia)); + } + + public SyntaxToken Transpile(string text) + { + return SyntaxFactory.Identifier( + SyntaxTriviaList.Empty, + SyntaxKind.IdentifierToken, + TranspileText(text), + text, + SyntaxTriviaList.Empty); + } + + public SyntaxToken Transpile( + string text, + JassSyntaxToken triviaFromToken) + { + return SyntaxFactory.Identifier( + Transpile(triviaFromToken.LeadingTrivia), + SyntaxKind.IdentifierToken, + TranspileText(text), + text, + Transpile(triviaFromToken.TrailingTrivia)); + } + + public SyntaxToken Transpile( + JassSyntaxTriviaList leadingTrivia, + string text, + JassSyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.Identifier( + Transpile(leadingTrivia), + SyntaxKind.IdentifierToken, + TranspileText(text), + text, + Transpile(trailingTrivia)); + } + + public SyntaxToken Transpile( + SyntaxKind syntaxKind, + JassSyntaxToken triviaFromToken) + { + return Transpile(triviaFromToken.LeadingTrivia, syntaxKind, triviaFromToken.TrailingTrivia); + } + + public SyntaxToken Transpile( + JassSyntaxTriviaList leadingTrivia, + SyntaxKind syntaxKind) + { + return SyntaxFactory.Token( + Transpile(leadingTrivia), + syntaxKind, + SyntaxTriviaList.Empty); + } + + public SyntaxToken Transpile( + SyntaxKind syntaxKind, + JassSyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.Token( + SyntaxTriviaList.Empty, + syntaxKind, + Transpile(trailingTrivia)); + } + + public SyntaxToken Transpile( + JassSyntaxTriviaList leadingTrivia, + SyntaxKind syntaxKind, + JassSyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.Token( + Transpile(leadingTrivia), + syntaxKind, + Transpile(trailingTrivia)); } private static IEnumerable GetReservedKeywords() diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs index e97e936e..71619f45 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp; using War3Net.CodeAnalysis.Jass; - using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -20,6 +19,11 @@ public partial class JassToCSharpTranspiler { public SyntaxTriviaList Transpile(JassSyntaxTriviaList triviaList) { + if (triviaList.Trivia.Length == 0) + { + return SyntaxTriviaList.Empty; + } + return SyntaxFactory.TriviaList(triviaList.Trivia.Select(Transpile)); } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs index 4fad9e65..3d51ce41 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeDeclarationTranspiler.cs @@ -9,7 +9,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { @@ -18,23 +20,46 @@ public partial class JassToCSharpTranspiler public MemberDeclarationSyntax Transpile(JassTypeDeclarationSyntax typeDeclaration) { var identifier = Transpile(typeDeclaration.IdentifierName.Token); - var baseList = SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.SimpleBaseType(Transpile(typeDeclaration.BaseType)))); + + var baseList = SyntaxFactory.BaseList( + Transpile(SyntaxKind.ColonToken, typeDeclaration.ExtendsToken), + SyntaxFactory.SingletonSeparatedList( + SyntaxFactory.SimpleBaseType(Transpile(typeDeclaration.BaseType)))); + + var indentationString = typeDeclaration.TypeToken.LeadingTrivia.GetIndentationString(); return SyntaxFactory.ClassDeclaration( default, - new SyntaxTokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)), + new SyntaxTokenList(TokenWithSpace(typeDeclaration.TypeToken.LeadingTrivia, SyntaxKind.PublicKeyword)), + Transpile(SyntaxKind.ClassKeyword, typeDeclaration.TypeToken.TrailingTrivia), identifier, null, baseList, default, - SyntaxFactory.SingletonList( - (MemberDeclarationSyntax)SyntaxFactory.ConstructorDeclaration( + SyntaxFactory.Token( + SyntaxTriviaList.Create(SyntaxFactory.ElasticWhitespace(indentationString)), + SyntaxKind.OpenBraceToken, + SyntaxTriviaList.Create(SyntaxFactory.ElasticCarriageReturnLineFeed)), + SyntaxFactory.SingletonList( + SyntaxFactory.ConstructorDeclaration( default, - new SyntaxTokenList(SyntaxFactory.Token(SyntaxKind.InternalKeyword)), - identifier, - SyntaxFactory.ParameterList(), + new SyntaxTokenList( + SyntaxFactory.Token( + SyntaxTriviaList.Create(SyntaxFactory.ElasticWhitespace(indentationString)), + SyntaxKind.InternalKeyword, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace))), + identifier.WithoutTrivia(), + SyntaxFactory.ParameterList( + SyntaxFactory.Token(SyntaxKind.OpenParenToken), + SyntaxFactory.SeparatedList(), + SyntaxFactory.Token(SyntaxKind.CloseParenToken).WithSpace()), null, - SyntaxFactory.Block()))); + SyntaxFactory.Block().WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed))), + SyntaxFactory.Token( + SyntaxTriviaList.Create(SyntaxFactory.ElasticWhitespace(indentationString)), + SyntaxKind.CloseBraceToken, + SyntaxTriviaList.Create(SyntaxFactory.ElasticCarriageReturnLineFeed)), + default); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs index 48fd6509..9cf48dd3 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/TypeTranspiler.cs @@ -5,38 +5,103 @@ // // ------------------------------------------------------------------------------ -using System; - -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public TypeSyntax Transpile(JassTypeSyntax type) + public TypeSyntax Transpile( + JassTypeSyntax type) { return type switch { - JassIdentifierNameSyntax identifierName => SyntaxFactory.ParseTypeName(Transpile(identifierName.Token).Text), + JassIdentifierNameSyntax identifierName => Transpile(identifierName), JassPredefinedTypeSyntax predefinedType => Transpile(predefinedType), }; } - public TypeSyntax Transpile(JassPredefinedTypeSyntax type) + public TypeSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassTypeSyntax type) + { + return type switch + { + JassIdentifierNameSyntax identifierName => Transpile(leadingTrivia, identifierName), + JassPredefinedTypeSyntax predefinedType => Transpile(leadingTrivia, predefinedType), + }; + } + + public TypeSyntax Transpile( + JassTypeSyntax type, + JassSyntaxTriviaList trailingTrivia) + { + return type switch + { + JassIdentifierNameSyntax identifierName => Transpile(identifierName, trailingTrivia), + JassPredefinedTypeSyntax predefinedType => Transpile(predefinedType, trailingTrivia), + }; + } + + public TypeSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassTypeSyntax type, + JassSyntaxTriviaList trailingTrivia) + { + return type switch + { + JassIdentifierNameSyntax identifierName => Transpile(leadingTrivia, identifierName, trailingTrivia), + JassPredefinedTypeSyntax predefinedType => Transpile(leadingTrivia, predefinedType, trailingTrivia), + }; + } + + public TypeSyntax TranspileAligned( + JassTypeSyntax type, + bool isArray) { - return type.SyntaxKind switch + return type switch + { + JassIdentifierNameSyntax identifierName => TranspileAligned(identifierName, isArray), + JassPredefinedTypeSyntax predefinedType => TranspileAligned(predefinedType, isArray), + }; + } + + public TypeSyntax TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassTypeSyntax type, + bool isArray) + { + return type switch + { + JassIdentifierNameSyntax identifierName => TranspileAligned(leadingTrivia, identifierName, isArray), + JassPredefinedTypeSyntax predefinedType => TranspileAligned(leadingTrivia, predefinedType, isArray), + }; + } + + public TypeSyntax TranspileAligned( + JassTypeSyntax type, + JassSyntaxTriviaList trailingTrivia, + bool isArray) + { + return type switch + { + JassIdentifierNameSyntax identifierName => TranspileAligned(identifierName, trailingTrivia, isArray), + JassPredefinedTypeSyntax predefinedType => TranspileAligned(predefinedType, trailingTrivia, isArray), + }; + } + + public TypeSyntax TranspileAligned( + JassSyntaxTriviaList leadingTrivia, + JassTypeSyntax type, + JassSyntaxTriviaList trailingTrivia, + bool isArray) + { + return type switch { - JassSyntaxKind.BooleanKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BoolKeyword)), - JassSyntaxKind.CodeKeyword => SyntaxFactory.ParseTypeName(typeof(Action).FullName!), - JassSyntaxKind.HandleKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ObjectKeyword)), - JassSyntaxKind.IntegerKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)), - JassSyntaxKind.NothingKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), - JassSyntaxKind.RealKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.FloatKeyword)), - JassSyntaxKind.StringKeyword => SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)), + JassIdentifierNameSyntax identifierName => TranspileAligned(leadingTrivia, identifierName, trailingTrivia, isArray), + JassPredefinedTypeSyntax predefinedType => TranspileAligned(leadingTrivia, predefinedType, trailingTrivia, isArray), }; } } diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs index ad55dc7c..b20eb6ca 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/UnaryExpressionTranspiler.cs @@ -8,7 +8,6 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -19,17 +18,10 @@ public ExpressionSyntax Transpile(JassUnaryExpressionSyntax unaryExpression) { return SyntaxFactory.PrefixUnaryExpression( TranspileUnaryExpressionKind(unaryExpression.SyntaxKind), + Transpile( + TranspileUnaryOperatorKind(unaryExpression.OperatorToken.SyntaxKind), + unaryExpression.OperatorToken), Transpile(unaryExpression.Expression)); } - - public SyntaxKind TranspileUnaryExpressionKind(JassSyntaxKind expressionKind) - { - return expressionKind switch - { - JassSyntaxKind.UnaryPlusExpression => SyntaxKind.UnaryPlusExpression, - JassSyntaxKind.UnaryMinusExpression => SyntaxKind.UnaryMinusExpression, - JassSyntaxKind.LogicalNotExpression => SyntaxKind.LogicalNotExpression, - }; - } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs index 1d4e36b6..95a48b96 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableDeclaratorTranspiler.cs @@ -5,45 +5,86 @@ // // ------------------------------------------------------------------------------ +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis.Transpilers.Extensions; namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { - public VariableDeclarationSyntax Transpile(JassVariableOrArrayDeclaratorSyntax declarator) + public VariableDeclarationSyntax Transpile( + JassVariableDeclaratorSyntax variableDeclarator, + bool isGlobalDeclaration) { - return declarator switch - { - JassArrayDeclaratorSyntax arrayDeclarator => Transpile(arrayDeclarator), - JassVariableDeclaratorSyntax variableDeclarator => Transpile(variableDeclarator), - }; + return Transpile( + variableDeclarator.GetLeadingTrivia(), + variableDeclarator, + variableDeclarator.GetTrailingTrivia(), + isGlobalDeclaration); + } + + private VariableDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassVariableDeclaratorSyntax variableDeclarator, + bool isGlobalDeclaration) + { + return Transpile( + leadingTrivia, + variableDeclarator, + variableDeclarator.GetTrailingTrivia(), + isGlobalDeclaration); + } + + private VariableDeclarationSyntax Transpile( + JassVariableDeclaratorSyntax variableDeclarator, + JassSyntaxTriviaList trailingTrivia, + bool isGlobalDeclaration) + { + return Transpile( + variableDeclarator.GetLeadingTrivia(), + variableDeclarator, + trailingTrivia, + isGlobalDeclaration); } - public VariableDeclarationSyntax Transpile(JassVariableDeclaratorSyntax variableDeclarator) + private VariableDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassVariableDeclaratorSyntax variableDeclarator, + JassSyntaxTriviaList trailingTrivia, + bool isGlobalDeclaration) { - var type = Transpile(variableDeclarator.Type); + VariableDeclaratorSyntax declarator; + if (variableDeclarator.Value is null) { - return SyntaxFactory.VariableDeclaration( - type, - SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(variableDeclarator.IdentifierName.Token), - null, - SyntaxFactory.EqualsValueClause(SyntaxFactory.DefaultExpression(type))))); + declarator = SyntaxFactory.VariableDeclarator( + Transpile(variableDeclarator.IdentifierName.Token).WithSpace(), + null, + SyntaxFactory.EqualsValueClause( + TokenWithSpace(SyntaxKind.EqualsToken), + SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression))); } else { - return SyntaxFactory.VariableDeclaration( - type, - SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator( - Transpile(variableDeclarator.IdentifierName.Token), - null, - Transpile(variableDeclarator.Value)))); + declarator = SyntaxFactory.VariableDeclarator( + Transpile(variableDeclarator.IdentifierName.Token), + null, + Transpile(variableDeclarator.Value)); } + + var typeNode = isGlobalDeclaration + ? TranspileAligned(leadingTrivia, variableDeclarator.Type, isArray: false) + : Transpile(leadingTrivia, variableDeclarator.Type); + + return SyntaxFactory.VariableDeclaration( + typeNode, + SyntaxFactory.SingletonSeparatedList( + declarator.WithTrailingTrivia(Transpile(trailingTrivia)))); } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableOrArrayDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableOrArrayDeclaratorTranspiler.cs new file mode 100644 index 00000000..a3407c1f --- /dev/null +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/VariableOrArrayDeclaratorTranspiler.cs @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Transpilers +{ + public partial class JassToCSharpTranspiler + { + public VariableDeclarationSyntax Transpile( + JassVariableOrArrayDeclaratorSyntax declarator, + bool isGlobalDeclaration) + { + return declarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => Transpile(arrayDeclarator, isGlobalDeclaration), + JassVariableDeclaratorSyntax variableDeclarator => Transpile(variableDeclarator, isGlobalDeclaration), + }; + } + + public VariableDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassVariableOrArrayDeclaratorSyntax declarator, + bool isGlobalDeclaration) + { + return declarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => Transpile(leadingTrivia, arrayDeclarator, isGlobalDeclaration), + JassVariableDeclaratorSyntax variableDeclarator => Transpile(leadingTrivia, variableDeclarator, isGlobalDeclaration), + }; + } + + public VariableDeclarationSyntax Transpile( + JassVariableOrArrayDeclaratorSyntax declarator, + JassSyntaxTriviaList trailingTrivia, + bool isGlobalDeclaration) + { + return declarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => Transpile(arrayDeclarator, trailingTrivia, isGlobalDeclaration), + JassVariableDeclaratorSyntax variableDeclarator => Transpile(variableDeclarator, trailingTrivia, isGlobalDeclaration), + }; + } + + public VariableDeclarationSyntax Transpile( + JassSyntaxTriviaList leadingTrivia, + JassVariableOrArrayDeclaratorSyntax declarator, + JassSyntaxTriviaList trailingTrivia, + bool isGlobalDeclaration) + { + return declarator switch + { + JassArrayDeclaratorSyntax arrayDeclarator => Transpile(leadingTrivia, arrayDeclarator, trailingTrivia, isGlobalDeclaration), + JassVariableDeclaratorSyntax variableDeclarator => Transpile(leadingTrivia, variableDeclarator, trailingTrivia, isGlobalDeclaration), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharpTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharpTranspiler.cs index f326bc97..dca9bc5d 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharpTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharpTranspiler.cs @@ -5,10 +5,22 @@ // // ------------------------------------------------------------------------------ +using System; +using System.Linq; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Syntax; + namespace War3Net.CodeAnalysis.Transpilers { public partial class JassToCSharpTranspiler { + private const int ArrayWhitespaceDiff = 3; + private const int PrefixWhitespaceDiff = -1; + public JassToCSharpTranspiler() { } @@ -19,5 +31,107 @@ public JassToCSharpTranspiler() public JassToLuaTranspiler? JassToLuaTranspiler { get; set; } public bool ApplyCSharpLuaTemplateAttribute { get; set; } + + private SyntaxToken TokenWithSpace(SyntaxKind tokenKind) + { + return SyntaxFactory.Token( + SyntaxTriviaList.Empty, + tokenKind, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)); + } + + private SyntaxToken TokenWithSpace(JassSyntaxTriviaList leadingTrivia, SyntaxKind tokenKind) + { + return SyntaxFactory.Token( + Transpile(leadingTrivia), + tokenKind, + SyntaxTriviaList.Create(SyntaxFactory.ElasticSpace)); + } + + private SyntaxToken Token(SyntaxKind tokenKind, JassSyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.Token( + SyntaxTriviaList.Empty, + tokenKind, + Transpile(trailingTrivia)); + } + + private SyntaxToken Token(SyntaxKind tokenKind, SyntaxTriviaList trailingTrivia) + { + return SyntaxFactory.Token( + SyntaxTriviaList.Empty, + tokenKind, + trailingTrivia); + } + + private JassSyntaxTriviaList MergeTrivia(JassSyntaxToken discardedToken, JassSyntaxTriviaList leadingTrivia) + { + if (IsSingleSpace(discardedToken.TrailingTrivia, leadingTrivia)) + { + return discardedToken.LeadingTrivia; + } + + return JassSyntaxFactory.ConcatTriviaLists(discardedToken.LeadingTrivia, discardedToken.TrailingTrivia, leadingTrivia); + } + + private JassSyntaxTriviaList MergeTrivia(JassSyntaxTriviaList trailingTrivia, JassSyntaxToken discardedToken) + { + if (IsSingleSpace(trailingTrivia, discardedToken.LeadingTrivia)) + { + return discardedToken.TrailingTrivia; + } + + return JassSyntaxFactory.ConcatTriviaLists(trailingTrivia, discardedToken.LeadingTrivia, discardedToken.TrailingTrivia); + } + + private JassSyntaxTriviaList MergeTrivia(JassSyntaxTriviaList trailingTrivia, JassSyntaxTriviaList leadingTrivia) + { + if (IsSingleSpace(trailingTrivia, leadingTrivia)) + { + return JassSyntaxTriviaList.Empty; + } + + return JassSyntaxFactory.ConcatTriviaLists(trailingTrivia, leadingTrivia); + } + + private SyntaxTriviaList MergeTrivia(SyntaxTriviaList trailingTrivia, SyntaxTriviaList leadingTrivia) + { + if (IsSingleSpace(trailingTrivia, leadingTrivia)) + { + return SyntaxTriviaList.Empty; + } + + return SyntaxFactory.TriviaList(trailingTrivia.Concat(leadingTrivia)); + } + + private bool IsSingleSpace(JassSyntaxTriviaList trailingTrivia, JassSyntaxTriviaList leadingTrivia) + { + if (trailingTrivia.Trivia.Length == 1 && leadingTrivia.Trivia.Length == 0) + { + return string.Equals(trailingTrivia.Trivia[0].Text, JassSymbol.Space, StringComparison.Ordinal); + } + + if (trailingTrivia.Trivia.Length == 0 && leadingTrivia.Trivia.Length == 1) + { + return string.Equals(leadingTrivia.Trivia[0].Text, JassSymbol.Space, StringComparison.Ordinal); + } + + return false; + } + + private bool IsSingleSpace(SyntaxTriviaList trailingTrivia, SyntaxTriviaList leadingTrivia) + { + if (trailingTrivia.Count == 1 && leadingTrivia.Count == 0) + { + return string.Equals(trailingTrivia[0].ToFullString(), " ", StringComparison.Ordinal); + } + + if (trailingTrivia.Count == 0 && leadingTrivia.Count == 1) + { + return string.Equals(leadingTrivia[0].ToFullString(), " ", StringComparison.Ordinal); + } + + return false; + } } } \ No newline at end of file From a321676a2712b4ef351295f9b97efe938fdae653 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 16 Nov 2025 11:59:54 +0100 Subject: [PATCH 10/53] Add JassToCSharpTranspilerTests. --- Directory.Packages.props | 1 + .../JassToCSharpTranspilerTests.cs | 66 +++++++ .../DiffAssert.cs | 162 ++++++++++++++++++ .../TestData/Transpilation/aligned-globals.cs | 13 ++ .../TestData/Transpilation/aligned-globals.j | 14 ++ .../TestData/Transpilation/if-statements.cs | 37 ++++ .../TestData/Transpilation/if-statements.j | 37 ++++ .../War3Net.TestTools.UnitTesting.csproj | 10 +- 8 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 tests/War3Net.CodeAnalysis.Transpilers.Tests/JassToCSharpTranspilerTests.cs create mode 100644 tests/War3Net.TestTools.UnitTesting/DiffAssert.cs create mode 100644 tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.cs create mode 100644 tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.j create mode 100644 tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.cs create mode 100644 tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.j diff --git a/Directory.Packages.props b/Directory.Packages.props index b4499b70..83f32d4b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,6 +4,7 @@ + diff --git a/tests/War3Net.CodeAnalysis.Transpilers.Tests/JassToCSharpTranspilerTests.cs b/tests/War3Net.CodeAnalysis.Transpilers.Tests/JassToCSharpTranspilerTests.cs new file mode 100644 index 00000000..d7566136 --- /dev/null +++ b/tests/War3Net.CodeAnalysis.Transpilers.Tests/JassToCSharpTranspilerTests.cs @@ -0,0 +1,66 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; +using System.IO; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using War3Net.CodeAnalysis.Jass; +using War3Net.TestTools.UnitTesting; + +namespace War3Net.CodeAnalysis.Transpilers.Tests +{ + [TestClass] + public class JassToCSharpTranspilerTests + { + [TestMethod] + [DynamicData(nameof(GetTranspilationFilePaths), DynamicDataSourceType.Method)] + public void TestTranspileToCSharp(string inputJassFilePath, string expectedCSharpFilePath) + { + using var fileStream = File.OpenRead(inputJassFilePath); + using var outputWriter = new StringWriter(); + + GenerateTranspiledScript(fileStream, outputWriter); + + var expectedScript = File.ReadAllText(expectedCSharpFilePath); + var actualScript = outputWriter.ToString(); + + DiffAssert.AreEqual(expectedScript, actualScript); + } + + private static IEnumerable GetTranspilationFilePaths() + { + foreach (var jassFilePath in Directory.EnumerateFiles(TestDataProvider.GetPath("Transpilation"), "*.j", SearchOption.TopDirectoryOnly)) + { + var csharpFilePath = Path.ChangeExtension(jassFilePath, ".cs"); + if (File.Exists(csharpFilePath)) + { + yield return new object?[] { jassFilePath, csharpFilePath }; + } + } + } + + private void GenerateTranspiledScript(Stream inputFileStream, TextWriter outputWriter) + { + var transpiler = new JassToCSharpTranspiler(); + transpiler.ApplyCSharpLuaTemplateAttribute = false; + + using var mapScriptReader = new StreamReader(inputFileStream); + var mapScript = mapScriptReader.ReadToEnd(); + var mapScriptSyntax = JassSyntaxFactory.ParseCompilationUnit(mapScript); + var memberDeclarations = transpiler.Transpile(mapScriptSyntax); + + foreach (var memberDeclaration in memberDeclarations) + { + outputWriter.Write(memberDeclaration.ToFullString()); + } + + outputWriter.Write(transpiler.Transpile(mapScriptSyntax.EndOfFileToken).ToFullString()); + } + } +} \ No newline at end of file diff --git a/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs b/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs new file mode 100644 index 00000000..242acb1f --- /dev/null +++ b/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs @@ -0,0 +1,162 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; + +using DiffPlex; +using DiffPlex.DiffBuilder; +using DiffPlex.DiffBuilder.Model; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace War3Net.TestTools.UnitTesting +{ + public static class DiffAssert + { + /// + /// Asserts that two strings are equal, providing a detailed diff output if they are not. + /// + /// The expected string. + /// The actual string. + public static void AreEqual(string expected, string actual) + { + if (string.Equals(expected, actual, StringComparison.Ordinal)) + { + return; + } + + var diffMessage = BuildDiffMessage(expected, actual); + Assert.Fail(diffMessage); + } + + /// + /// Asserts that two strings are equal, providing a detailed diff output if they are not. + /// + /// The expected string. + /// The actual string. + /// Additional message to include in the assertion failure. + public static void AreEqual(string expected, string actual, string message) + { + if (string.Equals(expected, actual, StringComparison.Ordinal)) + { + return; + } + + var diffMessage = BuildDiffMessage(expected, actual); + Assert.Fail($"{message}{Environment.NewLine}{diffMessage}"); + } + + /// + /// Asserts that two strings are equal, providing a detailed diff output if they are not. + /// Ignores differences in line ending styles (CRLF vs LF). + /// + /// The expected string. + /// The actual string. + public static void AreEqualIgnoreLineEndings(string expected, string actual) + { + var normalizedExpected = NormalizeLineEndings(expected); + var normalizedActual = NormalizeLineEndings(actual); + + if (string.Equals(normalizedExpected, normalizedActual, StringComparison.Ordinal)) + { + return; + } + + var diffMessage = BuildDiffMessage(normalizedExpected, normalizedActual); + Assert.Fail(diffMessage); + } + + /// + /// Asserts that two strings are equal, providing a detailed diff output if they are not. + /// Ignores differences in line ending styles (CRLF vs LF). + /// + /// The expected string. + /// The actual string. + /// Additional message to include in the assertion failure. + public static void AreEqualIgnoreLineEndings(string expected, string actual, string message) + { + var normalizedExpected = NormalizeLineEndings(expected); + var normalizedActual = NormalizeLineEndings(actual); + + if (string.Equals(normalizedExpected, normalizedActual, StringComparison.Ordinal)) + { + return; + } + + var diffMessage = BuildDiffMessage(normalizedExpected, normalizedActual); + Assert.Fail($"{message}{Environment.NewLine}{diffMessage}"); + } + + private static string BuildDiffMessage(string expected, string actual) + { + var diffBuilder = new InlineDiffBuilder(new Differ()); + var diff = diffBuilder.BuildDiffModel(expected, actual, ignoreWhitespace: false); + + var messageBuilder = new StringBuilder(); + messageBuilder.AppendLine(); + messageBuilder.AppendLine("Strings are not equal. Diff:"); + messageBuilder.AppendLine(); + + var addedLines = 0; + var deletedLines = 0; + var modifiedLines = 0; + + foreach (var line in diff.Lines) + { + switch (line.Type) + { + case ChangeType.Inserted: + messageBuilder.AppendLine($"+ {line.Text}"); + addedLines++; + break; + + case ChangeType.Deleted: + messageBuilder.AppendLine($"- {line.Text}"); + deletedLines++; + break; + + case ChangeType.Modified: + messageBuilder.AppendLine($"~ {line.Text}"); + modifiedLines++; + break; + + case ChangeType.Imaginary: + // Imaginary lines are used for alignment in side-by-side diffs + // We can skip them in inline diff output + break; + + case ChangeType.Unchanged: + messageBuilder.AppendLine($" {line.Text}"); + break; + } + } + + messageBuilder.AppendLine(); + messageBuilder.AppendLine("Summary:"); + messageBuilder.AppendLine($" Lines added: {addedLines}"); + messageBuilder.AppendLine($" Lines deleted: {deletedLines}"); + messageBuilder.AppendLine($" Lines modified: {modifiedLines}"); + + return messageBuilder.ToString(); + } + + [return: NotNullIfNotNull(nameof(text))] + private static string? NormalizeLineEndings(string? text) + { + if (text is null) + { + return null; + } + + return text + .Replace("\r\n", "\n", StringComparison.Ordinal) + .Replace("\r", "\n", StringComparison.Ordinal); + } + } +} \ No newline at end of file diff --git a/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.cs b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.cs new file mode 100644 index 00000000..01c86ff5 --- /dev/null +++ b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.cs @@ -0,0 +1,13 @@ + + public static @event udg_event = default; + public static int udg_integer = default; + public static bool udg_boolean = default; + public static string udg_string = default; + public static System.Action udg_code = default; + + // arrays + public static @event[] udg_events = new @event[JASS_MAX_ARRAY_SIZE]; + public static int[] udg_integers = new int[JASS_MAX_ARRAY_SIZE]; + public static bool[] udg_booleans = new bool[JASS_MAX_ARRAY_SIZE]; + public static string[] udg_strings = new string[JASS_MAX_ARRAY_SIZE]; + public static System.Action[] udg_codes = new System.Action[JASS_MAX_ARRAY_SIZE]; diff --git a/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.j b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.j new file mode 100644 index 00000000..b052fa19 --- /dev/null +++ b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/aligned-globals.j @@ -0,0 +1,14 @@ +globals + event udg_event + integer udg_integer + boolean udg_boolean + string udg_string + code udg_code + + // arrays + event array udg_events + integer array udg_integers + boolean array udg_booleans + string array udg_strings + code array udg_codes +endglobals \ No newline at end of file diff --git a/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.cs b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.cs new file mode 100644 index 00000000..b6368a80 --- /dev/null +++ b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.cs @@ -0,0 +1,37 @@ +public static void Test() { + if (udg_bool==true) { + } // endif + + if ( udg_bool == true ) { + } else { + } // endif + + if (udg_int==0) { + } else if (udg_int==1) { + } else if (udg_int==2) { + } // endif + + if ( udg_int == 0 ) { + } else if ( udg_int == 1 ) { + } else if ( udg_int == 2 ) { + } else { + } // endif + + if(udg_bool==true){ + } // endif + + if ( udg_bool == true ) { + } else { + } // endif + + if(udg_int==0){ + } else if(udg_int==1){ + } else if(udg_int==2){ + } // endif + + if ( udg_int == 0 ) { + } else if ( udg_int == 1 ) { + } else if ( udg_int == 2 ) { + } else { + } // endif +} \ No newline at end of file diff --git a/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.j b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.j new file mode 100644 index 00000000..9aa30ce8 --- /dev/null +++ b/tests/War3Net.TestTools.UnitTesting/TestData/Transpilation/if-statements.j @@ -0,0 +1,37 @@ +function Test takes nothing returns nothing + if udg_bool==true then + endif // endif + + if udg_bool == true then + else + endif // endif + + if udg_int==0then + elseif udg_int==1then + elseif udg_int==2then + endif // endif + + if udg_int == 0 then + elseif udg_int == 1 then + elseif udg_int == 2 then + else + endif // endif + + if(udg_bool==true)then + endif // endif + + if ( udg_bool == true ) then + else + endif // endif + + if(udg_int==0)then + elseif(udg_int==1)then + elseif(udg_int==2)then + endif // endif + + if ( udg_int == 0 ) then + elseif ( udg_int == 1 ) then + elseif ( udg_int == 2 ) then + else + endif // endif +endfunction \ No newline at end of file diff --git a/tests/War3Net.TestTools.UnitTesting/War3Net.TestTools.UnitTesting.csproj b/tests/War3Net.TestTools.UnitTesting/War3Net.TestTools.UnitTesting.csproj index 7c515bf0..dccdbf74 100644 --- a/tests/War3Net.TestTools.UnitTesting/War3Net.TestTools.UnitTesting.csproj +++ b/tests/War3Net.TestTools.UnitTesting/War3Net.TestTools.UnitTesting.csproj @@ -4,6 +4,10 @@ $(TfmGroupDotNet) + + + + @@ -13,8 +17,10 @@ - - + + + + From 3aa605acc953defcb6d7a6a6237587e219942d88 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:12:17 +0100 Subject: [PATCH 11/53] Rework MapScriptBuilder to output strings directly instead of using syntax classes. --- src/War3Net.Build/CompileResult.cs | 2 +- src/War3Net.Build/Extensions/MapExtensions.cs | 16 +- .../ModifiedAbilityDataExtensions.cs | 19 ++ ...Extensions.cs => TriggerItemExtensions.cs} | 18 +- .../VariableDefinitionExtensions.cs | 2 +- .../Extensions/WidgetDataExtensions.cs | 2 +- src/War3Net.Build/MapScriptBuilder.cs | 238 +++++++------- .../MapScriptBuilder/Audio/InitSounds.cs | 125 ++++---- .../MapScriptBuilder/Audio/Sounds.cs | 49 +-- .../MapScriptBuilder/Common/Config.cs | 115 ++++--- .../Common/ItemTableDropItems.cs | 197 +++++++----- .../MapScriptBuilder/Common/Main.cs | 261 +++++++-------- .../Common/NativeConditions.cs | 16 +- .../Constants/GeneratedFunctionName.cs | 48 +++ .../MapScriptBuilder/Constants/Math.cs | 17 + .../MapScriptBuilder/Constants/NativeName.cs | 2 +- .../MapScriptBuilder/Environment/Cameras.cs | 45 +-- .../Environment/CreateCameras.cs | 57 ++-- .../Environment/CreateRegions.cs | 85 ++--- .../MapScriptBuilder/Environment/Regions.cs | 45 +-- .../Info/InitAllyPriorities.cs | 104 +++--- .../Info/InitCustomPlayerSlots.cs | 79 ++--- .../MapScriptBuilder/Info/InitCustomTeams.cs | 94 +++--- .../MapScriptBuilder/Info/InitRandomGroups.cs | 92 +++--- .../MapScriptBuilder/Info/InitTechTree.cs | 27 +- .../Info/InitTechTreeForPlayer.cs | 42 +-- .../MapScriptBuilder/Info/InitUpgrades.cs | 28 +- .../Info/InitUpgradesForPlayer.cs | 41 ++- .../MapScriptBuilder/Info/MapItemTables.cs | 25 +- .../MapScriptBuilder/Info/RandomUnitTables.cs | 43 +-- .../MapScriptBuilder/Script/Globals.cs | 102 ++++-- .../Script/InitCustomTriggers.cs | 23 +- .../MapScriptBuilder/Script/InitGlobals.cs | 90 +++--- .../MapScriptBuilder/Script/InitTrig.cs | 30 +- .../Script/RunInitializationTriggers.cs | 31 +- .../MapScriptBuilder/Script/Triggers.cs | 53 +++- .../MapScriptBuilder/Script/Variables.cs | 52 +-- .../Widget/CreateAllDestructables.cs | 123 ++++---- .../MapScriptBuilder/Widget/CreateAllItems.cs | 98 +++--- .../MapScriptBuilder/Widget/CreateAllUnits.cs | 51 ++- .../Widget/CreateBuildingsForPlayer.cs | 40 ++- .../Widget/CreateNeutralHostile.cs | 37 ++- .../Widget/CreateNeutralPassive.cs | 37 ++- .../Widget/CreateNeutralPassiveBuildings.cs | 37 ++- .../Widget/CreateNeutralUnits.cs | 29 +- .../Widget/CreatePlayerBuildings.cs | 27 +- .../Widget/CreatePlayerUnits.cs | 25 +- .../MapScriptBuilder/Widget/CreateUnits.cs | 291 +++++++++-------- .../Widget/CreateUnitsForPlayer.cs | 38 ++- .../Widget/DestructableItemTables.cs | 26 +- .../MapScriptBuilder/Widget/Destructables.cs | 63 ++-- .../MapScriptBuilder/Widget/UnitItemTables.cs | 26 +- .../MapScriptBuilder/Widget/Units.cs | 65 ++-- src/War3Net.Build/TriggerRenderer.cs | 154 ++++----- .../TriggerRenderer/ForLoopRenderer.cs | 32 +- .../TriggerRenderer/ForeachLoopRenderer.cs | 29 +- .../TriggerRenderer/IfThenElseRenderer.cs | 23 +- .../TriggerRenderer/SetVariableRenderer.cs | 22 +- .../TriggerRenderer/TriggerActionRenderer.cs | 62 ++-- .../TriggerConditionRenderer.cs | 77 ++--- .../WaitForConditionRenderer.cs | 24 +- src/War3Net.Build/TriggerRendererContext.cs | 12 +- .../EscapedStringProvider.cs | 2 +- .../IndentedTextWriterExtensions.cs | 296 ++++++++++++++++++ .../JassExpression.cs | 137 ++++++++ src/War3Net.CodeAnalysis.Jass/JassLiteral.cs | 56 ++++ .../IndentedTextWriter.cs | 143 +++++++++ 67 files changed, 2678 insertions(+), 1719 deletions(-) rename src/War3Net.Build/Extensions/{TriggerDefinitionExtensions.cs => TriggerItemExtensions.cs} (75%) create mode 100644 src/War3Net.Build/MapScriptBuilder/Constants/GeneratedFunctionName.cs create mode 100644 src/War3Net.Build/MapScriptBuilder/Constants/Math.cs rename src/{War3Net.Build.Core/Providers => War3Net.CodeAnalysis.Jass}/EscapedStringProvider.cs (98%) create mode 100644 src/War3Net.CodeAnalysis.Jass/Extensions/IndentedTextWriterExtensions.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassExpression.cs create mode 100644 src/War3Net.CodeAnalysis.Jass/JassLiteral.cs create mode 100644 src/War3Net.CodeAnalysis/IndentedTextWriter.cs diff --git a/src/War3Net.Build/CompileResult.cs b/src/War3Net.Build/CompileResult.cs index dd90e358..6aa562b1 100644 --- a/src/War3Net.Build/CompileResult.cs +++ b/src/War3Net.Build/CompileResult.cs @@ -24,7 +24,7 @@ internal CompileResult(EmitResult emitResult) _diagnostics = emitResult.Diagnostics; } - internal CompileResult(bool success, IEnumerable diagnostics) + internal CompileResult(bool success, IEnumerable? diagnostics) { _success = success; _diagnostics = diagnostics?.ToImmutableArray() ?? ImmutableArray.Empty; diff --git a/src/War3Net.Build/Extensions/MapExtensions.cs b/src/War3Net.Build/Extensions/MapExtensions.cs index 890c5fe8..ba531618 100644 --- a/src/War3Net.Build/Extensions/MapExtensions.cs +++ b/src/War3Net.Build/Extensions/MapExtensions.cs @@ -53,17 +53,7 @@ public static void CompileScript(this Map map, MapScriptBuilder mapScriptBuilder throw new ArgumentException($"The map's script language must be set to jass in order to use the jass compiler.", nameof(map)); } - var compilationUnit = mapScriptBuilder.Build(map); - - using var stream = new MemoryStream(); - using (var writer = new StreamWriter(stream, _defaultEncoding, leaveOpen: true)) - { - var renderer = new JassRenderer(writer); - renderer.Render(compilationUnit); - } - - stream.Position = 0; - map.SetScriptFile(stream); + map.Script = mapScriptBuilder.Build(map); } public static CompileResult CompileScript(this Map map, Compiler compiler, IEnumerable luaSystemLibs) @@ -133,7 +123,9 @@ public static CompileResult CompileScript(this Map map, Compiler compiler, MapSc transpiler.RegisterJassFile(JassSyntaxFactory.ParseCompilationUnit(File.ReadAllText(commonJPath))); transpiler.RegisterJassFile(JassSyntaxFactory.ParseCompilationUnit(File.ReadAllText(blizzardJPath))); - var luaCompilationUnit = transpiler.Transpile(mapScriptBuilder.Build(map)); + var mapScript = mapScriptBuilder.Build(map); + var jassCompilationUnit = JassSyntaxFactory.ParseCompilationUnit(mapScript); + var luaCompilationUnit = transpiler.Transpile(jassCompilationUnit); using (var writer = new StreamWriter(stream, _defaultEncoding, leaveOpen: true)) { var luaRenderOptions = new LuaSyntaxGenerator.SettingInfo diff --git a/src/War3Net.Build/Extensions/ModifiedAbilityDataExtensions.cs b/src/War3Net.Build/Extensions/ModifiedAbilityDataExtensions.cs index d4079fec..f7bcbe10 100644 --- a/src/War3Net.Build/Extensions/ModifiedAbilityDataExtensions.cs +++ b/src/War3Net.Build/Extensions/ModifiedAbilityDataExtensions.cs @@ -16,13 +16,32 @@ namespace War3Net.Build.Extensions { public static class ModifiedAbilityDataExtensions { + private static readonly Lazy> _abilityOrderOnStrings = new(GetAbilityOrderOnStrings); private static readonly Lazy> _abilityOrderOffStrings = new(GetAbilityOrderOffStrings); + public static bool TryGetOrderOnString(this ModifiedAbilityData abilityData, [NotNullWhen(true)] out string? orderOnString) + { + return _abilityOrderOnStrings.Value.TryGetValue(abilityData.AbilityId, out orderOnString); + } + public static bool TryGetOrderOffString(this ModifiedAbilityData abilityData, [NotNullWhen(true)] out string? orderOffString) { return _abilityOrderOffStrings.Value.TryGetValue(abilityData.AbilityId, out orderOffString); } + private static Dictionary GetAbilityOrderOnStrings() + { + return new Dictionary + { + { "Ahea".FromRawcode(), "healon" }, + { "ACsa".FromRawcode(), "flamingarrows" }, + { "ANth".FromRawcode(), "Thornyshield" }, + { "AEim".FromRawcode(), "immolation" }, + { "ANba".FromRawcode(), "blackarrowon" }, + { "AHds".FromRawcode(), "divineshield" }, + }; + } + private static Dictionary GetAbilityOrderOffStrings() { return new Dictionary diff --git a/src/War3Net.Build/Extensions/TriggerDefinitionExtensions.cs b/src/War3Net.Build/Extensions/TriggerItemExtensions.cs similarity index 75% rename from src/War3Net.Build/Extensions/TriggerDefinitionExtensions.cs rename to src/War3Net.Build/Extensions/TriggerItemExtensions.cs index 2b2900a1..0c3f50d4 100644 --- a/src/War3Net.Build/Extensions/TriggerDefinitionExtensions.cs +++ b/src/War3Net.Build/Extensions/TriggerItemExtensions.cs @@ -1,5 +1,5 @@ -// ------------------------------------------------------------------------------ -// +// ------------------------------------------------------------------------------ +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -12,34 +12,34 @@ namespace War3Net.Build.Extensions { - public static class TriggerDefinitionExtensions + public static class TriggerItemExtensions { - public static string GetVariableName(this TriggerDefinition trigger) + public static string GetVariableName(this TriggerItem trigger) { return $"gg_trg_{trigger.GetTriggerIdentifierName()}"; } - public static string GetInitTrigFunctionName(this TriggerDefinition trigger) + public static string GetInitTrigFunctionName(this TriggerItem trigger) { return $"InitTrig_{trigger.GetTriggerIdentifierName()}"; } - public static string GetTrigConditionsFunctionName(this TriggerDefinition trigger) + public static string GetTrigConditionsFunctionName(this TriggerItem trigger) { return $"Trig_{trigger.GetTriggerIdentifierName()}_Conditions"; } - public static string GetTrigActionsFunctionName(this TriggerDefinition trigger) + public static string GetTrigActionsFunctionName(this TriggerItem trigger) { return $"Trig_{trigger.GetTriggerIdentifierName()}_Actions"; } - public static string GetTrigIdentifierBaseName(this TriggerDefinition trigger) + public static string GetTrigIdentifierBaseName(this TriggerItem trigger) { return $"Trig_{trigger.GetTriggerIdentifierName()}_"; } - public static string GetTriggerIdentifierName(this TriggerDefinition trigger) + public static string GetTriggerIdentifierName(this TriggerItem trigger) { return Regex.Replace(trigger.Name, "[^A-Za-z0-9_]", match => new string('_', Encoding.UTF8.GetBytes(match.Value).Length)); } diff --git a/src/War3Net.Build/Extensions/VariableDefinitionExtensions.cs b/src/War3Net.Build/Extensions/VariableDefinitionExtensions.cs index 881e8a69..7e67ada0 100644 --- a/src/War3Net.Build/Extensions/VariableDefinitionExtensions.cs +++ b/src/War3Net.Build/Extensions/VariableDefinitionExtensions.cs @@ -19,7 +19,7 @@ public static string GetVariableName(this VariableDefinition variable) return $"udg_{variable.Name}"; } - public static IExpressionSyntax GetInitialValueExpression(this VariableDefinition variable) + public static JassExpressionSyntax GetInitialValueExpression(this VariableDefinition variable) { throw new NotImplementedException(); } diff --git a/src/War3Net.Build/Extensions/WidgetDataExtensions.cs b/src/War3Net.Build/Extensions/WidgetDataExtensions.cs index 356e9e91..1ab190ee 100644 --- a/src/War3Net.Build/Extensions/WidgetDataExtensions.cs +++ b/src/War3Net.Build/Extensions/WidgetDataExtensions.cs @@ -20,7 +20,7 @@ public static bool HasItemTable(this WidgetData widgetData) public static bool HasItemTableSets(this WidgetData widgetData) { - return widgetData.ItemTableSets.Any(itemTableSet => itemTableSet.Items.Any()); + return widgetData.ItemTableSets.Any(itemTableSet => itemTableSet.Items.Count > 0); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder.cs b/src/War3Net.Build/MapScriptBuilder.cs index 7857c9a5..d33619a0 100644 --- a/src/War3Net.Build/MapScriptBuilder.cs +++ b/src/War3Net.Build/MapScriptBuilder.cs @@ -7,15 +7,15 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; namespace War3Net.Build { @@ -97,224 +97,242 @@ public virtual void SetDefaultOptionsForMap(Map map) UseWeatherEffectVariable = true; } - public virtual JassCompilationUnitSyntax Build(Map map) + public string Build(Map map) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - JassCommentSyntax commentLine1 = new("==========================================================================="); - JassCommentSyntax commentLine2 = new("***************************************************************************"); - JassCommentSyntax commentLine3 = new("*"); + using var stringWriter = new StringWriter(); + stringWriter.NewLine = JassSymbol.CarriageReturnLineFeed; + using var writer = new IndentedTextWriter(stringWriter); + + Build(map, writer); - List declarations = new(); + return stringWriter.ToString(); + } + + public virtual void Build(Map map, IndentedTextWriter writer) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } - void AppendBanner(string bannerText) + if (writer is null) { - declarations.Add(commentLine2); - declarations.Add(commentLine3); - declarations.Add(new JassCommentSyntax($"* {bannerText}")); - declarations.Add(commentLine3); - declarations.Add(commentLine2); - declarations.Add(JassEmptySyntax.Value); + throw new ArgumentNullException(nameof(writer)); } - void AppendBannerAndFunction(string bannerText, Func function, Func condition, bool includeCommentLine = false) + var commentLine1 = "//==========================================================================="; + var commentLine2 = "//***************************************************************************"; + var commentLine3 = "//*"; + + void WriteBanner(string bannerText) + { + writer.WriteLine(commentLine2); + writer.WriteLine(commentLine3); + writer.WriteLine($"{commentLine3} {bannerText}"); + writer.WriteLine(commentLine3); + writer.WriteLine(commentLine2); + writer.WriteLine(); + } + + void WriteBannerAndFunction(string bannerText, Action function, Func condition, bool includeCommentLine = false) { if (condition(map)) { - AppendBanner(bannerText); + WriteBanner(bannerText); if (includeCommentLine) { - declarations.Add(commentLine1); + writer.WriteLine(commentLine1); } - declarations.Add(function(map)); - declarations.Add(JassEmptySyntax.Value); + function.Invoke(map, writer); + writer.WriteLine(); } } - void AppendBannerAndFunctions(string bannerText, Func> functions, Func condition) + void WriteBannerAndFunctions(string bannerText, Action functions, Func condition) { if (condition(map)) { - AppendBanner(bannerText); - foreach (var function in functions(map)) - { - declarations.Add(function); - declarations.Add(JassEmptySyntax.Value); - } + WriteBanner(bannerText); + functions.Invoke(map, writer); } } - void AppendFunction(Func function, Func condition) + void WriteFunction(Action function, Func condition) { if (condition(map)) { - declarations.Add(commentLine1); - declarations.Add(function(map)); - declarations.Add(JassEmptySyntax.Value); + writer.WriteLine(commentLine1); + function.Invoke(map, writer); + writer.WriteLine(); } } - void AppendFunctionForIndex(int index, Func function, Func condition) + void WriteFunctionForIndex(int index, Action function, Func condition) { if (condition(map, index)) { - declarations.Add(commentLine1); - declarations.Add(function(map, index)); - declarations.Add(JassEmptySyntax.Value); + writer.WriteLine(commentLine1); + function.Invoke(map, index, writer); + writer.WriteLine(); } } - declarations.AddRange(GetMapScriptHeader(map)); - declarations.Add(JassEmptySyntax.Value); + WriteMapScriptHeader(map, writer); + writer.WriteLine(); - AppendBanner("Global Variables"); + WriteBanner("Global Variables"); - declarations.Add(Globals(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateGlobals(map, writer); + writer.WriteLine(); - if (InitGlobalsCondition(map)) + if (ShouldGenerateInitGlobals(map)) { - declarations.Add(InitGlobals(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitGlobals(map, writer); + writer.WriteLine(); } - AppendBanner("Custom Script Code"); - AppendBannerAndFunction("Random Groups", InitRandomGroups, InitRandomGroupsCondition); - AppendBannerAndFunctions("Map Item Tables", MapItemTables, MapItemTablesCondition); - AppendBannerAndFunction("Items", CreateAllItems, CreateAllItemsCondition); - AppendBannerAndFunctions("Unit Item Tables", UnitItemTables, UnitItemTablesCondition); - AppendBannerAndFunctions("Destructable Item Tables", DestructableItemTables, DestructableItemTablesCondition); - AppendBannerAndFunction("Sounds", InitSounds, InitSoundsCondition); - AppendBannerAndFunction("Destructable Objects", CreateAllDestructables, CreateAllDestructablesCondition); + WriteBanner("Custom Script Code"); + WriteBannerAndFunction("Random Groups", GenerateInitRandomGroups, ShouldGenerateInitRandomGroups); + WriteBannerAndFunctions("Map Item Tables", GenerateMapItemTables, ShouldGenerateMapItemTables); + WriteBannerAndFunction("Items", GenerateCreateAllItems, ShouldGenerateCreateAllItems); + WriteBannerAndFunctions("Unit Item Tables", GenerateUnitItemTables, ShouldGenerateUnitItemTables); + WriteBannerAndFunctions("Destructable Item Tables", GenerateDestructableItemTables, ShouldGenerateDestructableItemTables); + WriteBannerAndFunction("Sounds", GenerateInitSounds, ShouldGenerateInitSounds); + WriteBannerAndFunction("Destructable Objects", GenerateCreateAllDestructables, ShouldGenerateCreateAllDestructables); - if (CreateAllUnitsCondition(map)) + if (ShouldGenerateCreateAllUnits(map)) { - AppendBanner("Unit Creation"); + WriteBanner("Unit Creation"); foreach (var i in Enumerable.Range(0, MaxPlayerSlots)) { - AppendFunctionForIndex(i, CreateBuildingsForPlayer, CreateBuildingsForPlayerCondition); - AppendFunctionForIndex(i, CreateUnitsForPlayer, CreateUnitsForPlayerCondition); + WriteFunctionForIndex(i, GenerateCreateBuildingsForPlayer, ShouldGenerateCreateBuildingsForPlayer); + WriteFunctionForIndex(i, GenerateCreateUnitsForPlayer, ShouldGenerateCreateUnitsForPlayer); } - AppendFunction(CreateNeutralHostile, CreateNeutralHostileCondition); - AppendFunction(CreateNeutralPassiveBuildings, CreateNeutralPassiveBuildingsCondition); - AppendFunction(CreateNeutralPassive, CreateNeutralPassiveCondition); - AppendFunction(CreatePlayerBuildings, CreatePlayerBuildingsCondition); - AppendFunction(CreatePlayerUnits, CreatePlayerUnitsCondition); - AppendFunction(CreateNeutralUnits, CreateNeutralUnitsCondition); - AppendFunction(CreateAllUnits, (map) => true); + WriteFunction(GenerateCreateNeutralHostile, ShouldGenerateCreateNeutralHostile); + WriteFunction(GenerateCreateNeutralPassiveBuildings, ShouldGenerateCreateNeutralPassiveBuildings); + WriteFunction(GenerateCreateNeutralPassive, ShouldGenerateCreateNeutralPassive); + WriteFunction(GenerateCreatePlayerBuildings, ShouldGenerateCreatePlayerBuildings); + WriteFunction(GenerateCreatePlayerUnits, ShouldGenerateCreatePlayerUnits); + WriteFunction(GenerateCreateNeutralUnits, ShouldGenerateCreateNeutralUnits); + WriteFunction(GenerateCreateAllUnits, (map) => true); } - AppendBannerAndFunction("Regions", CreateRegions, CreateRegionsCondition); - AppendBannerAndFunction("Cameras", CreateCameras, CreateCamerasCondition); + WriteBannerAndFunction("Regions", GenerateCreateRegions, ShouldGenerateCreateRegions); + WriteBannerAndFunction("Cameras", GenerateCreateCameras, ShouldGenerateCreateCameras); - AppendBanner("Triggers"); + WriteBanner("Triggers"); if (map.Triggers is not null) { foreach (var trigger in map.Triggers.TriggerItems) { if (trigger is TriggerDefinition triggerDefinition && - InitTrigCondition(map, triggerDefinition)) + ShouldRenderTrigger(map, triggerDefinition)) { - declarations.Add(commentLine1); - declarations.Add(InitTrig(map, triggerDefinition)); - declarations.Add(JassEmptySyntax.Value); + var triggerRenderer = new TriggerRenderer(writer, TriggerData, map.Triggers.Variables, isLuaTrigger: false); + triggerRenderer.RenderTrigger(triggerDefinition); + writer.WriteLine(); } } - AppendFunction(InitCustomTriggers, InitCustomTriggersCondition); - AppendFunction(RunInitializationTriggers, RunInitializationTriggersCondition); + WriteFunction(GenerateInitCustomTriggers, ShouldGenerateInitCustomTriggers); + WriteFunction(GenerateRunInitializationTriggers, ShouldGenerateRunInitializationTriggers); } - if (InitUpgradesCondition(map)) + if (ShouldGenerateInitUpgrades(map)) { - AppendBanner("Upgrades"); + WriteBanner("Upgrades"); foreach (var i in Enumerable.Range(0, MaxPlayerSlots)) { - if (InitUpgrades_PlayerCondition(map, i)) + if (ShouldGenerateInitUpgradesForPlayer(map, i)) { - declarations.Add(InitUpgrades_Player(map, i)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitUpgradesForPlayer(map, i, writer); + writer.WriteLine(); } } - declarations.Add(InitUpgrades(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitUpgrades(map, writer); + writer.WriteLine(); } - if (InitTechTreeCondition(map)) + if (ShouldGenerateInitTechTree(map)) { - AppendBanner("TechTree"); + WriteBanner("TechTree"); foreach (var i in Enumerable.Range(0, MaxPlayerSlots)) { - if (InitTechTree_PlayerCondition(map, i)) + if (ShouldGenerateInitTechTreeForPlayer(map, i)) { - declarations.Add(InitTechTree_Player(map, i)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitTechTreeForPlayer(map, i, writer); + writer.WriteLine(); } } - declarations.Add(InitTechTree(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitTechTree(map, writer); + writer.WriteLine(); } - AppendBanner("Players"); + WriteBanner("Players"); - if (InitCustomPlayerSlotsCondition(map)) + if (ShouldGenerateInitCustomPlayerSlots(map)) { - declarations.Add(InitCustomPlayerSlots(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitCustomPlayerSlots(map, writer); + writer.WriteLine(); } - if (InitCustomTeamsCondition(map)) + if (ShouldGenerateInitCustomTeams(map)) { - declarations.Add(InitCustomTeams(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitCustomTeams(map, writer); + writer.WriteLine(); } - if (InitAllyPrioritiesCondition(map)) + if (ShouldGenerateInitAllyPriorities(map)) { var ids = Enumerable.Range(0, MaxPlayerSlots).ToArray(); if (map.Info.Players.Any(p => ids.Any(id => p.AllyLowPriorityFlags[id] || p.AllyHighPriorityFlags[id]))) { - declarations.Add(InitAllyPriorities(map)); - declarations.Add(JassEmptySyntax.Value); + GenerateInitAllyPriorities(map, writer); + writer.WriteLine(); } } - AppendBannerAndFunction("Main Initialization", main, mainCondition, true); - AppendBannerAndFunction("Map Configuration", config, configCondition); - - return SyntaxFactory.CompilationUnit(declarations); + WriteBannerAndFunction("Main Initialization", GenerateMain, ShouldGenerateMain, true); + WriteBannerAndFunction("Map Configuration", GenerateConfig, ShouldGenerateConfig); } - protected internal virtual IEnumerable GetMapScriptHeader(Map map) + protected internal virtual void WriteMapScriptHeader(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapInfo = map.Info; var mapTriggerStrings = map.TriggerStrings; - yield return new JassCommentSyntax($"==========================================================================="); - yield return new JassCommentSyntax($" "); - yield return new JassCommentSyntax($" {mapInfo.MapName.Localize(mapTriggerStrings)}"); - yield return new JassCommentSyntax($" "); - yield return new JassCommentSyntax($" Warcraft III map script"); - yield return new JassCommentSyntax($" Generated by {Assembly.GetExecutingAssembly().GetName().Name}"); - yield return new JassCommentSyntax($" Date: {DateTime.Now:ddd MMM dd HH:mm:ss yyyy}"); - yield return new JassCommentSyntax($" Map Author: {mapInfo.MapAuthor.Localize(mapTriggerStrings)}"); - yield return new JassCommentSyntax($" "); - yield return new JassCommentSyntax($"==========================================================================="); + writer.WriteLine("//==========================================================================="); + writer.WriteLine("// "); + writer.WriteLine($"// {mapInfo.MapName.Localize(mapTriggerStrings)}"); + writer.WriteLine("// "); + writer.WriteLine("// Warcraft III map script"); + writer.WriteLine($"// Generated by {Assembly.GetExecutingAssembly().GetName().Name}"); + writer.WriteLine($"// Date: {DateTime.Now:ddd MMM dd HH:mm:ss yyyy}"); + writer.WriteLine($"// Map Author: {mapInfo.MapAuthor.Localize(mapTriggerStrings)}"); + writer.WriteLine("// "); + writer.WriteLine("//==========================================================================="); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs b/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs index 5915206e..6a7f2a0a 100644 --- a/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs +++ b/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs @@ -6,40 +6,43 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using War3Net.Build.Audio; -using War3Net.Build.Providers; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitSounds(Map map) + protected internal virtual void GenerateInitSounds(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapSounds = map.Sounds; if (mapSounds is null) { throw new ArgumentException($"Function '{nameof(InitSounds)}' cannot be generated without {nameof(MapSounds)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitSounds); foreach (var sound in mapSounds.Sounds) { if (sound.Flags.HasFlag(SoundFlags.Music)) { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( sound.Name, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(sound.FilePath)))); + JassLiteral.String(sound.FilePath)); } else { @@ -48,115 +51,115 @@ protected internal virtual JassFunctionDeclarationSyntax InitSounds(Map map) && sound.Channel != SoundChannel.Music && sound.Channel != SoundChannel.UserInterface; - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( sound.Name, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.CreateSound, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(sound.FilePath)), - SyntaxFactory.LiteralExpression(sound.Flags.HasFlag(SoundFlags.Looping)), - SyntaxFactory.LiteralExpression(is3DSound), - SyntaxFactory.LiteralExpression(sound.Flags.HasFlag(SoundFlags.StopWhenOutOfRange)), - SyntaxFactory.LiteralExpression(sound.FadeInRate), - SyntaxFactory.LiteralExpression(sound.FadeOutRate), - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(sound.EaxSetting))))); + JassLiteral.String(sound.FilePath), + JassLiteral.Bool(sound.Flags.HasFlag(SoundFlags.Looping)), + JassLiteral.Bool(is3DSound), + JassLiteral.Bool(sound.Flags.HasFlag(SoundFlags.StopWhenOutOfRange)), + JassLiteral.Int(sound.FadeInRate), + JassLiteral.Int(sound.FadeOutRate), + JassLiteral.String(sound.EaxSetting))); if (!string.IsNullOrEmpty(sound.FacialAnimationLabel)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundFacialAnimationLabel, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.FacialAnimationLabel))); + sound.Name, + JassLiteral.String(sound.FacialAnimationLabel)); } if (!string.IsNullOrEmpty(sound.FacialAnimationGroupLabel)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundFacialAnimationGroupLabel, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.FacialAnimationGroupLabel))); + sound.Name, + JassLiteral.String(sound.FacialAnimationGroupLabel)); } if (!string.IsNullOrEmpty(sound.FacialAnimationSetFilepath)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundFacialAnimationSetFilepath, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.FacialAnimationSetFilepath))); + sound.Name, + JassLiteral.String(sound.FacialAnimationSetFilepath)); } if (sound.DialogueSpeakerNameKey > 0) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetDialogueSpeakerNameKey, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression($"TRIGSTR_{sound.DialogueSpeakerNameKey}"))); + sound.Name, + JassLiteral.String($"TRIGSTR_{sound.DialogueSpeakerNameKey}")); } if (sound.DialogueTextKey > 0) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetDialogueTextKey, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression($"TRIGSTR_{sound.DialogueTextKey}"))); + sound.Name, + JassLiteral.String($"TRIGSTR_{sound.DialogueTextKey}")); } if (sound.DistanceCutoff != 3000f) { var distanceCutoff = sound.DistanceCutoff == uint.MaxValue ? 3000f : sound.DistanceCutoff; - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundDistanceCutoff, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(distanceCutoff, precision: 1))); + sound.Name, + JassLiteral.Real(distanceCutoff)); } if ((int)sound.Channel != -1) { var channel = sound.Channel == SoundChannel.Undefined ? SoundChannel.General : sound.Channel; - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundChannel, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression((int)channel))); + sound.Name, + JassLiteral.Int((int)channel)); } - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundVolume, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.Volume == -1 ? 127 : sound.Volume))); + sound.Name, + JassLiteral.Int(sound.Volume == -1 ? 127 : sound.Volume)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundPitch, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.Pitch == uint.MaxValue ? 1f : sound.Pitch, precision: 1))); + sound.Name, + JassLiteral.Real(sound.Pitch == uint.MaxValue ? 1f : sound.Pitch)); if (is3DSound) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundDistances, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.MinDistance == uint.MaxValue ? 0f : sound.MinDistance, precision: 1), - SyntaxFactory.LiteralExpression(sound.MaxDistance == uint.MaxValue ? 10000f : sound.MaxDistance, precision: 1))); + sound.Name, + JassLiteral.Real(sound.MinDistance == uint.MaxValue ? 0f : sound.MinDistance), + JassLiteral.Real(sound.MaxDistance == uint.MaxValue ? 10000f : sound.MaxDistance)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundConeAngles, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.ConeAngleInside == uint.MaxValue ? 0f : sound.ConeAngleInside, precision: 1), - SyntaxFactory.LiteralExpression(sound.ConeAngleOutside == uint.MaxValue ? 0f : sound.ConeAngleOutside, precision: 1), - SyntaxFactory.LiteralExpression(sound.ConeOutsideVolume == -1 ? 127 : sound.ConeOutsideVolume))); + sound.Name, + JassLiteral.Real(sound.ConeAngleInside == uint.MaxValue ? 0f : sound.ConeAngleInside), + JassLiteral.Real(sound.ConeAngleOutside == uint.MaxValue ? 0f : sound.ConeAngleOutside), + JassLiteral.Int(sound.ConeOutsideVolume == -1 ? 127 : sound.ConeOutsideVolume)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundConeOrientation, - SyntaxFactory.VariableReferenceExpression(sound.Name), - SyntaxFactory.LiteralExpression(sound.ConeOrientation.X == uint.MaxValue ? 0f : sound.ConeOrientation.X, precision: 1), - SyntaxFactory.LiteralExpression(sound.ConeOrientation.Y == uint.MaxValue ? 0f : sound.ConeOrientation.Y, precision: 1), - SyntaxFactory.LiteralExpression(sound.ConeOrientation.Z == uint.MaxValue ? 0f : sound.ConeOrientation.Z, precision: 1))); + sound.Name, + JassLiteral.Real(sound.ConeOrientation.X == uint.MaxValue ? 0f : sound.ConeOrientation.X), + JassLiteral.Real(sound.ConeOrientation.Y == uint.MaxValue ? 0f : sound.ConeOrientation.Y), + JassLiteral.Real(sound.ConeOrientation.Z == uint.MaxValue ? 0f : sound.ConeOrientation.Z)); } } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitSounds)), statements); + writer.EndFunction(); } - protected internal virtual bool InitSoundsCondition(Map map) + protected internal virtual bool ShouldGenerateInitSounds(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Audio/Sounds.cs b/src/War3Net.Build/MapScriptBuilder/Audio/Sounds.cs index 85373d96..3e063784 100644 --- a/src/War3Net.Build/MapScriptBuilder/Audio/Sounds.cs +++ b/src/War3Net.Build/MapScriptBuilder/Audio/Sounds.cs @@ -6,60 +6,61 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.Build.Audio; -using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - public virtual IEnumerable SoundsApi(Map map, JassToCSharpTranspiler transpiler) + protected internal virtual void GenerateSoundVariables(Map map, IndentedTextWriter writer) { - if (transpiler is null) + if (map is null) { - throw new ArgumentNullException(nameof(transpiler)); + throw new ArgumentNullException(nameof(map)); } - return Sounds(map).Select(sound => transpiler.Transpile(sound)); - } - - protected internal virtual IEnumerable Sounds(Map map) - { - if (map is null) + if (writer is null) { - throw new ArgumentNullException(nameof(map)); + throw new ArgumentNullException(nameof(writer)); } var mapSounds = map.Sounds; if (mapSounds is null) { - yield break; + return; } foreach (var sound in mapSounds.Sounds) { if (sound.Flags.HasFlag(SoundFlags.Music)) { - yield return SyntaxFactory.GlobalDeclaration( - JassTypeSyntax.String, + writer.WriteAlignedGlobal( + JassKeyword.String, sound.Name); } else { - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(TypeName.Sound), + writer.WriteAlignedGlobal( + TypeName.Sound, sound.Name, - JassNullLiteralExpressionSyntax.Value); + JassKeyword.Null); } } } + + protected internal virtual bool ShouldGenerateSoundVariables(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + return map.Sounds is not null + && map.Sounds.Sounds.Count > 0; + } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Common/Config.cs b/src/War3Net.Build/MapScriptBuilder/Common/Config.cs index d1ecd765..13739767 100644 --- a/src/War3Net.Build/MapScriptBuilder/Common/Config.cs +++ b/src/War3Net.Build/MapScriptBuilder/Common/Config.cs @@ -1,127 +1,124 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // // ------------------------------------------------------------------------------ -#pragma warning disable IDE1006, SA1300 - using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Info; -using War3Net.Build.Providers; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax config(Map map) + protected internal virtual void GenerateConfig(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(config)}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.Config}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.Config); var playerDataCount = mapInfo.Players.Count; - var forceDataCount = mapInfo.Forces.Count; - statements.Add(SyntaxFactory.CallStatement(NativeName.SetMapName, SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(mapInfo.MapName)))); - statements.Add(SyntaxFactory.CallStatement(NativeName.SetMapDescription, SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(mapInfo.MapDescription)))); - statements.Add(SyntaxFactory.CallStatement(NativeName.SetPlayers, SyntaxFactory.LiteralExpression(playerDataCount))); - statements.Add(SyntaxFactory.CallStatement(NativeName.SetTeams, SyntaxFactory.LiteralExpression(playerDataCount))); + writer.WriteCall(NativeName.SetMapName, JassLiteral.String(mapInfo.MapName)); + writer.WriteCall(NativeName.SetMapDescription, JassLiteral.String(mapInfo.MapDescription)); + writer.WriteCall(NativeName.SetPlayers, JassLiteral.Int(playerDataCount)); + writer.WriteCall(NativeName.SetTeams, JassLiteral.Int(playerDataCount)); + var placement = mapInfo.Players.Any(player => player.AllyHighPriorityFlags != 0 || player.AllyLowPriorityFlags != 0) + ? PlacementName.TeamsTogether + : PlacementName.UseMapSettings; - if (mapInfo.Players.Any(player => player.AllyHighPriorityFlags != 0 || player.AllyLowPriorityFlags != 0)) - { - statements.Add(SyntaxFactory.CallStatement(NativeName.SetGamePlacement, SyntaxFactory.VariableReferenceExpression(PlacementName.TeamsTogether))); - } - else - { - statements.Add(SyntaxFactory.CallStatement(NativeName.SetGamePlacement, SyntaxFactory.VariableReferenceExpression(PlacementName.UseMapSettings))); - } + writer.WriteCall(NativeName.SetGamePlacement, placement); - statements.Add(JassEmptySyntax.Value); + writer.WriteLine(); if (!string.IsNullOrEmpty(LobbyMusic)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.PlayMusic, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(LobbyMusic)))); + JassLiteral.String(LobbyMusic)); } for (var i = 0; i < playerDataCount; i++) { var location = mapInfo.Players[i].StartPosition; - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.DefineStartLocation, - SyntaxFactory.LiteralExpression(i), - SyntaxFactory.LiteralExpression(location.X, precision: 1), - SyntaxFactory.LiteralExpression(location.Y, precision: 1))); + JassLiteral.Int(i), + JassLiteral.Real(location.X), + JassLiteral.Real(location.Y)); } - statements.Add(JassEmptySyntax.Value); - statements.Add(new JassCommentSyntax(" Player setup")); + writer.WriteLine(); + writer.WriteComment("Player setup"); - if (InitCustomPlayerSlotsCondition(map)) + if (ShouldGenerateInitCustomPlayerSlots(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitCustomPlayerSlots))); + writer.WriteCall(GeneratedFunctionName.InitCustomPlayerSlots); } - var elseStatements = new List(); if (!mapInfo.MapFlags.HasFlag(MapFlags.UseCustomForces)) { + if (mapInfo.FormatVersion < MapInfoFormatVersion.v15) + { + var condition = JassExpression.Equal( + JassExpression.InvokeSpaced(NativeName.GetGameTypeSelected), + GameType.UseMapSettings); + + writer.WriteIf(JassExpression.ParenthesizedCompact(condition)); + writer.WriteCall(GeneratedFunctionName.InitCustomTeams); + writer.WriteElse(); + } + for (var i = 0; i < playerDataCount; i++) { - elseStatements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.SetPlayerSlotAvailable, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(mapInfo.Players[i].Id)), - SyntaxFactory.VariableReferenceExpression(MapControlName.User))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(mapInfo.Players[i].Id)), + MapControlName.User); } - elseStatements.Add(SyntaxFactory.CallStatement(FunctionName.InitGenericPlayerSlots)); - } + writer.WriteCall(FunctionName.InitGenericPlayerSlots); - if (mapInfo.FormatVersion < MapInfoFormatVersion.v15) - { - statements.Add(SyntaxFactory.IfStatement( - SyntaxFactory.ParenthesizedExpression(SyntaxFactory.BinaryEqualsExpression( - SyntaxFactory.InvocationExpression(NativeName.GetGameTypeSelected), - SyntaxFactory.VariableReferenceExpression(GameType.UseMapSettings))), - SyntaxFactory.StatementList(SyntaxFactory.CallStatement(nameof(InitCustomTeams))), - new JassElseClauseSyntax(SyntaxFactory.StatementList(elseStatements)))); - } - else - { - statements.AddRange(elseStatements); + if (mapInfo.FormatVersion < MapInfoFormatVersion.v15) + { + writer.WriteEndIf(); + } } - if (InitCustomTeamsCondition(map) && InitCustomTeamsInvokeCondition(map)) + if (ShouldGenerateInitCustomTeams(map) && ShouldCallInitCustomTeams(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitCustomTeams))); + writer.WriteCall(GeneratedFunctionName.InitCustomTeams); } - if (InitAllyPrioritiesCondition(map)) + if (ShouldGenerateInitAllyPriorities(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitAllyPriorities))); + writer.WriteCall(GeneratedFunctionName.InitAllyPriorities); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(config)), statements); + writer.EndFunction(); } - protected internal virtual bool configCondition(Map map) + protected internal virtual bool ShouldGenerateConfig(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Common/ItemTableDropItems.cs b/src/War3Net.Build/MapScriptBuilder/Common/ItemTableDropItems.cs index ac6ec451..e69cf6da 100644 --- a/src/War3Net.Build/MapScriptBuilder/Common/ItemTableDropItems.cs +++ b/src/War3Net.Build/MapScriptBuilder/Common/ItemTableDropItems.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -13,15 +13,15 @@ using War3Net.Build.Info; using War3Net.Build.Providers; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax ItemTableDropItems(Map map, RandomItemTable table) + protected internal virtual void GenerateItemTableDropItems(Map map, RandomItemTable table, IndentedTextWriter writer) { if (map is null) { @@ -33,10 +33,20 @@ protected internal virtual JassFunctionDeclarationSyntax ItemTableDropItems(Map throw new ArgumentNullException(nameof(table)); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(table.GetDropItemsFunctionName()), GetItemTableDropItemsStatements(map, table.ItemSets, false)); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteFunction(table.GetDropItemsFunctionName()); + + WriteItemTableDropItemsStatements(map, table.ItemSets, false, writer); + + writer.EndFunction(); + writer.WriteLine(); } - protected internal virtual JassFunctionDeclarationSyntax ItemTableDropItems(Map map, WidgetData widgetData, int id) + protected internal virtual void GenerateItemTableDropItems(Map map, WidgetData widgetData, int id, IndentedTextWriter writer) { if (map is null) { @@ -48,16 +58,26 @@ protected internal virtual JassFunctionDeclarationSyntax ItemTableDropItems(Map throw new ArgumentNullException(nameof(widgetData)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var funcName = widgetData switch { DoodadData doodadData => doodadData.GetDropItemsFunctionName(id), UnitData unitData => unitData.GetDropItemsFunctionName(id), }; - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(funcName), GetItemTableDropItemsStatements(map, widgetData.ItemTableSets, true)); + writer.WriteFunction(funcName); + + WriteItemTableDropItemsStatements(map, widgetData.ItemTableSets, true, writer); + + writer.EndFunction(); + writer.WriteLine(); } - protected internal virtual IEnumerable GetItemTableDropItemsStatements(Map map, IEnumerable itemSets, bool chooseItemClass) + protected internal virtual void WriteItemTableDropItemsStatements(Map map, IEnumerable itemSets, bool chooseItemClass, IndentedTextWriter writer) { if (map is null) { @@ -69,123 +89,136 @@ protected internal virtual IEnumerable GetItemTableDropItemsSt throw new ArgumentNullException(nameof(itemSets)); } - var statements = new List(); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Widget), VariableName.TrigWidget, JassNullLiteralExpressionSyntax.Value)); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Unit), VariableName.TrigUnit, JassNullLiteralExpressionSyntax.Value)); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Integer, VariableName.ItemId, SyntaxFactory.LiteralExpression(0))); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Boolean, VariableName.CanDrop, SyntaxFactory.LiteralExpression(true))); - statements.Add(JassEmptySyntax.Value); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteAlignedLocal(TypeName.Widget, VariableName.TrigWidget, JassKeyword.Null); + writer.WriteAlignedLocal(TypeName.Unit, VariableName.TrigUnit, JassKeyword.Null); + writer.WriteAlignedLocal(JassKeyword.Integer, VariableName.ItemId, "0"); + writer.WriteAlignedLocal(JassKeyword.Boolean, VariableName.CanDrop, JassKeyword.True); + writer.WriteLine(); - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.TrigWidget, - SyntaxFactory.VariableReferenceExpression(VariableName.BJLastDyingWidget))); + VariableName.BJLastDyingWidget); - statements.Add(SyntaxFactory.IfStatement( - new JassParenthesizedExpressionSyntax(SyntaxFactory.BinaryEqualsExpression(SyntaxFactory.VariableReferenceExpression(VariableName.TrigWidget), JassNullLiteralExpressionSyntax.Value)), - SyntaxFactory.SetStatement(VariableName.TrigUnit, SyntaxFactory.InvocationExpression(NativeName.GetTriggerUnit)))); + writer.WriteIf(JassExpression.ParenthesizedCompact(JassExpression.Equal( + VariableName.TrigWidget, + JassKeyword.Null))); - statements.Add(JassEmptySyntax.Value); + writer.WriteSet(VariableName.TrigUnit, JassExpression.Invoke(NativeName.GetTriggerUnit)); + writer.WriteEndIf(); - var canDropConditionExpression = SyntaxFactory.UnaryNotExpression(SyntaxFactory.InvocationExpression(NativeName.IsUnitHidden, SyntaxFactory.VariableReferenceExpression(VariableName.TrigUnit))); + writer.WriteLine(); - var ifBody = new List() - { - SyntaxFactory.SetStatement(VariableName.CanDrop, canDropConditionExpression), - }; + var trigUnitNotNullExpression = JassExpression.ParenthesizedCompact(JassExpression.NotEqual( + VariableName.TrigUnit, + JassKeyword.Null)); + + var changingUnitNotNullExpression = JassExpression.NotEqual( + JassExpression.Invoke(NativeName.GetChangingUnit), + JassKeyword.Null); + + writer.WriteIf(trigUnitNotNullExpression); + + writer.WriteSet( + VariableName.CanDrop, + JassExpression.Not(JassExpression.Invoke( + NativeName.IsUnitHidden, + VariableName.TrigUnit))); + + writer.WriteIf(JassExpression.ParenthesizedCompact(JassExpression.And( + VariableName.CanDrop, + changingUnitNotNullExpression))); - ifBody.Add(SyntaxFactory.IfStatement( - new JassParenthesizedExpressionSyntax(SyntaxFactory.BinaryAndExpression( - SyntaxFactory.VariableReferenceExpression(VariableName.CanDrop), - SyntaxFactory.BinaryNotEqualsExpression(SyntaxFactory.InvocationExpression(NativeName.GetChangingUnit), JassNullLiteralExpressionSyntax.Value))), - SyntaxFactory.SetStatement( - VariableName.CanDrop, - new JassParenthesizedExpressionSyntax(SyntaxFactory.BinaryEqualsExpression( - SyntaxFactory.InvocationExpression(NativeName.GetChangingUnitPrevOwner), - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.VariableReferenceExpression(GlobalVariableName.PlayerNeutralHostile))))))); - - statements.Add(SyntaxFactory.IfStatement( - new JassParenthesizedExpressionSyntax(SyntaxFactory.BinaryNotEqualsExpression(SyntaxFactory.VariableReferenceExpression(VariableName.TrigUnit), JassNullLiteralExpressionSyntax.Value)), - SyntaxFactory.StatementList(ifBody))); - statements.Add(JassEmptySyntax.Value); + writer.WriteSet( + VariableName.CanDrop, + JassExpression.ParenthesizedCompact(JassExpression.Equal( + JassExpression.Invoke(NativeName.GetChangingUnitPrevOwner), + JassExpression.Invoke(NativeName.Player, GlobalVariableName.PlayerNeutralHostile)))); + + writer.WriteEndIf(); + writer.WriteEndIf(); + writer.WriteLine(); + + writer.WriteIf(JassExpression.ParenthesizedCompact(VariableName.CanDrop)); var i = 0; - var randomDistStatements = new List(); foreach (var itemSet in itemSets) { - randomDistStatements.Add(new JassCommentSyntax($" Item set {i}")); - randomDistStatements.Add(SyntaxFactory.CallStatement(FunctionName.RandomDistReset)); + writer.WriteComment($"Item set {i}"); + writer.WriteCall(FunctionName.RandomDistReset); var summedChance = 0; foreach (var item in itemSet.Items) { + string itemIdExpression; if (RandomItemProvider.IsRandomItem(item.ItemId, out var itemClass, out var level)) { if (chooseItemClass) { - randomDistStatements.Add(SyntaxFactory.CallStatement( - FunctionName.RandomDistAddItem, - SyntaxFactory.InvocationExpression( - NativeName.ChooseRandomItemEx, - SyntaxFactory.VariableReferenceExpression(itemClass.GetVariableName()), - SyntaxFactory.LiteralExpression(level)), - SyntaxFactory.LiteralExpression(item.Chance))); + itemIdExpression = JassExpression.InvokeSpaced( + NativeName.ChooseRandomItemEx, + itemClass.GetVariableName(), + JassLiteral.Int(level)); } else { - randomDistStatements.Add(SyntaxFactory.CallStatement( - FunctionName.RandomDistAddItem, - SyntaxFactory.InvocationExpression(NativeName.ChooseRandomItem, SyntaxFactory.LiteralExpression(level)), - SyntaxFactory.LiteralExpression(item.Chance))); + itemIdExpression = JassExpression.InvokeSpaced( + NativeName.ChooseRandomItem, + JassLiteral.Int(level)); } } else { - randomDistStatements.Add(SyntaxFactory.CallStatement( - FunctionName.RandomDistAddItem, - SyntaxFactory.FourCCLiteralExpression(item.ItemId), - SyntaxFactory.LiteralExpression(item.Chance))); + itemIdExpression = JassLiteral.FourCC(item.ItemId); } + writer.WriteCall( + FunctionName.RandomDistAddItem, + itemIdExpression, + JassLiteral.Int(item.Chance)); + summedChance += item.Chance; } if (summedChance < 100) { - randomDistStatements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.RandomDistAddItem, - SyntaxFactory.LiteralExpression(-1), - SyntaxFactory.LiteralExpression(100 - summedChance))); + "-1", + JassLiteral.Int(100 - summedChance)); } - var unitDropItemStatement = SyntaxFactory.CallStatement( - FunctionName.UnitDropItem, - SyntaxFactory.VariableReferenceExpression(VariableName.TrigUnit), - SyntaxFactory.VariableReferenceExpression(VariableName.ItemId)); + writer.WriteSet( + VariableName.ItemId, + JassExpression.InvokeSpaced(FunctionName.RandomDistChoose)); - randomDistStatements.Add(SyntaxFactory.SetStatement(VariableName.ItemId, SyntaxFactory.InvocationExpression(FunctionName.RandomDistChoose))); + writer.WriteIf(trigUnitNotNullExpression); + writer.WriteCall( + FunctionName.UnitDropItem, + VariableName.TrigUnit, + VariableName.ItemId); - randomDistStatements.Add(SyntaxFactory.IfStatement( - new JassParenthesizedExpressionSyntax(SyntaxFactory.BinaryNotEqualsExpression(SyntaxFactory.VariableReferenceExpression(VariableName.TrigUnit), JassNullLiteralExpressionSyntax.Value)), - SyntaxFactory.StatementList(unitDropItemStatement), - new JassElseClauseSyntax(SyntaxFactory.StatementList(SyntaxFactory.CallStatement( - FunctionName.WidgetDropItem, - SyntaxFactory.VariableReferenceExpression(VariableName.TrigWidget), - SyntaxFactory.VariableReferenceExpression(VariableName.ItemId)))))); + writer.WriteElse(); + writer.WriteCall( + FunctionName.WidgetDropItem, + VariableName.TrigWidget, + VariableName.ItemId); - randomDistStatements.Add(JassEmptySyntax.Value); + writer.WriteEndIf(); + writer.WriteLine(); i++; } - statements.Add(SyntaxFactory.IfStatement( - new JassParenthesizedExpressionSyntax(SyntaxFactory.VariableReferenceExpression(VariableName.CanDrop)), - randomDistStatements.ToArray())); - statements.Add(JassEmptySyntax.Value); - - statements.Add(SyntaxFactory.SetStatement(VariableName.BJLastDyingWidget, JassNullLiteralExpressionSyntax.Value)); - statements.Add(SyntaxFactory.CallStatement(NativeName.DestroyTrigger, SyntaxFactory.InvocationExpression(NativeName.GetTriggeringTrigger))); + writer.WriteEndIf(); + writer.WriteLine(); - return statements; + writer.WriteSet(VariableName.BJLastDyingWidget, JassKeyword.Null); + writer.WriteCallCompact(NativeName.DestroyTrigger, JassExpression.Invoke(NativeName.GetTriggeringTrigger)); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Common/Main.cs b/src/War3Net.Build/MapScriptBuilder/Common/Main.cs index 528d4cde..ba40f76c 100644 --- a/src/War3Net.Build/MapScriptBuilder/Common/Main.cs +++ b/src/War3Net.Build/MapScriptBuilder/Common/Main.cs @@ -1,268 +1,277 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // // ------------------------------------------------------------------------------ -#pragma warning disable IDE1006, SA1300 - using System; -using System.Collections.Generic; using War3Net.Build.Common; using War3Net.Build.Environment; using War3Net.Build.Info; using War3Net.Build.Providers; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax main(Map map) + protected internal virtual void GenerateMain(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapEnvironment = map.Environment; if (mapEnvironment is null) { - throw new ArgumentException($"Function '{nameof(main)}' cannot be generated without {nameof(MapEnvironment)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.Main}' cannot be generated without {nameof(MapEnvironment)}.", nameof(map)); } var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(main)}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.Main}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.Main); - if (UseWeatherEffectVariable && EnableGlobalWeatherEffectCondition(map)) + if (UseWeatherEffectVariable && ShouldCallEnableGlobalWeatherEffect(map)) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.WeatherEffect), VariableName.WeatherEffect)); + writer.WriteLocal(TypeName.WeatherEffect, VariableName.WeatherEffect); } if (mapInfo.CameraBoundsComplements is null) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetCameraBounds, - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.BottomLeft.X, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.BottomLeft.Y, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.TopRight.X, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.TopRight.Y, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.TopLeft.X, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.TopLeft.Y, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.BottomRight.X, precision: 1), - SyntaxFactory.LiteralExpression(mapInfo.CameraBounds.BottomRight.Y, precision: 1))); + JassLiteral.Real(mapInfo.CameraBounds.BottomLeft.X), + JassLiteral.Real(mapInfo.CameraBounds.BottomLeft.Y), + JassLiteral.Real(mapInfo.CameraBounds.TopRight.X), + JassLiteral.Real(mapInfo.CameraBounds.TopRight.Y), + JassLiteral.Real(mapInfo.CameraBounds.TopLeft.X), + JassLiteral.Real(mapInfo.CameraBounds.TopLeft.Y), + JassLiteral.Real(mapInfo.CameraBounds.BottomRight.X), + JassLiteral.Real(mapInfo.CameraBounds.BottomRight.Y)); } else { - statements.Add(SyntaxFactory.CallStatement( + var left = JassLiteral.Real(mapEnvironment.Left + (128 * mapInfo.CameraBoundsComplements.Left)); + var bottom = JassLiteral.Real(mapEnvironment.Bottom + (128 * mapInfo.CameraBoundsComplements.Bottom)); + var right = JassLiteral.Real(mapEnvironment.Right - (128 * mapInfo.CameraBoundsComplements.Right)); + var top = JassLiteral.Real(mapEnvironment.Top - (128 * mapInfo.CameraBoundsComplements.Top)); + + var marginLeft = JassExpression.Invoke(NativeName.GetCameraMargin, CameraMarginName.Left); + var marginBottom = JassExpression.Invoke(NativeName.GetCameraMargin, CameraMarginName.Bottom); + var marginRight = JassExpression.Invoke(NativeName.GetCameraMargin, CameraMarginName.Right); + var marginTop = JassExpression.Invoke(NativeName.GetCameraMargin, CameraMarginName.Top); + + writer.WriteCall( NativeName.SetCameraBounds, - SyntaxFactory.BinaryAdditionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Left + (128 * mapInfo.CameraBoundsComplements.Left), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Left))), - SyntaxFactory.BinaryAdditionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Bottom + (128 * mapInfo.CameraBoundsComplements.Bottom), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Bottom))), - SyntaxFactory.BinarySubtractionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Right - (128 * mapInfo.CameraBoundsComplements.Right), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Right))), - SyntaxFactory.BinarySubtractionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Top - (128 * mapInfo.CameraBoundsComplements.Top), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Top))), - SyntaxFactory.BinaryAdditionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Left + (128 * mapInfo.CameraBoundsComplements.Left), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Left))), - SyntaxFactory.BinarySubtractionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Top - (128 * mapInfo.CameraBoundsComplements.Top), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Top))), - SyntaxFactory.BinarySubtractionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Right - (128 * mapInfo.CameraBoundsComplements.Right), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Right))), - SyntaxFactory.BinaryAdditionExpression( - SyntaxFactory.LiteralExpression(mapEnvironment.Bottom + (128 * mapInfo.CameraBoundsComplements.Bottom), precision: 1), - SyntaxFactory.InvocationExpression(NativeName.GetCameraMargin, SyntaxFactory.VariableReferenceExpression(CameraMarginName.Bottom))))); + JassExpression.Add(left, marginLeft), + JassExpression.Add(bottom, marginBottom), + JassExpression.Subtract(right, marginRight), + JassExpression.Subtract(top, marginTop), + JassExpression.Add(left, marginLeft), + JassExpression.Subtract(top, marginTop), + JassExpression.Subtract(right, marginRight), + JassExpression.Add(bottom, marginBottom)); } - if (SetDayNightModelsCondition(map)) + if (ShouldCallSetDayNightModels(map)) { var lightEnvironment = mapInfo.LightEnvironment == Tileset.Unspecified ? mapInfo.Tileset : mapInfo.LightEnvironment; - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetDayNightModels, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(LightEnvironmentProvider.GetTerrainLightEnvironmentModel(lightEnvironment))), - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(LightEnvironmentProvider.GetUnitLightEnvironmentModel(lightEnvironment))))); + JassLiteral.String(LightEnvironmentProvider.GetTerrainLightEnvironmentModel(lightEnvironment)), + JassLiteral.String(LightEnvironmentProvider.GetUnitLightEnvironmentModel(lightEnvironment))); } - if (SetTerrainFogExCondition(map)) + if (ShouldCallSetTerrainFogEx(map)) { var precision = mapInfo.FormatVersion >= MapInfoFormatVersion.v31 ? 3 : 1; - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetTerrainFogEx, - SyntaxFactory.LiteralExpression((int)mapInfo.FogStyle), - SyntaxFactory.LiteralExpression(mapInfo.FogStartZ), - SyntaxFactory.LiteralExpression(mapInfo.FogEndZ), - SyntaxFactory.LiteralExpression(mapInfo.FogDensity, precision), - SyntaxFactory.LiteralExpression(mapInfo.FogColor.R / 255f, precision), - SyntaxFactory.LiteralExpression(mapInfo.FogColor.G / 255f, precision), - SyntaxFactory.LiteralExpression(mapInfo.FogColor.B / 255f, precision))); + JassLiteral.Int((int)mapInfo.FogStyle), + JassLiteral.Real(mapInfo.FogStartZ), + JassLiteral.Real(mapInfo.FogEndZ), + JassLiteral.Real(mapInfo.FogDensity, precision), + JassLiteral.Real(mapInfo.FogColor.R / 255f, precision), + JassLiteral.Real(mapInfo.FogColor.G / 255f, precision), + JassLiteral.Real(mapInfo.FogColor.B / 255f, precision)); } - if (SetWaterBaseColorCondition(map)) + if (ShouldCallSetWaterBaseColor(map)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetWaterBaseColor, - SyntaxFactory.LiteralExpression(mapInfo.WaterTintingColor.R), - SyntaxFactory.LiteralExpression(mapInfo.WaterTintingColor.G), - SyntaxFactory.LiteralExpression(mapInfo.WaterTintingColor.B), - SyntaxFactory.LiteralExpression(mapInfo.WaterTintingColor.A))); + JassLiteral.Int(mapInfo.WaterTintingColor.R), + JassLiteral.Int(mapInfo.WaterTintingColor.G), + JassLiteral.Int(mapInfo.WaterTintingColor.B), + JassLiteral.Int(mapInfo.WaterTintingColor.A)); } - if (EnableGlobalWeatherEffectCondition(map)) + if (ShouldCallEnableGlobalWeatherEffect(map)) { - var createWeather = SyntaxFactory.InvocationExpression( - NativeName.AddWeatherEffect, - SyntaxFactory.InvocationExpression( - NativeName.Rect, - SyntaxFactory.LiteralExpression(mapEnvironment.Left, precision: 1), - SyntaxFactory.LiteralExpression(mapEnvironment.Bottom, precision: 1), - SyntaxFactory.LiteralExpression(mapEnvironment.Right, precision: 1), - SyntaxFactory.LiteralExpression(mapEnvironment.Top, precision: 1)), - SyntaxFactory.FourCCLiteralExpression((int)mapInfo.GlobalWeather)); + var weatherType = JassLiteral.FourCC((int)mapInfo.GlobalWeather); + var weatherRegion = JassExpression.InvokeCompact( + NativeName.Rect, + JassLiteral.Real(mapEnvironment.Left), + JassLiteral.Real(mapEnvironment.Bottom), + JassLiteral.Real(mapEnvironment.Right), + JassLiteral.Real(mapEnvironment.Top)); if (UseWeatherEffectVariable) { - statements.Add(SyntaxFactory.SetStatement(VariableName.WeatherEffect, createWeather)); - statements.Add(SyntaxFactory.CallStatement(NativeName.EnableWeatherEffect, SyntaxFactory.VariableReferenceExpression(VariableName.WeatherEffect), SyntaxFactory.LiteralExpression(true))); + writer.WriteSet( + VariableName.WeatherEffect, + JassExpression.InvokeSpaced( + NativeName.AddWeatherEffect, + weatherRegion, + weatherType)); + + writer.WriteCall( + NativeName.EnableWeatherEffect, + VariableName.WeatherEffect, + JassKeyword.True); } else { - statements.Add(SyntaxFactory.CallStatement(NativeName.EnableWeatherEffect, createWeather, SyntaxFactory.LiteralExpression(true))); + writer.WriteCall( + NativeName.EnableWeatherEffect, + JassExpression.Invoke( + NativeName.AddWeatherEffect, + weatherRegion, + weatherType), + JassKeyword.True); } } - if (NewSoundEnvironmentCondition(map)) + if (ShouldCallNewSoundEnvironment(map)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.NewSoundEnvironment, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(string.IsNullOrEmpty(mapInfo.SoundEnvironment) ? "Default" : mapInfo.SoundEnvironment)))); + JassLiteral.String(string.IsNullOrEmpty(mapInfo.SoundEnvironment) ? "Default" : mapInfo.SoundEnvironment)); } - if (SetAmbientSoundCondition(map)) + if (ShouldCallSetAmbientSound(map)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.SetAmbientDaySound, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(SoundEnvironmentProvider.GetAmbientDaySound(mapInfo.Tileset))))); + JassLiteral.String(SoundEnvironmentProvider.GetAmbientDaySound(mapInfo.Tileset))); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.SetAmbientNightSound, - SyntaxFactory.LiteralExpression(EscapedStringProvider.GetEscapedString(SoundEnvironmentProvider.GetAmbientNightSound(mapInfo.Tileset))))); + JassLiteral.String(SoundEnvironmentProvider.GetAmbientNightSound(mapInfo.Tileset))); } - if (SetMapMusicCondition(map)) + if (ShouldCallSetMapMusic(map)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetMapMusic, - SyntaxFactory.LiteralExpression("Music"), - SyntaxFactory.LiteralExpression(true), - SyntaxFactory.LiteralExpression(0))); + JassLiteral.String("Music"), + JassKeyword.True, + "0"); } - if (InitSoundsCondition(map)) + if (ShouldGenerateInitSounds(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitSounds))); + writer.WriteCall(GeneratedFunctionName.InitSounds); } - if (CreateRegionsCondition(map)) + if (ShouldGenerateCreateRegions(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateRegions))); + writer.WriteCall(GeneratedFunctionName.CreateRegions); } - if (CreateCamerasCondition(map)) + if (ShouldGenerateCreateCameras(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateCameras))); + writer.WriteCall(GeneratedFunctionName.CreateCameras); } - if (InitUpgradesCondition(map)) + if (ShouldGenerateInitUpgrades(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitUpgrades))); + writer.WriteCall(GeneratedFunctionName.InitUpgrades); } - if (InitTechTreeCondition(map)) + if (ShouldGenerateInitTechTree(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitTechTree))); + writer.WriteCall(GeneratedFunctionName.InitTechTree); } - if (CreateAllDestructablesCondition(map)) + if (ShouldGenerateCreateAllDestructables(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateAllDestructables))); + writer.WriteCall(GeneratedFunctionName.CreateAllDestructables); } - if (CreateAllItemsCondition(map)) + if (ShouldGenerateCreateAllItems(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateAllItems))); + writer.WriteCall(GeneratedFunctionName.CreateAllItems); } - if (InitRandomGroupsCondition(map)) + if (ShouldGenerateInitRandomGroups(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitRandomGroups))); + writer.WriteCall(GeneratedFunctionName.InitRandomGroups); } - if (CreateAllUnitsCondition(map)) + if (ShouldGenerateCreateAllUnits(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateAllUnits))); + writer.WriteCall(GeneratedFunctionName.CreateAllUnits); } else { - if (CreateNeutralUnitsCondition(map)) + if (ShouldGenerateCreateNeutralUnits(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateNeutralUnits))); + writer.WriteCall(GeneratedFunctionName.CreateNeutralUnits); } - if (CreatePlayerUnitsCondition(map)) + if (ShouldGenerateCreatePlayerUnits(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreatePlayerUnits))); + writer.WriteCall(GeneratedFunctionName.CreatePlayerUnits); } } - if (InitBlizzardCondition(map)) + if (ShouldCallInitBlizzard(map)) { - statements.Add(SyntaxFactory.CallStatement(FunctionName.InitBlizzard)); + writer.WriteCall(FunctionName.InitBlizzard); } - if (InitGlobalsCondition(map)) + if (ShouldGenerateInitGlobals(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitGlobals))); + writer.WriteCall(GeneratedFunctionName.InitGlobals); } - if (InitCustomTriggersCondition(map)) + if (ShouldGenerateInitCustomTriggers(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitCustomTriggers))); + writer.WriteCall(GeneratedFunctionName.InitCustomTriggers); } - if (RunInitializationTriggersCondition(map)) + if (ShouldGenerateRunInitializationTriggers(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(RunInitializationTriggers))); + writer.WriteCall(GeneratedFunctionName.RunInitializationTriggers); } if (UseCSharpLua) { - statements.Add(SyntaxFactory.CallStatement(CSharpLua.LuaSyntaxGenerator.kManifestFuncName)); + writer.WriteCall(CSharpLua.LuaSyntaxGenerator.kManifestFuncName); } - statements.Add(JassEmptySyntax.Value); + writer.WriteLine(); - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(main)), statements); + writer.EndFunction(); } - protected internal virtual bool mainCondition(Map map) + protected internal virtual bool ShouldGenerateMain(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Common/NativeConditions.cs b/src/War3Net.Build/MapScriptBuilder/Common/NativeConditions.cs index eaae347e..cf3e9a04 100644 --- a/src/War3Net.Build/MapScriptBuilder/Common/NativeConditions.cs +++ b/src/War3Net.Build/MapScriptBuilder/Common/NativeConditions.cs @@ -14,7 +14,7 @@ namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual bool SetDayNightModelsCondition(Map map) + protected internal virtual bool ShouldCallSetDayNightModels(Map map) { if (map is null) { @@ -25,7 +25,7 @@ protected internal virtual bool SetDayNightModelsCondition(Map map) && map.Info.FormatVersion >= MapInfoFormatVersion.v15; } - protected internal virtual bool SetTerrainFogExCondition(Map map) + protected internal virtual bool ShouldCallSetTerrainFogEx(Map map) { if (map is null) { @@ -36,7 +36,7 @@ protected internal virtual bool SetTerrainFogExCondition(Map map) && map.Info.MapFlags.HasFlag(MapFlags.HasTerrainFog); } - protected internal virtual bool SetWaterBaseColorCondition(Map map) + protected internal virtual bool ShouldCallSetWaterBaseColor(Map map) { if (map is null) { @@ -47,7 +47,7 @@ protected internal virtual bool SetWaterBaseColorCondition(Map map) && map.Info.MapFlags.HasFlag(MapFlags.HasWaterTintingColor); } - protected internal virtual bool EnableGlobalWeatherEffectCondition(Map map) + protected internal virtual bool ShouldCallEnableGlobalWeatherEffect(Map map) { if (map is null) { @@ -58,7 +58,7 @@ protected internal virtual bool EnableGlobalWeatherEffectCondition(Map map) && map.Info.GlobalWeather != WeatherType.None; } - protected internal virtual bool NewSoundEnvironmentCondition(Map map) + protected internal virtual bool ShouldCallNewSoundEnvironment(Map map) { if (map is null) { @@ -69,7 +69,7 @@ protected internal virtual bool NewSoundEnvironmentCondition(Map map) && map.Info.FormatVersion > MapInfoFormatVersion.v15; } - protected internal virtual bool SetAmbientSoundCondition(Map map) + protected internal virtual bool ShouldCallSetAmbientSound(Map map) { if (map is null) { @@ -80,7 +80,7 @@ protected internal virtual bool SetAmbientSoundCondition(Map map) && map.Info.FormatVersion >= MapInfoFormatVersion.v15; } - protected internal virtual bool SetMapMusicCondition(Map map) + protected internal virtual bool ShouldCallSetMapMusic(Map map) { if (map is null) { @@ -91,7 +91,7 @@ protected internal virtual bool SetMapMusicCondition(Map map) && map.Info.FormatVersion >= MapInfoFormatVersion.v15; } - protected internal virtual bool InitBlizzardCondition(Map map) + protected internal virtual bool ShouldCallInitBlizzard(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Constants/GeneratedFunctionName.cs b/src/War3Net.Build/MapScriptBuilder/Constants/GeneratedFunctionName.cs new file mode 100644 index 00000000..01f5e759 --- /dev/null +++ b/src/War3Net.Build/MapScriptBuilder/Constants/GeneratedFunctionName.cs @@ -0,0 +1,48 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.Build +{ + public partial class MapScriptBuilder + { + internal static class GeneratedFunctionName + { + internal const string Config = "config"; + internal const string CreateAllDestructables = "CreateAllDestructables"; + internal const string CreateAllItems = "CreateAllItems"; + internal const string CreateAllUnits = "CreateAllUnits"; + internal const string CreateCameras = "CreateCameras"; + internal const string CreateNeutralHostile = "CreateNeutralHostile"; + internal const string CreateNeutralHostileBuildings = "CreateNeutralHostileBuildings"; + internal const string CreateNeutralPassive = "CreateNeutralPassive"; + internal const string CreateNeutralPassiveBuildings = "CreateNeutralPassiveBuildings"; + internal const string CreateNeutralUnits = "CreateNeutralUnits"; + internal const string CreatePlayerBuildings = "CreatePlayerBuildings"; + internal const string CreatePlayerUnits = "CreatePlayerUnits"; + internal const string CreateRegions = "CreateRegions"; + internal const string InitAllyPriorities = "InitAllyPriorities"; + internal const string InitCustomPlayerSlots = "InitCustomPlayerSlots"; + internal const string InitCustomTeams = "InitCustomTeams"; + internal const string InitCustomTriggers = "InitCustomTriggers"; + internal const string InitGlobals = "InitGlobals"; + internal const string InitRandomGroups = "InitRandomGroups"; + internal const string InitSounds = "InitSounds"; + internal const string InitTechTree = "InitTechTree"; + internal const string InitUpgrades = "InitUpgrades"; + internal const string Main = "main"; + internal const string RunInitializationTriggers = "RunInitializationTriggers"; + + internal static string CreateBuildingsForPlayer(int playerId) => $"CreateBuildingsForPlayer{playerId}"; + + internal static string CreateUnitsForPlayer(int playerId) => $"CreateUnitsForPlayer{playerId}"; + + internal static string InitTechTreeForPlayer(int playerId) => $"InitTechTree_Player{playerId}"; + + internal static string InitUpgradesForPlayer(int playerId) => $"InitUpgrades_Player{playerId}"; + } + } +} \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Constants/Math.cs b/src/War3Net.Build/MapScriptBuilder/Constants/Math.cs new file mode 100644 index 00000000..f68acfd0 --- /dev/null +++ b/src/War3Net.Build/MapScriptBuilder/Constants/Math.cs @@ -0,0 +1,17 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.Build +{ + public partial class MapScriptBuilder + { + private static class Math + { + internal const float Rad2Deg = 180f / 3.141593f; + } + } +} \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Constants/NativeName.cs b/src/War3Net.Build/MapScriptBuilder/Constants/NativeName.cs index 0e3132a5..c4673c0f 100644 --- a/src/War3Net.Build/MapScriptBuilder/Constants/NativeName.cs +++ b/src/War3Net.Build/MapScriptBuilder/Constants/NativeName.cs @@ -9,7 +9,7 @@ namespace War3Net.Build { public partial class MapScriptBuilder { - private class NativeName + internal static class NativeName { internal const string AddWeatherEffect = "AddWeatherEffect"; internal const string BlzCreateDeadDestructableWithSkin = "BlzCreateDeadDestructableWithSkin"; diff --git a/src/War3Net.Build/MapScriptBuilder/Environment/Cameras.cs b/src/War3Net.Build/MapScriptBuilder/Environment/Cameras.cs index 0ae97527..edba2b86 100644 --- a/src/War3Net.Build/MapScriptBuilder/Environment/Cameras.cs +++ b/src/War3Net.Build/MapScriptBuilder/Environment/Cameras.cs @@ -6,51 +6,52 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.Build.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - public virtual IEnumerable CamerasApi(Map map, JassToCSharpTranspiler transpiler) + protected internal virtual void GenerateCameraVariables(Map map, IndentedTextWriter writer) { - if (transpiler is null) + if (map is null) { - throw new ArgumentNullException(nameof(transpiler)); + throw new ArgumentNullException(nameof(map)); } - return Cameras(map).Select(camera => transpiler.Transpile(camera)); - } - - protected internal virtual IEnumerable Cameras(Map map) - { - if (map is null) + if (writer is null) { - throw new ArgumentNullException(nameof(map)); + throw new ArgumentNullException(nameof(writer)); } var mapCameras = map.Cameras; if (mapCameras is null) { - yield break; + return; } foreach (var camera in mapCameras.Cameras) { - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(TypeName.CameraSetup), + writer.WriteAlignedGlobal( + TypeName.CameraSetup, camera.GetVariableName(), - JassNullLiteralExpressionSyntax.Value); + JassKeyword.Null); } } + + protected internal virtual bool ShouldGenerateCameraVariables(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + return map.Cameras is not null + && map.Cameras.Cameras.Count > 0; + } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Environment/CreateCameras.cs b/src/War3Net.Build/MapScriptBuilder/Environment/CreateCameras.cs index 575d95e5..5f65d040 100644 --- a/src/War3Net.Build/MapScriptBuilder/Environment/CreateCameras.cs +++ b/src/War3Net.Build/MapScriptBuilder/Environment/CreateCameras.cs @@ -6,66 +6,67 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; using War3Net.Build.Environment; using War3Net.Build.Extensions; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateCameras(Map map) + protected internal virtual void GenerateCreateCameras(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapCameras = map.Cameras; if (mapCameras is null) { - throw new ArgumentException($"Function '{nameof(CreateCameras)}' cannot be generated without {nameof(MapCameras)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateCameras}' cannot be generated without {nameof(MapCameras)}.", nameof(map)); } - var statements = new List(); - statements.Add(JassEmptySyntax.Value); - - var zero = SyntaxFactory.LiteralExpression(0f); + writer.WriteFunction(GeneratedFunctionName.CreateCameras); + writer.WriteLine(); foreach (var camera in mapCameras.Cameras) { var cameraName = camera.GetVariableName(); - statements.Add(SyntaxFactory.SetStatement(cameraName, SyntaxFactory.InvocationExpression(NativeName.CreateCameraSetup))); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.ZOffset), SyntaxFactory.LiteralExpression(camera.ZOffset), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.Rotation), SyntaxFactory.LiteralExpression(camera.Rotation), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.AngleOfAttack), SyntaxFactory.LiteralExpression(camera.AngleOfAttack), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.TargetDistance), SyntaxFactory.LiteralExpression(camera.TargetDistance), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.Roll), SyntaxFactory.LiteralExpression(camera.Roll), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.FieldOfView), SyntaxFactory.LiteralExpression(camera.FieldOfView), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.FarZ), SyntaxFactory.LiteralExpression(camera.FarClippingPlane), zero)); + writer.WriteSet(cameraName, JassExpression.InvokeSpaced(NativeName.CreateCameraSetup)); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.ZOffset, JassLiteral.Real(camera.ZOffset), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.Rotation, JassLiteral.Real(camera.Rotation), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.AngleOfAttack, JassLiteral.Real(camera.AngleOfAttack), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.TargetDistance, JassLiteral.Real(camera.TargetDistance), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.Roll, JassLiteral.Real(camera.Roll), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.FieldOfView, JassLiteral.Real(camera.FieldOfView), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.FarZ, JassLiteral.Real(camera.FarClippingPlane), "0.0"); if (mapCameras.UseNewFormat) { - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.NearZ), SyntaxFactory.LiteralExpression(camera.NearClippingPlane), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.LocalPitch), SyntaxFactory.LiteralExpression(camera.LocalPitch), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.LocalYaw), SyntaxFactory.LiteralExpression(camera.LocalYaw), zero)); - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetField, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.VariableReferenceExpression(CameraFieldName.LocalRoll), SyntaxFactory.LiteralExpression(camera.LocalRoll), zero)); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.NearZ, JassLiteral.Real(camera.NearClippingPlane), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.LocalPitch, JassLiteral.Real(camera.LocalPitch), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.LocalYaw, JassLiteral.Real(camera.LocalYaw), "0.0"); + writer.WriteCall(NativeName.CameraSetupSetField, cameraName, CameraFieldName.LocalRoll, JassLiteral.Real(camera.LocalRoll), "0.0"); } - statements.Add(SyntaxFactory.CallStatement(NativeName.CameraSetupSetDestPosition, SyntaxFactory.VariableReferenceExpression(cameraName), SyntaxFactory.LiteralExpression(camera.TargetPosition.X), SyntaxFactory.LiteralExpression(camera.TargetPosition.Y), zero)); - statements.Add(JassEmptySyntax.Value); + writer.WriteCall(NativeName.CameraSetupSetDestPosition, cameraName, JassLiteral.Real(camera.TargetPosition.X), JassLiteral.Real(camera.TargetPosition.Y), "0.0"); + writer.WriteLine(); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreateCameras)), statements); + writer.EndFunction(); } - protected internal virtual bool CreateCamerasCondition(Map map) + protected internal virtual bool ShouldGenerateCreateCameras(Map map) { if (map is null) { @@ -78,7 +79,7 @@ protected internal virtual bool CreateCamerasCondition(Map map) } return map.Cameras is not null - && map.Cameras.Cameras.Any(); + && map.Cameras.Cameras.Count > 0; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Environment/CreateRegions.cs b/src/War3Net.Build/MapScriptBuilder/Environment/CreateRegions.cs index 554640f4..7d524895 100644 --- a/src/War3Net.Build/MapScriptBuilder/Environment/CreateRegions.cs +++ b/src/War3Net.Build/MapScriptBuilder/Environment/CreateRegions.cs @@ -6,105 +6,108 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; using War3Net.Build.Common; using War3Net.Build.Environment; using War3Net.Build.Extensions; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateRegions(Map map) + protected internal virtual void GenerateCreateRegions(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapRegions = map.Regions; if (mapRegions is null) { - throw new ArgumentException($"Function '{nameof(CreateRegions)}' cannot be generated without {nameof(MapRegions)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateRegions}' cannot be generated without {nameof(MapRegions)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.CreateRegions); if (UseWeatherEffectVariable) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.WeatherEffect), VariableName.WeatherEffect)); - statements.Add(JassEmptySyntax.Value); + writer.WriteLocal(TypeName.WeatherEffect, VariableName.WeatherEffect); + writer.WriteLine(); } foreach (var region in mapRegions.Regions) { var regionName = region.GetVariableName(); - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( regionName, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.Rect, - SyntaxFactory.LiteralExpression(region.Left, precision: 1), - SyntaxFactory.LiteralExpression(region.Bottom, precision: 1), - SyntaxFactory.LiteralExpression(region.Right, precision: 1), - SyntaxFactory.LiteralExpression(region.Top, precision: 1)))); + JassLiteral.Real(region.Left), + JassLiteral.Real(region.Bottom), + JassLiteral.Real(region.Right), + JassLiteral.Real(region.Top))); if (region.WeatherType != WeatherType.None) { if (UseWeatherEffectVariable) { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.WeatherEffect, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.AddWeatherEffect, - SyntaxFactory.VariableReferenceExpression(regionName), - SyntaxFactory.FourCCLiteralExpression((int)region.WeatherType)))); + regionName, + JassLiteral.FourCC((int)region.WeatherType))); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.EnableWeatherEffect, - SyntaxFactory.VariableReferenceExpression(VariableName.WeatherEffect), - JassBooleanLiteralExpressionSyntax.True)); + VariableName.WeatherEffect, + JassKeyword.True); } else { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.EnableWeatherEffect, - SyntaxFactory.InvocationExpression( + JassExpression.Invoke( NativeName.AddWeatherEffect, - SyntaxFactory.VariableReferenceExpression(regionName), - SyntaxFactory.FourCCLiteralExpression((int)region.WeatherType)), - JassBooleanLiteralExpressionSyntax.True)); + regionName, + JassLiteral.FourCC((int)region.WeatherType)), + JassKeyword.True); } } if (!string.IsNullOrEmpty(region.AmbientSound)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetSoundPosition, - SyntaxFactory.VariableReferenceExpression(region.AmbientSound), - SyntaxFactory.LiteralExpression(region.CenterX), - SyntaxFactory.LiteralExpression(region.CenterY), - SyntaxFactory.LiteralExpression(0f))); + region.AmbientSound, + JassLiteral.Real(region.CenterX), + JassLiteral.Real(region.CenterY), + "0.0"); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.RegisterStackedSound, - SyntaxFactory.VariableReferenceExpression(region.AmbientSound), - SyntaxFactory.LiteralExpression(true), - SyntaxFactory.LiteralExpression(region.Width), - SyntaxFactory.LiteralExpression(region.Height))); + region.AmbientSound, + JassKeyword.True, + JassLiteral.Real(region.Width), + JassLiteral.Real(region.Height)); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreateRegions)), statements); + writer.EndFunction(); } - protected internal virtual bool CreateRegionsCondition(Map map) + protected internal virtual bool ShouldGenerateCreateRegions(Map map) { if (map is null) { @@ -117,7 +120,7 @@ protected internal virtual bool CreateRegionsCondition(Map map) } return map.Regions is not null - && map.Regions.Regions.Any(); + && map.Regions.Regions.Count > 0; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Environment/Regions.cs b/src/War3Net.Build/MapScriptBuilder/Environment/Regions.cs index 5be30ea1..3b5df4f1 100644 --- a/src/War3Net.Build/MapScriptBuilder/Environment/Regions.cs +++ b/src/War3Net.Build/MapScriptBuilder/Environment/Regions.cs @@ -6,51 +6,52 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.Build.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - public virtual IEnumerable RegionsApi(Map map, JassToCSharpTranspiler transpiler) + protected internal virtual void GenerateRegionVariables(Map map, IndentedTextWriter writer) { - if (transpiler is null) + if (map is null) { - throw new ArgumentNullException(nameof(transpiler)); + throw new ArgumentNullException(nameof(map)); } - return Regions(map).Select(region => transpiler.Transpile(region)); - } - - protected internal virtual IEnumerable Regions(Map map) - { - if (map is null) + if (writer is null) { - throw new ArgumentNullException(nameof(map)); + throw new ArgumentNullException(nameof(writer)); } var mapRegions = map.Regions; if (mapRegions is null) { - yield break; + return; } foreach (var region in mapRegions.Regions) { - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(TypeName.Rect), + writer.WriteAlignedGlobal( + TypeName.Rect, region.GetVariableName(), - JassNullLiteralExpressionSyntax.Value); + JassKeyword.Null); } } + + protected internal virtual bool ShouldGenerateRegionVariables(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + return map.Regions is not null + && map.Regions.Regions.Count > 0; + } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitAllyPriorities.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitAllyPriorities.cs index 38ed4998..817ca312 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitAllyPriorities.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitAllyPriorities.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,55 +6,73 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitAllyPriorities(Map map) + protected internal virtual void GenerateInitAllyPriorities(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(InitAllyPriorities)}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitAllyPriorities}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitAllyPriorities); var playerDataCount = mapInfo.Players.Count; for (var i = 0; i < playerDataCount; i++) { var playerData = mapInfo.Players[i]; - var allyStartLocPrioStatements = new List(); - var enemyStartLocPrioStatements = new List(); - var allySlotIndex = 0; var enemySlotIndex = 0; + + writer.WriteLine(); + + var allyCountIndex = 0; + for (var j = 0; j < MaxPlayerSlots; j++) + { + if (playerData.AllyLowPriorityFlags[j] || playerData.AllyHighPriorityFlags[j]) + { + allyCountIndex++; + } + } + + writer.WriteCall( + NativeName.SetStartLocPrioCount, + JassLiteral.Int(i), + JassLiteral.Int(allyCountIndex)); + for (var j = 0; j < MaxPlayerSlots; j++) { var hasLowFlag = playerData.AllyLowPriorityFlags[j]; var hasHighFlag = playerData.AllyHighPriorityFlags[j]; if (hasLowFlag || hasHighFlag) { - allyStartLocPrioStatements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetStartLocPrio, - SyntaxFactory.LiteralExpression(i), - SyntaxFactory.LiteralExpression(allySlotIndex++), - SyntaxFactory.LiteralExpression(j), - SyntaxFactory.VariableReferenceExpression(hasHighFlag ? StartLocPrioName.High : StartLocPrioName.Low))); + JassLiteral.Int(i), + JassLiteral.Int(allySlotIndex++), + JassLiteral.Int(j), + hasHighFlag ? StartLocPrioName.High : StartLocPrioName.Low); } if (mapInfo.FormatVersion >= MapInfoFormatVersion.v31) @@ -63,42 +81,40 @@ protected internal virtual JassFunctionDeclarationSyntax InitAllyPriorities(Map hasHighFlag = playerData.EnemyHighPriorityFlags[j]; if (hasLowFlag || hasHighFlag) { - enemyStartLocPrioStatements.Add(SyntaxFactory.CallStatement( + if (enemySlotIndex == 0) + { + writer.WriteLine(); + + var enemyCountIndex = 0; + for (var k = 0; k < MaxPlayerSlots; k++) + { + if (playerData.EnemyLowPriorityFlags[k] || playerData.EnemyHighPriorityFlags[k]) + { + enemyCountIndex++; + } + } + + writer.WriteCall( + NativeName.SetEnemyStartLocPrioCount, + JassLiteral.Int(i), + JassLiteral.Int(enemyCountIndex)); + } + + writer.WriteCall( NativeName.SetEnemyStartLocPrio, - SyntaxFactory.LiteralExpression(i), - SyntaxFactory.LiteralExpression(enemySlotIndex++), - SyntaxFactory.LiteralExpression(j), - SyntaxFactory.VariableReferenceExpression(hasHighFlag ? StartLocPrioName.High : StartLocPrioName.Low))); + JassLiteral.Int(i), + JassLiteral.Int(enemySlotIndex++), + JassLiteral.Int(j), + hasHighFlag ? StartLocPrioName.High : StartLocPrioName.Low); } } } - - statements.Add(JassEmptySyntax.Value); - - statements.Add(SyntaxFactory.CallStatement( - NativeName.SetStartLocPrioCount, - SyntaxFactory.LiteralExpression(i), - SyntaxFactory.LiteralExpression(allySlotIndex))); - - statements.AddRange(allyStartLocPrioStatements); - - if (enemyStartLocPrioStatements.Count > 0) - { - statements.Add(JassEmptySyntax.Value); - - statements.Add(SyntaxFactory.CallStatement( - NativeName.SetEnemyStartLocPrioCount, - SyntaxFactory.LiteralExpression(i), - SyntaxFactory.LiteralExpression(enemySlotIndex))); - - statements.AddRange(enemyStartLocPrioStatements); - } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitAllyPriorities)), statements); + writer.EndFunction(); } - protected internal virtual bool InitAllyPrioritiesCondition(Map map) + protected internal virtual bool ShouldGenerateInitAllyPriorities(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitCustomPlayerSlots.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitCustomPlayerSlots.cs index 986e939e..9ce95686 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitCustomPlayerSlots.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitCustomPlayerSlots.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,32 +6,36 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using War3Net.Build.Extensions; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitCustomPlayerSlots(Map map) + protected internal virtual void GenerateInitCustomPlayerSlots(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(InitCustomPlayerSlots)}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitCustomPlayerSlots}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitCustomPlayerSlots); var playerDataCount = mapInfo.Players.Count; @@ -39,41 +43,44 @@ protected internal virtual JassFunctionDeclarationSyntax InitCustomPlayerSlots(M { var playerData = mapInfo.Players[i]; - statements.Add(JassEmptySyntax.Value); - statements.Add(new JassCommentSyntax($" Player {playerData.Id}")); + writer.WriteLine(); + writer.WriteComment($"Player {playerData.Id}"); + + var playerExpr = JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerData.Id)); + var playerColor = JassExpression.Invoke(NativeName.ConvertPlayerColor, JassLiteral.Int(playerData.Id)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerStartLocation, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.LiteralExpression(i))); + playerExpr, + JassLiteral.Int(i)); if (playerData.Flags.HasFlag(PlayerFlags.FixedStartPosition)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.ForcePlayerStartLocation, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.LiteralExpression(i))); + playerExpr, + JassLiteral.Int(i)); } - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerColor, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.InvocationExpression(NativeName.ConvertPlayerColor, SyntaxFactory.LiteralExpression(playerData.Id)))); + playerExpr, + playerColor); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerRacePreference, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.VariableReferenceExpression(playerData.Race.GetVariableName()))); + playerExpr, + playerData.Race.GetVariableName()); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerRaceSelectable, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.LiteralExpression(playerData.Flags.HasFlag(PlayerFlags.RaceSelectable) || !mapInfo.MapFlags.HasFlag(MapFlags.FixedPlayerSettingsForCustomForces)))); + playerExpr, + JassLiteral.Bool(playerData.Flags.HasFlag(PlayerFlags.RaceSelectable) || !mapInfo.MapFlags.HasFlag(MapFlags.FixedPlayerSettingsForCustomForces))); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerController, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.VariableReferenceExpression(playerData.Controller.GetVariableName()))); + playerExpr, + playerData.Controller.GetVariableName()); if (playerData.Controller == PlayerController.Rescuable) { @@ -82,23 +89,23 @@ protected internal virtual JassFunctionDeclarationSyntax InitCustomPlayerSlots(M var otherPlayerData = mapInfo.Players[j]; if (otherPlayerData.Controller == PlayerController.User) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerAlliance, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerData.Id)), - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(otherPlayerData.Id)), - SyntaxFactory.VariableReferenceExpression(AllianceTypeName.Rescuable), - SyntaxFactory.LiteralExpression(true))); + playerExpr, + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(otherPlayerData.Id)), + AllianceTypeName.Rescuable, + JassKeyword.True); } } } } - statements.Add(JassEmptySyntax.Value); + writer.WriteLine(); - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitCustomPlayerSlots)), statements); + writer.EndFunction(); } - protected internal virtual bool InitCustomPlayerSlotsCondition(Map map) + protected internal virtual bool ShouldGenerateInitCustomPlayerSlots(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitCustomTeams.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitCustomTeams.cs index ce91d1a5..9eda1eb1 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitCustomTeams.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitCustomTeams.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,32 +6,36 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitCustomTeams(Map map) + protected internal virtual void GenerateInitCustomTeams(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(InitCustomTeams)}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitCustomTeams}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitCustomTeams); var forceDataCount = mapInfo.Forces.Count; var useBlizzardAllianceFunctions = mapInfo.FormatVersion > MapInfoFormatVersion.v15; @@ -45,28 +49,30 @@ protected internal virtual JassFunctionDeclarationSyntax InitCustomTeams(Map map .Select(player => player.Id) .ToList(); - if (!playerSlots.Any()) + if (playerSlots.Count == 0) { continue; } - statements.Add(new JassCommentSyntax($" Force: {forceData.Name}")); + writer.WriteComment($"Force: {forceData.Name}"); var alliedVictory = forceData.Flags.HasFlag(ForceFlags.AlliedVictory); foreach (var playerSlot in playerSlots) { - statements.Add(SyntaxFactory.CallStatement( + var playerExpr = JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerSlot)); + + writer.WriteCall( NativeName.SetPlayerTeam, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerSlot)), - SyntaxFactory.LiteralExpression(i))); + playerExpr, + JassLiteral.Int(i)); if (alliedVictory) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerState, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerSlot)), - SyntaxFactory.VariableReferenceExpression(PlayerStateName.AlliedVictory), - SyntaxFactory.LiteralExpression(1))); + playerExpr, + PlayerStateName.AlliedVictory, + "1"); } } @@ -74,15 +80,15 @@ protected internal virtual JassFunctionDeclarationSyntax InitCustomTeams(Map map if (useBlizzardAllianceFunctions) { - void AddSetAllianceStateStatement(string statementName) + void WriteSetAllianceStateStatement(string statementName) { foreach (var (playerSlot1, playerSlot2) in playerSlotPairs) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( statementName, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerSlot1)), - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerSlot2)), - SyntaxFactory.LiteralExpression(true))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerSlot1)), + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerSlot2)), + JassKeyword.True); } } @@ -90,74 +96,74 @@ void AddSetAllianceStateStatement(string statementName) { if (mapInfo.FormatVersion >= MapInfoFormatVersion.v31) { - statements.Add(JassEmptySyntax.Value); - statements.Add(new JassCommentSyntax(" Allied")); + writer.WriteLine(); + writer.WriteComment(" Allied"); } - AddSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateAllyBJ); + WriteSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateAllyBJ); } if (forceData.Flags.HasFlag(ForceFlags.ShareVision)) { - AddSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateVisionBJ); + WriteSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateVisionBJ); } if (forceData.Flags.HasFlag(ForceFlags.ShareUnitControl)) { - AddSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateControlBJ); + WriteSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateControlBJ); } if (forceData.Flags.HasFlag(ForceFlags.ShareAdvancedUnitControl)) { - AddSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateFullControlBJ); + WriteSetAllianceStateStatement(FunctionName.SetPlayerAllianceStateFullControlBJ); } } else { - void AddSetAllianceStateStatement(string variableName, string comment) + void WriteSetAllianceStateStatement(string variableName, string comment) { - statements.Add(JassEmptySyntax.Value); - statements.Add(new JassCommentSyntax(comment)); + writer.WriteLine(); + writer.WriteComment(comment); foreach (var (playerSlot1, playerSlot2) in playerSlotPairs) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerAlliance, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerSlot1)), - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerSlot2)), - SyntaxFactory.VariableReferenceExpression(variableName), - SyntaxFactory.LiteralExpression(true))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerSlot1)), + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerSlot2)), + variableName, + JassKeyword.True); } } if (forceData.Flags.HasFlag(ForceFlags.Allied)) { - AddSetAllianceStateStatement(AllianceTypeName.Passive, " Allied"); + WriteSetAllianceStateStatement(AllianceTypeName.Passive, " Allied"); } if (forceData.Flags.HasFlag(ForceFlags.ShareVision)) { - AddSetAllianceStateStatement(AllianceTypeName.SharedVision, " Shared Vision"); + WriteSetAllianceStateStatement(AllianceTypeName.SharedVision, " Shared Vision"); } if (forceData.Flags.HasFlag(ForceFlags.ShareUnitControl)) { - AddSetAllianceStateStatement(AllianceTypeName.SharedControl, " Shared Control"); + WriteSetAllianceStateStatement(AllianceTypeName.SharedControl, " Shared Control"); } if (forceData.Flags.HasFlag(ForceFlags.ShareAdvancedUnitControl)) { - AddSetAllianceStateStatement(AllianceTypeName.SharedAdvancedControl, " Advanced Control"); + WriteSetAllianceStateStatement(AllianceTypeName.SharedAdvancedControl, " Advanced Control"); } } - statements.Add(JassEmptySyntax.Value); + writer.WriteLine(); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitCustomTeams)), statements); + writer.EndFunction(); } - protected internal virtual bool InitCustomTeamsCondition(Map map) + protected internal virtual bool ShouldGenerateInitCustomTeams(Map map) { if (map is null) { @@ -167,7 +173,7 @@ protected internal virtual bool InitCustomTeamsCondition(Map map) return map.Info is not null; } - protected internal virtual bool InitCustomTeamsInvokeCondition(Map map) + protected internal virtual bool ShouldCallInitCustomTeams(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitRandomGroups.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitRandomGroups.cs index 0e321765..dc10e166 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitRandomGroups.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitRandomGroups.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,101 +6,105 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Providers; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitRandomGroups(Map map) + protected internal virtual void GenerateInitRandomGroups(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var randomUnitTables = map.Info?.RandomUnitTables; if (randomUnitTables is null) { - throw new ArgumentException($"Function '{nameof(InitRandomGroups)}' cannot be generated without {nameof(MapInfo.RandomUnitTables)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitRandomGroups}' cannot be generated without {nameof(MapInfo.RandomUnitTables)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitRandomGroups); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Integer, VariableName.CurrentSet)); - statements.Add(JassEmptySyntax.Value); + writer.WriteLocal(JassKeyword.Integer, VariableName.CurrentSet); + writer.WriteLine(); foreach (var unitTable in randomUnitTables) { - statements.Add(new JassCommentSyntax($" Group {unitTable.Index} - {unitTable.Name}")); - statements.Add(SyntaxFactory.CallStatement(FunctionName.RandomDistReset)); + writer.WriteComment($"Group {unitTable.Index} - {unitTable.Name}"); + writer.WriteCall(FunctionName.RandomDistReset); for (var i = 0; i < unitTable.UnitSets.Count; i++) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.RandomDistAddItem, - SyntaxFactory.LiteralExpression(i), - SyntaxFactory.LiteralExpression(unitTable.UnitSets[i].Chance))); + JassLiteral.Int(i), + JassLiteral.Int(unitTable.UnitSets[i].Chance)); } - statements.Add(SyntaxFactory.SetStatement(VariableName.CurrentSet, SyntaxFactory.InvocationExpression(FunctionName.RandomDistChoose))); - statements.Add(JassEmptySyntax.Value); + writer.WriteSet(VariableName.CurrentSet, JassExpression.Invoke(FunctionName.RandomDistChoose)); + writer.WriteLine(); var groupVarName = unitTable.GetVariableName(); - var ifElseifBlocks = new List<(IExpressionSyntax Condition, IStatementSyntax[] Body)>(); for (var setIndex = 0; setIndex < unitTable.UnitSets.Count; setIndex++) { var set = unitTable.UnitSets[setIndex]; - var condition = SyntaxFactory.BinaryEqualsExpression(SyntaxFactory.VariableReferenceExpression(VariableName.CurrentSet), SyntaxFactory.LiteralExpression(setIndex)); - var bodyStatements = new List(); + var condition = JassExpression.ParenthesizedCompact(JassExpression.EqualCompact( + VariableName.CurrentSet, + JassLiteral.Int(setIndex))); + + if (setIndex == 0) + { + writer.WriteIf(condition); + } + else + { + writer.WriteElseIf(condition); + } for (var position = 0; position < unitTable.Types.Count; position++) { var id = set?.UnitIds[position] ?? 0; var unitTypeExpression = RandomUnitProvider.IsRandomUnit(id, out var level) - ? SyntaxFactory.InvocationExpression(NativeName.ChooseRandomCreep, SyntaxFactory.LiteralExpression(level)) - : id == 0 ? SyntaxFactory.LiteralExpression(-1) : SyntaxFactory.FourCCLiteralExpression(id); + ? JassExpression.Invoke(NativeName.ChooseRandomCreep, JassLiteral.Int(level)) + : id == 0 ? "-1" : JassLiteral.FourCC(id); - bodyStatements.Add(SyntaxFactory.SetStatement( - groupVarName, - SyntaxFactory.LiteralExpression(position), - unitTypeExpression)); + writer.WriteSet( + JassExpression.ElementAccess(groupVarName, position), + unitTypeExpression); } - - ifElseifBlocks.Add((new JassParenthesizedExpressionSyntax(condition), bodyStatements.ToArray())); } - var elseClauseStatements = new List(); + writer.WriteElse(); + for (var position = 0; position < unitTable.Types.Count; position++) { - elseClauseStatements.Add(SyntaxFactory.SetStatement( - groupVarName, - SyntaxFactory.LiteralExpression(position), - SyntaxFactory.LiteralExpression(-1))); + writer.WriteSet( + JassExpression.ElementAccess(groupVarName, position), + "-1"); } - statements.Add(SyntaxFactory.IfStatement( - ifElseifBlocks.First().Condition, - SyntaxFactory.StatementList(ifElseifBlocks.First().Body), - ifElseifBlocks.Skip(1).Select(elseIf => new JassElseIfClauseSyntax(elseIf.Condition, SyntaxFactory.StatementList(elseIf.Body))), - new JassElseClauseSyntax(SyntaxFactory.StatementList(elseClauseStatements)))); - - statements.Add(JassEmptySyntax.Value); + writer.WriteEndIf(); + writer.WriteLine(); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitRandomGroups)), statements); + writer.EndFunction(); } - protected internal virtual bool InitRandomGroupsCondition(Map map) + protected internal virtual bool ShouldGenerateInitRandomGroups(Map map) { if (map is null) { @@ -108,7 +112,7 @@ protected internal virtual bool InitRandomGroupsCondition(Map map) } return map.Info?.RandomUnitTables is not null - && map.Info.RandomUnitTables.Any(); + && map.Info.RandomUnitTables.Count > 0; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitTechTree.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitTechTree.cs index 855fb618..8adc4f75 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitTechTree.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitTechTree.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,38 +6,41 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitTechTree(Map map) + protected internal virtual void GenerateInitTechTree(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteFunction(GeneratedFunctionName.InitTechTree); for (var i = 0; i < MaxPlayerSlots; i++) { - if (InitTechTree_PlayerCondition(map, i)) + if (ShouldGenerateInitTechTreeForPlayer(map, i)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitTechTree_Player) + i)); + writer.WriteCall(GeneratedFunctionName.InitTechTreeForPlayer(i)); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitTechTree)), statements); + writer.EndFunction(); } - protected internal virtual bool InitTechTreeCondition(Map map) + protected internal virtual bool ShouldGenerateInitTechTree(Map map) { if (map is null) { @@ -45,7 +48,7 @@ protected internal virtual bool InitTechTreeCondition(Map map) } return map.Info is not null - && map.Info.TechData.Any(); + && map.Info.TechData.Count > 0; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitTechTreeForPlayer.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitTechTreeForPlayer.cs index 2de2ec00..2eb583e2 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitTechTreeForPlayer.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitTechTreeForPlayer.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,33 +6,39 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.Common.Extensions; -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; - namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitTechTree_Player(Map map, int playerId) + protected internal virtual void GenerateInitTechTreeForPlayer(Map map, int playerId, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var functionName = GeneratedFunctionName.InitTechTreeForPlayer(playerId); + var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(InitTechTree_Player) + playerId}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{functionName}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(functionName); foreach (var techData in mapInfo.TechData) { @@ -40,27 +46,27 @@ protected internal virtual JassFunctionDeclarationSyntax InitTechTree_Player(Map { if (techData.Id.ToRawcode()[0] == 'A') { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerAbilityAvailable, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerId)), - SyntaxFactory.FourCCLiteralExpression(techData.Id), - SyntaxFactory.LiteralExpression(false))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerId)), + JassLiteral.FourCC(techData.Id), + JassKeyword.False); } else { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerTechMaxAllowed, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerId)), - SyntaxFactory.FourCCLiteralExpression(techData.Id), - SyntaxFactory.LiteralExpression(0))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerId)), + JassLiteral.FourCC(techData.Id), + JassLiteral.Int(0)); } } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitTechTree_Player) + playerId), statements); + writer.EndFunction(); } - protected internal virtual bool InitTechTree_PlayerCondition(Map map, int playerId) + protected internal virtual bool ShouldGenerateInitTechTreeForPlayer(Map map, int playerId) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitUpgrades.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitUpgrades.cs index 66dbc61c..f68f0556 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitUpgrades.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitUpgrades.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,38 +6,40 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; - -using War3Net.CodeAnalysis.Jass.Syntax; -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitUpgrades(Map map) + protected internal virtual void GenerateInitUpgrades(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteFunction(GeneratedFunctionName.InitUpgrades); for (var i = 0; i < MaxPlayerSlots; i++) { - if (InitUpgrades_PlayerCondition(map, i)) + if (ShouldGenerateInitUpgradesForPlayer(map, i)) { - statements.Add(SyntaxFactory.CallStatement(nameof(InitUpgrades_Player) + i)); + writer.WriteCall(GeneratedFunctionName.InitUpgradesForPlayer(i)); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitUpgrades)), statements); + writer.EndFunction(); } - protected internal virtual bool InitUpgradesCondition(Map map) + protected internal virtual bool ShouldGenerateInitUpgrades(Map map) { if (map is null) { @@ -45,7 +47,7 @@ protected internal virtual bool InitUpgradesCondition(Map map) } return map.Info is not null - && map.Info.UpgradeData.Any(); + && map.Info.UpgradeData.Count > 0; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Info/InitUpgradesForPlayer.cs b/src/War3Net.Build/MapScriptBuilder/Info/InitUpgradesForPlayer.cs index 288070f7..c4162bb1 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/InitUpgradesForPlayer.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/InitUpgradesForPlayer.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -10,28 +10,35 @@ using System.Linq; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitUpgrades_Player(Map map, int playerId) + protected internal virtual void GenerateInitUpgradesForPlayer(Map map, int playerId, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var functionName = GeneratedFunctionName.InitUpgradesForPlayer(playerId); + var mapInfo = map.Info; if (mapInfo is null) { - throw new ArgumentException($"Function '{nameof(InitUpgrades_Player) + playerId}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); + throw new ArgumentException($"Function '{functionName}' cannot be generated without {nameof(MapInfo)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(functionName); var maxLevel = new Dictionary(); var researched = new Dictionary(); @@ -73,26 +80,26 @@ protected internal virtual JassFunctionDeclarationSyntax InitUpgrades_Player(Map foreach (var tech in maxLevel) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerTechMaxAllowed, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerId)), - SyntaxFactory.FourCCLiteralExpression(tech.Key), - SyntaxFactory.LiteralExpression(tech.Value))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerId)), + JassLiteral.FourCC(tech.Key), + JassLiteral.Int(tech.Value)); } foreach (var tech in researched) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetPlayerTechResearched, - SyntaxFactory.InvocationExpression(NativeName.Player, SyntaxFactory.LiteralExpression(playerId)), - SyntaxFactory.FourCCLiteralExpression(tech.Key), - SyntaxFactory.LiteralExpression(tech.Value + 1))); + JassExpression.Invoke(NativeName.Player, JassLiteral.Int(playerId)), + JassLiteral.FourCC(tech.Key), + JassLiteral.Int(tech.Value + 1)); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitUpgrades_Player) + playerId), statements); + writer.EndFunction(); } - protected internal virtual bool InitUpgrades_PlayerCondition(Map map, int playerId) + protected internal virtual bool ShouldGenerateInitUpgradesForPlayer(Map map, int playerId) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Info/MapItemTables.cs b/src/War3Net.Build/MapScriptBuilder/Info/MapItemTables.cs index 51e36ff9..c8b8fabb 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/MapItemTables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/MapItemTables.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,33 +6,42 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual IEnumerable MapItemTables(Map map) + protected internal virtual void GenerateMapItemTables(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var randomItemTables = map.Info?.RandomItemTables; if (randomItemTables is null) { - throw new ArgumentException($"'ItemTable_DropItems' functions cannot be generated without {nameof(MapInfo.RandomItemTables)}."); + throw new ArgumentException($"DropItems functions cannot be generated without {nameof(MapInfo.RandomItemTables)}."); + } + + foreach (var table in randomItemTables) + { + GenerateItemTableDropItems(map, table, writer); } - return randomItemTables.Select(table => ItemTableDropItems(map, table)); + writer.WriteLine(); } - protected internal virtual bool MapItemTablesCondition(Map map) + protected internal virtual bool ShouldGenerateMapItemTables(Map map) { if (map is null) { @@ -40,7 +49,7 @@ protected internal virtual bool MapItemTablesCondition(Map map) } return map.Info?.RandomItemTables is not null - && map.Info.RandomItemTables.Any(); + && map.Info.RandomItemTables.Count > 0; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Info/RandomUnitTables.cs b/src/War3Net.Build/MapScriptBuilder/Info/RandomUnitTables.cs index 11417c5d..e8b58a83 100644 --- a/src/War3Net.Build/MapScriptBuilder/Info/RandomUnitTables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Info/RandomUnitTables.cs @@ -6,53 +6,54 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis.CSharp.Syntax; using War3Net.Build.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - public virtual IEnumerable RandomUnitTablesApi(Map map, JassToCSharpTranspiler transpiler) + protected internal virtual void GenerateRandomUnitTables(Map map, IndentedTextWriter writer) { - if (transpiler is null) + if (map is null) { - throw new ArgumentNullException(nameof(transpiler)); + throw new ArgumentNullException(nameof(map)); } - return RandomUnitTables(map).Select(randomUnitTable => transpiler.Transpile(randomUnitTable)); - } - - protected internal virtual IEnumerable RandomUnitTables(Map map) - { - if (map is null) + if (writer is null) { - throw new ArgumentNullException(nameof(map)); + throw new ArgumentNullException(nameof(writer)); } var randomUnitTables = map.Info?.RandomUnitTables; if (randomUnitTables is null) { - yield break; + return; } var id = 0; foreach (var randomUnitTable in randomUnitTables) { - yield return SyntaxFactory.GlobalArrayDeclaration( - JassTypeSyntax.Integer, + writer.WriteAlignedGlobal( + $"{JassKeyword.Integer} {JassKeyword.Array}", randomUnitTable.GetVariableName(id)); id++; } } + + protected internal virtual bool ShouldGenerateRandomUnitTables(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + return map.Info?.RandomUnitTables is not null + && map.Info.RandomUnitTables.Count > 0; + } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs b/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs index a0ccae6a..e95e18d5 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs @@ -5,49 +5,99 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; +using System; -using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassGlobalDeclarationListSyntax Globals(Map map) + protected internal virtual void GenerateGlobals(Map map, IndentedTextWriter writer) { - var globalDeclarationList = new List(); - var generatedGlobals = new List(); + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } - generatedGlobals.AddRange(Regions(map)); - generatedGlobals.AddRange(Cameras(map)); - generatedGlobals.AddRange(Sounds(map)); - generatedGlobals.AddRange(Triggers(map)); - generatedGlobals.AddRange(Units(map)); - generatedGlobals.AddRange(Destructables(map)); - generatedGlobals.AddRange(RandomUnitTables(map)); + var shouldGenerateUserDefinedVariables = ShouldGenerateUserDefinedVariables(map); + var shouldGenerateRegionVariables = ShouldGenerateRegionVariables(map); + var shouldGenerateCameraVariables = ShouldGenerateCameraVariables(map); + var shouldGenerateSoundVariables = ShouldGenerateSoundVariables(map); + var shouldGenerateTriggerVariables = ShouldGenerateTriggerVariables(map); + var shouldGenerateUnitVariables = ShouldGenerateUnitVariables(map); + var shouldGenerateDestructableVariables = ShouldGenerateDestructableVariables(map); + var shouldGenerateRandomUnitTables = ShouldGenerateRandomUnitTables(map); - var userDefinedGlobals = new List(Variables(map)); + writer.WriteLine(JassKeyword.Globals); + writer.Indent(); - if (userDefinedGlobals.Any()) + if (shouldGenerateUserDefinedVariables) { - globalDeclarationList.Add(new JassCommentSyntax(" User-defined")); - globalDeclarationList.AddRange(userDefinedGlobals); + writer.WriteComment("User-defined"); + GenerateUserDefinedVariables(map, writer); + } - if (generatedGlobals.Any()) + if (shouldGenerateRegionVariables || + shouldGenerateCameraVariables || + shouldGenerateSoundVariables || + shouldGenerateTriggerVariables || + shouldGenerateUnitVariables || + shouldGenerateDestructableVariables || + shouldGenerateRandomUnitTables) + { + if (shouldGenerateUserDefinedVariables) { - globalDeclarationList.Add(JassEmptySyntax.Value); + writer.WriteLine(); } - } - if (generatedGlobals.Any()) - { - globalDeclarationList.Add(new JassCommentSyntax(" Generated")); - globalDeclarationList.AddRange(generatedGlobals); + writer.WriteComment("Generated"); + + if (shouldGenerateRegionVariables) + { + GenerateRegionVariables(map, writer); + } + + if (shouldGenerateCameraVariables) + { + GenerateCameraVariables(map, writer); + } + + if (shouldGenerateSoundVariables) + { + GenerateSoundVariables(map, writer); + } + + if (shouldGenerateTriggerVariables) + { + GenerateTriggerVariables(map, writer); + } + + if (shouldGenerateUnitVariables) + { + GenerateUnitVariables(map, writer); + } + + if (shouldGenerateDestructableVariables) + { + GenerateDestructableVariables(map, writer); + } + + if (shouldGenerateRandomUnitTables) + { + GenerateRandomUnitTables(map, writer); + } } - return new JassGlobalDeclarationListSyntax(globalDeclarationList.ToImmutableArray()); + writer.Unindent(); + writer.WriteLine(JassKeyword.EndGlobals); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Script/InitCustomTriggers.cs b/src/War3Net.Build/MapScriptBuilder/Script/InitCustomTriggers.cs index 39653fa0..52f22d16 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/InitCustomTriggers.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/InitCustomTriggers.cs @@ -6,47 +6,50 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitCustomTriggers(Map map) + protected internal virtual void GenerateInitCustomTriggers(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapTriggers = map.Triggers; if (mapTriggers is null) { - throw new ArgumentException($"Function '{nameof(InitCustomTriggers)}' cannot be generated without {nameof(MapTriggers)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitCustomTriggers}' cannot be generated without {nameof(MapTriggers)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitCustomTriggers); foreach (var trigger in mapTriggers.TriggerItems) { if (trigger is TriggerDefinition triggerDefinition && triggerDefinition.IsEnabled) { - statements.Add(SyntaxFactory.CallStatement(triggerDefinition.GetInitTrigFunctionName())); + writer.WriteCall(triggerDefinition.GetInitTrigFunctionName()); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitCustomTriggers)), statements); + writer.EndFunction(); } - protected internal virtual bool InitCustomTriggersCondition(Map map) + protected internal virtual bool ShouldGenerateInitCustomTriggers(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Script/InitGlobals.cs b/src/War3Net.Build/MapScriptBuilder/Script/InitGlobals.cs index 0cb74cdd..31aaa829 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/InitGlobals.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/InitGlobals.cs @@ -6,36 +6,38 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Info; -using War3Net.Build.Providers; using War3Net.Build.Script; +using War3Net.CodeAnalysis; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitGlobals(Map map) + protected internal virtual void GenerateInitGlobals(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapTriggers = map.Triggers; if (mapTriggers is null) { - throw new ArgumentException($"Function '{nameof(InitGlobals)}' cannot be generated without {nameof(MapTriggers)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitGlobals}' cannot be generated without {nameof(MapTriggers)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.InitGlobals); if (mapTriggers.Variables.Any(variable => (variable.IsArray || @@ -44,75 +46,85 @@ protected internal virtual JassFunctionDeclarationSyntax InitGlobals(Map map) TriggerData.TriggerTypeDefaults.TryGetValue(variable.Type, out _) || string.Equals(variable.Type, JassKeyword.String, StringComparison.Ordinal)))) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement( - JassTypeSyntax.Integer, + writer.WriteLocal( + JassKeyword.Integer, "i", - SyntaxFactory.LiteralExpression(0))); + "0"); } foreach (var variable in mapTriggers.Variables) { + string? initialValueExpression = null; + if (variable.IsInitialized) { - var initialValue = TriggerData.TriggerParams.TryGetValue(variable.InitialValue, out var triggerParam) && string.Equals(triggerParam.VariableType, variable.Type, StringComparison.Ordinal) + initialValueExpression = TriggerData.TriggerParams.TryGetValue(variable.InitialValue, out var triggerParam) && string.Equals(triggerParam.VariableType, variable.Type, StringComparison.Ordinal) ? triggerParam.ScriptText : string.Equals(variable.Type, JassKeyword.String, StringComparison.Ordinal) ? $"\"{EscapedStringProvider.GetEscapedString(variable.InitialValue)}\"" : variable.InitialValue; - - statements.AddRange(InitGlobal(variable, SyntaxFactory.ParseExpression(initialValue))); } else if (TriggerData.TriggerTypeDefaults.TryGetValue(variable.Type, out var triggerTypeDefault)) { - statements.AddRange(InitGlobal(variable, SyntaxFactory.ParseExpression(triggerTypeDefault.ScriptText))); + initialValueExpression = triggerTypeDefault.ScriptText; } else if (string.Equals(variable.Type, JassKeyword.String, StringComparison.Ordinal)) { - statements.AddRange(InitGlobal(variable, SyntaxFactory.LiteralExpression(string.Empty))); + initialValueExpression = "\"\""; + } + + if (initialValueExpression is not null) + { + WriteInitGlobal(variable, initialValueExpression, writer); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(InitGlobals)), statements); + writer.EndFunction(); } - protected internal virtual IEnumerable InitGlobal(VariableDefinition variable, IExpressionSyntax expression) + protected internal virtual void WriteInitGlobal(VariableDefinition variable, string initialValueExpression, IndentedTextWriter writer) { if (variable is null) { throw new ArgumentNullException(nameof(variable)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + if (variable.IsArray) { - yield return SyntaxFactory.SetStatement( + writer.WriteSet( + "i", + "0"); + + writer.WriteLoop(); + writer.WriteExitWhen(JassExpression.ParenthesizedCompact(JassExpression.GreaterThan( "i", - SyntaxFactory.LiteralExpression(0)); - - yield return SyntaxFactory.LoopStatement( - SyntaxFactory.ExitStatement(SyntaxFactory.ParenthesizedExpression(SyntaxFactory.BinaryGreaterThanExpression( - SyntaxFactory.VariableReferenceExpression("i"), - SyntaxFactory.LiteralExpression(variable.ArraySize)))), - SyntaxFactory.SetStatement( - variable.GetVariableName(), - SyntaxFactory.VariableReferenceExpression("i"), - expression), - SyntaxFactory.SetStatement( - "i", - SyntaxFactory.BinaryAdditionExpression( - SyntaxFactory.VariableReferenceExpression("i"), - SyntaxFactory.LiteralExpression(1)))); - - yield return JassEmptySyntax.Value; + JassLiteral.Int(variable.ArraySize)))); + + writer.WriteSet( + JassExpression.ElementAccess(variable.GetVariableName(), "i"), + initialValueExpression); + + writer.WriteSet( + "i", + JassExpression.Add("i", "1")); + + writer.WriteEndLoop(); + writer.WriteLine(); } else { - yield return SyntaxFactory.SetStatement( + writer.WriteSet( variable.GetVariableName(), - expression); + initialValueExpression); } } - protected internal virtual bool InitGlobalsCondition(Map map) + protected internal virtual bool ShouldGenerateInitGlobals(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs b/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs index 65131930..6c0e53fa 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,19 +6,18 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using War3Net.Build.Extensions; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax InitTrig(Map map, TriggerDefinition triggerDefinition) + protected internal virtual void GenerateInitTrig(Map map, TriggerDefinition triggerDefinition, IndentedTextWriter writer) { if (map is null) { @@ -30,25 +29,30 @@ protected internal virtual JassFunctionDeclarationSyntax InitTrig(Map map, Trigg throw new ArgumentNullException(nameof(triggerDefinition)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var triggerVariableName = triggerDefinition.GetVariableName(); - var statements = new List(); + writer.WriteFunction(triggerDefinition.GetInitTrigFunctionName()); - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( triggerVariableName, - SyntaxFactory.InvocationExpression(NativeName.CreateTrigger))); + JassExpression.InvokeSpaced(NativeName.CreateTrigger)); if (!triggerDefinition.IsInitiallyOn) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.DisableTrigger, - SyntaxFactory.FunctionReferenceExpression(triggerVariableName))); + triggerVariableName); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(triggerDefinition.GetInitTrigFunctionName()), statements); + writer.EndFunction(); } - protected internal virtual bool InitTrigCondition(Map map, TriggerDefinition triggerDefinition) + protected internal virtual bool ShouldRenderTrigger(Map map, TriggerDefinition triggerDefinition) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Script/RunInitializationTriggers.cs b/src/War3Net.Build/MapScriptBuilder/Script/RunInitializationTriggers.cs index e4ccfc45..b641aa6a 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/RunInitializationTriggers.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/RunInitializationTriggers.cs @@ -6,49 +6,52 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax RunInitializationTriggers(Map map) + protected internal virtual void GenerateRunInitializationTriggers(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapTriggers = map.Triggers; if (mapTriggers is null) { - throw new ArgumentException($"Function '{nameof(RunInitializationTriggers)}' cannot be generated without {nameof(MapTriggers)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.RunInitializationTriggers}' cannot be generated without {nameof(MapTriggers)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.RunInitializationTriggers); foreach (var trigger in mapTriggers.TriggerItems) { if (trigger is TriggerDefinition triggerDefinition && - RunInitializationTriggersConditionSingleTrigger(map, triggerDefinition)) + ShouldGenerateRunInitializationTriggersForTrigger(map, triggerDefinition)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.ConditionalTriggerExecute, - SyntaxFactory.VariableReferenceExpression(triggerDefinition.GetVariableName()))); + triggerDefinition.GetVariableName()); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(RunInitializationTriggers)), statements); + writer.EndFunction(); } - protected internal virtual bool RunInitializationTriggersCondition(Map map) + protected internal virtual bool ShouldGenerateRunInitializationTriggers(Map map) { if (map is null) { @@ -58,10 +61,10 @@ protected internal virtual bool RunInitializationTriggersCondition(Map map) return map.Triggers is not null && map.Triggers.TriggerItems.Any(trigger => trigger is TriggerDefinition triggerDefinition && - RunInitializationTriggersConditionSingleTrigger(map, triggerDefinition)); + ShouldGenerateRunInitializationTriggersForTrigger(map, triggerDefinition)); } - protected internal virtual bool RunInitializationTriggersConditionSingleTrigger(Map map, TriggerDefinition triggerDefinition) + protected internal virtual bool ShouldGenerateRunInitializationTriggersForTrigger(Map map, TriggerDefinition triggerDefinition) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Script/Triggers.cs b/src/War3Net.Build/MapScriptBuilder/Script/Triggers.cs index 2666ccd5..d98360d6 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/Triggers.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/Triggers.cs @@ -6,42 +6,65 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; +using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual IEnumerable Triggers(Map map) + protected internal virtual void GenerateTriggerVariables(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapTriggers = map.Triggers; if (mapTriggers is null) { - yield break; + return; + } + + foreach (var triggerItem in mapTriggers.TriggerItems.Where(ShouldGenerateTriggerVariable)) + { + writer.WriteAlignedGlobal( + TypeName.Trigger, + triggerItem.GetVariableName(), + JassKeyword.Null); + } + } + + protected internal virtual bool ShouldGenerateTriggerVariables(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); } - foreach (var trigger in mapTriggers.TriggerItems) + return map.Triggers is not null + && map.Triggers.TriggerItems.Any(ShouldGenerateTriggerVariable); + } + + protected internal virtual bool ShouldGenerateTriggerVariable(TriggerItem triggerItem) + { + if (triggerItem is null) { - if (trigger is TriggerDefinition triggerDefinition && - !triggerDefinition.IsComment) - { - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(TypeName.Trigger), - triggerDefinition.GetVariableName(), - JassNullLiteralExpressionSyntax.Value); - } + throw new ArgumentNullException(nameof(triggerItem)); } + + return triggerItem is TriggerDefinition triggerDefinition + && !triggerDefinition.IsComment; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Script/Variables.cs b/src/War3Net.Build/MapScriptBuilder/Script/Variables.cs index 4018cebb..6b01c888 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/Variables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/Variables.cs @@ -6,66 +6,80 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using War3Net.Build.Extensions; +using War3Net.CodeAnalysis; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual IEnumerable Variables(Map map) + protected internal virtual void GenerateUserDefinedVariables(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapTriggers = map.Triggers; if (mapTriggers is null) { - yield break; + return; } foreach (var variable in mapTriggers.Variables) { - var type = TriggerData.TriggerTypes.TryGetValue(variable.Type, out var triggerType) && !string.IsNullOrEmpty(triggerType.BaseType) + var variableType = TriggerData.TriggerTypes.TryGetValue(variable.Type, out var triggerType) && !string.IsNullOrEmpty(triggerType.BaseType) ? triggerType.BaseType : variable.Type; if (variable.IsArray) { - yield return SyntaxFactory.GlobalArrayDeclaration( - SyntaxFactory.ParseTypeName(type), + writer.WriteAlignedGlobal( + $"{variableType} {JassKeyword.Array}", variable.GetVariableName()); } else if (string.Equals(variable.Type, JassKeyword.String, StringComparison.Ordinal)) { - yield return SyntaxFactory.GlobalDeclaration( - JassTypeSyntax.String, + writer.WriteAlignedGlobal( + JassKeyword.String, variable.GetVariableName()); } else { - var value = variable.Type switch + var defaultValue = variable.Type switch { - JassKeyword.Integer => SyntaxFactory.LiteralExpression(0), - JassKeyword.Real => SyntaxFactory.LiteralExpression(0), - JassKeyword.Boolean => JassBooleanLiteralExpressionSyntax.False, + JassKeyword.Integer => "0", + JassKeyword.Real => "0", + JassKeyword.Boolean => JassKeyword.False, - _ => JassNullLiteralExpressionSyntax.Value, + _ => JassKeyword.Null, }; - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(type), + writer.WriteAlignedGlobal( + variableType, variable.GetVariableName(), - value); + defaultValue); } } } + + protected internal virtual bool ShouldGenerateUserDefinedVariables(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + return map.Triggers?.Variables is not null + && map.Triggers.Variables.Count > 0; + } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs index 809834c3..71bf66db 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs @@ -12,38 +12,44 @@ using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateAllDestructables(Map map) + protected internal virtual void GenerateCreateAllDestructables(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapDoodads = map.Doodads; if (mapDoodads is null) { - throw new ArgumentException($"Function '{nameof(CreateAllDestructables)}' cannot be generated without {nameof(MapDoodads)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateAllDestructables}' cannot be generated without {nameof(MapDoodads)}.", nameof(map)); } - var statements = new List(); + writer.WriteFunction(GeneratedFunctionName.CreateAllDestructables); + if (!ForceGenerateGlobalDestructableVariable) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Destructable), VariableName.Destructable)); + writer.WriteLocal(TypeName.Destructable, VariableName.Destructable); } - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Trigger), VariableName.Trigger)); + writer.WriteLocal(TypeName.Trigger, VariableName.Trigger); if (UseLifeVariable) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Real, VariableName.Life)); + writer.WriteLocal(JassKeyword.Real, VariableName.Life); } var createFunctions = new[] @@ -58,7 +64,7 @@ protected internal virtual JassFunctionDeclarationSyntax CreateAllDestructables( NativeName.BlzCreateDeadDestructableZWithSkin, }; - foreach (var (destructable, id) in mapDoodads.Doodads.IncludeId().Where(pair => CreateAllDestructablesConditionSingleDoodad(map, pair.Obj))) + foreach (var (destructable, id) in mapDoodads.Doodads.Where(ShouldGenerateDestructableVariable).IncludeId()) { var destructableVariableName = destructable.GetVariableName(); if (!ForceGenerateGlobalDestructableVariable && (!TriggerVariableReferences.TryGetValue(destructableVariableName, out var value) || !value)) @@ -72,84 +78,88 @@ protected internal virtual JassFunctionDeclarationSyntax CreateAllDestructables( var hasSkin = ForceGenerateUnitWithSkin || skinId != destructable.TypeId; var createFunctionIndex = isDead ? 1 : 0; - var arguments = new List(); - arguments.Add(SyntaxFactory.FourCCLiteralExpression(destructable.TypeId)); - arguments.Add(SyntaxFactory.LiteralExpression(destructable.Position.X)); - arguments.Add(SyntaxFactory.LiteralExpression(destructable.Position.Y)); + var arguments = new List(); + arguments.Add(JassLiteral.FourCC(destructable.TypeId)); + arguments.Add(JassLiteral.Real(destructable.Position.X)); + arguments.Add(JassLiteral.Real(destructable.Position.Y)); if (hasZ) { - arguments.Add(SyntaxFactory.LiteralExpression(destructable.Position.Z)); + arguments.Add(JassLiteral.Real(destructable.Position.Z)); createFunctionIndex += 2; } - arguments.Add(SyntaxFactory.LiteralExpression(destructable.Rotation * (180f / MathF.PI), precision: 3)); - arguments.Add(SyntaxFactory.LiteralExpression(destructable.Scale.X, precision: 3)); - arguments.Add(SyntaxFactory.LiteralExpression(destructable.Variation)); + arguments.Add(JassLiteral.Real(destructable.Rotation * Math.Rad2Deg, 3)); + arguments.Add(JassLiteral.Real(destructable.Scale.X, 3)); + arguments.Add(JassLiteral.Int(destructable.Variation)); if (hasSkin) { - arguments.Add(SyntaxFactory.FourCCLiteralExpression(destructable.SkinId)); + arguments.Add(JassLiteral.FourCC(destructable.SkinId)); createFunctionIndex += 4; } - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( destructableVariableName, - SyntaxFactory.InvocationExpression(createFunctions[createFunctionIndex], arguments.ToArray()))); + JassExpression.InvokeSpaced( + createFunctions[createFunctionIndex], + arguments.ToArray())); if (!isDead && destructable.Life != 100) { + var lifePercentLiteral = JassLiteral.Real(destructable.Life * 0.01f, 2); + if (UseLifeVariable) { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.Life, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.GetDestructableLife, - SyntaxFactory.VariableReferenceExpression(destructableVariableName)))); + destructableVariableName)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetDestructableLife, - SyntaxFactory.VariableReferenceExpression(destructableVariableName), - SyntaxFactory.BinaryMultiplicationExpression( - SyntaxFactory.LiteralExpression(destructable.Life * 0.01f, precision: 2), - SyntaxFactory.VariableReferenceExpression(VariableName.Life)))); + destructableVariableName, + JassExpression.Multiply( + lifePercentLiteral, + VariableName.Life)); } else { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetDestructableLife, - SyntaxFactory.VariableReferenceExpression(destructableVariableName), - SyntaxFactory.BinaryMultiplicationExpression( - SyntaxFactory.LiteralExpression(destructable.Life * 0.01f, precision: 2), - SyntaxFactory.InvocationExpression(NativeName.GetDestructableLife, SyntaxFactory.VariableReferenceExpression(destructableVariableName))))); + destructableVariableName, + JassExpression.Multiply( + lifePercentLiteral, + JassExpression.Invoke(NativeName.GetDestructableLife, destructableVariableName))); } } if (destructable.HasItemTable()) { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.Trigger, - SyntaxFactory.InvocationExpression(NativeName.CreateTrigger))); + JassExpression.InvokeSpaced(NativeName.CreateTrigger)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.TriggerRegisterDeathEvent, - SyntaxFactory.VariableReferenceExpression(VariableName.Trigger), - SyntaxFactory.VariableReferenceExpression(destructableVariableName))); + VariableName.Trigger, + destructableVariableName); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.TriggerAddAction, - SyntaxFactory.VariableReferenceExpression(VariableName.Trigger), - SyntaxFactory.FunctionReferenceExpression(FunctionName.SaveDyingWidget))); + VariableName.Trigger, + JassExpression.FunctionRef(FunctionName.SaveDyingWidget)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.TriggerAddAction, - SyntaxFactory.VariableReferenceExpression(VariableName.Trigger), - SyntaxFactory.FunctionReferenceExpression(destructable.GetDropItemsFunctionName(id)))); + VariableName.Trigger, + JassExpression.FunctionRef(destructable.GetDropItemsFunctionName(id))); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreateAllDestructables)), statements); + writer.EndFunction(); } - protected internal virtual bool CreateAllDestructablesCondition(Map map) + protected internal virtual bool ShouldGenerateCreateAllDestructables(Map map) { if (map is null) { @@ -162,24 +172,7 @@ protected internal virtual bool CreateAllDestructablesCondition(Map map) } return map.Doodads is not null - && map.Doodads.Doodads.Any(doodad => CreateAllDestructablesConditionSingleDoodad(map, doodad)); - } - - protected internal virtual bool CreateAllDestructablesConditionSingleDoodad(Map map, DoodadData doodadData) - { - if (map is null) - { - throw new ArgumentNullException(nameof(map)); - } - - if (doodadData is null) - { - throw new ArgumentNullException(nameof(doodadData)); - } - - return ForceGenerateGlobalDestructableVariable - || (TriggerVariableReferences.TryGetValue(doodadData.GetVariableName(), out var value) && value) - || doodadData.HasItemTable(); + && map.Doodads.Doodads.Any(ShouldGenerateDestructableVariable); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllItems.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllItems.cs index b76343c3..5815452e 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllItems.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllItems.cs @@ -13,31 +13,37 @@ using War3Net.Build.Info; using War3Net.Build.Providers; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateAllItems(Map map) + protected internal virtual void GenerateCreateAllItems(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapUnits = map.Units; if (mapUnits is null) { - throw new ArgumentException($"Function '{nameof(CreateAllItems)}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateAllItems}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); } - var statements = new List(); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Integer, VariableName.ItemId)); + writer.WriteFunction(GeneratedFunctionName.CreateAllItems); - foreach (var item in mapUnits.Units.Where(item => CreateAllItemsConditionSingleItem(map, item))) + writer.WriteLocal(JassKeyword.Integer, VariableName.ItemId); + + foreach (var item in mapUnits.Units.Where(item => ShouldGenerateCreateAllItemsForItem(map, item))) { if (item.IsRandomItem()) { @@ -45,12 +51,12 @@ protected internal virtual JassFunctionDeclarationSyntax CreateAllItems(Map map) switch (randomData) { case RandomUnitAny randomUnitAny: - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.ItemId, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.ChooseRandomItemEx, - SyntaxFactory.InvocationExpression(NativeName.ConvertItemType, SyntaxFactory.LiteralExpression((int)randomUnitAny.Class)), - SyntaxFactory.LiteralExpression(randomUnitAny.Level)))); + JassExpression.Invoke(NativeName.ConvertItemType, JassLiteral.Int((int)randomUnitAny.Class)), + JassLiteral.Int(randomUnitAny.Level))); break; @@ -58,37 +64,37 @@ protected internal virtual JassFunctionDeclarationSyntax CreateAllItems(Map map) break; case RandomUnitCustomTable randomUnitCustomTable: - statements.Add(SyntaxFactory.CallStatement(FunctionName.RandomDistReset)); + writer.WriteCall(FunctionName.RandomDistReset); var summedChance = 0; foreach (var randomItem in randomUnitCustomTable.RandomUnits) { - IExpressionSyntax id = RandomItemProvider.IsRandomItem(randomItem.UnitId, out var itemClass, out var level) - ? SyntaxFactory.InvocationExpression( + var itemIdExpression = RandomItemProvider.IsRandomItem(randomItem.UnitId, out var itemClass, out var level) + ? JassExpression.Invoke( NativeName.ChooseRandomItemEx, - SyntaxFactory.InvocationExpression(NativeName.ConvertItemType, SyntaxFactory.LiteralExpression((int)itemClass)), - SyntaxFactory.LiteralExpression(level)) - : SyntaxFactory.FourCCLiteralExpression(randomItem.UnitId); + JassExpression.Invoke(NativeName.ConvertItemType, JassLiteral.Int((int)itemClass)), + JassLiteral.Int(level)) + : JassLiteral.FourCC(randomItem.UnitId); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.RandomDistAddItem, - id, - SyntaxFactory.LiteralExpression(randomItem.Chance))); + itemIdExpression, + JassLiteral.Int(randomItem.Chance)); summedChance += randomItem.Chance; } if (summedChance < 100) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.RandomDistAddItem, - SyntaxFactory.LiteralExpression(-1), - SyntaxFactory.LiteralExpression(100 - summedChance))); + "-1", + JassLiteral.Int(100 - summedChance)); } - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.ItemId, - SyntaxFactory.InvocationExpression(FunctionName.RandomDistChoose))); + JassExpression.InvokeSpaced(FunctionName.RandomDistChoose)); break; @@ -96,39 +102,43 @@ protected internal virtual JassFunctionDeclarationSyntax CreateAllItems(Map map) break; } - statements.Add(SyntaxFactory.IfStatement( - SyntaxFactory.BinaryNotEqualsExpression(SyntaxFactory.VariableReferenceExpression(VariableName.ItemId), SyntaxFactory.LiteralExpression(-1)), - SyntaxFactory.CallStatement( - NativeName.CreateItem, - SyntaxFactory.VariableReferenceExpression(VariableName.ItemId), - SyntaxFactory.LiteralExpression(item.Position.X), - SyntaxFactory.LiteralExpression(item.Position.Y)))); + writer.WriteIf(JassExpression.NotEqual(VariableName.ItemId, "-1")); + + writer.WriteCall( + NativeName.CreateItem, + VariableName.ItemId, + JassLiteral.Real(item.Position.X), + JassLiteral.Real(item.Position.Y)); + + writer.WriteEndIf(); } else { - var args = new List() + var args = new List { - SyntaxFactory.FourCCLiteralExpression(item.TypeId), - SyntaxFactory.LiteralExpression(item.Position.X), - SyntaxFactory.LiteralExpression(item.Position.Y), + JassLiteral.FourCC(item.TypeId), + JassLiteral.Real(item.Position.X), + JassLiteral.Real(item.Position.Y), }; var hasSkin = item.SkinId != 0 && item.SkinId != item.TypeId; if (hasSkin) { - args.Add(SyntaxFactory.FourCCLiteralExpression(item.SkinId)); + args.Add(JassLiteral.FourCC(item.SkinId)); } - statements.Add(SyntaxFactory.CallStatement(hasSkin ? NativeName.BlzCreateItemWithSkin : NativeName.CreateItem, args.ToArray())); + writer.WriteCall( + hasSkin ? NativeName.BlzCreateItemWithSkin : NativeName.CreateItem, + args.ToArray()); } } - statements.Add(JassEmptySyntax.Value); + writer.WriteLine(); - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreateAllItems)), statements); + writer.EndFunction(); } - protected internal virtual bool CreateAllItemsCondition(Map map) + protected internal virtual bool ShouldGenerateCreateAllItems(Map map) { if (map is null) { @@ -141,10 +151,10 @@ protected internal virtual bool CreateAllItemsCondition(Map map) } return map.Units is not null - && map.Units.Units.Any(item => CreateAllItemsConditionSingleItem(map, item)); + && map.Units.Units.Any(item => ShouldGenerateCreateAllItemsForItem(map, item)); } - protected internal virtual bool CreateAllItemsConditionSingleItem(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateAllItemsForItem(Map map, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllUnits.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllUnits.cs index 2ef0d476..a05954a9 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllUnits.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllUnits.cs @@ -6,58 +6,61 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateAllUnits(Map map) + protected internal virtual void GenerateCreateAllUnits(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } - if (CreateNeutralPassiveBuildingsCondition(map)) + writer.WriteFunction(GeneratedFunctionName.CreateAllUnits); + + if (ShouldGenerateCreateNeutralPassiveBuildings(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateNeutralPassiveBuildings))); + writer.WriteCall(GeneratedFunctionName.CreateNeutralPassiveBuildings); } - if (CreatePlayerBuildingsCondition(map)) + if (ShouldGenerateCreatePlayerBuildings(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreatePlayerBuildings))); + writer.WriteCall(GeneratedFunctionName.CreatePlayerBuildings); } - if (CreateNeutralHostileCondition(map)) + if (ShouldGenerateCreateNeutralHostile(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateNeutralHostile))); + writer.WriteCall(GeneratedFunctionName.CreateNeutralHostile); } - if (CreateNeutralPassiveCondition(map)) + if (ShouldGenerateCreateNeutralPassive(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateNeutralPassive))); + writer.WriteCall(GeneratedFunctionName.CreateNeutralPassive); } - if (CreatePlayerUnitsCondition(map)) + if (ShouldGenerateCreatePlayerUnits(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreatePlayerUnits))); + writer.WriteCall(GeneratedFunctionName.CreatePlayerUnits); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreateAllUnits)), statements); + writer.EndFunction(); } - protected internal virtual bool CreateAllUnitsCondition(Map map) + protected internal virtual bool ShouldGenerateCreateAllUnits(Map map) { if (map is null) { @@ -67,25 +70,21 @@ protected internal virtual bool CreateAllUnitsCondition(Map map) if (map.Info is null || map.Info.FormatVersion >= MapInfoFormatVersion.v28) { return map.Units is not null - && map.Units.Units.Any(unit => CreateAllUnitsConditionSingleUnit(map, unit)); + && map.Units.Units.Any(ShouldGenerateCreateAllUnitsForUnit); } return map.Info.FormatVersion >= MapInfoFormatVersion.v15; } - protected internal virtual bool CreateAllUnitsConditionSingleUnit(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateAllUnitsForUnit(UnitData unitData) { - if (map is null) - { - throw new ArgumentNullException(nameof(map)); - } - if (unitData is null) { throw new ArgumentNullException(nameof(unitData)); } - return unitData.IsUnit() && !unitData.IsPlayerStartLocation(); + return unitData.IsUnit() + && !unitData.IsPlayerStartLocation(); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateBuildingsForPlayer.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateBuildingsForPlayer.cs index 674fc6c8..17694294 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateBuildingsForPlayer.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateBuildingsForPlayer.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -10,38 +10,46 @@ using War3Net.Build.Extensions; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateBuildingsForPlayer(Map map, int playerId) + protected internal virtual void GenerateCreateBuildingsForPlayer(Map map, int playerId, IndentedTextWriter writer) { - var functionName = nameof(CreateBuildingsForPlayer) + playerId; - if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var functionName = GeneratedFunctionName.CreateBuildingsForPlayer(playerId); + var mapUnits = map.Units; if (mapUnits is null) { throw new ArgumentException($"Function '{functionName}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); } - return SyntaxFactory.FunctionDeclaration( - SyntaxFactory.FunctionDeclarator(functionName), - CreateUnits( - map, - mapUnits.Units.IncludeId().Where(pair => CreateBuildingsForPlayerConditionSingleUnit(map, playerId, pair.Obj)), - SyntaxFactory.LiteralExpression(playerId))); + writer.WriteFunction(functionName); + + GenerateCreateUnits( + map, + mapUnits.Units.IncludeId().Where(pair => ShouldGenerateCreateBuildingsForPlayerAndUnit(map, playerId, pair.Obj)), + JassLiteral.Int(playerId), + writer); + + writer.EndFunction(); } - protected internal virtual bool CreateBuildingsForPlayerCondition(Map map, int playerId) + protected internal virtual bool ShouldGenerateCreateBuildingsForPlayer(Map map, int playerId) { if (map is null) { @@ -49,10 +57,10 @@ protected internal virtual bool CreateBuildingsForPlayerCondition(Map map, int p } return map.Units is not null - && map.Units.Units.Any(unit => CreateBuildingsForPlayerConditionSingleUnit(map, playerId, unit)); + && map.Units.Units.Any(unit => ShouldGenerateCreateBuildingsForPlayerAndUnit(map, playerId, unit)); } - protected internal virtual bool CreateBuildingsForPlayerConditionSingleUnit(Map map, int playerId, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateBuildingsForPlayerAndUnit(Map map, int playerId, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostile.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostile.cs index 6cb75bef..c6cd8469 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostile.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostile.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -10,36 +10,43 @@ using War3Net.Build.Extensions; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateNeutralHostile(Map map) + protected internal virtual void GenerateCreateNeutralHostile(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapUnits = map.Units; if (mapUnits is null) { - throw new ArgumentException($"Function '{nameof(CreateNeutralHostile)}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateNeutralHostile}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); } - return SyntaxFactory.FunctionDeclaration( - SyntaxFactory.FunctionDeclarator(nameof(CreateNeutralHostile)), - CreateUnits( - map, - mapUnits.Units.IncludeId().Where(pair => CreateNeutralHostileConditionSingleUnit(map, pair.Obj)), - SyntaxFactory.VariableReferenceExpression(GlobalVariableName.PlayerNeutralHostile))); + writer.WriteFunction(GeneratedFunctionName.CreateNeutralHostile); + + GenerateCreateUnits( + map, + mapUnits.Units.IncludeId().Where(pair => ShouldGenerateCreateNeutralHostileForUnit(map, pair.Obj)), + GlobalVariableName.PlayerNeutralHostile, + writer); + + writer.EndFunction(); } - protected internal virtual bool CreateNeutralHostileCondition(Map map) + protected internal virtual bool ShouldGenerateCreateNeutralHostile(Map map) { if (map is null) { @@ -47,10 +54,10 @@ protected internal virtual bool CreateNeutralHostileCondition(Map map) } return map.Units is not null - && map.Units.Units.Any(unit => CreateNeutralHostileConditionSingleUnit(map, unit)); + && map.Units.Units.Any(unit => ShouldGenerateCreateNeutralHostileForUnit(map, unit)); } - protected internal virtual bool CreateNeutralHostileConditionSingleUnit(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateNeutralHostileForUnit(Map map, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassive.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassive.cs index 3ef6fb76..9dc3c2fe 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassive.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassive.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -11,36 +11,43 @@ using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateNeutralPassive(Map map) + protected internal virtual void GenerateCreateNeutralPassive(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapUnits = map.Units; if (mapUnits is null) { - throw new ArgumentException($"Function '{nameof(CreateNeutralPassive)}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateNeutralPassive}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); } - return SyntaxFactory.FunctionDeclaration( - SyntaxFactory.FunctionDeclarator(nameof(CreateNeutralPassive)), - CreateUnits( - map, - mapUnits.Units.IncludeId().Where(pair => CreateNeutralPassiveConditionSingleUnit(map, pair.Obj)), - SyntaxFactory.VariableReferenceExpression(GlobalVariableName.PlayerNeutralPassive))); + writer.WriteFunction(GeneratedFunctionName.CreateNeutralPassive); + + GenerateCreateUnits( + map, + mapUnits.Units.IncludeId().Where(pair => ShouldGenerateCreateNeutralPassiveForUnit(map, pair.Obj)), + GlobalVariableName.PlayerNeutralPassive, + writer); + + writer.EndFunction(); } - protected internal virtual bool CreateNeutralPassiveCondition(Map map) + protected internal virtual bool ShouldGenerateCreateNeutralPassive(Map map) { if (map is null) { @@ -53,10 +60,10 @@ protected internal virtual bool CreateNeutralPassiveCondition(Map map) } return map.Units is not null - && map.Units.Units.Any(unit => CreateNeutralPassiveConditionSingleUnit(map, unit)); + && map.Units.Units.Any(unit => ShouldGenerateCreateNeutralPassiveForUnit(map, unit)); } - protected internal virtual bool CreateNeutralPassiveConditionSingleUnit(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateNeutralPassiveForUnit(Map map, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassiveBuildings.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassiveBuildings.cs index d24a5525..276c64b5 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassiveBuildings.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralPassiveBuildings.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -11,36 +11,43 @@ using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateNeutralPassiveBuildings(Map map) + protected internal virtual void GenerateCreateNeutralPassiveBuildings(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapUnits = map.Units; if (mapUnits is null) { - throw new ArgumentException($"Function '{nameof(CreateNeutralPassiveBuildings)}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateNeutralPassiveBuildings}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); } - return SyntaxFactory.FunctionDeclaration( - SyntaxFactory.FunctionDeclarator(nameof(CreateNeutralPassiveBuildings)), - CreateUnits( - map, - mapUnits.Units.IncludeId().Where(pair => CreateNeutralPassiveBuildingsConditionSingleUnit(map, pair.Obj)), - SyntaxFactory.VariableReferenceExpression(GlobalVariableName.PlayerNeutralPassive))); + writer.WriteFunction(GeneratedFunctionName.CreateNeutralPassiveBuildings); + + GenerateCreateUnits( + map, + mapUnits.Units.IncludeId().Where(pair => ShouldGenerateCreateNeutralPassiveBuildingsForUnit(map, pair.Obj)), + GlobalVariableName.PlayerNeutralPassive, + writer); + + writer.EndFunction(); } - protected internal virtual bool CreateNeutralPassiveBuildingsCondition(Map map) + protected internal virtual bool ShouldGenerateCreateNeutralPassiveBuildings(Map map) { if (map is null) { @@ -53,10 +60,10 @@ protected internal virtual bool CreateNeutralPassiveBuildingsCondition(Map map) } return map.Units is not null - && map.Units.Units.Any(unit => CreateNeutralPassiveBuildingsConditionSingleUnit(map, unit)); + && map.Units.Units.Any(unit => ShouldGenerateCreateNeutralPassiveBuildingsForUnit(map, unit)); } - protected internal virtual bool CreateNeutralPassiveBuildingsConditionSingleUnit(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateNeutralPassiveBuildingsForUnit(Map map, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralUnits.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralUnits.cs index 634f75fe..95fce222 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralUnits.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralUnits.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,40 +6,43 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using War3Net.Build.Info; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateNeutralUnits(Map map) + protected internal virtual void GenerateCreateNeutralUnits(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteFunction(GeneratedFunctionName.CreateNeutralUnits); - if (CreateNeutralHostileCondition(map)) + if (ShouldGenerateCreateNeutralHostile(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateNeutralHostile))); + writer.WriteCall(GeneratedFunctionName.CreateNeutralHostile); } - if (CreateNeutralPassiveCondition(map)) + if (ShouldGenerateCreateNeutralPassive(map)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateNeutralPassive))); + writer.WriteCall(GeneratedFunctionName.CreateNeutralPassive); } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreateNeutralUnits)), statements); + writer.EndFunction(); } - protected internal virtual bool CreateNeutralUnitsCondition(Map map) + protected internal virtual bool ShouldGenerateCreateNeutralUnits(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs index e59b20a8..4b6498e6 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,41 +6,44 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreatePlayerBuildings(Map map) + protected internal virtual void GenerateCreatePlayerBuildings(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteFunction(GeneratedFunctionName.CreatePlayerBuildings); for (var i = 0; i < MaxPlayerSlots; i++) { - if (CreateBuildingsForPlayerCondition(map, i)) + if (ShouldGenerateCreateBuildingsForPlayer(map, i)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateBuildingsForPlayer) + i)); + writer.WriteCall(GeneratedFunctionName.CreateBuildingsForPlayer(i)); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreatePlayerBuildings)), statements); + writer.EndFunction(); } - protected internal virtual bool CreatePlayerBuildingsCondition(Map map) + protected internal virtual bool ShouldGenerateCreatePlayerBuildings(Map map) { if (map is null) { @@ -56,7 +59,7 @@ protected internal virtual bool CreatePlayerBuildingsCondition(Map map) && map.Units.Units.Any(unit => CreatePlayerBuildingsConditionSingleUnit(map, unit)); } - protected internal virtual bool CreatePlayerBuildingsConditionSingleUnit(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateCreatePlayerBuildingsForUnit(Map map, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerUnits.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerUnits.cs index fa5fece5..6db895e8 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerUnits.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerUnits.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,41 +6,44 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreatePlayerUnits(Map map) + protected internal virtual void GenerateCreatePlayerUnits(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteFunction(GeneratedFunctionName.CreatePlayerUnits); for (var i = 0; i < MaxPlayerSlots; i++) { - if (CreateUnitsForPlayerCondition(map, i)) + if (ShouldGenerateCreateUnitsForPlayer(map, i)) { - statements.Add(SyntaxFactory.CallStatement(nameof(CreateUnitsForPlayer) + i)); + writer.WriteCall(GeneratedFunctionName.CreateUnitsForPlayer(i)); } } - return SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(nameof(CreatePlayerUnits)), statements); + writer.EndFunction(); } - protected internal virtual bool CreatePlayerUnitsCondition(Map map) + protected internal virtual bool ShouldGenerateCreatePlayerUnits(Map map) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs index c3e22938..1521f441 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -13,15 +13,15 @@ using War3Net.Build.Info; using War3Net.Build.Providers; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual IEnumerable CreateUnits(Map map, IEnumerable<(UnitData Unit, int Id)> units, IExpressionSyntax playerNumber) + protected internal virtual void GenerateCreateUnits(Map map, IEnumerable<(UnitData Unit, int Id)> units, string playerNumberExpression, IndentedTextWriter writer) { if (map is null) { @@ -33,26 +33,34 @@ protected internal virtual IEnumerable CreateUnits(Map map, IE throw new ArgumentNullException(nameof(units)); } - if (playerNumber is null) + if (playerNumberExpression is null) + { + throw new ArgumentNullException(nameof(playerNumberExpression)); + } + + if (writer is null) { - throw new ArgumentNullException(nameof(playerNumber)); + throw new ArgumentNullException(nameof(writer)); } - var statements = new List(); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Player), VariableName.Player, SyntaxFactory.InvocationExpression(NativeName.Player, playerNumber))); + writer.WriteLocal( + TypeName.Player, + VariableName.Player, + JassExpression.Invoke(NativeName.Player, playerNumberExpression)); + if (!ForceGenerateGlobalUnitVariable) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Unit), VariableName.Unit)); + writer.WriteLocal(TypeName.Unit, VariableName.Unit); } - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Integer, VariableName.UnitId)); - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(SyntaxFactory.ParseTypeName(TypeName.Trigger), VariableName.Trigger)); + writer.WriteLocal(JassKeyword.Integer, VariableName.UnitId); + writer.WriteLocal(TypeName.Trigger, VariableName.Trigger); if (UseLifeVariable) { - statements.Add(SyntaxFactory.LocalVariableDeclarationStatement(JassTypeSyntax.Real, VariableName.Life)); + writer.WriteLocal(JassKeyword.Real, VariableName.Life); } - statements.Add(JassEmptySyntax.Value); + writer.WriteLine(); foreach (var (unit, id) in units.OrderBy(pair => pair.Unit.CreationNumber)) { @@ -70,83 +78,84 @@ protected internal virtual IEnumerable CreateUnits(Map map, IE case RandomUnitAny randomUnitAny: if (unit.IsRandomBuilding()) { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.UnitId, - SyntaxFactory.InvocationExpression(NativeName.ChooseRandomNPBuilding))); + JassExpression.InvokeSpaced(NativeName.ChooseRandomNPBuilding)); } else { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.UnitId, - SyntaxFactory.InvocationExpression(NativeName.ChooseRandomCreep, SyntaxFactory.LiteralExpression(randomUnitAny.Level)))); + JassExpression.InvokeSpaced(NativeName.ChooseRandomCreep, JassLiteral.Int(randomUnitAny.Level))); } break; case RandomUnitGlobalTable randomUnitGlobalTable: - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.UnitId, - SyntaxFactory.ArrayReferenceExpression(randomUnitGlobalTable.GetVariableName(), SyntaxFactory.LiteralExpression(randomUnitGlobalTable.Column)))); + JassExpression.ElementAccess(randomUnitGlobalTable.GetVariableName(), randomUnitGlobalTable.Column)); break; case RandomUnitCustomTable randomUnitCustomTable: - statements.Add(SyntaxFactory.CallStatement(FunctionName.RandomDistReset)); + writer.WriteCall(FunctionName.RandomDistReset); var summedChance = 0; foreach (var randomUnit in randomUnitCustomTable.RandomUnits) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.RandomDistAddItem, RandomUnitProvider.IsRandomUnit(randomUnit.UnitId, out var level) - ? SyntaxFactory.InvocationExpression(NativeName.ChooseRandomCreep, SyntaxFactory.LiteralExpression(level)) - : SyntaxFactory.FourCCLiteralExpression(randomUnit.UnitId), - SyntaxFactory.LiteralExpression(randomUnit.Chance))); + ? JassExpression.Invoke(NativeName.ChooseRandomCreep, JassLiteral.Int(level)) + : JassLiteral.FourCC(randomUnit.UnitId), + JassLiteral.Int(randomUnit.Chance)); summedChance += randomUnit.Chance; } if (summedChance < 100) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( FunctionName.RandomDistAddItem, - SyntaxFactory.LiteralExpression(-1), - SyntaxFactory.LiteralExpression(100 - summedChance))); + "-1", + JassLiteral.Int(100 - summedChance)); } - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.UnitId, - SyntaxFactory.InvocationExpression(FunctionName.RandomDistChoose))); + JassExpression.InvokeSpaced(FunctionName.RandomDistChoose)); break; } - var ifBodyStatements = new List(); - ifBodyStatements.Add(SyntaxFactory.SetStatement( + writer.WriteIf(JassExpression.Parenthesized(JassExpression.NotEqual( + VariableName.UnitId, + "-1"))); + + writer.WriteSet( unitVariableName, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.CreateUnit, - SyntaxFactory.VariableReferenceExpression(VariableName.Player), - SyntaxFactory.VariableReferenceExpression(VariableName.UnitId), - SyntaxFactory.LiteralExpression(unit.Position.X, precision: 1), - SyntaxFactory.LiteralExpression(unit.Position.Y, precision: 1), - SyntaxFactory.LiteralExpression(unit.Rotation * (180f / MathF.PI), precision: 3)))); + VariableName.Player, + VariableName.UnitId, + JassLiteral.Real(unit.Position.X), + JassLiteral.Real(unit.Position.Y), + JassLiteral.Real(unit.Rotation * Math.Rad2Deg, 3))); - ifBodyStatements.AddRange(GetCreateUnitStatements(map, unit, id)); + WriteCreateUnitStatements(map, unit, id, writer); - statements.Add(SyntaxFactory.IfStatement( - new JassParenthesizedExpressionSyntax(SyntaxFactory.BinaryNotEqualsExpression(SyntaxFactory.VariableReferenceExpression(VariableName.UnitId), SyntaxFactory.LiteralExpression(-1))), - ifBodyStatements.ToArray())); + writer.WriteEndIf(); } else { - var args = new List() + var args = new List { - SyntaxFactory.VariableReferenceExpression(VariableName.Player), - SyntaxFactory.FourCCLiteralExpression(unit.TypeId), - SyntaxFactory.LiteralExpression(unit.Position.X, precision: 1), - SyntaxFactory.LiteralExpression(unit.Position.Y, precision: 1), - SyntaxFactory.LiteralExpression(unit.Rotation * (180f / MathF.PI), precision: 3), + VariableName.Player, + JassLiteral.FourCC(unit.TypeId), + JassLiteral.Real(unit.Position.X), + JassLiteral.Real(unit.Position.Y), + JassLiteral.Real(unit.Rotation * Math.Rad2Deg, 3), }; var skinId = unit.SkinId == 0 ? unit.TypeId : unit.SkinId; @@ -154,57 +163,57 @@ protected internal virtual IEnumerable CreateUnits(Map map, IE var hasSkin = ForceGenerateUnitWithSkin || skinId != unit.TypeId; if (hasSkin) { - args.Add(SyntaxFactory.FourCCLiteralExpression(skinId)); + args.Add(JassLiteral.FourCC(skinId)); } - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( unitVariableName, - SyntaxFactory.InvocationExpression(hasSkin ? NativeName.BlzCreateUnitWithSkin : NativeName.CreateUnit, args.ToArray()))); + JassExpression.InvokeSpaced( + hasSkin ? NativeName.BlzCreateUnitWithSkin : NativeName.CreateUnit, + args.ToArray())); if (unit.HeroLevel > 1) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetHeroLevel, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(unit.HeroLevel), - SyntaxFactory.LiteralExpression(false))); + unitVariableName, + JassLiteral.Int(unit.HeroLevel), + JassKeyword.False); } if (unit.HeroStrength > 0) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetHeroStr, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(unit.HeroStrength), - SyntaxFactory.LiteralExpression(true))); + unitVariableName, + JassLiteral.Int(unit.HeroStrength), + JassKeyword.True); } if (unit.HeroAgility > 0) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetHeroAgi, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(unit.HeroAgility), - SyntaxFactory.LiteralExpression(true))); + unitVariableName, + JassLiteral.Int(unit.HeroAgility), + JassKeyword.True); } if (unit.HeroIntelligence > 0) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetHeroInt, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(unit.HeroIntelligence), - SyntaxFactory.LiteralExpression(true))); + unitVariableName, + JassLiteral.Int(unit.HeroIntelligence), + JassKeyword.True); } - statements.AddRange(GetCreateUnitStatements(map, unit, id)); + WriteCreateUnitStatements(map, unit, id, writer); } } - - return statements; } - protected internal virtual IEnumerable GetCreateUnitStatements(Map map, UnitData unit, int id) + protected internal virtual void WriteCreateUnitStatements(Map map, UnitData unit, int id, IndentedTextWriter writer) { if (map is null) { @@ -216,9 +225,10 @@ protected internal virtual IEnumerable GetCreateUnitStatements throw new ArgumentNullException(nameof(unit)); } - var randomItemTables = map.Info?.RandomItemTables; - - var statements = new List(); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } var unitVariableName = unit.GetVariableName(); if (!ForceGenerateGlobalUnitVariable && (!TriggerVariableReferences.TryGetValue(unitVariableName, out var value) || !value)) @@ -228,53 +238,55 @@ protected internal virtual IEnumerable GetCreateUnitStatements if (unit.HP != -1) { + var lifePercentLiteral = JassLiteral.Real(unit.HP * 0.01f, 2); + if (UseLifeVariable) { - statements.Add(SyntaxFactory.SetStatement( + writer.WriteSet( VariableName.Life, - SyntaxFactory.InvocationExpression( + JassExpression.InvokeSpaced( NativeName.GetUnitState, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitStateName.Life)))); + unitVariableName, + UnitStateName.Life)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetUnitState, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitStateName.Life), - SyntaxFactory.BinaryMultiplicationExpression( - SyntaxFactory.LiteralExpression(unit.HP * 0.01f, precision: 2), - SyntaxFactory.VariableReferenceExpression(VariableName.Life)))); + unitVariableName, + UnitStateName.Life, + JassExpression.Multiply( + lifePercentLiteral, + VariableName.Life)); } else { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetUnitState, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitStateName.Life), - SyntaxFactory.BinaryMultiplicationExpression( - SyntaxFactory.LiteralExpression(unit.HP * 0.01f, precision: 2), - SyntaxFactory.InvocationExpression( + unitVariableName, + UnitStateName.Life, + JassExpression.Multiply( + lifePercentLiteral, + JassExpression.Invoke( NativeName.GetUnitState, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitStateName.Life))))); + unitVariableName, + UnitStateName.Life))); } } if (unit.MP != -1) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetUnitState, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitStateName.Mana), - SyntaxFactory.LiteralExpression(unit.MP))); + unitVariableName, + UnitStateName.Mana, + JassLiteral.Int(unit.MP)); } if (unit.IsGoldMine()) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetResourceAmount, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(unit.GoldAmount))); + unitVariableName, + JassLiteral.Int(unit.GoldAmount)); } var playerColorId = unit.CustomPlayerColorId; @@ -285,19 +297,20 @@ protected internal virtual IEnumerable GetCreateUnitStatements if (playerColorId != -1) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SetUnitColor, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.InvocationExpression(NativeName.ConvertPlayerColor, SyntaxFactory.LiteralExpression(playerColorId)))); + unitVariableName, + JassExpression.Invoke(NativeName.ConvertPlayerColor, JassLiteral.Int(playerColorId))); } if (unit.TargetAcquisition != -1f) { const float CampAcquisitionRange = 200f; - statements.Add(SyntaxFactory.CallStatement( + var acquisitionRange = unit.TargetAcquisition == -2f ? CampAcquisitionRange : unit.TargetAcquisition; + writer.WriteCall( NativeName.SetUnitAcquireRange, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(unit.TargetAcquisition == -2f ? CampAcquisitionRange : unit.TargetAcquisition, precision: 1))); + unitVariableName, + JassLiteral.Real(acquisitionRange)); } if (unit.WaygateDestinationRegionId != -1) @@ -305,16 +318,16 @@ protected internal virtual IEnumerable GetCreateUnitStatements var destinationRect = map.Regions?.Regions.Where(region => region.CreationNumber == unit.WaygateDestinationRegionId).SingleOrDefault(); if (destinationRect is not null) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.WaygateSetDestination, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(destinationRect.CenterX), - SyntaxFactory.LiteralExpression(destinationRect.CenterY))); + unitVariableName, + JassLiteral.Real(destinationRect.CenterX, 0), + JassLiteral.Real(destinationRect.CenterY, 0)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.WaygateActivate, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(true))); + unitVariableName, + JassKeyword.True); } } @@ -322,64 +335,64 @@ protected internal virtual IEnumerable GetCreateUnitStatements { for (var i = 0; i < ability.HeroAbilityLevel; i++) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.SelectHeroSkill, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.FourCCLiteralExpression(ability.AbilityId))); + unitVariableName, + JassLiteral.FourCC(ability.AbilityId)); } if (ability.IsAutocastActive) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.IssueImmediateOrderById, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.FourCCLiteralExpression(ability.AbilityId))); + unitVariableName, + JassLiteral.FourCC(ability.AbilityId)); } if (ability.TryGetOrderOffString(out var orderOffString)) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.IssueImmediateOrder, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.LiteralExpression(orderOffString))); + unitVariableName, + JassLiteral.String(orderOffString)); } } foreach (var item in unit.InventoryData) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.UnitAddItemToSlotById, - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.FourCCLiteralExpression(item.ItemId), - SyntaxFactory.LiteralExpression(item.Slot))); + unitVariableName, + JassLiteral.FourCC(item.ItemId), + JassLiteral.Int(item.Slot)); } if (unit.HasItemTable()) { - statements.Add(SyntaxFactory.SetStatement(VariableName.Trigger, SyntaxFactory.InvocationExpression(NativeName.CreateTrigger))); + writer.WriteSet( + VariableName.Trigger, + JassExpression.InvokeSpaced(NativeName.CreateTrigger)); - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.TriggerRegisterUnitEvent, - SyntaxFactory.VariableReferenceExpression(VariableName.Trigger), - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitEventName.Death))); + VariableName.Trigger, + unitVariableName, + UnitEventName.Death); if (map.Info is null || map.Info.FormatVersion >= MapInfoFormatVersion.v24) { - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.TriggerRegisterUnitEvent, - SyntaxFactory.VariableReferenceExpression(VariableName.Trigger), - SyntaxFactory.VariableReferenceExpression(unitVariableName), - SyntaxFactory.VariableReferenceExpression(UnitEventName.ChangeOwner))); + VariableName.Trigger, + unitVariableName, + UnitEventName.ChangeOwner); } - statements.Add(SyntaxFactory.CallStatement( + writer.WriteCall( NativeName.TriggerAddAction, - SyntaxFactory.VariableReferenceExpression(VariableName.Trigger), - SyntaxFactory.FunctionReferenceExpression(unit.GetDropItemsFunctionName(id)))); + VariableName.Trigger, + JassExpression.FunctionRef(unit.GetDropItemsFunctionName(id))); } - - return statements; } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnitsForPlayer.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnitsForPlayer.cs index bb2dec50..8d4855f8 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnitsForPlayer.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnitsForPlayer.cs @@ -10,38 +10,46 @@ using War3Net.Build.Extensions; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual JassFunctionDeclarationSyntax CreateUnitsForPlayer(Map map, int playerId) + protected internal virtual void GenerateCreateUnitsForPlayer(Map map, int playerId, IndentedTextWriter writer) { - var functionName = nameof(CreateUnitsForPlayer) + playerId; - if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var functionName = GeneratedFunctionName.CreateUnitsForPlayer(playerId); + var mapUnits = map.Units; if (mapUnits is null) { throw new ArgumentException($"Function '{functionName}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); } - return SyntaxFactory.FunctionDeclaration( - SyntaxFactory.FunctionDeclarator(functionName), - CreateUnits( - map, - mapUnits.Units.IncludeId().Where(pair => CreateUnitsForPlayerConditionSingleUnit(map, playerId, pair.Obj)), - SyntaxFactory.LiteralExpression(playerId))); + writer.WriteFunction(functionName); + + GenerateCreateUnits( + map, + mapUnits.Units.IncludeId().Where(pair => ShouldGenerateCreateUnitsForPlayerAndUnit(map, playerId, pair.Obj)), + JassLiteral.Int(playerId), + writer); + + writer.EndFunction(); } - protected internal virtual bool CreateUnitsForPlayerCondition(Map map, int playerId) + protected internal virtual bool ShouldGenerateCreateUnitsForPlayer(Map map, int playerId) { if (map is null) { @@ -49,10 +57,10 @@ protected internal virtual bool CreateUnitsForPlayerCondition(Map map, int playe } return map.Units is not null - && map.Units.Units.Any(unit => CreateUnitsForPlayerConditionSingleUnit(map, playerId, unit)); + && map.Units.Units.Any(unit => ShouldGenerateCreateUnitsForPlayerAndUnit(map, playerId, unit)); } - protected internal virtual bool CreateUnitsForPlayerConditionSingleUnit(Map map, int playerId, UnitData unitData) + protected internal virtual bool ShouldGenerateCreateUnitsForPlayerAndUnit(Map map, int playerId, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/DestructableItemTables.cs b/src/War3Net.Build/MapScriptBuilder/Widget/DestructableItemTables.cs index 18395c77..eda0576d 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/DestructableItemTables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/DestructableItemTables.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,41 +6,47 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual IEnumerable DestructableItemTables(Map map) + protected internal virtual void GenerateDestructableItemTables(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapDoodads = map.Doodads; if (mapDoodads is null) { - throw new ArgumentException($"Function '{nameof(DestructableItemTables)}' cannot be generated without {nameof(MapDoodads)}.", nameof(map)); + throw new ArgumentException($"DropItems functions cannot be generated without {nameof(MapDoodads)}.", nameof(map)); } for (var i = 0; i < mapDoodads.Doodads.Count; i++) { var doodad = mapDoodads.Doodads[i]; - if (DestructableItemTablesConditionSingleDoodad(map, doodad)) + if (ShouldGenerateDestructableItemTablesForDoodad(map, doodad)) { - yield return ItemTableDropItems(map, doodad, i); + GenerateItemTableDropItems(map, doodad, i, writer); } } + + writer.WriteLine(); } - protected internal virtual bool DestructableItemTablesCondition(Map map) + protected internal virtual bool ShouldGenerateDestructableItemTables(Map map) { if (map is null) { @@ -48,10 +54,10 @@ protected internal virtual bool DestructableItemTablesCondition(Map map) } return map.Doodads is not null - && map.Doodads.Doodads.Any(doodad => DestructableItemTablesConditionSingleDoodad(map, doodad)); + && map.Doodads.Doodads.Any(doodad => ShouldGenerateDestructableItemTablesForDoodad(map, doodad)); } - protected internal virtual bool DestructableItemTablesConditionSingleDoodad(Map map, DoodadData doodadData) + protected internal virtual bool ShouldGenerateDestructableItemTablesForDoodad(Map map, DoodadData doodadData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/Destructables.cs b/src/War3Net.Build/MapScriptBuilder/Widget/Destructables.cs index 54402493..e5aea8f0 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/Destructables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/Destructables.cs @@ -6,55 +6,66 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; - using War3Net.Build.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.Build.Widget; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - public virtual IEnumerable DestructablesApi(Map map, JassToCSharpTranspiler transpiler) + protected internal virtual void GenerateDestructableVariables(Map map, IndentedTextWriter writer) { - if (transpiler is null) + if (map is null) { - throw new ArgumentNullException(nameof(transpiler)); + throw new ArgumentNullException(nameof(map)); } - return Destructables(map).Select(destructable => transpiler.Transpile(destructable)); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var mapDoodads = map.Doodads; + if (mapDoodads is null) + { + return; + } + + foreach (var destructable in mapDoodads.Doodads.Where(ShouldGenerateDestructableVariable)) + { + writer.WriteAlignedGlobal( + TypeName.Destructable, + destructable.GetVariableName(), + JassKeyword.Null); + } } - protected internal virtual IEnumerable Destructables(Map map) + protected internal virtual bool ShouldGenerateDestructableVariables(Map map) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var mapDoodads = map.Doodads; - if (mapDoodads is null) - { - yield break; - } + return map.Doodads is not null + && map.Doodads.Doodads.Any(ShouldGenerateDestructableVariable); + } - foreach (var destructable in mapDoodads.Doodads.Where(destructable => CreateAllDestructablesConditionSingleDoodad(map, destructable))) + protected internal virtual bool ShouldGenerateDestructableVariable(DoodadData doodadData) + { + if (doodadData is null) { - var destructableVariableName = destructable.GetVariableName(); - if (ForceGenerateGlobalDestructableVariable || TriggerVariableReferences.ContainsKey(destructableVariableName)) - { - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(TypeName.Destructable), - destructableVariableName, - JassNullLiteralExpressionSyntax.Value); - } + throw new ArgumentNullException(nameof(doodadData)); } + + return ForceGenerateGlobalDestructableVariable + || (TriggerVariableReferences.TryGetValue(doodadData.GetVariableName(), out var value) && value) + || doodadData.HasItemTable(); } } } \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/UnitItemTables.cs b/src/War3Net.Build/MapScriptBuilder/Widget/UnitItemTables.cs index 81fd2150..629c3195 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/UnitItemTables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/UnitItemTables.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // Licensed under the MIT license. // See the LICENSE file in the project root for more information. @@ -6,41 +6,47 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; using War3Net.Build.Extensions; using War3Net.Build.Widget; -using War3Net.CodeAnalysis.Jass.Syntax; +using War3Net.CodeAnalysis; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual IEnumerable UnitItemTables(Map map) + protected internal virtual void GenerateUnitItemTables(Map map, IndentedTextWriter writer) { if (map is null) { throw new ArgumentNullException(nameof(map)); } + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + var mapUnits = map.Units; if (mapUnits is null) { - throw new ArgumentException($"Function '{nameof(UnitItemTables)}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); + throw new ArgumentException($"DropItems functions cannot be generated without {nameof(MapUnits)}.", nameof(map)); } for (var i = 0; i < mapUnits.Units.Count; i++) { var unit = mapUnits.Units[i]; - if (UnitItemTablesConditionSingleUnit(map, unit)) + if (ShouldGenerateUnitItemTablesForUnit(map, unit)) { - yield return ItemTableDropItems(map, unit, i); + GenerateItemTableDropItems(map, unit, i, writer); } } + + writer.WriteLine(); } - protected internal virtual bool UnitItemTablesCondition(Map map) + protected internal virtual bool ShouldGenerateUnitItemTables(Map map) { if (map is null) { @@ -48,10 +54,10 @@ protected internal virtual bool UnitItemTablesCondition(Map map) } return map.Units is not null - && map.Units.Units.Any(unit => UnitItemTablesConditionSingleUnit(map, unit)); + && map.Units.Units.Any(unit => ShouldGenerateUnitItemTablesForUnit(map, unit)); } - protected internal virtual bool UnitItemTablesConditionSingleUnit(Map map, UnitData unitData) + protected internal virtual bool ShouldGenerateUnitItemTablesForUnit(Map map, UnitData unitData) { if (map is null) { diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/Units.cs b/src/War3Net.Build/MapScriptBuilder/Widget/Units.cs index aa0d5193..02ee49f1 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/Units.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/Units.cs @@ -6,55 +6,72 @@ // ------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; - using War3Net.Build.Extensions; -using War3Net.CodeAnalysis.Jass.Syntax; -using War3Net.CodeAnalysis.Transpilers; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.Build.Widget; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - public virtual IEnumerable UnitsApi(Map map, JassToCSharpTranspiler transpiler) + protected internal virtual void GenerateUnitVariables(Map map, IndentedTextWriter writer) { - if (transpiler is null) + if (map is null) { - throw new ArgumentNullException(nameof(transpiler)); + throw new ArgumentNullException(nameof(map)); } - return Units(map).Select(unit => transpiler.Transpile(unit)); + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var mapUnits = map.Units; + if (mapUnits is null) + { + return; + } + + foreach (var unit in mapUnits.Units.Where(ShouldGenerateUnitVariable)) + { + writer.WriteAlignedGlobal( + TypeName.Unit, + unit.GetVariableName(), + JassKeyword.Null); + } } - protected internal virtual IEnumerable Units(Map map) + protected internal virtual bool ShouldGenerateUnitVariables(Map map) { if (map is null) { throw new ArgumentNullException(nameof(map)); } - var mapUnits = map.Units; - if (mapUnits is null) + return map.Units is not null + && map.Units.Units.Any(ShouldGenerateUnitVariable); + } + + protected internal virtual bool ShouldGenerateUnitVariable(UnitData unitData) + { + if (unitData is null) { - yield break; + throw new ArgumentNullException(nameof(unitData)); } - foreach (var unit in mapUnits.Units.Where(unit => CreateAllUnitsConditionSingleUnit(map, unit))) + if (!unitData.IsUnit() || unitData.IsPlayerStartLocation()) { - var unitVariableName = unit.GetVariableName(); - if (ForceGenerateGlobalUnitVariable || TriggerVariableReferences.ContainsKey(unitVariableName)) - { - yield return SyntaxFactory.GlobalDeclaration( - SyntaxFactory.ParseTypeName(TypeName.Unit), - unitVariableName, - JassNullLiteralExpressionSyntax.Value); - } + return false; } + + var unitVariableName = unitData.GetVariableName(); + + return ForceGenerateGlobalUnitVariable + || TriggerVariableReferences.ContainsKey(unitVariableName); } } } \ No newline at end of file diff --git a/src/War3Net.Build/TriggerRenderer.cs b/src/War3Net.Build/TriggerRenderer.cs index 7309710d..a8bca8b1 100644 --- a/src/War3Net.Build/TriggerRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer.cs @@ -11,27 +11,24 @@ using System.ComponentModel; using System.IO; using System.Linq; -using System.Text; using War3Net.Build.Extensions; -using War3Net.Build.Providers; using War3Net.Build.Script; +using War3Net.CodeAnalysis; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class TriggerRenderer { - private readonly TextWriter _writer; + private readonly IndentedTextWriter _writer; private readonly TriggerData _triggerData; private readonly ImmutableDictionary _variableTypes; private readonly bool _isLuaTrigger; public TriggerRenderer( - TextWriter writer, + IndentedTextWriter writer, TriggerData triggerData, IEnumerable variables, bool isLuaTrigger = false) @@ -49,14 +46,14 @@ public void RenderTrigger(TriggerDefinition triggerDefinition) throw new ArgumentNullException(nameof(triggerDefinition)); } - var commentLine = new JassCommentSyntax("===========================================================================").ToString(); + var commentLine = "//==========================================================================="; _writer.WriteLine(commentLine); - _writer.WriteLine(new JassCommentSyntax($" Trigger: {triggerDefinition.Name}").ToString()); + _writer.WriteComment($"Trigger: {triggerDefinition.Name}"); if (!string.IsNullOrEmpty(triggerDefinition.Description)) { - _writer.WriteLine(new JassCommentSyntax(string.Empty)); + _writer.WriteLine(JassSymbol.SlashSlash); using var stringReader = new StringReader(triggerDefinition.Description); while (true) @@ -67,7 +64,7 @@ public void RenderTrigger(TriggerDefinition triggerDefinition) break; } - _writer.WriteLine(new JassCommentSyntax($" {line}").ToString()); + _writer.WriteComment(line); } } @@ -88,25 +85,23 @@ public void RenderTrigger(TriggerDefinition triggerDefinition) private void RenderInitTrig(TriggerDefinition triggerDefinition) { - var stringBuilder = new StringBuilder(); - using var stringWriter = new StringWriter(stringBuilder); - var renderer = new JassRenderer(stringWriter); - var triggerVariableName = triggerDefinition.GetVariableName(); - var statements = new List(); + _writer.WriteFunction(triggerDefinition.GetInitTrigFunctionName()); - statements.Add(SyntaxFactory.SetStatement( + _writer.WriteSet( triggerVariableName, - SyntaxFactory.InvocationExpression(WellKnownNatives.CreateTrigger))); + JassExpression.InvokeSpaced(WellKnownNatives.CreateTrigger)); if (!triggerDefinition.IsInitiallyOn) { - statements.Add(SyntaxFactory.CallStatement( + _writer.WriteCall( WellKnownNatives.DisableTrigger, - SyntaxFactory.VariableReferenceExpression(triggerVariableName))); + triggerVariableName); } + var identifierBuilder = new TrigFunctionIdentifierBuilder(triggerDefinition.GetTriggerIdentifierName() + "_Func"); + foreach (var function in triggerDefinition.Functions.Where(function => function.Type == TriggerFunctionType.Event && function.IsEnabled)) { if (string.Equals(function.Name, "MapInitializationEvent", StringComparison.Ordinal)) @@ -114,37 +109,31 @@ private void RenderInitTrig(TriggerDefinition triggerDefinition) continue; } - var stringBuilder2 = new StringBuilder(); - using var stringWriter2 = new StringWriter(stringBuilder2); - var renderer2 = new JassRenderer(stringWriter2); - - var identifierBuilder = new TrigFunctionIdentifierBuilder(triggerDefinition.GetTriggerIdentifierName() + "_Func"); + var arguments = GetParameters(function, identifierBuilder) + .Prepend(triggerVariableName) + .ToArray(); - var context = new TriggerRendererContext(renderer2, identifierBuilder); - - var argumentListBuilder = ImmutableArray.CreateBuilder(); - argumentListBuilder.Add(SyntaxFactory.VariableReferenceExpression(triggerVariableName)); - BuildParameters(function, context, argumentListBuilder); - - statements.Add(SyntaxFactory.CallStatement(function.Name, new JassArgumentListSyntax(argumentListBuilder.ToImmutable()))); + _writer.WriteCall( + function.Name, + arguments); } if (triggerDefinition.Functions.Any(function => function.Type == TriggerFunctionType.Condition && function.IsEnabled)) { - statements.Add(SyntaxFactory.CallStatement( + _writer.WriteCall( WellKnownNatives.TriggerAddCondition, - SyntaxFactory.VariableReferenceExpression(triggerVariableName), - SyntaxFactory.InvocationExpression(WellKnownNatives.Condition, SyntaxFactory.FunctionReferenceExpression(triggerDefinition.GetTrigConditionsFunctionName())))); + triggerVariableName, + JassExpression.InvokeSpaced( + WellKnownNatives.Condition, + JassExpression.FunctionRef(triggerDefinition.GetTrigConditionsFunctionName()))); } - statements.Add(SyntaxFactory.CallStatement( + _writer.WriteCall( WellKnownNatives.TriggerAddAction, - SyntaxFactory.VariableReferenceExpression(triggerVariableName), - SyntaxFactory.FunctionReferenceExpression(triggerDefinition.GetTrigActionsFunctionName()))); - - renderer.Render(SyntaxFactory.FunctionDeclaration(SyntaxFactory.FunctionDeclarator(triggerDefinition.GetInitTrigFunctionName()), statements)); + triggerVariableName, + JassExpression.FunctionRef(triggerDefinition.GetTrigActionsFunctionName())); - _writer.WriteLine(stringBuilder.ToString()); + _writer.EndFunction(); } private ImmutableArray GetArgumentTypes(TriggerFunction function) @@ -167,47 +156,19 @@ private ImmutableArray GetArgumentTypes(TriggerFunction function) return argumentTypes; } - private void BuildParameters(TriggerFunction function, TriggerRendererContext context, ImmutableArray.Builder argumentListBuilder) + private IEnumerable GetParameters(TriggerFunction function, TrigFunctionIdentifierBuilder identifierBuilder) { var argumentTypes = GetArgumentTypes(function); for (var i = 0; i < argumentTypes.Length; i++) { - argumentListBuilder.Add(GetParameter(function.Parameters[i], argumentTypes[i], i, context)); + yield return GetParameter(function.Parameters[i], argumentTypes[i], i, identifierBuilder); } } - private void BuildParametersSkipLast(TriggerFunction function, TriggerRendererContext context, ImmutableArray.Builder argumentListBuilder) - { - var argumentTypes = GetArgumentTypes(function); - - for (var i = 0; i + 1 < argumentTypes.Length; i++) - { - argumentListBuilder.Add(GetParameter(function.Parameters[i], argumentTypes[i], i, context)); - } - } - - private ImmutableArray.Builder BuildParameters(TriggerFunction function, TriggerRendererContext context) - { - var argumentTypes = GetArgumentTypes(function); - - var argumentListBuilder = ImmutableArray.CreateBuilder(); - for (var i = 0; i < argumentTypes.Length; i++) - { - argumentListBuilder.Add(GetParameter(function.Parameters[i], argumentTypes[i], i, context)); - } - - return argumentListBuilder; - } - - private JassArgumentListSyntax GetParameters(TriggerFunction function, TriggerRendererContext context) - { - return new JassArgumentListSyntax(BuildParameters(function, context).ToImmutable()); - } - - private IExpressionSyntax GetParameter(TriggerFunctionParameter parameter, string type, int parameterIndex, TriggerRendererContext context) + private string GetParameter(TriggerFunctionParameter parameter, string type, int parameterIndex, TrigFunctionIdentifierBuilder identifierBuilder) { - context.TrigFunctionIdentifierBuilder.Append(parameterIndex + 1); + identifierBuilder.Append(parameterIndex + 1); try { switch (parameter.Type) @@ -216,19 +177,19 @@ private IExpressionSyntax GetParameter(TriggerFunctionParameter parameter, strin var triggerParam = _triggerData.TriggerParams[parameter.Value]; if (triggerParam.ScriptText.StartsWith('`') && triggerParam.ScriptText.EndsWith('`')) { - return SyntaxFactory.ParseExpression($"\"{triggerParam.ScriptText[1..^1]}\""); + return $"{JassSymbol.DoubleQuoteChar}{triggerParam.ScriptText[1..^1]}{JassSymbol.DoubleQuoteChar}"; } - return SyntaxFactory.ParseExpression(triggerParam.ScriptText); + return triggerParam.ScriptText; case TriggerFunctionParameterType.Variable: - var variableeName = parameter.Value.StartsWith("gg_", StringComparison.Ordinal) + var variableName = parameter.Value.StartsWith("gg_", StringComparison.Ordinal) ? parameter.Value : $"udg_{parameter.Value}"; return parameter.ArrayIndexer is null - ? SyntaxFactory.VariableReferenceExpression(variableeName) - : SyntaxFactory.ArrayReferenceExpression(variableeName, GetParameter(parameter.ArrayIndexer, JassKeyword.Integer, 0, context)); + ? variableName + : JassExpression.ElementAccess(variableName, GetParameter(parameter.ArrayIndexer, JassKeyword.Integer, 0, identifierBuilder)); case TriggerFunctionParameterType.Function: if (parameter.Function is null) @@ -238,10 +199,10 @@ private IExpressionSyntax GetParameter(TriggerFunctionParameter parameter, strin if (type == "boolexpr") { - var conditionFunctionName = context.TrigFunctionIdentifierBuilder.ToString(); - RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, parameter); + var conditionFunctionName = identifierBuilder.ToString(); + RenderConditionFunction(identifierBuilder, conditionFunctionName, parameter); - return SyntaxFactory.InvocationExpression(WellKnownNatives.Condition, SyntaxFactory.FunctionReferenceExpression(conditionFunctionName)); + return JassExpression.Invoke(WellKnownNatives.Condition, JassExpression.FunctionRef(conditionFunctionName)); } var scriptName = GetScriptName(parameter.Function); @@ -249,25 +210,26 @@ private IExpressionSyntax GetParameter(TriggerFunctionParameter parameter, strin if (string.Equals(scriptName, "OperatorInt", StringComparison.Ordinal) || string.Equals(scriptName, "OperatorReal", StringComparison.Ordinal)) { - var parameters = GetParameters(parameter.Function, context); + var parameters = GetParameters(parameter.Function, identifierBuilder).ToArray(); - return SyntaxFactory.ParenthesizedExpression(SyntaxFactory.BinaryExpression( - parameters.Arguments[0], - parameters.Arguments[2], - SyntaxFactory.ParseBinaryOperator(((JassStringLiteralExpressionSyntax)parameters.Arguments[1]).Value))); + return JassExpression.ParenthesizedCompact(JassExpression.Binary( + parameters[0], + parameters[1], + parameters[2])); } else if (string.Equals(scriptName, "OperatorString", StringComparison.Ordinal)) { - var parameters = GetParameters(parameter.Function, context); + var parameters = GetParameters(parameter.Function, identifierBuilder).ToArray(); - return SyntaxFactory.ParenthesizedExpression(SyntaxFactory.BinaryExpression( - parameters.Arguments[0], - parameters.Arguments[1], - BinaryOperatorType.Add)); + return JassExpression.ParenthesizedCompact(JassExpression.Add( + parameters[0], + parameters[1])); } else { - return SyntaxFactory.InvocationExpression(scriptName, GetParameters(parameter.Function, context)); + return JassExpression.Invoke( + scriptName, + GetParameters(parameter.Function, identifierBuilder).ToArray()); } case TriggerFunctionParameterType.String: @@ -293,15 +255,15 @@ private IExpressionSyntax GetParameter(TriggerFunctionParameter parameter, strin if (knownStringTypes.Contains(type)) { - return SyntaxFactory.ParseExpression($"\"{EscapedStringProvider.GetEscapedString(parameter.Value)}\""); + return JassLiteral.String(parameter.Value); } else if (knownFourCCTypes.Contains(type)) { - return SyntaxFactory.ParseExpression($"'{parameter.Value}'"); + return JassLiteral.FourCC(parameter.Value); } else { - return SyntaxFactory.ParseExpression(parameter.Value); + return parameter.Value; } default: @@ -310,7 +272,7 @@ private IExpressionSyntax GetParameter(TriggerFunctionParameter parameter, strin } finally { - context.TrigFunctionIdentifierBuilder.Remove(); + identifierBuilder.Remove(); } } diff --git a/src/War3Net.Build/TriggerRenderer/ForLoopRenderer.cs b/src/War3Net.Build/TriggerRenderer/ForLoopRenderer.cs index ebdee305..80471c8d 100644 --- a/src/War3Net.Build/TriggerRenderer/ForLoopRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/ForLoopRenderer.cs @@ -8,9 +8,8 @@ using System; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -30,30 +29,21 @@ private void RenderForLoop(TriggerFunction function, TriggerRendererContext cont { var argumentTypes = GetArgumentTypes(function); - context.Renderer.Render(SyntaxFactory.SetStatement(indexName, GetParameter(function.Parameters[0], argumentTypes[0], 0, context))); - context.Renderer.RenderNewLine(); - context.Renderer.Render(SyntaxFactory.SetStatement(indexEndName, GetParameter(function.Parameters[1], argumentTypes[1], 1, context))); - context.Renderer.RenderNewLine(); - - context.Renderer.Render(JassLoopCustomScriptAction.Value); - context.Renderer.RenderNewLine(); + context.Writer.WriteSet(indexName, GetParameter(function.Parameters[0], argumentTypes[0], 0, context.TrigFunctionIdentifierBuilder)); + context.Writer.WriteSet(indexEndName, GetParameter(function.Parameters[1], argumentTypes[1], 1, context.TrigFunctionIdentifierBuilder)); - context.Renderer.Render(SyntaxFactory.ExitStatement(SyntaxFactory.BinaryGreaterThanExpression( - SyntaxFactory.VariableReferenceExpression(indexName), - SyntaxFactory.VariableReferenceExpression(indexEndName)))); - context.Renderer.RenderNewLine(); + context.Writer.WriteLoop(); + context.Writer.WriteExitWhen(JassExpression.GreaterThan( + indexName, + indexEndName)); RenderTriggerAction(function.Parameters[2].Function, context); - context.Renderer.Render(SyntaxFactory.SetStatement( + context.Writer.WriteSet( indexName, - SyntaxFactory.BinaryAdditionExpression( - SyntaxFactory.VariableReferenceExpression(indexName), - SyntaxFactory.LiteralExpression(1)))); - context.Renderer.RenderNewLine(); + JassExpression.Add(indexName, "1")); - context.Renderer.Render(JassEndLoopCustomScriptAction.Value); - context.Renderer.RenderNewLine(); + context.Writer.WriteEndLoop(); } private void RenderForLoopVar(TriggerFunction function, TriggerRendererContext context) diff --git a/src/War3Net.Build/TriggerRenderer/ForeachLoopRenderer.cs b/src/War3Net.Build/TriggerRenderer/ForeachLoopRenderer.cs index be3bc276..1009bde9 100644 --- a/src/War3Net.Build/TriggerRenderer/ForeachLoopRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/ForeachLoopRenderer.cs @@ -5,12 +5,11 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Immutable; +using System.Linq; using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -23,12 +22,12 @@ private void RenderForeachLoop(TriggerFunction function, TriggerRendererContext RenderActionFunction(context.TrigFunctionIdentifierBuilder, actionFunctionName, function.Parameters[^1]); context.TrigFunctionIdentifierBuilder.Remove(); - var argumentListBuilder = ImmutableArray.CreateBuilder(); - BuildParametersSkipLast(function, context, argumentListBuilder); - argumentListBuilder.Add(SyntaxFactory.FunctionReferenceExpression(actionFunctionName)); - - context.Renderer.Render(SyntaxFactory.CallStatement(GetScriptName(function), new JassArgumentListSyntax(argumentListBuilder.ToImmutable()))); - context.Renderer.RenderNewLine(); + context.Writer.WriteCall( + GetScriptName(function), + GetParameters(function, context.TrigFunctionIdentifierBuilder) + .SkipLast(1) + .Append(JassExpression.FunctionRef(actionFunctionName)) + .ToArray()); } private void RenderForeachLoopMultiple(TriggerFunction function, TriggerRendererContext context) @@ -36,11 +35,11 @@ private void RenderForeachLoopMultiple(TriggerFunction function, TriggerRenderer var actionFunctionName = $"{context.TrigFunctionIdentifierBuilder}A"; RenderActionFunction(context.TrigFunctionIdentifierBuilder, actionFunctionName, function.ChildFunctions); - var argumentListBuilder = BuildParameters(function, context); - argumentListBuilder.Add(SyntaxFactory.FunctionReferenceExpression(actionFunctionName)); - - context.Renderer.Render(SyntaxFactory.CallStatement(GetScriptName(function), new JassArgumentListSyntax(argumentListBuilder.ToImmutable()))); - context.Renderer.RenderNewLine(); + context.Writer.WriteCall( + GetScriptName(function), + GetParameters(function, context.TrigFunctionIdentifierBuilder) + .Append(JassExpression.FunctionRef(actionFunctionName)) + .ToArray()); } } } \ No newline at end of file diff --git a/src/War3Net.Build/TriggerRenderer/IfThenElseRenderer.cs b/src/War3Net.Build/TriggerRenderer/IfThenElseRenderer.cs index c5ed196b..a5322bdf 100644 --- a/src/War3Net.Build/TriggerRenderer/IfThenElseRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/IfThenElseRenderer.cs @@ -6,9 +6,8 @@ // ------------------------------------------------------------------------------ using War3Net.Build.Script; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -21,22 +20,19 @@ private void RenderIfThenElse(TriggerFunction function, TriggerRendererContext c RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, function.Parameters[0]); context.TrigFunctionIdentifierBuilder.Remove(); - context.Renderer.Render(new JassIfCustomScriptAction(SyntaxFactory.ParenthesizedExpression(SyntaxFactory.InvocationExpression(conditionFunctionName)))); - context.Renderer.RenderNewLine(); + context.Writer.WriteIf(JassExpression.Parenthesized(JassExpression.Invoke(conditionFunctionName))); context.TrigFunctionIdentifierBuilder.Append(2); RenderTriggerAction(function.Parameters[1].Function, context); context.TrigFunctionIdentifierBuilder.Remove(); - context.Renderer.Render(JassElseCustomScriptAction.Value); - context.Renderer.RenderNewLine(); + context.Writer.WriteElse(); context.TrigFunctionIdentifierBuilder.Append(3); RenderTriggerAction(function.Parameters[2].Function, context); context.TrigFunctionIdentifierBuilder.Remove(); - context.Renderer.Render(JassEndIfCustomScriptAction.Value); - context.Renderer.RenderNewLine(); + context.Writer.WriteEndIf(); } private void RenderIfThenElseMultiple(TriggerFunction function, TriggerRendererContext context) @@ -44,8 +40,7 @@ private void RenderIfThenElseMultiple(TriggerFunction function, TriggerRendererC var conditionFunctionName = $"{context.TrigFunctionIdentifierBuilder}C"; RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, true, function.ChildFunctions); - context.Renderer.Render(new JassIfCustomScriptAction(SyntaxFactory.ParenthesizedExpression(SyntaxFactory.InvocationExpression(conditionFunctionName)))); - context.Renderer.RenderNewLine(); + context.Writer.WriteIf(JassExpression.Parenthesized(JassExpression.Invoke(conditionFunctionName))); context.TrigFunctionIdentifierBuilder.Append("Func"); @@ -60,8 +55,7 @@ private void RenderIfThenElseMultiple(TriggerFunction function, TriggerRendererC } } - context.Renderer.Render(JassElseCustomScriptAction.Value); - context.Renderer.RenderNewLine(); + context.Writer.WriteElse(); for (var i = 0; i < function.ChildFunctions.Count; i++) { @@ -76,8 +70,7 @@ private void RenderIfThenElseMultiple(TriggerFunction function, TriggerRendererC context.TrigFunctionIdentifierBuilder.Remove(); - context.Renderer.Render(JassEndIfCustomScriptAction.Value); - context.Renderer.RenderNewLine(); + context.Writer.WriteEndIf(); } } } \ No newline at end of file diff --git a/src/War3Net.Build/TriggerRenderer/SetVariableRenderer.cs b/src/War3Net.Build/TriggerRenderer/SetVariableRenderer.cs index 94ee58f5..36a7cd83 100644 --- a/src/War3Net.Build/TriggerRenderer/SetVariableRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/SetVariableRenderer.cs @@ -8,8 +8,8 @@ using System; using War3Net.Build.Script; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -25,21 +25,17 @@ private void RenderSetVariable(TriggerFunction function, TriggerRendererContext throw new InvalidOperationException($"Unable to determine the type of the global variable '{variableParameter.Value}'."); } + var variableName = $"udg_{variableParameter.Value}"; if (variableParameter.ArrayIndexer is not null) { - context.Renderer.Render(SyntaxFactory.SetStatement( - $"udg_{variableParameter.Value}", - GetParameter(variableParameter.ArrayIndexer, "integer", 0, context), - GetParameter(valueParameter, type, 1, context))); - } - else - { - context.Renderer.Render(SyntaxFactory.SetStatement( - $"udg_{variableParameter.Value}", - GetParameter(valueParameter, type, 1, context))); + variableName = JassExpression.ElementAccess( + variableName, + GetParameter(variableParameter.ArrayIndexer, "integer", 0, context.TrigFunctionIdentifierBuilder)); } - context.Renderer.RenderNewLine(); + context.Writer.WriteSet( + variableName, + GetParameter(valueParameter, type, 1, context.TrigFunctionIdentifierBuilder)); } } } \ No newline at end of file diff --git a/src/War3Net.Build/TriggerRenderer/TriggerActionRenderer.cs b/src/War3Net.Build/TriggerRenderer/TriggerActionRenderer.cs index 85a7e3d7..e695412b 100644 --- a/src/War3Net.Build/TriggerRenderer/TriggerActionRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/TriggerActionRenderer.cs @@ -8,13 +8,12 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text; +using System.Linq; using War3Net.Build.Script; +using War3Net.CodeAnalysis; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -33,35 +32,26 @@ private void RenderActionFunction(TrigFunctionIdentifierBuilder identifierBuilde throw new ArgumentException("Parameter function must be enabled and of type 'Action'.", nameof(parameter)); } - var stringBuilder = new StringBuilder(); - using var stringWriter = new StringWriter(stringBuilder); - var renderer = new JassRenderer(stringWriter); - - var context = new TriggerRendererContext(renderer, identifierBuilder); + using var writer = IndentedTextWriter.New(_writer); - renderer.Render(new JassFunctionCustomScriptAction(SyntaxFactory.FunctionDeclarator(functionName))); - renderer.RenderNewLine(); + var context = new TriggerRendererContext(writer, identifierBuilder); + writer.WriteFunction(functionName); RenderTriggerAction(function, context); + writer.EndFunction(); - renderer.Render(JassEndFunctionCustomScriptAction.Value); - renderer.RenderNewLine(); - - _writer.WriteLine(stringBuilder.ToString()); + _writer.WriteLine(writer.ToString()); } private void RenderActionFunction(TrigFunctionIdentifierBuilder identifierBuilder, string functionName, List functions) { identifierBuilder.Append("Func"); - var stringBuilder = new StringBuilder(); - using var stringWriter = new StringWriter(stringBuilder); - var renderer = new JassRenderer(stringWriter); + using var writer = IndentedTextWriter.New(_writer); - var context = new TriggerRendererContext(renderer, identifierBuilder); + var context = new TriggerRendererContext(writer, identifierBuilder); - renderer.Render(new JassFunctionCustomScriptAction(SyntaxFactory.FunctionDeclarator(functionName))); - renderer.RenderNewLine(); + writer.WriteFunction(functionName); for (var i = 0; i < functions.Count; i++) { @@ -76,10 +66,9 @@ private void RenderActionFunction(TrigFunctionIdentifierBuilder identifierBuilde context.TrigFunctionIdentifierBuilder.Remove(); } - renderer.Render(JassEndFunctionCustomScriptAction.Value); - renderer.RenderNewLine(); + writer.EndFunction(); - _writer.WriteLine(stringBuilder.ToString()); + _writer.WriteLine(writer.ToString()); identifierBuilder.Remove(); } @@ -125,37 +114,32 @@ private void RenderTriggerAction(TriggerFunction function, TriggerRendererContex break; case "CommentString": - context.Renderer.Render(new JassCommentSyntax(" " + function.Parameters[0].Value)); - context.Renderer.RenderNewLine(); + context.Writer.WriteComment(function.Parameters[0].Value); break; case "CustomScriptCode": if (_isLuaTrigger) { - context.Renderer.Render(new JassCommentSyntax("! beginusercode")); - context.Renderer.RenderNewLine(); - - context.Renderer.RenderLine(function.Parameters[0].Value); - - context.Renderer.Render(new JassCommentSyntax("! endusercode")); - context.Renderer.RenderNewLine(); + context.Writer.WriteLine("//! beginusercode"); + context.Writer.WriteLine(function.Parameters[0].Value); + context.Writer.WriteLine("//! endusercode"); } else { - context.Renderer.Render(SyntaxFactory.ParseStatementLine(function.Parameters[0].Value)); - context.Renderer.RenderNewLine(); + context.Writer.WriteLine(function.Parameters[0].Value); } break; case "ReturnAction": - context.Renderer.Render(JassReturnStatementSyntax.Empty); - context.Renderer.RenderNewLine(); + context.Writer.WriteReturn(); break; default: - context.Renderer.Render(SyntaxFactory.CallStatement(GetScriptName(function), GetParameters(function, context))); - context.Renderer.RenderNewLine(); + context.Writer.WriteCall( + GetScriptName(function), + GetParameters(function, context.TrigFunctionIdentifierBuilder).ToArray()); + break; } } diff --git a/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs b/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs index e2a2d65a..de3ba0c2 100644 --- a/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs @@ -8,13 +8,12 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text; +using System.Linq; using War3Net.Build.Script; +using War3Net.CodeAnalysis; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Syntax; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -33,38 +32,29 @@ private void RenderConditionFunction(TrigFunctionIdentifierBuilder identifierBui throw new ArgumentException("Parameter function must be enabled and of type 'Condition'.", nameof(parameter)); } - var stringBuilder = new StringBuilder(); - using var stringWriter = new StringWriter(stringBuilder); - var renderer = new JassRenderer(stringWriter); + using var writer = IndentedTextWriter.New(_writer); - var context = new TriggerRendererContext(renderer, identifierBuilder); + var context = new TriggerRendererContext(writer, identifierBuilder); - renderer.Render(new JassFunctionCustomScriptAction(SyntaxFactory.ConditionFunctionDeclarator(functionName))); - renderer.RenderNewLine(); + writer.WriteFilterFunction(functionName); var expression = GetTriggerConditionExpression(function, context); - renderer.Render(new JassReturnStatementSyntax(expression)); - renderer.RenderNewLine(); - - renderer.Render(JassEndFunctionCustomScriptAction.Value); - renderer.RenderNewLine(); + writer.WriteReturn(expression); + writer.EndFunction(); - _writer.WriteLine(stringBuilder.ToString()); + _writer.WriteLine(writer.ToString()); } private void RenderConditionFunction(TrigFunctionIdentifierBuilder identifierBuilder, string functionName, bool returnValue, List functions) { identifierBuilder.Append("Func"); - var stringBuilder = new StringBuilder(); - using var stringWriter = new StringWriter(stringBuilder); - var renderer = new JassRenderer(stringWriter); + using var writer = IndentedTextWriter.New(_writer); - var context = new TriggerRendererContext(renderer, identifierBuilder); + var context = new TriggerRendererContext(writer, identifierBuilder); - renderer.Render(new JassFunctionCustomScriptAction(SyntaxFactory.ConditionFunctionDeclarator(functionName))); - renderer.RenderNewLine(); + writer.WriteFilterFunction(functionName); for (var i = 0; i < functions.Count; i++) { @@ -80,32 +70,27 @@ private void RenderConditionFunction(TrigFunctionIdentifierBuilder identifierBui if (returnValue) { - context.Renderer.Render(SyntaxFactory.IfStatement( - SyntaxFactory.ParenthesizedExpression(SyntaxFactory.UnaryNotExpression(expression)), - new JassReturnStatementSyntax(JassBooleanLiteralExpressionSyntax.False))); - context.Renderer.RenderNewLine(); + writer.WriteIf(JassExpression.Parenthesized(JassExpression.Not(expression))); + writer.WriteReturn(JassKeyword.False); + writer.WriteEndIf(); } else { - context.Renderer.Render(SyntaxFactory.IfStatement( - SyntaxFactory.ParenthesizedExpression(expression), - new JassReturnStatementSyntax(JassBooleanLiteralExpressionSyntax.True))); - context.Renderer.RenderNewLine(); + writer.WriteIf(JassExpression.Parenthesized(expression)); + writer.WriteReturn(JassKeyword.True); + writer.WriteEndIf(); } } - context.Renderer.Render(new JassReturnStatementSyntax(SyntaxFactory.LiteralExpression(returnValue))); - context.Renderer.RenderNewLine(); - - renderer.Render(JassEndFunctionCustomScriptAction.Value); - renderer.RenderNewLine(); + writer.WriteReturn(JassLiteral.Bool(returnValue)); + writer.EndFunction(); - _writer.WriteLine(stringBuilder.ToString()); + _writer.WriteLine(writer.ToString()); identifierBuilder.Remove(); } - private IExpressionSyntax GetTriggerConditionExpression(TriggerFunction function, TriggerRendererContext context) + private string GetTriggerConditionExpression(TriggerFunction function, TriggerRendererContext context) { if (function.Type != TriggerFunctionType.Condition || !function.IsEnabled) { @@ -117,7 +102,7 @@ private IExpressionSyntax GetTriggerConditionExpression(TriggerFunction function var conditionFunctionName = $"{context.TrigFunctionIdentifierBuilder}C"; RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, function.Name == "AndMultiple", function.ChildFunctions); - return SyntaxFactory.InvocationExpression(conditionFunctionName); + return JassExpression.Invoke(conditionFunctionName); } else if (function.Name == "GetBooleanAnd" || function.Name == "GetBooleanOr") { @@ -131,19 +116,19 @@ private IExpressionSyntax GetTriggerConditionExpression(TriggerFunction function RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName2, function.Parameters[1]); context.TrigFunctionIdentifierBuilder.Remove(); - return SyntaxFactory.InvocationExpression( + return JassExpression.InvokeSpaced( function.Name, - SyntaxFactory.InvocationExpression(conditionFunctionName1), - SyntaxFactory.InvocationExpression(conditionFunctionName2)); + JassExpression.Invoke(conditionFunctionName1), + JassExpression.Invoke(conditionFunctionName2)); } else { - var parameters = GetParameters(function, context); + var parameters = GetParameters(function, context.TrigFunctionIdentifierBuilder).ToArray(); - return SyntaxFactory.ParenthesizedExpression(SyntaxFactory.BinaryExpression( - parameters.Arguments[0], - parameters.Arguments[2], - SyntaxFactory.ParseBinaryOperator(((JassStringLiteralExpressionSyntax)parameters.Arguments[1]).Value))); + return JassExpression.Parenthesized(JassExpression.Binary( + parameters[0], + parameters[1], + parameters[2])); } } } diff --git a/src/War3Net.Build/TriggerRenderer/WaitForConditionRenderer.cs b/src/War3Net.Build/TriggerRenderer/WaitForConditionRenderer.cs index 92754706..38900f3a 100644 --- a/src/War3Net.Build/TriggerRenderer/WaitForConditionRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/WaitForConditionRenderer.cs @@ -6,8 +6,8 @@ // ------------------------------------------------------------------------------ using War3Net.Build.Script; - -using SyntaxFactory = War3Net.CodeAnalysis.Jass.JassSyntaxFactory; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { @@ -22,15 +22,17 @@ private void RenderWaitForCondition(TriggerFunction function, TriggerRendererCon RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, function.Parameters[0]); context.TrigFunctionIdentifierBuilder.Remove(); - context.Renderer.Render(SyntaxFactory.LoopStatement( - SyntaxFactory.ExitStatement(SyntaxFactory.ParenthesizedExpression(SyntaxFactory.InvocationExpression(conditionFunctionName))), - SyntaxFactory.CallStatement( - WellKnownNatives.TriggerSleepAction, - SyntaxFactory.InvocationExpression( - WellKnownFunctions.RMaxBJ, - SyntaxFactory.VariableReferenceExpression("bj_WAIT_FOR_COND_MIN_INTERVAL"), - GetParameter(function.Parameters[1], argumentTypes[1], 1, context))))); - context.Renderer.RenderNewLine(); + context.Writer.WriteLoop(); + context.Writer.WriteExitWhen(JassExpression.Parenthesized(JassExpression.Invoke(conditionFunctionName))); + + context.Writer.WriteCallCompact( + WellKnownNatives.TriggerSleepAction, + JassExpression.Invoke( + WellKnownFunctions.RMaxBJ, + "bj_WAIT_FOR_COND_MIN_INTERVAL", + GetParameter(function.Parameters[1], argumentTypes[1], 1, context.TrigFunctionIdentifierBuilder))); + + context.Writer.WriteEndLoop(); } } } \ No newline at end of file diff --git a/src/War3Net.Build/TriggerRendererContext.cs b/src/War3Net.Build/TriggerRendererContext.cs index e1573bf5..932d88a9 100644 --- a/src/War3Net.Build/TriggerRendererContext.cs +++ b/src/War3Net.Build/TriggerRendererContext.cs @@ -5,22 +5,24 @@ // // ------------------------------------------------------------------------------ -using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis; namespace War3Net.Build { public class TriggerRendererContext { - private readonly JassRenderer _renderer; + private readonly IndentedTextWriter _writer; private readonly TrigFunctionIdentifierBuilder _builder; - public TriggerRendererContext(JassRenderer renderer, TrigFunctionIdentifierBuilder builder) + public TriggerRendererContext( + IndentedTextWriter writer, + TrigFunctionIdentifierBuilder builder) { - _renderer = renderer; + _writer = writer; _builder = builder; } - public JassRenderer Renderer => _renderer; + public IndentedTextWriter Writer => _writer; public TrigFunctionIdentifierBuilder TrigFunctionIdentifierBuilder => _builder; } diff --git a/src/War3Net.Build.Core/Providers/EscapedStringProvider.cs b/src/War3Net.CodeAnalysis.Jass/EscapedStringProvider.cs similarity index 98% rename from src/War3Net.Build.Core/Providers/EscapedStringProvider.cs rename to src/War3Net.CodeAnalysis.Jass/EscapedStringProvider.cs index 92990a96..367ed29f 100644 --- a/src/War3Net.Build.Core/Providers/EscapedStringProvider.cs +++ b/src/War3Net.CodeAnalysis.Jass/EscapedStringProvider.cs @@ -8,7 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace War3Net.Build.Providers +namespace War3Net.CodeAnalysis.Jass { // Based on https://referencesource.microsoft.com/#System/regex/system/text/regularexpressions/RegexParser.cs,845bf727ea7a0421 public static class EscapedStringProvider diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/IndentedTextWriterExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/IndentedTextWriterExtensions.cs new file mode 100644 index 00000000..c9fec4f1 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/IndentedTextWriterExtensions.cs @@ -0,0 +1,296 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass.Extensions +{ + public static class IndentedTextWriterExtensions + { + public static void WriteComment(this IndentedTextWriter writer, string comment) + { + writer.Write("// "); + writer.WriteLine(comment); + } + + public static void WriteFunction(this IndentedTextWriter writer, string functionName) + { + writer.Write(JassKeyword.Function); + writer.Write(' '); + writer.Write(functionName); + writer.Write(' '); + writer.Write(JassKeyword.Takes); + writer.Write(' '); + writer.Write(JassKeyword.Nothing); + writer.Write(' '); + writer.Write(JassKeyword.Returns); + writer.Write(' '); + writer.Write(JassKeyword.Nothing); + writer.WriteLine(); + writer.Indent(); + } + + public static void WriteFilterFunction(this IndentedTextWriter writer, string functionName) + { + writer.Write(JassKeyword.Function); + writer.Write(' '); + writer.Write(functionName); + writer.Write(' '); + writer.Write(JassKeyword.Takes); + writer.Write(' '); + writer.Write(JassKeyword.Nothing); + writer.Write(' '); + writer.Write(JassKeyword.Returns); + writer.Write(' '); + writer.Write(JassKeyword.Boolean); + writer.WriteLine(); + writer.Indent(); + } + + public static void EndFunction(this IndentedTextWriter writer) + { + writer.Unindent(); + writer.WriteLine(JassKeyword.EndFunction); + } + + public static void WriteLocal(this IndentedTextWriter writer, string typeName, string variableName) + { + writer.Write(JassKeyword.Local); + writer.Write(' '); + writer.Write(typeName); + writer.Write(' '); + writer.WriteLine(variableName); + } + + public static void WriteLocal(this IndentedTextWriter writer, string typeName, string variableName, string initialValue) + { + writer.Write(JassKeyword.Local); + writer.Write(' '); + writer.Write(typeName); + writer.Write(' '); + writer.Write(variableName); + writer.Write(" = "); + writer.WriteLine(initialValue); + } + + public static void WriteAlignedLocal( + this IndentedTextWriter writer, + string typeName, + string variableName, + string initialValue, + int typeColumnWidth = 8, + int variableNameColumnWidth = 11) + { + writer.Write(JassKeyword.Local); + writer.Write(' '); + writer.Write(typeName); + var typePadding = typeColumnWidth - typeName.Length; + if (typePadding > 0) + { + writer.Write(new string(' ', typePadding)); + } + else + { + writer.Write(' '); + } + + writer.Write(variableName); + + var namePadding = variableNameColumnWidth - variableName.Length; + if (namePadding > 0) + { + writer.Write(new string(' ', namePadding)); + } + else + { + writer.Write(' '); + } + + writer.Write("= "); + writer.WriteLine(initialValue); + } + + public static void WriteAlignedGlobal( + this IndentedTextWriter writer, + string typeName, + string variableName, + int typeColumnWidth = 24) + { + writer.Write(typeName); + var typePadding = typeColumnWidth - typeName.Length; + if (typePadding > 0) + { + writer.Write(new string(' ', typePadding)); + } + else + { + writer.Write(' '); + } + + writer.WriteLine(variableName); + } + + public static void WriteAlignedGlobal( + this IndentedTextWriter writer, + string typeName, + string variableName, + string value, + int typeColumnWidth = 24, + int variableNameColumnWidth = 27) + { + writer.Write(typeName); + var typePadding = typeColumnWidth - typeName.Length; + if (typePadding > 0) + { + writer.Write(new string(' ', typePadding)); + } + else + { + writer.Write(' '); + } + + writer.Write(variableName); + + var namePadding = variableNameColumnWidth - variableName.Length; + if (namePadding > 0) + { + writer.Write(new string(' ', namePadding)); + } + else + { + writer.Write(' '); + } + + writer.Write("= "); + writer.WriteLine(value); + } + + public static void WriteCall(this IndentedTextWriter writer, string functionName) + { + writer.Write(JassKeyword.Call); + writer.Write(' '); + writer.Write(functionName); + writer.Write("( )"); + writer.WriteLine(); + } + + public static void WriteCall(this IndentedTextWriter writer, string functionName, params string[] arguments) + { + writer.Write(JassKeyword.Call); + writer.Write(' '); + writer.Write(functionName); + writer.Write("( "); + for (var i = 0; i < arguments.Length; i++) + { + if (i > 0) + { + writer.Write(", "); + } + + writer.Write(arguments[i]); + } + + writer.Write(" )"); + writer.WriteLine(); + } + + public static void WriteCallCompact(this IndentedTextWriter writer, string functionName, params string[] arguments) + { + writer.Write(JassKeyword.Call); + writer.Write(' '); + writer.Write(functionName); + writer.Write('('); + for (var i = 0; i < arguments.Length; i++) + { + if (i > 0) + { + writer.Write(", "); + } + + writer.Write(arguments[i]); + } + + writer.Write(')'); + writer.WriteLine(); + } + + public static void WriteSet(this IndentedTextWriter writer, string variableName, string valueExpression) + { + writer.Write(JassKeyword.Set); + writer.Write(' '); + writer.Write(variableName); + writer.Write(" = "); + writer.WriteLine(valueExpression); + } + + public static void WriteIf(this IndentedTextWriter writer, string condition) + { + writer.Write(JassKeyword.If); + writer.Write(' '); + writer.Write(condition); + writer.Write(' '); + writer.Write(JassKeyword.Then); + writer.WriteLine(); + writer.Indent(); + } + + public static void WriteElseIf(this IndentedTextWriter writer, string condition) + { + writer.Unindent(); + writer.Write(JassKeyword.ElseIf); + writer.Write(' '); + writer.Write(condition); + writer.Write(' '); + writer.Write(JassKeyword.Then); + writer.WriteLine(); + writer.Indent(); + } + + public static void WriteElse(this IndentedTextWriter writer) + { + writer.Unindent(); + writer.WriteLine(JassKeyword.Else); + writer.Indent(); + } + + public static void WriteEndIf(this IndentedTextWriter writer) + { + writer.Unindent(); + writer.Write(JassKeyword.EndIf); + writer.WriteLine(); + } + + public static void WriteLoop(this IndentedTextWriter writer) + { + writer.WriteLine(JassKeyword.Loop); + writer.Indent(); + } + + public static void WriteExitWhen(this IndentedTextWriter writer, string condition) + { + writer.Write(JassKeyword.ExitWhen); + writer.Write(' '); + writer.WriteLine(condition); + } + + public static void WriteEndLoop(this IndentedTextWriter writer) + { + writer.Unindent(); + writer.WriteLine(JassKeyword.EndLoop); + } + + public static void WriteReturn(this IndentedTextWriter writer) + { + writer.WriteLine(JassKeyword.Return); + } + + public static void WriteReturn(this IndentedTextWriter writer, string expression) + { + writer.Write(JassKeyword.Return); + writer.Write(' '); + writer.WriteLine(expression); + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassExpression.cs b/src/War3Net.CodeAnalysis.Jass/JassExpression.cs new file mode 100644 index 00000000..b263f0f0 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassExpression.cs @@ -0,0 +1,137 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.CodeAnalysis.Jass +{ + public static class JassExpression + { + public static string FunctionRef(string functionName) + { + return $"{JassKeyword.Function} {functionName}"; + } + + public static string Invoke(string functionName) + { + return $"{functionName}()"; + } + + public static string Invoke(string functionName, params string[] arguments) + { + return $"{functionName}({string.Join(", ", arguments)})"; + } + + public static string InvokeCompact(string functionName, params string[] arguments) + { + return $"{functionName}({string.Join(",", arguments)})"; + } + + public static string InvokeSpaced(string functionName, params string[] arguments) + { + return $"{functionName}( {string.Join(", ", arguments)} )"; + } + + public static string Not(string expression) + { + return $"{JassKeyword.Not} {expression}"; + } + + public static string Negate(string expression) + { + return $"-{expression}"; + } + + public static string And(string left, string right) + { + return $"{left} {JassKeyword.And} {right}"; + } + + public static string Or(string left, string right) + { + return $"{left} {JassKeyword.Or} {right}"; + } + + public static string Equal(string left, string right) + { + return $"{left} == {right}"; + } + + public static string EqualCompact(string left, string right) + { + return $"{left}=={right}"; + } + + public static string NotEqual(string left, string right) + { + return $"{left} != {right}"; + } + + public static string Add(string left, string right) + { + return $"{left} + {right}"; + } + + public static string Subtract(string left, string right) + { + return $"{left} - {right}"; + } + + public static string Multiply(string left, string right) + { + return $"{left} * {right}"; + } + + public static string Divide(string left, string right) + { + return $"{left} / {right}"; + } + + public static string LessThan(string left, string right) + { + return $"{left} < {right}"; + } + + public static string LessThanOrEqual(string left, string right) + { + return $"{left} <= {right}"; + } + + public static string GreaterThan(string left, string right) + { + return $"{left} > {right}"; + } + + public static string GreaterThanOrEqual(string left, string right) + { + return $"{left} >= {right}"; + } + + public static string Binary(string left, string @operator, string right) + { + return $"{left} {@operator} {right}"; + } + + public static string Parenthesized(string expression) + { + return $"( {expression} )"; + } + + public static string ParenthesizedCompact(string expression) + { + return $"({expression})"; + } + + public static string ElementAccess(string arrayName, int index) + { + return $"{arrayName}[{index}]"; + } + + public static string ElementAccess(string arrayName, string index) + { + return $"{arrayName}[{index}]"; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs b/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs new file mode 100644 index 00000000..ad3df820 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Globalization; + +using War3Net.Common.Extensions; + +namespace War3Net.CodeAnalysis.Jass +{ + public static class JassLiteral + { + public static string Int(int value) + { + return value.ToString(CultureInfo.InvariantCulture); + } + + public static string Real(float value, int decimals = 1) + { + var rounded = MathF.Round(value, decimals, MidpointRounding.AwayFromZero); + var format = $"0.{new string('0', decimals)}"; + return rounded.ToString(format, CultureInfo.InvariantCulture); + } + + public static string Real(double value, int decimals = 1) + { + var rounded = Math.Round(value, decimals, MidpointRounding.AwayFromZero); + var format = $"0.{new string('0', decimals)}"; + return rounded.ToString(format, CultureInfo.InvariantCulture); + } + + public static string String(string? value) + { + return $"{JassSymbol.DoubleQuoteChar}{EscapedStringProvider.GetEscapedString(value ?? string.Empty)}{JassSymbol.DoubleQuoteChar}"; + } + + public static string Bool(bool value) + { + return value ? JassKeyword.True : JassKeyword.False; + } + + public static string FourCC(int value) + { + return $"{JassSymbol.SingleQuoteChar}{value.ToRawcode()}{JassSymbol.SingleQuoteChar}"; + } + + public static string FourCC(string value) + { + return $"{JassSymbol.SingleQuoteChar}{value}{JassSymbol.SingleQuoteChar}"; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis/IndentedTextWriter.cs b/src/War3Net.CodeAnalysis/IndentedTextWriter.cs new file mode 100644 index 00000000..2ebf5132 --- /dev/null +++ b/src/War3Net.CodeAnalysis/IndentedTextWriter.cs @@ -0,0 +1,143 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.IO; +using System.Text; + +namespace War3Net.CodeAnalysis +{ + public sealed class IndentedTextWriter : TextWriter + { + private const string DefaultIndentString = " "; + + private readonly TextWriter _writer; + private readonly string _indentString; + private int _indentLevel; + private bool _needsIndent; + + public IndentedTextWriter(TextWriter writer) + : this(writer, DefaultIndentString) + { + } + + public IndentedTextWriter(TextWriter writer, string indentString) + { + _writer = writer ?? throw new ArgumentNullException(nameof(writer)); + _indentString = indentString ?? throw new ArgumentNullException(nameof(indentString)); + _needsIndent = true; + } + + /// The existing from which to copy indent and newline strings. + public static IndentedTextWriter New(IndentedTextWriter writer) + { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var stringWriter = new StringWriter + { + NewLine = writer.NewLine, + }; + + return new IndentedTextWriter(stringWriter, writer.IndentString); + } + + public override Encoding Encoding => _writer.Encoding; + + public override string NewLine => _writer.NewLine; + + public string IndentString => _indentString; + + public int IndentLevel + { + get => _indentLevel; + set => _indentLevel = value < 0 ? 0 : value; + } + + public void Indent() => _indentLevel++; + + public void Unindent() + { + if (_indentLevel == 0) + { + throw new InvalidOperationException("Cannot unindent when indent level is 0."); + } + + _indentLevel--; + } + + public override void Write(char value) + { + if (_needsIndent) + { + WriteIndent(); + } + + _writer.Write(value); + + _needsIndent = value == '\n' || value == '\r'; + } + + public override void Write(string? value) + { + if (string.IsNullOrEmpty(value)) + { + return; + } + + if (_needsIndent) + { + WriteIndent(); + } + + _writer.Write(value); + + _needsIndent = value.EndsWith('\n') || value.EndsWith('\r'); + } + + public override void WriteLine() + { + _writer.WriteLine(); + _needsIndent = true; + } + + public override void WriteLine(string? value) + { + if (_needsIndent) + { + WriteIndent(); + } + + _writer.WriteLine(value); + _needsIndent = true; + } + + public override string? ToString() => _writer.ToString(); + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _writer.Dispose(); + } + + base.Dispose(disposing); + } + + private void WriteIndent() + { + for (var i = 0; i < _indentLevel; i++) + { + _writer.Write(_indentString); + } + + _needsIndent = false; + } + } +} \ No newline at end of file From f06c21a876bfd3f50c0294c131b7045c33c1a34d Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:14:02 +0100 Subject: [PATCH 12/53] JassTypeDeclarationSyntax bugfix. --- .../Syntax/JassTypeDeclarationSyntax.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs index 7e89b4d0..ec6de54d 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassTypeDeclarationSyntax.cs @@ -73,7 +73,7 @@ public override IEnumerable GetChildNodesAndTokens() public override IEnumerable GetDescendantNodes() { yield return IdentifierName; - foreach (var descendant in BaseType.GetDescendantNodes()) + foreach (var descendant in IdentifierName.GetDescendantNodes()) { yield return descendant; } @@ -89,7 +89,7 @@ public override IEnumerable GetDescendantTokens() { yield return TypeToken; - foreach (var descendant in BaseType.GetDescendantTokens()) + foreach (var descendant in IdentifierName.GetDescendantTokens()) { yield return descendant; } @@ -107,7 +107,7 @@ public override IEnumerable GetDescendantNodesAndTokens() yield return TypeToken; yield return IdentifierName; - foreach (var descendant in BaseType.GetDescendantNodesAndTokens()) + foreach (var descendant in IdentifierName.GetDescendantNodesAndTokens()) { yield return descendant; } From 668c0cd2f9c3967093e3a2779575a8f1d0b5c882 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:25:59 +0100 Subject: [PATCH 13/53] Fix DiffAssert failing without showing any changed lines. --- .../DiffAssert.cs | 7 +++++ .../StringHelper.cs | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/War3Net.TestTools.UnitTesting/StringHelper.cs diff --git a/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs b/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs index 242acb1f..d49fd2a7 100644 --- a/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs +++ b/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs @@ -143,6 +143,13 @@ private static string BuildDiffMessage(string expected, string actual) messageBuilder.AppendLine($" Lines deleted: {deletedLines}"); messageBuilder.AppendLine($" Lines modified: {modifiedLines}"); + if (addedLines == 0 && deletedLines == 0 && modifiedLines == 0) + { + return BuildDiffMessage( + StringHelper.ShowNewLineCharacters(expected), + StringHelper.ShowNewLineCharacters(actual)); + } + return messageBuilder.ToString(); } diff --git a/tests/War3Net.TestTools.UnitTesting/StringHelper.cs b/tests/War3Net.TestTools.UnitTesting/StringHelper.cs new file mode 100644 index 00000000..66cea568 --- /dev/null +++ b/tests/War3Net.TestTools.UnitTesting/StringHelper.cs @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace War3Net.TestTools.UnitTesting +{ + internal static class StringHelper + { + [return: NotNullIfNotNull(nameof(text))] + internal static string? ShowNewLineCharacters(string? text) + { + if (text is null) + { + return null; + } + + return text + .Replace("\r\n", "\\r\n", StringComparison.Ordinal) + .Replace("\n", "\\n\n", StringComparison.Ordinal) + .Replace("\r", "\\r\n", StringComparison.Ordinal); + } + } +} \ No newline at end of file From f327f194af5b02716fe65578b36c59f91fe470bc Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:36:12 +0100 Subject: [PATCH 14/53] Add DiffAssert.ContextLines to improve readability. --- .../DiffAssert.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs b/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs index d49fd2a7..58de5ca5 100644 --- a/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs +++ b/tests/War3Net.TestTools.UnitTesting/DiffAssert.cs @@ -6,6 +6,7 @@ // ------------------------------------------------------------------------------ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text; @@ -19,6 +20,12 @@ namespace War3Net.TestTools.UnitTesting { public static class DiffAssert { + /// + /// Gets or sets the number of context lines to show around differences in diff output. + /// Default is 3. + /// + public static int ContextLines { get; set; } = 3; + /// /// Asserts that two strings are equal, providing a detailed diff output if they are not. /// @@ -106,9 +113,42 @@ private static string BuildDiffMessage(string expected, string actual) var addedLines = 0; var deletedLines = 0; var modifiedLines = 0; + var contextBuffer = new Queue(); + var skippedLines = 0; + var unchangedLines = ContextLines; foreach (var line in diff.Lines) { + var isChange = line.Type != ChangeType.Unchanged && line.Type != ChangeType.Imaginary; + + if (line.Type == ChangeType.Unchanged && unchangedLines >= ContextLines) + { + contextBuffer.Enqueue($" {line.Text}"); + if (contextBuffer.Count > ContextLines) + { + contextBuffer.Dequeue(); + skippedLines++; + } + + continue; + } + + if (isChange) + { + if (skippedLines > 0) + { + messageBuilder.AppendLine($"... ({skippedLines} unchanged lines omitted) ..."); + skippedLines = 0; + } + + while (contextBuffer.Count > 0) + { + messageBuilder.AppendLine(contextBuffer.Dequeue()); + } + + unchangedLines = 0; + } + switch (line.Type) { case ChangeType.Inserted: @@ -133,10 +173,21 @@ private static string BuildDiffMessage(string expected, string actual) case ChangeType.Unchanged: messageBuilder.AppendLine($" {line.Text}"); + unchangedLines++; break; } } + if (contextBuffer.Count > 0) + { + skippedLines += contextBuffer.Count; + } + + if (skippedLines > 0) + { + messageBuilder.AppendLine($"... ({skippedLines} unchanged lines omitted) ..."); + } + messageBuilder.AppendLine(); messageBuilder.AppendLine("Summary:"); messageBuilder.AppendLine($" Lines added: {addedLines}"); From 3e9d99768a0688fd2e8b034438d65db8fb3522d2 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:13:01 +0100 Subject: [PATCH 15/53] Update MapScriptBuilderTests. --- .../MapScriptBuilder/Audio/InitSoundsTests.cs | 14 ++++++------ .../MapScriptBuilder/Common/ConfigTests.cs | 14 ++++++------ .../MapScriptBuilder/Common/MainTests.cs | 14 ++++++------ .../Environment/CreateCamerasTests.cs | 14 ++++++------ .../Environment/CreateRegionsTests.cs | 14 ++++++------ .../Info/InitAllyPrioritiesTests.cs | 14 ++++++------ .../Info/InitCustomPlayerSlotsTests.cs | 14 ++++++------ .../Info/InitCustomTeamsTests.cs | 22 +++++++++---------- .../Info/InitRandomGroupsTests.cs | 14 ++++++------ .../Script/InitCustomTriggersTests.cs | 14 ++++++------ .../Script/InitGlobalsTests.cs | 14 ++++++------ .../Script/RunInitializationTriggersTests.cs | 14 ++++++------ .../Widget/CreateAllDestructablesTests.cs | 14 ++++++------ .../Widget/CreateAllItemsTests.cs | 14 ++++++------ .../Widget/CreateAllUnitsTests.cs | 14 ++++++------ .../Widget/CreateNeutralHostileTests.cs | 14 ++++++------ .../CreateNeutralPassiveBuildingsTests.cs | 14 ++++++------ .../Widget/CreateNeutralPassiveTests.cs | 14 ++++++------ .../Widget/CreateNeutralUnitsTests.cs | 14 ++++++------ .../Widget/CreatePlayerBuildingsTests.cs | 14 ++++++------ .../Widget/CreatePlayerUnitsTests.cs | 14 ++++++------ .../Widget/DestructableItemTablesTests.cs | 2 +- .../MapScriptBuilderTestData.cs | 2 +- .../MapScriptBuilderTests.cs | 19 ++++++++++++++++ 24 files changed, 172 insertions(+), 153 deletions(-) diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Audio/InitSoundsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Audio/InitSoundsTests.cs index e239e501..689f279b 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Audio/InitSoundsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Audio/InitSoundsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitSounds), DynamicDataSourceType.Method)] public void TestBodyInitSounds(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitSounds"]; - var actual = testData.MapScriptBuilder.InitSounds(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitSounds, + writer => testData.MapScriptBuilder.GenerateInitSounds(testData.Map, writer)); } [FlakyTestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitSounds(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitSounds"); - var actual = testData.MapScriptBuilder.InitSoundsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitSounds); + var actual = testData.MapScriptBuilder.ShouldGenerateInitSounds(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionInitSounds(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("InitSounds")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitSounds)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Common/ConfigTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Common/ConfigTests.cs index b9206309..8cdf72ec 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Common/ConfigTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Common/ConfigTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataConfig), DynamicDataSourceType.Method)] public void TestBodyConfig(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["config"]; - var actual = testData.MapScriptBuilder.config(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.Config, + writer => testData.MapScriptBuilder.GenerateConfig(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionConfig(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("config"); - var actual = testData.MapScriptBuilder.configCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.Config); + var actual = testData.MapScriptBuilder.ShouldGenerateConfig(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionConfig(MapScriptBuilderTestData testData) { foreach (var testData in GetUnobfuscatedTestData()) { - if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey("config")) + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.Config)) { yield return testData; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Common/MainTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Common/MainTests.cs index 5f0eb45f..bc719328 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Common/MainTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Common/MainTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataMain), DynamicDataSourceType.Method)] public void TestBodyMain(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["main"]; - var actual = testData.MapScriptBuilder.main(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.Main, + writer => testData.MapScriptBuilder.GenerateMain(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionMain(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("main"); - var actual = testData.MapScriptBuilder.mainCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.Main); + var actual = testData.MapScriptBuilder.ShouldGenerateMain(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionMain(MapScriptBuilderTestData testData) { foreach (var testData in GetUnobfuscatedTestData()) { - if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey("main")) + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.Main)) { yield return testData; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateCamerasTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateCamerasTests.cs index 285b072b..c8f1a8eb 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateCamerasTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateCamerasTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateCameras), DynamicDataSourceType.Method)] public void TestBodyCreateCameras(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateCameras"]; - var actual = testData.MapScriptBuilder.CreateCameras(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateCameras, + writer => testData.MapScriptBuilder.GenerateCreateCameras(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateCameras(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateCameras"); - var actual = testData.MapScriptBuilder.CreateCamerasCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateCameras); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateCameras(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateCameras(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreateCameras")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateCameras)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateRegionsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateRegionsTests.cs index 628f14a2..555b326f 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateRegionsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Environment/CreateRegionsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateRegions), DynamicDataSourceType.Method)] public void TestBodyCreateRegions(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateRegions"]; - var actual = testData.MapScriptBuilder.CreateRegions(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateRegions, + writer => testData.MapScriptBuilder.GenerateCreateRegions(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateRegions(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateRegions"); - var actual = testData.MapScriptBuilder.CreateRegionsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateRegions); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateRegions(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateRegions(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreateRegions")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateRegions)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitAllyPrioritiesTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitAllyPrioritiesTests.cs index 8e7e1c1a..91f7ce07 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitAllyPrioritiesTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitAllyPrioritiesTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitAllyPriorities), DynamicDataSourceType.Method)] public void TestBodyInitAllyPriorities(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitAllyPriorities"]; - var actual = testData.MapScriptBuilder.InitAllyPriorities(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitAllyPriorities, + writer => testData.MapScriptBuilder.GenerateInitAllyPriorities(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitAllyPriorities(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitAllyPriorities"); - var actual = testData.MapScriptBuilder.InitAllyPrioritiesCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitAllyPriorities); + var actual = testData.MapScriptBuilder.ShouldGenerateInitAllyPriorities(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionInitAllyPriorities(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("InitAllyPriorities")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitAllyPriorities)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomPlayerSlotsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomPlayerSlotsTests.cs index bb80470e..3785643a 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomPlayerSlotsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomPlayerSlotsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitCustomPlayerSlots), DynamicDataSourceType.Method)] public void TestBodyInitCustomPlayerSlots(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitCustomPlayerSlots"]; - var actual = testData.MapScriptBuilder.InitCustomPlayerSlots(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitCustomPlayerSlots, + writer => testData.MapScriptBuilder.GenerateInitCustomPlayerSlots(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitCustomPlayerSlots(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitCustomPlayerSlots"); - var actual = testData.MapScriptBuilder.InitCustomPlayerSlotsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitCustomPlayerSlots); + var actual = testData.MapScriptBuilder.ShouldGenerateInitCustomPlayerSlots(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionInitCustomPlayerSlots(MapScriptBuilderTestData testData { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("InitCustomPlayerSlots")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitCustomPlayerSlots)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomTeamsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomTeamsTests.cs index 584099fd..96e95016 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomTeamsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitCustomTeamsTests.cs @@ -23,18 +23,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitCustomTeams), DynamicDataSourceType.Method)] public void TestBodyInitCustomTeams(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitCustomTeams"]; - var actual = testData.MapScriptBuilder.InitCustomTeams(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitCustomTeams, + writer => testData.MapScriptBuilder.GenerateInitCustomTeams(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitCustomTeams(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitCustomTeams"); - var actual = testData.MapScriptBuilder.InitCustomTeamsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitCustomTeams); + var actual = testData.MapScriptBuilder.ShouldGenerateInitCustomTeams(testData.Map); Assert.AreEqual(expected, actual); } @@ -43,12 +43,12 @@ public void TestConditionInitCustomTeams(MapScriptBuilderTestData testData) [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestInvokeConditionInitCustomTeams(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.TryGetValue("config", out var config) && - config.Body.Statements.Any(statement => + var expected = testData.DeclaredFunctions.TryGetValue(MapScriptBuilder.GeneratedFunctionName.Config, out var config) && + config.Statements.Any(statement => statement is JassCallStatementSyntax callStatement && - string.Equals(callStatement.IdentifierName.Name, "InitCustomTeams", StringComparison.Ordinal)); + string.Equals(callStatement.IdentifierName.Token.Text, MapScriptBuilder.GeneratedFunctionName.InitCustomTeams, StringComparison.Ordinal)); - var actual = testData.MapScriptBuilder.InitCustomTeamsInvokeCondition(testData.Map); + var actual = testData.MapScriptBuilder.ShouldCallInitCustomTeams(testData.Map); Assert.AreEqual(expected, actual); } @@ -57,7 +57,7 @@ statement is JassCallStatementSyntax callStatement && { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("InitCustomTeams")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitCustomTeams)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitRandomGroupsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitRandomGroupsTests.cs index 8456dfe3..cb1bc385 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitRandomGroupsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitRandomGroupsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitRandomGroups), DynamicDataSourceType.Method)] public void TestBodyInitRandomGroups(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitRandomGroups"]; - var actual = testData.MapScriptBuilder.InitRandomGroups(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitRandomGroups, + writer => testData.MapScriptBuilder.GenerateInitRandomGroups(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitRandomGroups(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitRandomGroups"); - var actual = testData.MapScriptBuilder.InitRandomGroupsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitRandomGroups); + var actual = testData.MapScriptBuilder.ShouldGenerateInitRandomGroups(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionInitRandomGroups(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("InitRandomGroups")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitRandomGroups)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitCustomTriggersTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitCustomTriggersTests.cs index bdbe6ef0..80e0b6a2 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitCustomTriggersTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitCustomTriggersTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitCustomTriggers), DynamicDataSourceType.Method)] public void TestBodyInitCustomTriggers(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitCustomTriggers"]; - var actual = testData.MapScriptBuilder.InitCustomTriggers(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitCustomTriggers, + writer => testData.MapScriptBuilder.GenerateInitCustomTriggers(testData.Map, writer)); } [FlakyTestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitCustomTriggers(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitCustomTriggers"); - var actual = testData.MapScriptBuilder.InitCustomTriggersCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitCustomTriggers); + var actual = testData.MapScriptBuilder.ShouldGenerateInitCustomTriggers(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionInitCustomTriggers(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (!testData.IsMeleeWithoutTrigger && testData.DeclaredFunctions.ContainsKey("InitCustomTriggers")) + if (!testData.IsMeleeWithoutTrigger && testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitCustomTriggers)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitGlobalsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitGlobalsTests.cs index ea2e432a..866b7001 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitGlobalsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Script/InitGlobalsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataInitGlobals), DynamicDataSourceType.Method)] public void TestBodyInitGlobals(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["InitGlobals"]; - var actual = testData.MapScriptBuilder.InitGlobals(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitGlobals, + writer => testData.MapScriptBuilder.GenerateInitGlobals(testData.Map, writer)); } [FlakyTestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionInitGlobals(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("InitGlobals"); - var actual = testData.MapScriptBuilder.InitGlobalsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitGlobals); + var actual = testData.MapScriptBuilder.ShouldGenerateInitGlobals(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionInitGlobals(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("InitGlobals")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitGlobals)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Script/RunInitializationTriggersTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Script/RunInitializationTriggersTests.cs index 438222ab..c1f78369 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Script/RunInitializationTriggersTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Script/RunInitializationTriggersTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataRunInitializationTriggers), DynamicDataSourceType.Method)] public void TestBodyRunInitializationTriggers(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["RunInitializationTriggers"]; - var actual = testData.MapScriptBuilder.RunInitializationTriggers(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.RunInitializationTriggers, + writer => testData.MapScriptBuilder.GenerateRunInitializationTriggers(testData.Map, writer)); } [FlakyTestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionRunInitializationTriggers(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("RunInitializationTriggers"); - var actual = testData.MapScriptBuilder.RunInitializationTriggersCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.RunInitializationTriggers); + var actual = testData.MapScriptBuilder.ShouldGenerateRunInitializationTriggers(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionRunInitializationTriggers(MapScriptBuilderTestData test { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("RunInitializationTriggers")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.RunInitializationTriggers)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllDestructablesTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllDestructablesTests.cs index 9e774e36..e16328bb 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllDestructablesTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllDestructablesTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateAllDestructables), DynamicDataSourceType.Method)] public void TestBodyCreateAllDestructables(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateAllDestructables"]; - var actual = testData.MapScriptBuilder.CreateAllDestructables(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateAllDestructables, + writer => testData.MapScriptBuilder.GenerateCreateAllDestructables(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateAllDestructables(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateAllDestructables"); - var actual = testData.MapScriptBuilder.CreateAllDestructablesCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateAllDestructables); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateAllDestructables(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateAllDestructables(MapScriptBuilderTestData testDat { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreateAllDestructables")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateAllDestructables)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllItemsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllItemsTests.cs index d70e1b39..56c80352 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllItemsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllItemsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateAllItems), DynamicDataSourceType.Method)] public void TestBodyCreateAllItems(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateAllItems"]; - var actual = testData.MapScriptBuilder.CreateAllItems(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateAllItems, + writer => testData.MapScriptBuilder.GenerateCreateAllItems(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateAllItems(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateAllItems"); - var actual = testData.MapScriptBuilder.CreateAllItemsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateAllItems); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateAllItems(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateAllItems(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreateAllItems")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateAllItems)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllUnitsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllUnitsTests.cs index 7670d027..041ce356 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllUnitsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateAllUnitsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateAllUnits), DynamicDataSourceType.Method)] public void TestBodyCreateAllUnits(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateAllUnits"]; - var actual = testData.MapScriptBuilder.CreateAllUnits(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateAllUnits, + writer => testData.MapScriptBuilder.GenerateCreateAllUnits(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateAllUnits(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateAllUnits"); - var actual = testData.MapScriptBuilder.CreateAllUnitsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateAllUnits); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateAllUnits(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateAllUnits(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreateAllUnits")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateAllUnits)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileTests.cs index 01dba9f3..3ad4a151 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateNeutralHostile), DynamicDataSourceType.Method)] public void TestBodyCreateNeutralHostile(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateNeutralHostile"]; - var actual = testData.MapScriptBuilder.CreateNeutralHostile(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateNeutralHostile, + writer => testData.MapScriptBuilder.GenerateCreateNeutralHostile(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateNeutralHostile(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateNeutralHostile"); - var actual = testData.MapScriptBuilder.CreateNeutralHostileCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralHostile); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateNeutralHostile(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateNeutralHostile(MapScriptBuilderTestData testData) { foreach (var testData in GetUnobfuscatedTestData()) { - if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey("CreateNeutralHostile")) + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralHostile)) { yield return testData; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveBuildingsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveBuildingsTests.cs index c4abc6ac..b1cbaa8c 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveBuildingsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveBuildingsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateNeutralPassiveBuildings), DynamicDataSourceType.Method)] public void TestBodyCreateNeutralPassiveBuildings(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateNeutralPassiveBuildings"]; - var actual = testData.MapScriptBuilder.CreateNeutralPassiveBuildings(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateNeutralPassiveBuildings, + writer => testData.MapScriptBuilder.GenerateCreateNeutralPassiveBuildings(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateNeutralPassiveBuildings(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateNeutralPassiveBuildings"); - var actual = testData.MapScriptBuilder.CreateNeutralPassiveBuildingsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralPassiveBuildings); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateNeutralPassiveBuildings(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateNeutralPassiveBuildings(MapScriptBuilderTestData { foreach (var testData in GetUnobfuscatedTestData()) { - if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey("CreateNeutralPassiveBuildings")) + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralPassiveBuildings)) { yield return testData; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveTests.cs index 0209dbb8..f769e93a 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralPassiveTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateNeutralPassive), DynamicDataSourceType.Method)] public void TestBodyCreateNeutralPassive(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateNeutralPassive"]; - var actual = testData.MapScriptBuilder.CreateNeutralPassive(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateNeutralPassive, + writer => testData.MapScriptBuilder.GenerateCreateNeutralPassive(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateNeutralPassive(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateNeutralPassive"); - var actual = testData.MapScriptBuilder.CreateNeutralPassiveCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralPassive); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateNeutralPassive(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateNeutralPassive(MapScriptBuilderTestData testData) { foreach (var testData in GetUnobfuscatedTestData()) { - if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey("CreateNeutralPassive")) + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralPassive)) { yield return testData; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralUnitsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralUnitsTests.cs index 7ea5dc7d..024c07e6 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralUnitsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralUnitsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreateNeutralUnits), DynamicDataSourceType.Method)] public void TestBodyCreateNeutralUnits(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreateNeutralUnits"]; - var actual = testData.MapScriptBuilder.CreateNeutralUnits(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateNeutralUnits, + writer => testData.MapScriptBuilder.GenerateCreateNeutralUnits(testData.Map, writer)); } [TestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreateNeutralUnits(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreateNeutralUnits"); - var actual = testData.MapScriptBuilder.CreateNeutralUnitsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralUnits); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateNeutralUnits(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreateNeutralUnits(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreateNeutralUnits")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralUnits)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerBuildingsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerBuildingsTests.cs index da044b9d..8da5aaea 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerBuildingsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerBuildingsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreatePlayerBuildings), DynamicDataSourceType.Method)] public void TestBodyCreatePlayerBuildings(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreatePlayerBuildings"]; - var actual = testData.MapScriptBuilder.CreatePlayerBuildings(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreatePlayerBuildings, + writer => testData.MapScriptBuilder.GenerateCreatePlayerBuildings(testData.Map, writer)); } [FlakyTestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreatePlayerBuildings(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreatePlayerBuildings"); - var actual = testData.MapScriptBuilder.CreatePlayerBuildingsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreatePlayerBuildings); + var actual = testData.MapScriptBuilder.ShouldGenerateCreatePlayerBuildings(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreatePlayerBuildings(MapScriptBuilderTestData testData { foreach (var testData in GetUnobfuscatedTestData()) { - if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey("CreatePlayerBuildings")) + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreatePlayerBuildings)) { yield return testData; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerUnitsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerUnitsTests.cs index 891ea0af..50f80129 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerUnitsTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreatePlayerUnitsTests.cs @@ -19,18 +19,18 @@ public partial class MapScriptBuilderTests [DynamicData(nameof(GetTestDataCreatePlayerUnits), DynamicDataSourceType.Method)] public void TestBodyCreatePlayerUnits(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions["CreatePlayerUnits"]; - var actual = testData.MapScriptBuilder.CreatePlayerUnits(testData.Map); - - SyntaxAssert.AreEqual(expected, actual); + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreatePlayerUnits, + writer => testData.MapScriptBuilder.GenerateCreatePlayerUnits(testData.Map, writer)); } [FlakyTestMethod] [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] public void TestConditionCreatePlayerUnits(MapScriptBuilderTestData testData) { - var expected = testData.DeclaredFunctions.ContainsKey("CreatePlayerUnits"); - var actual = testData.MapScriptBuilder.CreatePlayerUnitsCondition(testData.Map); + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreatePlayerUnits); + var actual = testData.MapScriptBuilder.ShouldGenerateCreatePlayerUnits(testData.Map); Assert.AreEqual(expected, actual); } @@ -39,7 +39,7 @@ public void TestConditionCreatePlayerUnits(MapScriptBuilderTestData testData) { foreach (var testData in _testData) { - if (testData.DeclaredFunctions.ContainsKey("CreatePlayerUnits")) + if (testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreatePlayerUnits)) { yield return new object[] { testData }; } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/DestructableItemTablesTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/DestructableItemTablesTests.cs index 9cb708b6..402961f5 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/DestructableItemTablesTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/DestructableItemTablesTests.cs @@ -18,7 +18,7 @@ public partial class MapScriptBuilderTests public void TestConditionDestructableItemTables(MapScriptBuilderTestData testData) { var expected = testData.DeclaredFunctions.ContainsKey("DestructableItemTables"); - var actual = testData.MapScriptBuilder.DestructableItemTablesCondition(testData.Map); + var actual = testData.MapScriptBuilder.ShouldGenerateDestructableItemTables(testData.Map); Assert.AreEqual(expected, actual); } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilderTestData.cs b/tests/War3Net.Build.Tests/MapScriptBuilderTestData.cs index 9e320e04..60cd4f0b 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilderTestData.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilderTestData.cs @@ -29,7 +29,7 @@ public MapScriptBuilderTestData(Map map, JassCompilationUnitSyntax compilationUn { if (declaration is JassFunctionDeclarationSyntax functionDeclaration) { - builder.Add(functionDeclaration.FunctionDeclarator.IdentifierName.Name, functionDeclaration); + builder.Add(functionDeclaration.FunctionDeclarator.IdentifierName.Token.Text, functionDeclaration); } } diff --git a/tests/War3Net.Build.Tests/MapScriptBuilderTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilderTests.cs index 0c8da5ef..d124ab1a 100644 --- a/tests/War3Net.Build.Tests/MapScriptBuilderTests.cs +++ b/tests/War3Net.Build.Tests/MapScriptBuilderTests.cs @@ -5,6 +5,7 @@ // // ------------------------------------------------------------------------------ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -12,6 +13,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using War3Net.Build.Info; +using War3Net.CodeAnalysis; using War3Net.CodeAnalysis.Jass; using War3Net.TestTools.UnitTesting; @@ -49,5 +51,22 @@ private static IEnumerable GetMapPaths() { return TestDataProvider.GetDynamicData("*", SearchOption.AllDirectories, "Maps"); } + + private static void AssertFunctionGeneratedCorrectly( + MapScriptBuilderTestData testData, + string functionName, + Action generateFunc) + { + using var stringWriter = new StringWriter(); + stringWriter.NewLine = JassSymbol.CarriageReturnLineFeed; + using var writer = new IndentedTextWriter(stringWriter); + + generateFunc.Invoke(writer); + + var expected = testData.DeclaredFunctions[functionName]; + var actual = JassSyntaxFactory.ParseTopLevelDeclaration(stringWriter.ToString()); + + SyntaxAssert.AreEqual(expected, actual); + } } } \ No newline at end of file From f0a28cfd68a7a75e5833a238863906195b561a39 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:20:56 +0100 Subject: [PATCH 16/53] MapScriptBuilder fixes. --- src/War3Net.Build/TriggerRenderer.cs | 8 +++++++- .../TriggerRenderer/TriggerConditionRenderer.cs | 8 +++++++- src/War3Net.CodeAnalysis.Jass/JassLiteral.cs | 8 ++------ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/War3Net.Build/TriggerRenderer.cs b/src/War3Net.Build/TriggerRenderer.cs index a8bca8b1..57a1c1e9 100644 --- a/src/War3Net.Build/TriggerRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer.cs @@ -212,9 +212,15 @@ private string GetParameter(TriggerFunctionParameter parameter, string type, int { var parameters = GetParameters(parameter.Function, identifierBuilder).ToArray(); + var @operator = parameters[1]; + if (@operator.StartsWith('"') && @operator.EndsWith('"')) + { + @operator = @operator[1..^1]; + } + return JassExpression.ParenthesizedCompact(JassExpression.Binary( parameters[0], - parameters[1], + @operator, parameters[2])); } else if (string.Equals(scriptName, "OperatorString", StringComparison.Ordinal)) diff --git a/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs b/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs index de3ba0c2..40295bd0 100644 --- a/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs @@ -125,9 +125,15 @@ private string GetTriggerConditionExpression(TriggerFunction function, TriggerRe { var parameters = GetParameters(function, context.TrigFunctionIdentifierBuilder).ToArray(); + var @operator = parameters[1]; + if (@operator.StartsWith('"') && @operator.EndsWith('"')) + { + @operator = @operator[1..^1]; + } + return JassExpression.Parenthesized(JassExpression.Binary( parameters[0], - parameters[1], + @operator, parameters[2])); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs b/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs index ad3df820..a2312347 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs @@ -21,16 +21,12 @@ public static string Int(int value) public static string Real(float value, int decimals = 1) { - var rounded = MathF.Round(value, decimals, MidpointRounding.AwayFromZero); - var format = $"0.{new string('0', decimals)}"; - return rounded.ToString(format, CultureInfo.InvariantCulture); + return value.ToString($"F{decimals}", CultureInfo.InvariantCulture); } public static string Real(double value, int decimals = 1) { - var rounded = Math.Round(value, decimals, MidpointRounding.AwayFromZero); - var format = $"0.{new string('0', decimals)}"; - return rounded.ToString(format, CultureInfo.InvariantCulture); + return value.ToString($"F{decimals}", CultureInfo.InvariantCulture); } public static string String(string? value) From 6ea1ae5375908145853e814f1941d31c4e2e8d09 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:03:53 +0100 Subject: [PATCH 17/53] Update JassScriptDecompiler to use new JASS syntax classes. --- .../Audio/MapSoundsDecompiler.cs | 205 ++++++------- .../DecompilationContext.cs | 23 +- .../Environment/MapCamerasDecompiler.cs | 53 ++-- .../Environment/MapRegionsDecompiler.cs | 74 +++-- .../FunctionDeclarationContext.cs | 17 +- .../JassScriptDecompiler.cs | 8 +- .../Script/MapTriggersDecompiler.cs | 125 ++++---- .../Special/CustomScriptCodeDecompiler.cs | 15 - .../Script/Special/ForEachLoopDecompiler.cs | 14 +- .../Script/Special/ForLoopDecompiler.cs | 98 +++--- .../Script/Special/IfThenElseDecompiler.cs | 14 +- .../Special/WaitForConditionDecompiler.cs | 30 +- .../BinaryExpressionDecompiler.cs | 4 +- ...ompiler.cs => BinaryOperatorDecompiler.cs} | 10 +- .../BooleanLiteralExpressionDecompiler.cs | 8 +- .../CallStatementDecompiler.cs | 8 +- .../CharacterLiteralExpressionDecompiler.cs | 8 +- .../DecimalLiteralExpressionDecompiler.cs | 8 +- ...s => ElementAccessExpressionDecompiler.cs} | 22 +- .../FourCCLiteralExpressionDecompiler.cs | 12 +- .../HexadecimalLiteralExpressionDecompiler.cs | 12 +- ...ompiler.cs => IdentifierNameDecompiler.cs} | 18 +- .../IfStatementDecompiler.cs | 28 +- .../InvocationExpressionDecompiler.cs | 20 +- .../LiteralExpressionDecompiler.cs | 63 ++++ .../LoopStatementDecompiler.cs | 6 +- .../NullLiteralExpressionDecompiler.cs | 8 +- .../OctalLiteralExpressionDecompiler.cs | 8 +- .../RealLiteralExpressionDecompiler.cs | 8 +- .../SetStatementDecompiler.cs | 7 +- .../SyntaxDecompilers/StatementDecompiler.cs | 10 +- .../StatementListDecompiler.cs | 46 ++- .../StringLiteralExpressionDecompiler.cs | 15 +- ...mmentDecompiler.cs => TriviaDecompiler.cs} | 9 +- .../UnaryExpressionDecompiler.cs | 15 +- .../Script/TriggerCallFunctionDecompiler.cs | 14 +- .../TriggerConditionFunctionDecompiler.cs | 24 +- .../TriggerFunctionParameterDecompiler.cs | 47 +-- .../VariableDeclarationContext.cs | 11 +- .../Widget/MapUnitsDecompiler.cs | 286 +++++++++--------- 40 files changed, 707 insertions(+), 704 deletions(-) rename src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/{BinaryOperatorTypeDecompiler.cs => BinaryOperatorDecompiler.cs} (86%) rename src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/{ArrayReferenceExpressionDecompiler.cs => ElementAccessExpressionDecompiler.cs} (72%) rename src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/{VariableReferenceExpressionDecompiler.cs => IdentifierNameDecompiler.cs} (91%) create mode 100644 src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LiteralExpressionDecompiler.cs rename src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/{CommentDecompiler.cs => TriviaDecompiler.cs} (81%) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Audio/MapSoundsDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Audio/MapSoundsDecompiler.cs index d8297c7a..c9fe8ec2 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Audio/MapSoundsDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Audio/MapSoundsDecompiler.cs @@ -45,59 +45,54 @@ public bool TryDecompileMapSounds(JassFunctionDeclarationSyntax functionDeclarat var sounds = new Dictionary(StringComparer.Ordinal); - foreach (var statement in functionDeclaration.Body.Statements) + foreach (var statement in functionDeclaration.Statements) { - if (statement is JassCommentSyntax || - statement is JassEmptySyntax) + if (statement is JassSetStatementSyntax setStatement) { - continue; - } - else if (statement is JassSetStatementSyntax setStatement) - { - if (setStatement.Indexer is null && - setStatement.IdentifierName.Name.StartsWith("gg_snd_", StringComparison.Ordinal)) + if (setStatement.ElementAccessClause is null && + setStatement.IdentifierName.Token.Text.StartsWith("gg_snd_", StringComparison.Ordinal)) { if (setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpression && - string.Equals(invocationExpression.IdentifierName.Name, "CreateSound", StringComparison.Ordinal)) + string.Equals(invocationExpression.IdentifierName.Token.Text, "CreateSound", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 7 && - invocationExpression.Arguments.Arguments[0] is JassStringLiteralExpressionSyntax fileNameLiteralExpression && - invocationExpression.Arguments.Arguments[1] is JassBooleanLiteralExpressionSyntax loopingLiteralExpression && - invocationExpression.Arguments.Arguments[2] is JassBooleanLiteralExpressionSyntax is3DLiteralExpression && - invocationExpression.Arguments.Arguments[3] is JassBooleanLiteralExpressionSyntax stopWhenOutOfRangeLiteralExpression && - invocationExpression.Arguments.Arguments[4].TryGetIntegerExpressionValue(out var fadeInRate) && - invocationExpression.Arguments.Arguments[5].TryGetIntegerExpressionValue(out var fadeOutRate) && - invocationExpression.Arguments.Arguments[6] is JassStringLiteralExpressionSyntax eaxSettingLiteralExpression) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 7 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetNotNullStringExpressionValue(out var fileName) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetBooleanExpressionValue(out var looping) && + invocationExpression.ArgumentList.ArgumentList.Items[2].TryGetBooleanExpressionValue(out var is3D) && + invocationExpression.ArgumentList.ArgumentList.Items[3].TryGetBooleanExpressionValue(out var stopWhenOutOfRange) && + invocationExpression.ArgumentList.ArgumentList.Items[4].TryGetIntegerExpressionValue(out var fadeInRate) && + invocationExpression.ArgumentList.ArgumentList.Items[5].TryGetIntegerExpressionValue(out var fadeOutRate) && + invocationExpression.ArgumentList.ArgumentList.Items[6].TryGetNotNullStringExpressionValue(out var eaxSetting)) { var flags = (SoundFlags)0; - if (loopingLiteralExpression.Value) + if (looping) { flags |= SoundFlags.Looping; } - if (is3DLiteralExpression.Value) + if (is3D) { flags |= SoundFlags.Is3DSound; } - if (stopWhenOutOfRangeLiteralExpression.Value) + if (stopWhenOutOfRange) { flags |= SoundFlags.StopWhenOutOfRange; } - var filePath = Regex.Unescape(fileNameLiteralExpression.Value); + var filePath = Regex.Unescape(fileName); Context.ImportedFileNames.Add(filePath); - if (!is3DLiteralExpression.Value && !IsInternalSound(filePath)) + if (!is3D && !IsInternalSound(filePath)) { flags |= SoundFlags.UNK16; } - sounds.Add(setStatement.IdentifierName.Name, new Sound + sounds.Add(setStatement.IdentifierName.Token.Text, new Sound { - Name = setStatement.IdentifierName.Name, + Name = setStatement.IdentifierName.Token.Text, FilePath = filePath, - EaxSetting = eaxSettingLiteralExpression.Value, + EaxSetting = eaxSetting, Flags = flags, FadeInRate = fadeInRate, FadeOutRate = fadeOutRate, @@ -115,11 +110,11 @@ invocationExpression.Arguments.Arguments[3] is JassBooleanLiteralExpressionSynta return false; } } - else if (setStatement.Value.Expression is JassStringLiteralExpressionSyntax stringLiteralExpression) + else if (setStatement.Value.Expression.TryGetNotNullStringExpressionValue(out var musicFileName)) { var flags = SoundFlags.Music; - var filePath = Regex.Unescape(stringLiteralExpression.Value); + var filePath = Regex.Unescape(musicFileName); Context.ImportedFileNames.Add(filePath); if (!IsInternalSound(filePath)) @@ -127,9 +122,9 @@ invocationExpression.Arguments.Arguments[3] is JassBooleanLiteralExpressionSynta flags |= SoundFlags.UNK16; } - sounds.Add(setStatement.IdentifierName.Name, new Sound + sounds.Add(setStatement.IdentifierName.Token.Text, new Sound { - Name = setStatement.IdentifierName.Name, + Name = setStatement.IdentifierName.Token.Text, FilePath = filePath, EaxSetting = string.Empty, Flags = flags, @@ -149,18 +144,18 @@ invocationExpression.Arguments.Arguments[3] is JassBooleanLiteralExpressionSynta } else if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "SetSoundParamsFromLabel", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundParamsFromLabel", StringComparison.Ordinal)) { continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundFacialAnimationLabel", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundFacialAnimationLabel", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax stringLiteralExpression && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetNotNullStringExpressionValue(out var facialAnimationLabel) && + sounds.TryGetValue(variableName, out var sound)) { - sound.FacialAnimationLabel = stringLiteralExpression.Value; + sound.FacialAnimationLabel = facialAnimationLabel; } else { @@ -168,14 +163,14 @@ callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax string return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundFacialAnimationGroupLabel", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundFacialAnimationGroupLabel", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax stringLiteralExpression && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetNotNullStringExpressionValue(out var facialAnimationGroupLabel) && + sounds.TryGetValue(variableName, out var sound)) { - sound.FacialAnimationGroupLabel = stringLiteralExpression.Value; + sound.FacialAnimationGroupLabel = facialAnimationGroupLabel; } else { @@ -183,14 +178,14 @@ callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax string return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundFacialAnimationSetFilepath", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundFacialAnimationSetFilepath", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax stringLiteralExpression && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetNotNullStringExpressionValue(out var facialAnimationSetFilepath) && + sounds.TryGetValue(variableName, out var sound)) { - sound.FacialAnimationSetFilepath = stringLiteralExpression.Value; + sound.FacialAnimationSetFilepath = facialAnimationSetFilepath; } else { @@ -198,14 +193,14 @@ callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax string return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetDialogueSpeakerNameKey", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetDialogueSpeakerNameKey", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax stringLiteralExpression && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound) && - stringLiteralExpression.Value.StartsWith("TRIGSTR_", StringComparison.Ordinal) && - int.TryParse(stringLiteralExpression.Value["TRIGSTR_".Length..], NumberStyles.None, CultureInfo.InvariantCulture, out var dialogueSpeakerNameKey)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetNotNullStringExpressionValue(out var dialogueSpeakerNameKeyString) && + sounds.TryGetValue(variableName, out var sound) && + dialogueSpeakerNameKeyString.StartsWith("TRIGSTR_", StringComparison.Ordinal) && + int.TryParse(dialogueSpeakerNameKeyString["TRIGSTR_".Length..], NumberStyles.None, CultureInfo.InvariantCulture, out var dialogueSpeakerNameKey)) { sound.DialogueSpeakerNameKey = dialogueSpeakerNameKey; } @@ -215,14 +210,14 @@ callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax string return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetDialogueTextKey", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetDialogueTextKey", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax stringLiteralExpression && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound) && - stringLiteralExpression.Value.StartsWith("TRIGSTR_", StringComparison.Ordinal) && - int.TryParse(stringLiteralExpression.Value["TRIGSTR_".Length..], NumberStyles.None, CultureInfo.InvariantCulture, out var dialogueTextKey)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetNotNullStringExpressionValue(out var dialogueTextKeyString) && + sounds.TryGetValue(variableName, out var sound) && + dialogueTextKeyString.StartsWith("TRIGSTR_", StringComparison.Ordinal) && + int.TryParse(dialogueTextKeyString["TRIGSTR_".Length..], NumberStyles.None, CultureInfo.InvariantCulture, out var dialogueTextKey)) { sound.DialogueTextKey = dialogueTextKey; } @@ -232,16 +227,16 @@ callStatement.Arguments.Arguments[1] is JassStringLiteralExpressionSyntax string return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundDuration", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundDuration", StringComparison.Ordinal)) { continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundDistanceCutoff", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundDistanceCutoff", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var cutoff) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var cutoff) && + sounds.TryGetValue(variableName, out var sound)) { sound.DistanceCutoff = cutoff; } @@ -251,12 +246,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundChannel", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundChannel", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var channel) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var channel) && + sounds.TryGetValue(variableName, out var sound)) { sound.Channel = (SoundChannel)channel; } @@ -266,12 +261,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundVolume", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundVolume", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var volume) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var volume) && + sounds.TryGetValue(variableName, out var sound)) { sound.Volume = volume; } @@ -281,12 +276,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundPitch", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundPitch", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var pitch) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var pitch) && + sounds.TryGetValue(variableName, out var sound)) { sound.Pitch = pitch; } @@ -296,13 +291,13 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundDistances", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundDistances", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var minDist) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var maxDist) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var minDist) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var maxDist) && + sounds.TryGetValue(variableName, out var sound) && sound.Flags.HasFlag(SoundFlags.Is3DSound)) { sound.MinDistance = minDist; @@ -314,14 +309,14 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundConeAngles", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundConeAngles", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var inside) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var outside) && - callStatement.Arguments.Arguments[3].TryGetIntegerExpressionValue(out var outsideVolume) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var inside) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var outside) && + callStatement.ArgumentList.ArgumentList.Items[3].TryGetIntegerExpressionValue(out var outsideVolume) && + sounds.TryGetValue(variableName, out var sound) && sound.Flags.HasFlag(SoundFlags.Is3DSound)) { sound.ConeAngleInside = inside; @@ -334,14 +329,14 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetSoundConeOrientation", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundConeOrientation", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var y) && - callStatement.Arguments.Arguments[3].TryGetRealExpressionValue(out var z) && - sounds.TryGetValue(variableReferenceExpression.IdentifierName.Name, out var sound) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y) && + callStatement.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var z) && + sounds.TryGetValue(variableName, out var sound) && sound.Flags.HasFlag(SoundFlags.Is3DSound)) { sound.ConeOrientation = new(x, y, z); @@ -365,7 +360,7 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va } } - if (sounds.Any()) + if (sounds.Count > 0) { mapSounds = new MapSounds(formatVersion); mapSounds.Sounds.AddRange(sounds.Values); diff --git a/src/War3Net.CodeAnalysis.Decompilers/DecompilationContext.cs b/src/War3Net.CodeAnalysis.Decompilers/DecompilationContext.cs index e26efe73..e9564aa6 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/DecompilationContext.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/DecompilationContext.cs @@ -13,6 +13,7 @@ using War3Net.Build.Info; using War3Net.Build.Script; using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers @@ -46,34 +47,24 @@ public DecompilationContext(Map map, Campaign? campaign, TriggerData? triggerDat var compilationUnit = JassSyntaxFactory.ParseCompilationUnit(map.Script); - var comments = new List(); var functionDeclarationsBuilder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal); var variableDeclarationsBuilder = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal); foreach (var declaration in compilationUnit.Declarations) { - if (declaration is JassCommentSyntax comment) + if (declaration is JassFunctionDeclarationSyntax functionDeclaration) { - comments.Add(comment); + functionDeclarationsBuilder.Add(functionDeclaration.FunctionDeclarator.IdentifierName.Token.Text, new FunctionDeclarationContext(functionDeclaration)); } - else + else if (declaration is JassGlobalsDeclarationSyntax globalsDeclaration) { - if (declaration is JassFunctionDeclarationSyntax functionDeclaration) + foreach (var globalDeclaration in globalsDeclaration.GlobalDeclarations) { - functionDeclarationsBuilder.Add(functionDeclaration.FunctionDeclarator.IdentifierName.Name, new FunctionDeclarationContext(functionDeclaration, comments)); - } - else if (declaration is JassGlobalDeclarationListSyntax globalDeclarationList) - { - foreach (var declaration2 in globalDeclarationList.Globals) + if (globalDeclaration is JassGlobalVariableDeclarationSyntax globalVariableDeclaration) { - if (declaration2 is JassGlobalDeclarationSyntax globalDeclaration) - { - variableDeclarationsBuilder.Add(globalDeclaration.Declarator.IdentifierName.Name, new VariableDeclarationContext(globalDeclaration)); - } + variableDeclarationsBuilder.Add(globalVariableDeclaration.Declarator.GetIdentifierName().Token.Text, new VariableDeclarationContext(globalVariableDeclaration)); } } - - comments.Clear(); } } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Environment/MapCamerasDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Environment/MapCamerasDecompiler.cs index b8e4dc26..d2b38c5d 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Environment/MapCamerasDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Environment/MapCamerasDecompiler.cs @@ -43,25 +43,20 @@ public bool TryDecompileMapCameras(JassFunctionDeclarationSyntax functionDeclara var cameras = new Dictionary(StringComparer.Ordinal); - foreach (var statement in functionDeclaration.Body.Statements) + foreach (var statement in functionDeclaration.Statements) { - if (statement is JassCommentSyntax || - statement is JassEmptySyntax) + if (statement is JassSetStatementSyntax setStatement) { - continue; - } - else if (statement is JassSetStatementSyntax setStatement) - { - if (setStatement.Indexer is null && - setStatement.IdentifierName.Name.StartsWith("gg_cam_", StringComparison.Ordinal) && + if (setStatement.ElementAccessClause is null && + setStatement.IdentifierName.Token.Text.StartsWith("gg_cam_", StringComparison.Ordinal) && setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpression && - string.Equals(invocationExpression.IdentifierName.Name, "CreateCameraSetup", StringComparison.Ordinal)) + string.Equals(invocationExpression.IdentifierName.Token.Text, "CreateCameraSetup", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.IsEmpty) + if (invocationExpression.ArgumentList.ArgumentList.Items.IsEmpty) { - cameras.Add(setStatement.IdentifierName.Name, new Camera + cameras.Add(setStatement.IdentifierName.Token.Text, new Camera { - Name = setStatement.IdentifierName.Name["gg_cam_".Length..].Replace('_', ' '), + Name = setStatement.IdentifierName.Token.Text["gg_cam_".Length..].Replace('_', ' '), NearClippingPlane = useNewFormat ? default : 100f, }); } @@ -78,17 +73,17 @@ setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpres } else if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "CameraSetupSetField", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "CameraSetupSetField", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax cameraVariableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassVariableReferenceExpressionSyntax cameraFieldVariableReferenceExpression && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var value) && - callStatement.Arguments.Arguments[3].TryGetRealExpressionValue(out var duration) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var cameraVariableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIdentifierNameValue(out var cameraField) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var value) && + callStatement.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var duration) && duration == 0f && - cameras.TryGetValue(cameraVariableReferenceExpression.IdentifierName.Name, out var camera)) + cameras.TryGetValue(cameraVariableName, out var camera)) { - switch (cameraFieldVariableReferenceExpression.IdentifierName.Name) + switch (cameraField) { case "CAMERA_FIELD_ZOFFSET": camera.ZOffset = value; @@ -131,15 +126,15 @@ callStatement.Arguments.Arguments[1] is JassVariableReferenceExpressionSyntax ca return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "CameraSetupSetDestPosition", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "CameraSetupSetDestPosition", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax cameraVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var y) && - callStatement.Arguments.Arguments[3].TryGetRealExpressionValue(out var duration) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var cameraVariableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y) && + callStatement.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var duration) && duration == 0f && - cameras.TryGetValue(cameraVariableReferenceExpression.IdentifierName.Name, out var camera)) + cameras.TryGetValue(cameraVariableName, out var camera)) { camera.TargetPosition = new(x, y); } @@ -162,7 +157,7 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax ca } } - if (cameras.Any()) + if (cameras.Count > 0) { mapCameras = new MapCameras(formatVersion, useNewFormat); mapCameras.Cameras.AddRange(cameras.Values); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Environment/MapRegionsDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Environment/MapRegionsDecompiler.cs index c4569433..6dee22b7 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Environment/MapRegionsDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Environment/MapRegionsDecompiler.cs @@ -46,31 +46,29 @@ public bool TryDecompileMapRegions(JassFunctionDeclarationSyntax functionDeclara var createdRegions = new List(); var regions = new Dictionary(StringComparer.Ordinal); - foreach (var statement in functionDeclaration.Body.Statements) + foreach (var statement in functionDeclaration.Statements) { - if (statement is JassLocalVariableDeclarationStatementSyntax || - statement is JassCommentSyntax || - statement is JassEmptySyntax) + if (statement is JassLocalVariableDeclarationStatementSyntax) { continue; } else if (statement is JassSetStatementSyntax setStatement) { - if (setStatement.Indexer is null && + if (setStatement.ElementAccessClause is null && setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpression) { - if (setStatement.IdentifierName.Name.StartsWith("gg_rct_", StringComparison.Ordinal) && - string.Equals(invocationExpression.IdentifierName.Name, "Rect", StringComparison.Ordinal)) + if (setStatement.IdentifierName.Token.Text.StartsWith("gg_rct_", StringComparison.Ordinal) && + string.Equals(invocationExpression.IdentifierName.Token.Text, "Rect", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 4 && - invocationExpression.Arguments.Arguments[0].TryGetRealExpressionValue(out var minx) && - invocationExpression.Arguments.Arguments[1].TryGetRealExpressionValue(out var miny) && - invocationExpression.Arguments.Arguments[2].TryGetRealExpressionValue(out var maxx) && - invocationExpression.Arguments.Arguments[3].TryGetRealExpressionValue(out var maxy)) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 4 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetRealExpressionValue(out var minx) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var miny) && + invocationExpression.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var maxx) && + invocationExpression.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var maxy)) { currentRegion = new Region { - Name = setStatement.IdentifierName.Name["gg_rct_".Length..].Replace('_', ' '), + Name = setStatement.IdentifierName.Token.Text["gg_rct_".Length..].Replace('_', ' '), Left = minx, Bottom = miny, Right = maxx, @@ -82,9 +80,9 @@ statement is JassCommentSyntax || createdRegions.Add(currentRegion); - if (!regions.TryAdd(setStatement.IdentifierName.Name, currentRegion)) + if (!regions.TryAdd(setStatement.IdentifierName.Token.Text, currentRegion)) { - regions[setStatement.IdentifierName.Name] = currentRegion; + regions[setStatement.IdentifierName.Token.Text] = currentRegion; } } else @@ -93,15 +91,15 @@ statement is JassCommentSyntax || return false; } } - else if (string.Equals(setStatement.IdentifierName.Name, "we", StringComparison.Ordinal) && - string.Equals(invocationExpression.IdentifierName.Name, "AddWeatherEffect", StringComparison.Ordinal)) + else if (string.Equals(setStatement.IdentifierName.Token.Text, "we", StringComparison.Ordinal) && + string.Equals(invocationExpression.IdentifierName.Token.Text, "AddWeatherEffect", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 2 && - invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax regionVariableReferenceExpression && - invocationExpression.Arguments.Arguments[1] is JassFourCCLiteralExpressionSyntax fourCCLiteralExpression && - regions.TryGetValue(regionVariableReferenceExpression.IdentifierName.Name, out var region)) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 2 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var regionVariableName) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var weatherTypeValue) && + regions.TryGetValue(regionVariableName, out var region)) { - region.WeatherType = (WeatherType)fourCCLiteralExpression.Value.InvertEndianness(); + region.WeatherType = (WeatherType)weatherTypeValue.InvertEndianness(); } else { @@ -121,19 +119,19 @@ invocationExpression.Arguments.Arguments[1] is JassFourCCLiteralExpressionSyntax } else if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "SetSoundPosition", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "SetSoundPosition", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax soundVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var y) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var soundVariableName) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y) && currentRegion is not null && currentRegion.CenterX == x && currentRegion.CenterY == y && (string.IsNullOrEmpty(currentRegion.AmbientSound) || - string.Equals(currentRegion.AmbientSound, soundVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal))) + string.Equals(currentRegion.AmbientSound, soundVariableName, StringComparison.Ordinal))) { - currentRegion.AmbientSound = soundVariableReferenceExpression.IdentifierName.Name; + currentRegion.AmbientSound = soundVariableName; } else { @@ -141,19 +139,19 @@ currentRegion is not null && return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "RegisterStackedSound", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "RegisterStackedSound", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax soundVariableReferenceExpression && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var rectWidth) && - callStatement.Arguments.Arguments[3].TryGetRealExpressionValue(out var rectHeight) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var soundVariableName) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var rectWidth) && + callStatement.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var rectHeight) && currentRegion is not null && currentRegion.Width == rectWidth && currentRegion.Height == rectHeight && (string.IsNullOrEmpty(currentRegion.AmbientSound) || - string.Equals(currentRegion.AmbientSound, soundVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal))) + string.Equals(currentRegion.AmbientSound, soundVariableName, StringComparison.Ordinal))) { - currentRegion.AmbientSound = soundVariableReferenceExpression.IdentifierName.Name; + currentRegion.AmbientSound = soundVariableName; } else { @@ -161,7 +159,7 @@ currentRegion is not null && return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "EnableWeatherEffect", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "EnableWeatherEffect", StringComparison.Ordinal)) { continue; } @@ -178,7 +176,7 @@ currentRegion is not null && } } - if (regions.Any()) + if (regions.Count > 0) { mapRegions = new MapRegions(formatVersion); mapRegions.Regions.AddRange(createdRegions); diff --git a/src/War3Net.CodeAnalysis.Decompilers/FunctionDeclarationContext.cs b/src/War3Net.CodeAnalysis.Decompilers/FunctionDeclarationContext.cs index 7a3b155e..6b3d8f3a 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/FunctionDeclarationContext.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/FunctionDeclarationContext.cs @@ -5,24 +5,23 @@ // // ------------------------------------------------------------------------------ -using System.Collections.Generic; -using System.Collections.Immutable; - +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers { internal sealed class FunctionDeclarationContext { - public FunctionDeclarationContext(JassFunctionDeclarationSyntax functionDeclaration, IEnumerable comments) + public FunctionDeclarationContext(JassFunctionDeclarationSyntax functionDeclaration) { FunctionDeclaration = functionDeclaration; - Comments = comments.ToImmutableList(); - if (functionDeclaration.FunctionDeclarator.ParameterList.Parameters.IsEmpty) + if (functionDeclaration.FunctionDeclarator.ParameterList is JassEmptyParameterListSyntax) { - IsActionsFunction = functionDeclaration.FunctionDeclarator.ReturnType == JassTypeSyntax.Nothing; - IsConditionsFunction = functionDeclaration.FunctionDeclarator.ReturnType == JassTypeSyntax.Boolean; + var returnTypeToken = functionDeclaration.FunctionDeclarator.ReturnClause.ReturnType.GetToken(); + IsActionsFunction = returnTypeToken.SyntaxKind == JassSyntaxKind.NothingKeyword; + IsConditionsFunction = returnTypeToken.SyntaxKind == JassSyntaxKind.BooleanKeyword; } Handled = false; @@ -30,8 +29,6 @@ public FunctionDeclarationContext(JassFunctionDeclarationSyntax functionDeclarat public JassFunctionDeclarationSyntax FunctionDeclaration { get; } - public ImmutableList Comments { get; } - public bool IsActionsFunction { get; } public bool IsConditionsFunction { get; } diff --git a/src/War3Net.CodeAnalysis.Decompilers/JassScriptDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/JassScriptDecompiler.cs index 1ccf7fe4..313251d7 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/JassScriptDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/JassScriptDecompiler.cs @@ -67,16 +67,16 @@ private IEnumerable GetCandidateFunctions(string? ex yield return expectedFunction; } - foreach (var statement in mainFunction.FunctionDeclaration.Body.Statements) + foreach (var statement in mainFunction.FunctionDeclaration.Statements) { - if (statement is JassCallStatementSyntax callStatement && callStatement.Arguments.Arguments.IsEmpty) + if (statement is JassCallStatementSyntax callStatement && callStatement.ArgumentList.ArgumentList.Items.IsEmpty) { - if (string.Equals(callStatement.IdentifierName.Name, expectedFunctionName, StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, expectedFunctionName, StringComparison.Ordinal)) { continue; } - if (Context.FunctionDeclarations.TryGetValue(callStatement.IdentifierName.Name, out var candidateFunction) && + if (Context.FunctionDeclarations.TryGetValue(callStatement.IdentifierName.Token.Text, out var candidateFunction) && candidateFunction.IsActionsFunction && !candidateFunction.Handled) { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs index ef32be5c..370cc511 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs @@ -11,6 +11,7 @@ using System.Linq; using War3Net.Build.Script; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; @@ -83,7 +84,7 @@ public bool TryDecompileMapTriggers( }); } - if (Context.VariableDeclarations.Any(declaration => declaration.Value.GlobalDeclaration.Declarator.IdentifierName.Name.StartsWith("udg_", StringComparison.Ordinal))) + if (Context.VariableDeclarations.Any(declaration => declaration.Value.GlobalVariableDeclaration.Declarator.GetIdentifierName().Token.Text.StartsWith("udg_", StringComparison.Ordinal))) { var variablesCategoryId = categoryId++; @@ -96,13 +97,13 @@ public bool TryDecompileMapTriggers( foreach (var declaration in Context.VariableDeclarations) { - var globalDeclaration = declaration.Value.GlobalDeclaration; - if (globalDeclaration.Declarator.IdentifierName.Name.StartsWith("udg_", StringComparison.Ordinal)) + var globalVariableDeclaration = declaration.Value.GlobalVariableDeclaration; + if (globalVariableDeclaration.Declarator.GetIdentifierName().Token.Text.StartsWith("udg_", StringComparison.Ordinal)) { var variableDefinition = new VariableDefinition { - Name = globalDeclaration.Declarator.IdentifierName.Name["udg_".Length..], - Type = globalDeclaration.Declarator.Type.TypeName.Name, + Name = globalVariableDeclaration.Declarator.GetIdentifierName().Token.Text["udg_".Length..], + Type = globalVariableDeclaration.Declarator.GetVariableType().GetToken().Text, Unk = 1, IsArray = declaration.Value.IsArray, ArraySize = 1, @@ -114,7 +115,7 @@ public bool TryDecompileMapTriggers( declaration.Value.VariableDefinition = variableDefinition; - if (globalDeclaration.Declarator is JassVariableDeclaratorSyntax variableDeclarator) + if (globalVariableDeclaration.Declarator is JassVariableDeclaratorSyntax variableDeclarator) { if (variableDeclarator.Value is not null && TryDecompileVariableDefinitionInitialValue(variableDeclarator.Value.Expression, variableDefinition.Type, out var initialValue)) @@ -140,19 +141,21 @@ public bool TryDecompileMapTriggers( if (initGlobalsFunction is not null) { - foreach (var statement in initGlobalsFunction.Body.Statements) + foreach (var statement in initGlobalsFunction.Statements) { if (statement is JassLoopStatementSyntax loopStatement) { - if (loopStatement.Body.Statements.Length == 3 && - loopStatement.Body.Statements[0] is JassExitStatementSyntax exitStatement && - loopStatement.Body.Statements[1] is JassSetStatementSyntax setVariableStatement && - loopStatement.Body.Statements[2] is JassSetStatementSyntax && - setVariableStatement.Indexer is JassVariableReferenceExpressionSyntax i && - string.Equals(i.IdentifierName.Name, "i", StringComparison.Ordinal)) + if (loopStatement.Statements.Length == 3 && + loopStatement.Statements[0] is JassExitStatementSyntax exitStatement && + loopStatement.Statements[1] is JassSetStatementSyntax setVariableStatement && + loopStatement.Statements[2] is JassSetStatementSyntax && + exitStatement.Condition.Deparenthesize() is JassBinaryExpressionSyntax binaryExpression && + binaryExpression.Right.TryGetIntegerExpressionValue(out var arraySize) && + setVariableStatement.ElementAccessClause is not null && + setVariableStatement.ElementAccessClause.Expression.TryGetIdentifierNameValue(out var indexVariableName) && + string.Equals(indexVariableName, "i", StringComparison.Ordinal)) { - var variableName = setVariableStatement.IdentifierName.Name["udg_".Length..]; - var arraySize = ((JassDecimalLiteralExpressionSyntax)((JassBinaryExpressionSyntax)exitStatement.Condition.Deparenthesize()).Right).Value; + var variableName = setVariableStatement.IdentifierName.Token.Text["udg_".Length..]; var variableDefinition = mapTriggers.Variables.Single(v => string.Equals(v.Name, variableName, StringComparison.Ordinal)); @@ -180,11 +183,11 @@ setVariableStatement.Indexer is JassVariableReferenceExpressionSyntax i && }); var triggers = new Dictionary(StringComparer.Ordinal); - foreach (var statement in initCustomTriggersFunction.Body.Statements) + foreach (var statement in initCustomTriggersFunction.Statements) { if (statement is JassCallStatementSyntax callStatement && - callStatement.Arguments.Arguments.IsEmpty && - Context.FunctionDeclarations.TryGetValue(callStatement.IdentifierName.Name, out var initTrigFunction) && + callStatement.ArgumentList.ArgumentList.Items.IsEmpty && + Context.FunctionDeclarations.TryGetValue(callStatement.IdentifierName.Token.Text, out var initTrigFunction) && TryDecompileTriggerDefinition(initTrigFunction, out var trigger)) { trigger.Id = triggerId++; @@ -201,14 +204,14 @@ setVariableStatement.Indexer is JassVariableReferenceExpressionSyntax i && if (runInitializationTriggersFunction is not null) { - foreach (var statement in runInitializationTriggersFunction.Body.Statements) + foreach (var statement in runInitializationTriggersFunction.Statements) { if (statement is JassCallStatementSyntax callStatement && - callStatement.Arguments.Arguments.Length == 1 && - string.Equals(callStatement.IdentifierName.Name, "ConditionalTriggerExecute", StringComparison.Ordinal) && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax triggerVariableReferenceExpression && - triggerVariableReferenceExpression.IdentifierName.Name.StartsWith("gg_trg_", StringComparison.Ordinal) && - triggers.TryGetValue(triggerVariableReferenceExpression.IdentifierName.Name["gg_trg_".Length..].Replace('_', ' '), out var triggerDefinition)) + callStatement.ArgumentList.ArgumentList.Items.Length == 1 && + string.Equals(callStatement.IdentifierName.Token.Text, "ConditionalTriggerExecute", StringComparison.Ordinal) && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var triggerVariableName) && + triggerVariableName.StartsWith("gg_trg_", StringComparison.Ordinal) && + triggers.TryGetValue(triggerVariableName["gg_trg_".Length..].Replace('_', ' '), out var triggerDefinition)) { triggerDefinition.Functions.Add(new TriggerFunction { @@ -235,19 +238,19 @@ private bool TryDecompileTriggerDefinition(FunctionDeclarationContext initTrigFu string? triggerVariableName = null; - var triggerFunctionName = initTrigFunction.FunctionDeclaration.FunctionDeclarator.IdentifierName.Name["InitTrig_".Length..]; + var triggerFunctionName = initTrigFunction.FunctionDeclaration.FunctionDeclarator.IdentifierName.Token.Text["InitTrig_".Length..]; - foreach (var statement in initTrigFunction.FunctionDeclaration.Body.Statements) + foreach (var statement in initTrigFunction.FunctionDeclaration.Statements) { if (statement is JassSetStatementSyntax setStatement) { if (setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpression && - invocationExpression.Arguments.Arguments.IsEmpty && - setStatement.Indexer is null && - string.Equals(setStatement.IdentifierName.Name, $"gg_trg_{triggerFunctionName}", StringComparison.Ordinal) && - string.Equals(invocationExpression.IdentifierName.Name, "CreateTrigger", StringComparison.Ordinal)) + invocationExpression.ArgumentList.ArgumentList.Items.IsEmpty && + setStatement.ElementAccessClause is null && + string.Equals(setStatement.IdentifierName.Token.Text, $"gg_trg_{triggerFunctionName}", StringComparison.Ordinal) && + string.Equals(invocationExpression.IdentifierName.Token.Text, "CreateTrigger", StringComparison.Ordinal)) { - triggerVariableName = setStatement.IdentifierName.Name; + triggerVariableName = setStatement.IdentifierName.Token.Text; trigger = new TriggerDefinition(); trigger.IsEnabled = true; @@ -263,18 +266,18 @@ setStatement.Indexer is null && } else if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "TriggerAddAction", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "TriggerAddAction", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && - string.Equals(variableReferenceExpression.IdentifierName.Name, triggerVariableName, StringComparison.Ordinal) && - Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Name, out var actionsFunctionDeclaration) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && + string.Equals(variableName, triggerVariableName, StringComparison.Ordinal) && + Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Token.Text, out var actionsFunctionDeclaration) && actionsFunctionDeclaration.IsActionsFunction) { var actionsFunction = actionsFunctionDeclaration.FunctionDeclaration; - if (TryDecompileActionStatementList(actionsFunction.Body, out var actionFunctions)) + if (TryDecompileActionStatements(actionsFunction.Statements, out var actionFunctions)) { trigger.Functions.AddRange(actionFunctions); } @@ -290,21 +293,21 @@ callStatement.Arguments.Arguments[1] is JassFunctionReferenceExpressionSyntax fu return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "TriggerAddCondition", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "TriggerAddCondition", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassInvocationExpressionSyntax conditionInvocationExpression && - string.Equals(conditionInvocationExpression.IdentifierName.Name, "Condition", StringComparison.Ordinal) && - conditionInvocationExpression.Arguments.Arguments.Length == 1 && - conditionInvocationExpression.Arguments.Arguments[0] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && - string.Equals(variableReferenceExpression.IdentifierName.Name, triggerVariableName, StringComparison.Ordinal) && - Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Name, out var conditionsFunctionDeclaration) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + callStatement.ArgumentList.ArgumentList.Items[1] is JassInvocationExpressionSyntax conditionInvocationExpression && + string.Equals(conditionInvocationExpression.IdentifierName.Token.Text, "Condition", StringComparison.Ordinal) && + conditionInvocationExpression.ArgumentList.ArgumentList.Items.Length == 1 && + conditionInvocationExpression.ArgumentList.ArgumentList.Items[0] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && + string.Equals(variableName, triggerVariableName, StringComparison.Ordinal) && + Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Token.Text, out var conditionsFunctionDeclaration) && conditionsFunctionDeclaration.IsConditionsFunction) { var conditionsFunction = conditionsFunctionDeclaration.FunctionDeclaration; - if (TryDecompileConditionStatementList(conditionsFunction.Body, out var conditionFunctions)) + if (TryDecompileConditionStatements(conditionsFunction.Statements, out var conditionFunctions)) { trigger.Functions.AddRange(conditionFunctions); } @@ -318,11 +321,11 @@ conditionInvocationExpression.Arguments.Arguments[0] is JassFunctionReferenceExp return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "DisableTrigger", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "DisableTrigger", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 1 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - string.Equals(variableReferenceExpression.IdentifierName.Name, triggerVariableName, StringComparison.Ordinal)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 1 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + string.Equals(variableName, triggerVariableName, StringComparison.Ordinal)) { trigger.IsInitiallyOn = false; @@ -335,21 +338,21 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va } else { - if (Context.TriggerData.TriggerData.TriggerEvents.TryGetValue(callStatement.IdentifierName.Name, out var triggerEvent) && - callStatement.Arguments.Arguments.Length == triggerEvent.ArgumentTypes.Length + 1 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - string.Equals(variableReferenceExpression.IdentifierName.Name, triggerVariableName, StringComparison.Ordinal)) + if (Context.TriggerData.TriggerData.TriggerEvents.TryGetValue(callStatement.IdentifierName.Token.Text, out var triggerEvent) && + callStatement.ArgumentList.ArgumentList.Items.Length == triggerEvent.ArgumentTypes.Length + 1 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + string.Equals(variableName, triggerVariableName, StringComparison.Ordinal)) { var function = new TriggerFunction { Type = TriggerFunctionType.Event, IsEnabled = true, - Name = callStatement.IdentifierName.Name, + Name = callStatement.IdentifierName.Token.Text, }; - for (var i = 1; i < callStatement.Arguments.Arguments.Length; i++) + for (var i = 1; i < callStatement.ArgumentList.ArgumentList.Items.Length; i++) { - if (TryDecompileTriggerFunctionParameter(callStatement.Arguments.Arguments[i], triggerEvent.ArgumentTypes[i - 1], out var functionParameter)) + if (TryDecompileTriggerFunctionParameter(callStatement.ArgumentList.ArgumentList.Items[i], triggerEvent.ArgumentTypes[i - 1], out var functionParameter)) { function.Parameters.Add(functionParameter); } @@ -376,9 +379,9 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax va return trigger is not null; } - private bool TryDecompileVariableDefinitionInitialValue(IExpressionSyntax expression, string type, [NotNullWhen(true)] out string? initialValue) + private bool TryDecompileVariableDefinitionInitialValue(JassExpressionSyntax expression, string type, [NotNullWhen(true)] out string? initialValue) { - if (expression is not JassNullLiteralExpressionSyntax && + if (expression.SyntaxKind != JassSyntaxKind.NullLiteralExpression && (!Context.TriggerData.TriggerData.TriggerTypeDefaults.TryGetValue(type, out var typeDefault) || !string.Equals(typeDefault.ScriptText, expression.ToString(), StringComparison.Ordinal)) && TryDecompileTriggerFunctionParameter(expression, type, out var functionParameter)) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/CustomScriptCodeDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/CustomScriptCodeDecompiler.cs index 697fa58c..f6fe5dd2 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/CustomScriptCodeDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/CustomScriptCodeDecompiler.cs @@ -12,21 +12,6 @@ namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { - private TriggerFunction DecompileCustomScriptAction(IDeclarationLineSyntax declarationLine) - { - return DecompileCustomScriptAction(declarationLine.ToString()); - } - - private TriggerFunction DecompileCustomScriptAction(IGlobalLineSyntax globalLine) - { - return DecompileCustomScriptAction(globalLine.ToString()); - } - - private TriggerFunction DecompileCustomScriptAction(IStatementLineSyntax statementLine) - { - return DecompileCustomScriptAction(statementLine.ToString()); - } - private TriggerFunction DecompileCustomScriptAction(string customScriptCode) { return new TriggerFunction diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForEachLoopDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForEachLoopDecompiler.cs index 3a8a8b33..2f19d337 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForEachLoopDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForEachLoopDecompiler.cs @@ -22,14 +22,14 @@ private bool TryDecompileForEachLoopActionFunction(JassCallStatementSyntax callS { if (parameters.Length > 0 && string.Equals(parameters[^1], JassKeyword.Code, StringComparison.Ordinal) && - Context.TriggerData.TriggerActions.TryGetValue(callStatement.IdentifierName.Name, out var actions)) + Context.TriggerData.TriggerActions.TryGetValue(callStatement.IdentifierName.Token.Text, out var actions)) { - var action = actions.First(action => action.ArgumentTypes.Length == callStatement.Arguments.Arguments.Length - 1); + var action = actions.First(action => action.ArgumentTypes.Length == callStatement.ArgumentList.ArgumentList.Items.Length - 1); - if (callStatement.Arguments.Arguments[^1] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && - Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Name, out var actionsFunctionDeclaration) && + if (callStatement.ArgumentList.ArgumentList.Items[^1] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && + Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Token.Text, out var actionsFunctionDeclaration) && actionsFunctionDeclaration.IsActionsFunction && - TryDecompileActionStatementList(actionsFunctionDeclaration.FunctionDeclaration.Body, out var loopActionFunctions)) + TryDecompileActionStatements(actionsFunctionDeclaration.FunctionDeclaration.Statements, out var loopActionFunctions)) { var function = new TriggerFunction { @@ -38,9 +38,9 @@ private bool TryDecompileForEachLoopActionFunction(JassCallStatementSyntax callS Name = action.FunctionName, }; - for (var i = 0; i < callStatement.Arguments.Arguments.Length - 1; i++) + for (var i = 0; i < callStatement.ArgumentList.ArgumentList.Items.Length - 1; i++) { - if (TryDecompileTriggerFunctionParameter(callStatement.Arguments.Arguments[i], action.ArgumentTypes[i], out var functionParameter)) + if (TryDecompileTriggerFunctionParameter(callStatement.ArgumentList.ArgumentList.Items[i], action.ArgumentTypes[i], out var functionParameter)) { function.Parameters.Add(functionParameter); } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForLoopDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForLoopDecompiler.cs index 1fa6e1db..22ce2fab 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForLoopDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/ForLoopDecompiler.cs @@ -20,28 +20,28 @@ public partial class JassScriptDecompiler { private bool TryDecompileForLoopActionFunction( JassSetStatementSyntax setStatement, - IStatementSyntax? statement2, - IStatementSyntax? statement3, + JassStatementSyntax? statement2, + JassStatementSyntax? statement3, ref List functions) { if (statement2 is JassSetStatementSyntax setIndexEndStatement && statement3 is JassLoopStatementSyntax loopStatement && - loopStatement.Body.Statements.Length >= 2 && - loopStatement.Body.Statements[0] is JassExitStatementSyntax exitStatement && + loopStatement.Statements.Length >= 2 && + loopStatement.Statements[0] is JassExitStatementSyntax exitStatement && exitStatement.Condition.Deparenthesize() is JassBinaryExpressionSyntax exitExpression && - exitExpression.Operator == BinaryOperatorType.GreaterThan && - exitExpression.Left is JassVariableReferenceExpressionSyntax exitLeftVariableReferenceExpression && - exitExpression.Right is JassVariableReferenceExpressionSyntax exitRightVariableReferenceExpression && - loopStatement.Body.Statements[^1] is JassSetStatementSyntax incrementStatement && + exitExpression.SyntaxKind == JassSyntaxKind.GreaterThanExpression && + exitExpression.Left.TryGetIdentifierNameValue(out var exitLeftVariableName) && + exitExpression.Right.TryGetIdentifierNameValue(out var exitRightVariableName) && + loopStatement.Statements[^1] is JassSetStatementSyntax incrementStatement && incrementStatement.Value.Expression is JassBinaryExpressionSyntax incrementExpression && - incrementExpression.Operator == BinaryOperatorType.Add && - incrementExpression.Left is JassVariableReferenceExpressionSyntax incrementVariableReferenceExpression && - incrementExpression.Right is JassDecimalLiteralExpressionSyntax incrementLiteralExpression && - incrementLiteralExpression.Value == 1 && - string.Equals(setStatement.IdentifierName.Name, exitLeftVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setIndexEndStatement.IdentifierName.Name, exitRightVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setStatement.IdentifierName.Name, incrementStatement.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setStatement.IdentifierName.Name, incrementVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal)) + incrementExpression.SyntaxKind == JassSyntaxKind.AddExpression && + incrementExpression.Left.TryGetIdentifierNameValue(out var incrementVariableName) && + incrementExpression.Right.TryGetIntegerExpressionValue(out var incrementValue) && + incrementValue == 1 && + string.Equals(setStatement.IdentifierName.Token.Text, exitLeftVariableName, StringComparison.Ordinal) && + string.Equals(setIndexEndStatement.IdentifierName.Token.Text, exitRightVariableName, StringComparison.Ordinal) && + string.Equals(setStatement.IdentifierName.Token.Text, incrementStatement.IdentifierName.Token.Text, StringComparison.Ordinal) && + string.Equals(setStatement.IdentifierName.Token.Text, incrementVariableName, StringComparison.Ordinal)) { var loopFunction = new TriggerFunction { @@ -49,10 +49,10 @@ incrementExpression.Right is JassDecimalLiteralExpressionSyntax incrementLiteral IsEnabled = true, }; - var loopBody = new JassStatementListSyntax(ImmutableArray.CreateRange(loopStatement.Body.Statements, 1, loopStatement.Body.Statements.Length - 2, statement => statement)); + var loopBody = ImmutableArray.CreateRange(loopStatement.Statements, 1, loopStatement.Statements.Length - 2, statement => statement); if (TryDecompileTriggerFunctionParameter(setStatement.Value.Expression, JassKeyword.Integer, out var indexFunctionParameter) && TryDecompileTriggerFunctionParameter(setIndexEndStatement.Value.Expression, JassKeyword.Integer, out var indexEndFunctionParameter) && - TryDecompileActionStatementList(loopBody, out var loopActionFunctions)) + TryDecompileActionStatements(loopBody, out var loopActionFunctions)) { loopFunction.Parameters.Add(indexFunctionParameter); loopFunction.Parameters.Add(indexEndFunctionParameter); @@ -68,13 +68,13 @@ incrementExpression.Right is JassDecimalLiteralExpressionSyntax incrementLiteral return false; } - if (string.Equals(setStatement.IdentifierName.Name, "bj_forLoopAIndex", StringComparison.Ordinal) && - string.Equals(setIndexEndStatement.IdentifierName.Name, "bj_forLoopAIndexEnd", StringComparison.Ordinal)) + if (string.Equals(setStatement.IdentifierName.Token.Text, "bj_forLoopAIndex", StringComparison.Ordinal) && + string.Equals(setIndexEndStatement.IdentifierName.Token.Text, "bj_forLoopAIndexEnd", StringComparison.Ordinal)) { loopFunction.Name = "ForLoopAMultiple"; } - else if (string.Equals(setStatement.IdentifierName.Name, "bj_forLoopBIndex", StringComparison.Ordinal) && - string.Equals(setIndexEndStatement.IdentifierName.Name, "bj_forLoopBIndexEnd", StringComparison.Ordinal)) + else if (string.Equals(setStatement.IdentifierName.Token.Text, "bj_forLoopBIndex", StringComparison.Ordinal) && + string.Equals(setIndexEndStatement.IdentifierName.Token.Text, "bj_forLoopBIndexEnd", StringComparison.Ordinal)) { loopFunction.Name = "ForLoopBMultiple"; } @@ -94,32 +94,32 @@ incrementExpression.Right is JassDecimalLiteralExpressionSyntax incrementLiteral private bool TryDecompileForLoopVarActionFunction( JassSetStatementSyntax setStatement, - IStatementSyntax? statement2, + JassStatementSyntax? statement2, ref List functions) { if (statement2 is JassLoopStatementSyntax loopStatement && - loopStatement.Body.Statements.Length >= 2 && - loopStatement.Body.Statements[0] is JassExitStatementSyntax exitStatement && + loopStatement.Statements.Length >= 2 && + loopStatement.Statements[0] is JassExitStatementSyntax exitStatement && exitStatement.Condition.Deparenthesize() is JassBinaryExpressionSyntax exitExpression && - exitExpression.Operator == BinaryOperatorType.GreaterThan && - loopStatement.Body.Statements[^1] is JassSetStatementSyntax incrementStatement && + exitExpression.SyntaxKind == JassSyntaxKind.GreaterThanExpression && + loopStatement.Statements[^1] is JassSetStatementSyntax incrementStatement && incrementStatement.Value.Expression is JassBinaryExpressionSyntax incrementExpression && - incrementExpression.Operator == BinaryOperatorType.Add && - incrementExpression.Right is JassDecimalLiteralExpressionSyntax incrementLiteralExpression && - incrementLiteralExpression.Value == 1 && + incrementExpression.SyntaxKind == JassSyntaxKind.AddExpression && + incrementExpression.Right.TryGetIntegerExpressionValue(out var incrementValue) && + incrementValue == 1 && TryDecompileTriggerFunctionParameterVariable(setStatement, out var variableFunctionParameter, out var variableType) && string.Equals(variableType, JassKeyword.Integer, StringComparison.Ordinal) && TryDecompileTriggerFunctionParameter(setStatement.Value.Expression, JassKeyword.Integer, out var indexFunctionParameter) && TryDecompileTriggerFunctionParameter(exitExpression.Right, JassKeyword.Integer, out var indexEndFunctionParameter)) { - if (setStatement.Indexer is null) + if (setStatement.ElementAccessClause is null) { - if (incrementStatement.Indexer is null && - exitExpression.Left is JassVariableReferenceExpressionSyntax exitLeftVariableReferenceExpression && - incrementExpression.Left is JassVariableReferenceExpressionSyntax incrementVariableReferenceExpression && - string.Equals(setStatement.IdentifierName.Name, incrementStatement.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setStatement.IdentifierName.Name, exitLeftVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setStatement.IdentifierName.Name, incrementVariableReferenceExpression.IdentifierName.Name, StringComparison.Ordinal)) + if (incrementStatement.ElementAccessClause is null && + exitExpression.Left.TryGetIdentifierNameValue(out var exitLeftVariableName) && + incrementExpression.Left.TryGetIdentifierNameValue(out var incrementVariableName) && + string.Equals(setStatement.IdentifierName.Token.Text, incrementStatement.IdentifierName.Token.Text, StringComparison.Ordinal) && + string.Equals(setStatement.IdentifierName.Token.Text, exitLeftVariableName, StringComparison.Ordinal) && + string.Equals(setStatement.IdentifierName.Token.Text, incrementVariableName, StringComparison.Ordinal)) { } else @@ -129,16 +129,16 @@ incrementExpression.Left is JassVariableReferenceExpressionSyntax incrementVaria } else { - var indexer = setStatement.Indexer.ToString(); - if (incrementStatement.Indexer is not null && - exitExpression.Left is JassArrayReferenceExpressionSyntax exitLeftArrayReferenceExpression && - incrementExpression.Left is JassArrayReferenceExpressionSyntax incrementArrayReferenceExpression && - string.Equals(setStatement.IdentifierName.Name, incrementStatement.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setStatement.IdentifierName.Name, exitLeftArrayReferenceExpression.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(setStatement.IdentifierName.Name, incrementArrayReferenceExpression.IdentifierName.Name, StringComparison.Ordinal) && - string.Equals(indexer, incrementStatement.Indexer.ToString(), StringComparison.Ordinal) && - string.Equals(indexer, exitLeftArrayReferenceExpression.Indexer.ToString(), StringComparison.Ordinal) && - string.Equals(indexer, incrementArrayReferenceExpression.Indexer.ToString(), StringComparison.Ordinal)) + var elementAccess = setStatement.ElementAccessClause.ToString(); + if (incrementStatement.ElementAccessClause is not null && + exitExpression.Left is JassElementAccessExpressionSyntax exitLeftElementAccessExpression && + incrementExpression.Left is JassElementAccessExpressionSyntax incrementElementAccessExpression && + string.Equals(setStatement.IdentifierName.Token.Text, incrementStatement.IdentifierName.Token.Text, StringComparison.Ordinal) && + string.Equals(setStatement.IdentifierName.Token.Text, exitLeftElementAccessExpression.IdentifierName.Token.Text, StringComparison.Ordinal) && + string.Equals(setStatement.IdentifierName.Token.Text, incrementElementAccessExpression.IdentifierName.Token.Text, StringComparison.Ordinal) && + string.Equals(elementAccess, incrementStatement.ElementAccessClause.ToString(), StringComparison.Ordinal) && + string.Equals(elementAccess, exitLeftElementAccessExpression.ElementAccessClause.ToString(), StringComparison.Ordinal) && + string.Equals(elementAccess, incrementElementAccessExpression.ElementAccessClause.ToString(), StringComparison.Ordinal)) { } else @@ -158,8 +158,8 @@ incrementExpression.Left is JassArrayReferenceExpressionSyntax incrementArrayRef loopFunction.Parameters.Add(indexFunctionParameter); loopFunction.Parameters.Add(indexEndFunctionParameter); - var loopBody = new JassStatementListSyntax(ImmutableArray.CreateRange(loopStatement.Body.Statements, 1, loopStatement.Body.Statements.Length - 2, statement => statement)); - if (TryDecompileActionStatementList(loopBody, out var loopActionFunctions)) + var loopBody = ImmutableArray.CreateRange(loopStatement.Statements, 1, loopStatement.Statements.Length - 2, statement => statement); + if (TryDecompileActionStatements(loopBody, out var loopActionFunctions)) { foreach (var loopActionFunction in loopActionFunctions) { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/IfThenElseDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/IfThenElseDecompiler.cs index 96c81dec..0f3c716f 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/IfThenElseDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/IfThenElseDecompiler.cs @@ -27,25 +27,25 @@ private bool TryDecompileIfThenElseActionFunction(JassIfStatementSyntax ifStatem Name = "IfThenElseMultiple", }; - if (!TryDecompileActionStatementList(ifStatement.Body, out var thenActions) || - !TryDecompileActionStatementList(ifStatement.ElseClause.Body, out var elseActions)) + if (!TryDecompileActionStatements(ifStatement.IfClause.Statements, out var thenActions) || + !TryDecompileActionStatements(ifStatement.ElseClause.Statements, out var elseActions)) { actionFunction = null; return false; } - var conditionExpression = ifStatement.Condition.Deparenthesize(); + var conditionExpression = ifStatement.IfClause.IfClauseDeclarator.Condition.Deparenthesize(); if (conditionExpression is JassInvocationExpressionSyntax conditionInvocationExpression && - Context.FunctionDeclarations.TryGetValue(conditionInvocationExpression.IdentifierName.Name, out var conditionsFunctionDeclaration) && + Context.FunctionDeclarations.TryGetValue(conditionInvocationExpression.IdentifierName.Token.Text, out var conditionsFunctionDeclaration) && conditionsFunctionDeclaration.IsConditionsFunction) { var conditionsFunction = conditionsFunctionDeclaration.FunctionDeclaration; - if (conditionsFunction.Body.Statements.Length == 1 && + if (conditionsFunction.Statements.Length == 1 && thenActions.Count == 1 && elseActions.Count == 1 && - TryDecompileConditionStatement(conditionsFunction.Body.Statements[0], true, out var conditionFunction)) + TryDecompileConditionStatement(conditionsFunction.Statements[0], true, out var conditionFunction)) { function.Name = "IfThenElse"; @@ -75,7 +75,7 @@ private bool TryDecompileIfThenElseActionFunction(JassIfStatementSyntax ifStatem } else { - if (TryDecompileConditionStatementList(conditionsFunction.Body, out var conditionFunctions)) + if (TryDecompileConditionStatements(conditionsFunction.Statements, out var conditionFunctions)) { foreach (var condition in conditionFunctions) { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/WaitForConditionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/WaitForConditionDecompiler.cs index 70082ad7..c48003ab 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/Special/WaitForConditionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/Special/WaitForConditionDecompiler.cs @@ -19,26 +19,26 @@ public partial class JassScriptDecompiler { private bool TryDecompileWaitForConditionActionFunction(JassLoopStatementSyntax loopStatement, [NotNullWhen(true)] out TriggerFunction? actionFunction) { - if (loopStatement.Body.Statements.Length == 2 && - loopStatement.Body.Statements[0] is JassExitStatementSyntax exitStatement && + if (loopStatement.Statements.Length == 2 && + loopStatement.Statements[0] is JassExitStatementSyntax exitStatement && exitStatement.Condition.Deparenthesize() is JassInvocationExpressionSyntax exitInvocationExpression && - exitInvocationExpression.Arguments.Arguments.IsEmpty && - loopStatement.Body.Statements[1] is JassCallStatementSyntax callStatement && - string.Equals(callStatement.IdentifierName.Name, "TriggerSleepAction", StringComparison.Ordinal) && - callStatement.Arguments.Arguments.Length == 1 && - callStatement.Arguments.Arguments[0] is JassInvocationExpressionSyntax callInvocationExpression && - string.Equals(callInvocationExpression.IdentifierName.Name, "RMaxBJ", StringComparison.Ordinal) && - callInvocationExpression.Arguments.Arguments.Length == 2 && - callInvocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax variableReferenceExpression && - string.Equals(variableReferenceExpression.IdentifierName.Name, "bj_WAIT_FOR_COND_MIN_INTERVAL", StringComparison.Ordinal) && - Context.FunctionDeclarations.TryGetValue(exitInvocationExpression.IdentifierName.Name, out var exitFunctionDeclaration) && + exitInvocationExpression.ArgumentList.ArgumentList.Items.IsEmpty && + loopStatement.Statements[1] is JassCallStatementSyntax callStatement && + string.Equals(callStatement.IdentifierName.Token.Text, "TriggerSleepAction", StringComparison.Ordinal) && + callStatement.ArgumentList.ArgumentList.Items.Length == 1 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassInvocationExpressionSyntax callInvocationExpression && + string.Equals(callInvocationExpression.IdentifierName.Token.Text, "RMaxBJ", StringComparison.Ordinal) && + callInvocationExpression.ArgumentList.ArgumentList.Items.Length == 2 && + callInvocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var variableName) && + string.Equals(variableName, "bj_WAIT_FOR_COND_MIN_INTERVAL", StringComparison.Ordinal) && + Context.FunctionDeclarations.TryGetValue(exitInvocationExpression.IdentifierName.Token.Text, out var exitFunctionDeclaration) && exitFunctionDeclaration.IsConditionsFunction) { var exitFunction = exitFunctionDeclaration.FunctionDeclaration; - if (exitFunction.Body.Statements.Length == 1 && - TryDecompileConditionStatement(exitFunction.Body.Statements[0], true, out var conditionFunction) && - TryDecompileTriggerFunctionParameter(callInvocationExpression.Arguments.Arguments[1], JassKeyword.Real, out var intervalParameter)) + if (exitFunction.Statements.Length == 1 && + TryDecompileConditionStatement(exitFunction.Statements[0], true, out var conditionFunction) && + TryDecompileTriggerFunctionParameter(callInvocationExpression.ArgumentList.ArgumentList.Items[1], JassKeyword.Real, out var intervalParameter)) { actionFunction = new TriggerFunction { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryExpressionDecompiler.cs index 6217c588..be3e2701 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryExpressionDecompiler.cs @@ -98,8 +98,8 @@ private bool TryDecompileBinaryExpression( } else { - if (TryDecompileBinaryOperatorType( - binaryExpression.Operator, + if (TryDecompileBinaryOperator( + binaryExpression.OperatorToken, leftOptions[left].Type, leftOptions[left].Parameter, rightOptions[right].Parameter, diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryOperatorTypeDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryOperatorDecompiler.cs similarity index 86% rename from src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryOperatorTypeDecompiler.cs rename to src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryOperatorDecompiler.cs index 83498e98..b8f3e1dc 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryOperatorTypeDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BinaryOperatorDecompiler.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -16,8 +16,8 @@ namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { - private bool TryDecompileBinaryOperatorType( - BinaryOperatorType binaryOperatorType, + private bool TryDecompileBinaryOperator( + JassSyntaxToken operatorToken, string expectedType, TriggerFunctionParameter leftOperandParameter, TriggerFunctionParameter rightOperandParameter, @@ -36,7 +36,7 @@ private bool TryDecompileBinaryOperatorType( { if (triggerCall.ArgumentTypes.Length == 2) { - if (binaryOperatorType == BinaryOperatorType.Add) + if (operatorToken.SyntaxKind == JassSyntaxKind.PlusToken) { function = new TriggerFunction { @@ -53,7 +53,7 @@ private bool TryDecompileBinaryOperatorType( } else if (triggerCall.ArgumentTypes.Length == 3) { - if (TryDecompileTriggerFunctionParameter(binaryOperatorType, triggerCall.ArgumentTypes[1], out var operatorFunctionParameter)) + if (TryDecompileTriggerFunctionParameter(operatorToken, triggerCall.ArgumentTypes[1], out var operatorFunctionParameter)) { function = new TriggerFunction { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BooleanLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BooleanLiteralExpressionDecompiler.cs index a441177f..5412d7bd 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BooleanLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/BooleanLiteralExpressionDecompiler.cs @@ -18,7 +18,7 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileBooleanLiteralExpression( - JassBooleanLiteralExpressionSyntax booleanLiteralExpression, + JassLiteralExpressionSyntax booleanLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { @@ -27,12 +27,12 @@ private bool TryDecompileBooleanLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = booleanLiteralExpression.ToString(), + Value = booleanLiteralExpression.Token.Text, }; return true; } - else if (TryDecompileTriggerFunctionParameterPreset(booleanLiteralExpression.ToString(), expectedType, out _, out functionParameter)) + else if (TryDecompileTriggerFunctionParameterPreset(booleanLiteralExpression.Token.Text, expectedType, out _, out functionParameter)) { return true; } @@ -42,7 +42,7 @@ private bool TryDecompileBooleanLiteralExpression( } private bool TryDecompileBooleanLiteralExpression( - JassBooleanLiteralExpressionSyntax booleanLiteralExpression, + JassLiteralExpressionSyntax booleanLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { if (TryDecompileBooleanLiteralExpression(booleanLiteralExpression, JassKeyword.Boolean, out var functionParameter)) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CallStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CallStatementDecompiler.cs index a4ac27f8..31fe1905 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CallStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CallStatementDecompiler.cs @@ -19,12 +19,12 @@ private bool TryDecompileCallStatement( JassCallStatementSyntax callStatement, ref List functions) { - if (!Context.TriggerData.TriggerActions.TryGetValue(callStatement.IdentifierName.Name, out var actions)) + if (!Context.TriggerData.TriggerActions.TryGetValue(callStatement.IdentifierName.Token.Text, out var actions)) { return false; } - var action = actions.First(action => action.ArgumentTypes.Length == callStatement.Arguments.Arguments.Length); + var action = actions.First(action => action.ArgumentTypes.Length == callStatement.ArgumentList.ArgumentList.Items.Length); if (TryDecompileForEachLoopActionFunction(callStatement, action.ArgumentTypes, out var loopActionFunction)) { @@ -39,9 +39,9 @@ private bool TryDecompileCallStatement( Name = action.FunctionName, }; - for (var j = 0; j < callStatement.Arguments.Arguments.Length; j++) + for (var j = 0; j < callStatement.ArgumentList.ArgumentList.Items.Length; j++) { - if (TryDecompileTriggerFunctionParameter(callStatement.Arguments.Arguments[j], action.ArgumentTypes[j], out var functionParameter)) + if (TryDecompileTriggerFunctionParameter(callStatement.ArgumentList.ArgumentList.Items[j], action.ArgumentTypes[j], out var functionParameter)) { function.Parameters.Add(functionParameter); } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs index fd1e05d6..1384ab7f 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs @@ -19,7 +19,7 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileCharacterLiteralExpression( - JassCharacterLiteralExpressionSyntax characterLiteralExpression, + JassLiteralExpressionSyntax characterLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { @@ -29,7 +29,7 @@ private bool TryDecompileCharacterLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = ((int)characterLiteralExpression.Value).ToString(CultureInfo.InvariantCulture), + Value = ((int)characterLiteralExpression.Token.Text[1]).ToString(CultureInfo.InvariantCulture), }; return true; @@ -40,10 +40,10 @@ private bool TryDecompileCharacterLiteralExpression( } private bool TryDecompileCharacterLiteralExpression( - JassCharacterLiteralExpressionSyntax characterLiteralExpression, + JassLiteralExpressionSyntax characterLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = ((int)characterLiteralExpression.Value).ToString(CultureInfo.InvariantCulture); + var value = ((int)characterLiteralExpression.Token.Text[1]).ToString(CultureInfo.InvariantCulture); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/DecimalLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/DecimalLiteralExpressionDecompiler.cs index 45f41b3f..d6cb8b01 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/DecimalLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/DecimalLiteralExpressionDecompiler.cs @@ -18,7 +18,7 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileDecimalLiteralExpression( - JassDecimalLiteralExpressionSyntax decimalLiteralExpression, + JassLiteralExpressionSyntax decimalLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { @@ -28,7 +28,7 @@ private bool TryDecompileDecimalLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = decimalLiteralExpression.ToString(), + Value = decimalLiteralExpression.Token.Text, }; return true; @@ -39,10 +39,10 @@ private bool TryDecompileDecimalLiteralExpression( } private bool TryDecompileDecimalLiteralExpression( - JassDecimalLiteralExpressionSyntax decimalLiteralExpression, + JassLiteralExpressionSyntax decimalLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = decimalLiteralExpression.ToString(); + var value = decimalLiteralExpression.Token.Text; decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/ArrayReferenceExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/ElementAccessExpressionDecompiler.cs similarity index 72% rename from src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/ArrayReferenceExpressionDecompiler.cs rename to src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/ElementAccessExpressionDecompiler.cs index 8e863080..b4a640e5 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/ArrayReferenceExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/ElementAccessExpressionDecompiler.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -18,13 +18,13 @@ namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { - private bool TryDecompileArrayReferenceExpression( - JassArrayReferenceExpressionSyntax arrayReferenceExpression, + private bool TryDecompileElementAccessExpression( + JassElementAccessExpressionSyntax elementAccessExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { if (Context.TriggerData.TriggerParams.TryGetValue(string.Empty, out var triggerParamsForAllTypes) && - triggerParamsForAllTypes.TryGetValue(arrayReferenceExpression.ToString(), out var triggerParams)) + triggerParamsForAllTypes.TryGetValue(elementAccessExpression.ToString(), out var triggerParams)) { var triggerParam = triggerParams.SingleOrDefault(param => string.Equals(param.VariableType, expectedType, StringComparison.Ordinal)); if (triggerParam is not null) @@ -39,10 +39,10 @@ private bool TryDecompileArrayReferenceExpression( } } - if (TryDecompileTriggerFunctionParameter(arrayReferenceExpression.Indexer, JassKeyword.Integer, out var arrayIndexer)) + if (TryDecompileTriggerFunctionParameter(elementAccessExpression.ElementAccessClause.Expression, JassKeyword.Integer, out var arrayIndexer)) { return TryDecompileVariableDeclarationReference( - arrayReferenceExpression.IdentifierName.Name, + elementAccessExpression.IdentifierName.Token.Text, arrayIndexer, expectedType, out functionParameter); @@ -52,12 +52,12 @@ private bool TryDecompileArrayReferenceExpression( return false; } - private bool TryDecompileArrayReferenceExpression( - JassArrayReferenceExpressionSyntax arrayReferenceExpression, + private bool TryDecompileElementAccessExpression( + JassElementAccessExpressionSyntax elementAccessExpression, [NotNullWhen(true)] out List? decompileOptions) { if (Context.TriggerData.TriggerParams.TryGetValue(string.Empty, out var triggerParamsForAllTypes) && - triggerParamsForAllTypes.TryGetValue(arrayReferenceExpression.ToString(), out var triggerParams) && + triggerParamsForAllTypes.TryGetValue(elementAccessExpression.ToString(), out var triggerParams) && triggerParams.Length == 1) { var triggerParam = triggerParams[0]; @@ -76,10 +76,10 @@ private bool TryDecompileArrayReferenceExpression( return true; } - if (TryDecompileTriggerFunctionParameter(arrayReferenceExpression.Indexer, JassKeyword.Integer, out var arrayIndexer)) + if (TryDecompileTriggerFunctionParameter(elementAccessExpression.ElementAccessClause.Expression, JassKeyword.Integer, out var arrayIndexer)) { return TryDecompileVariableDeclarationReference( - arrayReferenceExpression.IdentifierName.Name, + elementAccessExpression.IdentifierName.Token.Text, arrayIndexer, out decompileOptions); } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/FourCCLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/FourCCLiteralExpressionDecompiler.cs index b5bb667c..8bf63920 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/FourCCLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/FourCCLiteralExpressionDecompiler.cs @@ -19,11 +19,11 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileFourCCLiteralExpression( - JassFourCCLiteralExpressionSyntax fourCCLiteralExpression, + JassLiteralExpressionSyntax fourCCLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { - if (TryDecompileTriggerFunctionParameterPreset(fourCCLiteralExpression.ToString(), expectedType, out _, out functionParameter)) + if (TryDecompileTriggerFunctionParameterPreset(fourCCLiteralExpression.Token.Text, expectedType, out _, out functionParameter)) { return true; } @@ -33,7 +33,7 @@ private bool TryDecompileFourCCLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = fourCCLiteralExpression.Value.ToJassRawcode(), + Value = fourCCLiteralExpression.Token.Text[1..^1], }; return true; @@ -43,7 +43,7 @@ private bool TryDecompileFourCCLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = fourCCLiteralExpression.Value.ToJassRawcode(), + Value = fourCCLiteralExpression.Token.Text[1..^1], }; return true; @@ -54,7 +54,7 @@ private bool TryDecompileFourCCLiteralExpression( } private bool TryDecompileFourCCLiteralExpression( - JassFourCCLiteralExpressionSyntax fourCCLiteralExpression, + JassLiteralExpressionSyntax fourCCLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { if (Context.TriggerData.TriggerTypes.TryGetValue(JassKeyword.Integer, out var customTypes)) @@ -68,7 +68,7 @@ private bool TryDecompileFourCCLiteralExpression( Parameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = fourCCLiteralExpression.Value.ToJassRawcode(), + Value = fourCCLiteralExpression.Token.Text[1..^1], }, }); } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs index c2860d28..c9e2b38f 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs @@ -19,17 +19,20 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileHexadecimalLiteralExpression( - JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression, + JassLiteralExpressionSyntax hexadecimalLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { if (string.Equals(expectedType, JassKeyword.Integer, StringComparison.Ordinal) || string.Equals(expectedType, JassKeyword.Real, StringComparison.Ordinal)) { + var text = hexadecimalLiteralExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); + var value = Convert.ToInt32(text[2..], 16); + functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = hexadecimalLiteralExpression.Value.ToString(CultureInfo.InvariantCulture), + Value = value.ToString(CultureInfo.InvariantCulture), }; return true; @@ -40,10 +43,11 @@ private bool TryDecompileHexadecimalLiteralExpression( } private bool TryDecompileHexadecimalLiteralExpression( - JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression, + JassLiteralExpressionSyntax hexadecimalLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = hexadecimalLiteralExpression.Value.ToString(CultureInfo.InvariantCulture); + var text = hexadecimalLiteralExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); + var value = Convert.ToInt32(text[2..], 16).ToString(CultureInfo.InvariantCulture); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/VariableReferenceExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IdentifierNameDecompiler.cs similarity index 91% rename from src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/VariableReferenceExpressionDecompiler.cs rename to src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IdentifierNameDecompiler.cs index 2d76b9e3..61785b9d 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/VariableReferenceExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IdentifierNameDecompiler.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // @@ -17,13 +17,13 @@ namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { - private bool TryDecompileVariableReferenceExpression( - JassVariableReferenceExpressionSyntax variableReferenceExpression, + private bool TryDecompileIdentifierName( + JassIdentifierNameSyntax identifierName, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { if (Context.TriggerData.TriggerParams.TryGetValue(string.Empty, out var triggerParamsForAllTypes) && - triggerParamsForAllTypes.TryGetValue(variableReferenceExpression.ToString(), out var triggerParams)) + triggerParamsForAllTypes.TryGetValue(identifierName.Token.Text, out var triggerParams)) { var triggerParam = triggerParams.SingleOrDefault(param => string.Equals(param.VariableType, expectedType, StringComparison.Ordinal)); if (triggerParam is not null) @@ -39,18 +39,18 @@ private bool TryDecompileVariableReferenceExpression( } return TryDecompileVariableDeclarationReference( - variableReferenceExpression.IdentifierName.Name, + identifierName.Token.Text, null, expectedType, out functionParameter); } - private bool TryDecompileVariableReferenceExpression( - JassVariableReferenceExpressionSyntax variableReferenceExpression, + private bool TryDecompileIdentifierName( + JassIdentifierNameSyntax identifierName, [NotNullWhen(true)] out List? decompileOptions) { if (Context.TriggerData.TriggerParams.TryGetValue(string.Empty, out var triggerParamsForAllTypes) && - triggerParamsForAllTypes.TryGetValue(variableReferenceExpression.ToString(), out var triggerParams) && + triggerParamsForAllTypes.TryGetValue(identifierName.Token.Text, out var triggerParams) && triggerParams.Length == 1) { var triggerParam = triggerParams[0]; @@ -70,7 +70,7 @@ private bool TryDecompileVariableReferenceExpression( } return TryDecompileVariableDeclarationReference( - variableReferenceExpression.IdentifierName.Name, + identifierName.Token.Text, null, out decompileOptions); } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs index a2b161c1..a882af5a 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs @@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis; using War3Net.Build.Script; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; @@ -26,9 +27,9 @@ private bool TryDecompileIfStatement( return true; } - functions.Add(DecompileCustomScriptAction(new JassIfCustomScriptAction(ifStatement.Condition))); + functions.Add(DecompileCustomScriptAction(ifStatement.IfClause.IfClauseDeclarator.ToString())); - if (TryDecompileActionStatementList(ifStatement.Body, out var thenActions)) + if (TryDecompileActionStatements(ifStatement.IfClause.Statements, out var thenActions)) { functions.AddRange(thenActions); } @@ -39,9 +40,9 @@ private bool TryDecompileIfStatement( foreach (var elseIfClause in ifStatement.ElseIfClauses) { - functions.Add(DecompileCustomScriptAction(new JassElseIfCustomScriptAction(elseIfClause.Condition))); + functions.Add(DecompileCustomScriptAction(elseIfClause.ElseIfClauseDeclarator.ToString())); - if (TryDecompileActionStatementList(elseIfClause.Body, out var elseIfActions)) + if (TryDecompileActionStatements(elseIfClause.Statements, out var elseIfActions)) { functions.AddRange(elseIfActions); } @@ -53,9 +54,9 @@ private bool TryDecompileIfStatement( if (ifStatement.ElseClause is not null) { - functions.Add(DecompileCustomScriptAction(JassElseCustomScriptAction.Value)); + functions.Add(DecompileCustomScriptAction(ifStatement.ElseClause.ElseToken.ToString())); - if (TryDecompileActionStatementList(ifStatement.ElseClause.Body, out var elseActions)) + if (TryDecompileActionStatements(ifStatement.ElseClause.Statements, out var elseActions)) { functions.AddRange(elseActions); } @@ -65,7 +66,7 @@ private bool TryDecompileIfStatement( } } - functions.Add(DecompileCustomScriptAction(JassEndIfCustomScriptAction.Value)); + functions.Add(DecompileCustomScriptAction(ifStatement.EndIfToken.ToString())); return true; } @@ -78,17 +79,18 @@ private bool TryDecompileIfStatement( { if (ifStatement.ElseIfClauses.IsEmpty && ifStatement.ElseClause is null && - ifStatement.Body.Statements.Length == 1 && - ifStatement.Body.Statements[0] is JassReturnStatementSyntax returnStatement && - returnStatement.Value is JassBooleanLiteralExpressionSyntax booleanLiteralExpression && - booleanLiteralExpression.Value != returnValue) + ifStatement.IfClause.Statements.Length == 1 && + ifStatement.IfClause.Statements[0] is JassReturnStatementSyntax returnStatement && + returnStatement.Value is not null && + returnStatement.Value.TryGetBooleanExpressionValue(out var returnStatementValue) && + returnStatementValue != returnValue) { - var conditionExpression = ifStatement.Condition.Deparenthesize(); + var conditionExpression = ifStatement.IfClause.IfClauseDeclarator.Condition.Deparenthesize(); if (returnValue) { if (conditionExpression is JassUnaryExpressionSyntax unaryExpression && - unaryExpression.Operator == UnaryOperatorType.Not) + unaryExpression.SyntaxKind == JassSyntaxKind.LogicalNotExpression) { conditionExpression = unaryExpression.Expression.Deparenthesize(); } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/InvocationExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/InvocationExpressionDecompiler.cs index 85a67899..74192db8 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/InvocationExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/InvocationExpressionDecompiler.cs @@ -26,7 +26,7 @@ private bool TryDecompileInvocationExpression( return true; } - if (Context.TriggerData.TriggerData.TriggerCalls.TryGetValue(invocationExpression.IdentifierName.Name, out var triggerCall)) + if (Context.TriggerData.TriggerData.TriggerCalls.TryGetValue(invocationExpression.IdentifierName.Token.Text, out var triggerCall)) { if (string.Equals(triggerCall.ReturnType, expectedType, StringComparison.Ordinal) && TryDecompileTriggerCallFunction(invocationExpression, triggerCall, out var callFunction)) @@ -34,7 +34,7 @@ private bool TryDecompileInvocationExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.Function, - Value = invocationExpression.IdentifierName.Name, + Value = invocationExpression.IdentifierName.Token.Text, Function = callFunction, }; @@ -42,17 +42,17 @@ private bool TryDecompileInvocationExpression( } } - if (string.Equals(invocationExpression.IdentifierName.Name, "Condition", StringComparison.Ordinal)) + if (string.Equals(invocationExpression.IdentifierName.Token.Text, "Condition", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 1 && - invocationExpression.Arguments.Arguments[0] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && - Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Name, out var conditionFunctionDeclaration) && + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 1 && + invocationExpression.ArgumentList.ArgumentList.Items[0] is JassFunctionReferenceExpressionSyntax functionReferenceExpression && + Context.FunctionDeclarations.TryGetValue(functionReferenceExpression.IdentifierName.Token.Text, out var conditionFunctionDeclaration) && conditionFunctionDeclaration.IsConditionsFunction) { var conditionFunction = conditionFunctionDeclaration.FunctionDeclaration; - if (conditionFunction.Body.Statements.Length == 1 && - TryDecompileConditionStatement(conditionFunction.Body.Statements[0], true, out var function)) + if (conditionFunction.Statements.Length == 1 && + TryDecompileConditionStatement(conditionFunction.Statements[0], true, out var function)) { functionParameter = new TriggerFunctionParameter { @@ -93,7 +93,7 @@ private bool TryDecompileInvocationExpression( } } - if (Context.TriggerData.TriggerData.TriggerCalls.TryGetValue(invocationExpression.IdentifierName.Name, out var triggerCall) && + if (Context.TriggerData.TriggerData.TriggerCalls.TryGetValue(invocationExpression.IdentifierName.Token.Text, out var triggerCall) && TryDecompileTriggerCallFunction(invocationExpression, triggerCall, out var callFunction)) { result.Add(new DecompileOption @@ -102,7 +102,7 @@ private bool TryDecompileInvocationExpression( Parameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.Function, - Value = invocationExpression.IdentifierName.Name, + Value = invocationExpression.IdentifierName.Token.Text, Function = callFunction, }, }); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LiteralExpressionDecompiler.cs new file mode 100644 index 00000000..08b125c2 --- /dev/null +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LiteralExpressionDecompiler.cs @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using War3Net.Build.Script; +using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Syntax; + +namespace War3Net.CodeAnalysis.Decompilers +{ + public partial class JassScriptDecompiler + { + private bool TryDecompileLiteralExpression( + JassLiteralExpressionSyntax literalExpression, + string expectedType, + [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) + { + return literalExpression.SyntaxKind switch + { + JassSyntaxKind.CharacterLiteralExpression => TryDecompileCharacterLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.FourCCLiteralExpression => TryDecompileFourCCLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.HexadecimalLiteralExpression => TryDecompileHexadecimalLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.RealLiteralExpression => TryDecompileRealLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.OctalLiteralExpression => TryDecompileOctalLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.DecimalLiteralExpression => TryDecompileDecimalLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.TrueLiteralExpression => TryDecompileBooleanLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.FalseLiteralExpression => TryDecompileBooleanLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.StringLiteralExpression => TryDecompileStringLiteralExpression(literalExpression, expectedType, out functionParameter), + JassSyntaxKind.NullLiteralExpression => TryDecompileNullLiteralExpression(literalExpression, expectedType, out functionParameter), + + _ => throw new NotSupportedException($"Unsupported literal expression kind: {literalExpression.SyntaxKind}"), + }; + } + + private bool TryDecompileLiteralExpression( + JassLiteralExpressionSyntax literalExpression, + [NotNullWhen(true)] out List? decompileOptions) + { + return literalExpression.SyntaxKind switch + { + JassSyntaxKind.CharacterLiteralExpression => TryDecompileCharacterLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.FourCCLiteralExpression => TryDecompileFourCCLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.HexadecimalLiteralExpression => TryDecompileHexadecimalLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.RealLiteralExpression => TryDecompileRealLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.OctalLiteralExpression => TryDecompileOctalLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.DecimalLiteralExpression => TryDecompileDecimalLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.TrueLiteralExpression => TryDecompileBooleanLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.FalseLiteralExpression => TryDecompileBooleanLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.StringLiteralExpression => TryDecompileStringLiteralExpression(literalExpression, out decompileOptions), + JassSyntaxKind.NullLiteralExpression => TryDecompileNullLiteralExpression(literalExpression, out decompileOptions), + + _ => throw new NotSupportedException($"Unsupported literal expression kind: {literalExpression.SyntaxKind}"), + }; + } + } +} \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs index 3a5d48a2..65b3d41f 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs @@ -24,14 +24,14 @@ private bool TryDecompileLoopStatement( return true; } - if (!TryDecompileActionStatementList(loopStatement.Body, out var loopActions)) + if (!TryDecompileActionStatements(loopStatement.Statements, out var loopActions)) { return false; } - functions.Add(DecompileCustomScriptAction(JassLoopCustomScriptAction.Value)); + functions.Add(DecompileCustomScriptAction(loopStatement.LoopToken.ToString())); functions.AddRange(loopActions); - functions.Add(DecompileCustomScriptAction(JassEndLoopCustomScriptAction.Value)); + functions.Add(DecompileCustomScriptAction(loopStatement.EndLoopToken.ToString())); return false; } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/NullLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/NullLiteralExpressionDecompiler.cs index c60ef2d0..8faa74fc 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/NullLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/NullLiteralExpressionDecompiler.cs @@ -16,19 +16,19 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileNullLiteralExpression( - JassNullLiteralExpressionSyntax nullLiteralExpression, + JassLiteralExpressionSyntax nullLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { - return TryDecompileTriggerFunctionParameterPreset(nullLiteralExpression.ToString(), expectedType, out _, out functionParameter); + return TryDecompileTriggerFunctionParameterPreset(nullLiteralExpression.Token.Text, expectedType, out _, out functionParameter); } private bool TryDecompileNullLiteralExpression( - JassNullLiteralExpressionSyntax nullLiteralExpression, + JassLiteralExpressionSyntax nullLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { if (Context.TriggerData.TriggerParams.TryGetValue(string.Empty, out var triggerParamsForAllTypes) && - triggerParamsForAllTypes.TryGetValue(nullLiteralExpression.ToString(), out var triggerParams)) + triggerParamsForAllTypes.TryGetValue(nullLiteralExpression.Token.Text, out var triggerParams)) { decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs index 787d751a..15e14124 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs @@ -19,7 +19,7 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileOctalLiteralExpression( - JassOctalLiteralExpressionSyntax octalLiteralExpression, + JassLiteralExpressionSyntax octalLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { @@ -29,7 +29,7 @@ private bool TryDecompileOctalLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = octalLiteralExpression.Value.ToString(CultureInfo.InvariantCulture), + Value = Convert.ToInt32(octalLiteralExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture), }; return true; @@ -40,10 +40,10 @@ private bool TryDecompileOctalLiteralExpression( } private bool TryDecompileOctalLiteralExpression( - JassOctalLiteralExpressionSyntax octalLiteralExpression, + JassLiteralExpressionSyntax octalLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = octalLiteralExpression.Value.ToString(CultureInfo.InvariantCulture); + var value = Convert.ToInt32(octalLiteralExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/RealLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/RealLiteralExpressionDecompiler.cs index 0b468f16..f6e6dc82 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/RealLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/RealLiteralExpressionDecompiler.cs @@ -18,7 +18,7 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileRealLiteralExpression( - JassRealLiteralExpressionSyntax realLiteralExpression, + JassLiteralExpressionSyntax realLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { @@ -27,7 +27,7 @@ private bool TryDecompileRealLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = realLiteralExpression.ToString(), + Value = realLiteralExpression.Token.Text, }; return true; @@ -38,7 +38,7 @@ private bool TryDecompileRealLiteralExpression( } private bool TryDecompileRealLiteralExpression( - JassRealLiteralExpressionSyntax realLiteralExpression, + JassLiteralExpressionSyntax realLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { decompileOptions = new(); @@ -49,7 +49,7 @@ private bool TryDecompileRealLiteralExpression( Parameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = realLiteralExpression.ToString(), + Value = realLiteralExpression.Token.Text, }, }); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/SetStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/SetStatementDecompiler.cs index 4c690bf6..ab9203be 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/SetStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/SetStatementDecompiler.cs @@ -6,6 +6,7 @@ // ------------------------------------------------------------------------------ using System.Collections.Generic; +using System.Collections.Immutable; using War3Net.Build.Script; using War3Net.CodeAnalysis.Jass.Syntax; @@ -16,12 +17,12 @@ public partial class JassScriptDecompiler { private bool TryDecompileSetStatement( JassSetStatementSyntax setStatement, - JassStatementListSyntax statementList, + ImmutableArray statements, ref int i, ref List functions) { - var lookaheadStatement1 = i + 1 < statementList.Statements.Length ? statementList.Statements[i + 1] : null; - var lookaheadStatement2 = i + 2 < statementList.Statements.Length ? statementList.Statements[i + 2] : null; + var lookaheadStatement1 = i + 1 < statements.Length ? statements[i + 1] : null; + var lookaheadStatement2 = i + 2 < statements.Length ? statements[i + 2] : null; if (TryDecompileForLoopActionFunction(setStatement, lookaheadStatement1, lookaheadStatement2, ref functions)) { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementDecompiler.cs index e5fae454..15259aa7 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementDecompiler.cs @@ -6,6 +6,7 @@ // ------------------------------------------------------------------------------ using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using War3Net.Build.Script; @@ -16,14 +17,13 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileActionStatement( - JassStatementListSyntax statementList, + ImmutableArray statements, ref int i, ref List functions) { - return statementList.Statements[i] switch + return statements[i] switch { - JassCommentSyntax comment => TryDecompileComment(comment, ref functions), - JassSetStatementSyntax setStatement => TryDecompileSetStatement(setStatement, statementList, ref i, ref functions), + JassSetStatementSyntax setStatement => TryDecompileSetStatement(setStatement, statements, ref i, ref functions), JassCallStatementSyntax callStatement => TryDecompileCallStatement(callStatement, ref functions), JassIfStatementSyntax ifStatement => TryDecompileIfStatement(ifStatement, ref functions), JassLoopStatementSyntax loopStatement => TryDecompileLoopStatement(loopStatement, ref functions), @@ -35,7 +35,7 @@ private bool TryDecompileActionStatement( /// for AND conditions, for OR conditions. private bool TryDecompileConditionStatement( - IStatementSyntax statement, + JassStatementSyntax statement, bool returnValue, [NotNullWhen(true)] out TriggerFunction? function) { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs index 9004c789..815ffdf0 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs @@ -6,33 +6,27 @@ // ------------------------------------------------------------------------------ using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using War3Net.Build.Script; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { - private bool TryDecompileActionStatementList(JassStatementListSyntax statementList, [NotNullWhen(true)] out List? actionFunctions) + private bool TryDecompileActionStatements(ImmutableArray statements, [NotNullWhen(true)] out List? actionFunctions) { var result = new List(); - for (var i = 0; i < statementList.Statements.Length; i++) + for (var i = 0; i < statements.Length; i++) { - if (!TryDecompileActionStatement(statementList, ref i, ref result)) + if (!TryDecompileActionStatement(statements, ref i, ref result)) { - if (statementList.Statements[i] is IStatementLineSyntax statementLine) - { - result.Add(DecompileCustomScriptAction(statementLine)); - } - else - { - actionFunctions = null; - return false; - } + result.Add(DecompileCustomScriptAction(statements[i].ToString())); } } @@ -40,13 +34,13 @@ private bool TryDecompileActionStatementList(JassStatementListSyntax statementLi return true; } - private bool TryDecompileConditionStatementList( - JassStatementListSyntax statementList, + private bool TryDecompileConditionStatements( + ImmutableArray statements, [NotNullWhen(true)] out List? conditionFunctions) { var result = new List(); - foreach (var conditionStatement in statementList.Statements.SkipLast(1)) + foreach (var conditionStatement in statements.SkipLast(1)) { if (TryDecompileConditionStatement(conditionStatement, true, out var conditionFunction)) { @@ -60,9 +54,10 @@ private bool TryDecompileConditionStatementList( } // Last statement must be "return true" - if (statementList.Statements[^1] is not JassReturnStatementSyntax finalReturnStatement || - finalReturnStatement.Value is not JassBooleanLiteralExpressionSyntax returnBooleanLiteralExpression || - !returnBooleanLiteralExpression.Value) + if (statements[^1] is not JassReturnStatementSyntax finalReturnStatement || + finalReturnStatement.Value is null || + !finalReturnStatement.Value.TryGetBooleanExpressionValue(out var returnStatementValue) || + !returnStatementValue) { conditionFunctions = null; return false; @@ -72,8 +67,8 @@ finalReturnStatement.Value is not JassBooleanLiteralExpressionSyntax returnBoole return true; } - private bool TryDecompileAndOrMultipleStatementList( - JassStatementListSyntax statementList, + private bool TryDecompileAndOrMultipleStatements( + ImmutableArray statements, [NotNullWhen(true)] out TriggerFunction? conditionFunction) { var result = new TriggerFunction @@ -83,18 +78,19 @@ private bool TryDecompileAndOrMultipleStatementList( }; // Last statement must be "return true" or "return false" - if (statementList.Statements[^1] is not JassReturnStatementSyntax finalReturnStatement || - finalReturnStatement.Value is not JassBooleanLiteralExpressionSyntax returnBooleanLiteralExpression) + if (statements[^1] is not JassReturnStatementSyntax finalReturnStatement || + finalReturnStatement.Value is null || + !finalReturnStatement.Value.TryGetBooleanExpressionValue(out var returnStatementValue)) { conditionFunction = null; return false; } - result.Name = returnBooleanLiteralExpression.Value ? "AndMultiple" : "OrMultiple"; + result.Name = returnStatementValue ? "AndMultiple" : "OrMultiple"; - foreach (var conditionStatement in statementList.Statements.SkipLast(1)) + foreach (var conditionStatement in statements.SkipLast(1)) { - if (TryDecompileConditionStatement(conditionStatement, returnBooleanLiteralExpression.Value, out var function)) + if (TryDecompileConditionStatement(conditionStatement, returnStatementValue, out var function)) { function.Branch = 0; result.ChildFunctions.Add(function); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs index 42adf42a..6961f0c6 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs @@ -19,11 +19,13 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileStringLiteralExpression( - JassStringLiteralExpressionSyntax stringLiteralExpression, + JassLiteralExpressionSyntax stringLiteralExpression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { - if (TryDecompileTriggerFunctionParameterPreset($"`{stringLiteralExpression.Value}`", expectedType, out _, out functionParameter)) + var stringValue = stringLiteralExpression.Token.Text[1..^1]; + + if (TryDecompileTriggerFunctionParameterPreset($"`{stringValue}`", expectedType, out _, out functionParameter)) { return true; } @@ -35,7 +37,7 @@ private bool TryDecompileStringLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = Regex.Unescape(stringLiteralExpression.Value), + Value = Regex.Unescape(stringValue), }; return true; @@ -46,10 +48,11 @@ private bool TryDecompileStringLiteralExpression( } private bool TryDecompileStringLiteralExpression( - JassStringLiteralExpressionSyntax stringLiteralExpression, + JassLiteralExpressionSyntax stringLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = Regex.Unescape(stringLiteralExpression.Value); + var stringValue = stringLiteralExpression.Token.Text[1..^1]; + var value = Regex.Unescape(stringValue); decompileOptions = new(); decompileOptions.Add(new DecompileOption @@ -66,7 +69,7 @@ private bool TryDecompileStringLiteralExpression( { foreach (var customType in customTypes) { - if (TryDecompileTriggerFunctionParameterPreset($"`{stringLiteralExpression.Value}`", customType.Key, out _, out var functionParameter)) + if (TryDecompileTriggerFunctionParameterPreset($"`{stringValue}`", customType.Key, out _, out var functionParameter)) { decompileOptions.Add(new DecompileOption { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CommentDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs similarity index 81% rename from src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CommentDecompiler.cs rename to src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs index abedc8e6..fc2bc5f8 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CommentDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs @@ -1,10 +1,11 @@ // ------------------------------------------------------------------------------ -// +// // Licensed under the MIT license. // See the LICENSE file in the project root for more information. // // ------------------------------------------------------------------------------ +using System; using System.Collections.Generic; using War3Net.Build.Script; @@ -15,10 +16,10 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileComment( - JassCommentSyntax comment, + JassSyntaxTrivia trivia, ref List functions) { - if (comment.Comment.Length > 1 && comment.Comment.StartsWith(' ')) + if (trivia.Text.Length > 3 && trivia.Text.StartsWith("// ", StringComparison.Ordinal)) { functions.Add(new TriggerFunction { @@ -30,7 +31,7 @@ private bool TryDecompileComment( new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = comment.Comment[1..], + Value = trivia.Text[3..], }, }, }); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/UnaryExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/UnaryExpressionDecompiler.cs index 90b6ff0b..cfca76d8 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/UnaryExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/UnaryExpressionDecompiler.cs @@ -11,7 +11,6 @@ using War3Net.Build.Script; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers @@ -23,16 +22,16 @@ private bool TryDecompileUnaryExpression( string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { - switch (unaryExpression.Operator) + switch (unaryExpression.SyntaxKind) { - case UnaryOperatorType.Plus: - case UnaryOperatorType.Minus: + case JassSyntaxKind.UnaryPlusExpression: + case JassSyntaxKind.UnaryMinusExpression: if (string.Equals(expectedType, JassKeyword.Integer, StringComparison.Ordinal) || string.Equals(expectedType, JassKeyword.Real, StringComparison.Ordinal)) { if (TryDecompileTriggerFunctionParameter(unaryExpression.Expression, expectedType, out functionParameter)) { - functionParameter.Value = unaryExpression.Operator.GetSymbol() + functionParameter.Value; + functionParameter.Value = unaryExpression.OperatorToken.Text + functionParameter.Value; return true; } } @@ -48,10 +47,10 @@ private bool TryDecompileUnaryExpression( JassUnaryExpressionSyntax unaryExpression, [NotNullWhen(true)] out List? decompileOptions) { - switch (unaryExpression.Operator) + switch (unaryExpression.SyntaxKind) { - case UnaryOperatorType.Plus: - case UnaryOperatorType.Minus: + case JassSyntaxKind.UnaryPlusExpression: + case JassSyntaxKind.UnaryMinusExpression: var result = new List(); if (TryDecompileUnaryExpression(unaryExpression, JassKeyword.Integer, out var functionParameterInt)) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerCallFunctionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerCallFunctionDecompiler.cs index 92481f48..6e75a635 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerCallFunctionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerCallFunctionDecompiler.cs @@ -19,7 +19,7 @@ public partial class JassScriptDecompiler [Obsolete] private bool TryDecompileTriggerCallFunction(JassInvocationExpressionSyntax invocationExpression, [NotNullWhen(true)] out TriggerFunction? callFunction) { - if (Context.TriggerData.TriggerData.TriggerCalls.TryGetValue(invocationExpression.IdentifierName.Name, out var triggerCall) && + if (Context.TriggerData.TriggerData.TriggerCalls.TryGetValue(invocationExpression.IdentifierName.Token.Text, out var triggerCall) && TryDecompileTriggerCallFunction(invocationExpression, triggerCall, out callFunction)) { return true; @@ -34,18 +34,18 @@ private bool TryDecompileTriggerCallFunction( TriggerData.TriggerCall triggerCall, [NotNullWhen(true)] out TriggerFunction? callFunction) { - if (triggerCall.ArgumentTypes.Length == invocationExpression.Arguments.Arguments.Length) + if (triggerCall.ArgumentTypes.Length == invocationExpression.ArgumentList.ArgumentList.Items.Length) { var function = new TriggerFunction { Type = TriggerFunctionType.Call, IsEnabled = true, - Name = invocationExpression.IdentifierName.Name, + Name = invocationExpression.IdentifierName.Token.Text, }; - for (var i = 0; i < invocationExpression.Arguments.Arguments.Length; i++) + for (var i = 0; i < invocationExpression.ArgumentList.ArgumentList.Items.Length; i++) { - if (TryDecompileTriggerFunctionParameter(invocationExpression.Arguments.Arguments[i], triggerCall.ArgumentTypes[i], out var functionParameter)) + if (TryDecompileTriggerFunctionParameter(invocationExpression.ArgumentList.ArgumentList.Items[i], triggerCall.ArgumentTypes[i], out var functionParameter)) { function.Parameters.Add(functionParameter); } @@ -79,7 +79,7 @@ private bool TryDecompileTriggerCallFunction(JassBinaryExpressionSyntax binaryEx if (argumentTypes.Length == 2) { if (string.Equals(type, JassKeyword.String, StringComparison.Ordinal) && - binaryExpression.Operator == BinaryOperatorType.Add && + binaryExpression.SyntaxKind == JassSyntaxKind.AddExpression && TryDecompileTriggerFunctionParameter(binaryExpression.Left, argumentTypes[0], out var leftFunctionParameter) && TryDecompileTriggerFunctionParameter(binaryExpression.Right, argumentTypes[1], out var rightFunctionParameter)) { @@ -100,7 +100,7 @@ private bool TryDecompileTriggerCallFunction(JassBinaryExpressionSyntax binaryEx else if (argumentTypes.Length == 3) { if (TryDecompileTriggerFunctionParameter(binaryExpression.Left, argumentTypes[0], out var leftFunctionParameter) && - TryDecompileTriggerFunctionParameter(binaryExpression.Operator, argumentTypes[1], out var operatorFunctionParameter) && + TryDecompileTriggerFunctionParameter(binaryExpression.OperatorToken, argumentTypes[1], out var operatorFunctionParameter) && TryDecompileTriggerFunctionParameter(binaryExpression.Right, argumentTypes[2], out var rightFunctionParameter)) { var function = new TriggerFunction diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerConditionFunctionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerConditionFunctionDecompiler.cs index c6be4a1d..ea85802a 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerConditionFunctionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerConditionFunctionDecompiler.cs @@ -16,25 +16,25 @@ namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { - private bool TryDecompileConditionExpression(IExpressionSyntax expression, [NotNullWhen(true)] out TriggerFunction? conditionFunction) + private bool TryDecompileConditionExpression(JassExpressionSyntax expression, [NotNullWhen(true)] out TriggerFunction? conditionFunction) { expression = expression.Deparenthesize(); if (expression is JassInvocationExpressionSyntax invocationExpression) { - if (string.Equals(invocationExpression.IdentifierName.Name, "GetBooleanAnd", StringComparison.Ordinal) || - string.Equals(invocationExpression.IdentifierName.Name, "GetBooleanOr", StringComparison.Ordinal)) + if (string.Equals(invocationExpression.IdentifierName.Token.Text, "GetBooleanAnd", StringComparison.Ordinal) || + string.Equals(invocationExpression.IdentifierName.Token.Text, "GetBooleanOr", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 2) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 2) { var function = new TriggerFunction { Type = TriggerFunctionType.Condition, IsEnabled = true, - Name = invocationExpression.IdentifierName.Name, + Name = invocationExpression.IdentifierName.Token.Text, }; - foreach (var argument in invocationExpression.Arguments.Arguments) + foreach (var argument in invocationExpression.ArgumentList.ArgumentList.Items) { if (TryDecompileConditionExpression(argument, out var conditionSubFunction)) { @@ -63,20 +63,20 @@ private bool TryDecompileConditionExpression(IExpressionSyntax expression, [NotN } else { - if (invocationExpression.Arguments.Arguments.IsEmpty && - Context.FunctionDeclarations.TryGetValue(invocationExpression.IdentifierName.Name, out var conditionsFunctionDeclaration) && + if (invocationExpression.ArgumentList.ArgumentList.Items.IsEmpty && + Context.FunctionDeclarations.TryGetValue(invocationExpression.IdentifierName.Token.Text, out var conditionsFunctionDeclaration) && conditionsFunctionDeclaration.IsConditionsFunction) { var conditionsFunction = conditionsFunctionDeclaration.FunctionDeclaration; - if (TryDecompileAndOrMultipleStatementList(conditionsFunction.Body, out conditionFunction)) + if (TryDecompileAndOrMultipleStatements(conditionsFunction.Statements, out conditionFunction)) { return true; } - if (conditionsFunction.Body.Statements.Length == 1) + if (conditionsFunction.Statements.Length == 1) { - if (conditionsFunction.Body.Statements[0] is JassReturnStatementSyntax singleReturnStatement) + if (conditionsFunction.Statements[0] is JassReturnStatementSyntax singleReturnStatement) { return TryDecompileReturnStatement(singleReturnStatement, out conditionFunction); } @@ -116,7 +116,7 @@ private bool TryDecompileConditionExpression(IExpressionSyntax expression, [NotN if (Context.TriggerData.TriggerConditions.TryGetValue(decompileOption.Type, out var triggerCondition) && triggerCondition.ArgumentTypes.Length == 3) { - if (!TryDecompileTriggerFunctionParameter(binaryExpression.Operator, triggerCondition.ArgumentTypes[1], out var operatorFunctionParameter)) + if (!TryDecompileTriggerFunctionParameter(binaryExpression.OperatorToken, triggerCondition.ArgumentTypes[1], out var operatorFunctionParameter)) { continue; } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerFunctionParameterDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerFunctionParameterDecompiler.cs index 09be9d47..6c50412b 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerFunctionParameterDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/TriggerFunctionParameterDecompiler.cs @@ -12,7 +12,6 @@ using War3Net.Build.Script; using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers @@ -20,25 +19,17 @@ namespace War3Net.CodeAnalysis.Decompilers public partial class JassScriptDecompiler { private bool TryDecompileTriggerFunctionParameter( - IExpressionSyntax expression, + JassExpressionSyntax expression, string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { return expression switch { - JassCharacterLiteralExpressionSyntax characterLiteralExpression => TryDecompileCharacterLiteralExpression(characterLiteralExpression, expectedType, out functionParameter), - JassFourCCLiteralExpressionSyntax fourCCLiteralExpression => TryDecompileFourCCLiteralExpression(fourCCLiteralExpression, expectedType, out functionParameter), - JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression => TryDecompileHexadecimalLiteralExpression(hexadecimalLiteralExpression, expectedType, out functionParameter), - JassRealLiteralExpressionSyntax realLiteralExpression => TryDecompileRealLiteralExpression(realLiteralExpression, expectedType, out functionParameter), - JassOctalLiteralExpressionSyntax octalLiteralExpression => TryDecompileOctalLiteralExpression(octalLiteralExpression, expectedType, out functionParameter), - JassDecimalLiteralExpressionSyntax decimalLiteralExpression => TryDecompileDecimalLiteralExpression(decimalLiteralExpression, expectedType, out functionParameter), - JassBooleanLiteralExpressionSyntax booleanLiteralExpression => TryDecompileBooleanLiteralExpression(booleanLiteralExpression, expectedType, out functionParameter), - JassStringLiteralExpressionSyntax stringLiteralExpression => TryDecompileStringLiteralExpression(stringLiteralExpression, expectedType, out functionParameter), - JassNullLiteralExpressionSyntax nullLiteralExpression => TryDecompileNullLiteralExpression(nullLiteralExpression, expectedType, out functionParameter), + JassLiteralExpressionSyntax literalExpression => TryDecompileLiteralExpression(literalExpression, expectedType, out functionParameter), JassFunctionReferenceExpressionSyntax functionReferenceExpression => TryDecompileFunctionReferenceExpression(functionReferenceExpression, expectedType, out functionParameter), JassInvocationExpressionSyntax invocationExpression => TryDecompileInvocationExpression(invocationExpression, expectedType, out functionParameter), - JassArrayReferenceExpressionSyntax arrayReferenceExpression => TryDecompileArrayReferenceExpression(arrayReferenceExpression, expectedType, out functionParameter), - JassVariableReferenceExpressionSyntax variableReferenceExpression => TryDecompileVariableReferenceExpression(variableReferenceExpression, expectedType, out functionParameter), + JassElementAccessExpressionSyntax elementAccessExpression => TryDecompileElementAccessExpression(elementAccessExpression, expectedType, out functionParameter), + JassIdentifierNameSyntax identifierName => TryDecompileIdentifierName(identifierName, expectedType, out functionParameter), JassParenthesizedExpressionSyntax parenthesizedExpression => TryDecompileParenthesizedExpression(parenthesizedExpression, expectedType, out functionParameter), JassUnaryExpressionSyntax unaryExpression => TryDecompileUnaryExpression(unaryExpression, expectedType, out functionParameter), JassBinaryExpressionSyntax binaryExpression => TryDecompileBinaryExpression(binaryExpression, expectedType, out functionParameter), @@ -48,24 +39,16 @@ private bool TryDecompileTriggerFunctionParameter( } private bool TryDecompileTriggerFunctionParameter( - IExpressionSyntax expression, + JassExpressionSyntax expression, [NotNullWhen(true)] out List? decompileOptions) { return expression switch { - JassCharacterLiteralExpressionSyntax characterLiteralExpression => TryDecompileCharacterLiteralExpression(characterLiteralExpression, out decompileOptions), - JassFourCCLiteralExpressionSyntax fourCCLiteralExpression => TryDecompileFourCCLiteralExpression(fourCCLiteralExpression, out decompileOptions), - JassHexadecimalLiteralExpressionSyntax hexadecimalLiteralExpression => TryDecompileHexadecimalLiteralExpression(hexadecimalLiteralExpression, out decompileOptions), - JassRealLiteralExpressionSyntax realLiteralExpression => TryDecompileRealLiteralExpression(realLiteralExpression, out decompileOptions), - JassOctalLiteralExpressionSyntax octalLiteralExpression => TryDecompileOctalLiteralExpression(octalLiteralExpression, out decompileOptions), - JassDecimalLiteralExpressionSyntax decimalLiteralExpression => TryDecompileDecimalLiteralExpression(decimalLiteralExpression, out decompileOptions), - JassBooleanLiteralExpressionSyntax booleanLiteralExpression => TryDecompileBooleanLiteralExpression(booleanLiteralExpression, out decompileOptions), - JassStringLiteralExpressionSyntax stringLiteralExpression => TryDecompileStringLiteralExpression(stringLiteralExpression, out decompileOptions), - JassNullLiteralExpressionSyntax nullLiteralExpression => TryDecompileNullLiteralExpression(nullLiteralExpression, out decompileOptions), + JassLiteralExpressionSyntax literalExpression => TryDecompileLiteralExpression(literalExpression, out decompileOptions), JassFunctionReferenceExpressionSyntax functionReferenceExpression => TryDecompileFunctionReferenceExpression(functionReferenceExpression, out decompileOptions), JassInvocationExpressionSyntax invocationExpression => TryDecompileInvocationExpression(invocationExpression, out decompileOptions), - JassArrayReferenceExpressionSyntax arrayReferenceExpression => TryDecompileArrayReferenceExpression(arrayReferenceExpression, out decompileOptions), - JassVariableReferenceExpressionSyntax variableReferenceExpression => TryDecompileVariableReferenceExpression(variableReferenceExpression, out decompileOptions), + JassElementAccessExpressionSyntax elementAccessExpression => TryDecompileElementAccessExpression(elementAccessExpression, out decompileOptions), + JassIdentifierNameSyntax identifierName => TryDecompileIdentifierName(identifierName, out decompileOptions), JassParenthesizedExpressionSyntax parenthesizedExpression => TryDecompileParenthesizedExpression(parenthesizedExpression, out decompileOptions), JassUnaryExpressionSyntax unaryExpression => TryDecompileUnaryExpression(unaryExpression, out decompileOptions), JassBinaryExpressionSyntax binaryExpression => TryDecompileBinaryExpression(binaryExpression, out decompileOptions), @@ -74,10 +57,10 @@ private bool TryDecompileTriggerFunctionParameter( }; } - private bool TryDecompileTriggerFunctionParameter(BinaryOperatorType binaryOperatorType, string type, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) + private bool TryDecompileTriggerFunctionParameter(JassSyntaxToken operatorToken, string type, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { if (Context.TriggerData.TriggerParams.TryGetValue(type, out var triggerParamsForType) && - triggerParamsForType.TryGetValue($"\"{binaryOperatorType.GetSymbol()}\"", out var triggerParams)) + triggerParamsForType.TryGetValue($"\"{operatorToken.Text}\"", out var triggerParams)) { functionParameter = new TriggerFunctionParameter { @@ -132,17 +115,17 @@ private bool TryDecompileTriggerFunctionParameterPreset( private bool TryDecompileTriggerFunctionParameterVariable(JassSetStatementSyntax setStatement, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter, [NotNullWhen(true)] out string? type) { - if (setStatement.IdentifierName.Name.StartsWith("udg_", StringComparison.Ordinal) && - Context.VariableDeclarations.TryGetValue(setStatement.IdentifierName.Name, out var variableDeclaration)) + if (setStatement.IdentifierName.Token.Text.StartsWith("udg_", StringComparison.Ordinal) && + Context.VariableDeclarations.TryGetValue(setStatement.IdentifierName.Token.Text, out var variableDeclaration)) { - functionParameter = DecompileVariableTriggerFunctionParameter(setStatement.IdentifierName.Name); + functionParameter = DecompileVariableTriggerFunctionParameter(setStatement.IdentifierName.Token.Text); type = variableDeclaration.Type; - if (setStatement.Indexer is null) + if (setStatement.ElementAccessClause is null) { return true; } - else if (TryDecompileTriggerFunctionParameter(setStatement.Indexer, JassKeyword.Integer, out var arrayIndexer)) + else if (TryDecompileTriggerFunctionParameter(setStatement.ElementAccessClause.Expression, JassKeyword.Integer, out var arrayIndexer)) { functionParameter.ArrayIndexer = arrayIndexer; diff --git a/src/War3Net.CodeAnalysis.Decompilers/VariableDeclarationContext.cs b/src/War3Net.CodeAnalysis.Decompilers/VariableDeclarationContext.cs index d37bb87e..739b79c8 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/VariableDeclarationContext.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/VariableDeclarationContext.cs @@ -6,21 +6,22 @@ // ------------------------------------------------------------------------------ using War3Net.Build.Script; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers { internal sealed class VariableDeclarationContext { - public VariableDeclarationContext(JassGlobalDeclarationSyntax globalDeclaration) + public VariableDeclarationContext(JassGlobalVariableDeclarationSyntax globalVariableDeclaration) { - GlobalDeclaration = globalDeclaration; - IsArray = globalDeclaration.Declarator is JassArrayDeclaratorSyntax; + GlobalVariableDeclaration = globalVariableDeclaration; + IsArray = globalVariableDeclaration.Declarator is JassArrayDeclaratorSyntax; - Type = globalDeclaration.Declarator.Type.TypeName.Name; + Type = globalVariableDeclaration.Declarator.GetVariableType().GetToken().Text; } - public JassGlobalDeclarationSyntax GlobalDeclaration { get; } + public JassGlobalVariableDeclarationSyntax GlobalVariableDeclaration { get; } public bool IsArray { get; } diff --git a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs index aa480b99..835ed4d1 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs @@ -11,6 +11,7 @@ using System.Numerics; using War3Net.Build.Widget; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; using War3Net.Common.Extensions; @@ -117,27 +118,22 @@ private bool TryDecompileCreateUnitsFunction(JassFunctionDeclarationSyntax creat var result = new List(); - foreach (var statement in createUnitsFunction.Body.Statements) + foreach (var statement in createUnitsFunction.Statements) { - if (statement is JassCommentSyntax || - statement is JassEmptySyntax) + if (statement is JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement) { - continue; - } - else if (statement is JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement) - { - var typeName = localVariableDeclarationStatement.Declarator.Type.TypeName.Name; + var typeName = localVariableDeclarationStatement.Declarator.GetVariableType().GetToken().Text; if (string.Equals(typeName, "player", StringComparison.Ordinal)) { if (localVariableDeclarationStatement.Declarator is JassVariableDeclaratorSyntax variableDeclarator && variableDeclarator.Value is not null && variableDeclarator.Value.Expression is JassInvocationExpressionSyntax playerInvocationExpression && - string.Equals(playerInvocationExpression.IdentifierName.Name, "Player", StringComparison.Ordinal) && - playerInvocationExpression.Arguments.Arguments.Length == 1 && - playerInvocationExpression.Arguments.Arguments[0].TryGetPlayerIdExpressionValue(Context.MaxPlayerSlots, out var playerId)) + string.Equals(playerInvocationExpression.IdentifierName.Token.Text, "Player", StringComparison.Ordinal) && + playerInvocationExpression.ArgumentList.ArgumentList.Items.Length == 1 && + playerInvocationExpression.ArgumentList.ArgumentList.Items[0].TryGetPlayerIdExpressionValue(Context.MaxPlayerSlots, out var playerId)) { - localPlayerVariableName = variableDeclarator.IdentifierName.Name; + localPlayerVariableName = variableDeclarator.IdentifierName.Token.Text; localPlayerVariableValue = playerId; } else @@ -168,19 +164,19 @@ variableDeclarator.Value.Expression is JassInvocationExpressionSyntax playerInvo } else if (statement is JassSetStatementSyntax setStatement) { - if (setStatement.Indexer is null) + if (setStatement.ElementAccessClause is null) { if (setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpression) { - if (string.Equals(invocationExpression.IdentifierName.Name, "CreateUnit", StringComparison.Ordinal)) + if (string.Equals(invocationExpression.IdentifierName.Token.Text, "CreateUnit", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 5 && - invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax playerVariableReferenceExpression && - invocationExpression.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var unitId) && - invocationExpression.Arguments.Arguments[2].TryGetRealExpressionValue(out var x) && - invocationExpression.Arguments.Arguments[3].TryGetRealExpressionValue(out var y) && - invocationExpression.Arguments.Arguments[4].TryGetRealExpressionValue(out var face) && - string.Equals(playerVariableReferenceExpression.IdentifierName.Name, localPlayerVariableName, StringComparison.Ordinal)) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 5 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var playerVariableName) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var unitId) && + invocationExpression.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var x) && + invocationExpression.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var y) && + invocationExpression.ArgumentList.ArgumentList.Items[4].TryGetRealExpressionValue(out var face) && + string.Equals(playerVariableName, localPlayerVariableName, StringComparison.Ordinal)) { var unit = new UnitData { @@ -192,7 +188,7 @@ invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSy Flags = 2, GoldAmount = 12500, HeroLevel = 1, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; unit.SkinId = unit.TypeId; @@ -205,16 +201,16 @@ invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSy return false; } } - else if (string.Equals(invocationExpression.IdentifierName.Name, "BlzCreateUnitWithSkin", StringComparison.Ordinal)) + else if (string.Equals(invocationExpression.IdentifierName.Token.Text, "BlzCreateUnitWithSkin", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 6 && - invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax playerVariableReferenceExpression && - invocationExpression.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var unitId) && - invocationExpression.Arguments.Arguments[2].TryGetRealExpressionValue(out var x) && - invocationExpression.Arguments.Arguments[3].TryGetRealExpressionValue(out var y) && - invocationExpression.Arguments.Arguments[4].TryGetRealExpressionValue(out var face) && - invocationExpression.Arguments.Arguments[5].TryGetIntegerExpressionValue(out var skinId) && - string.Equals(playerVariableReferenceExpression.IdentifierName.Name, localPlayerVariableName, StringComparison.Ordinal)) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 6 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIdentifierNameValue(out var playerVariableName) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var unitId) && + invocationExpression.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var x) && + invocationExpression.ArgumentList.ArgumentList.Items[3].TryGetRealExpressionValue(out var y) && + invocationExpression.ArgumentList.ArgumentList.Items[4].TryGetRealExpressionValue(out var face) && + invocationExpression.ArgumentList.ArgumentList.Items[5].TryGetIntegerExpressionValue(out var skinId) && + string.Equals(playerVariableName, localPlayerVariableName, StringComparison.Ordinal)) { var unit = new UnitData { @@ -227,7 +223,7 @@ invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSy Flags = 2, GoldAmount = 12500, HeroLevel = 1, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; result.Add(unit); @@ -238,17 +234,17 @@ invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSy return false; } } - else if (string.Equals(invocationExpression.IdentifierName.Name, "CreateTrigger", StringComparison.Ordinal)) + else if (string.Equals(invocationExpression.IdentifierName.Token.Text, "CreateTrigger", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(invocationExpression.IdentifierName.Name, "GetUnitState", StringComparison.Ordinal)) + else if (string.Equals(invocationExpression.IdentifierName.Token.Text, "GetUnitState", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(invocationExpression.IdentifierName.Name, "RandomDistChoose", StringComparison.Ordinal)) + else if (string.Equals(invocationExpression.IdentifierName.Token.Text, "RandomDistChoose", StringComparison.Ordinal)) { // TODO continue; @@ -278,11 +274,11 @@ invocationExpression.Arguments.Arguments[0] is JassVariableReferenceExpressionSy } else if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "SetResourceAmount", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "SetResourceAmount", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var amount)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var amount)) { result[^1].GoldAmount = amount; } @@ -292,14 +288,14 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetUnitColor", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetUnitColor", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassInvocationExpressionSyntax convertPlayerColorInvocationExpression && - string.Equals(convertPlayerColorInvocationExpression.IdentifierName.Name, "ConvertPlayerColor", StringComparison.Ordinal) && - convertPlayerColorInvocationExpression.Arguments.Arguments.Length == 1 && - convertPlayerColorInvocationExpression.Arguments.Arguments[0].TryGetIntegerExpressionValue(out var playerColorId)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1] is JassInvocationExpressionSyntax convertPlayerColorInvocationExpression && + string.Equals(convertPlayerColorInvocationExpression.IdentifierName.Token.Text, "ConvertPlayerColor", StringComparison.Ordinal) && + convertPlayerColorInvocationExpression.ArgumentList.ArgumentList.Items.Length == 1 && + convertPlayerColorInvocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIntegerExpressionValue(out var playerColorId)) { result[^1].CustomPlayerColorId = playerColorId; } @@ -309,11 +305,11 @@ callStatement.Arguments.Arguments[1] is JassInvocationExpressionSyntax convertPl return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetUnitAcquireRange", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetUnitAcquireRange", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var acquireRange)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var acquireRange)) { const float CampAcquireRange = 200f; result[^1].TargetAcquisition = acquireRange == CampAcquireRange ? -2f : acquireRange; @@ -324,18 +320,18 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetUnitState", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetUnitState", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1] is JassVariableReferenceExpressionSyntax unitStateVariableReferenceExpression) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIdentifierNameValue(out var unitState)) { - if (string.Equals(unitStateVariableReferenceExpression.IdentifierName.Name, "UNIT_STATE_LIFE", StringComparison.Ordinal)) + if (string.Equals(unitState, "UNIT_STATE_LIFE", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments[2] is JassBinaryExpressionSyntax binaryExpression && + if (callStatement.ArgumentList.ArgumentList.Items[2] is JassBinaryExpressionSyntax binaryExpression && binaryExpression.Left.TryGetRealExpressionValue(out var hp) && - binaryExpression.Operator == BinaryOperatorType.Multiplication && - binaryExpression.Right is JassVariableReferenceExpressionSyntax) + binaryExpression.SyntaxKind == JassSyntaxKind.MultiplyExpression && + binaryExpression.Right is JassIdentifierNameSyntax) { result[^1].HP = (int)(100 * hp); } @@ -345,9 +341,9 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(unitStateVariableReferenceExpression.IdentifierName.Name, "UNIT_STATE_MANA", StringComparison.Ordinal)) + else if (string.Equals(unitState, "UNIT_STATE_MANA", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments[2].TryGetIntegerExpressionValue(out var mp)) + if (callStatement.ArgumentList.ArgumentList.Items[2].TryGetIntegerExpressionValue(out var mp)) { result[^1].MP = mp; } @@ -369,12 +365,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "UnitAddItemToSlotById", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "UnitAddItemToSlotById", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var itemId) && - callStatement.Arguments.Arguments[2].TryGetIntegerExpressionValue(out var slot)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var itemId) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetIntegerExpressionValue(out var slot)) { result[^1].InventoryData.Add(new InventoryItemData { @@ -388,12 +384,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax && return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetHeroLevel", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetHeroLevel", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var level) && - callStatement.Arguments.Arguments[2] is JassBooleanLiteralExpressionSyntax) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var level) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetBooleanExpressionValue(out _)) { result[^1].HeroLevel = level; } @@ -403,12 +399,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetHeroStr", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetHeroStr", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var value) && - callStatement.Arguments.Arguments[2] is JassBooleanLiteralExpressionSyntax) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var value) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetBooleanExpressionValue(out _)) { result[^1].HeroStrength = value; } @@ -418,12 +414,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetHeroAgi", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetHeroAgi", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var value) && - callStatement.Arguments.Arguments[2] is JassBooleanLiteralExpressionSyntax) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var value) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetBooleanExpressionValue(out _)) { result[^1].HeroAgility = value; } @@ -433,12 +429,12 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SetHeroInt", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SetHeroInt", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax unitVariableReferenceExpression && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var value) && - callStatement.Arguments.Arguments[2] is JassBooleanLiteralExpressionSyntax) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassIdentifierNameSyntax && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var value) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetBooleanExpressionValue(out _)) { result[^1].HeroIntelligence = value; } @@ -448,39 +444,39 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un return false; } } - else if (string.Equals(callStatement.IdentifierName.Name, "SelectHeroSkill", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "SelectHeroSkill", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "IssueImmediateOrder", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "IssueImmediateOrder", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "RandomDistReset", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "RandomDistReset", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "RandomDistAddItem", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "RandomDistAddItem", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "TriggerRegisterUnitEvent", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "TriggerRegisterUnitEvent", StringComparison.Ordinal)) { // TODO continue; } - else if (string.Equals(callStatement.IdentifierName.Name, "TriggerAddAction", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "TriggerAddAction", StringComparison.Ordinal)) { // TODO continue; } - else if (callStatement.Arguments.Arguments.IsEmpty) + else if (callStatement.ArgumentList.ArgumentList.Items.IsEmpty) { - if (Context.FunctionDeclarations.TryGetValue(callStatement.IdentifierName.Name, out var subFunction) && + if (Context.FunctionDeclarations.TryGetValue(callStatement.IdentifierName.Token.Text, out var subFunction) && TryDecompileCreateUnitsFunction(subFunction.FunctionDeclaration, out var subFunctionResult)) { result.AddRange(subFunctionResult); @@ -499,9 +495,9 @@ callStatement.Arguments.Arguments[0] is JassVariableReferenceExpressionSyntax un } else if (statement is JassIfStatementSyntax ifStatement) { - if (ifStatement.Condition.Deparenthesize() is JassBinaryExpressionSyntax binaryExpression && - binaryExpression.Left is JassVariableReferenceExpressionSyntax && - binaryExpression.Operator == BinaryOperatorType.NotEquals && + if (ifStatement.IfClause.IfClauseDeclarator.Condition.Deparenthesize() is JassBinaryExpressionSyntax binaryExpression && + binaryExpression.Left is JassIdentifierNameSyntax && + binaryExpression.SyntaxKind == JassSyntaxKind.NotEqualsExpression && binaryExpression.Right.TryGetIntegerExpressionValue(out var value) && value == -1) { @@ -529,23 +525,18 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat { var result = new List(); - foreach (var statement in createItemsFunction.Body.Statements) + foreach (var statement in createItemsFunction.Statements) { - if (statement is JassCommentSyntax || - statement is JassEmptySyntax) - { - continue; - } - else if (statement is JassSetStatementSyntax setStatement) + if (statement is JassSetStatementSyntax setStatement) { if (setStatement.Value.Expression is JassInvocationExpressionSyntax invocationExpression) { - if (string.Equals(invocationExpression.IdentifierName.Name, "CreateItem", StringComparison.Ordinal)) + if (string.Equals(invocationExpression.IdentifierName.Token.Text, "CreateItem", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 3 && - invocationExpression.Arguments.Arguments[0].TryGetIntegerExpressionValue(out var unitId) && - invocationExpression.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - invocationExpression.Arguments.Arguments[2].TryGetRealExpressionValue(out var y)) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 3 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIntegerExpressionValue(out var unitId) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + invocationExpression.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y)) { var unit = new UnitData { @@ -557,7 +548,7 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat Flags = 2, GoldAmount = 12500, HeroLevel = 1, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; unit.SkinId = unit.TypeId; @@ -565,13 +556,13 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat result.Add(unit); } } - else if (string.Equals(invocationExpression.IdentifierName.Name, "BlzCreateItemWithSkin", StringComparison.Ordinal)) + else if (string.Equals(invocationExpression.IdentifierName.Token.Text, "BlzCreateItemWithSkin", StringComparison.Ordinal)) { - if (invocationExpression.Arguments.Arguments.Length == 4 && - invocationExpression.Arguments.Arguments[0].TryGetIntegerExpressionValue(out var unitId) && - invocationExpression.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - invocationExpression.Arguments.Arguments[2].TryGetRealExpressionValue(out var y) && - invocationExpression.Arguments.Arguments[3].TryGetIntegerExpressionValue(out var skinId)) + if (invocationExpression.ArgumentList.ArgumentList.Items.Length == 4 && + invocationExpression.ArgumentList.ArgumentList.Items[0].TryGetIntegerExpressionValue(out var unitId) && + invocationExpression.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + invocationExpression.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y) && + invocationExpression.ArgumentList.ArgumentList.Items[3].TryGetIntegerExpressionValue(out var skinId)) { var unit = new UnitData { @@ -584,7 +575,7 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat Flags = 2, GoldAmount = 12500, HeroLevel = 1, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; result.Add(unit); @@ -594,12 +585,12 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat } else if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "CreateItem", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "CreateItem", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0].TryGetIntegerExpressionValue(out var itemId) && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var y)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIntegerExpressionValue(out var itemId) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y)) { var item = new UnitData { @@ -611,7 +602,7 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat Flags = 2, GoldAmount = 12500, HeroLevel = 1, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; item.SkinId = item.TypeId; @@ -619,13 +610,13 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat result.Add(item); } } - else if (string.Equals(callStatement.IdentifierName.Name, "BlzCreateItemWithSkin", StringComparison.Ordinal)) + else if (string.Equals(callStatement.IdentifierName.Token.Text, "BlzCreateItemWithSkin", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 4 && - callStatement.Arguments.Arguments[0].TryGetIntegerExpressionValue(out var itemId) && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var y) && - callStatement.Arguments.Arguments[3].TryGetIntegerExpressionValue(out var skinId)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 4 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIntegerExpressionValue(out var itemId) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y) && + callStatement.ArgumentList.ArgumentList.Items[3].TryGetIntegerExpressionValue(out var skinId)) { var item = new UnitData { @@ -638,7 +629,7 @@ private bool TryDecompileCreateItemsFunction(JassFunctionDeclarationSyntax creat Flags = 2, GoldAmount = 12500, HeroLevel = 1, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; result.Add(item); @@ -655,15 +646,15 @@ private bool TryDecompileStartLocationPositionsConfigFunction(JassFunctionDeclar { var result = new Dictionary(); - foreach (var statement in configFunction.Body.Statements) + foreach (var statement in configFunction.Statements) { if (statement is JassCallStatementSyntax callStatement && - string.Equals(callStatement.IdentifierName.Name, "DefineStartLocation", StringComparison.Ordinal)) + string.Equals(callStatement.IdentifierName.Token.Text, "DefineStartLocation", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 3 && - callStatement.Arguments.Arguments[0].TryGetIntegerExpressionValue(out var index) && - callStatement.Arguments.Arguments[1].TryGetRealExpressionValue(out var x) && - callStatement.Arguments.Arguments[2].TryGetRealExpressionValue(out var y)) + if (callStatement.ArgumentList.ArgumentList.Items.Length == 3 && + callStatement.ArgumentList.ArgumentList.Items[0].TryGetIntegerExpressionValue(out var index) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetRealExpressionValue(out var x) && + callStatement.ArgumentList.ArgumentList.Items[2].TryGetRealExpressionValue(out var y)) { result.Add(index, new Vector2(x, y)); } @@ -690,23 +681,18 @@ private bool TryDecompileInitCustomPlayerSlotsFunction( { var result = new List(); - foreach (var statement in initCustomPlayerSlotsFunction.Body.Statements) + foreach (var statement in initCustomPlayerSlotsFunction.Statements) { - if (statement is JassCommentSyntax || - statement is JassEmptySyntax) - { - continue; - } - else if (statement is JassCallStatementSyntax callStatement) + if (statement is JassCallStatementSyntax callStatement) { - if (string.Equals(callStatement.IdentifierName.Name, "SetPlayerStartLocation", StringComparison.Ordinal)) + if (string.Equals(callStatement.IdentifierName.Token.Text, "SetPlayerStartLocation", StringComparison.Ordinal)) { - if (callStatement.Arguments.Arguments.Length == 2 && - callStatement.Arguments.Arguments[0] is JassInvocationExpressionSyntax playerInvocationExpression && - string.Equals(playerInvocationExpression.IdentifierName.Name, "Player", StringComparison.Ordinal) && - playerInvocationExpression.Arguments.Arguments.Length == 1 && - playerInvocationExpression.Arguments.Arguments[0].TryGetPlayerIdExpressionValue(Context.MaxPlayerSlots, out var playerId) && - callStatement.Arguments.Arguments[1].TryGetIntegerExpressionValue(out var startLocationNumber) && + if (callStatement.ArgumentList.ArgumentList.Items.Length == 2 && + callStatement.ArgumentList.ArgumentList.Items[0] is JassInvocationExpressionSyntax playerInvocationExpression && + string.Equals(playerInvocationExpression.IdentifierName.Token.Text, "Player", StringComparison.Ordinal) && + playerInvocationExpression.ArgumentList.ArgumentList.Items.Length == 1 && + playerInvocationExpression.ArgumentList.ArgumentList.Items[0].TryGetPlayerIdExpressionValue(Context.MaxPlayerSlots, out var playerId) && + callStatement.ArgumentList.ArgumentList.Items[1].TryGetIntegerExpressionValue(out var startLocationNumber) && startLocationPositions.TryGetValue(startLocationNumber, out var startLocationPosition)) { var unit = new UnitData @@ -720,7 +706,7 @@ callStatement.Arguments.Arguments[0] is JassInvocationExpressionSyntax playerInv GoldAmount = 12500, HeroLevel = 0, TargetAcquisition = 0, - CreationNumber = CreationNumber++ + CreationNumber = CreationNumber++, }; unit.SkinId = unit.TypeId; From 1aa1c64ff53b1256305fb3beac721447689fbf2c Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:22:32 +0100 Subject: [PATCH 18/53] Fix comment decompilation. --- .../Script/MapTriggersDecompiler.cs | 8 +++- .../IfStatementDecompiler.cs | 3 ++ .../LoopStatementDecompiler.cs | 1 + .../StatementListDecompiler.cs | 2 + .../SyntaxDecompilers/TriviaDecompiler.cs | 39 +++++++++++++------ 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs index 370cc511..654d6ffc 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/MapTriggersDecompiler.cs @@ -279,7 +279,9 @@ callStatement.ArgumentList.ArgumentList.Items[1] is JassFunctionReferenceExpress if (TryDecompileActionStatements(actionsFunction.Statements, out var actionFunctions)) { - trigger.Functions.AddRange(actionFunctions); + var functions = trigger.Functions; + functions.AddRange(actionFunctions); + DecompileLeadingTrivia(actionsFunction.EndFunctionToken.LeadingTrivia, ref functions); } else { @@ -309,7 +311,9 @@ conditionInvocationExpression.ArgumentList.ArgumentList.Items[0] is JassFunction if (TryDecompileConditionStatements(conditionsFunction.Statements, out var conditionFunctions)) { - trigger.Functions.AddRange(conditionFunctions); + var functions = trigger.Functions; + functions.AddRange(conditionFunctions); + DecompileLeadingTrivia(conditionsFunction.EndFunctionToken.LeadingTrivia, ref functions); } else { diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs index a882af5a..e84d2dd0 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/IfStatementDecompiler.cs @@ -40,6 +40,7 @@ private bool TryDecompileIfStatement( foreach (var elseIfClause in ifStatement.ElseIfClauses) { + DecompileLeadingTrivia(elseIfClause.ElseIfClauseDeclarator.ElseIfToken.LeadingTrivia, ref functions); functions.Add(DecompileCustomScriptAction(elseIfClause.ElseIfClauseDeclarator.ToString())); if (TryDecompileActionStatements(elseIfClause.Statements, out var elseIfActions)) @@ -54,6 +55,7 @@ private bool TryDecompileIfStatement( if (ifStatement.ElseClause is not null) { + DecompileLeadingTrivia(ifStatement.ElseClause.ElseToken.LeadingTrivia, ref functions); functions.Add(DecompileCustomScriptAction(ifStatement.ElseClause.ElseToken.ToString())); if (TryDecompileActionStatements(ifStatement.ElseClause.Statements, out var elseActions)) @@ -66,6 +68,7 @@ private bool TryDecompileIfStatement( } } + DecompileLeadingTrivia(ifStatement.EndIfToken.LeadingTrivia, ref functions); functions.Add(DecompileCustomScriptAction(ifStatement.EndIfToken.ToString())); return true; diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs index 65b3d41f..04774222 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs @@ -31,6 +31,7 @@ private bool TryDecompileLoopStatement( functions.Add(DecompileCustomScriptAction(loopStatement.LoopToken.ToString())); functions.AddRange(loopActions); + DecompileLeadingTrivia(loopStatement.EndLoopToken.LeadingTrivia, ref functions); functions.Add(DecompileCustomScriptAction(loopStatement.EndLoopToken.ToString())); return false; diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs index 815ffdf0..e1101106 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StatementListDecompiler.cs @@ -24,6 +24,8 @@ private bool TryDecompileActionStatements(ImmutableArray st for (var i = 0; i < statements.Length; i++) { + DecompileLeadingTrivia(statements[i].GetLeadingTrivia(), ref result); + if (!TryDecompileActionStatement(statements, ref i, ref result)) { result.Add(DecompileCustomScriptAction(statements[i].ToString())); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs index fc2bc5f8..120291bb 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/TriviaDecompiler.cs @@ -9,33 +9,50 @@ using System.Collections.Generic; using War3Net.Build.Script; +using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Decompilers { public partial class JassScriptDecompiler { + private void DecompileLeadingTrivia( + JassSyntaxTriviaList leadingTrivia, + ref List functions) + { + foreach (var trivia in leadingTrivia.Trivia) + { + _ = TryDecompileComment(trivia, ref functions); + } + } + private bool TryDecompileComment( JassSyntaxTrivia trivia, ref List functions) { - if (trivia.Text.Length > 3 && trivia.Text.StartsWith("// ", StringComparison.Ordinal)) + if (trivia.Text.StartsWith(JassSymbol.SlashSlash, StringComparison.Ordinal)) { - functions.Add(new TriggerFunction + if (trivia.Text.Length > 3 && trivia.Text[2] == JassSymbol.SpaceChar) { - Type = TriggerFunctionType.Action, - IsEnabled = true, - Name = "CommentString", - Parameters = new() + functions.Add(new TriggerFunction { - new TriggerFunctionParameter + Type = TriggerFunctionType.Action, + IsEnabled = true, + Name = "CommentString", + Parameters = new() { - Type = TriggerFunctionParameterType.String, - Value = trivia.Text[3..], + new TriggerFunctionParameter + { + Type = TriggerFunctionParameterType.String, + Value = trivia.Text[3..], + }, }, - }, - }); + }); + + return true; + } + functions.Add(DecompileCustomScriptAction(trivia.Text)); return true; } From 737f42e13c60334aa0e1ac36bd7ec93395d27d2f Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:24:39 +0100 Subject: [PATCH 19/53] JassScriptDecompiler fixes. --- .../SyntaxDecompilers/LoopStatementDecompiler.cs | 2 +- .../Widget/MapUnitsDecompiler.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs index 04774222..e02ba45d 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/LoopStatementDecompiler.cs @@ -34,7 +34,7 @@ private bool TryDecompileLoopStatement( DecompileLeadingTrivia(loopStatement.EndLoopToken.LeadingTrivia, ref functions); functions.Add(DecompileCustomScriptAction(loopStatement.EndLoopToken.ToString())); - return false; + return true; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs index 835ed4d1..021d9a25 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs @@ -255,11 +255,11 @@ variableDeclarator.Value.Expression is JassInvocationExpressionSyntax playerInvo return false; } } - else if (setStatement.Value.Expression is JassArrayReferenceExpressionSyntax) - { - // TODO - continue; - } + // else if (setStatement.Value.Expression is JassArrayReferenceExpressionSyntax) + // { + // // TODO + // continue; + // } else { units = null; From 2711753b8fd16bcfb461f72b4533b06527c1d722 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 11:55:07 +0100 Subject: [PATCH 20/53] Update tests. --- .../Providers/GameBuildsProviderTests.cs | 2 +- .../Parser/BinaryOperatorParserTests.cs | 30 ++-- .../Parser/ExpressionParserTests.cs | 165 ++++++++---------- .../SyntaxAssert.cs | 60 ++----- .../TriggerAssert.cs | 4 +- 5 files changed, 108 insertions(+), 153 deletions(-) diff --git a/tests/War3Net.Build.Core.Tests/Providers/GameBuildsProviderTests.cs b/tests/War3Net.Build.Core.Tests/Providers/GameBuildsProviderTests.cs index e9af8852..69d3b129 100644 --- a/tests/War3Net.Build.Core.Tests/Providers/GameBuildsProviderTests.cs +++ b/tests/War3Net.Build.Core.Tests/Providers/GameBuildsProviderTests.cs @@ -66,7 +66,7 @@ public void TestVersionAndEditorVersionMatch(Version version, EditorVersion? edi return mappings #if !ENABLE_FLAKY_TESTS - .Where(kvp => GameBuildsProvider.GetGameBuilds(kvp.Key).Any()) + .Where(kvp => GameBuildsProvider.GetGameBuilds(kvp.Key).Count > 0) #endif .Select(kvp => new object?[] { kvp.Key, kvp.Value }); } diff --git a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/BinaryOperatorParserTests.cs b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/BinaryOperatorParserTests.cs index 4d636eba..31678f98 100644 --- a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/BinaryOperatorParserTests.cs +++ b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/BinaryOperatorParserTests.cs @@ -9,8 +9,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using War3Net.CodeAnalysis.Jass.Syntax; - namespace War3Net.CodeAnalysis.Jass.Tests.Parser { [TestClass] @@ -18,10 +16,10 @@ public class BinaryOperatorParserTests { [TestMethod] [DynamicData(nameof(GetValidOperators), DynamicDataSourceType.Method)] - public void TestValidOperators(string binaryOperator, BinaryOperatorType expected) + public void TestValidOperators(string binaryOperator, JassSyntaxKind expected) { Assert.IsTrue(JassSyntaxFactory.TryParseBinaryOperator(binaryOperator, out var actual)); - Assert.AreEqual(expected, actual); + Assert.AreEqual(expected, actual.SyntaxKind); } [TestMethod] @@ -33,18 +31,18 @@ public void TestInvalidOperators(string binaryOperator) private static IEnumerable GetValidOperators() { - yield return new object?[] { "+", BinaryOperatorType.Add }; - yield return new object?[] { "-", BinaryOperatorType.Subtract }; - yield return new object?[] { "*", BinaryOperatorType.Multiplication }; - yield return new object?[] { "/", BinaryOperatorType.Division }; - yield return new object?[] { ">", BinaryOperatorType.GreaterThan }; - yield return new object?[] { "<", BinaryOperatorType.LessThan }; - yield return new object?[] { "==", BinaryOperatorType.Equals }; - yield return new object?[] { "!=", BinaryOperatorType.NotEquals }; - yield return new object?[] { ">=", BinaryOperatorType.GreaterOrEqual }; - yield return new object?[] { "<=", BinaryOperatorType.LessOrEqual }; - yield return new object?[] { "and", BinaryOperatorType.And }; - yield return new object?[] { "or", BinaryOperatorType.Or }; + yield return new object?[] { "+", JassSyntaxKind.PlusToken }; + yield return new object?[] { "-", JassSyntaxKind.MinusToken }; + yield return new object?[] { "*", JassSyntaxKind.AsteriskToken }; + yield return new object?[] { "/", JassSyntaxKind.SlashToken }; + yield return new object?[] { ">", JassSyntaxKind.GreaterThanToken }; + yield return new object?[] { "<", JassSyntaxKind.LessThanToken }; + yield return new object?[] { "==", JassSyntaxKind.EqualsEqualsToken }; + yield return new object?[] { "!=", JassSyntaxKind.ExclamationEqualsToken }; + yield return new object?[] { ">=", JassSyntaxKind.GreaterThanEqualsToken }; + yield return new object?[] { "<=", JassSyntaxKind.LessThanEqualsToken }; + yield return new object?[] { "and", JassSyntaxKind.AndKeyword }; + yield return new object?[] { "or", JassSyntaxKind.OrKeyword }; } private static IEnumerable GetInvalidOperators() diff --git a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs index a7672794..8cd8fa52 100644 --- a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs +++ b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs @@ -22,7 +22,7 @@ public class ExpressionParserTests { [TestMethod] [DynamicData(nameof(GetTestExpressions), DynamicDataSourceType.Method)] - public void TestExpressionParser(string expression, IExpressionSyntax? expected = null) + public void TestExpressionParser(string expression, JassExpressionSyntax? expected = null) { if (expected is null) { @@ -39,9 +39,9 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected { #region InvocationExpression yield return new object?[] { @"foo()", InvocationExpression(@"foo") }; - yield return new object?[] { @"foo( bar )", InvocationExpression(@"foo", VariableReferenceExpression(@"bar")) }; - yield return new object?[] { @"foo ( a , b )", InvocationExpression(@"foo", VariableReferenceExpression(@"a"), VariableReferenceExpression(@"b")) }; - yield return new object?[] { @"foo(a,b)", InvocationExpression(@"foo", VariableReferenceExpression(@"a"), VariableReferenceExpression(@"b")) }; + yield return new object?[] { @"foo( bar )", InvocationExpression(@"foo", IdentifierName(@"bar")) }; + yield return new object?[] { @"foo ( a , b )", InvocationExpression(@"foo", IdentifierName(@"a"), IdentifierName(@"b")) }; + yield return new object?[] { @"foo(a,b)", InvocationExpression(@"foo", IdentifierName(@"a"), IdentifierName(@"b")) }; yield return new object?[] { @"foo(,)" }; yield return new object?[] { @"foo(a,)" }; yield return new object?[] { @"foo(,b)" }; @@ -53,7 +53,7 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected #endregion #region ArrayReferenceExpression - yield return new object?[] { @"foo[bar]", ArrayReferenceExpression(@"foo", VariableReferenceExpression(@"bar")) }; + yield return new object?[] { @"foo[bar]", ElementAccessExpression(@"foo", IdentifierName(@"bar")) }; yield return new object?[] { @"foo[bar" }; #endregion @@ -64,8 +64,8 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected #endregion #region VariableReferenceExpression - yield return new object?[] { @"player_id", VariableReferenceExpression(@"player_id") }; - yield return new object?[] { @"player_6", VariableReferenceExpression(@"player_6") }; + yield return new object?[] { @"player_id", IdentifierName(@"player_id") }; + yield return new object?[] { @"player_6", IdentifierName(@"player_6") }; yield return new object?[] { @"player_" }; yield return new object?[] { @"_player" }; yield return new object?[] { @"6player" }; @@ -76,29 +76,29 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected #endregion #region DecimalLiteralExpression - yield return new object?[] { @"1", new JassDecimalLiteralExpressionSyntax(1) }; - yield return new object?[] { @"255", new JassDecimalLiteralExpressionSyntax(255) }; + yield return new object?[] { @"1", LiteralExpression(Literal(1)) }; + yield return new object?[] { @"255", LiteralExpression(Literal(255)) }; yield return new object?[] { @"255abc" }; yield return new object?[] { @"255_" }; #endregion #region OctalLiteralExpression - yield return new object?[] { @"0", new JassOctalLiteralExpressionSyntax(0) }; - yield return new object?[] { @"010", new JassOctalLiteralExpressionSyntax(8) }; + yield return new object?[] { @"0", LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")) }; + yield return new object?[] { @"010", LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "010")) }; yield return new object?[] { @"0abc" }; yield return new object?[] { @"0_" }; #endregion #region HexadecimalLiteralExpression - yield return new object?[] { @"$6", new JassHexadecimalLiteralExpressionSyntax(6) }; - yield return new object?[] { @"$A", new JassHexadecimalLiteralExpressionSyntax(10) }; - yield return new object?[] { @"$FF", new JassHexadecimalLiteralExpressionSyntax(255) }; - yield return new object?[] { @"0x6", new JassHexadecimalLiteralExpressionSyntax(6) }; - yield return new object?[] { @"0xA", new JassHexadecimalLiteralExpressionSyntax(10) }; - yield return new object?[] { @"0xFF", new JassHexadecimalLiteralExpressionSyntax(255) }; - yield return new object?[] { @"0X6", new JassHexadecimalLiteralExpressionSyntax(6) }; - yield return new object?[] { @"0XA", new JassHexadecimalLiteralExpressionSyntax(10) }; - yield return new object?[] { @"0XFF", new JassHexadecimalLiteralExpressionSyntax(255) }; + yield return new object?[] { @"$6", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "$6")) }; + yield return new object?[] { @"$A", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "$A")) }; + yield return new object?[] { @"$FF", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "$FF")) }; + yield return new object?[] { @"0x6", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "0x6")) }; + yield return new object?[] { @"0xA", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "0xA")) }; + yield return new object?[] { @"0xFF", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "0xFF")) }; + yield return new object?[] { @"0X6", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "0X6")) }; + yield return new object?[] { @"0XA", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "0XA")) }; + yield return new object?[] { @"0XFF", LiteralExpression(Token(JassSyntaxKind.HexadecimalLiteralToken, "0XFF")) }; yield return new object?[] { @"$ALOL" }; yield return new object?[] { @"$A_" }; yield return new object?[] { @"0xLOL" }; @@ -108,7 +108,7 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected #endregion #region FourCCLiteralExpression - yield return new object?[] { @"'hpea'", new JassFourCCLiteralExpressionSyntax(@"hpea".FromJassRawcode()) }; + yield return new object?[] { @"'hpea'", LiteralExpression(FourCCLiteral(@"hpea".FromJassRawcode())) }; yield return new object?[] { @"'hpeasant'" }; yield return new object?[] { @"'pea'" }; yield return new object?[] { @"''" }; @@ -116,9 +116,9 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected #endregion #region RealLiteralExpression - yield return new object?[] { @"0.", LiteralExpression(0f, precision: 0) }; - yield return new object?[] { @".0", LiteralExpression(0f) }; - yield return new object?[] { @"3.141", LiteralExpression(3.141f, precision: 3) }; + yield return new object?[] { @"0.", LiteralExpression(Token(JassSyntaxKind.RealLiteralToken, "0.")) }; + yield return new object?[] { @".0", LiteralExpression(Token(JassSyntaxKind.RealLiteralToken, ".0")) }; + yield return new object?[] { @"3.141", LiteralExpression(Token(JassSyntaxKind.RealLiteralToken, "3.141")) }; yield return new object?[] { @"." }; yield return new object?[] { @"0.abc" }; yield return new object?[] { @"0.0abc" }; @@ -126,27 +126,27 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected #endregion #region BooleanLiteralExpression - yield return new object?[] { @"true", JassBooleanLiteralExpressionSyntax.True }; - yield return new object?[] { @"false", JassBooleanLiteralExpressionSyntax.False }; + yield return new object?[] { @"true", LiteralExpression(Literal(true)) }; + yield return new object?[] { @"false", LiteralExpression(Literal(false)) }; #endregion #region StringLiteralExpression - yield return new object?[] { "\" true \"", new JassStringLiteralExpressionSyntax(" true ") }; - yield return new object?[] { "\" \\\"true\\\" \"", new JassStringLiteralExpressionSyntax(" \\\"true\\\" ") }; - yield return new object?[] { "\" \r\t\\\\ \"", new JassStringLiteralExpressionSyntax(" \r\t\\\\ ") }; + yield return new object?[] { "\" true \"", LiteralExpression(Literal(" true ")) }; + yield return new object?[] { "\" \\\"true\\\" \"", LiteralExpression(Literal(" \\\"true\\\" ")) }; + yield return new object?[] { "\" \r\t\\\\ \"", LiteralExpression(Literal(" \r\t\\\\ ")) }; yield return new object?[] { "\" true" }; - yield return new object?[] { "\" \n \"", new JassStringLiteralExpressionSyntax(" \n ") }; + yield return new object?[] { "\" \n \"", LiteralExpression(Literal(" \n ")) }; #endregion #region NullLiteralExpression - yield return new object?[] { @"null", JassNullLiteralExpressionSyntax.Value }; + yield return new object?[] { @"null", LiteralExpression(Literal(null)) }; #endregion #region ParenthesizedExpression - yield return new object?[] { @"(0)", new JassParenthesizedExpressionSyntax(new JassOctalLiteralExpressionSyntax(0)) }; - yield return new object?[] { @"(1)", new JassParenthesizedExpressionSyntax(new JassDecimalLiteralExpressionSyntax(1)) }; - yield return new object?[] { @"(player_id)", new JassParenthesizedExpressionSyntax(VariableReferenceExpression(@"player_id")) }; - yield return new object?[] { @"( player_id )", new JassParenthesizedExpressionSyntax(VariableReferenceExpression(@"player_id")) }; + yield return new object?[] { @"(0)", ParenthesizedExpression(LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0"))) }; + yield return new object?[] { @"(1)", ParenthesizedExpression(LiteralExpression(Literal(1))) }; + yield return new object?[] { @"(player_id)", ParenthesizedExpression(IdentifierName(@"player_id")) }; + yield return new object?[] { @"( player_id )", ParenthesizedExpression(IdentifierName(@"player_id")) }; yield return new object?[] { @"(player_id" }; yield return new object?[] { @"player_id)" }; yield return new object?[] { @"()" }; @@ -158,59 +158,54 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected yield return new object?[] { @"(5 > 0)", - ParenthesizedExpression(new JassBinaryExpressionSyntax( - BinaryOperatorType.GreaterThan, - new JassDecimalLiteralExpressionSyntax(5), - new JassOctalLiteralExpressionSyntax(0))), + ParenthesizedExpression(BinaryGreaterThanExpression( + LiteralExpression(Literal(5)), + LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")))), }; yield return new object?[] { @"(0 > foo())", - new JassParenthesizedExpressionSyntax(new JassBinaryExpressionSyntax( - BinaryOperatorType.GreaterThan, - new JassOctalLiteralExpressionSyntax(0), + ParenthesizedExpression(BinaryGreaterThanExpression( + LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")), InvocationExpression("foo"))), }; yield return new object?[] { @"(foo() > 0)", - new JassParenthesizedExpressionSyntax(new JassBinaryExpressionSyntax( - BinaryOperatorType.GreaterThan, + ParenthesizedExpression(BinaryGreaterThanExpression( InvocationExpression("foo"), - new JassOctalLiteralExpressionSyntax(0))), + LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")))), }; yield return new object?[] { "(GetUnitState(oldUnit, UNIT_STATE_MAX_LIFE) > 0)", - new JassParenthesizedExpressionSyntax(new JassBinaryExpressionSyntax( - BinaryOperatorType.GreaterThan, + ParenthesizedExpression(BinaryGreaterThanExpression( InvocationExpression( "GetUnitState", - VariableReferenceExpression("oldUnit"), - VariableReferenceExpression("UNIT_STATE_MAX_LIFE")), - new JassOctalLiteralExpressionSyntax(0))), + IdentifierName("oldUnit"), + IdentifierName("UNIT_STATE_MAX_LIFE")), + LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")))), }; #endregion #region UnaryExpression - yield return new object?[] { @"+6", new JassUnaryExpressionSyntax(UnaryOperatorType.Plus, new JassDecimalLiteralExpressionSyntax(6)) }; - yield return new object?[] { @"-7", new JassUnaryExpressionSyntax(UnaryOperatorType.Minus, new JassDecimalLiteralExpressionSyntax(7)) }; - yield return new object?[] { @"+ 6", new JassUnaryExpressionSyntax(UnaryOperatorType.Plus, new JassDecimalLiteralExpressionSyntax(6)) }; - yield return new object?[] { @"- 7", new JassUnaryExpressionSyntax(UnaryOperatorType.Minus, new JassDecimalLiteralExpressionSyntax(7)) }; - yield return new object?[] { @"not true", new JassUnaryExpressionSyntax(UnaryOperatorType.Not, JassBooleanLiteralExpressionSyntax.True) }; - yield return new object?[] { @"not(true)", new JassUnaryExpressionSyntax(UnaryOperatorType.Not, new JassParenthesizedExpressionSyntax(JassBooleanLiteralExpressionSyntax.True)) }; - yield return new object?[] { @"nottrue", VariableReferenceExpression(@"nottrue") }; + yield return new object?[] { @"+6", UnaryPlusExpression(LiteralExpression(Literal(6))) }; + yield return new object?[] { @"-7", UnaryMinusExpression(LiteralExpression(Literal(7))) }; + yield return new object?[] { @"+ 6", UnaryPlusExpression(LiteralExpression(Literal(6))) }; + yield return new object?[] { @"- 7", UnaryMinusExpression(LiteralExpression(Literal(7))) }; + yield return new object?[] { @"not true", UnaryNotExpression(LiteralExpression(Literal(true))) }; + yield return new object?[] { @"not(true)", UnaryNotExpression(ParenthesizedExpression(LiteralExpression(Literal(true)))) }; + yield return new object?[] { @"nottrue", IdentifierName(@"nottrue") }; #endregion - yield return new object?[] { @"trueandfalseornull", VariableReferenceExpression(@"trueandfalseornull") }; + yield return new object?[] { @"trueandfalseornull", IdentifierName(@"trueandfalseornull") }; - var expr1 = new JassBinaryExpressionSyntax( - BinaryOperatorType.Add, - new JassDecimalLiteralExpressionSyntax(50), - new JassDecimalLiteralExpressionSyntax(60)); + var expr1 = BinaryAdditionExpression( + LiteralExpression(Literal(50)), + LiteralExpression(Literal(60))); yield return new object?[] { @"50+60", expr1 }; yield return new object?[] { @"50 + 60", expr1 }; @@ -219,33 +214,29 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected yield return new object?[] { @"2 + 6 * 10", - new JassBinaryExpressionSyntax( - BinaryOperatorType.Add, - new JassDecimalLiteralExpressionSyntax(2), - new JassBinaryExpressionSyntax( - BinaryOperatorType.Multiplication, - new JassDecimalLiteralExpressionSyntax(6), - new JassDecimalLiteralExpressionSyntax(10))), + BinaryAdditionExpression( + LiteralExpression(Literal(2)), + BinaryMultiplicationExpression( + LiteralExpression(Literal(6)), + LiteralExpression(Literal(10)))), }; yield return new object?[] { @"(2 + 6) * 10", - new JassBinaryExpressionSyntax( - BinaryOperatorType.Multiplication, - new JassParenthesizedExpressionSyntax(new JassBinaryExpressionSyntax( - BinaryOperatorType.Add, - new JassDecimalLiteralExpressionSyntax(2), - new JassDecimalLiteralExpressionSyntax(6))), - new JassDecimalLiteralExpressionSyntax(10)), + BinaryMultiplicationExpression( + ParenthesizedExpression(BinaryAdditionExpression( + LiteralExpression(Literal(2)), + LiteralExpression(Literal(6)))), + LiteralExpression(Literal(10))), }; + yield return new object?[] { @"(player_id) * 10", - new JassBinaryExpressionSyntax( - BinaryOperatorType.Multiplication, - new JassParenthesizedExpressionSyntax(VariableReferenceExpression(@"player_id")), - new JassDecimalLiteralExpressionSyntax(10)), + BinaryMultiplicationExpression( + ParenthesizedExpression(IdentifierName(@"player_id")), + LiteralExpression(Literal(10))), }; yield return new object?[] @@ -259,17 +250,15 @@ public void TestExpressionParser(string expression, IExpressionSyntax? expected yield return new object?[] { @"FORCE_ALL_PLAYERS[(player_id - 1)] == ConvertedPlayer(player_id)", - new JassBinaryExpressionSyntax( - BinaryOperatorType.Equals, - ArrayReferenceExpression( + BinaryEqualsExpression( + ElementAccessExpression( @"FORCE_ALL_PLAYERS", - new JassParenthesizedExpressionSyntax(new JassBinaryExpressionSyntax( - BinaryOperatorType.Subtract, - VariableReferenceExpression(@"player_id"), - new JassDecimalLiteralExpressionSyntax(1)))), + ParenthesizedExpression(BinarySubtractionExpression( + IdentifierName(@"player_id"), + LiteralExpression(Literal(1))))), InvocationExpression( @"ConvertedPlayer", - VariableReferenceExpression(@"player_id"))), + IdentifierName(@"player_id"))), }; } } diff --git a/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs b/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs index db5f81d9..9b7fdfce 100644 --- a/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs +++ b/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs @@ -28,29 +28,13 @@ public static void AreEqual(JassCompilationUnitSyntax? expected, JassCompilation } } - //public static void AreEqual(IDeclarationLineSyntax? expected, IDeclarationLineSyntax? actual) - //{ - // if (!expected.NullableEquals(actual)) - // { - // Assert.Fail("Declaration lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); - // } - //} - - //public static void AreEqual(IGlobalLineSyntax? expected, IGlobalLineSyntax? actual) - //{ - // if (!expected.NullableEquals(actual)) - // { - // Assert.Fail("Global lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); - // } - //} - - //public static void AreEqual(IStatementLineSyntax? expected, IStatementLineSyntax? actual) - //{ - // if (!expected.NullableEquals(actual)) - // { - // Assert.Fail("Statement lines are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); - // } - //} + public static void AreEqual(JassSyntaxNode? expected, JassSyntaxNode? actual) + { + if (!expected.NullableEquivalentTo(actual)) + { + Assert.Fail("Syntax nodes are not equal:\r\n" + GetAssertFailedMessage(expected, actual)); + } + } public static void AreEqual(JassExpressionSyntax? expected, JassExpressionSyntax? actual) { @@ -84,29 +68,13 @@ public static void AreNotEqual(JassCompilationUnitSyntax? expected, JassCompilat } } - //public static void AreNotEqual(IDeclarationLineSyntax? expected, IDeclarationLineSyntax? actual) - //{ - // if (expected.NullableEquals(actual)) - // { - // Assert.Fail($"Declaration lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); - // } - //} - - //public static void AreNotEqual(IGlobalLineSyntax? expected, IGlobalLineSyntax? actual) - //{ - // if (expected.NullableEquals(actual)) - // { - // Assert.Fail($"Global lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); - // } - //} - - //public static void AreNotEqual(IStatementLineSyntax? expected, IStatementLineSyntax? actual) - //{ - // if (expected.NullableEquals(actual)) - // { - // Assert.Fail($"Statement lines are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); - // } - //} + public static void AreNotEqual(JassSyntaxNode? expected, JassSyntaxNode? actual) + { + if (expected.NullableEquivalentTo(actual)) + { + Assert.Fail($"Syntax nodes are equal:\r\n'{expected?.ToString()}'<{expected?.GetType().Name ?? "null"}>."); + } + } public static void AreNotEqual(JassTopLevelDeclarationSyntax? expected, JassTopLevelDeclarationSyntax? actual) { diff --git a/tests/War3Net.TestTools.UnitTesting/TriggerAssert.cs b/tests/War3Net.TestTools.UnitTesting/TriggerAssert.cs index 1b02441a..c193c2e8 100644 --- a/tests/War3Net.TestTools.UnitTesting/TriggerAssert.cs +++ b/tests/War3Net.TestTools.UnitTesting/TriggerAssert.cs @@ -101,8 +101,8 @@ public static void AreEqual(TriggerFunction expectedFunction, TriggerFunction ac var expectedFunctionParameter = expectedFunction.Parameters.Single(); var actualFunctionParameter = actualFunction.Parameters.Single(); - var expectedCustomScriptAction = JassSyntaxFactory.ParseStatementLine(expectedFunctionParameter.Value); - var actualCustomScriptAction = JassSyntaxFactory.ParseStatementLine(actualFunctionParameter.Value); + var expectedCustomScriptAction = JassSyntaxFactory.ParseCustomScriptAction(expectedFunctionParameter.Value); + var actualCustomScriptAction = JassSyntaxFactory.ParseCustomScriptAction(actualFunctionParameter.Value); Assert.AreEqual(expectedFunctionParameter.Type, actualFunctionParameter.Type); SyntaxAssert.AreEqual(expectedCustomScriptAction, actualCustomScriptAction); From 750ef9886b3d376648c22a30bacf8770f32e0f9b Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:12:54 +0100 Subject: [PATCH 21/53] Rename Newline -> NewLine for consistency with system libraries. --- src/War3Net.CodeAnalysis.Jass/JassParser.cs | 8 ++++---- .../JassParser/SyntaxTriviaListParser.cs | 10 +++++----- .../JassParser/SyntaxTriviaParser.cs | 8 ++++---- .../JassSyntaxFacts.cs | 2 +- .../JassSyntaxKind.cs | 2 +- .../JassSyntaxKindFacts.cs | 2 +- .../JassSyntaxNormalizer.cs | 4 ++-- .../Normalizer/CallStatementNormalizer.cs | 2 +- .../Normalizer/ExitStatementNormalizer.cs | 2 +- .../Normalizer/FunctionDeclaratorNormalizer.cs | 2 +- .../GlobalConstantDeclarationNormalizer.cs | 2 +- .../GlobalVariableDeclarationNormalizer.cs | 2 +- ...alVariableDeclarationStatementNormalizer.cs | 2 +- .../NativeFunctionDeclarationNormalizer.cs | 2 +- .../Normalizer/ReturnStatementNormalizer.cs | 2 +- .../Normalizer/SetStatementNormalizer.cs | 2 +- .../Normalizer/SyntaxTokenNormalizer.cs | 8 ++++---- .../Normalizer/SyntaxTriviaListNormalizer.cs | 18 +++++++++--------- .../Normalizer/TypeDeclarationNormalizer.cs | 2 +- .../Renderer/SyntaxTriviaRenderer.cs | 2 +- .../Syntax/JassSyntaxTrivia.cs | 4 ++-- .../Syntax/JassSyntaxTriviaList.cs | 2 +- .../SyntaxFactory/SyntaxTriviaFactory.cs | 6 +++--- .../JassToCSharp/SyntaxTriviaTranspiler.cs | 2 +- 24 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser.cs index 59b215e7..72cbcaa7 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser.cs @@ -37,8 +37,8 @@ internal partial class JassParser private JassParser() { var whitespaceTriviaParser = GetWhitespaceTriviaParser(); - var newlineTriviaParser = GetNewlineTriviaParser(); - var singleNewlineTriviaParser = GetSingleNewlineTriviaParser(); + var newLineTriviaParser = GetNewLineTriviaParser(); + var singleNewLineTriviaParser = GetSingleNewLineTriviaParser(); var singleLineCommentTriviaParser = GetSingleLineCommentTriviaParser(); var simpleTriviaListParser = GetSimpleTriviaListParser( @@ -46,12 +46,12 @@ private JassParser() var leadingTriviaListParser = GetLeadingTriviaListParser( whitespaceTriviaParser, - newlineTriviaParser, + newLineTriviaParser, singleLineCommentTriviaParser); var trailingTriviaListParser = GetTrailingTriviaListParser( whitespaceTriviaParser, - singleNewlineTriviaParser, + singleNewLineTriviaParser, singleLineCommentTriviaParser); var identifierParser = GetIdentifierParser(); diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs index b8bdd6db..f9276b0c 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs @@ -29,13 +29,13 @@ internal static Parser GetSimpleTriviaListParser( internal static Parser GetLeadingTriviaListParser( Parser whitespaceTriviaParser, - Parser newlineTriviaParser, + Parser newLineTriviaParser, Parser singleLineCommentTriviaParser) { return OneOf( OneOf( whitespaceTriviaParser, - newlineTriviaParser, + newLineTriviaParser, singleLineCommentTriviaParser) .Many() .Select(trivia => new JassSyntaxTriviaList(trivia.ToImmutableArray())), @@ -44,7 +44,7 @@ internal static Parser GetLeadingTriviaListParser( internal static Parser GetTrailingTriviaListParser( Parser whitespaceTriviaParser, - Parser singleNewlineTriviaParser, + Parser singleNewLineTriviaParser, Parser singleLineCommentTriviaParser) { return OneOf( @@ -54,9 +54,9 @@ internal static Parser GetTrailingTriviaListParser( .Many() .Then( OneOf( - singleNewlineTriviaParser.Select(newline => Maybe.Just(newline)), + singleNewLineTriviaParser.Select(newLine => Maybe.Just(newLine)), End.ThenReturn(Maybe.Nothing())), - (trivia, newline) => new JassSyntaxTriviaList((newline.HasValue ? trivia.Append(newline.Value) : trivia).ToImmutableArray())), + (trivia, newLine) => new JassSyntaxTriviaList((newLine.HasValue ? trivia.Append(newLine.Value) : trivia).ToImmutableArray())), Return(JassSyntaxTriviaList.Empty)); } } diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs index 9fb076a6..43cc76f6 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs @@ -23,20 +23,20 @@ internal static Parser GetWhitespaceTriviaParser() .Select(whitespace => new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, whitespace)); } - internal static Parser GetNewlineTriviaParser() + internal static Parser GetNewLineTriviaParser() { return OneOf(Symbol.CarriageReturn, Symbol.LineFeed) .AtLeastOnceString() - .Select(newline => new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, newline)); + .Select(newLine => new JassSyntaxTrivia(JassSyntaxKind.NewLineTrivia, newLine)); } - internal static Parser GetSingleNewlineTriviaParser() + internal static Parser GetSingleNewLineTriviaParser() { return OneOf( Try(Symbol.CarriageReturnLineFeed), Symbol.CarriageReturnString, Symbol.LineFeedString) - .Select(newline => new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, newline)); + .Select(newLine => new JassSyntaxTrivia(JassSyntaxKind.NewLineTrivia, newLine)); } internal static Parser GetSingleLineCommentTriviaParser() diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs index 2d753940..cc8a8165 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFacts.cs @@ -17,7 +17,7 @@ public static bool IsWhitespaceCharacter(char ch) || ch == JassSymbol.TabChar; } - public static bool IsNewlineCharacter(char ch) + public static bool IsNewLineCharacter(char ch) { return ch == JassSymbol.CarriageReturnChar || ch == JassSymbol.LineFeedChar; diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs index e61446ef..b117f54c 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKind.cs @@ -242,7 +242,7 @@ public enum JassSyntaxKind OctalLiteralToken = 8514, FourCCLiteralToken = 8515, - NewlineTrivia = 8539, + NewLineTrivia = 8539, WhitespaceTrivia = 8540, SingleLineCommentTrivia = 8541, diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs index 027f1cba..3cdd72c7 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxKindFacts.cs @@ -48,7 +48,7 @@ public static bool IsAnyToken(JassSyntaxKind syntaxKind) public static bool IsTrivia(JassSyntaxKind syntaxKind) { - return syntaxKind >= JassSyntaxKind.NewlineTrivia && syntaxKind <= JassSyntaxKind.SingleLineCommentTrivia; + return syntaxKind >= JassSyntaxKind.NewLineTrivia && syntaxKind <= JassSyntaxKind.SingleLineCommentTrivia; } public static bool IsBinaryExpressionToken(JassSyntaxKind binaryOperatorTokenSyntaxKind) diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs index c8181419..ff2f275b 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxNormalizer.cs @@ -26,7 +26,7 @@ internal sealed partial class JassSyntaxNormalizer : JassSyntaxRewriter private int _currentLevelOfIndentation; private bool _encounteredAnyTextOnCurrentLine; - private bool _requireNewlineTrivia; + private bool _requireNewLineTrivia; public JassSyntaxNormalizer( bool addSpacesToOuterInvocation = true, @@ -46,7 +46,7 @@ public JassSyntaxNormalizer( _currentLevelOfIndentation = 0; _encounteredAnyTextOnCurrentLine = false; - _requireNewlineTrivia = false; + _requireNewLineTrivia = false; } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs index 630eb80d..d7230856 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/CallStatementNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteCallStatement(JassCallStatementSyntax callStateme var normalized = base.RewriteCallStatement(callStatement, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs index 235f25a5..2b845d05 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ExitStatementNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteExitStatement(JassExitStatementSyntax exitStateme var normalized = base.RewriteExitStatement(exitStatement, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs index 2cf5b09b..76fa8cc5 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/FunctionDeclaratorNormalizer.cs @@ -19,7 +19,7 @@ protected override bool RewriteFunctionDeclarator(JassFunctionDeclaratorSyntax f _nodes.RemoveAt(_nodes.Count - 1); _currentLevelOfIndentation++; - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs index 3cdfa911..2942ec3f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalConstantDeclarationNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteGlobalConstantDeclaration(JassGlobalConstantDecla var normalized = base.RewriteGlobalConstantDeclaration(globalConstantDeclaration, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs index b8e88144..d76fa00d 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/GlobalVariableDeclarationNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteGlobalVariableDeclaration(JassGlobalVariableDecla var normalized = base.RewriteGlobalVariableDeclaration(globalVariableDeclaration, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs index 53563600..ca891893 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/LocalVariableDeclarationStatementNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteLocalVariableDeclarationStatement(JassLocalVariab var normalized = base.RewriteLocalVariableDeclarationStatement(localVariableDeclarationStatement, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs index ce580432..0592bc5e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/NativeFunctionDeclarationNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteNativeFunctionDeclaration(JassNativeFunctionDecla var normalized = base.RewriteNativeFunctionDeclaration(nativeFunctionDeclaration, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs index 32083ebf..b9fd90a1 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/ReturnStatementNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteReturnStatement(JassReturnStatementSyntax returnS var normalized = base.RewriteReturnStatement(returnStatement, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs index 1fba3b99..5b5ba385 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/SetStatementNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteSetStatement(JassSetStatementSyntax setStatement, var normalized = base.RewriteSetStatement(setStatement, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs index ec76c600..0f7e59f9 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTokenNormalizer.cs @@ -16,7 +16,7 @@ partial class JassSyntaxNormalizer { private static readonly HashSet _increaseIndentationSyntaxKinds = GetIncreaseIndentationSyntaxKinds(); private static readonly HashSet _decreaseIndentationSyntaxKinds = GetDecreaseIndentationSyntaxKinds(); - private static readonly HashSet _requireNewlineSyntaxKinds = GetRequireNewlineSyntaxKinds(); + private static readonly HashSet _requireNewLineSyntaxKinds = GetRequireNewLineSyntaxKinds(); /// protected override bool RewriteToken(JassSyntaxToken? token, [NotNullIfNotNull("token")] out JassSyntaxToken? result) @@ -36,9 +36,9 @@ protected override bool RewriteToken(JassSyntaxToken? token, [NotNullIfNotNull(" var normalizedLeadingTrivia = RewriteLeadingTrivia(token.LeadingTrivia, out var leadingTrivia); - if (_requireNewlineSyntaxKinds.Contains(_currentToken.SyntaxKind)) + if (_requireNewLineSyntaxKinds.Contains(_currentToken.SyntaxKind)) { - _requireNewlineTrivia = true; + _requireNewLineTrivia = true; } if (_increaseIndentationSyntaxKinds.Contains(_currentToken.SyntaxKind)) @@ -98,7 +98,7 @@ private static HashSet GetDecreaseIndentationSyntaxKinds() }; } - private static HashSet GetRequireNewlineSyntaxKinds() + private static HashSet GetRequireNewLineSyntaxKinds() { return new HashSet { diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs index a97efe3a..ec0b14e3 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/SyntaxTriviaListNormalizer.cs @@ -19,11 +19,11 @@ protected override bool RewriteLeadingTrivia(JassSyntaxTriviaList triviaList, ou { var triviaBuilder = ImmutableArray.CreateBuilder(); - if (_requireNewlineTrivia) + if (_requireNewLineTrivia) { - triviaBuilder.Add(JassSyntaxTrivia.Newline); + triviaBuilder.Add(JassSyntaxTrivia.NewLine); _encounteredAnyTextOnCurrentLine = false; - _requireNewlineTrivia = false; + _requireNewLineTrivia = false; } HandleExistingTrivia(triviaList, triviaBuilder); @@ -157,11 +157,11 @@ private void HandleExistingTrivia(JassSyntaxTriviaList triviaList, ImmutableArra for (var i = 0; i < triviaList.Trivia.Length; i++) { var trivia = triviaList.Trivia[i]; - if (trivia.SyntaxKind == JassSyntaxKind.NewlineTrivia) + if (trivia.SyntaxKind == JassSyntaxKind.NewLineTrivia) { triviaBuilder.Add(trivia); _encounteredAnyTextOnCurrentLine = false; - _requireNewlineTrivia = false; + _requireNewLineTrivia = false; } else if (trivia.SyntaxKind == JassSyntaxKind.SingleLineCommentTrivia) { @@ -187,15 +187,15 @@ private void HandleExistingTrivia(JassSyntaxTriviaList triviaList, ImmutableArra triviaBuilder.Add(trivia); } - _requireNewlineTrivia = true; + _requireNewLineTrivia = true; } } - if (_requireNewlineTrivia) + if (_requireNewLineTrivia) { - triviaBuilder.Add(JassSyntaxTrivia.Newline); + triviaBuilder.Add(JassSyntaxTrivia.NewLine); _encounteredAnyTextOnCurrentLine = false; - _requireNewlineTrivia = false; + _requireNewLineTrivia = false; } } } diff --git a/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs b/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs index ff54b325..6728b78e 100644 --- a/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Normalizer/TypeDeclarationNormalizer.cs @@ -18,7 +18,7 @@ protected override bool RewriteTypeDeclaration(JassTypeDeclarationSyntax typeDec var normalized = base.RewriteTypeDeclaration(typeDeclaration, out result); _nodes.RemoveAt(_nodes.Count - 1); - _requireNewlineTrivia = _encounteredAnyTextOnCurrentLine; + _requireNewLineTrivia = _encounteredAnyTextOnCurrentLine; return normalized; } diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs index c05aa805..bc4a4923 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/SyntaxTriviaRenderer.cs @@ -18,7 +18,7 @@ public void Render(JassSyntaxTrivia trivia) WriteSpace(); Write(trivia.Text.TrimEnd()); } - else if (trivia.SyntaxKind == JassSyntaxKind.NewlineTrivia) + else if (trivia.SyntaxKind == JassSyntaxKind.NewLineTrivia) { var lines = 0; var isCarriageReturn = false; diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs index 34a69923..8d21d354 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTrivia.cs @@ -13,8 +13,8 @@ namespace War3Net.CodeAnalysis.Jass.Syntax { public class JassSyntaxTrivia { - public static readonly JassSyntaxTrivia SingleSpace = new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, JassSymbol.Space); - public static readonly JassSyntaxTrivia Newline = new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, JassSymbol.CarriageReturnLineFeed); + public static readonly JassSyntaxTrivia SingleSpace = new(JassSyntaxKind.WhitespaceTrivia, JassSymbol.Space); + public static readonly JassSyntaxTrivia NewLine = new(JassSyntaxKind.NewLineTrivia, JassSymbol.CarriageReturnLineFeed); internal JassSyntaxTrivia( JassSyntaxKind syntaxKind, diff --git a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs index 094c2624..8ae869f5 100644 --- a/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs +++ b/src/War3Net.CodeAnalysis.Jass/Syntax/JassSyntaxTriviaList.cs @@ -14,7 +14,7 @@ public class JassSyntaxTriviaList { public static readonly JassSyntaxTriviaList Empty = new(ImmutableArray.Empty); public static readonly JassSyntaxTriviaList SingleSpace = new(ImmutableArray.Create(JassSyntaxTrivia.SingleSpace)); - public static readonly JassSyntaxTriviaList Newline = new(ImmutableArray.Create(JassSyntaxTrivia.Newline)); + public static readonly JassSyntaxTriviaList NewLine = new(ImmutableArray.Create(JassSyntaxTrivia.NewLine)); internal JassSyntaxTriviaList( ImmutableArray trivia) diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs index 7df57047..ea4bf86e 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs @@ -20,7 +20,7 @@ public static JassSyntaxTrivia SyntaxTrivia(JassSyntaxKind syntaxKind, string te { return syntaxKind switch { - JassSyntaxKind.NewlineTrivia => NewlineTrivia(text), + JassSyntaxKind.NewLineTrivia => NewLineTrivia(text), JassSyntaxKind.WhitespaceTrivia => WhitespaceTrivia(text), JassSyntaxKind.SingleLineCommentTrivia => SingleLineCommentTrivia(text), @@ -28,7 +28,7 @@ public static JassSyntaxTrivia SyntaxTrivia(JassSyntaxKind syntaxKind, string te }; } - public static JassSyntaxTrivia NewlineTrivia(string text) + public static JassSyntaxTrivia NewLineTrivia(string text) { if (string.IsNullOrEmpty(text)) { @@ -40,7 +40,7 @@ public static JassSyntaxTrivia NewlineTrivia(string text) throw new ArgumentException("Text may only contain '\\r' and '\\n' characters.", nameof(text)); } - return new JassSyntaxTrivia(JassSyntaxKind.NewlineTrivia, text); + return new JassSyntaxTrivia(JassSyntaxKind.NewLineTrivia, text); } public static JassSyntaxTrivia WhitespaceTrivia(string text) diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs index 71619f45..4ee14918 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/SyntaxTriviaTranspiler.cs @@ -31,7 +31,7 @@ public SyntaxTrivia Transpile(JassSyntaxTrivia trivia) { return trivia.SyntaxKind switch { - JassSyntaxKind.NewlineTrivia => SyntaxFactory.EndOfLine(trivia.Text), + JassSyntaxKind.NewLineTrivia => SyntaxFactory.EndOfLine(trivia.Text), JassSyntaxKind.WhitespaceTrivia => SyntaxFactory.Whitespace(trivia.Text), JassSyntaxKind.SingleLineCommentTrivia => SyntaxFactory.Comment(trivia.Text), }; From 95c3a117e6fac9e178e4560a0cec36ae2470a60a Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 18:01:24 +0100 Subject: [PATCH 22/53] WIP migration guide. --- docs/guides/jass-migration-guide-v5-to-v6.md | 228 +++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 docs/guides/jass-migration-guide-v5-to-v6.md diff --git a/docs/guides/jass-migration-guide-v5-to-v6.md b/docs/guides/jass-migration-guide-v5-to-v6.md new file mode 100644 index 00000000..ed57d0e8 --- /dev/null +++ b/docs/guides/jass-migration-guide-v5-to-v6.md @@ -0,0 +1,228 @@ +# War3Net.CodeAnalysis.Jass v5 -> v6 migration guide + +## Overview + +War3Net.CodeAnalysis.Jass v6.0.0 introduced major breaking changes to make the library better suited for certain use cases. + +New classes have been added for tokens and trivia, making it possible to model a JASS script with 100% accuracy. + +This guide contains mapping tables for migrating your code from v5 to v6. + +## Syntax changes + +
New types + +New syntax node classes to hold tokens: + +| Class name | Token(s) | +|---------------------------------------|-----------------------| +| `JassElementAccessClauseSyntax` | `[` and `]` | +| `JassElseIfClauseDeclaratorSyntax` | `elseif` and `then` | +| `JassEmptyParameterListSyntax` | `takes` and `nothing` | +| `JassGlobalConstantDeclarationSyntax` | `constant` | +| `JassIfClauseDeclaratorSyntax` | `if` and `then` | +| `JassReturnClauseSyntax` | `returns` | + +Other new syntax node classes: + +| Class name | Purpose | +|-----------------------------------------------|--------------------------------------------------------------------------------------------| +| `JassIfClauseSyntax` | Holds `JassIfClauseDeclaratorSyntax` and statements | +| `JassParameterListOrEmptyParameterListSyntax` | Abstract base class for empty (`takes nothing`) and not-empty (`takes `) lists | +| `JassSyntaxNode` | Abstract base class for all new and existing syntax node classes | + +Other new classes: + +| Type name | Purpose | +|-------------------------|--------------------------------------------------------------------------------| +| `JassSyntaxNodeOrToken` | Can be used to model "custom script actions" (one full line of the map script) | +| `JassSyntaxToken` | Holds a token's text and trivia | +| `JassSyntaxTrivia` | Contains trivia as text (whitespace, newlines, single line comments) | +| `JassSyntaxTriviaList` | A collection of leading or trailing trivia for a token | + +
+ +
Renamed types + +The following interfaces have been changed to abstract classes: + +| Old type name | New type name | +|------------------------------|---------------------------------------| +| `IExpressionSyntax` | `JassExpressionSyntax` | +| `IGlobalDeclarationSyntax` | `JassGlobalDeclarationSyntax` | +| `IStatementSyntax` | `JassStatementSyntax` | +| `ITopLevelDeclarationSyntax` | `JassTopLevelDeclarationSyntax` | +| `IVariableDeclaratorSyntax` | `JassVariableOrArrayDeclaratorSyntax` | + +The following classes have been renamed: + +| Old class name | New class name | +|--------------------------------------|---------------------------------------| +| `JassArrayReferenceExpressionSyntax` | `JassElementAccessExpressionSyntax` | +| `JassGlobalDeclarationListSyntax` | `JassGlobalsDeclarationSyntax` | +| `JassGlobalDeclarationSyntax` | `JassGlobalVariableDeclarationSyntax` | + +
+ +
Replaced types + +Specific literal expression classes have been removed, you can now use the generic JassLiteralExpressionSyntax class. + +The new JassLiteralExpressionSyntax contains a token (with string text) property instead of the actual type of the expression. + +| Old type | New JassSyntaxKind | +|------------------------------------------|-----------------------------------------------| +| `JassBooleanLiteralExpressionSyntax` | `JassSyntaxKind.BooleanLiteralExpression` | +| `JassCharacterLiteralExpressionSyntax` | `JassSyntaxKind.CharacterLiteralExpression` | +| `JassDecimalLiteralExpressionSyntax` | `JassSyntaxKind.DecimalLiteralExpression` | +| `JassFourCCLiteralExpressionSyntax` | `JassSyntaxKind.FourCCLiteralExpression` | +| `JassHexadecimalLiteralExpressionSyntax` | `JassSyntaxKind.HexadecimalLiteralExpression` | +| `JassNullLiteralExpressionSyntax` | `JassSyntaxKind.NullLiteralExpression` | +| `JassOctalLiteralExpressionSyntax` | `JassSyntaxKind.OctalLiteralExpression` | +| `JassRealLiteralExpressionSyntax` | `JassSyntaxKind.RealLiteralExpression` | +| `JassStringLiteralExpressionSyntax` | `JassSyntaxKind.StringLiteralExpression` | + +Script line interfaces have been removed, the new `JassSyntaxNodeOrToken` serves the same purpose: + +| Removed interface | +|--------------------------| +| `IDeclarationLineSyntax` | +| `IGlobalLineSyntax` | +| `IStatementLineSyntax` | + +Custom script action classes have been removed, these have been replaced by new syntax node classes or the `JassSyntaxToken` class: + +| Removed class | Replacement class or token kind | +|-------------------------------------|-------------------------------------| +| `JassDebugCustomScriptAction` | NO REPLACEMENT YET | +| `JassElseCustomScriptAction` | `JassSyntaxKind.ElseKeyword` | +| `JassElseIfCustomScriptAction` | `JassElseIfClauseDeclaratorSyntax` | +| `JassEndFunctionCustomScriptAction` | `JassSyntaxKind.EndFunctionKeyword` | +| `JassEndGlobalsCustomScriptAction` | `JassSyntaxKind.EndGlobalsKeyword` | +| `JassEndIfCustomScriptAction` | `JassSyntaxKind.EndIfKeyword` | +| `JassEndLoopCustomScriptAction` | `JassSyntaxKind.EndLoopKeyword` | +| `JassFunctionCustomScriptAction` | `JassFunctionDeclaratorSyntax` | +| `JassGlobalsCustomScriptAction` | `JassSyntaxKind.GlobalsKeyword` | +| `JassIfCustomScriptAction` | `JassIfClauseDeclaratorSyntax` | +| `JassLoopCustomScriptAction` | `JassSyntaxKind.LoopKeyword` | + +The `BinaryOperatorType` and `UnaryOperatorType` enums have been removed, the type of the operator can now be determined by the syntax kind of the operator token: + +| Old member name | New token kind | +|-------------------------------------|-----------------------------------------| +| `BinaryOperatorType.Add` | `JassSyntaxKind.PlusToken` | +| `BinaryOperatorType.Subtract` | `JassSyntaxKind.MinusToken` | +| `BinaryOperatorType.Multiplication` | `JassSyntaxKind.AsteriskToken` | +| `BinaryOperatorType.Division` | `JassSyntaxKind.SlashToken` | +| `BinaryOperatorType.GreaterThan` | `JassSyntaxKind.GreaterThanToken` | +| `BinaryOperatorType.LessThan` | `JassSyntaxKind.LessThanToken` | +| `BinaryOperatorType.Equals` | `JassSyntaxKind.EqualsEqualsToken` | +| `BinaryOperatorType.NotEquals` | `JassSyntaxKind.ExclamationEqualsToken` | +| `BinaryOperatorType.GreaterOrEqual` | `JassSyntaxKind.GreaterThanEqualsToken` | +| `BinaryOperatorType.LessOrEqual` | `JassSyntaxKind.LessThanEqualsToken` | +| `BinaryOperatorType.And` | `JassSyntaxKind.AndKeyword` | +| `BinaryOperatorType.Or` | `JassSyntaxKind.OrKeyword` | +| `UnaryOperatorType.Plus` | `JassSyntaxKind.PlusToken` | +| `UnaryOperatorType.Minus` | `JassSyntaxKind.MinusToken` | +| `UnaryOperatorType.Not` | `JassSyntaxKind.NotKeyword` | + +Comments and empty lines are now handled by trivia: + +| Removed class | +| --------------------| +| `JassCommentSyntax` | +| `JassEmptySyntax` | + +
+ +
Removed types + +The following types have been removed: + +| Removed type | Alternative | +|-------------------------------|---------------------------------------------------------------------| +| `IInvocationSyntax` | NO ALTERNATIVE | +| `IVariableDeclaratorSyntax` | Use `GetVariableType()` and `GetIdentifierName()` extension methods | +| `JassDebugCustomScriptAction` | NO ALTERNATIVE | + +The following types are no longer relevant: + +| Removed type | Alternative | +|-----------------------------------------|----------------------------------------------------| +| `JassStatementListSyntax` | Use `ImmutableArray` directly | +| `JassVariableReferenceExpressionSyntax` | Use `JassIdentifierNameSyntax` directly | + +The following classes were unused and are no longer relevant: + +| Removed class | +|----------------------------------| +| `IMemberDeclarationSyntax` | +| `IScopedDeclarationSyntax` | +| `IScopedGlobalDeclarationSyntax` | + +
+ +
Renamed members + +The following methods have been renamed in syntax node classes: + +| Old method name | New method name | +|-----------------|------------------| +| `Equals` | `IsEquivalentTo` | + +The following properties have been renamed. + +If the containing type has been changed or renamed, the new type name is also listed in the new column. + +| Old property name | New property name | +|----------------------------------------------|---------------------------------------------------------| +| `JassArgumentListSyntax.Arguments` | `ArgumentList` | +| `JassArrayReferenceExpressionSyntax.Indexer` | `JassElementAccessExpressionSyntax.ElementAccessClause` | +| `JassCallStatementSyntax.Arguments` | `ArgumentList` | +| `JassGlobalDeclarationListSyntax.Globals` | `JassGlobalsDeclarationSyntax.GlobalDeclarations` | +| `JassInvocationExpressionSyntax.Arguments` | `ArgumentList` | +| `JassParameterListSyntax.Empty` | `JassEmptyParameterListSyntax.Value` | +| `JassParameterListSyntax.Parameters` | `ParameterList` | +| `JassTypeSyntax.Boolean` | `JassPredefinedTypeSyntax.Boolean` | +| `JassTypeSyntax.Code` | `JassPredefinedTypeSyntax.Code` | +| `JassTypeSyntax.Handle` | `JassPredefinedTypeSyntax.Handle` | +| `JassTypeSyntax.Integer` | `JassPredefinedTypeSyntax.Integer` | +| `JassTypeSyntax.Nothing` | `JassPredefinedTypeSyntax.Nothing` | +| `JassTypeSyntax.Real` | `JassPredefinedTypeSyntax.Real` | +| `JassTypeSyntax.String` | `JassPredefinedTypeSyntax.String` | + +
+ +
Replaced members + +The following properties have been replaced: + +| Old property name | New property type and name | Old type | +|---------------------------------------|-----------------------------------------------------|---------------------------| +| `JassBinaryExpressionSyntax.Operator` | `JassSyntaxToken OperatorToken` | `BinaryOperatorType` | +| `JassElseClauseSyntax.Body` | `ImmutableArray Statements` | `JassStatementListSyntax` | +| `JassIdentifierNameSyntax.Name` | `JassSyntaxToken Token` | `string` | +| `JassSetStatementSyntax.Indexer` | `JassElementAccessClauseSyntax ElementAccessClause` | `IExpressionSyntax` | +| `JassUnaryExpressionSyntax.Operator` | `JassSyntaxToken OperatorToken` | `UnaryOperatorType` | + +Other replacements: + +| Old property name | Alternative | +|----------------------------------------------------------|------------------------------------------------------| +| `JassBooleanLiteralExpressionSyntax.False` | `JassSyntaxFactory.Literal(false)` | +| `JassBooleanLiteralExpressionSyntax.True` | `JassSyntaxFactory.Literal(true)` | +| `JassNativeFunctionDeclarationSyntax.FunctionDeclarator` | All declarator properties are now available directly | +| `JassNullLiteralExpressionSyntax.Value` | `JassSyntaxFactory.Literal(null)` | +| `JassTypeSyntax.TypeName` | `JassTypeSyntaxExtensions.GetToken()` | + +
+ +
Other (breaking) changes + +- JassTypeSyntax is now abstract and inherits JassExpressionSyntax +- JassIdentifierNameSyntax now inherits JassTypeSyntax -> JassExpressionSyntax +- Properties that used to be of type `JassParameterListSyntax` are now `JassParameterListOrEmptyParameterListSyntax` +- The constructor of syntax node classes is now internal +- Properties have been changed from `{ get; init; }` to `{ get; }` + +
From 60f06ba7fafa096f5eff64094176f5768c26978a Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 18:03:06 +0100 Subject: [PATCH 23/53] Fixes. --- .../Widget/MapUnitsDecompiler.cs | 10 +++++----- .../War3Net.CodeAnalysis.Jass.csproj | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs index 021d9a25..9ac3de06 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs @@ -255,11 +255,11 @@ variableDeclarator.Value.Expression is JassInvocationExpressionSyntax playerInvo return false; } } - // else if (setStatement.Value.Expression is JassArrayReferenceExpressionSyntax) - // { - // // TODO - // continue; - // } + else if (setStatement.Value.Expression is JassElementAccessExpressionSyntax) + { + // TODO + continue; + } else { units = null; diff --git a/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj b/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj index fc086c35..6395a902 100644 --- a/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj +++ b/src/War3Net.CodeAnalysis.Jass/War3Net.CodeAnalysis.Jass.csproj @@ -9,12 +9,12 @@ jass;warcraft3 - + - + From ad4c119d1c770b1b0d4288b9470d9771bbe24b89 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sat, 24 Jan 2026 18:05:59 +0100 Subject: [PATCH 24/53] Parse 0 as decimal number (not octal). --- .../JassParser/OctalLiteralExpressionParser.cs | 2 +- .../Parser/ExpressionParserTests.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs index 069ec685..a164adb2 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs @@ -19,7 +19,7 @@ internal partial class JassParser internal static Parser GetOctalLiteralExpressionParser( Parser triviaParser) { - return Try(Symbol.Zero.Then(UnsignedInt(8).Optional())) + return Try(Symbol.Zero.Then(UnsignedInt(8))) .MapWithInput((s, _) => s.ToString()) .AsToken(triviaParser, JassSyntaxKind.OctalLiteralToken) .Map(token => (JassExpressionSyntax)new JassLiteralExpressionSyntax(token)) diff --git a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs index 8cd8fa52..e61438e0 100644 --- a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs +++ b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs @@ -76,6 +76,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect #endregion #region DecimalLiteralExpression + yield return new object?[] { @"0", LiteralExpression(Literal(0)) }; yield return new object?[] { @"1", LiteralExpression(Literal(1)) }; yield return new object?[] { @"255", LiteralExpression(Literal(255)) }; yield return new object?[] { @"255abc" }; @@ -83,7 +84,6 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect #endregion #region OctalLiteralExpression - yield return new object?[] { @"0", LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")) }; yield return new object?[] { @"010", LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "010")) }; yield return new object?[] { @"0abc" }; yield return new object?[] { @"0_" }; @@ -143,7 +143,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect #endregion #region ParenthesizedExpression - yield return new object?[] { @"(0)", ParenthesizedExpression(LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0"))) }; + yield return new object?[] { @"(0)", ParenthesizedExpression(LiteralExpression(Literal(0))) }; yield return new object?[] { @"(1)", ParenthesizedExpression(LiteralExpression(Literal(1))) }; yield return new object?[] { @"(player_id)", ParenthesizedExpression(IdentifierName(@"player_id")) }; yield return new object?[] { @"( player_id )", ParenthesizedExpression(IdentifierName(@"player_id")) }; @@ -160,14 +160,14 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect @"(5 > 0)", ParenthesizedExpression(BinaryGreaterThanExpression( LiteralExpression(Literal(5)), - LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")))), + LiteralExpression(Literal(0)))), }; yield return new object?[] { @"(0 > foo())", ParenthesizedExpression(BinaryGreaterThanExpression( - LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")), + LiteralExpression(Literal(0)), InvocationExpression("foo"))), }; @@ -176,7 +176,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect @"(foo() > 0)", ParenthesizedExpression(BinaryGreaterThanExpression( InvocationExpression("foo"), - LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")))), + LiteralExpression(Literal(0)))), }; yield return new object?[] @@ -187,7 +187,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect "GetUnitState", IdentifierName("oldUnit"), IdentifierName("UNIT_STATE_MAX_LIFE")), - LiteralExpression(Token(JassSyntaxKind.OctalLiteralToken, "0")))), + LiteralExpression(Literal(0)))), }; #endregion From addf14f0f82bb5029ed0abe8aac8d8b4cf0a237a Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 07:53:27 +0100 Subject: [PATCH 25/53] Update dotnet build command in build script. --- .github/scripts/build-and-pack-nuget.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/build-and-pack-nuget.sh b/.github/scripts/build-and-pack-nuget.sh index 2bfc0501..2d7cf738 100644 --- a/.github/scripts/build-and-pack-nuget.sh +++ b/.github/scripts/build-and-pack-nuget.sh @@ -159,10 +159,10 @@ while [ -n "$REMAINING_PROJECTS" ] && [ $ITERATION -lt $MAX_ITERATIONS ]; do dotnet restore "$project" -p:Configuration=Release --verbosity minimal --force --no-cache # Build the project - dotnet build "$project" --configuration Release --no-restore --verbosity minimal + dotnet build "$project" -p:PACK=true -p:WarningLevel=0 -p:RunAnalyzers=false -p:SuppressTfmSupportBuildWarnings=true --configuration Release --no-restore --verbosity minimal # Pack directly to artifacts with project name folder structure for proper NuGet feed - dotnet pack "$project" --configuration Release --no-build --output "./artifacts/${PROJECT_NAME}" -p:PACK=true --verbosity minimal + dotnet pack "$project" -p:PACK=true --configuration Release --no-build --output "./artifacts/${PROJECT_NAME}" --verbosity minimal fi BUILT_PROJECTS="${BUILT_PROJECTS}${PROJECT_NAME};" From 8882cc0228cd5e12bf932695508b90a43322fc34 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:03:21 +0100 Subject: [PATCH 26/53] Fix? --- .github/scripts/build-and-pack-nuget.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/scripts/build-and-pack-nuget.sh b/.github/scripts/build-and-pack-nuget.sh index 2d7cf738..a19f08b8 100644 --- a/.github/scripts/build-and-pack-nuget.sh +++ b/.github/scripts/build-and-pack-nuget.sh @@ -31,8 +31,8 @@ can_build_project() { # Get the dependencies - dotnet list outputs them with paths like ..\ProjectName\ProjectName.csproj # We need to extract just the project name from the filename local deps=$(dotnet list "$project" reference 2>/dev/null | grep '\.csproj$' | while read -r line; do - # Remove everything up to the last backslash, then remove .csproj extension - echo "$line" | sed 's/.*\\//' | sed 's/\.csproj$//' + # Remove everything up to the last slash (forward or back), then remove .csproj extension + echo "$line" | sed 's/.*[\\\/]//' | sed 's/\.csproj$//' done | tr '\n' ' ') for dep in $deps; do @@ -72,7 +72,7 @@ while [ -n "$REMAINING_PROJECTS" ] && [ $ITERATION -lt $MAX_ITERATIONS ]; do echo "$STILL_REMAINING" | tr ';' '\n' | while read -r p; do if [ -n "$p" ]; then echo " - $(basename $(dirname "$p"))" - echo " Dependencies: $(dotnet list "$p" reference 2>/dev/null | grep -E "^\s+.*\.csproj" | sed 's/.*\///' | sed 's/\.csproj.*//' | tr '\n' ' ')" + echo " Dependencies: $(dotnet list "$p" reference 2>/dev/null | grep -E "^\s+.*\.csproj" | sed 's/.*[\\\/]//' | sed 's/\.csproj.*//' | tr '\n' ' ')" fi done echo "Already built: $BUILT_PROJECTS" From 17b7abc7f1873cae5f53efb0194721ceab0f5be2 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:15:34 +0100 Subject: [PATCH 27/53] Make MapScriptBuilder.GenerateGlobals public to replace removed Api methods. --- src/War3Net.Build/MapScriptBuilder/Script/Globals.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs b/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs index e95e18d5..b50c2790 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/Globals.cs @@ -15,7 +15,7 @@ namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual void GenerateGlobals(Map map, IndentedTextWriter writer) + public virtual void GenerateGlobals(Map map, IndentedTextWriter writer) { if (map is null) { From 6f97675a9055f03e24264df0dd8b458b9bcd29ed Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:16:06 +0100 Subject: [PATCH 28/53] Delete unused method. --- .../MapScriptBuilder/Script/InitTrig.cs | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs b/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs index 6c0e53fa..86fb22cd 100644 --- a/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs +++ b/src/War3Net.Build/MapScriptBuilder/Script/InitTrig.cs @@ -7,51 +7,12 @@ using System; -using War3Net.Build.Extensions; using War3Net.Build.Script; -using War3Net.CodeAnalysis; -using War3Net.CodeAnalysis.Jass; -using War3Net.CodeAnalysis.Jass.Extensions; namespace War3Net.Build { public partial class MapScriptBuilder { - protected internal virtual void GenerateInitTrig(Map map, TriggerDefinition triggerDefinition, IndentedTextWriter writer) - { - if (map is null) - { - throw new ArgumentNullException(nameof(map)); - } - - if (triggerDefinition is null) - { - throw new ArgumentNullException(nameof(triggerDefinition)); - } - - if (writer is null) - { - throw new ArgumentNullException(nameof(writer)); - } - - var triggerVariableName = triggerDefinition.GetVariableName(); - - writer.WriteFunction(triggerDefinition.GetInitTrigFunctionName()); - - writer.WriteSet( - triggerVariableName, - JassExpression.InvokeSpaced(NativeName.CreateTrigger)); - - if (!triggerDefinition.IsInitiallyOn) - { - writer.WriteCall( - NativeName.DisableTrigger, - triggerVariableName); - } - - writer.EndFunction(); - } - protected internal virtual bool ShouldRenderTrigger(Map map, TriggerDefinition triggerDefinition) { if (map is null) From aa7886042d05c864795deaa90cd32a866b2bf3d3 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:19:01 +0100 Subject: [PATCH 29/53] Update exception message to match changed JassSyntaxFacts.IsWhitespaceCharacter implementation. --- .../SyntaxFactory/SyntaxTriviaFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs index ea4bf86e..fb7ef6d9 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTriviaFactory.cs @@ -52,7 +52,7 @@ public static JassSyntaxTrivia WhitespaceTrivia(string text) if (!text.All(JassSyntaxFacts.IsWhitespaceCharacter)) { - throw new ArgumentException("Text may only contain whitespace characters (excluding '\\r' and '\\n').", nameof(text)); + throw new ArgumentException("Text may only contain ' ' and '\\t' characters.", nameof(text)); } return new JassSyntaxTrivia(JassSyntaxKind.WhitespaceTrivia, text); From fad80e6e017723364d963d4e5a5ceb8240798d7f Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:25:08 +0100 Subject: [PATCH 30/53] Rename methods to match syntax kinds. --- .../SyntaxFactory/BinaryExpressionFactory.cs | 12 ++++++------ .../Parser/ExpressionParserTests.cs | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs index bec4a8bc..3245dc8e 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs @@ -11,7 +11,7 @@ namespace War3Net.CodeAnalysis.Jass { public static partial class JassSyntaxFactory { - public static JassBinaryExpressionSyntax BinaryAdditionExpression(JassExpressionSyntax left, JassExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryAddExpression(JassExpressionSyntax left, JassExpressionSyntax right) { return new JassBinaryExpressionSyntax( left, @@ -19,7 +19,7 @@ public static JassBinaryExpressionSyntax BinaryAdditionExpression(JassExpression right); } - public static JassBinaryExpressionSyntax BinarySubtractionExpression(JassExpressionSyntax left, JassExpressionSyntax right) + public static JassBinaryExpressionSyntax BinarySubtractExpression(JassExpressionSyntax left, JassExpressionSyntax right) { return new JassBinaryExpressionSyntax( left, @@ -27,7 +27,7 @@ public static JassBinaryExpressionSyntax BinarySubtractionExpression(JassExpress right); } - public static JassBinaryExpressionSyntax BinaryMultiplicationExpression(JassExpressionSyntax left, JassExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryMultiplyExpression(JassExpressionSyntax left, JassExpressionSyntax right) { return new JassBinaryExpressionSyntax( left, @@ -35,7 +35,7 @@ public static JassBinaryExpressionSyntax BinaryMultiplicationExpression(JassExpr right); } - public static JassBinaryExpressionSyntax BinaryDivisionExpression(JassExpressionSyntax left, JassExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryDivideExpression(JassExpressionSyntax left, JassExpressionSyntax right) { return new JassBinaryExpressionSyntax( left, @@ -75,7 +75,7 @@ public static JassBinaryExpressionSyntax BinaryNotEqualsExpression(JassExpressio right); } - public static JassBinaryExpressionSyntax BinaryGreaterOrEqualExpression(JassExpressionSyntax left, JassExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryGreaterThanOrEqualExpression(JassExpressionSyntax left, JassExpressionSyntax right) { return new JassBinaryExpressionSyntax( left, @@ -83,7 +83,7 @@ public static JassBinaryExpressionSyntax BinaryGreaterOrEqualExpression(JassExpr right); } - public static JassBinaryExpressionSyntax BinaryLessOrEqualExpression(JassExpressionSyntax left, JassExpressionSyntax right) + public static JassBinaryExpressionSyntax BinaryLessThanOrEqualExpression(JassExpressionSyntax left, JassExpressionSyntax right) { return new JassBinaryExpressionSyntax( left, diff --git a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs index e61438e0..15080453 100644 --- a/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs +++ b/tests/War3Net.CodeAnalysis.Jass.Tests/Parser/ExpressionParserTests.cs @@ -203,7 +203,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect yield return new object?[] { @"trueandfalseornull", IdentifierName(@"trueandfalseornull") }; - var expr1 = BinaryAdditionExpression( + var expr1 = BinaryAddExpression( LiteralExpression(Literal(50)), LiteralExpression(Literal(60))); @@ -214,9 +214,9 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect yield return new object?[] { @"2 + 6 * 10", - BinaryAdditionExpression( + BinaryAddExpression( LiteralExpression(Literal(2)), - BinaryMultiplicationExpression( + BinaryMultiplyExpression( LiteralExpression(Literal(6)), LiteralExpression(Literal(10)))), }; @@ -224,8 +224,8 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect yield return new object?[] { @"(2 + 6) * 10", - BinaryMultiplicationExpression( - ParenthesizedExpression(BinaryAdditionExpression( + BinaryMultiplyExpression( + ParenthesizedExpression(BinaryAddExpression( LiteralExpression(Literal(2)), LiteralExpression(Literal(6)))), LiteralExpression(Literal(10))), @@ -234,7 +234,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect yield return new object?[] { @"(player_id) * 10", - BinaryMultiplicationExpression( + BinaryMultiplyExpression( ParenthesizedExpression(IdentifierName(@"player_id")), LiteralExpression(Literal(10))), }; @@ -253,7 +253,7 @@ public void TestExpressionParser(string expression, JassExpressionSyntax? expect BinaryEqualsExpression( ElementAccessExpression( @"FORCE_ALL_PLAYERS", - ParenthesizedExpression(BinarySubtractionExpression( + ParenthesizedExpression(BinarySubtractExpression( IdentifierName(@"player_id"), LiteralExpression(Literal(1))))), InvocationExpression( From eb24d7480ec298dea3816f774c9d5f3de485caab Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:49:23 +0100 Subject: [PATCH 31/53] MapInfo JSON serialization bugfix. --- .../Serialization/Json/Info/MapInfo.cs | 2 +- src/War3Net.Common/EnumConvert.cs | 80 +++++++++++++++++++ .../Extensions/JsonElementExtensions.cs | 28 +++++++ .../Info/MapInfoTests.cs | 34 ++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/src/War3Net.Build.Core/Serialization/Json/Info/MapInfo.cs b/src/War3Net.Build.Core/Serialization/Json/Info/MapInfo.cs index f275779a..6cc88f53 100644 --- a/src/War3Net.Build.Core/Serialization/Json/Info/MapInfo.cs +++ b/src/War3Net.Build.Core/Serialization/Json/Info/MapInfo.cs @@ -34,7 +34,7 @@ internal void GetFrom(JsonElement jsonElement) if (FormatVersion >= MapInfoFormatVersion.v18) { MapVersion = jsonElement.GetInt32(nameof(MapVersion)); - EditorVersion = (EditorVersion)jsonElement.GetInt32(nameof(EditorVersion)); + EditorVersion = jsonElement.GetInt32Raw(nameof(EditorVersion)); if (FormatVersion >= MapInfoFormatVersion.v27) { diff --git a/src/War3Net.Common/EnumConvert.cs b/src/War3Net.Common/EnumConvert.cs index 8980f14c..dbe0bf37 100644 --- a/src/War3Net.Common/EnumConvert.cs +++ b/src/War3Net.Common/EnumConvert.cs @@ -16,6 +16,16 @@ namespace War3Net.Common public static class EnumConvert where TEnum : struct, Enum { + public static TEnum FromByteRaw(byte value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(byte)) + { + throw new InvalidOperationException($"FromByteRaw requires that enum of type {typeof(TEnum).Name} uses byte as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromByte(byte value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(byte)) @@ -36,6 +46,16 @@ public static TEnum FromByte(byte value, bool allowNoFlags = true) return result; } + public static TEnum FromSByteRaw(sbyte value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(sbyte)) + { + throw new InvalidOperationException($"FromSByteRaw requires that enum of type {typeof(TEnum).Name} uses sbyte as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromSByte(sbyte value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(sbyte)) @@ -56,6 +76,16 @@ public static TEnum FromSByte(sbyte value, bool allowNoFlags = true) return result; } + public static TEnum FromInt16Raw(short value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(short)) + { + throw new InvalidOperationException($"FromInt16Raw requires that enum of type {typeof(TEnum).Name} uses short as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromInt16(short value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(short)) @@ -76,6 +106,16 @@ public static TEnum FromInt16(short value, bool allowNoFlags = true) return result; } + public static TEnum FromUInt16Raw(ushort value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(ushort)) + { + throw new InvalidOperationException($"FromUInt16Raw requires that enum of type {typeof(TEnum).Name} uses ushort as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromUInt16(ushort value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(ushort)) @@ -96,6 +136,16 @@ public static TEnum FromUInt16(ushort value, bool allowNoFlags = true) return result; } + public static TEnum FromInt32Raw(int value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(int)) + { + throw new InvalidOperationException($"FromInt32Raw requires that enum of type {typeof(TEnum).Name} uses int as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromInt32(int value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(int)) @@ -116,6 +166,16 @@ public static TEnum FromInt32(int value, bool allowNoFlags = true) return result; } + public static TEnum FromUInt32Raw(uint value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(uint)) + { + throw new InvalidOperationException($"FromUInt32Raw requires that enum of type {typeof(TEnum).Name} uses uint as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromUInt32(uint value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(uint)) @@ -136,6 +196,16 @@ public static TEnum FromUInt32(uint value, bool allowNoFlags = true) return result; } + public static TEnum FromInt64Raw(long value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(long)) + { + throw new InvalidOperationException($"FromInt64Raw requires that enum of type {typeof(TEnum).Name} uses long as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromInt64(long value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(long)) @@ -156,6 +226,16 @@ public static TEnum FromInt64(long value, bool allowNoFlags = true) return result; } + public static TEnum FromUInt64Raw(ulong value) + { + if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(ulong)) + { + throw new InvalidOperationException($"FromUInt64Raw requires that enum of type {typeof(TEnum).Name} uses ulong as its underlying type."); + } + + return Unsafe.As(ref value); + } + public static TEnum FromUInt64(ulong value, bool allowNoFlags = true) { if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(ulong)) diff --git a/src/War3Net.Common/Extensions/JsonElementExtensions.cs b/src/War3Net.Common/Extensions/JsonElementExtensions.cs index 20c47511..8832b413 100644 --- a/src/War3Net.Common/Extensions/JsonElementExtensions.cs +++ b/src/War3Net.Common/Extensions/JsonElementExtensions.cs @@ -20,6 +20,14 @@ public static TEnum GetByte(this JsonElement jsonElement) : Enum.Parse(jsonElement.GetString()); } + public static TEnum GetByteRaw(this JsonElement jsonElement) + where TEnum : struct, Enum + { + return jsonElement.ValueKind == JsonValueKind.Number + ? EnumConvert.FromByteRaw(jsonElement.GetByte()) + : Enum.Parse(jsonElement.GetString()); + } + public static TEnum GetInt32(this JsonElement jsonElement) where TEnum : struct, Enum { @@ -28,18 +36,38 @@ public static TEnum GetInt32(this JsonElement jsonElement) : Enum.Parse(jsonElement.GetString()); } + public static TEnum GetInt32Raw(this JsonElement jsonElement) + where TEnum : struct, Enum + { + return jsonElement.ValueKind == JsonValueKind.Number + ? EnumConvert.FromInt32Raw(jsonElement.GetInt32()) + : Enum.Parse(jsonElement.GetString()); + } + public static TEnum GetByte(this JsonElement jsonElement, ReadOnlySpan propertyName) where TEnum : struct, Enum { return jsonElement.GetProperty(propertyName).GetByte(); } + public static TEnum GetByteRaw(this JsonElement jsonElement, ReadOnlySpan propertyName) + where TEnum : struct, Enum + { + return jsonElement.GetProperty(propertyName).GetByteRaw(); + } + public static TEnum GetInt32(this JsonElement jsonElement, ReadOnlySpan propertyName) where TEnum : struct, Enum { return jsonElement.GetProperty(propertyName).GetInt32(); } + public static TEnum GetInt32Raw(this JsonElement jsonElement, ReadOnlySpan propertyName) + where TEnum : struct, Enum + { + return jsonElement.GetProperty(propertyName).GetInt32Raw(); + } + public static JsonElement.ArrayEnumerator EnumerateArray(this JsonElement jsonElement, ReadOnlySpan propertyName) => jsonElement.GetProperty(propertyName).EnumerateArray(); public static JsonElement.ObjectEnumerator EnumerateObject(this JsonElement jsonElement, ReadOnlySpan propertyName) => jsonElement.GetProperty(propertyName).EnumerateObject(); diff --git a/tests/War3Net.Build.Core.Tests/Info/MapInfoTests.cs b/tests/War3Net.Build.Core.Tests/Info/MapInfoTests.cs index 193622ed..636828a6 100644 --- a/tests/War3Net.Build.Core.Tests/Info/MapInfoTests.cs +++ b/tests/War3Net.Build.Core.Tests/Info/MapInfoTests.cs @@ -5,13 +5,17 @@ //
// ------------------------------------------------------------------------------ +using System; using System.Collections.Generic; using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.VisualStudio.TestTools.UnitTesting; using War3Net.Build.Extensions; using War3Net.Build.Info; +using War3Net.Build.Serialization.Json; using War3Net.TestTools.UnitTesting; namespace War3Net.Build.Core.Tests.Info @@ -174,6 +178,36 @@ public void TestParseReforgedMapInfo(string mapInfoFilePath, bool expectCustomAb Assert.AreEqual(expectSupportedModes, mapInfo.SupportedModes); } + [TestMethod] + public void TestJsonSerializeRegression() + { + var mapInfo = Build.MapFactory.Info(); + + var options = new JsonSerializerOptions(); + options.Converters.Add(new JsonMapInfoConverter()); + options.Converters.Add(new JsonStringEnumConverter()); + + var json = JsonSerializer.Serialize(mapInfo, options); + _ = JsonSerializer.Deserialize(json, options); + } + + [TestMethod] + public void TestJsonSerializeInvalidEditorVersion() + { + var mapInfo = Build.MapFactory.Info(); + mapInfo.EditorVersion = (EditorVersion)123456; + + var options = new JsonSerializerOptions(); + options.Converters.Add(new JsonMapInfoConverter()); + options.Converters.Add(new JsonStringEnumConverter()); + + var json = JsonSerializer.Serialize(mapInfo, options); + var result = JsonSerializer.Deserialize(json, options); + + Assert.IsNotNull(result); + Assert.AreEqual(123456, (int)result.EditorVersion); + } + private static void TestParseMapInfoInternal(string mapInfoFilePath) { ParseTestHelper.RunBinaryRWTest( From 0c22b060ebaef9ea74cc41e20c9f96f86650f86e Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:51:54 +0100 Subject: [PATCH 32/53] Add TriggerConditionConstants. --- .../Constants/TriggerConditionConstants.cs | 21 +++++++++++++++++++ .../TriggerConditionRenderer.cs | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/War3Net.Build/TriggerRenderer/Constants/TriggerConditionConstants.cs diff --git a/src/War3Net.Build/TriggerRenderer/Constants/TriggerConditionConstants.cs b/src/War3Net.Build/TriggerRenderer/Constants/TriggerConditionConstants.cs new file mode 100644 index 00000000..4c344cc9 --- /dev/null +++ b/src/War3Net.Build/TriggerRenderer/Constants/TriggerConditionConstants.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.Build +{ + public partial class TriggerRenderer + { + // [TriggerConditions] in triggerdata.txt + private static class TriggerConditionConstants + { + internal const string GetBooleanAnd = "GetBooleanAnd"; + internal const string GetBooleanOr = "GetBooleanOr"; + internal const string AndMultiple = "AndMultiple"; + internal const string OrMultiple = "OrMultiple"; + } + } +} \ No newline at end of file diff --git a/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs b/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs index 40295bd0..d1a8ec41 100644 --- a/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs +++ b/src/War3Net.Build/TriggerRenderer/TriggerConditionRenderer.cs @@ -97,14 +97,14 @@ private string GetTriggerConditionExpression(TriggerFunction function, TriggerRe throw new ArgumentException("Function must be enabled and of type 'Condition'.", nameof(function)); } - if (function.Name == "OrMultiple" || function.Name == "AndMultiple") + if (function.Name == TriggerConditionConstants.OrMultiple || function.Name == TriggerConditionConstants.AndMultiple) { var conditionFunctionName = $"{context.TrigFunctionIdentifierBuilder}C"; - RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, function.Name == "AndMultiple", function.ChildFunctions); + RenderConditionFunction(context.TrigFunctionIdentifierBuilder, conditionFunctionName, function.Name == TriggerConditionConstants.AndMultiple, function.ChildFunctions); return JassExpression.Invoke(conditionFunctionName); } - else if (function.Name == "GetBooleanAnd" || function.Name == "GetBooleanOr") + else if (function.Name == TriggerConditionConstants.GetBooleanAnd || function.Name == TriggerConditionConstants.GetBooleanOr) { context.TrigFunctionIdentifierBuilder.Append(1); var conditionFunctionName1 = context.TrigFunctionIdentifierBuilder.ToString(); From 1858cd407f04a3d1aa9a79f18436c3fe8b25effc Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 08:58:49 +0100 Subject: [PATCH 33/53] Add W3MathF class. --- src/War3Net.Build.Core/Common/W3MathF.cs | 15 +++++++++++++++ .../MapScriptBuilder/Constants/Math.cs | 17 ----------------- .../Widget/CreateAllDestructables.cs | 3 ++- .../MapScriptBuilder/Widget/CreateUnits.cs | 5 +++-- .../Widget/MapUnitsDecompiler.cs | 5 +++-- 5 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 src/War3Net.Build.Core/Common/W3MathF.cs delete mode 100644 src/War3Net.Build/MapScriptBuilder/Constants/Math.cs diff --git a/src/War3Net.Build.Core/Common/W3MathF.cs b/src/War3Net.Build.Core/Common/W3MathF.cs new file mode 100644 index 00000000..f43586ca --- /dev/null +++ b/src/War3Net.Build.Core/Common/W3MathF.cs @@ -0,0 +1,15 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +namespace War3Net.Build.Common +{ + public static class W3MathF + { + public const float Deg2Rad = 3.141593f / 180f; + public const float Rad2Deg = 180f / 3.141593f; + } +} \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Constants/Math.cs b/src/War3Net.Build/MapScriptBuilder/Constants/Math.cs deleted file mode 100644 index f68acfd0..00000000 --- a/src/War3Net.Build/MapScriptBuilder/Constants/Math.cs +++ /dev/null @@ -1,17 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// Licensed under the MIT license. -// See the LICENSE file in the project root for more information. -// -// ------------------------------------------------------------------------------ - -namespace War3Net.Build -{ - public partial class MapScriptBuilder - { - private static class Math - { - internal const float Rad2Deg = 180f / 3.141593f; - } - } -} \ No newline at end of file diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs index 71bf66db..1c2b8387 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateAllDestructables.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; +using War3Net.Build.Common; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Widget; @@ -88,7 +89,7 @@ protected internal virtual void GenerateCreateAllDestructables(Map map, Indented createFunctionIndex += 2; } - arguments.Add(JassLiteral.Real(destructable.Rotation * Math.Rad2Deg, 3)); + arguments.Add(JassLiteral.Real(destructable.Rotation * W3MathF.Rad2Deg, 3)); arguments.Add(JassLiteral.Real(destructable.Scale.X, 3)); arguments.Add(JassLiteral.Int(destructable.Variation)); if (hasSkin) diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs index 1521f441..8e976325 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateUnits.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; +using War3Net.Build.Common; using War3Net.Build.Extensions; using War3Net.Build.Info; using War3Net.Build.Providers; @@ -141,7 +142,7 @@ protected internal virtual void GenerateCreateUnits(Map map, IEnumerable<(UnitDa VariableName.UnitId, JassLiteral.Real(unit.Position.X), JassLiteral.Real(unit.Position.Y), - JassLiteral.Real(unit.Rotation * Math.Rad2Deg, 3))); + JassLiteral.Real(unit.Rotation * W3MathF.Rad2Deg, 3))); WriteCreateUnitStatements(map, unit, id, writer); @@ -155,7 +156,7 @@ protected internal virtual void GenerateCreateUnits(Map map, IEnumerable<(UnitDa JassLiteral.FourCC(unit.TypeId), JassLiteral.Real(unit.Position.X), JassLiteral.Real(unit.Position.Y), - JassLiteral.Real(unit.Rotation * Math.Rad2Deg, 3), + JassLiteral.Real(unit.Rotation * W3MathF.Rad2Deg, 3), }; var skinId = unit.SkinId == 0 ? unit.TypeId : unit.SkinId; diff --git a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs index 9ac3de06..af7a08cd 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Widget/MapUnitsDecompiler.cs @@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; +using War3Net.Build.Common; using War3Net.Build.Widget; using War3Net.CodeAnalysis.Jass; using War3Net.CodeAnalysis.Jass.Extensions; @@ -183,7 +184,7 @@ variableDeclarator.Value.Expression is JassInvocationExpressionSyntax playerInvo OwnerId = localPlayerVariableValue.Value, TypeId = unitId.InvertEndianness(), Position = new Vector3(x, y, 0f), - Rotation = face * (MathF.PI / 180f), + Rotation = face * W3MathF.Deg2Rad, Scale = Vector3.One, Flags = 2, GoldAmount = 12500, @@ -217,7 +218,7 @@ variableDeclarator.Value.Expression is JassInvocationExpressionSyntax playerInvo OwnerId = localPlayerVariableValue.Value, TypeId = unitId.InvertEndianness(), Position = new Vector3(x, y, 0f), - Rotation = face * (MathF.PI / 180f), + Rotation = face * W3MathF.Deg2Rad, Scale = Vector3.One, SkinId = skinId.InvertEndianness(), Flags = 2, From 99d7049ddb603e47fef3c35080b5ef5a575c8dc2 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:16:04 +0100 Subject: [PATCH 34/53] Centralize parse methods in JassLiteral to prevent inconsistent and incorrect implementations. --- .../CharacterLiteralExpressionDecompiler.cs | 4 +- .../HexadecimalLiteralExpressionDecompiler.cs | 6 +-- .../OctalLiteralExpressionDecompiler.cs | 4 +- .../StringLiteralExpressionDecompiler.cs | 4 +- .../JassExpressionSyntaxExtensions.cs | 14 +++--- src/War3Net.CodeAnalysis.Jass/JassLiteral.cs | 50 +++++++++++++++++++ .../LiteralExpressionTranspiler.cs | 8 +-- .../JassToLua/LiteralExpressionTranspiler.cs | 8 +-- .../JassLiteralTests.cs | 30 +++++++++++ 9 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 tests/War3Net.CodeAnalysis.Jass.Tests/JassLiteralTests.cs diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs index 1384ab7f..d20c1992 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/CharacterLiteralExpressionDecompiler.cs @@ -29,7 +29,7 @@ private bool TryDecompileCharacterLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = ((int)characterLiteralExpression.Token.Text[1]).ToString(CultureInfo.InvariantCulture), + Value = ((int)JassLiteral.ParseChar(characterLiteralExpression.Token.Text)).ToString(CultureInfo.InvariantCulture), }; return true; @@ -43,7 +43,7 @@ private bool TryDecompileCharacterLiteralExpression( JassLiteralExpressionSyntax characterLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = ((int)characterLiteralExpression.Token.Text[1]).ToString(CultureInfo.InvariantCulture); + var value = ((int)JassLiteral.ParseChar(characterLiteralExpression.Token.Text)).ToString(CultureInfo.InvariantCulture); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs index c9e2b38f..c00c7734 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/HexadecimalLiteralExpressionDecompiler.cs @@ -26,8 +26,7 @@ private bool TryDecompileHexadecimalLiteralExpression( if (string.Equals(expectedType, JassKeyword.Integer, StringComparison.Ordinal) || string.Equals(expectedType, JassKeyword.Real, StringComparison.Ordinal)) { - var text = hexadecimalLiteralExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); - var value = Convert.ToInt32(text[2..], 16); + var value = JassLiteral.ParseHex(hexadecimalLiteralExpression.Token.Text); functionParameter = new TriggerFunctionParameter { @@ -46,8 +45,7 @@ private bool TryDecompileHexadecimalLiteralExpression( JassLiteralExpressionSyntax hexadecimalLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var text = hexadecimalLiteralExpression.Token.Text.Replace(JassSymbol.Dollar, "0x", StringComparison.Ordinal); - var value = Convert.ToInt32(text[2..], 16).ToString(CultureInfo.InvariantCulture); + var value = JassLiteral.ParseHex(hexadecimalLiteralExpression.Token.Text).ToString(CultureInfo.InvariantCulture); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs index 15e14124..163ed4eb 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/OctalLiteralExpressionDecompiler.cs @@ -29,7 +29,7 @@ private bool TryDecompileOctalLiteralExpression( functionParameter = new TriggerFunctionParameter { Type = TriggerFunctionParameterType.String, - Value = Convert.ToInt32(octalLiteralExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture), + Value = JassLiteral.ParseOctal(octalLiteralExpression.Token.Text).ToString(CultureInfo.InvariantCulture), }; return true; @@ -43,7 +43,7 @@ private bool TryDecompileOctalLiteralExpression( JassLiteralExpressionSyntax octalLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var value = Convert.ToInt32(octalLiteralExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture); + var value = JassLiteral.ParseOctal(octalLiteralExpression.Token.Text).ToString(CultureInfo.InvariantCulture); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs index 6961f0c6..4b68b228 100644 --- a/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs +++ b/src/War3Net.CodeAnalysis.Decompilers/Script/SyntaxDecompilers/StringLiteralExpressionDecompiler.cs @@ -23,7 +23,7 @@ private bool TryDecompileStringLiteralExpression( string expectedType, [NotNullWhen(true)] out TriggerFunctionParameter? functionParameter) { - var stringValue = stringLiteralExpression.Token.Text[1..^1]; + var stringValue = JassLiteral.ParseString(stringLiteralExpression.Token.Text); if (TryDecompileTriggerFunctionParameterPreset($"`{stringValue}`", expectedType, out _, out functionParameter)) { @@ -51,7 +51,7 @@ private bool TryDecompileStringLiteralExpression( JassLiteralExpressionSyntax stringLiteralExpression, [NotNullWhen(true)] out List? decompileOptions) { - var stringValue = stringLiteralExpression.Token.Text[1..^1]; + var stringValue = JassLiteral.ParseString(stringLiteralExpression.Token.Text); var value = Regex.Unescape(stringValue); decompileOptions = new(); diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs index 1183caf5..64b6238f 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs @@ -50,7 +50,7 @@ public static bool TryGetCharacterExpressionValue(this JassExpressionSyntax expr if (expression is JassLiteralExpressionSyntax literalExpression && literalExpression.Token.SyntaxKind == JassSyntaxKind.CharacterLiteralToken) { - value = literalExpression.Token.Text[1]; + value = JassLiteral.ParseChar(literalExpression.Token.Text); return true; } @@ -77,19 +77,19 @@ public static bool TryGetIntegerExpressionValue(this JassExpressionSyntax expres switch (literalExpression.Token.SyntaxKind) { case JassSyntaxKind.DecimalLiteralToken: - value = int.Parse(literalExpression.Token.Text, CultureInfo.InvariantCulture); + value = JassLiteral.ParseInt(literalExpression.Token.Text); return true; case JassSyntaxKind.HexadecimalLiteralToken: - value = Convert.ToInt32(literalExpression.Token.Text.StartsWith(JassSymbol.DollarChar) ? literalExpression.Token.Text[1..] : literalExpression.Token.Text[2..], 16); + value = JassLiteral.ParseHex(literalExpression.Token.Text); return true; case JassSyntaxKind.OctalLiteralToken: - value = Convert.ToInt32(literalExpression.Token.Text, 8); + value = JassLiteral.ParseOctal(literalExpression.Token.Text); return true; case JassSyntaxKind.FourCCLiteralToken: - value = literalExpression.Token.Text[1..^1].FromJassRawcode(); + value = JassLiteral.ParseFourCC(literalExpression.Token.Text); return true; default: @@ -180,7 +180,7 @@ public static bool TryGetStringExpressionValue(this JassExpressionSyntax express switch (literalExpression.Token.SyntaxKind) { case JassSyntaxKind.StringLiteralToken: - value = literalExpression.Token.Text[1..^1]; + value = JassLiteral.ParseString(literalExpression.Token.Text); return true; case JassSyntaxKind.NullKeyword: @@ -198,7 +198,7 @@ public static bool TryGetNotNullStringExpressionValue(this JassExpressionSyntax if (expression is JassLiteralExpressionSyntax literalExpression && literalExpression.Token.SyntaxKind == JassSyntaxKind.StringLiteralToken) { - value = literalExpression.Token.Text[1..^1]; + value = JassLiteral.ParseString(literalExpression.Token.Text); return true; } diff --git a/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs b/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs index a2312347..791b7637 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassLiteral.cs @@ -8,6 +8,7 @@ using System; using System.Globalization; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.Common.Extensions; namespace War3Net.CodeAnalysis.Jass @@ -48,5 +49,54 @@ public static string FourCC(string value) { return $"{JassSymbol.SingleQuoteChar}{value}{JassSymbol.SingleQuoteChar}"; } + + public static float ParseReal(string value) + { + return float.Parse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture); + } + + public static char ParseChar(string value) + { + if (value[1] == '\\') + { + return value[2] switch + { + 'r' => '\r', + 'n' => '\n', + 't' => '\t', + 'b' => '\b', + 'f' => '\f', + _ => value[2], + }; + } + + return value[1]; + } + + public static string ParseString(string value) + { + return value[1..^1]; + } + + public static int ParseInt(string value) + { + return int.Parse(value, NumberStyles.None, CultureInfo.InvariantCulture); + } + + public static int ParseHex(string value) + { + var hexDigits = value.StartsWith(JassSymbol.DollarChar) ? value[1..] : value[2..]; + return Convert.ToInt32(hexDigits, 16); + } + + public static int ParseOctal(string value) + { + return Convert.ToInt32(value, 8); + } + + public static int ParseFourCC(string value) + { + return value[1..^1].FromJassRawcode(); + } } } \ No newline at end of file diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs index 6616e173..035b0e15 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToCSharp/LiteralExpressionTranspiler.cs @@ -45,7 +45,7 @@ private ExpressionSyntax TranspileLiteral(SyntaxKind expressionKind, SyntaxKind private ExpressionSyntax TranspileDecimalLiteral(JassLiteralExpressionSyntax literalExpression) { - var value = Convert.ToInt32(literalExpression.Token.Text, 10); + var value = JassLiteral.ParseInt(literalExpression.Token.Text); var text = value.ToString(CultureInfo.InvariantCulture); return SyntaxFactory.LiteralExpression( @@ -59,7 +59,7 @@ private ExpressionSyntax TranspileDecimalLiteral(JassLiteralExpressionSyntax lit private ExpressionSyntax TranspileOctalLiteral(JassLiteralExpressionSyntax literalExpression) { - var value = Convert.ToInt32(literalExpression.Token.Text, 8); + var value = JassLiteral.ParseOctal(literalExpression.Token.Text); var text = value.ToString(CultureInfo.InvariantCulture); return SyntaxFactory.LiteralExpression( @@ -87,7 +87,7 @@ private ExpressionSyntax TranspileHexadecimalLiteral(JassLiteralExpressionSyntax private ExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax literalExpression) { - var value = literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar).FromRawcode(); + var value = JassLiteral.ParseFourCC(literalExpression.Token.Text); var text = value.ToString(CultureInfo.InvariantCulture); return SyntaxFactory.LiteralExpression( @@ -101,7 +101,7 @@ private ExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax lite private ExpressionSyntax TranspileCharacterLiteral(JassLiteralExpressionSyntax literalExpression) { - var value = (int)char.Parse(literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar)); + var value = JassLiteral.ParseChar(literalExpression.Token.Text); var text = $"(int){literalExpression.Token.Text}"; return SyntaxFactory.LiteralExpression( diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs index 6d71338a..aae40b77 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/LiteralExpressionTranspiler.cs @@ -61,7 +61,7 @@ private LuaExpressionSyntax TranspileDecimalLiteral(JassLiteralExpressionSyntax private LuaExpressionSyntax TranspileOctalLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) { type = JassPredefinedTypeSyntax.Integer; - var text = Convert.ToInt32(literalExpression.Token.Text, 8).ToString(CultureInfo.InvariantCulture); + var text = JassLiteral.ParseOctal(literalExpression.Token.Text).ToString(CultureInfo.InvariantCulture); return new LuaIdentifierLiteralExpressionSyntax(text); } @@ -77,7 +77,7 @@ private LuaExpressionSyntax TranspileHexadecimalLiteral(JassLiteralExpressionSyn private LuaExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) { type = JassPredefinedTypeSyntax.Integer; - var text = $"FourCC(\"{literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar)}\")"; + var text = $"FourCC(\"{literalExpression.Token.Text[1..^1]}\")"; return new LuaIdentifierLiteralExpressionSyntax(text); } @@ -85,7 +85,7 @@ private LuaExpressionSyntax TranspileFourCCLiteral(JassLiteralExpressionSyntax l private LuaExpressionSyntax TranspileCharacterLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) { type = JassPredefinedTypeSyntax.Integer; - var text = ((int)char.Parse(literalExpression.Token.Text.Trim(JassSymbol.SingleQuoteChar))).ToString(CultureInfo.InvariantCulture); + var text = ((int)JassLiteral.ParseChar(literalExpression.Token.Text)).ToString(CultureInfo.InvariantCulture); return new LuaIdentifierLiteralExpressionSyntax(text); } @@ -99,7 +99,7 @@ private LuaExpressionSyntax TranspileRealLiteral(JassLiteralExpressionSyntax lit private LuaExpressionSyntax TranspileStringLiteral(JassLiteralExpressionSyntax literalExpression, out JassTypeSyntax type) { type = JassPredefinedTypeSyntax.String; - var text = literalExpression.Token.Text + var text = JassLiteral.ParseString(literalExpression.Token.Text) .Replace(JassSymbol.CarriageReturn, @"\r", StringComparison.Ordinal) .Replace(JassSymbol.LineFeed, @"\n", StringComparison.Ordinal); diff --git a/tests/War3Net.CodeAnalysis.Jass.Tests/JassLiteralTests.cs b/tests/War3Net.CodeAnalysis.Jass.Tests/JassLiteralTests.cs new file mode 100644 index 00000000..cddc1d0b --- /dev/null +++ b/tests/War3Net.CodeAnalysis.Jass.Tests/JassLiteralTests.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace War3Net.CodeAnalysis.Jass.Tests +{ + [TestClass] + public class JassLiteralTests + { + [TestMethod] + [DataRow("'t'", 't')] + [DataRow("'\\r'", '\r')] + [DataRow("'\\n'", '\n')] + [DataRow("'\\t'", '\t')] + [DataRow("'\\b'", '\b')] + [DataRow("'\\f'", '\f')] + [DataRow("'\\\\'", '\\')] + [DataRow("'\\\"'", '"')] + [DataRow("'\\''", '\'')] + public void TestParseChar(string characterLiteral, char expectedValue) + { + Assert.AreEqual(expectedValue, JassLiteral.ParseChar(characterLiteral)); + } + } +} \ No newline at end of file From 344f1a82e66fb0a9381e2e0b15dae9ce90303ff4 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:29:35 +0100 Subject: [PATCH 35/53] Add missing MapScriptBuilder tests. --- .../Widget/CreateNeutralHostileBuildings.cs | 82 +++++++++++++++++++ .../Info/InitTechTreeTests.cs | 49 +++++++++++ .../Info/InitUpgradesTests.cs | 49 +++++++++++ .../CreateNeutralHostileBuildingsTests.cs | 49 +++++++++++ 4 files changed, 229 insertions(+) create mode 100644 src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostileBuildings.cs create mode 100644 tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitTechTreeTests.cs create mode 100644 tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitUpgradesTests.cs create mode 100644 tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileBuildingsTests.cs diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostileBuildings.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostileBuildings.cs new file mode 100644 index 00000000..1bcf6965 --- /dev/null +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreateNeutralHostileBuildings.cs @@ -0,0 +1,82 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Linq; + +using War3Net.Build.Extensions; +using War3Net.Build.Info; +using War3Net.Build.Widget; +using War3Net.CodeAnalysis; +using War3Net.CodeAnalysis.Jass.Extensions; + +namespace War3Net.Build +{ + public partial class MapScriptBuilder + { + protected internal virtual void GenerateCreateNeutralHostileBuildings(Map map, IndentedTextWriter writer) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var mapUnits = map.Units; + if (mapUnits is null) + { + throw new ArgumentException($"Function '{GeneratedFunctionName.CreateNeutralHostileBuildings}' cannot be generated without {nameof(MapUnits)}.", nameof(map)); + } + + writer.WriteFunction(GeneratedFunctionName.CreateNeutralHostileBuildings); + + GenerateCreateUnits( + map, + mapUnits.Units.IncludeId().Where(pair => ShouldGenerateCreateNeutralHostileBuildingsForUnit(map, pair.Obj)), + GlobalVariableName.PlayerNeutralHostile, + writer); + + writer.EndFunction(); + } + + protected internal virtual bool ShouldGenerateCreateNeutralHostileBuildings(Map map) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + if (map.Info is not null && map.Info.FormatVersion < MapInfoFormatVersion.v15) + { + return false; + } + + return map.Units is not null + && map.Units.Units.Any(unit => ShouldGenerateCreateNeutralHostileBuildingsForUnit(map, unit)); + } + + protected internal virtual bool ShouldGenerateCreateNeutralHostileBuildingsForUnit(Map map, UnitData unitData) + { + if (map is null) + { + throw new ArgumentNullException(nameof(map)); + } + + if (unitData is null) + { + throw new ArgumentNullException(nameof(unitData)); + } + + var neutralHostileId = MaxPlayerSlots; + return unitData.OwnerId == neutralHostileId && unitData.IsUnit() && unitData.IsBuilding(map.UnitObjectData); + } + } +} \ No newline at end of file diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitTechTreeTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitTechTreeTests.cs new file mode 100644 index 00000000..71dda39f --- /dev/null +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitTechTreeTests.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using War3Net.TestTools.UnitTesting; + +namespace War3Net.Build.Tests +{ + public partial class MapScriptBuilderTests + { + [FlakyTestMethod] + [DynamicData(nameof(GetTestDataInitTechTree), DynamicDataSourceType.Method)] + public void TestBodyInitTechTree(MapScriptBuilderTestData testData) + { + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitTechTree, + writer => testData.MapScriptBuilder.GenerateInitTechTree(testData.Map, writer)); + } + + [FlakyTestMethod] + [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] + public void TestConditionInitTechTree(MapScriptBuilderTestData testData) + { + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitTechTree); + var actual = testData.MapScriptBuilder.ShouldGenerateInitTechTree(testData.Map); + + Assert.AreEqual(expected, actual); + } + + private static IEnumerable GetTestDataInitTechTree() + { + foreach (var testData in GetUnobfuscatedTestData()) + { + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitTechTree)) + { + yield return testData; + } + } + } + } +} \ No newline at end of file diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitUpgradesTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitUpgradesTests.cs new file mode 100644 index 00000000..b1a9b1b7 --- /dev/null +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Info/InitUpgradesTests.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using War3Net.TestTools.UnitTesting; + +namespace War3Net.Build.Tests +{ + public partial class MapScriptBuilderTests + { + [FlakyTestMethod] + [DynamicData(nameof(GetTestDataInitUpgrades), DynamicDataSourceType.Method)] + public void TestBodyInitUpgrades(MapScriptBuilderTestData testData) + { + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.InitUpgrades, + writer => testData.MapScriptBuilder.GenerateInitUpgrades(testData.Map, writer)); + } + + [FlakyTestMethod] + [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] + public void TestConditionInitUpgrades(MapScriptBuilderTestData testData) + { + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitUpgrades); + var actual = testData.MapScriptBuilder.ShouldGenerateInitUpgrades(testData.Map); + + Assert.AreEqual(expected, actual); + } + + private static IEnumerable GetTestDataInitUpgrades() + { + foreach (var testData in GetUnobfuscatedTestData()) + { + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.InitUpgrades)) + { + yield return testData; + } + } + } + } +} \ No newline at end of file diff --git a/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileBuildingsTests.cs b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileBuildingsTests.cs new file mode 100644 index 00000000..5f67d9f2 --- /dev/null +++ b/tests/War3Net.Build.Tests/MapScriptBuilder/Widget/CreateNeutralHostileBuildingsTests.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------ +// +// Licensed under the MIT license. +// See the LICENSE file in the project root for more information. +// +// ------------------------------------------------------------------------------ + +using System.Collections.Generic; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using War3Net.TestTools.UnitTesting; + +namespace War3Net.Build.Tests +{ + public partial class MapScriptBuilderTests + { + [FlakyTestMethod] + [DynamicData(nameof(GetTestDataCreateNeutralHostileBuildings), DynamicDataSourceType.Method)] + public void TestBodyCreateNeutralHostileBuildings(MapScriptBuilderTestData testData) + { + AssertFunctionGeneratedCorrectly( + testData, + MapScriptBuilder.GeneratedFunctionName.CreateNeutralHostileBuildings, + writer => testData.MapScriptBuilder.GenerateCreateNeutralHostileBuildings(testData.Map, writer)); + } + + [TestMethod] + [DynamicData(nameof(GetUnobfuscatedTestData), DynamicDataSourceType.Method)] + public void TestConditionCreateNeutralHostileBuildings(MapScriptBuilderTestData testData) + { + var expected = testData.DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralHostileBuildings); + var actual = testData.MapScriptBuilder.ShouldGenerateCreateNeutralHostileBuildings(testData.Map); + + Assert.AreEqual(expected, actual); + } + + private static IEnumerable GetTestDataCreateNeutralHostileBuildings() + { + foreach (var testData in GetUnobfuscatedTestData()) + { + if (((MapScriptBuilderTestData)testData[0]).DeclaredFunctions.ContainsKey(MapScriptBuilder.GeneratedFunctionName.CreateNeutralHostileBuildings)) + { + yield return testData; + } + } + } + } +} \ No newline at end of file From 8a1c0472aa6abf280cdbd548b5a4a6849ec9ac0b Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:30:13 +0100 Subject: [PATCH 36/53] Fix nameof -> GeneratedFunctionName. --- src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs b/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs index 6a7f2a0a..471ba0d3 100644 --- a/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs +++ b/src/War3Net.Build/MapScriptBuilder/Audio/InitSounds.cs @@ -31,7 +31,7 @@ protected internal virtual void GenerateInitSounds(Map map, IndentedTextWriter w var mapSounds = map.Sounds; if (mapSounds is null) { - throw new ArgumentException($"Function '{nameof(InitSounds)}' cannot be generated without {nameof(MapSounds)}.", nameof(map)); + throw new ArgumentException($"Function '{GeneratedFunctionName.InitSounds}' cannot be generated without {nameof(MapSounds)}.", nameof(map)); } writer.WriteFunction(GeneratedFunctionName.InitSounds); From 0f0453ac112e547891a6442a801d69c1fa754656 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:34:11 +0100 Subject: [PATCH 37/53] Prefer checking expression's syntax kind. --- .../Extensions/JassExpressionSyntaxExtensions.cs | 6 +++--- .../Renderer/UnaryExpressionRenderer.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs b/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs index 64b6238f..e1627f99 100644 --- a/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs +++ b/src/War3Net.CodeAnalysis.Jass/Extensions/JassExpressionSyntaxExtensions.cs @@ -99,12 +99,12 @@ public static bool TryGetIntegerExpressionValue(this JassExpressionSyntax expres } else if (expression is JassUnaryExpressionSyntax unaryExpression) { - switch (unaryExpression.OperatorToken.SyntaxKind) + switch (unaryExpression.SyntaxKind) { - case JassSyntaxKind.PlusToken: + case JassSyntaxKind.UnaryPlusExpression: return unaryExpression.Expression.TryGetIntegerExpressionValue(out value); - case JassSyntaxKind.MinusToken: + case JassSyntaxKind.UnaryMinusExpression: if (unaryExpression.Expression.TryGetIntegerExpressionValue(out var result)) { value = -result; diff --git a/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs b/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs index 8ea7d4fd..f683fd80 100644 --- a/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs +++ b/src/War3Net.CodeAnalysis.Jass/Renderer/UnaryExpressionRenderer.cs @@ -14,7 +14,7 @@ public partial class JassRenderer public void Render(JassUnaryExpressionSyntax unaryExpression) { Render(unaryExpression.OperatorToken); - if (unaryExpression.OperatorToken.SyntaxKind == JassSyntaxKind.NotKeyword) + if (unaryExpression.SyntaxKind == JassSyntaxKind.LogicalNotExpression) { WriteSpace(); } From de426b2de4c72fa083dd9bcaa4db3def7f6a3093 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:38:51 +0100 Subject: [PATCH 38/53] Fix syntax kind validation. --- .../SyntaxFactory/BinaryExpressionFactory.cs | 9 +++++++-- .../SyntaxFactory/DebugStatementFactory.cs | 16 ++++++++++++---- .../SyntaxFactory/UnaryExpressionFactory.cs | 9 +++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs index 3245dc8e..4dd543cf 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/BinaryExpressionFactory.cs @@ -5,6 +5,8 @@ //
// ------------------------------------------------------------------------------ +using System; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -109,8 +111,11 @@ public static JassBinaryExpressionSyntax BinaryOrExpression(JassExpressionSyntax public static JassBinaryExpressionSyntax BinaryExpression(JassExpressionSyntax left, JassSyntaxToken operatorToken, JassExpressionSyntax right) { - // Token validation - JassSyntaxFacts.GetBinaryExpressionKind(operatorToken.SyntaxKind); + var expressionKind = JassSyntaxFacts.GetBinaryExpressionKind(operatorToken.SyntaxKind); + if (expressionKind == JassSyntaxKind.None) + { + throw new ArgumentException($"'{operatorToken.SyntaxKind}' is not a valid operator kind for binary expressions.", nameof(operatorToken)); + } return new JassBinaryExpressionSyntax( left, diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs index 0791f0f2..dae98a17 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/DebugStatementFactory.cs @@ -5,6 +5,8 @@ //
// ------------------------------------------------------------------------------ +using System; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -13,8 +15,11 @@ public static partial class JassSyntaxFactory { public static JassDebugStatementSyntax DebugStatement(JassStatementSyntax statement) { - // Statement validation - JassSyntaxFacts.GetDebugStatementKind(statement.SyntaxKind); + var statementKind = JassSyntaxFacts.GetDebugStatementKind(statement.SyntaxKind); + if (statementKind == JassSyntaxKind.None) + { + throw new ArgumentException($"'{statement.SyntaxKind}' is not a valid statement kind for debug statements.", nameof(statement)); + } return new JassDebugStatementSyntax( Token(JassSyntaxKind.DebugKeyword), @@ -25,8 +30,11 @@ public static JassDebugStatementSyntax DebugStatement(JassSyntaxToken debugToken { ThrowHelper.ThrowIfInvalidToken(debugToken, JassSyntaxKind.DebugKeyword); - // Statement validation - JassSyntaxFacts.GetDebugStatementKind(statement.SyntaxKind); + var statementKind = JassSyntaxFacts.GetDebugStatementKind(statement.SyntaxKind); + if (statementKind == JassSyntaxKind.None) + { + throw new ArgumentException($"'{statement.SyntaxKind}' is not a valid statement kind for debug statements.", nameof(statement)); + } return new JassDebugStatementSyntax( debugToken, diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs index 48fa668e..37a6b222 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/UnaryExpressionFactory.cs @@ -5,6 +5,8 @@ //
// ------------------------------------------------------------------------------ +using System; + using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Jass @@ -34,8 +36,11 @@ public static JassUnaryExpressionSyntax UnaryNotExpression(JassExpressionSyntax public static JassUnaryExpressionSyntax UnaryNotExpression(JassSyntaxToken operatorToken, JassExpressionSyntax expression) { - // Token validation - JassSyntaxFacts.GetUnaryExpressionKind(operatorToken.SyntaxKind); + var expressionKind = JassSyntaxFacts.GetUnaryExpressionKind(operatorToken.SyntaxKind); + if (expressionKind == JassSyntaxKind.None) + { + throw new ArgumentException($"'{operatorToken.SyntaxKind}' is not a valid operator kind for unary expressions.", nameof(operatorToken)); + } return new JassUnaryExpressionSyntax( operatorToken, From 93001b0e6fb98a239beca20794eeec64432f2262 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:42:09 +0100 Subject: [PATCH 39/53] Improve exception message. --- .../SyntaxFactory/SyntaxTokenFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs index d6d21fc7..3522cebb 100644 --- a/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/SyntaxFactory/SyntaxTokenFactory.cs @@ -27,7 +27,7 @@ public static JassSyntaxToken Token(JassSyntaxKind syntaxKind) var text = JassSyntaxFacts.GetText(syntaxKind); if (text.Length == 0 && syntaxKind != JassSyntaxKind.EndOfFileToken) { - throw new InvalidEnumArgumentException(nameof(syntaxKind), (int)syntaxKind, typeof(JassSyntaxKind)); + throw new ArgumentException($"'{syntaxKind}' does not have default text.", nameof(syntaxKind)); } token = new JassSyntaxToken(JassSyntaxTriviaList.Empty, syntaxKind, text, JassSyntaxTriviaList.Empty); @@ -55,7 +55,7 @@ public static JassSyntaxToken Token(JassSyntaxTriviaList leadingTrivia, JassSynt var text = JassSyntaxFacts.GetText(syntaxKind); if (text.Length == 0 && syntaxKind != JassSyntaxKind.EndOfFileToken) { - throw new InvalidEnumArgumentException(nameof(syntaxKind), (int)syntaxKind, typeof(JassSyntaxKind)); + throw new ArgumentException($"'{syntaxKind}' does not have default text.", nameof(syntaxKind)); } return new JassSyntaxToken(leadingTrivia, syntaxKind, text, trailingTrivia); From a7d9d23146c3ec9288ccbbe670869f15deb65c9b Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:06:08 +0100 Subject: [PATCH 40/53] Central package management fix. --- Directory.Build.props | 2 +- Directory.Packages.props | 1 + NuGet.config | 2 +- src/Directory.Build.props | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ae833a36..cfc5905e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,7 +6,7 @@
- + diff --git a/Directory.Packages.props b/Directory.Packages.props index 83f32d4b..169d8908 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,6 +11,7 @@ + diff --git a/NuGet.config b/NuGet.config index 8a2bf809..d4b82f99 100644 --- a/NuGet.config +++ b/NuGet.config @@ -16,9 +16,9 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ccc2aceb..30bfe7ae 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -17,7 +17,7 @@ - + From 3bc13a908193b52e195d94effda080ee4552408f Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:36:42 +0100 Subject: [PATCH 41/53] Update CSharpLua submodule. --- Directory.Packages.props | 4 ++-- submodules/CSharp.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 169d8908..8aa27407 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -40,8 +40,8 @@ - - + + diff --git a/submodules/CSharp.lua b/submodules/CSharp.lua index 22c13bdf..8ad08a0b 160000 --- a/submodules/CSharp.lua +++ b/submodules/CSharp.lua @@ -1 +1 @@ -Subproject commit 22c13bdfc5dcadeb433000cd7af9f2ddff76f05b +Subproject commit 8ad08a0bfc48d075d6732ef720736ab196c3d154 From d4d39201caa80eb0dab45ea5af8bc15a154338bd Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:56:27 +0100 Subject: [PATCH 42/53] Update PolyglotJassToLuaTranspiler. --- .../JassToLua/BinaryExpressionTranspiler.cs | 8 +- .../PolyglotJassToLuaTranspiler.cs | 186 ++++++++---------- 2 files changed, 87 insertions(+), 107 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs index d90f14b1..80cb52cc 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/BinaryExpressionTranspiler.cs @@ -38,9 +38,9 @@ public string TranspileBinaryExpressionKind(JassSyntaxKind expressionKind, JassT break; default: - type = left.Equals(JassPredefinedTypeSyntax.String) || right.Equals(JassPredefinedTypeSyntax.String) + type = left.IsEquivalentTo(JassPredefinedTypeSyntax.String) || right.IsEquivalentTo(JassPredefinedTypeSyntax.String) ? JassPredefinedTypeSyntax.String - : left.Equals(JassPredefinedTypeSyntax.Real) || right.Equals(JassPredefinedTypeSyntax.Real) + : left.IsEquivalentTo(JassPredefinedTypeSyntax.Real) || right.IsEquivalentTo(JassPredefinedTypeSyntax.Real) ? JassPredefinedTypeSyntax.Real : left; break; @@ -48,10 +48,10 @@ public string TranspileBinaryExpressionKind(JassSyntaxKind expressionKind, JassT return expressionKind switch { - JassSyntaxKind.AddExpression => type.Equals(JassPredefinedTypeSyntax.String) ? LuaSyntaxNode.Tokens.Concatenation : LuaSyntaxNode.Tokens.Plus, + JassSyntaxKind.AddExpression => type.IsEquivalentTo(JassPredefinedTypeSyntax.String) ? LuaSyntaxNode.Tokens.Concatenation : LuaSyntaxNode.Tokens.Plus, JassSyntaxKind.SubtractExpression => LuaSyntaxNode.Tokens.Sub, JassSyntaxKind.MultiplyExpression => LuaSyntaxNode.Tokens.Multiply, - JassSyntaxKind.DivideExpression => type.Equals(JassPredefinedTypeSyntax.Integer) ? LuaSyntaxNode.Tokens.IntegerDiv : LuaSyntaxNode.Tokens.Div, + JassSyntaxKind.DivideExpression => type.IsEquivalentTo(JassPredefinedTypeSyntax.Integer) ? LuaSyntaxNode.Tokens.IntegerDiv : LuaSyntaxNode.Tokens.Div, JassSyntaxKind.GreaterThanExpression => ">", JassSyntaxKind.LessThanExpression => "<", JassSyntaxKind.EqualsExpression => LuaSyntaxNode.Tokens.EqualsEquals, diff --git a/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs index 917808ba..229c1b44 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs @@ -17,7 +17,7 @@ namespace War3Net.CodeAnalysis.Transpilers { /// - /// Special that can handle lua code embedded in the jass code using //! beginusercode and //! endusercode. + /// Special that can handle lua code embedded in the jass code using //! beginusercode and //! endusercode. /// public class PolyglotJassToLuaTranspiler { @@ -38,195 +38,172 @@ public PolyglotJassToLuaTranspiler( _writer = writer; _isUserCode = false; - _scriptContext = JassScriptContext.Declarations; + _scriptContext = JassScriptContext.TopLevelDeclarations; } private enum JassScriptContext { - Declarations, - Globals, - Statements, + TopLevelDeclarations, + GlobalsBlock, + FunctionBody, } public void Transpile(string input) { using var reader = new StringReader(input); + var lineNumber = 0; while (true) { + lineNumber++; var line = reader.ReadLine(); if (line is null) { break; } - if (JassSyntaxFactory.TryParseComment(line, out var comment)) + var trimmed = line.AsSpan().TrimStart(); + if (trimmed.StartsWith("//")) { - if (string.Equals(comment.Comment, "! beginusercode", StringComparison.Ordinal)) + var comment = trimmed.TrimEnd(); + + if (trimmed.Equals("//! beginusercode", StringComparison.Ordinal)) { if (_isUserCode) { - throw new ArgumentException("Invalid: beginusercode", nameof(input)); + throw new ArgumentException("Unexpected //! beginusercode", nameof(input)); } _isUserCode = true; continue; } - else if (string.Equals(comment.Comment, "! endusercode", StringComparison.Ordinal)) + else if (trimmed.Equals("//! endusercode", StringComparison.Ordinal)) { if (!_isUserCode) { - throw new ArgumentException("Invalid: endusercode", nameof(input)); + throw new ArgumentException("Unexpected //! endusercode", nameof(input)); } _isUserCode = false; continue; } + else if (_isUserCode) + { + _writer.WriteLine(line); + } + else if (!_transpiler.IgnoreComments) + { + _renderer.Render(new LuaShortCommentStatement(trimmed[2..].ToString())); + } } - - if (_isUserCode) + else if (_isUserCode) { _writer.WriteLine(line); } - else + else if (JassSyntaxFactory.TryParseScriptLine(line, out var scriptLine)) { - switch (_scriptContext) + try { - case JassScriptContext.Declarations: - Transpile(JassSyntaxFactory.ParseDeclarationLine(line)); - break; - - case JassScriptContext.Globals: - Transpile(JassSyntaxFactory.ParseGlobalLine(line)); - break; - - case JassScriptContext.Statements: - Transpile(JassSyntaxFactory.ParseStatementLine(line)); - break; + Transpile(scriptLine.Value); } + catch (Exception ex) + { + throw new ArgumentException($"Failed to transpile JASS on line {lineNumber}: {line}", nameof(input), ex); + } + } + else + { + throw new ArgumentException($"Invalid JASS on line {lineNumber}: {line}", nameof(input)); } } } - private void Transpile(IDeclarationLineSyntax declarationLine) + private void Transpile(JassSyntaxNodeOrToken scriptLine) + { + if (scriptLine.TryPickToken(out var token, out var node)) + { + Transpile(token); + } + else + { + Transpile(node); + } + } + + private void Transpile(JassSyntaxToken token) { - switch (declarationLine) + switch (token.SyntaxKind) { - case JassCommentSyntax comment: - _renderer.Render((LuaShortCommentStatement)_transpiler.Transpile(comment)); + case JassSyntaxKind.ElseKeyword: + _renderer.RenderElse(); break; - case JassEmptySyntax: - if (!_transpiler.IgnoreEmptyDeclarations) - { - _writer.WriteLine(); - } + case JassSyntaxKind.EndFunctionKeyword: + _renderer.RenderEnd(); + _transpiler.ClearLocalTypes(); + _scriptContext = JassScriptContext.TopLevelDeclarations; + break; + case JassSyntaxKind.EndGlobalsKeyword: + _scriptContext = JassScriptContext.TopLevelDeclarations; break; - case JassTypeDeclarationSyntax: + case JassSyntaxKind.EndIfKeyword: + _renderer.RenderEnd(); break; - case JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration: - _transpiler.RegisterFunctionReturnType(nativeFunctionDeclaration.FunctionDeclarator); + case JassSyntaxKind.EndLoopKeyword: + _renderer.RenderEnd(); break; - case JassGlobalsCustomScriptAction: - _scriptContext = JassScriptContext.Globals; + case JassSyntaxKind.GlobalsKeyword: + _scriptContext = JassScriptContext.GlobalsBlock; break; - case JassFunctionCustomScriptAction functionCustomScriptAction: - _renderer.RenderFunctionDeclarator(_transpiler.Transpile(functionCustomScriptAction.FunctionDeclarator)); - _scriptContext = JassScriptContext.Statements; + case JassSyntaxKind.LoopKeyword: + _renderer.RenderLoop(); break; } } - private void Transpile(IGlobalLineSyntax globalLine) + private void Transpile(JassSyntaxNode node) { - switch (globalLine) + switch (node) { - case JassCommentSyntax comment: - _renderer.Render((LuaShortCommentStatement)_transpiler.Transpile(comment)); - break; - - case JassEmptySyntax: - if (!_transpiler.IgnoreEmptyDeclarations) - { - _writer.WriteLine(); - } - - break; - case JassGlobalDeclarationSyntax globalDeclaration: _renderer.Render((LuaLocalDeclarationStatementSyntax)_transpiler.Transpile(globalDeclaration)); break; - case JassEndGlobalsCustomScriptAction: - _scriptContext = JassScriptContext.Declarations; - break; - } - } - - private void Transpile(IStatementLineSyntax statementLine) - { - switch (statementLine) - { case JassCallStatementSyntax callStatement: _renderer.Render((LuaExpressionStatementSyntax)_transpiler.Transpile(callStatement)); break; - case JassCommentSyntax comment: - _renderer.Render((LuaShortCommentStatement)_transpiler.Transpile(comment)); - break; - - case JassDebugCustomScriptAction: + case JassDebugStatementSyntax: throw new NotSupportedException(); - case JassElseCustomScriptAction: - _renderer.RenderElse(); - break; - - case JassElseIfCustomScriptAction elseIfCustomScriptAction: - _renderer.RenderElseIf(_transpiler.Transpile(elseIfCustomScriptAction.Condition, out _)); - break; - - case JassEmptySyntax: - if (!_transpiler.IgnoreEmptyStatements) - { - _writer.WriteLine(); - } - - break; - - case JassEndFunctionCustomScriptAction: - _renderer.RenderEnd(); - _transpiler.ClearLocalTypes(); - _scriptContext = JassScriptContext.Declarations; - break; - - case JassEndIfCustomScriptAction: - _renderer.RenderEnd(); - break; - - case JassEndLoopCustomScriptAction: - _renderer.RenderEnd(); + case JassElseIfClauseDeclaratorSyntax elseIfClauseDeclarator: + _renderer.RenderElseIf(_transpiler.Transpile(elseIfClauseDeclarator.Condition, out _)); break; case JassExitStatementSyntax exitStatement: _renderer.Render((LuaIfStatementSyntax)_transpiler.Transpile(exitStatement)); break; - case JassIfCustomScriptAction ifCustomScriptAction: - _renderer.RenderIf(_transpiler.Transpile(ifCustomScriptAction.Condition, out _)); + case JassFunctionDeclaratorSyntax functionDeclarator: + _renderer.RenderFunctionDeclarator(_transpiler.Transpile(functionDeclarator)); + _scriptContext = JassScriptContext.FunctionBody; + break; + + case JassIfClauseDeclaratorSyntax ifClauseDeclarator: + _renderer.RenderIf(_transpiler.Transpile(ifClauseDeclarator.Condition, out _)); break; case JassLocalVariableDeclarationStatementSyntax localVariableDeclarationStatement: _renderer.Render((LuaLocalDeclarationStatementSyntax)_transpiler.Transpile(localVariableDeclarationStatement)); break; - case JassLoopCustomScriptAction: - _renderer.RenderLoop(); + case JassNativeFunctionDeclarationSyntax nativeFunctionDeclaration: + _transpiler.RegisterFunctionReturnType(nativeFunctionDeclaration); break; case JassReturnStatementSyntax returnStatement: @@ -236,6 +213,9 @@ private void Transpile(IStatementLineSyntax statementLine) case JassSetStatementSyntax setStatement: _renderer.Render((LuaExpressionStatementSyntax)_transpiler.Transpile(setStatement)); break; + + case JassTypeDeclarationSyntax: + break; } } } From b3f309b4818da94274cdb1e1831ac89c512d345f Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:04:43 +0100 Subject: [PATCH 43/53] Bugfix transpile array to lua. --- .../JassToLua/ArrayDeclaratorTranspiler.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs index ac5b558f..d44bc1b9 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/JassToLua/ArrayDeclaratorTranspiler.cs @@ -8,6 +8,7 @@ using CSharpLua.LuaAst; using War3Net.CodeAnalysis.Jass; +using War3Net.CodeAnalysis.Jass.Extensions; using War3Net.CodeAnalysis.Jass.Syntax; namespace War3Net.CodeAnalysis.Transpilers @@ -16,7 +17,7 @@ public partial class JassToLuaTranspiler { public LuaVariableDeclaratorSyntax Transpile(JassArrayDeclaratorSyntax arrayDeclarator) { - LuaExpressionSyntax expression = arrayDeclarator.Type.SyntaxKind switch + LuaExpressionSyntax expression = arrayDeclarator.Type.GetToken().SyntaxKind switch { JassSyntaxKind.IntegerKeyword => new LuaInvocationExpressionSyntax("__jarray", "0"), JassSyntaxKind.RealKeyword => new LuaInvocationExpressionSyntax("__jarray", "0.0"), From 77d5c3fea53f08bb8d447a405ad2f5f672d4c57f Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:07:44 +0100 Subject: [PATCH 44/53] Update CSharpLua submodule. --- submodules/CSharp.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/CSharp.lua b/submodules/CSharp.lua index 8ad08a0b..59801751 160000 --- a/submodules/CSharp.lua +++ b/submodules/CSharp.lua @@ -1 +1 @@ -Subproject commit 8ad08a0bfc48d075d6732ef720736ab196c3d154 +Subproject commit 5980175154b7e42212dff6225e11750ed402d70b From d11409331f9fa17bbedad337eb0e289bf83c3acf Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:21:04 +0100 Subject: [PATCH 45/53] Fix build errors. --- .../Widget/CreatePlayerBuildings.cs | 2 +- .../JassSyntaxFactory.cs | 10 +++++++++ .../SyntaxAssert.cs | 22 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs b/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs index 4b6498e6..f5194d7d 100644 --- a/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs +++ b/src/War3Net.Build/MapScriptBuilder/Widget/CreatePlayerBuildings.cs @@ -56,7 +56,7 @@ protected internal virtual bool ShouldGenerateCreatePlayerBuildings(Map map) } return map.Units is not null - && map.Units.Units.Any(unit => CreatePlayerBuildingsConditionSingleUnit(map, unit)); + && map.Units.Units.Any(unit => ShouldGenerateCreatePlayerBuildingsForUnit(map, unit)); } protected internal virtual bool ShouldGenerateCreatePlayerBuildingsForUnit(Map map, UnitData unitData) diff --git a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs index 8f8e68f0..87dd64c4 100644 --- a/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs +++ b/src/War3Net.CodeAnalysis.Jass/JassSyntaxFactory.cs @@ -33,6 +33,11 @@ public static JassCompilationUnitSyntax ParseCompilationUnit(string compilationU return JassParser.Instance.CompilationUnitParser.ParseOrThrow(compilationUnit); } + public static JassSyntaxNodeOrToken ParseCustomScriptAction(string customScriptAction) + { + throw new NotImplementedException(); + } + public static JassExpressionSyntax ParseExpression(string expression) { return JassParser.Instance.ExpressionParser.ParseOrThrow(expression); @@ -118,6 +123,11 @@ public static bool TryParseParameterList(string parameterList, [NotNullWhen(true return TryParse(parameterList, JassParser.Instance.ParameterListParser, out result); } + public static bool TryParseScriptLine(string scriptLine, [NotNullWhen(true)] out JassSyntaxNodeOrToken? result) + { + throw new NotImplementedException(); + } + public static bool TryParseStatement(string statement, [NotNullWhen(true)] out JassStatementSyntax? result) { return TryParse(statement, JassParser.Instance.StatementParser, out result); diff --git a/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs b/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs index 9b7fdfce..bcbd5c55 100644 --- a/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs +++ b/tests/War3Net.TestTools.UnitTesting/SyntaxAssert.cs @@ -199,6 +199,28 @@ private static string GetAssertFailedMessage(JassTopLevelDeclarationSyntax? expe return GetAssertFailedMessage((object?)expected, actual); } + public static void AreEqual(JassSyntaxNodeOrToken expected, JassSyntaxNodeOrToken actual) + { + if (expected.IsNode && actual.IsNode) + { + if (!expected.AsNode.IsEquivalentTo(actual.AsNode)) + { + Assert.Fail("Syntax nodes are not equal:\r\n" + GetAssertFailedMessage(expected.AsNode, actual.AsNode)); + } + } + else if (expected.IsToken && actual.IsToken) + { + if (!expected.AsToken.IsEquivalentTo(actual.AsToken)) + { + Assert.Fail($"Syntax tokens are not equal:\r\nExpected: '{expected.AsToken.ToFullString()}'<{expected.AsToken.SyntaxKind}>\r\nActual: '{actual.AsToken.ToFullString()}'<{actual.AsToken.SyntaxKind}>"); + } + } + else + { + Assert.Fail($"Syntax types are not equal:\r\nExpected: {(expected.IsNode ? "Node" : "Token")}\r\nActual: {(actual.IsNode ? "Node" : "Token")}"); + } + } + public static void ExpressionThrowsException(string expression) { var message = new BoxedString(); From f40ad618392f1f039ffaf5d1d0c82af2328c55b3 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:23:54 +0100 Subject: [PATCH 46/53] Add JassSyntaxKind to migration guide. --- docs/guides/jass-migration-guide-v5-to-v6.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/guides/jass-migration-guide-v5-to-v6.md b/docs/guides/jass-migration-guide-v5-to-v6.md index ed57d0e8..231d8cca 100644 --- a/docs/guides/jass-migration-guide-v5-to-v6.md +++ b/docs/guides/jass-migration-guide-v5-to-v6.md @@ -31,10 +31,11 @@ Other new syntax node classes: | `JassParameterListOrEmptyParameterListSyntax` | Abstract base class for empty (`takes nothing`) and not-empty (`takes `) lists | | `JassSyntaxNode` | Abstract base class for all new and existing syntax node classes | -Other new classes: +Other new types: | Type name | Purpose | |-------------------------|--------------------------------------------------------------------------------| +| `JassSyntaxKind` | Mainly used to tell the difference between literals and operators | | `JassSyntaxNodeOrToken` | Can be used to model "custom script actions" (one full line of the map script) | | `JassSyntaxToken` | Holds a token's text and trivia | | `JassSyntaxTrivia` | Contains trivia as text (whitespace, newlines, single line comments) | From 3571e32fa79273aaebd18c33840854d9f1bed553 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:25:00 +0100 Subject: [PATCH 47/53] Update versions to 6.0.0 --- Directory.Packages.props | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8aa27407..eaf391c7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -32,21 +32,21 @@ - - - - - - + + + + + + - + - + - - - + + + \ No newline at end of file From 51abd6c917e0ab2e411e09d324b7d684890c9a65 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:31:29 +0100 Subject: [PATCH 48/53] Fix SetProjectVersionsFromCentralPackageManagement target. --- src/Directory.Build.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 19ee7535..10a8f469 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,5 +1,5 @@ - + From 76bf8f43a068eeb6df9e5d13e886f862cf0c9ab0 Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:34:32 +0100 Subject: [PATCH 49/53] Split target. --- src/Directory.Build.targets | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 10a8f469..2311b170 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,5 +1,5 @@ - + @@ -14,4 +14,13 @@ $(PackageVersion) + + + + + + + %(ThisProjectPackageVersion.Version) + + \ No newline at end of file From c8337041ed440f3ec8b52b9eda56344971967e4d Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:47:19 +0100 Subject: [PATCH 50/53] Fix. --- .../PolyglotJassToLuaTranspiler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs b/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs index 229c1b44..6f499f3d 100644 --- a/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs +++ b/src/War3Net.CodeAnalysis.Transpilers/PolyglotJassToLuaTranspiler.cs @@ -67,7 +67,7 @@ public void Transpile(string input) { var comment = trimmed.TrimEnd(); - if (trimmed.Equals("//! beginusercode", StringComparison.Ordinal)) + if (comment.Equals("//! beginusercode", StringComparison.Ordinal)) { if (_isUserCode) { @@ -77,7 +77,7 @@ public void Transpile(string input) _isUserCode = true; continue; } - else if (trimmed.Equals("//! endusercode", StringComparison.Ordinal)) + else if (comment.Equals("//! endusercode", StringComparison.Ordinal)) { if (!_isUserCode) { From f833546bf03e79989fda962d4a11f35722203e5a Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:08:26 +0100 Subject: [PATCH 51/53] Revert directory rename to make it easier to review changes. --- .../{JassParser => Parser}/ArgumentListParser.cs | 0 .../{JassParser => Parser}/BinaryOperatorParser.cs | 0 .../{JassParser => Parser}/CallStatementParser.cs | 0 .../{JassParser => Parser}/CharacterLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/CompilationUnitParser.cs | 0 .../{JassParser => Parser}/DebugStatementParser.cs | 0 .../{JassParser => Parser}/DecimalLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/ElementAccessClauseParser.cs | 0 .../{JassParser => Parser}/ElseIfClauseDeclaratorParser.cs | 0 .../{JassParser => Parser}/EqualsValueClauseParser.cs | 0 .../{JassParser => Parser}/ExitStatementParser.cs | 0 .../{JassParser => Parser}/ExpressionParser.cs | 0 .../{JassParser => Parser}/FourCCLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/FunctionDeclarationParser.cs | 0 .../{JassParser => Parser}/FunctionDeclaratorParser.cs | 0 .../{JassParser => Parser}/GlobalConstantDeclarationParser.cs | 0 .../{JassParser => Parser}/GlobalDeclarationParser.cs | 0 .../{JassParser => Parser}/GlobalVariableDeclarationParser.cs | 0 .../{JassParser => Parser}/GlobalsDeclarationParser.cs | 0 .../{JassParser => Parser}/HexadecimalLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/IdentifierNameParser.cs | 0 .../{JassParser => Parser}/IfClauseDeclaratorParser.cs | 0 .../{JassParser => Parser}/IfStatementParser.cs | 0 .../LocalVariableDeclarationStatementParser.cs | 0 .../{JassParser => Parser}/LoopStatementParser.cs | 0 .../{JassParser => Parser}/NativeFunctionDeclarationParser.cs | 0 .../{JassParser => Parser}/OctalLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/ParameterListParser.cs | 0 .../{JassParser => Parser}/ParameterParser.cs | 0 .../{JassParser => Parser}/ParenthesizedExpressionParser.cs | 0 .../{JassParser => Parser}/RealLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/ReturnClauseParser.cs | 0 .../{JassParser => Parser}/ReturnStatementParser.cs | 0 .../{JassParser => Parser}/SetStatementParser.cs | 0 .../{JassParser => Parser}/StatementParser.cs | 0 .../{JassParser => Parser}/StringLiteralExpressionParser.cs | 0 .../{JassParser => Parser}/SyntaxTriviaListParser.cs | 0 .../{JassParser => Parser}/SyntaxTriviaParser.cs | 0 .../{JassParser => Parser}/TopLevelDeclarationParser.cs | 0 .../{JassParser => Parser}/TypeDeclarationParser.cs | 0 .../{JassParser => Parser}/TypeParser.cs | 0 .../{JassParser => Parser}/UnaryOperatorParser.cs | 0 .../{JassParser => Parser}/VariableOrArrayDeclaratorParser.cs | 0 43 files changed, 0 insertions(+), 0 deletions(-) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ArgumentListParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/BinaryOperatorParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/CallStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/CharacterLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/CompilationUnitParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/DebugStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/DecimalLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ElementAccessClauseParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ElseIfClauseDeclaratorParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/EqualsValueClauseParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ExitStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/FourCCLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/FunctionDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/FunctionDeclaratorParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/GlobalConstantDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/GlobalDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/GlobalVariableDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/GlobalsDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/HexadecimalLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/IdentifierNameParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/IfClauseDeclaratorParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/IfStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/LocalVariableDeclarationStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/LoopStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/NativeFunctionDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/OctalLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ParameterListParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ParameterParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ParenthesizedExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/RealLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ReturnClauseParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/ReturnStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/SetStatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/StatementParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/StringLiteralExpressionParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/SyntaxTriviaListParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/SyntaxTriviaParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/TopLevelDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/TypeDeclarationParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/TypeParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/UnaryOperatorParser.cs (100%) rename src/War3Net.CodeAnalysis.Jass/{JassParser => Parser}/VariableOrArrayDeclaratorParser.cs (100%) diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ArgumentListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ArgumentListParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ArgumentListParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ArgumentListParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/BinaryOperatorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/BinaryOperatorParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/BinaryOperatorParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/BinaryOperatorParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/CallStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/CallStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/CallStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/CallStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/CharacterLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/CharacterLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/CharacterLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/CharacterLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/CompilationUnitParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/CompilationUnitParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/CompilationUnitParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/CompilationUnitParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/DebugStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/DebugStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/DebugStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/DecimalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/DecimalLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/DecimalLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/DecimalLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ElementAccessClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ElementAccessClauseParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ElementAccessClauseParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ElementAccessClauseParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ElseIfClauseDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ElseIfClauseDeclaratorParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ElseIfClauseDeclaratorParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ElseIfClauseDeclaratorParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/EqualsValueClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/EqualsValueClauseParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/EqualsValueClauseParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/EqualsValueClauseParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ExitStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ExitStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ExitStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ExitStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/FourCCLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FourCCLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/FourCCLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/FourCCLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclaratorParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/FunctionDeclaratorParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/FunctionDeclaratorParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalConstantDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalConstantDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/GlobalConstantDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/GlobalConstantDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/GlobalDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/GlobalDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalVariableDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalVariableDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/GlobalVariableDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/GlobalVariableDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/GlobalsDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/GlobalsDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/GlobalsDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/GlobalsDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/HexadecimalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/HexadecimalLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/HexadecimalLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/HexadecimalLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/IdentifierNameParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/IdentifierNameParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/IdentifierNameParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/IdentifierNameParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/IfClauseDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/IfClauseDeclaratorParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/IfClauseDeclaratorParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/IfClauseDeclaratorParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/IfStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/IfStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/IfStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/IfStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/LocalVariableDeclarationStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/LocalVariableDeclarationStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/LocalVariableDeclarationStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/LocalVariableDeclarationStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/LoopStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/LoopStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/LoopStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/LoopStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/NativeFunctionDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/NativeFunctionDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/NativeFunctionDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/NativeFunctionDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/OctalLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/OctalLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/OctalLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ParameterListParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ParameterListParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ParameterListParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ParameterParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ParameterParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ParameterParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ParameterParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ParenthesizedExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ParenthesizedExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ParenthesizedExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ParenthesizedExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/RealLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/RealLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/RealLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/RealLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnClauseParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ReturnClauseParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ReturnClauseParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ReturnClauseParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/ReturnStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/ReturnStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/ReturnStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/ReturnStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SetStatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/SetStatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/SetStatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/SetStatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/StatementParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/StatementParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/StatementParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/StringLiteralExpressionParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/StringLiteralExpressionParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/StringLiteralExpressionParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/StringLiteralExpressionParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/SyntaxTriviaListParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaListParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/SyntaxTriviaListParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/SyntaxTriviaParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/SyntaxTriviaParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/SyntaxTriviaParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/TopLevelDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/TopLevelDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/TopLevelDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/TopLevelDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/TypeDeclarationParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/TypeDeclarationParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/TypeDeclarationParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/TypeDeclarationParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/TypeParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/TypeParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/TypeParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/TypeParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/UnaryOperatorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/UnaryOperatorParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/UnaryOperatorParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/UnaryOperatorParser.cs diff --git a/src/War3Net.CodeAnalysis.Jass/JassParser/VariableOrArrayDeclaratorParser.cs b/src/War3Net.CodeAnalysis.Jass/Parser/VariableOrArrayDeclaratorParser.cs similarity index 100% rename from src/War3Net.CodeAnalysis.Jass/JassParser/VariableOrArrayDeclaratorParser.cs rename to src/War3Net.CodeAnalysis.Jass/Parser/VariableOrArrayDeclaratorParser.cs From d323fa61669943d2a277bed6796ffd4257f5238d Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:29:43 +0100 Subject: [PATCH 52/53] Document the most important changes in the changelogs for War3Net.Build(.Core) and War3Net.CodeAnalysis.Jass. --- docs/changelogs/War3Net.Build.Core.changelog.md | 6 ++++++ docs/changelogs/War3Net.Build.changelog.md | 6 ++++++ docs/changelogs/War3Net.CodeAnalysis.Jass.changelog.md | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 docs/changelogs/War3Net.CodeAnalysis.Jass.changelog.md diff --git a/docs/changelogs/War3Net.Build.Core.changelog.md b/docs/changelogs/War3Net.Build.Core.changelog.md index 806477fd..2d53792f 100644 --- a/docs/changelogs/War3Net.Build.Core.changelog.md +++ b/docs/changelogs/War3Net.Build.Core.changelog.md @@ -1,5 +1,11 @@ # War3Net.Build.Core Changelog +## v6.0.0 +### Changes +- Added W3MathF class. +### Bugfixes +- Fixed exception when deserializing MapInfo.EditorVersion as JSON string. + ## v1.5.3 ### Changes - Add UseNewFormat property to MapCustomTextTriggers. diff --git a/docs/changelogs/War3Net.Build.changelog.md b/docs/changelogs/War3Net.Build.changelog.md index 00a17935..41114da2 100644 --- a/docs/changelogs/War3Net.Build.changelog.md +++ b/docs/changelogs/War3Net.Build.changelog.md @@ -1,5 +1,11 @@ # War3Net.Build Changelog +## v6.0.0 +### Breaking changes +- MapScriptBuilder methods now write to an IndentedTextWriter instead of returning a syntax class. +- TriggerRenderer and TriggerRendererContext now expect an IndentedTextWriter instead of JassRenderer/TextWriter. +- MapScriptBuilder's C# api methods have been removed, you can now use the GenerateGlobals methods and manually transpile to C#. + ## v1.5.0 ### Changes - Support parsing and serializing .wtg files. diff --git a/docs/changelogs/War3Net.CodeAnalysis.Jass.changelog.md b/docs/changelogs/War3Net.CodeAnalysis.Jass.changelog.md new file mode 100644 index 00000000..cc5b44cd --- /dev/null +++ b/docs/changelogs/War3Net.CodeAnalysis.Jass.changelog.md @@ -0,0 +1,5 @@ +# War3Net.CodeAnalysis.Jass Changelog + +## v6.0.0 +### Breaking changes +- Breaking changes have been documented in [the migration guide](../guides/jass-migration-guide-v5-to-v6.md) From 79cedf78f5c05a79590c537d2254e78fc2a53f2e Mon Sep 17 00:00:00 2001 From: Drake53 <49623303+Drake53@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:34:19 +0100 Subject: [PATCH 53/53] Document additional breaking changes. --- docs/changelogs/War3Net.Build.Core.changelog.md | 2 ++ docs/changelogs/War3Net.Build.changelog.md | 2 +- docs/guides/jass-migration-guide-v5-to-v6.md | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/changelogs/War3Net.Build.Core.changelog.md b/docs/changelogs/War3Net.Build.Core.changelog.md index 2d53792f..95d5542a 100644 --- a/docs/changelogs/War3Net.Build.Core.changelog.md +++ b/docs/changelogs/War3Net.Build.Core.changelog.md @@ -1,6 +1,8 @@ # War3Net.Build.Core Changelog ## v6.0.0 +### Breaking changes +- The EscapedStringProvider class has been moved to War3Net.CodeAnalysis.Jass. ### Changes - Added W3MathF class. ### Bugfixes diff --git a/docs/changelogs/War3Net.Build.changelog.md b/docs/changelogs/War3Net.Build.changelog.md index 41114da2..017ed5dd 100644 --- a/docs/changelogs/War3Net.Build.changelog.md +++ b/docs/changelogs/War3Net.Build.changelog.md @@ -2,7 +2,7 @@ ## v6.0.0 ### Breaking changes -- MapScriptBuilder methods now write to an IndentedTextWriter instead of returning a syntax class. +- MapScriptBuilder methods have been renamed and now write to an IndentedTextWriter instead of returning a syntax class. - TriggerRenderer and TriggerRendererContext now expect an IndentedTextWriter instead of JassRenderer/TextWriter. - MapScriptBuilder's C# api methods have been removed, you can now use the GenerateGlobals methods and manually transpile to C#. diff --git a/docs/guides/jass-migration-guide-v5-to-v6.md b/docs/guides/jass-migration-guide-v5-to-v6.md index 231d8cca..aa854aa5 100644 --- a/docs/guides/jass-migration-guide-v5-to-v6.md +++ b/docs/guides/jass-migration-guide-v5-to-v6.md @@ -225,5 +225,7 @@ Other replacements: - Properties that used to be of type `JassParameterListSyntax` are now `JassParameterListOrEmptyParameterListSyntax` - The constructor of syntax node classes is now internal - Properties have been changed from `{ get; init; }` to `{ get; }` +- `JassSymbol` now contains both `char` and `string` constants, existing `char` constants got the `Char` suffix +- `JassSyntaxFacts.IsWhitespaceCharacter(char)` now only considers spaces and tabs to be whitespace (previously used `char.IsWhitespace` and excluded \r and \n)