diff --git a/Sources/BinaryParseKit/BinaryParseKit.swift b/Sources/BinaryParseKit/BinaryParseKit.swift index e0b1cec..7c398cd 100644 --- a/Sources/BinaryParseKit/BinaryParseKit.swift +++ b/Sources/BinaryParseKit/BinaryParseKit.swift @@ -538,3 +538,23 @@ public macro matchDefault() = #externalMacro( module: "BinaryParseKitMacros", type: "EmptyPeerMacro", ) + +// MARK: - Bitmask + +@attached(peer) +public macro mask(bitCount: Int) = #externalMacro( + module: "BinaryParseKitMacros", + type: "EmptyPeerMacro", +) + +@attached(peer) +public macro mask() = #externalMacro( + module: "BinaryParseKitMacros", + type: "EmptyPeerMacro", +) + +@attached(extension, conformances: BinaryParseKit.Parsable, names: arbitrary) +public macro ParseBitmask() = #externalMacro( + module: "BinaryParseKitMacros", + type: "ConstructParseBitmaskMacro", +) diff --git a/Sources/BinaryParseKit/Protocols/BitmaskParsable.swift b/Sources/BinaryParseKit/Protocols/BitmaskParsable.swift new file mode 100644 index 0000000..e0f7419 --- /dev/null +++ b/Sources/BinaryParseKit/Protocols/BitmaskParsable.swift @@ -0,0 +1,10 @@ +// +// BitmaskParsable.swift +// BinaryParseKit +// +// Created by Larry Zeng on 11/28/25. +// + +public protocol BitmaskParsable: Parsable { + static var bitCount: Int { get } +} diff --git a/Sources/BinaryParseKitMacros/BinaryParseKitMacro.swift b/Sources/BinaryParseKitMacros/BinaryParseKitMacro.swift index bf3f18c..c56c7cb 100644 --- a/Sources/BinaryParseKitMacros/BinaryParseKitMacro.swift +++ b/Sources/BinaryParseKitMacros/BinaryParseKitMacro.swift @@ -7,5 +7,6 @@ struct BinaryParseKitPlugin: CompilerPlugin { EmptyPeerMacro.self, ConstructStructParseMacro.self, ConstructEnumParseMacro.self, + ConstructParseBitmaskMacro.self, ] } diff --git a/Sources/BinaryParseKitMacros/Macros/ParseBitmask/ConstructParseBitmaskMacro.swift b/Sources/BinaryParseKitMacros/Macros/ParseBitmask/ConstructParseBitmaskMacro.swift new file mode 100644 index 0000000..340a4cc --- /dev/null +++ b/Sources/BinaryParseKitMacros/Macros/ParseBitmask/ConstructParseBitmaskMacro.swift @@ -0,0 +1,72 @@ +// +// ConstructParseBitmaskMacro.swift +// BinaryParseKit +// +// Created by Larry Zeng on 11/28/25. +// +import SwiftDiagnostics +import SwiftSyntax +import SwiftSyntaxMacros + +enum ParseBitmaskMacroError: Error, DiagnosticMessage { + case onlyStructsAreSupported + + var message: String { + switch self { + case .onlyStructsAreSupported: "@ParseBitmask can only be applied to structs." + } + } + + var diagnosticID: SwiftDiagnostics.MessageID { + .init( + domain: "observer.universe.BinaryParseKit.ParseBitmaskMacroError", + id: "\(self)", + ) + } + + var severity: SwiftDiagnostics.DiagnosticSeverity { + switch self { + case .onlyStructsAreSupported: .error + } + } +} + +public struct ConstructParseBitmaskMacro: ExtensionMacro { + public static func expansion( + of node: SwiftSyntax.AttributeSyntax, + attachedTo declaration: some SwiftSyntax.DeclGroupSyntax, + providingExtensionsOf type: some SwiftSyntax.TypeSyntaxProtocol, + conformingTo _: [SwiftSyntax.TypeSyntax], + in context: some SwiftSyntaxMacros.MacroExpansionContext, + ) throws -> [SwiftSyntax.ExtensionDeclSyntax] { + guard let structDeclaration = declaration.as(StructDeclSyntax.self) else { + throw ParseBitmaskMacroError.onlyStructsAreSupported + } + + let type = type.trimmed + + let accessorInfo = try extractAccessor( + from: node, + attachedTo: declaration, + in: context, + ) + + // extract mask macro info + + let bitmaskParsableExtension = + try ExtensionDeclSyntax("extension \(type): \(raw: Constants.Protocols.bitmaskParsableProtocol)") { + try VariableDeclSyntax("static var bitCount: Int") { + #"fatalError("TODO")"# + } + + // FIXME: accessors + try InitializerDeclSyntax( + "\(accessorInfo.parsingAccessor) init(parsing span: inout \(raw: Constants.BinaryParsing.parserSpan)) throws(\(raw: Constants.BinaryParsing.thrownParsingError))", + ) { + #"fatalError("TODO")"# + } + } + + return [bitmaskParsableExtension] + } +} diff --git a/Sources/BinaryParseKitMacros/Macros/Supports/Constants.swift b/Sources/BinaryParseKitMacros/Macros/Supports/Constants.swift index 834aa79..d080e93 100644 --- a/Sources/BinaryParseKitMacros/Macros/Supports/Constants.swift +++ b/Sources/BinaryParseKitMacros/Macros/Supports/Constants.swift @@ -35,6 +35,7 @@ extension Constants { static let expressibleByParsingProtocol = PackageMember(name: "ExpressibleByParsing") static let matchableProtocol = PackageMember(name: "Matchable") static let printableProtocol = PackageMember(name: "Printable") + static let bitmaskParsableProtocol = PackageMember(name: "BitmaskParsable") } } diff --git a/Sources/BinaryParseKitMacros/Macros/Supports/MacroAccessorVisitor.swift b/Sources/BinaryParseKitMacros/Macros/Supports/MacroAccessorVisitor.swift index 3d8efc3..882aef3 100644 --- a/Sources/BinaryParseKitMacros/Macros/Supports/MacroAccessorVisitor.swift +++ b/Sources/BinaryParseKitMacros/Macros/Supports/MacroAccessorVisitor.swift @@ -28,7 +28,7 @@ enum MacroAccessorError: DiagnosticMessage, Error { var diagnosticID: SwiftDiagnostics.MessageID { .init( - domain: "BinaryParseKit.MacroACLError", + domain: "observer.universe.BinaryParseKit.MacroACLError", id: "\(self)", ) }