@@ -30,25 +30,49 @@ extension HTMLKitUtilities {
3030 //context.diagnose(Diagnostic(node: expression, message: DiagnosticMsg(id: "somethingWentWrong", message: "Something went wrong. (" + expression.debugDescription + ")", severity: .warning)))
3131 return nil
3232 }
33- var string : String = " "
34- switch returnType {
35- case . interpolation( let s) : string = s
36- default : return returnType
37- }
38- var remaining_interpolation : Int = returnType. isInterpolation ? 1 : 0 , interpolation : [ ExpressionSegmentSyntax ] = [ ]
33+ guard returnType. isInterpolation else { return returnType }
34+ var remaining_interpolation : Int = 1
35+ var string : String
3936 if let stringLiteral: StringLiteralExprSyntax = expression. stringLiteral {
40- remaining_interpolation = stringLiteral. segments. count ( where: { $0. is ( ExpressionSegmentSyntax . self) } )
41- interpolation = stringLiteral. segments. compactMap ( { $0. as ( ExpressionSegmentSyntax . self) } )
42- }
43- for expr in interpolation {
44- string. replace ( " \( expr) " , with: promoteInterpolation ( context: context, remaining_interpolation: & remaining_interpolation, expr: expr, lookupFiles: lookupFiles) )
45- }
46- if remaining_interpolation > 0 {
47- warn_interpolation ( context: context, node: expression, string: & string, remaining_interpolation: & remaining_interpolation, lookupFiles: lookupFiles)
48- if remaining_interpolation > 0 && !string. contains ( " \\ ( " ) {
49- string = " \\ ( " + string + " ) "
37+ remaining_interpolation = 0
38+ var interpolation : [ ExpressionSegmentSyntax ] = [ ]
39+ var segments : [ any ( SyntaxProtocol & SyntaxHashable ) ] = [ ]
40+ for segment in stringLiteral. segments {
41+ segments. append ( segment)
42+ if let expression: ExpressionSegmentSyntax = segment. as ( ExpressionSegmentSyntax . self) {
43+ interpolation. append ( expression)
44+ }
45+ remaining_interpolation += segment. is ( StringSegmentSyntax . self) ? 0 : 1
46+ }
47+ var minimum : Int = 0
48+ for expr in interpolation {
49+ let promotions : [ any ( SyntaxProtocol & SyntaxHashable ) ] = promoteInterpolation ( context: context, remaining_interpolation: & remaining_interpolation, expr: expr, lookupFiles: lookupFiles)
50+ for (i, segment) in segments. enumerated ( ) {
51+ if i >= minimum && segment. as ( ExpressionSegmentSyntax . self) == expr {
52+ segments. remove ( at: i)
53+ segments. insert ( contentsOf: promotions, at: i)
54+ minimum += promotions. count
55+ break
56+ }
57+ }
58+ }
59+ string = segments. map ( { " \( $0) " } ) . joined ( )
60+ } else {
61+ warn_interpolation ( context: context, node: expression)
62+ var expression_string : String = " \( expression) "
63+ while expression_string. first? . isWhitespace ?? false {
64+ expression_string. removeFirst ( )
65+ }
66+ while expression_string. last? . isWhitespace ?? false {
67+ expression_string. removeLast ( )
68+ }
69+ if let member: MemberAccessExprSyntax = expression. memberAccess {
70+ string = " \\ ( " + member. singleLineDescription + " ) "
71+ } else {
72+ string = " \" + String(describing: " + expression_string + " ) + \" "
5073 }
5174 }
75+ // TODO: promote interpolation via lookupFiles here (remove `warn_interpolation` above and from `promoteInterpolation`)
5276 if remaining_interpolation > 0 {
5377 returnType = . interpolation( string)
5478 } else {
@@ -62,47 +86,51 @@ extension HTMLKitUtilities {
6286 remaining_interpolation: inout Int ,
6387 expr: ExpressionSegmentSyntax ,
6488 lookupFiles: Set < String >
65- ) -> String {
66- var string : String = " \( expr) "
67- guard let expression: ExprSyntax = expr. expressions. first? . expression else { return string }
68- if let stringLiteral: StringLiteralExprSyntax = expression. stringLiteral {
69- let segments : StringLiteralSegmentListSyntax = stringLiteral. segments
70- if segments. count ( where: { $0. is ( StringSegmentSyntax . self) } ) == segments. count {
71- remaining_interpolation = 0
72- string = segments. map ( { $0. as ( StringSegmentSyntax . self) !. content. text } ) . joined ( )
73- } else {
74- string = " "
75- for segment in segments {
76- if let literal: String = segment. as ( StringSegmentSyntax . self) ? . content. text {
77- string += literal
78- } else if let interpolation: ExpressionSegmentSyntax = segment. as ( ExpressionSegmentSyntax . self) {
79- let promoted : String = promoteInterpolation ( context: context, remaining_interpolation: & remaining_interpolation, expr: interpolation, lookupFiles: lookupFiles)
80- if " \( interpolation) " == promoted {
81- //string += "\\(\"\(promoted)\".escapingHTML(escapeAttributes: true))"
82- string += " \( promoted) "
83- warn_interpolation ( context: context, node: interpolation, string: & string, remaining_interpolation: & remaining_interpolation, lookupFiles: lookupFiles)
89+ ) -> [ any ( SyntaxProtocol & SyntaxHashable ) ] {
90+ func create( _ string: String ) -> StringLiteralExprSyntax {
91+ var s : StringLiteralExprSyntax = StringLiteralExprSyntax ( content: string)
92+ s. openingQuote = TokenSyntax ( stringLiteral: " " )
93+ s. closingQuote = TokenSyntax ( stringLiteral: " " )
94+ return s
95+ }
96+ func interpolate( _ syntax: ExprSyntaxProtocol ) -> ExpressionSegmentSyntax {
97+ var list : LabeledExprListSyntax = LabeledExprListSyntax ( )
98+ list. append ( LabeledExprSyntax ( expression: syntax) )
99+ return ExpressionSegmentSyntax ( expressions: list)
100+ }
101+ var values : [ any ( SyntaxProtocol & SyntaxHashable ) ] = [ ]
102+ for element in expr. expressions {
103+ let expression : ExprSyntax = element. expression
104+ if let stringLiteral: StringLiteralExprSyntax = expression. stringLiteral {
105+ let segments : StringLiteralSegmentListSyntax = stringLiteral. segments
106+ if segments. count ( where: { $0. is ( StringSegmentSyntax . self) } ) == segments. count {
107+ remaining_interpolation -= 1
108+ values. append ( create ( stringLiteral. string) )
109+ } else {
110+ for segment in segments {
111+ if let literal: String = segment. as ( StringSegmentSyntax . self) ? . content. text {
112+ values. append ( create ( literal) )
113+ } else if let interpolation: ExpressionSegmentSyntax = segment. as ( ExpressionSegmentSyntax . self) {
114+ let promotions : [ any ( SyntaxProtocol & SyntaxHashable ) ] = promoteInterpolation ( context: context, remaining_interpolation: & remaining_interpolation, expr: interpolation, lookupFiles: lookupFiles)
115+ values. append ( contentsOf: promotions)
84116 } else {
85- string += promoted
117+ context. diagnose ( Diagnostic ( node: segment, message: DiagnosticMsg ( id: " somethingWentWrong " , message: " Something went wrong. ( " + expression. debugDescription + " ) " ) ) )
118+ return values
86119 }
87- } else {
88- //string += "\\(\"\(segment)\".escapingHTML(escapeAttributes: true))"
89- warn_interpolation ( context: context, node: segment, string: & string, remaining_interpolation: & remaining_interpolation, lookupFiles: lookupFiles)
90- string += " \( segment) "
91120 }
92121 }
122+ } else if let fix: String = expression. integerLiteral? . literal. text ?? expression. floatLiteral? . literal. text {
123+ remaining_interpolation -= 1
124+ values. append ( create ( fix) )
125+ } else {
126+ //if let decl:DeclReferenceExprSyntax = expression.declRef {
127+ // TODO: lookup and try to promote | need to wait for swift-syntax to update to access SwiftLexicalLookup
128+ //}
129+ values. append ( interpolate ( expression) )
130+ warn_interpolation ( context: context, node: expression)
93131 }
94- } else if let fix: String = expression. integerLiteral? . literal. text ?? expression. floatLiteral? . literal. text {
95- let target : String = " \( expr) "
96- remaining_interpolation -= string. ranges ( of: target) . count
97- string. replace ( target, with: fix)
98- } else {
99- //if let decl:DeclReferenceExprSyntax = expression.declRef {
100- // TODO: lookup and try to promote | need to wait for swift-syntax to update to access SwiftLexicalLookup
101- //}
102- //string = "\\(\"\(string)\".escapingHTML(escapeAttributes: true))"
103- warn_interpolation ( context: context, node: expr, string: & string, remaining_interpolation: & remaining_interpolation, lookupFiles: lookupFiles)
104132 }
105- return string
133+ return values
106134 }
107135 // MARK: Extract Literal
108136 static func extract_literal(
@@ -132,10 +160,10 @@ extension HTMLKitUtilities {
132160 break
133161 }
134162 }
135- return . interpolation( function. singleLineDescription )
163+ return . interpolation( " \( function) " )
136164 }
137165 if expression. memberAccess != nil || expression. is ( ForceUnwrapExprSyntax . self) {
138- return . interpolation( expression. singleLineDescription )
166+ return . interpolation( " \( expression) " )
139167 }
140168 if let array: ArrayExprSyntax = expression. array {
141169 let separator : String
@@ -167,18 +195,14 @@ extension HTMLKitUtilities {
167195 case . array( let a) : results. append ( a)
168196 case . boolean( let b) : results. append ( b)
169197 }
198+
170199 }
171200 }
172201 return . array( results)
173202 }
174203 if let decl: DeclReferenceExprSyntax = expression. declRef {
175- var string : String = decl. baseName. text, remaining_interpolation : Int = 1
176- warn_interpolation ( context: context, node: expression, string: & string, remaining_interpolation: & remaining_interpolation, lookupFiles: lookupFiles)
177- if remaining_interpolation > 0 {
178- return . interpolation( string)
179- } else {
180- return . string( string)
181- }
204+ warn_interpolation ( context: context, node: expression)
205+ return . interpolation( decl. baseName. text)
182206 }
183207 return nil
184208 }
@@ -231,4 +255,13 @@ public enum LiteralReturnType {
231255 return self
232256 }
233257 }
258+ }
259+
260+ // MARK: Misc
261+ extension MemberAccessExprSyntax {
262+ var singleLineDescription : String {
263+ var string : String = " \( self ) "
264+ string. removeAll { $0. isWhitespace }
265+ return string
266+ }
234267}
0 commit comments