1pub mod format;
7
8use std::io::{self, Write};
9
10use core_mumu::{
11 parser::interpreter::Interpreter,
12 parser::types::{IteratorHandle, IteratorKind, Value},
13};
14
15pub fn to_printable(v: &Value) -> String {
18 match v {
19 Value::SingleString(s) => s.clone(),
20 Value::Int(i) => i.to_string(),
21 Value::Long(l) => l.to_string(),
22 Value::Float(f) => f.to_string(),
23 Value::Bool(b) => b.to_string(),
24 Value::KeyedError(map) => {
25 let msg = map
26 .get("message")
27 .and_then(|v| if let Value::SingleString(s) = v { Some(s.as_str()) } else { None })
28 .unwrap_or("");
29 let line = map
30 .get("line")
31 .and_then(|v| if let Value::Int(i) = v { Some(*i) } else { None })
32 .unwrap_or(0);
33 let col = map
34 .get("col")
35 .and_then(|v| if let Value::Int(i) = v { Some(*i) } else { None })
36 .unwrap_or(0);
37 if !msg.is_empty() {
38 if line > 0 || col > 0 {
39 format!("Error{{ line:{}, col:{}, message:\"{}\" }}", line, col, msg)
40 } else {
41 format!("Error{{ message:\"{}\" }}", msg)
42 }
43 } else {
44 format!("Error{{ …{} keys… }}", map.len())
45 }
46 }
47 _ => format!("{:?}", v),
48 }
49}
50
51pub fn escape_str(s: &str) -> String {
53 let mut out = String::with_capacity(s.len() + 8);
54 for ch in s.chars() {
55 match ch {
56 '\\' => out.push_str("\\\\"),
57 '"' => out.push_str("\\\""),
58 '\n' => out.push_str("\\n"),
59 '\r' => out.push_str("\\r"),
60 '\t' => out.push_str("\\t"),
61 other => out.push(other),
62 }
63 }
64 out
65}
66
67pub fn deep_to_string(v: &Value) -> String {
69 deep_to_string_inner(v, 0)
70}
71
72fn deep_to_string_inner(v: &Value, depth: usize) -> String {
73 if depth > 64 {
74 return "<depth-limit>".to_string();
75 }
76 match v {
77 Value::SingleString(s) => format!("\"{}\"", escape_str(s)),
78 Value::Int(i) => i.to_string(),
79 Value::Long(l) => l.to_string(),
80 Value::Float(f) => {
81 if f.fract() == 0.0 {
82 format!("{:.1}", f)
83 } else {
84 f.to_string()
85 }
86 }
87 Value::Bool(b) => b.to_string(),
88 Value::Undefined => "undefined".to_string(),
89 Value::Placeholder => "_".to_string(),
90
91 Value::IntArray(xs) => {
92 let inner = xs.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");
93 format!("[{}]", inner)
94 }
95 Value::FloatArray(xs) => {
96 let inner = xs
97 .iter()
98 .map(|f| if f.fract() == 0.0 { format!("{:.1}", f) } else { f.to_string() })
99 .collect::<Vec<_>>()
100 .join(", ");
101 format!("[{}]", inner)
102 }
103 Value::BoolArray(xs) => {
104 let inner = xs.iter().map(|b| b.to_string()).collect::<Vec<_>>().join(", ");
105 format!("[{}]", inner)
106 }
107 Value::StrArray(xs) => {
108 let inner = xs
109 .iter()
110 .map(|s| format!("\"{}\"", escape_str(s)))
111 .collect::<Vec<_>>()
112 .join(", ");
113 format!("[{}]", inner)
114 }
115 Value::Int2DArray(rows) => {
116 let inner = rows
117 .iter()
118 .map(|r| format!("[{}]", r.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ")))
119 .collect::<Vec<_>>()
120 .join(", ");
121 format!("[{}]", inner)
122 }
123 Value::Float2DArray(rows) => {
124 let fmt = |f: &f64| if f.fract() == 0.0 { format!("{:.1}", f) } else { f.to_string() };
125 let inner = rows
126 .iter()
127 .map(|r| format!("[{}]", r.iter().map(fmt).collect::<Vec<_>>().join(", ")))
128 .collect::<Vec<_>>()
129 .join(", ");
130 format!("[{}]", inner)
131 }
132 Value::MixedArray(items) => {
133 let inner = items
134 .iter()
135 .map(|x| deep_to_string_inner(x, depth + 1))
136 .collect::<Vec<_>>()
137 .join(", ");
138 format!("[{}]", inner)
139 }
140 Value::KeyedArray(map) => {
141 let parts = map
142 .iter()
143 .map(|(k, v)| format!("{}: {}", k, deep_to_string_inner(v, depth + 1)))
144 .collect::<Vec<_>>()
145 .join(", ");
146 format!("[{}]", parts)
147 }
148 Value::KeyedError(map) => {
149 let msg = map
150 .get("message")
151 .and_then(|v| if let Value::SingleString(s) = v { Some(s.as_str()) } else { None })
152 .unwrap_or("");
153 let line = map
154 .get("line")
155 .and_then(|v| if let Value::Int(i) = v { Some(*i) } else { None })
156 .unwrap_or(0);
157 let col = map
158 .get("col")
159 .and_then(|v| if let Value::Int(i) = v { Some(*i) } else { None })
160 .unwrap_or(0);
161 if !msg.is_empty() {
162 if line > 0 || col > 0 {
163 format!("Error{{ line:{}, col:{}, message:\"{}\" }}", line, col, escape_str(msg))
164 } else {
165 format!("Error{{ message:\"{}\" }}", escape_str(msg))
166 }
167 } else {
168 format!("Error{{ …{} keys… }}", map.len())
169 }
170 }
171
172 Value::Function(_) => "[Function]".to_string(),
173 Value::Stream(sh) => format!("<Stream id={}, label={}>", sh.stream_id, sh.label),
174 Value::Iterator(_) => "[Iterator]".to_string(),
175 Value::Tensor(_) => "[Tensor]".to_string(),
176 Value::Ref(cell) => {
177 let guard = cell.lock().unwrap();
178 deep_to_string_inner(&*guard, depth + 1)
179 }
180 Value::Regex(rx) => format!("Regex(/{}{}/)", rx.pattern, rx.flags),
181 }
182}
183
184pub fn print_no_nl(interp: &mut Interpreter, s: &str) {
186 print!("{}", s);
187 let _ = io::stdout().flush();
188 interp.push_print(s);
189}
190
191pub fn print_with_nl(interp: &mut Interpreter, s: &str) {
193 println!("{}", s);
194 interp.push_print(&(s.to_string() + "\n"));
195}
196
197pub fn drain_iterator_blocking(
199 interp: &mut Interpreter,
200 it: &IteratorHandle,
201 printer: &dyn Fn(&mut Interpreter, &str),
202) -> Result<(), String> {
203 match &it.kind {
204 IteratorKind::Core(state_arc) => {
205 let mut guard = state_arc
206 .lock()
207 .map_err(|_| "std: drain => iterator lock error".to_string())?;
208 while !guard.done && guard.current < guard.end {
209 let item = guard.current;
210 guard.current += 1;
211 if guard.current >= guard.end {
212 guard.done = true;
213 }
214 drop(guard);
215 printer(interp, &item.to_string());
216 guard = state_arc
217 .lock()
218 .map_err(|_| "std: drain => iterator lock error".to_string())?;
219 }
220 Ok(())
221 }
222 IteratorKind::Plugin(plugin_arc) => {
223 let mut plugin =
224 plugin_arc.lock().map_err(|_| "std: drain => plugin iterator lock error".to_string())?;
225 loop {
226 match plugin.next_value() {
227 Ok(item) => {
228 let s = to_printable(&item);
229 printer(interp, &s);
230 }
231 Err(e) if e == "NO_MORE_DATA" => break,
232 Err(e) => return Err(e),
233 }
234 }
235 Ok(())
236 }
237 }
238}