///|
/// Python's `str` and `repr` of a value.
///
/// The two differ in exactly one place -- a string is itself under `str` and
/// quoted under `repr` -- and `print` uses `str` while a container prints its
/// elements with `repr`. Everything else is the same function.
///
/// A closure, a module, a class or a primitive has no printable form here.
/// Python prints one with an address in it, which no implementation can
/// reproduce, so printing one is an undefined operation and is reported as
/// such rather than invented.
pub fn Value::str(self : Value) -> String? {
match self {
Str(s) => Some(s)
other => other.repr()
}
}
///|
pub fn Value::repr(self : Value) -> String? {
match self {
None => Some("None")
Bool(b) => Some(if b { "True" } else { "False" })
Int(n) => Some(n.to_string())
Float(d) => Some(@basic.py_float_repr(d))
Str(s) => Some(@basic.py_repr(s))
List(xs) => bracketed(xs, "[", "]", trailing_comma=false)
// A one-element tuple keeps its comma: `('x',)`.
Tuple(xs) => bracketed(xs, "(", ")", trailing_comma=xs.length() == 1)
Dict(entries) => {
let out = StringBuilder()
out.write_string("{")
for i, e in entries {
if i > 0 {
out.write_string(", ")
}
out.write_string(@basic.py_repr(e.0))
out.write_string(": ")
match e.1.repr() {
Some(t) => out.write_string(t)
None => return None
}
}
out.write_string("}")
Some(out.to_string())
}
// `P(x=1, y='a')`: the class's short name and every field, inherited
// first, which is the order `fields` gives them.
Obj(entry, env) => {
let out = StringBuilder()
out.write_string(entry.short_name())
out.write_string("(")
for i, x in entry.fields() {
if i > 0 {
out.write_string(", ")
}
out.write_string(x)
out.write_string("=")
match env.get(x) {
Some(v) =>
match v.repr() {
Some(t) => out.write_string(t)
None => return None
}
None => return None
}
}
out.write_string(")")
Some(out.to_string())
}
_ => None
}
}
///|
fn bracketed(
xs : Array[Value],
open : String,
close : String,
trailing_comma~ : Bool,
) -> String? {
let out = StringBuilder()
out.write_string(open)
for i, v in xs {
if i > 0 {
out.write_string(", ")
}
match v.repr() {
Some(t) => out.write_string(t)
None => return None
}
}
if trailing_comma {
out.write_string(",")
}
out.write_string(close)
Some(out.to_string())
}