Skip to content

Commit 4e7b80e

Browse files
moved some stuff around; micro-optimizations
1 parent 8cea34d commit 4e7b80e

File tree

1 file changed

+42
-45
lines changed

1 file changed

+42
-45
lines changed

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 42 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import struct NIOCore.ByteBuffer
2020

2121
enum HTMLElement : ExpressionMacro {
2222
static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
23-
let string:String = parse_macro(context: context, expression: node.as(MacroExpansionExprSyntax.self)!)
24-
let has_interpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty
23+
let string:String = parse_macro(context: context, expression: node.macroExpansion!)
2524
var set:Set<HTMLElementType?> = [.htmlUTF8Bytes, .htmlUTF16Bytes, .htmlUTF8CString]
2625

2726
#if canImport(Foundation)
@@ -33,6 +32,7 @@ enum HTMLElement : ExpressionMacro {
3332
#endif
3433

3534
if set.contains(HTMLElementType(rawValue: node.macroName.text)) {
35+
let has_interpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty
3636
guard !has_interpolation else {
3737
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "interpolationNotAllowedForDataType", message: "String Interpolation is not allowed for this data type. Runtime values get converted to raw text, which is not the expected result.")))
3838
return ""
@@ -66,6 +66,7 @@ enum HTMLElement : ExpressionMacro {
6666
}
6767

6868
private extension HTMLElement {
69+
// MARK: Parse Macro
6970
static func parse_macro(context: some MacroExpansionContext, expression: MacroExpansionExprSyntax) -> String {
7071
guard let elementType:HTMLElementType = HTMLElementType(rawValue: expression.macroName.text) else { return "\(expression)" }
7172
let childs:SyntaxChildren = expression.arguments.children(viewMode: .all)
@@ -94,6 +95,7 @@ private extension HTMLElement {
9495
}
9596
return string
9697
}
98+
// MARK: Parse Arguments
9799
static func parse_arguments(context: some MacroExpansionContext, elementType: HTMLElementType, children: Slice<SyntaxChildren>) -> ElementData {
98100
var attributes:[String] = [], innerHTML:[String] = []
99101
for element in children {
@@ -118,14 +120,15 @@ private extension HTMLElement {
118120
}
119121
return ElementData(attributes: attributes, innerHTML: innerHTML)
120122
}
123+
// MARK: Parse Global Attributes
121124
static func parse_global_attributes(context: some MacroExpansionContext, elementType: HTMLElementType, array: ArrayExprSyntax) -> [String] {
122125
var keys:Set<String> = [], attributes:[String] = []
123126
for element in array.elements {
124127
let function:FunctionCallExprSyntax = element.expression.as(FunctionCallExprSyntax.self)!, key_argument:LabeledExprSyntax = function.arguments.first!, key_element:ExprSyntax = key_argument.expression
125128
var key:String = function.calledExpression.memberAccess!.declName.baseName.text, value:String? = nil
126129
switch key {
127130
case "custom", "data":
128-
var (literalValue, returnType):(String, LiteralReturnType) = parse_literal_value(context: context, elementType: elementType, key: key, argument: function.arguments.last!)!
131+
var (literalValue, returnType):(String, LiteralReturnType) = parse_literal_value(context: context, elementType: elementType, key: key, expression: function.arguments.last!.expression)!
129132
if returnType == .string {
130133
literalValue.escapeHTML(escapeAttributes: true)
131134
}
@@ -138,7 +141,7 @@ private extension HTMLElement {
138141
break
139142
case "event":
140143
key = "on" + key_element.memberAccess!.declName.baseName.text
141-
if var result:(String, LiteralReturnType) = parse_literal_value(context: context, elementType: elementType, key: key, argument: function.arguments.last!) {
144+
if var result:(String, LiteralReturnType) = parse_literal_value(context: context, elementType: elementType, key: key, expression: function.arguments.last!.expression) {
142145
if result.1 == .string {
143146
result.0.escapeHTML(escapeAttributes: true)
144147
}
@@ -167,14 +170,15 @@ private extension HTMLElement {
167170
}
168171
return attributes
169172
}
173+
// MARK: Parse innerHTML
170174
static func parse_inner_html(context: some MacroExpansionContext, elementType: HTMLElementType, child: LabeledExprSyntax) -> String? {
171175
if let macro:MacroExpansionExprSyntax = child.expression.macroExpansion {
172176
var string:String = parse_macro(context: context, expression: macro)
173177
if elementType == .escapeHTML {
174178
string.escapeHTML(escapeAttributes: false)
175179
}
176180
return string
177-
} else if var string:String = parse_literal_value(context: context, elementType: elementType, key: "", argument: child)?.value {
181+
} else if var string:String = parse_literal_value(context: context, elementType: elementType, key: "", expression: child.expression)?.value {
178182
string.escapeHTML(escapeAttributes: false)
179183
return string
180184
} else {
@@ -184,7 +188,7 @@ private extension HTMLElement {
184188
}
185189
static func unallowed_expression(context: some MacroExpansionContext, node: LabeledExprSyntax) {
186190
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unallowedExpression", message: "String Interpolation is required when encoding runtime values."), fixIts: [
187-
FixIt(message: DiagnosticMsg(id: "useStringInterpolation", message: "Use String Interpolation.", severity: .error), changes: [
191+
FixIt(message: DiagnosticMsg(id: "useStringInterpolation", message: "Use String Interpolation."), changes: [
188192
FixIt.Change.replace(
189193
oldNode: Syntax(node),
190194
newNode: Syntax(StringLiteralExprSyntax(content: "\\(\(node))"))
@@ -212,9 +216,10 @@ private extension HTMLElement {
212216
}
213217
}
214218

219+
// MARK: Parse Attribute
215220
static func parse_attribute(context: some MacroExpansionContext, elementType: HTMLElementType, key: String, argument: LabeledExprSyntax) -> String? {
216221
let expression:ExprSyntax = argument.expression
217-
if var result:(String, LiteralReturnType) = parse_literal_value(context: context, elementType: elementType, key: key, argument: argument) {
222+
if var result:(String, LiteralReturnType) = parse_literal_value(context: context, elementType: elementType, key: key, expression: expression) {
218223
switch result.1 {
219224
case .boolean: return result.0.elementsEqual("true") ? "" : nil
220225
case .string:
@@ -233,27 +238,15 @@ private extension HTMLElement {
233238
}
234239
return nil
235240
}
236-
static func get_separator(key: String) -> String {
237-
switch key {
238-
case "accept", "coords", "exportparts", "imagesizes", "imagesrcset", "sizes", "srcset": return ","
239-
default: return " "
240-
}
241-
}
242-
static func parse_literal_value(context: some MacroExpansionContext, elementType: HTMLElementType, key: String, argument: LabeledExprSyntax) -> (value: String, returnType: LiteralReturnType)? {
243-
let expression:ExprSyntax = argument.expression
241+
// MARK: Parse Literal Value
242+
static func parse_literal_value(context: some MacroExpansionContext, elementType: HTMLElementType, key: String, expression: ExprSyntax) -> (value: String, returnType: LiteralReturnType)? {
244243
if let boolean:String = expression.booleanLiteral?.literal.text {
245244
return (boolean, .boolean)
246245
}
247246
func return_string_or_interpolation() -> (String, LiteralReturnType)? {
248-
if let string:String = expression.stringLiteral?.string {
247+
if let string:String = expression.stringLiteral?.string ?? expression.integerLiteral?.literal.text ?? expression.floatLiteral?.literal.text {
249248
return (string, .string)
250249
}
251-
if let integer:String = expression.integerLiteral?.literal.text {
252-
return (integer, .string)
253-
}
254-
if let float:String = expression.floatLiteral?.literal.text {
255-
return (float, .string)
256-
}
257250
if let function:FunctionCallExprSyntax = expression.as(FunctionCallExprSyntax.self) {
258251
switch key {
259252
case "height", "width":
@@ -276,29 +269,32 @@ private extension HTMLElement {
276269
return (HTMLElementAttribute.Extra.htmlValue(enumName: enumName(elementType: elementType, key: key), for: decl), .string)
277270
}
278271
}
279-
let separator:String = get_separator(key: key)
280-
let string_return_logic:(ExprSyntax, String) -> String = {
281-
if $1.contains(separator) {
282-
context.diagnose(Diagnostic(node: $0, message: DiagnosticMsg(id: "characterNotAllowedInDeclaration", message: "Character \"" + separator + "\" is not allowed when declaring values for \"" + key + "\".")))
283-
}
284-
return $1
285-
}
286-
if let value:String = expression.array?.elements.compactMap({
287-
if let string:String = $0.expression.stringLiteral?.string {
288-
return string_return_logic($0.expression, string)
289-
}
290-
if let string:String = $0.expression.integerLiteral?.literal.text {
291-
return string
292-
}
293-
if let string:String = $0.expression.floatLiteral?.literal.text {
294-
return string
295-
}
296-
if let string:String = $0.expression.memberAccess?.declName.baseName.text {
297-
return HTMLElementAttribute.Extra.htmlValue(enumName: enumName(elementType: elementType, key: key), for: string)
272+
if let array:ArrayExprSyntax = expression.array {
273+
let separator:String
274+
switch key {
275+
case "accept", "coords", "exportparts", "imagesizes", "imagesrcset", "sizes", "srcset":
276+
separator = ","
277+
break
278+
default:
279+
separator = " "
280+
break
298281
}
299-
return nil
300-
}).joined(separator: separator) {
301-
return (value, .string)
282+
return (array.elements.compactMap({
283+
if let string:String = $0.expression.stringLiteral?.string {
284+
if string.contains(separator) {
285+
context.diagnose(Diagnostic(node: $0.expression, message: DiagnosticMsg(id: "characterNotAllowedInDeclaration", message: "Character \"" + separator + "\" is not allowed when declaring values for \"" + key + "\".")))
286+
return nil
287+
}
288+
return string
289+
}
290+
if let string:String = $0.expression.integerLiteral?.literal.text ?? $0.expression.floatLiteral?.literal.text {
291+
return string
292+
}
293+
if let string:String = $0.expression.memberAccess?.declName.baseName.text {
294+
return HTMLElementAttribute.Extra.htmlValue(enumName: enumName(elementType: elementType, key: key), for: string)
295+
}
296+
return nil
297+
}).joined(separator: separator), .string)
302298
}
303299
return nil
304300
}
@@ -320,6 +316,7 @@ private extension HTMLElement {
320316
}
321317
return (string, returnType)
322318
}
319+
// MARK: Flatten Interpolation
323320
static func flatten_interpolation(context: some MacroExpansionContext, remaining_interpolation: inout Int, expr: ExpressionSegmentSyntax) -> String {
324321
let expression:ExprSyntax = expr.expressions.first!.expression
325322
var string:String = "\(expr)"
@@ -525,7 +522,7 @@ enum HTMLElementType : String, CaseIterable {
525522
}
526523

527524
// MARK: Misc
528-
extension ExprSyntax {
525+
extension SyntaxProtocol {
529526
var booleanLiteral : BooleanLiteralExprSyntax? { self.as(BooleanLiteralExprSyntax.self) }
530527
var stringLiteral : StringLiteralExprSyntax? { self.as(StringLiteralExprSyntax.self) }
531528
var integerLiteral : IntegerLiteralExprSyntax? { self.as(IntegerLiteralExprSyntax.self) }

0 commit comments

Comments
 (0)