1use std::io::{self, Write};
18use std::sync::{Arc, Mutex};
19
20use core_mumu::{
21 parser::interpreter::Interpreter,
22 parser::types::{FunctionValue, IteratorHandle, IteratorKind, PluginIterator, Value},
23};
24
25fn to_printable(v: &Value) -> String {
28 match v {
29 Value::SingleString(s) => s.clone(),
30 Value::Int(i) => i.to_string(),
31 Value::Long(l) => l.to_string(),
32 Value::Float(f) => f.to_string(),
33 Value::Bool(b) => b.to_string(),
34 _ => format!("{:?}", v),
36 }
37}
38
39fn escape_str(s: &str) -> String {
40 let mut out = String::with_capacity(s.len() + 8);
41 for ch in s.chars() {
42 match ch {
43 '\\' => out.push_str("\\\\"),
44 '"' => out.push_str("\\\""),
45 '\n' => out.push_str("\\n"),
46 '\r' => out.push_str("\\r"),
47 '\t' => out.push_str("\\t"),
48 other => out.push(other),
49 }
50 }
51 out
52}
53
54fn deep_to_string(v: &Value) -> String {
60 deep_to_string_inner(v, 0)
61}
62
63fn deep_to_string_inner(v: &Value, depth: usize) -> String {
64 if depth > 64 {
65 return "<depth-limit>".to_string();
66 }
67 match v {
68 Value::SingleString(s) => format!("\"{}\"", escape_str(s)),
69 Value::Int(i) => i.to_string(),
70 Value::Long(l) => l.to_string(),
71 Value::Float(f) => {
72 if f.fract() == 0.0 { format!("{:.1}", f) } else { f.to_string() }
73 }
74 Value::Bool(b) => b.to_string(),
75 Value::Undefined => "undefined".to_string(),
76 Value::Placeholder => "_".to_string(),
77
78 Value::IntArray(xs) => {
79 let inner = xs.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");
80 format!("[{}]", inner)
81 }
82 Value::FloatArray(xs) => {
83 let inner = xs.iter()
84 .map(|f| if f.fract()==0.0 { format!("{:.1}", f) } else { f.to_string() })
85 .collect::<Vec<_>>().join(", ");
86 format!("[{}]", inner)
87 }
88 Value::BoolArray(xs) => {
89 let inner = xs.iter().map(|b| b.to_string()).collect::<Vec<_>>().join(", ");
90 format!("[{}]", inner)
91 }
92 Value::StrArray(xs) => {
93 let inner = xs.iter().map(|s| format!("\"{}\"", escape_str(s))).collect::<Vec<_>>().join(", ");
94 format!("[{}]", inner)
95 }
96 Value::Int2DArray(rows) => {
97 let inner = rows.iter()
98 .map(|r| format!("[{}]", r.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ")))
99 .collect::<Vec<_>>().join(", ");
100 format!("[{}]", inner)
101 }
102 Value::Float2DArray(rows) => {
103 let fmt = |f: &f64| if f.fract()==0.0 { format!("{:.1}", f) } else { f.to_string() };
104 let inner = rows.iter()
105 .map(|r| format!("[{}]", r.iter().map(fmt).collect::<Vec<_>>().join(", ")))
106 .collect::<Vec<_>>().join(", ");
107 format!("[{}]", inner)
108 }
109 Value::MixedArray(items) => {
110 let inner = items.iter()
111 .map(|x| deep_to_string_inner(x, depth+1))
112 .collect::<Vec<_>>().join(", ");
113 format!("[{}]", inner)
114 }
115 Value::KeyedArray(map) => {
116 let parts = map.iter()
117 .map(|(k, v)| format!("{}: {}", k, deep_to_string_inner(v, depth+1)))
118 .collect::<Vec<_>>().join(", ");
119 format!("[{}]", parts)
120 }
121
122 Value::Function(_) => "[Function]".to_string(),
123 Value::Stream(sh) => format!("<Stream id={}, label={}>", sh.stream_id, sh.label),
124 Value::Iterator(_) => "[Iterator]".to_string(),
125 Value::Tensor(_) => "[Tensor]".to_string(),
126 Value::Ref(cell) => {
127 let guard = cell.lock().unwrap();
128 deep_to_string_inner(&*guard, depth+1)
129 }
130 Value::Regex(rx) => format!("Regex(/{}{}/)", rx.pattern, rx.flags),
131 }
132}
133
134fn print_no_nl(interp: &mut Interpreter, s: &str) {
135 print!("{}", s);
136 let _ = io::stdout().flush();
137 interp.push_print(s);
138}
139
140fn print_with_nl(interp: &mut Interpreter, s: &str) {
141 println!("{}", s);
142 interp.push_print(&(s.to_string() + "\n"));
143}
144
145fn drain_iterator_blocking(
148 interp: &mut Interpreter,
149 it: &IteratorHandle,
150 printer: &dyn Fn(&mut Interpreter, &str),
151) -> Result<(), String> {
152 match &it.kind {
153 IteratorKind::Core(state_arc) => {
154 let mut guard = state_arc
155 .lock()
156 .map_err(|_| "std: drain => iterator lock error".to_string())?;
157 while !guard.done && guard.current < guard.end {
158 let item = guard.current;
159 guard.current += 1;
160 if guard.current >= guard.end {
161 guard.done = true;
162 }
163 drop(guard);
164 printer(interp, &item.to_string());
165 guard = state_arc
166 .lock()
167 .map_err(|_| "std: drain => iterator lock error".to_string())?;
168 }
169 Ok(())
170 }
171 IteratorKind::Plugin(plugin_arc) => {
172 let mut plugin =
173 plugin_arc.lock().map_err(|_| "std: drain => plugin iterator lock error".to_string())?;
174 loop {
175 match plugin.next_value() {
176 Ok(item) => {
177 let s = to_printable(&item);
178 printer(interp, &s);
179 }
180 Err(e) if e == "NO_MORE_DATA" => break,
181 Err(e) => return Err(e),
182 }
183 }
184 Ok(())
185 }
186 }
187}
188
189#[cfg(not(target_arch = "wasm32"))]
193fn std_input_bridge(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
194 if args.len() > 1 {
195 return Err(format!(
196 "std:input => expected 0 or 1 arg (prompt), got {}",
197 args.len()
198 ));
199 }
200
201 if let Some(Value::SingleString(prompt)) = args.get(0) {
202 print!("{}", prompt);
203 let _ = io::stdout().flush();
204 }
205
206 let mut buf = String::new();
207 match io::stdin().read_line(&mut buf) {
208 Ok(0) => Ok(Value::SingleString(String::new())), Ok(_) => {
210 if buf.ends_with('\n') {
211 buf.pop();
212 if buf.ends_with('\r') {
213 buf.pop();
214 }
215 }
216 Ok(Value::SingleString(buf))
217 }
218 Err(e) => Err(format!("std:input => {}", e)),
219 }
220}
221
222#[cfg(target_arch = "wasm32")]
223fn std_input_bridge(_interp: &mut Interpreter, _args: Vec<Value>) -> Result<Value, String> {
224 Err("std:input is unavailable in this build (browser)".to_string())
225}
226
227#[cfg(not(target_arch = "wasm32"))]
228#[derive(Default)]
229struct StdinLines;
230
231#[cfg(not(target_arch = "wasm32"))]
232impl PluginIterator for StdinLines {
233 fn next_value(&mut self) -> Result<Value, String> {
234 let mut buf = String::new();
235 let n = io::stdin()
236 .read_line(&mut buf)
237 .map_err(|e| format!("std:input_iter => {}", e))?;
238 if n == 0 {
239 return Err("NO_MORE_DATA".into());
240 }
241 if buf.ends_with('\n') {
242 buf.pop();
243 if buf.ends_with('\r') {
244 buf.pop();
245 }
246 }
247 Ok(Value::SingleString(buf))
248 }
249}
250
251#[cfg(not(target_arch = "wasm32"))]
252fn std_input_iter_bridge(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
253 if !args.is_empty() {
254 return Err(format!(
255 "std:input_iter => expected 0 args, got {}",
256 args.len()
257 ));
258 }
259
260 let handle = IteratorHandle {
261 kind: IteratorKind::Plugin(Arc::new(Mutex::new(StdinLines::default()))),
262 };
263
264 Ok(Value::Iterator(handle))
265}
266
267#[cfg(target_arch = "wasm32")]
268fn std_input_iter_bridge(_interp: &mut Interpreter, _args: Vec<Value>) -> Result<Value, String> {
269 Err("std:input_iter is unavailable in this build (browser)".to_string())
270}
271
272fn std_put_bridge(interp: &mut Interpreter, mut args: Vec<Value>) -> Result<Value, String> {
273 if args.len() != 1 {
274 return Err(format!(
275 "std:put => expected exactly 1 argument, got {}",
276 args.len()
277 ));
278 }
279 let val = args.remove(0);
280
281 match &val {
282 Value::Iterator(handle) => {
283 drain_iterator_blocking(interp, handle, &print_no_nl)?;
284 Ok(val)
285 }
286 other => {
287 let s = to_printable(other);
288 print_no_nl(interp, &s);
289 Ok(val)
290 }
291 }
292}
293
294fn std_log_bridge(interp: &mut Interpreter, mut args: Vec<Value>) -> Result<Value, String> {
295 if args.len() != 1 {
296 return Err(format!(
297 "std:log => expected exactly 1 argument, got {}",
298 args.len()
299 ));
300 }
301 let val = args.remove(0);
302
303 match &val {
304 Value::Iterator(handle) => {
305 drain_iterator_blocking(interp, handle, &print_with_nl)?;
306 Ok(val)
307 }
308 other => {
309 let s = to_printable(other);
310 print_with_nl(interp, &s);
311 Ok(val)
312 }
313 }
314}
315
316fn std_deep_bridge(interp: &mut Interpreter, mut args: Vec<Value>) -> Result<Value, String> {
318 if args.len() != 1 {
319 return Err(format!(
320 "std:deep => expected exactly 1 argument, got {}",
321 args.len()
322 ));
323 }
324 let val = args.remove(0);
325 let s = deep_to_string(&val);
326 println!("{}", s);
327 interp.push_print(&(s + "\n"));
328 Ok(val)
329}
330
331pub fn register_all(interp: &mut Interpreter) {
334 macro_rules! reg {
335 ($name:expr, $f:expr) => {{
336 let func = Arc::new(Mutex::new($f));
337 interp.register_dynamic_function($name, func);
338 interp.set_variable($name, Value::Function(Box::new(FunctionValue::Named($name.into()))));
339 }};
340 }
341
342 reg!("std:put", std_put_bridge);
344 reg!("std:log", std_log_bridge);
345 reg!("std:deep", std_deep_bridge);
346
347 reg!("std:input", std_input_bridge);
349 reg!("std:input_iter", std_input_iter_bridge);
350}
351
352#[cfg(not(target_arch = "wasm32"))]
355#[no_mangle]
356pub unsafe extern "C" fn Cargo_lock(
357 interp_ptr: *mut std::ffi::c_void,
358 _extra: *const std::ffi::c_void,
359) -> i32 {
360 if interp_ptr.is_null() {
361 return 1;
362 }
363 let interp = &mut *(interp_ptr as *mut Interpreter);
364 register_all(interp);
365 0
366}