From 038aca797c0a347e686d5b122b4fd8e201fd40b2 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 26 Aug 2026 09:00:00 +0200 Subject: [PATCH] feat(printer): add write and display formatting --- Sources/KiteCore/Printer.swift | 92 ++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Sources/KiteCore/Printer.swift diff --git a/Sources/KiteCore/Printer.swift b/Sources/KiteCore/Printer.swift new file mode 100644 index 0000000..4344bc1 --- /dev/null +++ b/Sources/KiteCore/Printer.swift @@ -0,0 +1,92 @@ +public func displayString(_ value: Value) -> String { + render(value, write: false) +} + +public func writeString(_ value: Value) -> String { + render(value, write: true) +} + +func formatReal(_ d: Double) -> String { + if d.isNaN { return "+nan.0" } + if d.isInfinite { return d > 0 ? "+inf.0" : "-inf.0" } + if d == d.rounded() && abs(d) < 1e15 { + return String(format: "%.1f", d) + } + return String(d) +} + +private func render(_ value: Value, write: Bool) -> String { + switch value { + case .null: + return "()" + case .bool(let b): + return b ? "#t" : "#f" + case .integer(let n): + return String(n) + case .rational(let n, let d): + return "\(n)/\(d)" + case .real(let d): + return formatReal(d) + case .char(let c): + if write { return writeChar(c) } + return String(c) + case .string(let s): + if write { return "\"" + escapeString(s) + "\"" } + return s + case .symbol(let s): + return baseName(s) + case .pair: + return renderList(value, write: write) + case .builtin(let b): + return "#" + case .closure(let l): + return "#" + case .continuation: + return "#" + case .syntax: + return "#" + case .unspecified: + return "" + case .eof: + return "#" + } +} + +private func renderList(_ value: Value, write: Bool) -> String { + var parts: [String] = [] + var cur = value + while case .pair(let p) = cur { + parts.append(render(p.car, write: write)) + cur = p.cdr + } + if case .null = cur { + return "(" + parts.joined(separator: " ") + ")" + } + return "(" + parts.joined(separator: " ") + " . " + render(cur, write: write) + ")" +} + +private func writeChar(_ c: Character) -> String { + switch c { + case " ": return "#\\space" + case "\n": return "#\\newline" + case "\t": return "#\\tab" + case "\r": return "#\\return" + case "\u{0}": return "#\\null" + default: return "#\\\(c)" + } +} + +private func escapeString(_ s: String) -> String { + var out = "" + for c in s { + switch c { + case "\"": out += "\\\"" + case "\\": out += "\\\\" + case "\n": out += "\\n" + case "\t": out += "\\t" + case "\r": out += "\\r" + default: out.append(c) + } + } + return out +}