From d9f67033b6ce8e2ce81a1d0691ed9c029c5029de Mon Sep 17 00:00:00 2001 From: Brendan Szymanski Date: Wed, 1 Jul 2026 13:36:01 -0400 Subject: [PATCH] Capture interface functions and record fields correctly in parser --- Sources/SwiftGtkGenCore/IRModel.swift | 8 ++++++-- Sources/SwiftGtkGenCore/XMLParser.swift | 12 ++++++++--- Tests/SwiftGtkGenCoreTests/ParserTests.swift | 21 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftGtkGenCore/IRModel.swift b/Sources/SwiftGtkGenCore/IRModel.swift index 0e28946..74b99e8 100644 --- a/Sources/SwiftGtkGenCore/IRModel.swift +++ b/Sources/SwiftGtkGenCore/IRModel.swift @@ -154,6 +154,9 @@ public struct Interface { public var properties: [Property] /// The signals declared by this interface. public var signals: [Signal] + /// The functions associated with this interface (namespace-level `` + /// elements that reference the interface's type). + public var functions: [GlobalFunction] /// The prerequisite types a class must satisfy to implement this interface. public var prereqs: [String] /// Creates a new interface definition. @@ -163,12 +166,13 @@ public struct Interface { /// - methods: The methods declared by the interface. Defaults to empty. /// - properties: The properties declared by the interface. Defaults to empty. /// - signals: The signals declared by the interface. Defaults to empty. + /// - functions: The functions associated with this interface. Defaults to empty. /// - prereqs: The prerequisite types. Defaults to empty. /// - doc: Documentation comment from the GIR XML. public init(name: String, cType: String, methods: [Method] = [], properties: [Property] = [], - signals: [Signal] = [], prereqs: [String] = [], doc: String? = nil) { + signals: [Signal] = [], functions: [GlobalFunction] = [], prereqs: [String] = [], doc: String? = nil) { self.name = name; self.cType = cType; self.methods = methods - self.properties = properties; self.signals = signals; self.prereqs = prereqs + self.properties = properties; self.signals = signals; self.functions = functions; self.prereqs = prereqs self.doc = doc } } diff --git a/Sources/SwiftGtkGenCore/XMLParser.swift b/Sources/SwiftGtkGenCore/XMLParser.swift index 611bc53..ca25a15 100644 --- a/Sources/SwiftGtkGenCore/XMLParser.swift +++ b/Sources/SwiftGtkGenCore/XMLParser.swift @@ -259,7 +259,13 @@ final class GIRXMLDelegate: NSObject, XMLParserDelegate { currentText = "" break - case "virtual-method", "field", "parameters": + case "field": + guard let name = requireAttribute("name", from: attributeDict, for: elementName, parser: parser) else { return } + let isReadable = attributeDict["readable"] != "0" + let isWritable = attributeDict["writable"] == "1" + currentRecord?.fields.append(Field(name: name, type: .void, isReadable: isReadable, isWritable: isWritable)) + + case "virtual-method", "parameters": untrackedDepth += 1 default: @@ -347,7 +353,7 @@ final class GIRXMLDelegate: NSObject, XMLParserDelegate { currentRecord?.methods.append(Method(name: fn.name, cIdentifier: fn.cIdentifier, parameters: fn.parameters, returnType: fn.returnType)) } else if currentInterface != nil { - // Interface functions handled via interface methods + currentInterface?.functions.append(fn) } else { currentNamespace?.functions.append(fn) } @@ -394,7 +400,7 @@ final class GIRXMLDelegate: NSObject, XMLParserDelegate { if let a = currentAlias { currentNamespace?.aliases.append(a) } currentAlias = nil - case "virtual-method", "field", "parameters": + case "virtual-method", "parameters": untrackedDepth -= 1 case "doc": diff --git a/Tests/SwiftGtkGenCoreTests/ParserTests.swift b/Tests/SwiftGtkGenCoreTests/ParserTests.swift index fc9ca26..7c73cff 100644 --- a/Tests/SwiftGtkGenCoreTests/ParserTests.swift +++ b/Tests/SwiftGtkGenCoreTests/ParserTests.swift @@ -196,6 +196,27 @@ func testParsingMissingAttributes() { } } +@Test("Parser captures interface-level functions") +func testInterfaceFunctions() throws { + let xml = """ + + + + + + + + + + + """ + let repo = try GIRParser().parse(xmlString: xml) + let iface = repo.namespaces[0].interfaces[0] + #expect(iface.functions.count == 1) + #expect(iface.functions[0].name == "get_id") + #expect(iface.functions[0].cIdentifier == "gtk_buildable_get_id") +} + @Test("Parser rejects invalid XML") func testParsingError() { let parser = GIRParser()