1use super::*;
4
5pub(crate) fn console_log(it: &mut Interp, _this: Value, args: &[Value]) -> Result<Value, Value> {
8 let parts: Vec<String> = args.iter().map(display_value).collect();
9 let line = parts.join(" ");
10 if !crate::kernel::uart::is_silent() {
11 crate::println!("{}", line);
12 }
13 it.out.push_str(&line);
14 it.out.push('\n');
15 Ok(Value::Undefined)
16}
17
18pub(crate) fn display_value(v: &Value) -> String {
24 display_value_inner(v, &mut Vec::new())
25}
26pub(crate) fn display_value_inner(v: &Value, ancestors: &mut Vec<super::super::value::ObjRef>) -> String {
27 match v {
28 Value::Str(s) => (**s).clone(),
29 Value::Object(o) => {
30 if let ObjKind::Proxy { target, .. } = &o.borrow().kind {
37 let target = unwrap_proxy_target(target);
38 if ancestors.iter().any(|a| Rc::ptr_eq(a, o)) {
39 return String::from("[Circular]");
40 }
41 ancestors.push(o.clone());
42 let out = display_value_inner(&Value::Object(target), ancestors);
43 ancestors.pop();
44 return out;
45 }
46 let kind_tag = matches!(&o.borrow().kind, ObjKind::Array(_) | ObjKind::Plain);
47 if !kind_tag {
48 return v.to_js_string();
49 }
50 if ancestors.iter().any(|a| Rc::ptr_eq(a, o)) {
51 return String::from("[Circular]");
52 }
53 ancestors.push(o.clone());
54 let b = o.borrow();
55 let out = match &b.kind {
56 ObjKind::Array(items) => {
57 let parts: Vec<String> =
58 items.iter().map(|x| display_inner_with(x, ancestors)).collect();
59 format!("[ {} ]", parts.join(", "))
60 }
61 ObjKind::Plain => {
62 let parts: Vec<String> = b
63 .props
64 .iter()
65 .map(|(k, val)| format!("{}: {}", k, display_inner_with(val, ancestors)))
66 .collect();
67 format!("{{ {} }}", parts.join(", "))
68 }
69 _ => v.to_js_string(),
70 };
71 drop(b);
72 ancestors.pop();
73 out
74 }
75 _ => v.to_js_string(),
76 }
77}
78pub(crate) fn display_inner_with(v: &Value, ancestors: &mut Vec<super::super::value::ObjRef>) -> String {
79 match v {
80 Value::Str(s) => format!("'{}'", s),
81 _ => display_value_inner(v, ancestors),
82 }
83}
84
85pub(crate) fn math_floor(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
88 Ok(Value::Number(libm::floor(arg(a, 0).to_number())))
89}
90pub(crate) fn math_ceil(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
91 Ok(Value::Number(libm::ceil(arg(a, 0).to_number())))
92}
93pub(crate) fn math_round(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
94 let n = arg(a, 0).to_number();
96 Ok(Value::Number(libm::floor(n + 0.5)))
97}
98pub(crate) fn math_trunc(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
99 Ok(Value::Number(libm::trunc(arg(a, 0).to_number())))
100}
101pub(crate) fn math_abs(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
102 Ok(Value::Number(libm::fabs(arg(a, 0).to_number())))
103}
104pub(crate) fn math_sign(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
105 let n = arg(a, 0).to_number();
106 Ok(Value::Number(if n > 0.0 {
107 1.0
108 } else if n < 0.0 {
109 -1.0
110 } else {
111 n
112 }))
113}
114pub(crate) fn math_sqrt(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
115 Ok(Value::Number(libm::sqrt(arg(a, 0).to_number())))
116}
117pub(crate) fn math_pow(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
118 Ok(Value::Number(libm::pow(
119 arg(a, 0).to_number(),
120 arg(a, 1).to_number(),
121 )))
122}
123pub(crate) fn math_sin(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
124 Ok(Value::Number(libm::sin(arg(a, 0).to_number())))
125}
126pub(crate) fn math_cos(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
127 Ok(Value::Number(libm::cos(arg(a, 0).to_number())))
128}
129pub(crate) fn math_log(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
130 Ok(Value::Number(libm::log(arg(a, 0).to_number())))
131}
132pub(crate) fn math_exp(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
133 Ok(Value::Number(libm::exp(arg(a, 0).to_number())))
134}
135pub(crate) fn math_min(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
136 let mut m = f64::INFINITY;
137 for v in a {
138 let n = v.to_number();
139 if n.is_nan() {
140 return Ok(Value::Number(f64::NAN));
141 }
142 if n < m {
143 m = n;
144 }
145 }
146 Ok(Value::Number(m))
147}
148pub(crate) fn math_max(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
149 let mut m = f64::NEG_INFINITY;
150 for v in a {
151 let n = v.to_number();
152 if n.is_nan() {
153 return Ok(Value::Number(f64::NAN));
154 }
155 if n > m {
156 m = n;
157 }
158 }
159 Ok(Value::Number(m))
160}
161
162pub(crate) static RNG_SEED: AtomicU64 = AtomicU64::new(0x2545F4914F6CDD1D);
163pub(crate) fn math_random(_: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
164 let mut x = RNG_SEED.load(Ordering::Relaxed);
166 x ^= x >> 12;
167 x ^= x << 25;
168 x ^= x >> 27;
169 RNG_SEED.store(x, Ordering::Relaxed);
170 let r = (x.wrapping_mul(0x2545F4914F6CDD1D) >> 11) as f64 / (1u64 << 53) as f64;
171 Ok(Value::Number(r))
172}
173
174pub(crate) fn json_parse(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
179 let s = arg(a, 0).to_js_string();
180 let root = match crate::os_lib::json::parse(&s) {
181 Ok(jv) => json_to_value(&jv),
182 Err(e) => return Err(it.error(format!("JSON.parse: {}", e))),
183 };
184 let reviver = arg(a, 1);
185 if !matches!(&reviver, Value::Object(o) if o.borrow().is_callable()) {
186 return Ok(root);
187 }
188 let holder = Obj::plain();
192 holder.borrow_mut().props.insert(String::new(), root);
193 internalize_json_property(it, &Value::Object(holder), "", &reviver)
194}
195pub(crate) fn internalize_json_property(
196 it: &mut Interp,
197 holder: &Value,
198 key: &str,
199 reviver: &Value,
200) -> Result<Value, Value> {
201 let val = it.get_property(holder, key)?;
202 let val = if let Value::Object(o) = &val {
203 let is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
204 if is_array {
205 let len = match &o.borrow().kind {
206 ObjKind::Array(items) => items.len(),
207 _ => 0,
208 };
209 for i in 0..len {
210 let new_elem =
211 internalize_json_property(it, &val, &i.to_string(), reviver)?;
212 if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
213 if i < items.len() {
214 items[i] = new_elem;
215 }
216 }
217 }
218 } else {
219 let keys: Vec<String> = o.borrow().props.keys().map(Clone::clone).collect();
220 for k in keys {
221 let new_val = internalize_json_property(it, &val, &k, reviver)?;
222 if matches!(new_val, Value::Undefined) {
223 o.borrow_mut().props.shift_remove(&k);
224 } else {
225 o.borrow_mut().props.insert(k, new_val);
226 }
227 }
228 }
229 val
230 } else {
231 val
232 };
233 it.call_value(reviver, holder.clone(), &[Value::str(key), val])
234}
235pub(crate) fn json_stringify(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
238 let v = arg(a, 0);
239 let replacer = arg(a, 1);
240 let key_filter: Option<Vec<String>> = match &replacer {
241 Value::Object(o) if matches!(&o.borrow().kind, ObjKind::Array(_)) => {
242 Some(this_items(&replacer).iter().map(|x| x.to_js_string()).collect())
243 }
244 _ => None,
245 };
246 let replacer_fn = match &replacer {
247 Value::Object(o) if o.borrow().is_callable() => Some(replacer.clone()),
248 _ => None,
249 };
250 let indent = match arg(a, 2) {
251 Value::Number(n) => {
252 let n = (n as usize).min(10);
253 " ".repeat(n)
254 }
255 Value::Str(s) => s.chars().take(10).collect(),
256 _ => String::new(),
257 };
258 let v = if let Some(rf) = &replacer_fn {
260 it.call_value(rf, v.clone(), &[Value::str(""), v.clone()])?
261 } else {
262 v
263 };
264 match value_to_json_string(
265 it,
266 &v,
267 &indent,
268 0,
269 key_filter.as_ref(),
270 replacer_fn.as_ref(),
271 )? {
272 Some(s) => Ok(Value::str(s)),
273 None => Ok(Value::Undefined),
274 }
275}
276
277pub(crate) fn json_raw_json(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
284 let s = arg(a, 0).to_js_string();
285 let is_ws = |c: char| matches!(c, '\u{9}' | '\u{a}' | '\u{d}' | '\u{20}');
286 if s.is_empty() || s.chars().next().is_some_and(is_ws) || s.chars().last().is_some_and(is_ws) {
287 return Err(it.error("JSON.rawJSON: argument must not be empty or have leading/trailing whitespace"));
288 }
289 if let Err(e) = crate::os_lib::json::parse(&s) {
290 return Err(it.error(format!("JSON.rawJSON: {}", e)));
291 }
292 let obj = Obj::plain();
293 {
294 let mut b = obj.borrow_mut();
295 b.props.insert("rawJSON".into(), Value::str(s));
296 b.frozen = true;
297 b.sealed = true;
298 b.non_extensible = true;
299 }
300 Ok(Value::Object(obj))
301}
302pub(crate) fn json_is_raw_json(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
306 let is_raw = match arg(a, 0) {
307 Value::Object(o) => {
308 let b = o.borrow();
309 b.frozen
310 && b.proto.is_none()
311 && b.props.len() == 1
312 && matches!(b.props.get("rawJSON"), Some(Value::Str(_)))
313 }
314 _ => false,
315 };
316 Ok(Value::Bool(is_raw))
317}
318pub(crate) fn json_to_value(jv: &crate::os_lib::json::JsonValue) -> Value {
319 use crate::os_lib::json::JsonValue as J;
320 match jv {
321 J::Null => Value::Null,
322 J::Bool(b) => Value::Bool(*b),
323 J::Number(n) => Value::Number(*n),
324 J::String(s) => Value::str(s.clone()),
325 J::Array(items) => Value::Object(Obj::array(items.iter().map(json_to_value).collect())),
326 J::Object(map) => {
327 let o = Obj::plain();
328 for (k, v) in map {
329 o.borrow_mut().props.insert(k.clone(), json_to_value(v));
330 }
331 Value::Object(o)
332 }
333 }
334}
335
336pub(crate) fn value_to_json_string(
342 it: &mut Interp,
343 v: &Value,
344 indent: &str,
345 depth: usize,
346 key_filter: Option<&Vec<String>>,
347 replacer_fn: Option<&Value>,
348) -> Result<Option<String>, Value> {
349 value_to_json_string_inner(it, v, indent, depth, key_filter, replacer_fn, &mut Vec::new())
350}
351pub(crate) fn value_to_json_string_inner(
358 it: &mut Interp,
359 v: &Value,
360 indent: &str,
361 depth: usize,
362 key_filter: Option<&Vec<String>>,
363 replacer_fn: Option<&Value>,
364 ancestors: &mut Vec<super::super::value::ObjRef>,
365) -> Result<Option<String>, Value> {
366 if depth > 30 || ancestors.len() > 30 {
367 return Err(it.type_error("Maximum JSON nesting depth exceeded"));
368 }
369 let pretty = !indent.is_empty();
370 let nl_cur = if pretty {
371 format!("\n{}", indent.repeat(depth))
372 } else {
373 String::new()
374 };
375 let nl_inner = if pretty {
376 format!("\n{}", indent.repeat(depth + 1))
377 } else {
378 String::new()
379 };
380 let colon = if pretty { ": " } else { ":" };
381 Ok(match v {
382 Value::Undefined => None,
383 Value::Null => Some("null".into()),
384 Value::Bool(b) => Some(if *b { "true".into() } else { "false".into() }),
385 Value::Number(n) => Some(if n.is_finite() {
386 fmt_number(*n)
387 } else {
388 "null".into()
389 }),
390 Value::Str(s) => Some(json_quote(s)),
391 Value::BigInt(_) => return Err(it.error("Do not know how to serialize a BigInt")),
396 Value::Object(o) => {
397 let raw_json = {
402 let b = o.borrow();
403 if b.frozen
404 && b.proto.is_none()
405 && b.props.len() == 1
406 && matches!(b.props.get("rawJSON"), Some(Value::Str(_)))
407 {
408 match b.props.get("rawJSON") {
409 Some(Value::Str(s)) => Some(s.to_string()),
410 _ => None,
411 }
412 } else {
413 None
414 }
415 };
416 if let Some(s) = raw_json {
417 return Ok(Some(s));
418 }
419 let is_date = matches!(&o.borrow().kind, ObjKind::DateObj(_));
420 if is_date {
421 let ms = match &o.borrow().kind {
422 ObjKind::DateObj(ms) => *ms,
423 _ => unreachable!(),
424 };
425 return Ok(Some(json_quote(&format_iso(ms))));
426 }
427 let is_fn = matches!(&o.borrow().kind, ObjKind::Function(_) | ObjKind::Native { .. });
428 if is_fn {
429 return Ok(None);
430 }
431 let proxy_target = match &o.borrow().kind {
435 ObjKind::Proxy { target, .. } => Some(target.clone()),
436 _ => None,
437 };
438 if let Some(target) = proxy_target {
439 return value_to_json_string_inner(
440 it,
441 &Value::Object(unwrap_proxy_target(&target)),
442 indent,
443 depth,
444 key_filter,
445 replacer_fn,
446 ancestors,
447 );
448 }
449 let to_json = it.get_property(v, "toJSON").unwrap_or(Value::Undefined);
455 if matches!(&to_json, Value::Object(f) if f.borrow().is_callable()) {
456 let replaced = it.call_value(&to_json, v.clone(), &[])?;
457 return value_to_json_string_inner(
458 it, &replaced, indent, depth, key_filter, replacer_fn, ancestors,
459 );
460 }
461 if ancestors.iter().any(|a| Rc::ptr_eq(a, o)) {
463 return Err(it.error("Converting circular structure to JSON"));
464 }
465 ancestors.push(o.clone());
466 let result = (|| -> Result<Option<String>, Value> {
467 let kind_is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
468 if kind_is_array {
469 let items = match &o.borrow().kind {
470 ObjKind::Array(items) => items.clone(),
471 _ => unreachable!(),
472 };
473 if items.is_empty() {
474 return Ok(Some("[]".into()));
475 }
476 let mut parts = Vec::with_capacity(items.len());
477 for (i, x) in items.iter().enumerate() {
478 let x = if let Some(rf) = replacer_fn {
479 it.call_value(rf, v.clone(), &[Value::str(i.to_string()), x.clone()])?
480 } else {
481 x.clone()
482 };
483 let s = value_to_json_string_inner(
484 it,
485 &x,
486 indent,
487 depth + 1,
488 key_filter,
489 replacer_fn,
490 ancestors,
491 )?
492 .unwrap_or_else(|| "null".into());
493 parts.push(s);
494 }
495 return Ok(Some(format!(
496 "[{}{}{}]",
497 nl_inner,
498 parts.join(&format!(",{}", nl_inner)),
499 nl_cur
500 )));
501 }
502 if is_internal_host(&o.borrow().kind) {
503 return Ok(Some("{}".into()));
504 }
505 let plain_keys: Vec<(String, ())> = o
509 .borrow()
510 .props
511 .keys()
512 .filter(|k| !is_symbol_like_key(k))
513 .filter(|k| o.borrow().attrs.get(*k).copied().unwrap_or_default().enumerable)
514 .map(|k| (k.clone(), ()))
515 .collect();
516 let mut keys: Vec<String> = super::object_array::spec_key_order(plain_keys)
517 .into_iter()
518 .map(|(k, _)| k)
519 .collect();
520 for k in accessor_only_keys(&o.borrow()) {
521 if o.borrow().attrs.get(&k).copied().unwrap_or_default().enumerable {
522 keys.push(k);
523 }
524 }
525 let mut parts = Vec::new();
526 for k in keys {
527 if let Some(filter) = key_filter {
528 if !filter.contains(&k) {
529 continue;
530 }
531 }
532 let getter = o.borrow().accessors.get(&k).and_then(|acc| acc.get.clone());
533 let val = if let Some(g) = getter {
534 it.call_value(&g, Value::Object(o.clone()), &[])?
535 } else {
536 o.borrow().props.get(&k).cloned().unwrap_or(Value::Undefined)
537 };
538 let val = if let Some(rf) = replacer_fn {
539 it.call_value(rf, v.clone(), &[Value::str(k.clone()), val])?
540 } else {
541 val
542 };
543 if let Some(s) = value_to_json_string_inner(
544 it,
545 &val,
546 indent,
547 depth + 1,
548 key_filter,
549 replacer_fn,
550 ancestors,
551 )? {
552 parts.push(format!("{}{}{}", json_quote(&k), colon, s));
553 }
554 }
555 if parts.is_empty() {
556 return Ok(Some("{}".into()));
557 }
558 Ok(Some(format!(
559 "{{{}{}{}}}",
560 nl_inner,
561 parts.join(&format!(",{}", nl_inner)),
562 nl_cur
563 )))
564 })();
565 ancestors.pop();
566 return result;
567 }
568 })
569}
570pub(crate) fn json_quote(s: &str) -> String {
571 let mut out = String::from("\"");
572 for c in s.chars() {
573 match c {
574 '"' => out.push_str("\\\""),
575 '\\' => out.push_str("\\\\"),
576 '\n' => out.push_str("\\n"),
577 '\t' => out.push_str("\\t"),
578 '\r' => out.push_str("\\r"),
579 _ => out.push(c),
580 }
581 }
582 out.push('"');
583 out
584}
585