Add NodeType-Checking Macros
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "f3f24165eda2a67f91718e2f9f96a832181fa7258df6be8ec1058e1a5ef951b5",
|
"originHash" : "3969417c2a67000e225174da55741dc4261b615b990ae4ce381417f06c5e9099",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "swift-docc-plugin",
|
"identity" : "swift-docc-plugin",
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/swiftlang/swift-syntax",
|
"location" : "https://github.com/swiftlang/swift-syntax",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
|
"revision" : "4799286537280063c85a32f09884cfbca301b1a1",
|
||||||
"version" : "509.1.1"
|
"version" : "602.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+6
-3
@@ -30,7 +30,7 @@ let package = Package(
|
|||||||
.package(path: "./tree-sitter-p4"),
|
.package(path: "./tree-sitter-p4"),
|
||||||
.package(url: "https://github.com/tree-sitter/swift-tree-sitter", revision: "main"),
|
.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/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: [
|
targets: [
|
||||||
.macro(
|
.macro(
|
||||||
@@ -38,7 +38,8 @@ let package = Package(
|
|||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
|
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
|
||||||
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
|
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
|
||||||
]),
|
],
|
||||||
|
swiftSettings: [.enableExperimentalFeature("CodeItemMacros")]),
|
||||||
.target(
|
.target(
|
||||||
name: "P4Compiler",
|
name: "P4Compiler",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
@@ -50,6 +51,7 @@ let package = Package(
|
|||||||
.target(name: "P4Lang"),
|
.target(name: "P4Lang"),
|
||||||
.target(name: "P4Runtime"),
|
.target(name: "P4Runtime"),
|
||||||
],
|
],
|
||||||
|
swiftSettings: [.enableExperimentalFeature("CodeItemMacros")],
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "TreeSitterExtensions",
|
name: "TreeSitterExtensions",
|
||||||
@@ -60,7 +62,8 @@ let package = Package(
|
|||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "Common",
|
name: "Common",
|
||||||
dependencies: ["Macros"]
|
dependencies: ["Macros"],
|
||||||
|
swiftSettings: [.enableExperimentalFeature("CodeItemMacros")],
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "P4Lang",
|
name: "P4Lang",
|
||||||
|
|||||||
@@ -17,7 +17,23 @@
|
|||||||
|
|
||||||
import SwiftCompilerPlugin
|
import SwiftCompilerPlugin
|
||||||
import SwiftSyntax
|
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 struct UseOkResult: ExpressionMacro {
|
||||||
public static func expansion(
|
public static func expansion(
|
||||||
@@ -25,7 +41,7 @@ public struct UseOkResult: ExpressionMacro {
|
|||||||
in context: some MacroExpansionContext
|
in context: some MacroExpansionContext
|
||||||
) throws -> ExprSyntax {
|
) throws -> ExprSyntax {
|
||||||
|
|
||||||
guard let argument = node.argumentList.first?.expression else {
|
guard let argument = node.arguments.first?.expression else {
|
||||||
throw Require.Error.SyntaxError
|
throw Require.Error.SyntaxError
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +64,7 @@ public struct UseErrorResult: ExpressionMacro {
|
|||||||
in context: some MacroExpansionContext
|
in context: some MacroExpansionContext
|
||||||
) throws -> ExprSyntax {
|
) throws -> ExprSyntax {
|
||||||
|
|
||||||
guard let argument = node.argumentList.first?.expression else {
|
guard let argument = node.arguments.first?.expression else {
|
||||||
throw Require.Error.SyntaxError
|
throw Require.Error.SyntaxError
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +94,7 @@ public struct RequireResult: ExpressionMacro {
|
|||||||
in context: some MacroExpansionContext
|
in context: some MacroExpansionContext
|
||||||
) throws -> ExprSyntax {
|
) throws -> ExprSyntax {
|
||||||
|
|
||||||
guard let argument = node.argumentList.first?.expression else {
|
guard let argument = node.arguments.first?.expression else {
|
||||||
throw Require.Error.SyntaxError
|
throw Require.Error.SyntaxError
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +117,9 @@ public struct RequireErrorResult: ExpressionMacro {
|
|||||||
in context: some MacroExpansionContext
|
in context: some MacroExpansionContext
|
||||||
) throws -> ExprSyntax {
|
) throws -> ExprSyntax {
|
||||||
|
|
||||||
let arguments = node.argumentList.indices
|
let arguments = node.arguments.indices
|
||||||
let expected_error = node.argumentList[arguments.startIndex].expression
|
let expected_error = node.arguments[arguments.startIndex].expression
|
||||||
let error_producer = node.argumentList[arguments.index(after: arguments.startIndex)].expression
|
let error_producer = node.arguments[arguments.index(after: arguments.startIndex)].expression
|
||||||
|
|
||||||
return ExprSyntax(
|
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
|
@main
|
||||||
struct P4Macros: CompilerPlugin {
|
struct P4Macros: CompilerPlugin {
|
||||||
var providingMacros: [Macro.Type] = [
|
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
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user