Skip to content

Commit

Permalink
much better diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
MahdiBM committed Jul 11, 2024
1 parent a887797 commit 966a7c2
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 25 deletions.
72 changes: 56 additions & 16 deletions Sources/EnumeratorMacroImpl/EnumeratorMacroType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,74 @@ extension EnumeratorMacroType: MemberMacro {
if exprList.isEmpty {
throw MacroError.expectedAtLeastOneArgument
}
let templates = try exprList.compactMap { element in
let templates = try exprList.compactMap {
element -> (template: String, syntax: StringLiteralExprSyntax) in
guard let stringLiteral = element.expression.as(StringLiteralExprSyntax.self) else {
throw MacroError.allArgumentsMustBeStringLiterals(violation: element.description)
}
return stringLiteral
let template = stringLiteral
.segments
.formatted()
.description
return (template, stringLiteral)
}
let rendered = try templates.map { template in
try MustacheTemplate(
string: "{{%CONTENT_TYPE:TEXT}}\n" + template
).render([
"cases": cases
])
let rendered = templates.compactMap {
(template, syntax) -> (rendered: String, syntax: StringLiteralExprSyntax)? in
do {
let rendered = try MustacheTemplate(
string: "{{%CONTENT_TYPE:TEXT}}\n" + template
).render([
"cases": cases
])
return (rendered, syntax)
} catch {
let message: MacroError
let errorSyntax: SyntaxProtocol
if let parserError = error as? MustacheTemplate.ParserError {
message = .mustacheTemplateError(
message: String(describing: parserError.error)
)
let segments = Array(syntax.segments)
let segmentIdx = parserError.context.lineNumber - 2
if segmentIdx < segments.count {
let syntaxAtErrorLine = segments[segmentIdx]
errorSyntax = syntaxAtErrorLine
} else {
errorSyntax = syntax
}
} else {
message = .mustacheTemplateError(
message: String(describing: error)
)
errorSyntax = syntax
}
context.diagnose(
Diagnostic(
node: errorSyntax,
message: message
)
)
return nil
}
}
let syntaxes: [DeclSyntax] = rendered.flatMap { rendered in
SourceFileSyntax(
let syntaxes: [DeclSyntax] = rendered.compactMap {
(rendered, syntax) -> [DeclSyntax]? in
let decls = SourceFileSyntax(
stringLiteral: rendered
).statements.compactMap { statement in
DeclSyntax(statement.item)
}
}

let withErrors = syntaxes.filter(\.hasError)
guard withErrors.isEmpty else {
throw MacroError.renderedSyntaxesContainsErrors(withErrors.map(\.description))
}
if let withError = decls.first(where: \.hasError) {
context.diagnose(
Diagnostic(
node: syntax,
message: MacroError.renderedSyntaxContainsErrors(withError.description)
)
)
return nil
}
return decls
}.flatMap { $0 }

return syntaxes
}
Expand Down
23 changes: 14 additions & 9 deletions Sources/EnumeratorMacroImpl/MacroError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,28 @@ enum MacroError: Error, CustomStringConvertible {
case unacceptableArguments
case expectedAtLeastOneArgument
case allArgumentsMustBeStringLiterals(violation: String)
case renderedSyntaxesContainsErrors([String])
case renderedSyntaxContainsErrors(String)
case couldNotFindLocationOfNode(syntax: String)
case mustacheTemplateError(message: String)

var description: String {
switch self {
case .isNotEnum:
return "Only enums are supported"
"Only enums are supported"
case .macroDeclarationHasNoArguments:
return "The macro declaration needs to have at least 1 StringLiteral argument"
"The macro declaration needs to have at least 1 StringLiteral argument"
case .unacceptableArguments:
return "The arguments passed to the macro were unacceptable"
"The arguments passed to the macro were unacceptable"
case .expectedAtLeastOneArgument:
return "At least one argument of type StaticString is required"
"At least one argument of type StaticString is required"
case let .allArgumentsMustBeStringLiterals(violation):
return "All arguments must be string literals, but found: \(violation)"
case let .renderedSyntaxesContainsErrors(syntaxes):
let syntaxes = syntaxes.joined(separator: "\n\(String(repeating: "-", count: 20))\n")
return "Some rendered syntaxes contain errors:\n\(syntaxes)"
"All arguments must be string literals, but found: \(violation)"
case let .renderedSyntaxContainsErrors(syntax):
"Rendered syntax contains errors:\n\(syntax)"
case let .couldNotFindLocationOfNode(syntax):
"Could not find location of node for syntax:\n\(syntax)"
case let .mustacheTemplateError(message):
"Error while rendering the template: \(message)"
}
}
}
Expand Down

0 comments on commit 966a7c2

Please sign in to comment.