about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-12-19T09·58+0300
committertazjin <tazjin@tvl.su>2022-12-22T19·09+0000
commite306d1d1a1cf5068277b774f586fc22e05dd671f (patch)
tree512e70edc6e706c913d77b7f2f461eed4e796fc1
parentea7d63e177d8a951e30bc00918081eb069e2efb2 (diff)
feat(tvix/eval): add Value::explain method r/5475
This value creates a human-readable explanation of a value. This can
be used to implement documentation related functionality.

For some values, the amount of information displayed can be expanded
quite a bit.

Change-Id: Ie8c400feae909e7680af163596f99060262e4241
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7592
Reviewed-by: grfn <grfn@gws.fyi>
Tested-by: BuildkiteCI
-rw-r--r--tvix/eval/src/value/mod.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs
index 3e59c19c3196..711ffcc6f78f 100644
--- a/tvix/eval/src/value/mod.rs
+++ b/tvix/eval/src/value/mod.rs
@@ -433,6 +433,39 @@ impl Value {
             }
         }
     }
+
+    /// Explain a value in a human-readable way, e.g. by presenting
+    /// the docstrings of functions if present.
+    pub fn explain(&self) -> String {
+        match self {
+            Value::Null => "the 'null' value".into(),
+            Value::Bool(b) => format!("the boolean value '{}'", b),
+            Value::Integer(i) => format!("the integer '{}'", i),
+            Value::Float(f) => format!("the float '{}'", f),
+            Value::String(s) => format!("the string '{}'", s),
+            Value::Path(p) => format!("the path '{}'", p.to_string_lossy()),
+            Value::Attrs(attrs) => format!("a {}-item attribute set", attrs.len()),
+            Value::List(list) => format!("a {}-item list", list.len()),
+            Value::Closure(_f) => format!("a user-defined Nix function"), // TODO: name, loc, etc.
+
+            Value::Builtin(b) => {
+                let mut out = format!("the builtin function '{}'", b.name());
+                if let Some(docs) = b.documentation() {
+                    out.push_str("\n\n");
+                    out.push_str(docs);
+                }
+                out
+            }
+
+            // TODO: handle suspended thunks with a different explanation instead of panicking
+            Value::Thunk(t) => t.value().explain(),
+
+            Value::AttrNotFound
+            | Value::Blueprint(_)
+            | Value::DeferredUpvalue(_)
+            | Value::UnresolvedPath(_) => "an internal Tvix evaluator value".into(),
+        }
+    }
 }
 
 trait TotalDisplay {