├── LICENSE ├── Package.swift ├── README.md └── Sources ├── SwiftGodotMacroLibrary ├── MacroCallable.swift ├── MacroExport.swift ├── MacroGodot.swift └── MacroSharedApi.swift └── SwiftGodotMacros └── MacroDefs.swift /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2023 Miguel de Icaza (https://github.com/migueldeicaza) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.7 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftGodot", 8 | products: [ 9 | .library( 10 | name: "SwiftGodot", 11 | targets: ["SwiftGodot"]) 12 | ], 13 | targets: [ 14 | .binaryTarget( 15 | name: "SwiftGodot", 16 | url: "https://github.com/migueldeicaza/SwiftGodot/releases/download/0.60.1/SwiftGodot.xcframework.zip", 17 | checksum: ""), 18 | .testTarget(name: "SwiftGodotTests", dependencies: ["SwiftGodot"]), 19 | ] 20 | ) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This module is inteded to simplify the consumption of a pre-built 2 | SwiftGodot package with Swift. 3 | 4 | If instead you want to reference and consume the source code for 5 | SwiftGodot, use https://github.com/migueldeicaza/SwiftGodot -------------------------------------------------------------------------------- /Sources/SwiftGodotMacroLibrary/MacroCallable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Miguel de Icaza on 9/25/23. 6 | // 7 | 8 | import Foundation 9 | import SwiftCompilerPlugin 10 | import SwiftDiagnostics 11 | import SwiftSyntax 12 | import SwiftSyntaxBuilder 13 | import SwiftSyntaxMacros 14 | 15 | public struct GodotCallable: PeerMacro { 16 | static func process (funcDecl: FunctionDeclSyntax) throws -> String { 17 | let funcName = funcDecl.name.text 18 | var genMethod = "func _mproxy_\(funcName) (args: [Variant]) -> Variant? {\n" 19 | var retProp: String? = nil 20 | var retOptional: Bool = false 21 | 22 | if let (retType, ro) = getIdentifier (funcDecl.signature.returnClause?.type) { 23 | retProp = godotTypeToProp (typeName: retType) 24 | genMethod.append ("\tlet result = \(funcName) (") 25 | retOptional = ro 26 | } else { 27 | genMethod.append ("\t\(funcName) (") 28 | } 29 | // let result = computeGodot (String (args [0]), Int (args [1])) 30 | 31 | var argc = 0 32 | for parameter in funcDecl.signature.parameterClause.parameters { 33 | guard let ptype = getTypeName(parameter) else { 34 | throw MacroError.typeName (parameter) 35 | } 36 | let first = parameter.firstName.text 37 | if argc != 0 { 38 | genMethod.append (", ") 39 | } 40 | if first != "_" { 41 | genMethod.append ("\(first): ") 42 | } 43 | genMethod.append ("\(ptype) (args [\(argc)])!") 44 | argc += 1 45 | } 46 | 47 | genMethod.append (")\n") 48 | if retProp != nil { 49 | if retOptional { 50 | genMethod.append ("\tguard let result else { return nil }\n") 51 | } 52 | genMethod.append ("\treturn Variant (result)\n") 53 | } else { 54 | genMethod.append ("\treturn nil\n") 55 | } 56 | if genMethod != "" { 57 | genMethod.append("}\n") 58 | } 59 | 60 | return genMethod 61 | } 62 | 63 | 64 | public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingPeersOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] { 65 | guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else { 66 | let classError = Diagnostic(node: declaration.root, message: GodotMacroError.requiresFunction) 67 | context.diagnose(classError) 68 | return [] 69 | } 70 | return [SwiftSyntax.DeclSyntax (stringLiteral: try process (funcDecl: funcDecl))] 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Sources/SwiftGodotMacroLibrary/MacroExport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Miguel de Icaza on 9/25/23. 6 | // 7 | 8 | import Foundation 9 | import SwiftCompilerPlugin 10 | import SwiftDiagnostics 11 | import SwiftSyntax 12 | import SwiftSyntaxBuilder 13 | import SwiftSyntaxMacros 14 | 15 | public struct GodotExport: PeerMacro { 16 | 17 | 18 | static func makeGetAccessor (varName: String, isOptional: Bool) -> String { 19 | let name = "_mproxy_get_\(varName)" 20 | if isOptional { 21 | return 22 | """ 23 | func \(name) (args: [Variant]) -> Variant? { 24 | guard let result = \(varName) else { return nil } 25 | return Variant (result) 26 | } 27 | """ 28 | } else { 29 | return 30 | """ 31 | func \(name) (args: [Variant]) -> Variant? { 32 | return Variant (\(varName)) 33 | } 34 | """ 35 | } 36 | } 37 | 38 | static func makeSetAccessor (varName: String, typeName: String, isOptional: Bool) -> String { 39 | let name = "_mproxy_set_\(varName)" 40 | var body: String = "" 41 | 42 | if godotVariants [typeName] == nil { 43 | let optBody = isOptional ? " else { \(varName) = nil }" : "" 44 | body = 45 | """ 46 | if let res: \(typeName) = args [0].asObject () { 47 | \(varName) = res 48 | }\(optBody) 49 | """ 50 | } else { 51 | if isOptional { 52 | body = 53 | """ 54 | if let v = args [0] { 55 | \(varName) = \(typeName)(v) 56 | } else { 57 | \(varName) = nil 58 | } 59 | } 60 | """ 61 | } else { 62 | body = 63 | """ 64 | \(varName) = \(typeName)(args [0])! 65 | """ 66 | } 67 | return "func \(name) (args: [Variant]) -> Variant? {\n\t/*\(body)*/\n\treturn nil\n}" 68 | } 69 | return "func \(name) (args: [Variant]) -> Variant? {\n\t\(body)\n\treturn nil\n}" 70 | } 71 | 72 | 73 | public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingPeersOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] { 74 | guard let varDecl = declaration.as(VariableDeclSyntax.self) else { 75 | let classError = Diagnostic(node: declaration.root, message: GodotMacroError.requiresVar) 76 | context.diagnose(classError) 77 | return [] 78 | } 79 | var isOptional = false 80 | guard let last = varDecl.bindings.last else { 81 | throw GodotMacroError.noVariablesFound 82 | } 83 | guard var type = last.typeAnnotation?.type else { 84 | throw GodotMacroError.noTypeFound(varDecl) 85 | } 86 | if let optSyntax = type.as (OptionalTypeSyntax.self) { 87 | isOptional = true 88 | type = optSyntax.wrappedType 89 | } 90 | guard let typeName = type.as (IdentifierTypeSyntax.self)?.name.text else { 91 | throw GodotMacroError.unsupportedType(varDecl) 92 | } 93 | 94 | var results: [DeclSyntax] = [] 95 | 96 | for singleVar in varDecl.bindings { 97 | guard let ips = singleVar.pattern.as(IdentifierPatternSyntax.self) else { 98 | throw GodotMacroError.expectedIdentifier(singleVar) 99 | } 100 | let varName = ips.identifier.text 101 | let setterName = "_mproxy_set_\(varName)" 102 | let getterName = "_mproxy_get_\(varName)" 103 | 104 | if let accessors = last.accessorBlock { 105 | if accessors.as (CodeBlockSyntax.self) != nil { 106 | throw MacroError.propertyGetSet 107 | } 108 | if let block = accessors.as (AccessorBlockSyntax.self) { 109 | var hasSet = false 110 | var hasGet = false 111 | switch block.accessors { 112 | case .accessors(let list): 113 | for accessor in list { 114 | switch accessor.accessorSpecifier.tokenKind { 115 | case .keyword(let val): 116 | switch val { 117 | case .didSet, .willSet: 118 | hasSet = true 119 | hasGet = true 120 | case .set: 121 | hasSet = true 122 | case .get: 123 | hasGet = true 124 | default: 125 | break 126 | } 127 | default: 128 | break 129 | } 130 | } 131 | default: 132 | throw MacroError.propertyGetSet 133 | } 134 | 135 | if hasSet == false || hasGet == false { 136 | throw MacroError.propertyGetSet 137 | } 138 | } 139 | } 140 | results.append (DeclSyntax(stringLiteral: makeSetAccessor(varName: varName, typeName: typeName, isOptional: isOptional))) 141 | results.append (DeclSyntax(stringLiteral: makeGetAccessor(varName: varName, isOptional: isOptional))) 142 | 143 | } 144 | return results 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /Sources/SwiftGodotMacroLibrary/MacroGodot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GodotMacro.swift 3 | // 4 | // Created by Miguel de Icaza on 9/25/23. 5 | // 6 | // TODO: 7 | // - Make it so that if a class has an init() that we do not generate ours, 8 | // so users can initialize their defaults. But how do we deal with the 9 | // requirement to call classInit? 10 | // 11 | 12 | import Foundation 13 | import SwiftCompilerPlugin 14 | import SwiftDiagnostics 15 | import SwiftSyntax 16 | import SwiftSyntaxBuilder 17 | import SwiftSyntaxMacros 18 | 19 | class GodotMacroProcessor { 20 | let classDecl: ClassDeclSyntax 21 | let className: String 22 | 23 | init (classDecl: ClassDeclSyntax) { 24 | self.classDecl = classDecl 25 | className = classDecl.name.text 26 | } 27 | 28 | var propertyDeclarations: [String: String] = [:] 29 | func lookupProp (parameterTypeName: String, parameterName: String) -> String { 30 | let key = "\(parameterTypeName)/\(parameterName)" 31 | if let v = propertyDeclarations [key] { 32 | return v 33 | } 34 | let propType = godotTypeToProp (typeName: parameterTypeName) 35 | 36 | let name = "prop_\(propertyDeclarations.count)" 37 | 38 | // TODO: perhaps for these prop infos that are parameters to functions, we should not bother making them unique 39 | // and instead share all the Ints, all the Floats and so on. 40 | ctor.append ("\tlet \(name) = PropInfo (propertyType: \(propType), propertyName: \"\(parameterName)\(parameterTypeName)\", className: className, hint: .none, hintStr: \"\", usage: .propertyUsageDefault)\n") 41 | propertyDeclarations [key] = name 42 | return name 43 | } 44 | 45 | // Processes a function 46 | func processFunction (_ funcDecl: FunctionDeclSyntax) throws { 47 | guard hasCallableAttribute(funcDecl.attributes) else { 48 | return 49 | } 50 | let funcName = funcDecl.name.text 51 | var funcArgs = "" 52 | var retProp: String? = nil 53 | if let (retType, _) = getIdentifier (funcDecl.signature.returnClause?.type) { 54 | retProp = lookupProp(parameterTypeName: retType, parameterName: "") 55 | } 56 | 57 | for parameter in funcDecl.signature.parameterClause.parameters { 58 | guard let ptype = getTypeName(parameter) else { 59 | throw MacroError.typeName (parameter) 60 | } 61 | let propInfo = lookupProp (parameterTypeName: ptype, parameterName: "") 62 | if funcArgs == "" { 63 | funcArgs = "\tlet \(funcName)Args = [\n" 64 | } 65 | funcArgs.append ("\t\t\(propInfo),\n") 66 | } 67 | if funcArgs != "" { 68 | funcArgs.append ("\t]\n") 69 | } 70 | ctor.append (funcArgs) 71 | ctor.append ("\tclassInfo.registerMethod(name: \"funcName\", flags: .default, returnValue: \(retProp ?? "nil"), arguments: \(funcArgs == "" ? "[]" : "\(funcName)Args"), function: \(className)._mproxy_\(funcName))") 72 | } 73 | 74 | func processVariable (_ varDecl: VariableDeclSyntax) throws { 75 | guard hasExportAttribute(varDecl.attributes) else { 76 | return 77 | } 78 | guard let last = varDecl.bindings.last else { 79 | throw GodotMacroError.noVariablesFound 80 | } 81 | guard var type = last.typeAnnotation?.type else { 82 | throw GodotMacroError.noTypeFound(varDecl) 83 | } 84 | if let optSyntax = type.as (OptionalTypeSyntax.self) { 85 | type = optSyntax.wrappedType 86 | } 87 | guard let typeName = type.as (IdentifierTypeSyntax.self)?.name.text else { 88 | throw GodotMacroError.unsupportedType(varDecl) 89 | } 90 | let exportAttr = varDecl.attributes.first?.as(AttributeSyntax.self) 91 | let lel = exportAttr?.arguments?.as(LabeledExprListSyntax.self) 92 | let f = lel?.first?.expression.as(MemberAccessExprSyntax.self)?.declName 93 | 94 | let s = lel?.dropFirst().first 95 | 96 | for singleVar in varDecl.bindings { 97 | guard let ips = singleVar.pattern.as(IdentifierPatternSyntax.self) else { 98 | throw GodotMacroError.expectedIdentifier(singleVar) 99 | } 100 | let varName = ips.identifier.text 101 | let setterName = "_mproxy_set_\(varName)" 102 | let getterName = "_mproxy_get_\(varName)" 103 | 104 | if let accessors = last.accessorBlock { 105 | if accessors.as (CodeBlockSyntax.self) != nil { 106 | throw MacroError.propertyGetSet 107 | } 108 | if let block = accessors.as (AccessorBlockSyntax.self) { 109 | var hasSet = false 110 | var hasGet = false 111 | switch block.accessors { 112 | case .accessors(let list): 113 | for accessor in list { 114 | switch accessor.accessorSpecifier.tokenKind { 115 | case .keyword(let val): 116 | switch val { 117 | case .didSet, .willSet: 118 | hasSet = true 119 | hasGet = true 120 | case .set: 121 | hasSet = true 122 | case .get: 123 | hasGet = true 124 | default: 125 | break 126 | } 127 | default: 128 | break 129 | } 130 | } 131 | default: 132 | throw MacroError.propertyGetSet 133 | } 134 | 135 | if hasSet == false || hasGet == false { 136 | throw MacroError.propertyGetSet 137 | } 138 | } 139 | } 140 | let propType = godotTypeToProp (typeName: typeName) 141 | let pinfo = "_p\(varName)" 142 | ctor.append ( 143 | """ 144 | let \(pinfo) = PropInfo ( 145 | propertyType: \(propType), 146 | propertyName: "\(varName)", 147 | className: className, 148 | hint: .\(f?.description ?? "none"), 149 | hintStr: \(s?.description ?? "\"\""), 150 | usage: .propertyUsageDefault) 151 | 152 | """) 153 | 154 | ctor.append("\tclassInfo.registerMethod (name: \"\(getterName)\", flags: .default, returnValue: \(pinfo), arguments: [], function: \(className).\(getterName))\n") 155 | ctor.append("\tclassInfo.registerMethod (name: \"\(setterName)\", flags: .default, returnValue: nil, arguments: [\(pinfo)], function: \(className).\(setterName))\n") 156 | ctor.append("\tclassInfo.registerProperty (\(pinfo), getter: \"\(getterName)\", setter: \"\(setterName)\")") 157 | } 158 | } 159 | 160 | var ctor: String = "" 161 | var genMethods: [String] = [] 162 | 163 | func processType () throws -> String { 164 | ctor = 165 | """ 166 | static func _initClass () { 167 | let className = StringName("\(className)") 168 | let classInfo = ClassInfo<\(className)> (name: className)\n 169 | """ 170 | for member in classDecl.memberBlock.members.enumerated() { 171 | let decl = member.element.decl 172 | if let funcDecl = decl.as(FunctionDeclSyntax.self) { 173 | try processFunction (funcDecl) 174 | } 175 | else if let varDecl = decl.as (VariableDeclSyntax.self) { 176 | try processVariable (varDecl) 177 | } 178 | } 179 | ctor.append("}") 180 | return ctor 181 | } 182 | 183 | } 184 | 185 | /// 186 | /// The Godot macro is applied to a class and it generates the boilerplate 187 | /// `init(nativeHandle:)` and `init()` constructors along with the 188 | /// static class initializer for any exported properties and methods. 189 | /// 190 | public struct GodotMacro: MemberMacro { 191 | 192 | public static func expansion(of node: AttributeSyntax, 193 | providingMembersOf declaration: some DeclGroupSyntax, 194 | in context: some MacroExpansionContext) throws -> [DeclSyntax] { 195 | 196 | guard let classDecl = declaration.as(ClassDeclSyntax.self) else { 197 | let classError = Diagnostic(node: declaration.root, message: GodotMacroError.requiresClass) 198 | context.diagnose(classError) 199 | return [] 200 | } 201 | 202 | let processor = GodotMacroProcessor(classDecl: classDecl) 203 | do { 204 | let classInit = try processor.processType () 205 | let initRawHandleSyntax = try InitializerDeclSyntax("required init(nativeHandle _: UnsafeRawPointer)") { 206 | StmtSyntax("\n\tfatalError(\"init(nativeHandle:) called, it is a sign that something is wrong, as these objects should not be re-hydrated\")") 207 | } 208 | let initSyntax = try InitializerDeclSyntax("required init()") { 209 | StmtSyntax("\n\t\(classDecl.name)._initClass ()\n\tsuper.init ()") 210 | } 211 | 212 | return [DeclSyntax (initRawHandleSyntax), DeclSyntax (initSyntax), DeclSyntax(stringLiteral: classInit)] 213 | } catch { 214 | let diagnostic: Diagnostic 215 | if let detail = error as? GodotMacroError { 216 | diagnostic = Diagnostic(node: declaration.root, message: detail) 217 | } else { 218 | diagnostic = Diagnostic(node: declaration.root, message: GodotMacroError.unknownError(error)) 219 | } 220 | context.diagnose(diagnostic) 221 | return [] 222 | } 223 | } 224 | } 225 | 226 | @main 227 | struct godotMacrosPlugin: CompilerPlugin { 228 | let providingMacros: [Macro.Type] = [ 229 | GodotMacro.self, 230 | GodotCallable.self, 231 | GodotExport.self 232 | ] 233 | } 234 | -------------------------------------------------------------------------------- /Sources/SwiftGodotMacroLibrary/MacroSharedApi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Miguel de Icaza on 9/25/23. 6 | // 7 | 8 | import Foundation 9 | import SwiftCompilerPlugin 10 | import SwiftDiagnostics 11 | import SwiftSyntax 12 | import SwiftSyntaxBuilder 13 | import SwiftSyntaxMacros 14 | 15 | 16 | // Given a TypeSyntax, returns the type and whether it is an optional type or not 17 | func getIdentifier (_ x: TypeSyntax?) -> (String, Bool)? { 18 | guard var x else { return nil } 19 | var opt = false 20 | if let optSyntax = x.as (OptionalTypeSyntax.self) { 21 | x = optSyntax.wrappedType 22 | opt = true 23 | } 24 | if let txt = x.as (IdentifierTypeSyntax.self)?.name.text { 25 | return (txt, opt) 26 | } 27 | return nil 28 | } 29 | 30 | enum GodotMacroError: Error, DiagnosticMessage { 31 | case requiresClass 32 | case requiresVar 33 | case requiresFunction 34 | case noVariablesFound 35 | case noTypeFound(VariableDeclSyntax) 36 | case unsupportedType(VariableDeclSyntax) 37 | case expectedIdentifier(PatternBindingListSyntax.Element) 38 | case unknownError(Error) 39 | 40 | var severity: DiagnosticSeverity { 41 | return .error 42 | } 43 | 44 | var message: String { 45 | switch self { 46 | case .requiresClass: 47 | "@Godot attribute can only be applied to a class" 48 | case .requiresVar: 49 | "@Export attribute can only be applied to variables" 50 | case .requiresFunction: 51 | "@Callable attribute can only be applied to functions" 52 | case .noVariablesFound: 53 | "@Export no variables found" 54 | case .noTypeFound(let v): 55 | "@Export no type was found \(v)" 56 | case .unsupportedType (let v): 57 | "@Export the type \(v) is not supported" 58 | case .expectedIdentifier(let e): 59 | "@Export expected an identifier, instead got \(e)" 60 | case .unknownError(let e): 61 | "Unknown nested error processing this directive: \(e)" 62 | } 63 | } 64 | 65 | var diagnosticID: MessageID { 66 | MessageID(domain: "SwiftGodotMacros", id: message) 67 | } 68 | } 69 | 70 | enum MacroError: Error { 71 | case typeName(FunctionParameterSyntax) 72 | case missingParameterName(FunctionParameterSyntax) 73 | case noVariablesFound(VariableDeclSyntax) 74 | case noTypeFound(VariableDeclSyntax) 75 | case unsupportedType(VariableDeclSyntax) 76 | case propertyGetSet 77 | var localizedDescription: String { 78 | switch self { 79 | case .typeName (let p): 80 | return "Could not lookup the typename \(p)" 81 | case .missingParameterName(let p): 82 | return "Missing a parameter name \(p)" 83 | case .noVariablesFound(let v): 84 | return "No variables were found on \(v)" 85 | case .noTypeFound(let v): 86 | return "No type was found \(v)" 87 | case .unsupportedType(let v): 88 | return "This type is not supported in the macro binding \(v)" 89 | case .propertyGetSet: 90 | return "Properties exported to Godot must be readable and writable" 91 | } 92 | } 93 | } 94 | 95 | /// Returns true if the declarartion has the '@name' attribute 96 | func hasAttribute (_ name: String, _ attrs: AttributeListSyntax?) -> Bool { 97 | guard let attrs else { return false } 98 | let match = attrs.contains { 99 | guard case let .attribute(attribute) = $0 else { 100 | return false 101 | } 102 | if attribute.attributeName.as (IdentifierTypeSyntax.self)?.name.text == name { 103 | return true 104 | } 105 | return false 106 | } 107 | return match 108 | } 109 | 110 | /// True if the attribtue list syntax has an attribute name 'Export' 111 | func hasExportAttribute (_ attrs: AttributeListSyntax?) -> Bool { 112 | hasAttribute ("Export", attrs) 113 | } 114 | 115 | /// True if the attribtue list syntax has an attribute name 'Callable' 116 | func hasCallableAttribute (_ attrs: AttributeListSyntax?) -> Bool { 117 | hasAttribute ("Callable", attrs) 118 | } 119 | 120 | func getTypeName (_ parameter: FunctionParameterSyntax) -> String? { 121 | guard let typeName = parameter.type.as (IdentifierTypeSyntax.self)?.name.text else { 122 | return nil 123 | } 124 | return typeName 125 | } 126 | 127 | var godotVariants = [ 128 | "Int": ".int", 129 | "Float": ".float", 130 | "Double": ".float", 131 | "Bool": ".bool", 132 | "AABB": ".aabb", 133 | "Array": ".array", 134 | "Basis": ".basis", 135 | "Callable": ".callable", 136 | "Color": ".color", 137 | "GDictionary": ".dictionary", 138 | "Nil": ".nil", 139 | "NodePath": ".nodePath", 140 | "PackedByteArray": ".packedByteArray", 141 | "PackedColorArray": ".packedColorArray", 142 | "PackedFloat32Array": ".packedFloat32Array", 143 | "PackedFloat64Array": ".packedFloat64Array", 144 | "PackedInt32Array": ".packedInt32Array", 145 | "PackedInt64Array": ".packedInt64Array", 146 | "PackedStringArray": ".packedStringArray", 147 | "PackedVector2Array": ".packedVector2Array", 148 | "PackedVector3Array": ".packedVector3Array", 149 | "Plane": ".plane", 150 | "Projection": ".projection", 151 | "Quaternion": ".quaternion", 152 | "RID": ".rid", 153 | "Rect2": ".rect2", 154 | "Rect2i": ".rect2i", 155 | "Signal": ".signal", 156 | "String": ".string", 157 | "StringName": ".stringName", 158 | "Transform2D": ".transform2d", 159 | "Transform3D": ".transform3d", 160 | "Vector2": ".vector2", 161 | "Vector2i": ".vector2i", 162 | "Vector3": ".vector3", 163 | "Vector3i": ".vector3i", 164 | "Vector4": ".vector4", 165 | "Vector4i": ".vector4i", 166 | ] 167 | 168 | func godotTypeToProp (typeName: String) -> String { 169 | godotVariants [typeName] ?? ".object" 170 | } 171 | 172 | -------------------------------------------------------------------------------- /Sources/SwiftGodotMacros/MacroDefs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Miguel de Icaza on 9/25/23. 6 | // 7 | 8 | import Foundation 9 | import SwiftGodot 10 | 11 | @attached(member, 12 | names: named (init(nativeHandle:)), named (init()), named(_initClass), arbitrary) 13 | public macro Godot() = #externalMacro(module: "SwiftGodotMacroLibrary", type: "GodotMacro") 14 | 15 | @attached(peer, names: prefixed(_mproxy_)) 16 | public macro Callable() = #externalMacro(module: "SwiftGodotMacroLibrary", type: "GodotCallable") 17 | 18 | @attached(peer, names: prefixed(_mproxy_get_), prefixed(_mproxy_set_), arbitrary) 19 | public macro Export(_ hint: PropertyHint = .none, _ hintStr: String? = nil) = #externalMacro(module: "SwiftGodotMacroLibrary", type: "GodotExport") 20 | 21 | --------------------------------------------------------------------------------