From 40510439464d7b1730ff143dd7b1eeff0626f329 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Sat, 18 May 2024 14:47:45 +0100 Subject: [PATCH] Refactor some parts of the generator code (#73) * Create MemberAccessExprSyntax helper to simplify chained member access * Improve EnumCaseElementSyntax with helper * misc refactor * Add SwitchCaseSyntax helper * Introduce a factory concept --- .../StringInterpolationProtocolFactory.swift | 104 +++ Sources/StringGenerator/StringGenerator.swift | 721 ++++++------------ .../SwiftSyntax/EnumCaseElementSyntax.swift | 18 + .../SwiftSyntax/MemberAccessExprSyntax.swift | 35 + .../SwiftSyntax/SwitchCaseSyntax.swift | 20 + 5 files changed, 409 insertions(+), 489 deletions(-) create mode 100644 Sources/StringGenerator/Factories/StringInterpolationProtocolFactory.swift create mode 100644 Sources/StringGenerator/SwiftSyntax/EnumCaseElementSyntax.swift create mode 100644 Sources/StringGenerator/SwiftSyntax/MemberAccessExprSyntax.swift create mode 100644 Sources/StringGenerator/SwiftSyntax/SwitchCaseSyntax.swift diff --git a/Sources/StringGenerator/Factories/StringInterpolationProtocolFactory.swift b/Sources/StringGenerator/Factories/StringInterpolationProtocolFactory.swift new file mode 100644 index 0000000..a275a64 --- /dev/null +++ b/Sources/StringGenerator/Factories/StringInterpolationProtocolFactory.swift @@ -0,0 +1,104 @@ +import SwiftSyntax +import SwiftSyntaxBuilder + +enum StringInterpolationProtocolFactory { + static func initializedVariable( + named variableName: TokenSyntax, + type: MemberAccessExprSyntax, + literalCapacity: some ExprSyntaxProtocol, + interpolationCount: some ExprSyntaxProtocol + ) -> VariableDeclSyntax { + VariableDeclSyntax(bindingSpecifier: .keyword(.var)) { + PatternBindingSyntax( + pattern: IdentifierPatternSyntax(identifier: variableName), + initializer: InitializerClauseSyntax( + value: FunctionCallExprSyntax( + callee: type + ) { + // literalCapacity: {something} + LabeledExprSyntax( + label: "literalCapacity", + expression: literalCapacity + ) + // interpolationCount: {something} + LabeledExprSyntax( + label: "interpolationCount", + expression: interpolationCount + ) + } + ) + ) + } + } + + static func appendFormatSpecifiableInterpolations( + fromArguments sequenceName: TokenSyntax, + intoVariable variableName: TokenSyntax + ) -> ForStmtSyntax { + ForStmtSyntax( + pattern: IdentifierPatternSyntax(identifier: "argument"), + sequence: DeclReferenceExprSyntax(baseName: sequenceName), + body: CodeBlockSyntax { + // switch argument { ... } + SwitchExprSyntax(subject: DeclReferenceExprSyntax(baseName: "argument")) { + // case object(let object): + // stringInterpolation.appendInterpolation(string) + for placeholder in String.LocalizationValue.Placeholder.allCases { + // case object(let value): + SwitchCaseSyntax( + singleCasePattern: ExpressionPatternSyntax( + expression: FunctionCallExprSyntax( + callee: MemberAccessExprSyntax(name: placeholder.caseName) + ) { + LabeledExprSyntax( + expression: PatternExprSyntax( + pattern: ValueBindingPatternSyntax( + bindingSpecifier: .keyword(.let), + pattern: IdentifierPatternSyntax( + identifier: "value" + ) + ) + ) + ) + } + ) + ) { + // stringInterpolation.appendInterpolation(value) + FunctionCallExprSyntax( + callee: MemberAccessExprSyntax(variableName, "appendInterpolation") + ) { + LabeledExprSyntax(expression: DeclReferenceExprSyntax(baseName: "value")) + } + } + } + } + } + ) + } + + // let {variableName} = {type}.init(stringInterpolation:) + static func initializerClosure( + bindingSpecifier: Keyword = .let, + named variableName: TokenSyntax, + type: MemberAccessExprSyntax + ) -> VariableDeclSyntax { + VariableDeclSyntax(bindingSpecifier: .keyword(bindingSpecifier)) { + PatternBindingSyntax( + pattern: IdentifierPatternSyntax(identifier: variableName), + initializer: InitializerClauseSyntax( + value: MemberAccessExprSyntax( + base: type, + declName: DeclReferenceExprSyntax( + baseName: .keyword(.`init`), + argumentNames: DeclNameArgumentsSyntax( + arguments: DeclNameArgumentListSyntax { + DeclNameArgumentSyntax(name: "stringInterpolation") + } + ) + ) + ) + ) + ) + } + } +} diff --git a/Sources/StringGenerator/StringGenerator.swift b/Sources/StringGenerator/StringGenerator.swift index be9d294..4baa52e 100644 --- a/Sources/StringGenerator/StringGenerator.swift +++ b/Sources/StringGenerator/StringGenerator.swift @@ -68,101 +68,70 @@ public struct StringGenerator { ], name: structToken ) { - // BundleDescription - EnumDeclSyntax( - name: .type(.BundleDescription), - memberBlockBuilder: { - EnumCaseDeclSyntax { - EnumCaseElementSyntax(name: .identifier("main")) - } - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("atURL"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "URL" - ] - ) - ) - } - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("forClass"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "AnyClass" - ] - ) - ) - } + // enum BundleDescription { ... } + EnumDeclSyntax(name: .type(.BundleDescription)) { + // case main + EnumCaseDeclSyntax { + EnumCaseElementSyntax(name: "main") } - ) + // case atURL(URL) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "atURL", + parameters: "URL" + ) + } + // case forClass(AnyClass) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "forClass", + parameters: "AnyClass" + ) + } + } .with(\.trailingTrivia, .newlines(2)) - // Argument - EnumDeclSyntax( - name: .type(.Argument), - memberBlockBuilder: { - // case object(String) - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("object"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "String" - ] - ) - ) - } - // case int(Int) - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("int"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "Int" - ] - ) - ) - } - // case uint(UInt) - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("uint"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "UInt" - ] - ) - ) - } - // case double(Double) - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("double"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "Double" - ] - ) - ) - } - // case float(Float) - EnumCaseDeclSyntax { - EnumCaseElementSyntax( - name: .identifier("float"), - parameterClause: EnumCaseParameterClauseSyntax( - parameters: [ - "Float" - ] - ) - ) - } + // enum Argument { ... } + EnumDeclSyntax(name: .type(.Argument)) { + // case object(String) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "object", + parameters: "String" + ) } - ) + // case int(Int) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "int", + parameters: "Int" + ) + } + // case uint(UInt) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "uint", + parameters: "UInt" + ) + } + // case double(Double) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "double", + parameters: "Double" + ) + } + // case float(Float) + EnumCaseDeclSyntax { + EnumCaseElementSyntax( + name: "float", + parameters: "Float" + ) + } + } .with(\.trailingTrivia, .newlines(2)) - // Properties + // let key: StaticString VariableDeclSyntax( .let, name: PatternSyntax(IdentifierPatternSyntax(identifier: "key")), @@ -170,6 +139,7 @@ public struct StringGenerator { type: .identifier(.StaticString) ) ) + // let arguments: [Argument] VariableDeclSyntax( .let, name: PatternSyntax(IdentifierPatternSyntax(identifier: "arguments")), @@ -177,6 +147,7 @@ public struct StringGenerator { type: ArrayTypeSyntax(element: .identifier(.Argument)) ) ) + // let table: String? VariableDeclSyntax( .let, name: PatternSyntax(IdentifierPatternSyntax(identifier: "table")), @@ -184,13 +155,14 @@ public struct StringGenerator { type: OptionalTypeSyntax(wrappedType: .identifier(.String)) ) ) + // let bundle: BundleDescription VariableDeclSyntax( .let, name: PatternSyntax(IdentifierPatternSyntax(identifier: "bundle")), type: TypeAnnotationSyntax(type: .identifier(.BundleDescription)) ).with(\.trailingTrivia, .newlines(2)) - // Init + // fileprivate init(key:arguments:table:bundle:) InitializerDeclSyntax( modifiers: [ DeclModifierSyntax(name: .keyword(.fileprivate)), @@ -217,35 +189,27 @@ public struct StringGenerator { ) .multiline() ) { + // self.key = key InfixOperatorExprSyntax( - leftOperand: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .keyword(.`self`)), - name: "key" - ), + leftOperand: MemberAccessExprSyntax(.keyword(.`self`), "key"), operator: AssignmentExprSyntax(), rightOperand: DeclReferenceExprSyntax(baseName: "key") ) + // self.arguments = arguments InfixOperatorExprSyntax( - leftOperand: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .keyword(.`self`)), - name: "arguments" - ), + leftOperand: MemberAccessExprSyntax(.keyword(.`self`), "arguments"), operator: AssignmentExprSyntax(), rightOperand: DeclReferenceExprSyntax(baseName: "arguments") ) + // self.table = table InfixOperatorExprSyntax( - leftOperand: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .keyword(.`self`)), - name: "table" - ), + leftOperand: MemberAccessExprSyntax(.keyword(.`self`), "table"), operator: AssignmentExprSyntax(), rightOperand: DeclReferenceExprSyntax(baseName: "table") ) + // self.bundle = bundle InfixOperatorExprSyntax( - leftOperand: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .keyword(.`self`)), - name: "bundle" - ), + leftOperand: MemberAccessExprSyntax(.keyword(.`self`), "bundle"), operator: AssignmentExprSyntax(), rightOperand: DeclReferenceExprSyntax(baseName: "bundle") ) @@ -286,10 +250,7 @@ public struct StringGenerator { ) { LabeledExprSyntax( label: "description", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - name: "bundle" - ) + expression: MemberAccessExprSyntax(variableToken, "bundle") ) }, operator: BinaryOperatorExprSyntax(operator: .binaryOperator("??")), @@ -308,10 +269,7 @@ public struct StringGenerator { ) { LabeledExprSyntax( label: "describing", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - name: "key" - ) + expression: MemberAccessExprSyntax(variableToken, "key") ) } ) @@ -328,10 +286,7 @@ public struct StringGenerator { LabeledExprSyntax( label: "format", expression: FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: "bundle"), - name: "localizedString" - ) + callee: MemberAccessExprSyntax("bundle", "localizedString") ) { // forKey: key, LabeledExprSyntax( @@ -346,10 +301,7 @@ public struct StringGenerator { // table: localizable.table LabeledExprSyntax( label: "table", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - name: "table" - ) + expression: MemberAccessExprSyntax(variableToken, "table") ) } ) @@ -362,13 +314,7 @@ public struct StringGenerator { LabeledExprSyntax( label: "arguments", expression: FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - base: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - declName: DeclReferenceExprSyntax(baseName: "arguments") - ), - declName: DeclReferenceExprSyntax(baseName: "map") - ) + callee: MemberAccessExprSyntax(variableToken, "arguments", "map") ) { LabeledExprSyntax( expression: KeyPathExprSyntax( @@ -425,117 +371,29 @@ public struct StringGenerator { ), accessorBlock: AccessorBlockSyntax( accessors: .getter(CodeBlockItemListSyntax { - // var interpolation = String.LocalizationValue.StringInterpolation(literalCapacity: 0, interpolationCount: arguments.count) - VariableDeclSyntax(bindingSpecifier: .keyword(.var)) { - PatternBindingSyntax( - pattern: IdentifierPatternSyntax(identifier: .identifier("stringInterpolation")), - initializer: InitializerClauseSyntax( - value: FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - base: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .type(.String)), - declName: DeclReferenceExprSyntax(baseName: .type(.LocalizationValue)) - ), - declName: DeclReferenceExprSyntax(baseName: .type(.StringInterpolation)) - ) - ) { - // literalCapacity: 0 - LabeledExprSyntax( - label: "literalCapacity", - expression: IntegerLiteralExprSyntax(0) - ) - // interpolationCount: arguments.count - LabeledExprSyntax( - label: "interpolationCount", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: "arguments"), - declName: DeclReferenceExprSyntax(baseName: "count") - ) - ) - } - ) - ) - } + // var stringInterpolation = String.LocalizationValue.StringInterpolation(literalCapacity: 0, interpolationCount: arguments.count) + StringInterpolationProtocolFactory.initializedVariable( + named: "stringInterpolation", + type: MemberAccessExprSyntax( + .type(.String), .type(.LocalizationValue), .type(.StringInterpolation) + ), + literalCapacity: IntegerLiteralExprSyntax(0), + interpolationCount: MemberAccessExprSyntax("arguments", "count") + ) // for argument in arguments { ... } - ForStmtSyntax( - pattern: IdentifierPatternSyntax(identifier: "argument"), - sequence: DeclReferenceExprSyntax(baseName: "arguments"), - body: CodeBlockSyntax { - // switch argument { ... } - SwitchExprSyntax(subject: DeclReferenceExprSyntax(baseName: "argument")) { - // case object(let object): - // stringInterpolation.appendInterpolation(string) - for placeholder in String.LocalizationValue.Placeholder.allCases { - SwitchCaseSyntax( - // case object(let value): - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: placeholder.caseName) - ) - ) { - LabeledExprSyntax( - expression: PatternExprSyntax( - pattern: ValueBindingPatternSyntax( - bindingSpecifier: .keyword(.let), - pattern: IdentifierPatternSyntax( - identifier: "value" - ) - ) - ) - ) - } - ) - ) - } - ) - ), - // stringInterpolation.appendInterpolation(value) - statements: CodeBlockItemListSyntax { - FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: "stringInterpolation"), - name: "appendInterpolation" - ) - ) { - LabeledExprSyntax( - expression: DeclReferenceExprSyntax(baseName: "value") - ) - } - } - ) - } - } - } + StringInterpolationProtocolFactory.appendFormatSpecifiableInterpolations( + fromArguments: "arguments", + intoVariable: "stringInterpolation" ) // let makeDefaultValue = String.LocalizationValue.init(stringInterpolation:) - VariableDeclSyntax(bindingSpecifier: .keyword(.let)) { - PatternBindingSyntax( - pattern: IdentifierPatternSyntax(identifier: "makeDefaultValue"), - initializer: InitializerClauseSyntax( - value: MemberAccessExprSyntax( - base: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .type(.String)), - declName: DeclReferenceExprSyntax(baseName: .type(.LocalizationValue)) - ), - declName: DeclReferenceExprSyntax( - baseName: .keyword(.`init`), - argumentNames: DeclNameArgumentsSyntax( - arguments: DeclNameArgumentListSyntax { - DeclNameArgumentSyntax(name: "stringInterpolation") - } - ) - ) - ) - ) + StringInterpolationProtocolFactory.initializerClosure( + named: "makeDefaultValue", + type: MemberAccessExprSyntax( + .type(.String), .type(.LocalizationValue) ) - } + ) // return makeDefaultValue(stringInterpolation) ReturnStmtSyntax( @@ -567,7 +425,7 @@ public struct StringGenerator { PatternBindingSyntax( pattern: IdentifierPatternSyntax(identifier: .identifier("value")), typeAnnotation: TypeAnnotationSyntax( - type: IdentifierTypeSyntax(name: .type(.CVarArg)) + type: .identifier(.CVarArg) ), accessorBlock: AccessorBlockSyntax( accessors: .getter(CodeBlockItemListSyntax { @@ -576,39 +434,28 @@ public struct StringGenerator { // case object(let value): // value for placeholder in String.LocalizationValue.Placeholder.allCases { + // case object(let value): SwitchCaseSyntax( - // case object(let value): - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: placeholder.caseName) - ) - ) { - LabeledExprSyntax( - expression: PatternExprSyntax( - pattern: ValueBindingPatternSyntax( - bindingSpecifier: .keyword(.let), - pattern: IdentifierPatternSyntax( - identifier: "value" - ) - ) - ) - ) - } + singleCasePattern: ExpressionPatternSyntax( + expression: FunctionCallExprSyntax( + callee: MemberAccessExprSyntax(name: placeholder.caseName) + ) { + LabeledExprSyntax( + expression: PatternExprSyntax( + pattern: ValueBindingPatternSyntax( + bindingSpecifier: .keyword(.let), + pattern: IdentifierPatternSyntax( + identifier: "value" + ) ) ) - } - ) - ), + ) + } + ) + ) { // value - statements: CodeBlockItemListSyntax { - DeclReferenceExprSyntax(baseName: "value") - } - ) + DeclReferenceExprSyntax(baseName: "value") + } } } }) @@ -694,125 +541,89 @@ public struct StringGenerator { ) { // case .main: SwitchCaseSyntax( - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "main") - ) - ) - ) - } - ) - ), - statements: CodeBlockItemListSyntax { - // Bundle.main - MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .type(.Bundle)), - name: "main" - ) - } - ) + singleCasePattern: ExpressionPatternSyntax( + expression: MemberAccessExprSyntax(name: "main") + ) + ) { + // Bundle.main + MemberAccessExprSyntax(.type(.Bundle), "main") + } // case .atURL(let url): SwitchCaseSyntax( - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "atURL") - ), - leftParen: .leftParenToken(), - rightParen: .rightParenToken() - ) { - LabeledExprSyntax( - expression: PatternExprSyntax( - pattern: ValueBindingPatternSyntax( - bindingSpecifier: .keyword(.let), - pattern: IdentifierPatternSyntax( - identifier: "url" - ) - ) - ) - ) - } - ) - ) - } - ) - ), - statements: CodeBlockItemListSyntax { - // Bundle(url: url) - FunctionCallExprSyntax( - calledExpression: DeclReferenceExprSyntax( - baseName: .type(.Bundle) - ), + singleCasePattern: ExpressionPatternSyntax( + expression: FunctionCallExprSyntax( + calledExpression: MemberAccessExprSyntax(name: "atURL"), leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { LabeledExprSyntax( - label: "url", - expression: DeclReferenceExprSyntax( - baseName: "url" + expression: PatternExprSyntax( + pattern: ValueBindingPatternSyntax( + bindingSpecifier: .keyword(.let), + pattern: IdentifierPatternSyntax( + identifier: "url" + ) + ) ) ) } + ) + ) { + // Bundle(url: url) + FunctionCallExprSyntax( + calledExpression: DeclReferenceExprSyntax( + baseName: .type(.Bundle) + ), + leftParen: .leftParenToken(), + rightParen: .rightParenToken() + ) { + LabeledExprSyntax( + label: "url", + expression: DeclReferenceExprSyntax( + baseName: "url" + ) + ) } - ) + } // case .forClass(let anyClass): SwitchCaseSyntax( - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "forClass") - ), - leftParen: .leftParenToken(), - rightParen: .rightParenToken() - ) { - LabeledExprSyntax( - expression: PatternExprSyntax( - pattern: ValueBindingPatternSyntax( - bindingSpecifier: .keyword(.let), - pattern: IdentifierPatternSyntax( - identifier: "anyClass" - ) - ) - ) - ) - } - ) - ) - } - ) - ), - statements: CodeBlockItemListSyntax { - // Bundle(for: anyClass) - FunctionCallExprSyntax( - calledExpression: DeclReferenceExprSyntax( - baseName: .type(.Bundle) - ), + singleCasePattern: ExpressionPatternSyntax( + expression: FunctionCallExprSyntax( + calledExpression: MemberAccessExprSyntax(name: "forClass"), leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { LabeledExprSyntax( - label: "for", - expression: DeclReferenceExprSyntax( - baseName: "anyClass" + expression: PatternExprSyntax( + pattern: ValueBindingPatternSyntax( + bindingSpecifier: .keyword(.let), + pattern: IdentifierPatternSyntax( + identifier: "anyClass" + ) + ) ) ) } + ) + ) { + // Bundle(for: anyClass) + FunctionCallExprSyntax( + calledExpression: DeclReferenceExprSyntax( + baseName: .type(.Bundle) + ), + leftParen: .leftParenToken(), + rightParen: .rightParenToken() + ) { + LabeledExprSyntax( + label: "for", + expression: DeclReferenceExprSyntax( + baseName: "anyClass" + ) + ) } - ) + } } } } @@ -847,126 +658,79 @@ public struct StringGenerator { ) { // case .main: SwitchCaseSyntax( - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "main") - ) - ) - ) - } - ) - ), - statements: CodeBlockItemListSyntax { - // .main - MemberAccessExprSyntax( - name: "main" - ) - } - ) + singleCasePattern: ExpressionPatternSyntax( + expression: MemberAccessExprSyntax(name: "main") + ) + ) { + // .main + MemberAccessExprSyntax(name: "main") + } // case .atURL(let url): SwitchCaseSyntax( - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "atURL") - ), - leftParen: .leftParenToken(), - rightParen: .rightParenToken() - ) { - LabeledExprSyntax( - expression: PatternExprSyntax( - pattern: ValueBindingPatternSyntax( - bindingSpecifier: .keyword(.let), - pattern: IdentifierPatternSyntax( - identifier: "url" - ) - ) - ) - ) - } - ) - ) - } - ) - ), - statements: CodeBlockItemListSyntax { - // .atURL(url) - FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax( - baseName: "atURL" - ) - ), + singleCasePattern: ExpressionPatternSyntax( + expression: FunctionCallExprSyntax( + calledExpression: MemberAccessExprSyntax(name: "atURL"), leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { LabeledExprSyntax( - expression: DeclReferenceExprSyntax( - baseName: "url" + expression: PatternExprSyntax( + pattern: ValueBindingPatternSyntax( + bindingSpecifier: .keyword(.let), + pattern: IdentifierPatternSyntax( + identifier: "url" + ) + ) ) ) } + ) + ) { + // .atURL(url) + FunctionCallExprSyntax( + calledExpression: MemberAccessExprSyntax(name: "atURL"), + leftParen: .leftParenToken(), + rightParen: .rightParenToken() + ) { + LabeledExprSyntax( + expression: DeclReferenceExprSyntax(baseName: "url") + ) } - ) + } // case .forClass(let anyClass): SwitchCaseSyntax( - label: .case( - SwitchCaseLabelSyntax( - caseItems: SwitchCaseItemListSyntax { - SwitchCaseItemSyntax( - pattern: ExpressionPatternSyntax( - expression: FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "forClass") - ), - leftParen: .leftParenToken(), - rightParen: .rightParenToken() - ) { - LabeledExprSyntax( - expression: PatternExprSyntax( - pattern: ValueBindingPatternSyntax( - bindingSpecifier: .keyword(.let), - pattern: IdentifierPatternSyntax( - identifier: "anyClass" - ) - ) - ) - ) - } - ) - ) - } - ) - ), - statements: CodeBlockItemListSyntax { - // .forClass(anyClass) - FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax( - baseName: "forClass" - ) - ), + singleCasePattern: ExpressionPatternSyntax( + expression: FunctionCallExprSyntax( + calledExpression: MemberAccessExprSyntax(name: "forClass"), leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { LabeledExprSyntax( - expression: DeclReferenceExprSyntax( - baseName: "anyClass" + expression: PatternExprSyntax( + pattern: ValueBindingPatternSyntax( + bindingSpecifier: .keyword(.let), + pattern: IdentifierPatternSyntax( + identifier: "anyClass" + ) + ) ) ) } + ) + ) { + // .forClass(anyClass) + FunctionCallExprSyntax( + calledExpression: MemberAccessExprSyntax(name: "forClass"), + leftParen: .leftParenToken(), + rightParen: .rightParenToken() + ) { + LabeledExprSyntax( + expression: DeclReferenceExprSyntax(baseName: "anyClass") + ) } - ) + } } } } @@ -1015,50 +779,33 @@ public struct StringGenerator { ) ) { FunctionCallExprSyntax( - callee: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: .keyword(.`self`)), - name: .keyword(.`init`) - ) + callee: MemberAccessExprSyntax(.keyword(.`self`), .keyword(.`init`)) ) { // localizable.key, LabeledExprSyntax( - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - declName: DeclReferenceExprSyntax(baseName: "key") - ) + expression: MemberAccessExprSyntax(variableToken, "key") ) // defaultValue: localizable.defaultValue, LabeledExprSyntax( label: "defaultValue", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - declName: DeclReferenceExprSyntax(baseName: "defaultValue") - ) + expression: MemberAccessExprSyntax(variableToken, "defaultValue") ) // table: localizable.table, LabeledExprSyntax( label: "table", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - declName: DeclReferenceExprSyntax(baseName: "table") - ) + expression: MemberAccessExprSyntax(variableToken, "table") ) // bundle: .from(description: localizable.bundle) LabeledExprSyntax( label: "bundle", expression: FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: "from") - ), + calledExpression: MemberAccessExprSyntax(name: "from"), leftParen: .leftParenToken(), rightParen: .rightParenToken() ) { LabeledExprSyntax( label: "description", - expression: MemberAccessExprSyntax( - base: DeclReferenceExprSyntax(baseName: variableToken), - declName: DeclReferenceExprSyntax(baseName: "bundle") - ) + expression: MemberAccessExprSyntax(variableToken, "bundle") ) } ) @@ -1285,9 +1032,7 @@ extension Resource { ) LabeledExprSyntax( label: "bundle", - expression: MemberAccessExprSyntax( - name: .identifier("current") - ) + expression: MemberAccessExprSyntax(name: "current") ) } .multiline() @@ -1300,9 +1045,7 @@ extension Resource { LabeledExprSyntax( label: variableToken.text, expression: FunctionCallExprSyntax( - calledExpression: MemberAccessExprSyntax( - declName: DeclReferenceExprSyntax(baseName: name) - ), + calledExpression: MemberAccessExprSyntax(name: name), leftParen: arguments.isEmpty ? nil : .leftParenToken(), rightParen: arguments.isEmpty ? nil : .rightParenToken() ) { @@ -1456,7 +1199,7 @@ extension Trivia { } } -private extension String.LocalizationValue.Placeholder { +extension String.LocalizationValue.Placeholder { var identifier: String { switch self { case .int: "Int" diff --git a/Sources/StringGenerator/SwiftSyntax/EnumCaseElementSyntax.swift b/Sources/StringGenerator/SwiftSyntax/EnumCaseElementSyntax.swift new file mode 100644 index 0000000..e3f05ea --- /dev/null +++ b/Sources/StringGenerator/SwiftSyntax/EnumCaseElementSyntax.swift @@ -0,0 +1,18 @@ +import SwiftSyntax +import SwiftSyntaxBuilder + +extension EnumCaseElementSyntax { + @_disfavoredOverload + init(name: TokenSyntax, parameters: EnumCaseParameterSyntax...) { + self.init( + name: name, + parameterClause: EnumCaseParameterClauseSyntax( + parameters: EnumCaseParameterListSyntax { + for parameter in parameters { + parameter + } + } + ) + ) + } +} diff --git a/Sources/StringGenerator/SwiftSyntax/MemberAccessExprSyntax.swift b/Sources/StringGenerator/SwiftSyntax/MemberAccessExprSyntax.swift new file mode 100644 index 0000000..434c318 --- /dev/null +++ b/Sources/StringGenerator/SwiftSyntax/MemberAccessExprSyntax.swift @@ -0,0 +1,35 @@ +import SwiftSyntax + +extension MemberAccessExprSyntax { + init(_ firstIdentifier: TokenSyntax, _ otherIdentifiers: TokenSyntax...) { + var identifiers = [firstIdentifier] + otherIdentifiers + precondition(identifiers.count >= 2) + + self.init( + declName: DeclReferenceExprSyntax(baseName: identifiers.removeLast()), + identifiers: identifiers + ) + } + + private init(declName: DeclReferenceExprSyntax, identifiers: [TokenSyntax]) { + var identifiers = identifiers + + switch identifiers.count { + case 0: + preconditionFailure() + case 1: + self.init( + base: DeclReferenceExprSyntax(baseName: identifiers.removeLast()), + declName: declName + ) + default: + self.init( + base: MemberAccessExprSyntax( + declName: DeclReferenceExprSyntax(baseName: identifiers.removeLast()), + identifiers: identifiers + ), + declName: declName + ) + } + } +} diff --git a/Sources/StringGenerator/SwiftSyntax/SwitchCaseSyntax.swift b/Sources/StringGenerator/SwiftSyntax/SwitchCaseSyntax.swift new file mode 100644 index 0000000..07892dd --- /dev/null +++ b/Sources/StringGenerator/SwiftSyntax/SwitchCaseSyntax.swift @@ -0,0 +1,20 @@ +import SwiftSyntax +import SwiftSyntaxBuilder + +extension SwitchCaseSyntax { + init( + singleCasePattern: ExpressionPatternSyntax, + @CodeBlockItemListBuilder statementsBuilder: () -> CodeBlockItemListSyntax + ) { + self.init( + label: .case( + SwitchCaseLabelSyntax { + SwitchCaseItemSyntax( + pattern: singleCasePattern + ) + } + ), + statements: statementsBuilder() + ) + } +}