Files
luma/Sources/LumaCore/Patterns/Engine+Patterns.swift
Ole André Vadla Ravnås 69c706789f Follow the pattern compiler's module API
Compile, then decode through the module. Pass platform before arch,
and default both to the host rather than darwin/arm64.
2026-10-01 20:49:11 +02:00

72 lines
2.5 KiB
Swift

import Foundation
public struct PatternMemoryDecoding: Sendable {
public let value: DecodedPattern
public let data: Data
}
public enum PatternMemoryError: LocalizedError {
case detached
public var errorDescription: String? {
switch self {
case .detached:
return "The session is not attached."
}
}
}
extension Engine {
public static let largestPatternRead = 1 << 20
public func describePatternLibrary() async -> [[String: Any]] {
var described: [[String: Any]] = []
for source in patterns.sources {
var entry: [String: Any] = ["id": source.id, "name": source.name, "kind": source.kind == .library ? "library" : "pattern"]
if let summary = try? await patternDecoder.summary(of: source) {
entry.merge(summary.jsonObject) { _, new in new }
}
described.append(entry)
}
return described
}
public func decodePattern(
text: String, typeName: String, sessionID: UUID, address: UInt64, byteCount: Int
) async throws -> PatternMemoryDecoding {
guard let node = node(forSessionID: sessionID), let target = node.processInfo else {
throw PatternMemoryError.detached
}
var data = Data(try await node.readRemoteMemory(at: address, count: byteCount))
while true {
let value = try await patternDecoder.decode(
text: text, typeName: typeName, data: data, address: address, platform: target.platform, arch: target.arch)
guard value.truncated, data.count < Self.largestPatternRead,
let more = try? await node.readRemoteMemory(at: address, count: min(data.count * 2, Self.largestPatternRead))
else {
return PatternMemoryDecoding(value: value, data: data)
}
data = Data(more)
}
}
}
extension PatternSummary {
public var jsonObject: [String: Any] {
var object: [String: Any] = [
"types": declaredTypes.map { type -> [String: Any] in
var entry: [String: Any] = ["name": type.name, "kind": "\(type.kind)"]
if let size = type.size {
entry["size"] = size
}
return entry
},
"diagnostics": diagnostics.map { ["line": $0.line + 1, "column": $0.character + 1, "message": $0.message] },
]
if let rootType {
object["root_type"] = rootType
}
return object
}
}