// // ParseError.swift // Metrika // // Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // Copyright © 2026 Simon-Pierre Boucher. All rights reserved. // /// Parse failure with the 1-based source column and, where possible, a /// suggested fix (CLAUDE.md §4: errors must cite column position and /// suggest fixes via Levenshtein distance on known verbs). public struct ZQParseError: Error, Equatable, Sendable, CustomStringConvertible { public var message: String public var column: Int public var suggestion: String? public init(message: String, column: Int, suggestion: String? = nil) { self.message = message self.column = column self.suggestion = suggestion } public var description: String { var text = "parse error at column \(column): \(message)" if let suggestion { text += "\n did you mean '\(suggestion)'?" } return text } } /// Levenshtein edit distance, used to suggest the closest known verb for /// an unrecognized command. public func levenshteinDistance(_ a: String, _ b: String) -> Int { let a = Array(a), b = Array(b) if a.isEmpty { return b.count } if b.isEmpty { return a.count } var previous = Array(0...b.count) var current = [Int](repeating: 0, count: b.count + 1) for i in 1...a.count { current[0] = i for j in 1...b.count { let substitution = previous[j - 1] + (a[i - 1] == b[j - 1] ? 0 : 1) current[j] = min(previous[j] + 1, current[j - 1] + 1, substitution) } swap(&previous, ¤t) } return previous[b.count] }