1use std::collections::BTreeMap;
2use std::rc::Rc;
3use std::sync::atomic::Ordering;
4use std::{cell::RefCell, future::Future, pin::Pin};
5
6use crate::mcp::VmMcpClientHandle;
7
8use super::{VmAtomicHandle, VmChannelHandle, VmClosure, VmError, VmGenerator, VmRange};
9
10pub type VmAsyncBuiltinFn =
12 Rc<dyn Fn(Vec<VmValue>) -> Pin<Box<dyn Future<Output = Result<VmValue, VmError>>>>>;
13
14#[derive(Debug, Clone)]
16pub enum VmValue {
17 Int(i64),
18 Float(f64),
19 String(Rc<str>),
20 Bytes(Rc<Vec<u8>>),
21 Bool(bool),
22 Nil,
23 List(Rc<Vec<VmValue>>),
24 Dict(Rc<BTreeMap<String, VmValue>>),
25 Closure(Rc<VmClosure>),
26 BuiltinRef(Rc<str>),
30 Duration(u64),
31 EnumVariant {
32 enum_name: String,
33 variant: String,
34 fields: Vec<VmValue>,
35 },
36 StructInstance {
37 struct_name: String,
38 fields: BTreeMap<String, VmValue>,
39 },
40 TaskHandle(String),
41 Channel(VmChannelHandle),
42 Atomic(VmAtomicHandle),
43 McpClient(VmMcpClientHandle),
44 Set(Rc<Vec<VmValue>>),
45 Generator(VmGenerator),
46 Range(VmRange),
47 Iter(Rc<RefCell<crate::vm::iter::VmIter>>),
49 Pair(Rc<(VmValue, VmValue)>),
54}
55
56impl VmValue {
57 pub fn is_truthy(&self) -> bool {
58 match self {
59 VmValue::Bool(b) => *b,
60 VmValue::Nil => false,
61 VmValue::Int(n) => *n != 0,
62 VmValue::Float(n) => *n != 0.0,
63 VmValue::String(s) => !s.is_empty(),
64 VmValue::Bytes(bytes) => !bytes.is_empty(),
65 VmValue::List(l) => !l.is_empty(),
66 VmValue::Dict(d) => !d.is_empty(),
67 VmValue::Closure(_) => true,
68 VmValue::BuiltinRef(_) => true,
69 VmValue::Duration(ms) => *ms > 0,
70 VmValue::EnumVariant { .. } => true,
71 VmValue::StructInstance { .. } => true,
72 VmValue::TaskHandle(_) => true,
73 VmValue::Channel(_) => true,
74 VmValue::Atomic(_) => true,
75 VmValue::McpClient(_) => true,
76 VmValue::Set(s) => !s.is_empty(),
77 VmValue::Generator(_) => true,
78 VmValue::Range(_) => true,
81 VmValue::Iter(_) => true,
82 VmValue::Pair(_) => true,
83 }
84 }
85
86 pub fn type_name(&self) -> &'static str {
87 match self {
88 VmValue::String(_) => "string",
89 VmValue::Bytes(_) => "bytes",
90 VmValue::Int(_) => "int",
91 VmValue::Float(_) => "float",
92 VmValue::Bool(_) => "bool",
93 VmValue::Nil => "nil",
94 VmValue::List(_) => "list",
95 VmValue::Dict(_) => "dict",
96 VmValue::Closure(_) => "closure",
97 VmValue::BuiltinRef(_) => "builtin",
98 VmValue::Duration(_) => "duration",
99 VmValue::EnumVariant { .. } => "enum",
100 VmValue::StructInstance { .. } => "struct",
101 VmValue::TaskHandle(_) => "task_handle",
102 VmValue::Channel(_) => "channel",
103 VmValue::Atomic(_) => "atomic",
104 VmValue::McpClient(_) => "mcp_client",
105 VmValue::Set(_) => "set",
106 VmValue::Generator(_) => "generator",
107 VmValue::Range(_) => "range",
108 VmValue::Iter(_) => "iter",
109 VmValue::Pair(_) => "pair",
110 }
111 }
112
113 pub fn display(&self) -> String {
114 let mut out = String::new();
115 self.write_display(&mut out);
116 out
117 }
118
119 pub fn write_display(&self, out: &mut String) {
122 use std::fmt::Write;
123
124 match self {
125 VmValue::Int(n) => {
126 let _ = write!(out, "{n}");
127 }
128 VmValue::Float(n) => {
129 if *n == (*n as i64) as f64 && n.abs() < 1e15 {
130 let _ = write!(out, "{n:.1}");
131 } else {
132 let _ = write!(out, "{n}");
133 }
134 }
135 VmValue::String(s) => out.push_str(s),
136 VmValue::Bytes(bytes) => {
137 const MAX_PREVIEW_BYTES: usize = 32;
138
139 out.push_str("b\"");
140 for byte in bytes.iter().take(MAX_PREVIEW_BYTES) {
141 let _ = write!(out, "{byte:02x}");
142 }
143 if bytes.len() > MAX_PREVIEW_BYTES {
144 let _ = write!(out, "...+{}", bytes.len() - MAX_PREVIEW_BYTES);
145 }
146 out.push('"');
147 }
148 VmValue::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
149 VmValue::Nil => out.push_str("nil"),
150 VmValue::List(items) => {
151 out.push('[');
152 for (i, item) in items.iter().enumerate() {
153 if i > 0 {
154 out.push_str(", ");
155 }
156 item.write_display(out);
157 }
158 out.push(']');
159 }
160 VmValue::Dict(map) => {
161 out.push('{');
162 for (i, (k, v)) in map.iter().enumerate() {
163 if i > 0 {
164 out.push_str(", ");
165 }
166 out.push_str(k);
167 out.push_str(": ");
168 v.write_display(out);
169 }
170 out.push('}');
171 }
172 VmValue::Closure(c) => {
173 let _ = write!(out, "<fn({})>", c.func.params.join(", "));
174 }
175 VmValue::BuiltinRef(name) => {
176 let _ = write!(out, "<builtin {name}>");
177 }
178 VmValue::Duration(ms) => {
179 if *ms >= 3_600_000 && ms % 3_600_000 == 0 {
180 let _ = write!(out, "{}h", ms / 3_600_000);
181 } else if *ms >= 60_000 && ms % 60_000 == 0 {
182 let _ = write!(out, "{}m", ms / 60_000);
183 } else if *ms >= 1000 && ms % 1000 == 0 {
184 let _ = write!(out, "{}s", ms / 1000);
185 } else {
186 let _ = write!(out, "{}ms", ms);
187 }
188 }
189 VmValue::EnumVariant {
190 enum_name,
191 variant,
192 fields,
193 } => {
194 if fields.is_empty() {
195 let _ = write!(out, "{enum_name}.{variant}");
196 } else {
197 let _ = write!(out, "{enum_name}.{variant}(");
198 for (i, v) in fields.iter().enumerate() {
199 if i > 0 {
200 out.push_str(", ");
201 }
202 v.write_display(out);
203 }
204 out.push(')');
205 }
206 }
207 VmValue::StructInstance {
208 struct_name,
209 fields,
210 } => {
211 let _ = write!(out, "{struct_name} {{");
212 for (i, (k, v)) in fields.iter().enumerate() {
213 if i > 0 {
214 out.push_str(", ");
215 }
216 out.push_str(k);
217 out.push_str(": ");
218 v.write_display(out);
219 }
220 out.push('}');
221 }
222 VmValue::TaskHandle(id) => {
223 let _ = write!(out, "<task:{id}>");
224 }
225 VmValue::Channel(ch) => {
226 let _ = write!(out, "<channel:{}>", ch.name);
227 }
228 VmValue::Atomic(a) => {
229 let _ = write!(out, "<atomic:{}>", a.value.load(Ordering::SeqCst));
230 }
231 VmValue::McpClient(c) => {
232 let _ = write!(out, "<mcp_client:{}>", c.name);
233 }
234 VmValue::Set(items) => {
235 out.push_str("set(");
236 for (i, item) in items.iter().enumerate() {
237 if i > 0 {
238 out.push_str(", ");
239 }
240 item.write_display(out);
241 }
242 out.push(')');
243 }
244 VmValue::Generator(g) => {
245 if g.done.get() {
246 out.push_str("<generator (done)>");
247 } else {
248 out.push_str("<generator>");
249 }
250 }
251 VmValue::Range(r) => {
254 let _ = write!(out, "{} to {}", r.start, r.end);
255 if !r.inclusive {
256 out.push_str(" exclusive");
257 }
258 }
259 VmValue::Iter(h) => {
260 if matches!(&*h.borrow(), crate::vm::iter::VmIter::Exhausted) {
261 out.push_str("<iter (exhausted)>");
262 } else {
263 out.push_str("<iter>");
264 }
265 }
266 VmValue::Pair(p) => {
267 out.push('(');
268 p.0.write_display(out);
269 out.push_str(", ");
270 p.1.write_display(out);
271 out.push(')');
272 }
273 }
274 }
275
276 pub fn as_dict(&self) -> Option<&BTreeMap<String, VmValue>> {
278 if let VmValue::Dict(d) = self {
279 Some(d)
280 } else {
281 None
282 }
283 }
284
285 pub fn as_int(&self) -> Option<i64> {
286 if let VmValue::Int(n) = self {
287 Some(*n)
288 } else {
289 None
290 }
291 }
292
293 pub fn as_bytes(&self) -> Option<&[u8]> {
294 if let VmValue::Bytes(bytes) = self {
295 Some(bytes.as_slice())
296 } else {
297 None
298 }
299 }
300}
301
302pub type VmBuiltinFn = Rc<dyn Fn(&[VmValue], &mut String) -> Result<VmValue, VmError>>;