diff --git a/Package.resolved b/Package.resolved index 4915589..4bcd2af 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "f3f24165eda2a67f91718e2f9f96a832181fa7258df6be8ec1058e1a5ef951b5", + "originHash" : "3969417c2a67000e225174da55741dc4261b615b990ae4ce381417f06c5e9099", "pins" : [ { "identity" : "swift-docc-plugin", @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax", "state" : { - "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", - "version" : "509.1.1" + "revision" : "4799286537280063c85a32f09884cfbca301b1a1", + "version" : "602.0.0" } }, { diff --git a/Package.swift b/Package.swift index b957fd9..1447c9d 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( .package(path: "./tree-sitter-p4"), .package(url: "https://github.com/tree-sitter/swift-tree-sitter", revision: "main"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), - .package(url: "https://github.com/swiftlang/swift-syntax", from: "509.0.0"), + .package(url: "https://github.com/swiftlang/swift-syntax", from: "602.0.0"), ], targets: [ .macro( @@ -38,7 +38,8 @@ let package = Package( dependencies: [ .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), - ]), + ], + swiftSettings: [.enableExperimentalFeature("CodeItemMacros")]), .target( name: "P4Compiler", dependencies: [ @@ -50,6 +51,7 @@ let package = Package( .target(name: "P4Lang"), .target(name: "P4Runtime"), ], + swiftSettings: [.enableExperimentalFeature("CodeItemMacros")], ), .target( name: "TreeSitterExtensions", @@ -60,7 +62,8 @@ let package = Package( ), .target( name: "Common", - dependencies: ["Macros"] + dependencies: ["Macros"], + swiftSettings: [.enableExperimentalFeature("CodeItemMacros")], ), .target( name: "P4Lang", diff --git a/Sources/Macros/Macros.swift b/Sources/Macros/Macros.swift index c919f8c..2efe56b 100644 --- a/Sources/Macros/Macros.swift +++ b/Sources/Macros/Macros.swift @@ -17,7 +17,23 @@ import SwiftCompilerPlugin import SwiftSyntax -import SwiftSyntaxMacros +@_spi(ExperimentalLanguageFeature) import SwiftSyntaxMacros + +public func remove_embedded_quotes(_ from: String) -> String { + return from.replacing("\"", with: []) +} + +struct MacroError: Error, CustomStringConvertible { + var message: String + var description: String { + get { + return message + } + } + public init(withMessage _message: String) { + message = _message + } +} public struct UseOkResult: ExpressionMacro { public static func expansion( @@ -25,7 +41,7 @@ public struct UseOkResult: ExpressionMacro { in context: some MacroExpansionContext ) throws -> ExprSyntax { - guard let argument = node.argumentList.first?.expression else { + guard let argument = node.arguments.first?.expression else { throw Require.Error.SyntaxError } @@ -48,7 +64,7 @@ public struct UseErrorResult: ExpressionMacro { in context: some MacroExpansionContext ) throws -> ExprSyntax { - guard let argument = node.argumentList.first?.expression else { + guard let argument = node.arguments.first?.expression else { throw Require.Error.SyntaxError } @@ -78,7 +94,7 @@ public struct RequireResult: ExpressionMacro { in context: some MacroExpansionContext ) throws -> ExprSyntax { - guard let argument = node.argumentList.first?.expression else { + guard let argument = node.arguments.first?.expression else { throw Require.Error.SyntaxError } @@ -101,9 +117,9 @@ public struct RequireErrorResult: ExpressionMacro { in context: some MacroExpansionContext ) throws -> ExprSyntax { - let arguments = node.argumentList.indices - let expected_error = node.argumentList[arguments.startIndex].expression - let error_producer = node.argumentList[arguments.index(after: arguments.startIndex)].expression + let arguments = node.arguments.indices + let expected_error = node.arguments[arguments.startIndex].expression + let error_producer = node.arguments[arguments.index(after: arguments.startIndex)].expression return ExprSyntax( """ @@ -121,9 +137,84 @@ public struct RequireErrorResult: ExpressionMacro { } } +public struct RequireNodeType: CodeItemMacro { + public static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> [CodeBlockItemSyntax] { + let arguments = node.arguments.indices + var arg_index = arguments.startIndex + let node_to_check = node.arguments[arg_index].expression + arg_index = arguments.index(after: arg_index) + let expected_type = node.arguments[arg_index].expression + arg_index = arguments.index(after: arg_index) + let expected_type_nice_name = node.arguments[arg_index].expression + + let error_message = "Did not find " + remove_embedded_quotes(expected_type_nice_name.description) + + return [CodeBlockItemSyntax( + """ + if \(node_to_check).nodeType != \(expected_type) { + return Result.Error( + ErrorOnNode(node: \(node_to_check), withError: "\(raw: error_message)")) + } + """)] + } +} +public struct RequireNodesType: CodeItemMacro { + public static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> [CodeBlockItemSyntax] { + let arguments = node.arguments.indices + var arg_index = arguments.startIndex + + let node_to_check = node.arguments[arg_index].expression + + arg_index = arguments.index(after: arg_index) + guard let expected_types = node.arguments[arg_index].expression.as(ArrayExprSyntax.self) else { + throw MacroError(withMessage: "Node(s) to check must be in an array") + } + + arg_index = arguments.index(after: arg_index) + guard + let expected_type_nice_names = node.arguments[arg_index].expression.as(ArrayExprSyntax.self) + else { + throw MacroError(withMessage: "Node nice names must be in an array") + } + + let error_message = "Did not find one of the expected types: " + expected_type_nice_names.elements.map(){ l in + remove_embedded_quotes("\(l.expression)") + }.joined(separator: ",") + + + let ifs = expected_types.elements.map(){ l in + "\(node_to_check).nodeType != \(l.expression)" + }.joined(separator: " && ") + + return [CodeBlockItemSyntax( + """ + if \(raw: ifs) { + return Result.Error( + ErrorOnNode(node: \(node_to_check), withError: "\(raw: error_message)")) + } + """)] + } +} +public struct SkipUnlessNodeType: CodeItemMacro { + public static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> [CodeBlockItemSyntax] { + let arguments = node.arguments.indices + var arg_index = arguments.startIndex + let node_to_check = node.arguments[arg_index].expression + arg_index = arguments.index(after: arg_index) + let expected_type = node.arguments[arg_index].expression + + return [CodeBlockItemSyntax( + """ + if \(node_to_check).nodeType != \(expected_type) { + return Result.Ok(.none) + } + """)] + } +} + @main struct P4Macros: CompilerPlugin { var providingMacros: [Macro.Type] = [ - RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self, + RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self, RequireNodeType.self, SkipUnlessNodeType.self, RequireNodesType.self ] }