77
88import SwiftSyntax
99import SwiftSyntaxMacros
10+ import SwiftDiagnostics
1011import HTMLKitUtilities
1112
1213struct HTMLElement : ExpressionMacro {
@@ -28,9 +29,14 @@ private extension HTMLElement {
2829 if let child: LabeledExprSyntax = element. as ( LabeledExprSyntax . self) {
2930 if var key: String = child. label? . text { // attributes
3031 if key == " data " {
31- let tuple : TupleExprSyntax = child. expression. as ( TupleExprSyntax . self) !
32+ //context.diagnose(Diagnostic(node: node, message: ErrorDiagnostic(id: "bro", message: child.expression.debugDescription)))
33+ let tuple : TupleExprSyntax = child. expression. as ( TupleExprSyntax . self) !, valueExpression : ExprSyntax = tuple. elements. last!. expression
34+ var ( value, returnType) : ( String , LiteralReturnType ) = parse_literal_value ( elementType: elementType, key: " data " , expression: valueExpression) !
35+ if returnType == . interpolation {
36+ value = " \\ ( " + value + " ) "
37+ }
3238 key += " - \( tuple. elements. first!. expression. as ( StringLiteralExprSyntax . self) !. string) "
33- attributes. append ( key + " = \\ \" \( tuple . elements . last! . expression . as ( StringLiteralExprSyntax . self ) ! . string ) \\ \" " )
39+ attributes. append ( key + " = \\ \" " + value + " \\ \" " )
3440 } else {
3541 if key == " acceptCharset " {
3642 key = " accept-charset "
@@ -67,54 +73,47 @@ private extension HTMLElement {
6773 }
6874 }
6975
70- static func parse_attribute( elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> String ? {
71- if let boolean: String = expression. as ( BooleanLiteralExprSyntax . self) ? . literal. text {
72- return boolean. elementsEqual ( " true " ) ? key : nil
76+ static func enumName( elementType: HTMLElementType , key: String ) -> String {
77+ switch elementType. rawValue + key {
78+ case " buttontype " : return " buttontype "
79+ case " inputtype " : return " inputmode "
80+ case " oltype " : return " numberingtype "
81+ case " scripttype " : return " scripttype "
82+ default : return key
7383 }
84+ }
85+
86+ static func parse_attribute( elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> String ? {
7487 func yup( _ value: String ) -> String { key + " = \\ \" " + value + " \\ \" " }
75- if let string: String = expression. as ( StringLiteralExprSyntax . self) ? . string {
76- return yup ( string)
77- }
78- if let integer: String = expression. as ( IntegerLiteralExprSyntax . self) ? . literal. text {
79- return yup ( integer)
80- }
81- if let float: String = expression. as ( FloatLiteralExprSyntax . self) ? . literal. text {
82- return yup ( float)
83- }
84- func enumName( ) -> String {
85- switch elementType. rawValue + key { // better performance than switching key, than switching elementType
86- case " buttontype " : return " buttontype "
87- case " inputtype " : return " inputmode "
88- case " oltype " : return " numberingtype "
89- case " scripttype " : return " scripttype "
90- default : return key
88+ if let ( string, returnType) : ( String , LiteralReturnType ) = parse_literal_value ( elementType: elementType, key: key, expression: expression) {
89+ switch returnType {
90+ case . boolean: return string. elementsEqual ( " true " ) ? key : nil
91+ case . string: return yup ( string)
92+ case . interpolation: return yup ( " \\ ( " + string + " ) " )
9193 }
9294 }
9395 if let value: String = expression. as ( ArrayExprSyntax . self) ? . elements. compactMap ( {
94- if let string: String = $0. expression. as ( StringLiteralExprSyntax . self ) ? . string {
96+ if let string: String = $0. expression. stringLiteral ? . string {
9597 return string
9698 }
97- if let string: String = $0. expression. as ( IntegerLiteralExprSyntax . self ) ? . literal. text {
99+ if let string: String = $0. expression. integerLiteral ? . literal. text {
98100 return string
99101 }
100102 if let string: String = $0. expression. as ( MemberAccessExprSyntax . self) ? . declName. baseName. text {
101- return HTMLElementAttribute . htmlValue ( enumName: enumName ( ) , for: string)
103+ return HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType : elementType , key : key ) , for: string)
102104 }
103105 return nil
104106 } ) . joined ( separator: get_separator ( key: key) ) {
105107 return yup ( value)
106108 }
107109 func member( _ value: String ) -> String {
108110 var string : String = String ( value [ value. index ( after: value. startIndex) ... ] )
109- string = HTMLElementAttribute . htmlValue ( enumName: enumName ( ) , for: string)
111+ string = HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType : elementType , key : key ) , for: string)
110112 return yup ( string)
111113 }
112114 if let function: FunctionCallExprSyntax = expression. as ( FunctionCallExprSyntax . self) {
113115 return member ( " \( function) " )
114116 }
115- if let value: String = expression. as ( MemberAccessExprSyntax . self) ? . declName. baseName. text {
116- return member ( " . " + value)
117- }
118117 return nil
119118 }
120119 static func get_separator( key: String ) -> String {
@@ -123,6 +122,53 @@ private extension HTMLElement {
123122 default : return " "
124123 }
125124 }
125+ static func parse_literal_value( elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> ( value: String , returnType: LiteralReturnType ) ? {
126+ if let boolean: String = expression. booleanLiteral? . literal. text {
127+ return ( boolean, . boolean)
128+ }
129+ if let string: String = expression. stringLiteral? . string {
130+ return ( string, . string)
131+ }
132+ if let integer: String = expression. integerLiteral? . literal. text {
133+ return ( integer, . string)
134+ }
135+ if let float: String = expression. floatLiteral? . literal. text {
136+ return ( float, . string)
137+ }
138+ if let function: FunctionCallExprSyntax = expression. as ( FunctionCallExprSyntax . self) {
139+ switch key {
140+ case " height " , " width " :
141+ var value : String = " \( function) "
142+ value = String ( value [ value. index ( after: value. startIndex) ... ] )
143+ value = HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: value)
144+ return ( value, . string)
145+ default :
146+ return ( " \( function) " , . interpolation)
147+ }
148+ }
149+ if let member: MemberAccessExprSyntax = expression. as ( MemberAccessExprSyntax . self) {
150+ let decl : String = member. declName. baseName. text
151+ if let base: ExprSyntax = member. base {
152+ if let integer: String = base. integerLiteral? . literal. text {
153+ switch decl {
154+ case " description " :
155+ return ( integer, . string)
156+ default :
157+ return ( integer, . interpolation)
158+ }
159+ } else {
160+ return ( " \( member) " , . interpolation)
161+ }
162+ } else {
163+ return ( HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: decl) , . string)
164+ }
165+ }
166+ return nil
167+ }
168+ }
169+
170+ enum LiteralReturnType {
171+ case boolean, string, interpolation
126172}
127173
128174// MARK: HTMLElementType
@@ -270,6 +316,12 @@ enum HTMLElementType : String {
270316 }
271317}
272318
319+ extension ExprSyntax {
320+ var booleanLiteral : BooleanLiteralExprSyntax ? { self . as ( BooleanLiteralExprSyntax . self) }
321+ var stringLiteral : StringLiteralExprSyntax ? { self . as ( StringLiteralExprSyntax . self) }
322+ var integerLiteral : IntegerLiteralExprSyntax ? { self . as ( IntegerLiteralExprSyntax . self) }
323+ var floatLiteral : FloatLiteralExprSyntax ? { self . as ( FloatLiteralExprSyntax . self) }
324+ }
273325extension StringLiteralExprSyntax {
274326 var string : String { " \( segments) " }
275327}
0 commit comments