feat(printer): add write and display formatting
This commit is contained in:
1 parent
e101bbcfef
commit
038aca797c
1 file changed
+92
@@ -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 "#<procedure:\(b.name)>"
|
||||||
|
case .closure(let l):
|
||||||
|
return "#<procedure:\(l.name)>"
|
||||||
|
case .continuation:
|
||||||
|
return "#<continuation>"
|
||||||
|
case .syntax:
|
||||||
|
return "#<syntax>"
|
||||||
|
case .unspecified:
|
||||||
|
return ""
|
||||||
|
case .eof:
|
||||||
|
return "#<eof>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in new issue
Block a user