Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions Sources/SWBMacro/MacroNamespace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,17 @@ public final class MacroNamespace: CustomDebugStringConvertible, Encodable, Send
/// Descriptive label, for diagnostic purposes.
public let debugDescription: String

/// Looks up and returns the macro declaration that's associated with name, if any. The name is not allowed to be the empty string.
/// Looks up and returns the macro declaration that's associated with 'name', if any. The name is not allowed to be the empty string.
public func lookupMacroDeclaration(_ name: String) -> MacroDeclaration? {
return macroRegistry.withLock { macroRegistry in
return _lookupMacroDeclarationUnlocked(name, in: macroRegistry)
precondition(name != "")
var currentNamespace: MacroNamespace? = self
while let namespace = currentNamespace {
if let macroDecl = namespace.macroRegistry.withLock({ $0[name] }) {
return macroDecl
}
currentNamespace = namespace.parentNamespace
}
return nil
}

/// Perform an unlocked macro lookup.
Expand Down Expand Up @@ -137,11 +143,17 @@ public final class MacroNamespace: CustomDebugStringConvertible, Encodable, Send
/// Maps condition parameter names to condition parameters. Each declaration is an instance of MacroConditionParameter.
private let conditionParameters = LockedValue<Dictionary<String,MacroConditionParameter>>([:])

/// Looks up and returns the macro condition parameter that's associated with name, if any. The name is not allowed to be the empty string.
/// Looks up and returns the macro condition parameter that's associated with 'name', if any. The name is not allowed to be the empty string.
public func lookupConditionParameter(_ name: String) -> MacroConditionParameter? {
conditionParameters.withLock { conditionParameters in
_lookupConditionParameterUnlocked(name, in: conditionParameters)
precondition(name != "")
var currentNamespace: MacroNamespace? = self
while let namespace = currentNamespace {
if let condParam = namespace.conditionParameters.withLock({ $0[name] }) {
return condParam
}
currentNamespace = namespace.parentNamespace
}
return nil
}

private func _lookupConditionParameterUnlocked(_ name: String, in conditionParameters: [String: MacroConditionParameter]) -> MacroConditionParameter? {
Expand Down
27 changes: 27 additions & 0 deletions Tests/SWBMacroTests/MacroBasicTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,32 @@ import SWBMacro
let middleLookedupCondParam = middleNamespace.lookupConditionParameter("upper")
#expect(middleLookedupCondParam == nil)
}

@Test
func deepNamespaceHierarchy() throws {
let depth = 600
var namespaces: [MacroNamespace] = []

let root = MacroNamespace(debugDescription: "root")
let rootMacro = try root.declareStringMacro("ROOT_MACRO")
namespaces.append(root)

for i in 1..<depth {
let parent = namespaces[i - 1]
let child = MacroNamespace(parent: parent, debugDescription: "namespace_\(i)")
namespaces.append(child)
}

let deepest = namespaces[depth - 1]
let lookedUp = deepest.lookupMacroDeclaration("ROOT_MACRO")
#expect(lookedUp === rootMacro)

let nonExistent = deepest.lookupMacroDeclaration("NON_EXISTENT_MACRO")
#expect(nonExistent == nil)

let rootCondParam = root.declareConditionParameter("rootCond")
let lookedUpCondParam = deepest.lookupConditionParameter("rootCond")
#expect(lookedUpCondParam === rootCondParam)
}
}

Loading