1use regex::{Regex, RegexBuilder};
2use std::cell::{Cell, RefCell};
3use std::collections::{HashMap, HashSet};
4use std::ffi::c_void;
5use std::fmt;
6use std::fs;
7use std::future::Future;
8use std::io::{self, Write};
9use std::net::{TcpListener, TcpStream, UdpSocket};
10use std::ops::Deref;
11#[cfg(unix)]
12use std::os::unix::net::{UnixListener, UnixStream};
13use std::path::{Path, PathBuf};
14use std::rc::{Rc, Weak};
15use std::sync::mpsc;
16use std::sync::{
17 atomic::{AtomicBool, Ordering},
18 Arc,
19};
20use std::time::{Duration, Instant};
21
22mod collection;
23mod executor;
24mod stdlib;
25
26use self::collection::common::{
27 collection_contains, collection_difference, collection_intersection, collection_subset,
28 collection_union, construct_pair, construct_pairlist, expect_pair_like,
29 is_mutating_collection_method, pairlist_eq, reject_named_args, require_arity,
30};
31use self::executor::AsyncExecutor;
32use crate::ast::{
33 BlockStatement, CallArgument, ClassDeclaration, ClassMember, DeclarationBindingEntry, DictKey,
34 Expression, FieldDeclaration, ForStatement, FunctionDeclaration, ImportDeclaration,
35 MethodDeclaration, Parameter, Program, Statement, SwitchStatement, TemplatePart,
36 TraitDeclaration, TryStatement, VariableUnpackDeclaration,
37};
38use crate::sema;
39use crate::{
40 parse_program_with_compile_options, parse_program_with_compile_options_and_source_file,
41 OptimizationOptions, OptimizationPass, ParseOptions, Result, ZuzuRustError,
42};
43
44#[derive(Clone, Default)]
45pub struct ExecutionOutput {
46 pub stdout: String,
47 pub stderr: String,
48}
49
50#[derive(Debug, Clone, PartialEq)]
51pub enum HostValue {
52 Null,
53 Bool(bool),
54 Number(f64),
55 String(String),
56 Binary(Vec<u8>),
57 Array(Vec<HostValue>),
58 Dict(HashMap<String, HostValue>),
59 PairList(Vec<(String, HostValue)>),
60 Path(PathBuf),
61}
62
63#[derive(Clone)]
64pub struct Runtime {
65 inner: Rc<RuntimeInner>,
66}
67
68pub struct RuntimeInner {
69 module_roots: Vec<PathBuf>,
70 policy: RuntimePolicy,
71 run_sema: bool,
72 infer_types: bool,
73 optimizations: OptimizationOptions,
74 module_cache: RefCell<HashMap<String, ModuleRecord>>,
75 regex_cache: RefCell<HashMap<(String, String), Regex>>,
76 per_object_trait_class_cache: RefCell<HashMap<String, Rc<UserClassValue>>>,
77 module_loading: RefCell<HashSet<String>>,
78 output: RefCell<ExecutionOutput>,
79 special_props: RefCell<Vec<HashMap<String, Value>>>,
80 thrown_values: RefCell<HashMap<String, Value>>,
81 next_thrown_id: RefCell<usize>,
82 path_line_cursors: RefCell<HashMap<String, usize>>,
83 socket_state: RefCell<SocketState>,
84 current_env_stack: RefCell<Vec<Rc<Environment>>>,
85 current_method_stack: RefCell<Vec<Rc<MethodValue>>>,
86 signal_handlers: RefCell<HashMap<String, Vec<Value>>>,
87 db_state: RefCell<self::stdlib::DbState>,
88 clib_state: RefCell<self::stdlib::ClibState>,
89 running_async_functions: RefCell<Vec<usize>>,
90 polling_tasks: RefCell<Vec<usize>>,
91 background_tasks: RefCell<Vec<Rc<RefCell<TaskState>>>>,
92 worker_endpoints: RefCell<HashMap<usize, WorkerEndpointState>>,
93 next_worker_endpoint_id: RefCell<usize>,
94 worker_cancel_requested: Option<Arc<AtomicBool>>,
95 async_executor: AsyncExecutor,
96}
97
98impl Deref for Runtime {
99 type Target = RuntimeInner;
100
101 fn deref(&self) -> &Self::Target {
102 &self.inner
103 }
104}
105
106pub struct ReplEvalResult {
107 pub output: ExecutionOutput,
108 pub value: String,
109}
110
111pub struct ReplSession<'runtime> {
112 runtime: &'runtime Runtime,
113 env: Rc<Environment>,
114}
115
116pub struct LoadedScript {
117 _runtime: Runtime,
118 env: Rc<Environment>,
119}
120
121impl LoadedScript {
122 pub fn has_function(&self, name: &str) -> bool {
123 matches!(
124 self.env.get_optional(name),
125 Some(Value::Function(_)) | Some(Value::NativeFunction(_))
126 )
127 }
128
129 pub fn call(&self, name: &str, args: Vec<HostValue>) -> Result<HostValue> {
130 self._runtime
131 .async_executor
132 .enter(|| self.call_inner(name, args))
133 }
134
135 pub fn call_request(&self, env: HostValue) -> Result<HostValue> {
136 self.call("__request__", vec![env])
137 }
138
139 fn call_inner(&self, name: &str, args: Vec<HostValue>) -> Result<HostValue> {
140 let callee = self.env.get(name)?;
141 let args = args
142 .into_iter()
143 .map(|value| self._runtime.host_value_to_value(value))
144 .collect::<Result<Vec<_>>>()?;
145 let result = self._runtime.call_value(callee, args, Vec::new())?;
146 let result = self._runtime.await_if_task(result)?;
147 self._runtime.value_to_host_value(result)
148 }
149}
150
151#[derive(Clone, Default)]
152pub struct RuntimePolicy {
153 denied_capabilities: HashSet<String>,
154 denied_modules: HashSet<String>,
155 debug_level: u32,
156}
157
158impl RuntimePolicy {
159 pub fn new() -> Self {
160 Self::default()
161 }
162
163 pub fn deny_capability(mut self, capability: impl Into<String>) -> Self {
164 let capability = capability.into();
165 if !capability.is_empty() {
166 self.denied_capabilities.insert(capability);
167 }
168 self
169 }
170
171 pub fn deny_module(mut self, module: impl Into<String>) -> Self {
172 let module = module.into();
173 if !module.is_empty() {
174 self.denied_modules.insert(module);
175 }
176 self
177 }
178
179 pub fn debug_level(mut self, level: u32) -> Self {
180 self.debug_level = level;
181 self
182 }
183}
184
185pub(in crate::runtime) const DENIAL_CAPABILITIES: &[&str] = &[
186 "fs", "net", "perl", "js", "proc", "db", "clib", "gui", "worker",
187];
188
189fn quote_zuzu_string(text: &str) -> String {
190 let mut out = String::from("\"");
191 for ch in text.chars() {
192 match ch {
193 '\\' => out.push_str("\\\\"),
194 '"' => out.push_str("\\\""),
195 '\n' => out.push_str("\\n"),
196 '\r' => out.push_str("\\r"),
197 '\t' => out.push_str("\\t"),
198 other => out.push(other),
199 }
200 }
201 out.push('"');
202 out
203}
204
205#[derive(Clone)]
206struct ModuleRecord {
207 exports: HashMap<String, Value>,
208}
209
210#[derive(Default)]
211struct SocketState {
212 next_socket_id: usize,
213 tcp_servers: HashMap<String, TcpListener>,
214 tcp_sockets: HashMap<String, TcpSocketState>,
215 udp_sockets: HashMap<String, UdpSocket>,
216 #[cfg(unix)]
217 unix_servers: HashMap<String, UnixServerState>,
218 #[cfg(unix)]
219 unix_sockets: HashMap<String, UnixSocketState>,
220}
221
222struct TcpSocketState {
223 stream: TcpStream,
224 read_buffer: Vec<u8>,
225}
226
227#[cfg(unix)]
228struct UnixServerState {
229 listener: UnixListener,
230 path: PathBuf,
231}
232
233#[cfg(unix)]
234struct UnixSocketState {
235 stream: UnixStream,
236 read_buffer: Vec<u8>,
237}
238
239#[cfg(unix)]
240impl Drop for UnixServerState {
241 fn drop(&mut self) {
242 let _ = fs::remove_file(&self.path);
243 }
244}
245
246#[derive(Clone)]
247enum Value {
248 Null,
249 Boolean(bool),
250 Number(f64),
251 String(String),
252 BinaryString(Vec<u8>),
253 Regex(String, String),
254 Array(Vec<Value>),
255 SystemArray(Vec<Value>),
256 Set(Vec<Value>),
257 Bag(Vec<Value>),
258 Dict(HashMap<String, Value>),
259 SystemDict(HashMap<String, Value>),
260 PairList(Vec<(String, Value)>),
261 Pair(String, Box<Value>),
262 Function(Rc<FunctionValue>),
263 NativeFunction(Rc<String>),
264 Method(Rc<MethodValue>),
265 Iterator(Rc<RefCell<IteratorState>>),
266 Class(Rc<String>),
267 UserClass(Rc<UserClassValue>),
268 Trait(Rc<TraitValue>),
269 Object(Rc<RefCell<ObjectValue>>),
270 Task(Rc<RefCell<TaskState>>),
271 Channel(Rc<RefCell<ChannelState>>),
272 CancellationSource(Rc<RefCell<CancellationState>>),
273 CancellationToken(Rc<RefCell<CancellationState>>),
274 Shared(Rc<RefCell<Value>>),
275 Ref(Rc<LvalueRef>),
276 AliasRef(Rc<LvalueRef>),
277 WeakFunction(Weak<FunctionValue>),
278 WeakNativeFunction(Weak<String>),
279 WeakMethod(Weak<MethodValue>),
280 WeakIterator(Weak<RefCell<IteratorState>>),
281 WeakClass(Weak<String>),
282 WeakUserClass(Weak<UserClassValue>),
283 WeakTrait(Weak<TraitValue>),
284 WeakObject(Weak<RefCell<ObjectValue>>),
285 WeakTask(Weak<RefCell<TaskState>>),
286 WeakChannel(Weak<RefCell<ChannelState>>),
287 WeakCancellationSource(Weak<RefCell<CancellationState>>),
288 WeakCancellationToken(Weak<RefCell<CancellationState>>),
289 WeakShared(Weak<RefCell<Value>>),
290 WeakRef(Weak<LvalueRef>),
291 WeakAliasRef(Weak<LvalueRef>),
292 WeakStoredScalar(Box<Value>),
293}
294
295struct IteratorState {
296 items: Vec<Value>,
297 index: usize,
298}
299
300#[derive(Clone)]
301struct FunctionValue {
302 name: Option<String>,
303 params: Vec<Parameter>,
304 return_type: Option<String>,
305 body: Rc<RefCell<FunctionBody>>,
306 env: Rc<Environment>,
307 is_async: bool,
308 current_method: Option<Rc<MethodValue>>,
309}
310
311#[derive(Clone)]
312enum FunctionBody {
313 Bodyless,
314 Forward(Rc<FunctionValue>),
315 Block(BlockStatement),
316 Expression(Expression),
317}
318
319struct UserClassValue {
320 name: String,
321 base: Option<ClassBase>,
322 traits: Vec<Rc<TraitValue>>,
323 fields: Vec<FieldSpec>,
324 methods: HashMap<String, Rc<MethodValue>>,
325 static_methods: HashMap<String, Rc<MethodValue>>,
326 nested_classes: HashMap<String, Rc<UserClassValue>>,
327 source_decl: Option<ClassDeclaration>,
328 closure_env: Option<Rc<Environment>>,
329}
330
331#[derive(Clone)]
332struct FieldSpec {
333 name: String,
334 declared_type: Option<String>,
335 mutable: bool,
336 accessors: Vec<String>,
337 default_value: Option<Expression>,
338 is_weak_storage: bool,
339}
340
341struct MethodValue {
342 name: String,
343 params: Vec<Parameter>,
344 return_type: Option<String>,
345 body: BlockStatement,
346 env: Rc<Environment>,
347 #[allow(dead_code)]
348 is_static: bool,
349 is_async: bool,
350 is_bodyless: bool,
351 bound_receiver: Option<Value>,
352 bound_name: Option<String>,
353}
354
355pub(in crate::runtime) enum TaskKind {
356 Resolved,
357 Sleep {
358 deadline: Instant,
359 },
360 Function {
361 function: Rc<FunctionValue>,
362 args: Vec<Value>,
363 named_args: Vec<(String, Value)>,
364 started: bool,
365 },
366 FunctionWaiting {
367 awaited: Rc<RefCell<TaskState>>,
368 frames: Vec<AsyncFrame>,
369 disposition: AwaitDisposition,
370 },
371 Spawn {
372 body: BlockStatement,
373 env: Rc<Environment>,
374 started: bool,
375 },
376 SpawnWaiting {
377 awaited: Rc<RefCell<TaskState>>,
378 frames: Vec<AsyncFrame>,
379 disposition: AwaitDisposition,
380 },
381 All {
382 tasks: Vec<Value>,
383 },
384 Race {
385 tasks: Vec<Value>,
386 },
387 Timeout {
388 deadline: Instant,
389 seconds: f64,
390 task: Value,
391 },
392 ChannelRecv {
393 channel: Rc<RefCell<ChannelState>>,
394 },
395 NativeAsync {
396 cancel_requested: Option<Rc<Cell<bool>>>,
397 },
398}
399
400#[derive(Clone)]
401enum AsyncFrame {
402 Function {
403 statements: Vec<Statement>,
404 index: usize,
405 env: Rc<Environment>,
406 return_type: Option<String>,
407 name: Option<String>,
408 },
409 Block {
410 statements: Vec<Statement>,
411 index: usize,
412 env: Rc<Environment>,
413 cleanup_env: bool,
414 },
415 Do {
416 statements: Vec<Statement>,
417 index: usize,
418 env: Rc<Environment>,
419 cleanup_env: bool,
420 last: Value,
421 },
422}
423
424#[derive(Clone)]
425enum AwaitDisposition {
426 Discard,
427 StoreLast,
428 Return,
429}
430
431enum AsyncPoll {
432 Complete(Value),
433 Await {
434 awaited: Rc<RefCell<TaskState>>,
435 frames: Vec<AsyncFrame>,
436 disposition: AwaitDisposition,
437 },
438}
439
440#[derive(Clone)]
441pub(in crate::runtime) enum TaskOutcome {
442 Fulfilled(Value),
443 Rejected(String),
444 Cancelled(String),
445}
446
447pub(in crate::runtime) struct TaskState {
448 pub(in crate::runtime) status: String,
449 pub(in crate::runtime) kind: TaskKind,
450 pub(in crate::runtime) outcome: Option<TaskOutcome>,
451}
452
453pub(in crate::runtime) struct ChannelState {
454 pub(in crate::runtime) messages: Vec<Value>,
455 pub(in crate::runtime) closed: bool,
456}
457
458pub(in crate::runtime) struct CancellationState {
459 pub(in crate::runtime) cancelled: bool,
460 pub(in crate::runtime) reason: Value,
461 pub(in crate::runtime) watched: Vec<Rc<RefCell<TaskState>>>,
462}
463
464pub(in crate::runtime) enum WorkerFrame {
465 Message(Vec<u8>),
466 Close,
467 Cancel(String),
468}
469
470pub(in crate::runtime) struct WorkerEndpointState {
471 pub(in crate::runtime) sender: mpsc::Sender<WorkerFrame>,
472 pub(in crate::runtime) receiver: mpsc::Receiver<WorkerFrame>,
473 pub(in crate::runtime) queue: Vec<Value>,
474 pub(in crate::runtime) local_closed: bool,
475 pub(in crate::runtime) remote_closed: bool,
476 pub(in crate::runtime) cancelled: bool,
477 pub(in crate::runtime) cancel_requested: Arc<AtomicBool>,
478}
479
480struct TraitValue {
481 name: String,
482 methods: HashMap<String, Rc<MethodValue>>,
483 source_decl: Option<TraitDeclaration>,
484 closure_env: Option<Rc<Environment>>,
485}
486
487struct ObjectValue {
488 class: Rc<UserClassValue>,
489 fields: HashMap<String, Value>,
490 weak_fields: HashSet<String>,
491 builtin_value: Option<Value>,
492}
493
494#[derive(Clone)]
495enum ClassBase {
496 User(Rc<UserClassValue>),
497 Builtin(String),
498}
499
500enum LvalueRef {
501 Expression {
502 env: Rc<Environment>,
503 target: Expression,
504 },
505 ObjectField {
506 object: Weak<RefCell<ObjectValue>>,
507 name: String,
508 },
509}
510
511struct Environment {
512 parent: Option<Rc<Environment>>,
513 bindings: RefCell<HashMap<String, Binding>>,
514}
515
516#[derive(Clone)]
517struct Binding {
518 value: Value,
519 mutable: bool,
520 is_weak_storage: bool,
521}
522
523#[allow(dead_code)]
524#[derive(Clone)]
525struct SimpleRegex {
526 parts: Vec<RegexPart>,
527 case_insensitive: bool,
528}
529
530#[allow(dead_code)]
531#[derive(Clone)]
532enum RegexPart {
533 Literal(String),
534 DigitClassPlus,
535 LowerAlphaClassPlus,
536 Group(Vec<RegexPart>),
537}
538
539#[allow(dead_code)]
540struct RegexMatch {
541 start: usize,
542 end: usize,
543 groups: Vec<String>,
544}
545
546enum ControlFlow {
547 Normal,
548 Return(Value),
549 #[allow(dead_code)]
550 Throw(Value),
551 Continue,
552 Break,
553}
554
555#[derive(Clone, Copy)]
556enum CollectionKind {
557 Array,
558 Set,
559 Bag,
560}
561
562pub fn module_search_roots(include_dirs: Vec<PathBuf>) -> Vec<PathBuf> {
563 let initial_cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
564 let mut roots = include_dirs
565 .into_iter()
566 .map(|path| absolutize_module_path(path, &initial_cwd))
567 .collect::<Vec<_>>();
568
569 roots.extend(source_checkout_module_dirs(&initial_cwd));
570
571 if let Some(zuzulib) = std::env::var_os("ZUZULIB") {
572 roots.extend(
573 std::env::split_paths(&zuzulib).map(|path| absolutize_module_path(path, &initial_cwd)),
574 );
575 }
576
577 if let Some(user_dir) = user_modules_dir() {
578 if user_dir.is_dir() {
579 roots.push(user_dir);
580 }
581 }
582
583 if let Some(system_dir) = system_modules_dir() {
584 if system_dir.is_dir() {
585 roots.push(system_dir);
586 }
587 }
588
589 if let Some(stdlib) = std::env::var_os("ZUZU_STDLIB").filter(|value| !value.is_empty()) {
590 roots.push(absolutize_module_path(PathBuf::from(stdlib), &initial_cwd));
591 } else if let Some(stdlib) = installed_stdlib_modules_dir() {
592 roots.push(stdlib);
593 }
594
595 dedup_paths(roots)
596}
597
598fn source_checkout_module_dirs(start: &Path) -> Vec<PathBuf> {
599 let mut current = start.to_path_buf();
600 loop {
601 let candidates = [
602 current.join("modules"),
603 current.join("languagetests").join("lang").join("modules"),
604 current.join("stdlib").join("modules"),
605 current.join("stdlib").join("test-modules"),
606 ];
607 let roots = candidates
608 .into_iter()
609 .filter(|path| path.is_dir())
610 .collect::<Vec<_>>();
611 if !roots.is_empty() {
612 return roots;
613 }
614 if !current.pop() {
615 break;
616 }
617 }
618 Vec::new()
619}
620
621fn absolutize_module_path(path: PathBuf, base: &Path) -> PathBuf {
622 if path.is_absolute() {
623 path
624 } else {
625 base.join(path)
626 }
627}
628
629fn user_modules_dir() -> Option<PathBuf> {
630 if cfg!(windows) {
631 return std::env::var_os("LOCALAPPDATA")
632 .map(PathBuf::from)
633 .map(|path| path.join("Zuzu").join("modules"));
634 }
635 std::env::var_os("HOME")
636 .map(PathBuf::from)
637 .map(|path| path.join(".zuzu").join("modules"))
638}
639
640fn system_modules_dir() -> Option<PathBuf> {
641 if cfg!(windows) {
642 return std::env::var_os("ProgramData")
643 .map(PathBuf::from)
644 .map(|path| path.join("Zuzu").join("modules"));
645 }
646 Some(PathBuf::from("/var/lib/zuzu/modules"))
647}
648
649fn installed_stdlib_modules_dir() -> Option<PathBuf> {
650 let exe = std::env::current_exe().ok()?;
651 let bin_dir = exe.parent()?;
652 let prefix = if bin_dir.file_name().and_then(|name| name.to_str()) == Some("bin") {
653 bin_dir.parent()?
654 } else {
655 bin_dir
656 };
657 Some(prefix.join("share").join("zuzu-rust").join("modules"))
658}
659
660fn dedup_paths(paths: Vec<PathBuf>) -> Vec<PathBuf> {
661 let mut seen = HashSet::new();
662 let mut out = Vec::new();
663 for path in paths {
664 if seen.insert(path.clone()) {
665 out.push(path);
666 }
667 }
668 out
669}
670
671impl Runtime {
672 pub fn new(module_roots: Vec<PathBuf>) -> Self {
673 Self::with_policy(module_roots, RuntimePolicy::default())
674 }
675
676 pub fn with_policy(module_roots: Vec<PathBuf>, policy: RuntimePolicy) -> Self {
677 Self::with_policy_and_worker_cancel(module_roots, policy, None)
678 }
679
680 pub(in crate::runtime) fn with_policy_and_worker_cancel(
681 module_roots: Vec<PathBuf>,
682 policy: RuntimePolicy,
683 worker_cancel_requested: Option<Arc<AtomicBool>>,
684 ) -> Self {
685 Self {
686 inner: Rc::new(RuntimeInner {
687 module_roots,
688 policy,
689 run_sema: true,
690 infer_types: true,
691 optimizations: OptimizationOptions::default(),
692 module_cache: RefCell::new(HashMap::new()),
693 regex_cache: RefCell::new(HashMap::new()),
694 per_object_trait_class_cache: RefCell::new(HashMap::new()),
695 module_loading: RefCell::new(HashSet::new()),
696 output: RefCell::new(ExecutionOutput::default()),
697 special_props: RefCell::new(vec![HashMap::new()]),
698 thrown_values: RefCell::new(HashMap::new()),
699 next_thrown_id: RefCell::new(0),
700 path_line_cursors: RefCell::new(HashMap::new()),
701 socket_state: RefCell::new(SocketState::default()),
702 current_env_stack: RefCell::new(Vec::new()),
703 current_method_stack: RefCell::new(Vec::new()),
704 signal_handlers: RefCell::new(HashMap::new()),
705 db_state: RefCell::new(self::stdlib::DbState::default()),
706 clib_state: RefCell::new(self::stdlib::ClibState::default()),
707 running_async_functions: RefCell::new(Vec::new()),
708 polling_tasks: RefCell::new(Vec::new()),
709 background_tasks: RefCell::new(Vec::new()),
710 worker_endpoints: RefCell::new(HashMap::new()),
711 next_worker_endpoint_id: RefCell::new(1),
712 worker_cancel_requested,
713 async_executor: AsyncExecutor::new(),
714 }),
715 }
716 }
717
718 pub fn from_repo_root(repo_root: &Path) -> Self {
719 Self::new(module_search_roots(source_checkout_module_dirs(repo_root)))
720 }
721
722 pub fn from_repo_root_with_policy(repo_root: &Path, policy: RuntimePolicy) -> Self {
723 Self::with_policy(
724 module_search_roots(source_checkout_module_dirs(repo_root)),
725 policy,
726 )
727 }
728
729 pub fn with_parse_options(mut self, run_sema: bool, infer_types: bool) -> Self {
730 let inner = Rc::get_mut(&mut self.inner)
731 .expect("parse options must be set before runtime is cloned");
732 inner.run_sema = run_sema;
733 inner.infer_types = infer_types;
734 self
735 }
736
737 pub fn with_optimization_options(mut self, optimizations: OptimizationOptions) -> Self {
738 let inner = Rc::get_mut(&mut self.inner)
739 .expect("optimization options must be set before runtime is cloned");
740 inner.optimizations = optimizations;
741 self
742 }
743
744 pub fn repl_session(&self) -> ReplSession<'_> {
745 let env = Rc::new(Environment::new(None));
746 self.install_builtins(&env);
747 ReplSession { runtime: self, env }
748 }
749
750 #[allow(dead_code)]
751 fn composite_value_ref_target(&self, env: Rc<Environment>, field_name: &str) -> Value {
752 Value::Ref(Rc::new(LvalueRef::Expression {
753 env,
754 target: Expression::DictAccess {
755 line: 0,
756 source_file: None,
757 object: Box::new(Expression::Identifier {
758 line: 0,
759 source_file: None,
760 name: "self".to_owned(),
761 inferred_type: None,
762 binding_depth: None,
763 }),
764 key: Box::new(DictKey::Identifier {
765 line: 0,
766 source_file: None,
767 name: field_name.to_owned(),
768 }),
769 inferred_type: None,
770 },
771 }))
772 }
773
774 fn is_ref_backed_composite(&self, value: &Value) -> bool {
775 matches!(
776 value,
777 Value::Array(_)
778 | Value::Set(_)
779 | Value::Bag(_)
780 | Value::Dict(_)
781 | Value::PairList(_)
782 | Value::Pair(_, _)
783 | Value::Shared(_)
784 )
785 }
786
787 fn deref_value(&self, value: &Value) -> Result<Value> {
788 let mut current = value.clone();
789 for _ in 0..32 {
790 match current {
791 value if value.is_weak_value() => {
792 current = value.resolve_weak_value();
793 }
794 Value::Ref(reference) | Value::AliasRef(reference) => {
795 current = self.call_ref(Rc::clone(&reference), Vec::new(), Vec::new())?;
796 }
797 Value::Shared(value) => {
798 current = value.borrow().clone();
799 }
800 _ => return Ok(current),
801 }
802 }
803 Err(ZuzuRustError::runtime(
804 "reference dereference recursion limit reached",
805 ))
806 }
807
808 fn value_is_nullish(&self, value: &Value) -> Result<bool> {
809 self.value_is_nullish_inner(value, 0)
810 }
811
812 fn value_is_nullish_inner(&self, value: &Value, depth: usize) -> Result<bool> {
813 if depth > 32 {
814 return Err(ZuzuRustError::runtime(
815 "reference dereference recursion limit reached",
816 ));
817 }
818 match value {
819 Value::Null => Ok(true),
820 Value::WeakFunction(value) => Ok(value.upgrade().is_none()),
821 Value::WeakNativeFunction(value) => Ok(value.upgrade().is_none()),
822 Value::WeakMethod(value) => Ok(value.upgrade().is_none()),
823 Value::WeakIterator(value) => Ok(value.upgrade().is_none()),
824 Value::WeakClass(value) => Ok(value.upgrade().is_none()),
825 Value::WeakUserClass(value) => Ok(value.upgrade().is_none()),
826 Value::WeakTrait(value) => Ok(value.upgrade().is_none()),
827 Value::WeakObject(value) => Ok(value.upgrade().is_none()),
828 Value::WeakTask(value) => Ok(value.upgrade().is_none()),
829 Value::WeakChannel(value) => Ok(value.upgrade().is_none()),
830 Value::WeakCancellationSource(value) => Ok(value.upgrade().is_none()),
831 Value::WeakCancellationToken(value) => Ok(value.upgrade().is_none()),
832 Value::WeakShared(value) => {
833 let Some(value) = value.upgrade() else {
834 return Ok(true);
835 };
836 let result = self.value_is_nullish_inner(&value.borrow(), depth + 1);
837 result
838 }
839 Value::WeakRef(value) | Value::WeakAliasRef(value) => {
840 let Some(reference) = value.upgrade() else {
841 return Ok(true);
842 };
843 let value = self.call_ref(reference, Vec::new(), Vec::new())?;
844 self.value_is_nullish_inner(&value, depth + 1)
845 }
846 Value::WeakStoredScalar(value) => self.value_is_nullish_inner(value, depth + 1),
847 Value::Ref(reference) | Value::AliasRef(reference) => {
848 let value = self.call_ref(Rc::clone(reference), Vec::new(), Vec::new())?;
849 self.value_is_nullish_inner(&value, depth + 1)
850 }
851 Value::Shared(value) => {
852 let result = self.value_is_nullish_inner(&value.borrow(), depth + 1);
853 result
854 }
855 _ => Ok(false),
856 }
857 }
858
859 pub(in crate::runtime) fn normalize_value(&self, value: Value) -> Result<Value> {
860 match value {
861 value if value.is_weak_value() => self.deref_value(&value),
862 Value::AliasRef(_) | Value::Shared(_) => self.deref_value(&value),
863 other => Ok(other),
864 }
865 }
866
867 fn with_current_env<T>(
868 &self,
869 env: Rc<Environment>,
870 f: impl FnOnce() -> Result<T>,
871 ) -> Result<T> {
872 self.current_env_stack.borrow_mut().push(env);
873 let result = f();
874 self.current_env_stack.borrow_mut().pop();
875 result
876 }
877
878 fn current_env(&self) -> Option<Rc<Environment>> {
879 self.current_env_stack.borrow().last().cloned()
880 }
881
882 fn parse_options(&self) -> ParseOptions {
883 ParseOptions::new(self.run_sema, self.infer_types, self.optimizations.clone())
884 }
885
886 fn emit_semantic_warnings(&self, program: &Program) -> Result<()> {
887 if !self.run_sema {
888 return Ok(());
889 }
890 for warning in sema::weak_storage_warnings(program) {
891 self.emit_stderr(&format!("{warning}\n"))?;
892 }
893 Ok(())
894 }
895
896 fn assign_reference(&self, reference: Rc<LvalueRef>, value: Value) -> Result<Value> {
897 self.call_ref(reference, vec![value], Vec::new())
898 }
899
900 fn assign_reference_with_weak_write(
901 &self,
902 reference: Rc<LvalueRef>,
903 value: Value,
904 weak_write: bool,
905 ) -> Result<Value> {
906 self.call_ref(
907 reference,
908 vec![value, Value::Boolean(weak_write)],
909 Vec::new(),
910 )
911 }
912
913 fn maybe_return_trivial_field_getter(
914 &self,
915 object: &Rc<RefCell<ObjectValue>>,
916 method: &Rc<MethodValue>,
917 ) -> Option<Result<Value>> {
918 if !method.params.is_empty() {
919 return None;
920 }
921 let [statement] = method.body.statements.as_slice() else {
922 return None;
923 };
924 let field_name = match statement {
925 Statement::ReturnStatement(node) => match node.argument.as_ref() {
926 Some(Expression::Identifier { name, .. }) => Some(name.as_str()),
927 _ => None,
928 },
929 Statement::ExpressionStatement(node) => match &node.expression {
930 Expression::Identifier { name, .. } => Some(name.as_str()),
931 _ => None,
932 },
933 _ => None,
934 }?;
935 let value = object.borrow().fields.get(field_name).cloned()?;
939 Some(Ok(if value.is_weak_value() {
940 value.resolve_weak_value()
941 } else {
942 value
943 }))
944 }
945
946 pub fn run_script_file(&self, script_path: &Path) -> Result<ExecutionOutput> {
947 self.run_script_file_with_args(script_path, &[])
948 }
949
950 pub fn run_script_file_with_args(
951 &self,
952 script_path: &Path,
953 argv: &[String],
954 ) -> Result<ExecutionOutput> {
955 let source = fs::read_to_string(script_path)?;
956 self.run_script_source_with_args_and_source_file(
957 &source,
958 argv,
959 Some(&script_path.display().to_string()),
960 )
961 }
962
963 pub fn last_output(&self) -> ExecutionOutput {
964 self.output.borrow().clone()
965 }
966
967 pub(crate) fn emit_stdout(&self, text: &str) -> Result<()> {
968 self.output.borrow_mut().stdout.push_str(text);
969 let mut stdout = io::stdout().lock();
970 stdout.write_all(text.as_bytes())?;
971 stdout.flush()?;
972 Ok(())
973 }
974
975 pub(crate) fn emit_stderr(&self, text: &str) -> Result<()> {
976 self.output.borrow_mut().stderr.push_str(text);
977 let mut stderr = io::stderr().lock();
978 stderr.write_all(text.as_bytes())?;
979 stderr.flush()?;
980 Ok(())
981 }
982
983 pub(crate) fn warn_blocking_operation(&self, operation: &str) -> Result<()> {
984 if self.policy.debug_level == 0 || self.polling_tasks.borrow().is_empty() {
985 return Ok(());
986 }
987 self.emit_stderr(&format!(
988 "BlockingOperation: {operation} called while polling async task\n"
989 ))
990 }
991
992 pub fn run_script_source(&self, source: &str) -> Result<ExecutionOutput> {
993 self.run_script_source_with_args(source, &[])
994 }
995
996 pub fn run_script_source_with_args(
997 &self,
998 source: &str,
999 argv: &[String],
1000 ) -> Result<ExecutionOutput> {
1001 self.run_script_source_with_args_and_source_file(source, argv, None)
1002 }
1003
1004 pub fn run_script_source_with_args_and_source_file(
1005 &self,
1006 source: &str,
1007 argv: &[String],
1008 source_file: Option<&str>,
1009 ) -> Result<ExecutionOutput> {
1010 self.async_executor.enter(|| {
1011 self.run_script_source_with_args_and_source_file_inner(source, argv, source_file)
1012 })
1013 }
1014
1015 pub fn load_program_without_main(
1016 &self,
1017 program: &Program,
1018 source_file: Option<&str>,
1019 ) -> Result<LoadedScript> {
1020 self.async_executor
1021 .enter(|| self.load_program_without_main_inner(program, source_file))
1022 }
1023
1024 pub fn gui_xml_preview_widget(&self, xml: &str) -> Result<*mut c_void> {
1031 self.async_executor
1032 .enter(|| self.gui_xml_preview_widget_inner(xml))
1033 }
1034
1035 fn gui_xml_preview_widget_inner(&self, xml: &str) -> Result<*mut c_void> {
1036 let source = format!(
1037 "from std/gui import gui_from_xml;\n\
1038 gui_from_xml({});\n",
1039 quote_zuzu_string(xml),
1040 );
1041 let options = self.parse_options();
1042 let program = parse_program_with_compile_options(&source, &options)?;
1043 self.emit_semantic_warnings(&program)?;
1044 let env = Rc::new(Environment::new(None));
1045 self.install_builtins(&env);
1046 let value = self.eval_repl_program(&program, env)?;
1047 stdlib::gui::preview_widget(self, &value)
1048 }
1049
1050 fn run_script_source_with_args_and_source_file_inner(
1051 &self,
1052 source: &str,
1053 argv: &[String],
1054 source_file: Option<&str>,
1055 ) -> Result<ExecutionOutput> {
1056 self.reset_top_level_execution_state();
1057 let options = self.parse_options();
1058 let program =
1059 parse_program_with_compile_options_and_source_file(source, &options, source_file)?;
1060 self.emit_semantic_warnings(&program)?;
1061 let env = Rc::new(Environment::new(None));
1062 self.install_builtins(&env);
1063 self.define_file_const(&env, program.source_file.as_deref(), false);
1064 match self.eval_program(&program, Rc::clone(&env)) {
1065 Err(ZuzuRustError::Thrown { value, .. }) => Err(ZuzuRustError::runtime(format!(
1066 "uncaught exception: {value}"
1067 ))),
1068 Err(err) => Err(err),
1069 Ok(flow) => match flow {
1070 ControlFlow::Normal => {
1071 self.call_main_if_present(Rc::clone(&env), argv)?;
1072 self.cancel_background_tasks(Value::String("shutdown".to_owned()));
1073 Ok(self.output.borrow().clone())
1074 }
1075 ControlFlow::Return(_) => Err(ZuzuRustError::runtime(
1076 "return is not valid at top-level scope",
1077 )),
1078 ControlFlow::Throw(value) => Err(ZuzuRustError::runtime(format!(
1079 "uncaught exception: {}",
1080 value
1081 ))),
1082 ControlFlow::Continue | ControlFlow::Break => Err(ZuzuRustError::runtime(
1083 "loop control is not valid at top-level scope",
1084 )),
1085 },
1086 }
1087 }
1088
1089 fn load_program_without_main_inner(
1090 &self,
1091 program: &Program,
1092 source_file: Option<&str>,
1093 ) -> Result<LoadedScript> {
1094 self.reset_top_level_execution_state();
1095 self.emit_semantic_warnings(program)?;
1096 let env = Rc::new(Environment::new(None));
1097 self.install_builtins(&env);
1098 self.define_file_const(&env, program.source_file.as_deref().or(source_file), false);
1099 match self.eval_program(program, Rc::clone(&env)) {
1100 Err(ZuzuRustError::Thrown { value, .. }) => Err(ZuzuRustError::runtime(format!(
1101 "uncaught exception: {value}"
1102 ))),
1103 Err(err) => Err(err),
1104 Ok(flow) => match flow {
1105 ControlFlow::Normal => Ok(LoadedScript {
1106 _runtime: self.clone(),
1107 env,
1108 }),
1109 ControlFlow::Return(_) => Err(ZuzuRustError::runtime(
1110 "return is not valid at top-level scope",
1111 )),
1112 ControlFlow::Throw(value) => Err(ZuzuRustError::runtime(format!(
1113 "uncaught exception: {}",
1114 value
1115 ))),
1116 ControlFlow::Continue | ControlFlow::Break => Err(ZuzuRustError::runtime(
1117 "loop control is not valid at top-level scope",
1118 )),
1119 },
1120 }
1121 }
1122
1123 fn reset_top_level_execution_state(&self) {
1124 *self.output.borrow_mut() = ExecutionOutput::default();
1125 let mut special_props = self.special_props.borrow_mut();
1126 special_props.clear();
1127 special_props.push(HashMap::new());
1128 drop(special_props);
1129 self.thrown_values.borrow_mut().clear();
1130 *self.next_thrown_id.borrow_mut() = 0;
1131 self.path_line_cursors.borrow_mut().clear();
1132 self.background_tasks.borrow_mut().clear();
1133 *self.socket_state.borrow_mut() = SocketState::default();
1134 }
1135
1136 fn host_value_to_value(&self, value: HostValue) -> Result<Value> {
1137 match value {
1138 HostValue::Null => Ok(Value::Null),
1139 HostValue::Bool(value) => Ok(Value::Boolean(value)),
1140 HostValue::Number(value) => Ok(Value::Number(value)),
1141 HostValue::String(value) => Ok(Value::String(value)),
1142 HostValue::Binary(value) => Ok(Value::BinaryString(value)),
1143 HostValue::Array(values) => values
1144 .into_iter()
1145 .map(|value| self.host_value_to_value(value))
1146 .collect::<Result<Vec<_>>>()
1147 .map(Value::Array),
1148 HostValue::Dict(values) => values
1149 .into_iter()
1150 .map(|(key, value)| Ok((key, self.host_value_to_value(value)?)))
1151 .collect::<Result<HashMap<_, _>>>()
1152 .map(Value::Dict),
1153 HostValue::PairList(values) => values
1154 .into_iter()
1155 .map(|(key, value)| Ok((key, self.host_value_to_value(value)?)))
1156 .collect::<Result<Vec<_>>>()
1157 .map(Value::PairList),
1158 HostValue::Path(path) => self.construct_builtin_class(
1159 "Path",
1160 vec![Value::String(path.to_string_lossy().to_string())],
1161 Vec::new(),
1162 ),
1163 }
1164 }
1165
1166 fn value_to_host_value(&self, value: Value) -> Result<HostValue> {
1167 let value = self.deref_value(&value)?;
1168 match value {
1169 Value::Null => Ok(HostValue::Null),
1170 Value::Boolean(value) => Ok(HostValue::Bool(value)),
1171 Value::Number(value) => Ok(HostValue::Number(value)),
1172 Value::String(value) => Ok(HostValue::String(value)),
1173 Value::BinaryString(value) => Ok(HostValue::Binary(value)),
1174 Value::Array(values) | Value::SystemArray(values) => values
1175 .into_iter()
1176 .map(|value| self.value_to_host_value(value))
1177 .collect::<Result<Vec<_>>>()
1178 .map(HostValue::Array),
1179 Value::Dict(values) | Value::SystemDict(values) => values
1180 .into_iter()
1181 .map(|(key, value)| Ok((key, self.value_to_host_value(value)?)))
1182 .collect::<Result<HashMap<_, _>>>()
1183 .map(HostValue::Dict),
1184 Value::PairList(values) => values
1185 .into_iter()
1186 .map(|(key, value)| Ok((key, self.value_to_host_value(value)?)))
1187 .collect::<Result<Vec<_>>>()
1188 .map(HostValue::PairList),
1189 Value::Object(object) if object.borrow().class.name == "Path" => {
1190 let path = match object.borrow().fields.get("path") {
1191 Some(Value::String(path)) => PathBuf::from(path),
1192 _ => PathBuf::new(),
1193 };
1194 Ok(HostValue::Path(path))
1195 }
1196 other => Err(ZuzuRustError::runtime(format!(
1197 "cannot convert {} to HostValue",
1198 self.typeof_name(&other)
1199 ))),
1200 }
1201 }
1202
1203 fn call_main_if_present(&self, env: Rc<Environment>, argv: &[String]) -> Result<()> {
1204 let Some(callee) = env.get_optional("__main__") else {
1205 return Ok(());
1206 };
1207 let should_await_main = matches!(&callee, Value::Function(function) if function.is_async);
1208 let args = Value::Array(argv.iter().map(|arg| Value::String(arg.clone())).collect());
1209 let result = self.call_value(callee, vec![args], Vec::new())?;
1210 if should_await_main {
1211 let _ = self.await_value(result)?;
1212 }
1213 Ok(())
1214 }
1215
1216 fn eval_program(&self, program: &Program, env: Rc<Environment>) -> Result<ControlFlow> {
1217 self.eval_statements(&program.statements, env)
1218 }
1219
1220 fn eval_repl_program(&self, program: &Program, env: Rc<Environment>) -> Result<Value> {
1221 let mut result = Value::Null;
1222 for statement in &program.statements {
1223 result = self.eval_repl_statement(statement, Rc::clone(&env))?;
1224 }
1225 Ok(result)
1226 }
1227
1228 fn eval_repl_statement(&self, statement: &Statement, env: Rc<Environment>) -> Result<Value> {
1229 match statement {
1230 Statement::VariableDeclaration(node) => {
1231 let value = match node.init.as_ref() {
1232 Some(init) => self.eval_expression(init, Rc::clone(&env))?,
1233 None => Value::Null,
1234 };
1235 if node.init.is_some() && node.runtime_typecheck_required != Some(false) {
1236 self.assert_declared_type(node.declared_type.as_deref(), &value, &node.name)?;
1237 }
1238 env.define_with_storage(
1239 node.name.clone(),
1240 value.clone(),
1241 node.kind != "const",
1242 node.is_weak_storage,
1243 );
1244 Ok(value)
1245 }
1246 Statement::VariableUnpackDeclaration(node) => {
1247 self.eval_variable_unpack_declaration(node, Rc::clone(&env))
1248 }
1249 Statement::FunctionDeclaration(node) => {
1250 let func = self.make_function_from_decl(node, Rc::clone(&env));
1251 let value = Value::Function(Rc::new(func));
1252 if node.is_predeclared {
1253 if env.get_here(&node.name).is_some() {
1254 return Err(ZuzuRustError::runtime(format!(
1255 "Redeclaration of '{}' in the same scope",
1256 node.name
1257 )));
1258 }
1259 env.define(node.name.clone(), value.clone(), false);
1260 return Ok(value);
1261 }
1262 if let Some(Value::Function(existing)) = env.get_here(&node.name) {
1263 if matches!(*existing.body.borrow(), FunctionBody::Bodyless) {
1264 *existing.body.borrow_mut() =
1265 FunctionBody::Forward(Rc::clone(match &value {
1266 Value::Function(function) => function,
1267 _ => unreachable!(),
1268 }));
1269 return Ok(Value::Function(existing));
1270 }
1271 }
1272 if env.get_here(&node.name).is_some() {
1273 return Err(ZuzuRustError::runtime(format!(
1274 "Redeclaration of '{}' in the same scope",
1275 node.name
1276 )));
1277 }
1278 env.define(node.name.clone(), value.clone(), false);
1279 Ok(value)
1280 }
1281 Statement::ClassDeclaration(node) => {
1282 let class = self.make_user_class_from_decl(node, Rc::clone(&env))?;
1283 let value = Value::UserClass(Rc::new(class));
1284 env.define(node.name.clone(), value.clone(), false);
1285 Ok(value)
1286 }
1287 Statement::TraitDeclaration(node) => {
1288 let mut methods = HashMap::new();
1289 for member in &node.body {
1290 if let ClassMember::Method(method) = member {
1291 self.install_method_decl(&mut methods, method, Rc::clone(&env))?;
1292 }
1293 }
1294 let value = Value::Trait(Rc::new(TraitValue {
1295 name: node.name.clone(),
1296 methods,
1297 source_decl: Some(node.clone()),
1298 closure_env: Some(Rc::clone(&env)),
1299 }));
1300 env.define(node.name.clone(), value.clone(), false);
1301 Ok(value)
1302 }
1303 Statement::ExpressionStatement(node) => self.eval_expression(&node.expression, env),
1304 _ => match self.eval_statement(statement, env)? {
1305 ControlFlow::Normal => Ok(Value::Null),
1306 ControlFlow::Return(_) => Err(ZuzuRustError::runtime(
1307 "return is not valid at top-level scope",
1308 )),
1309 ControlFlow::Throw(value) => Err(ZuzuRustError::runtime(format!(
1310 "uncaught exception: {}",
1311 value
1312 ))),
1313 ControlFlow::Continue | ControlFlow::Break => Err(ZuzuRustError::runtime(
1314 "loop control is not valid at top-level scope",
1315 )),
1316 },
1317 }
1318 }
1319
1320 fn eval_statements(
1321 &self,
1322 statements: &[Statement],
1323 env: Rc<Environment>,
1324 ) -> Result<ControlFlow> {
1325 for statement in statements {
1326 let flow = self.eval_statement(statement, Rc::clone(&env))?;
1327 if !matches!(flow, ControlFlow::Normal) {
1328 return Ok(flow);
1329 }
1330 }
1331 Ok(ControlFlow::Normal)
1332 }
1333
1334 fn eval_function_statements(
1335 &self,
1336 statements: &[Statement],
1337 env: Rc<Environment>,
1338 ) -> Result<ControlFlow> {
1339 for (index, statement) in statements.iter().enumerate() {
1340 let is_last = index + 1 == statements.len();
1341 if is_last {
1342 if let Statement::ExpressionStatement(node) = statement {
1343 return Ok(ControlFlow::Return(
1344 self.eval_expression(&node.expression, env)?,
1345 ));
1346 }
1347 }
1348 let flow = self.eval_statement(statement, Rc::clone(&env))?;
1349 if !matches!(flow, ControlFlow::Normal) {
1350 return Ok(flow);
1351 }
1352 let do_return = self.get_special_prop("__do_return__");
1353 if !matches!(do_return, Value::Null) {
1354 self.set_special_prop("__do_return__", Value::Null);
1355 return Ok(ControlFlow::Return(do_return));
1356 }
1357 }
1358 Ok(ControlFlow::Normal)
1359 }
1360
1361 fn eval_statement(&self, statement: &Statement, env: Rc<Environment>) -> Result<ControlFlow> {
1362 match statement {
1363 Statement::Block(block) => self.eval_block(block, env),
1364 Statement::VariableDeclaration(node) => {
1365 let value = match node.init.as_ref() {
1366 Some(init) => self.eval_expression(init, Rc::clone(&env))?,
1367 None => Value::Null,
1368 };
1369 if node.init.is_some() && node.runtime_typecheck_required != Some(false) {
1370 self.assert_declared_type(node.declared_type.as_deref(), &value, &node.name)?;
1371 }
1372 env.define_with_storage(
1373 node.name.clone(),
1374 value,
1375 node.kind != "const",
1376 node.is_weak_storage,
1377 );
1378 Ok(ControlFlow::Normal)
1379 }
1380 Statement::VariableUnpackDeclaration(node) => {
1381 self.eval_variable_unpack_declaration(node, env)?;
1382 Ok(ControlFlow::Normal)
1383 }
1384 Statement::FunctionDeclaration(node) => {
1385 let func = self.make_function_from_decl(node, Rc::clone(&env));
1386 let value = Value::Function(Rc::new(func));
1387 if node.is_predeclared {
1388 if env.get_here(&node.name).is_some() {
1389 return Err(ZuzuRustError::runtime(format!(
1390 "Redeclaration of '{}' in the same scope",
1391 node.name
1392 )));
1393 }
1394 env.define(node.name.clone(), value, false);
1395 return Ok(ControlFlow::Normal);
1396 }
1397 if let Some(Value::Function(existing)) = env.get_here(&node.name) {
1398 if matches!(*existing.body.borrow(), FunctionBody::Bodyless) {
1399 *existing.body.borrow_mut() =
1400 FunctionBody::Forward(Rc::clone(match &value {
1401 Value::Function(function) => function,
1402 _ => unreachable!(),
1403 }));
1404 return Ok(ControlFlow::Normal);
1405 }
1406 }
1407 if env.get_here(&node.name).is_some() {
1408 return Err(ZuzuRustError::runtime(format!(
1409 "Redeclaration of '{}' in the same scope",
1410 node.name
1411 )));
1412 }
1413 env.define(node.name.clone(), value, false);
1414 Ok(ControlFlow::Normal)
1415 }
1416 Statement::ClassDeclaration(node) => {
1417 let class = self.make_user_class_from_decl(node, Rc::clone(&env))?;
1418 env.define(node.name.clone(), Value::UserClass(Rc::new(class)), false);
1419 Ok(ControlFlow::Normal)
1420 }
1421 Statement::TraitDeclaration(node) => {
1422 let mut methods = HashMap::new();
1423 for member in &node.body {
1424 if let ClassMember::Method(method) = member {
1425 methods.insert(
1426 method.name.clone(),
1427 Rc::new(self.make_method_from_decl(method, Rc::clone(&env))),
1428 );
1429 }
1430 }
1431 env.define(
1432 node.name.clone(),
1433 Value::Trait(Rc::new(TraitValue {
1434 name: node.name.clone(),
1435 methods,
1436 source_decl: Some(node.clone()),
1437 closure_env: Some(Rc::clone(&env)),
1438 })),
1439 false,
1440 );
1441 Ok(ControlFlow::Normal)
1442 }
1443 Statement::ImportDeclaration(node) => {
1444 self.eval_import(node, env)?;
1445 Ok(ControlFlow::Normal)
1446 }
1447 Statement::IfStatement(node) => {
1448 if self.value_is_truthy(&self.eval_expression(&node.test, Rc::clone(&env))?)? {
1449 self.eval_block(&node.consequent, env)
1450 } else if let Some(alternate) = &node.alternate {
1451 self.eval_statement(alternate, env)
1452 } else {
1453 Ok(ControlFlow::Normal)
1454 }
1455 }
1456 Statement::WhileStatement(node) => {
1457 loop {
1458 if !self.value_is_truthy(&self.eval_expression(&node.test, Rc::clone(&env))?)? {
1459 break;
1460 }
1461 match self.eval_block(&node.body, Rc::clone(&env))? {
1462 ControlFlow::Normal => {}
1463 ControlFlow::Continue => continue,
1464 ControlFlow::Break => break,
1465 other => return Ok(other),
1466 }
1467 }
1468 Ok(ControlFlow::Normal)
1469 }
1470 Statement::TryStatement(node) => self.eval_try_statement(node, env),
1471 Statement::ReturnStatement(node) => Ok(ControlFlow::Return(
1472 self.eval_optional_expr(node.argument.as_ref(), env)?,
1473 )),
1474 Statement::LoopControlStatement(node) => match node.keyword.as_str() {
1475 "next" | "continue" => Ok(ControlFlow::Continue),
1476 "last" => Ok(ControlFlow::Break),
1477 _ => Err(ZuzuRustError::runtime(format!(
1478 "unsupported loop control '{}'",
1479 node.keyword
1480 ))),
1481 },
1482 Statement::ThrowStatement(node) => {
1483 let value = self.eval_expression(&node.argument, env)?;
1484 self.annotate_exception_metadata(&value, node.source_file.as_deref(), node.line);
1485 match &value {
1486 Value::String(text) => Err(ZuzuRustError::thrown(text.clone())),
1487 _ => Err(ZuzuRustError::thrown_with_token(
1488 self.render_value(&value)?,
1489 self.store_thrown_value(value)?,
1490 )),
1491 }
1492 }
1493 Statement::DieStatement(node) => {
1494 let value = self.eval_expression(&node.argument, env)?;
1495 let value =
1496 self.normalize_die_value(value, node.source_file.as_deref(), node.line)?;
1497 Err(ZuzuRustError::thrown_with_token(
1498 self.render_value(&value)?,
1499 self.store_thrown_value(value)?,
1500 ))
1501 }
1502 Statement::PostfixConditionalStatement(node) => {
1503 let test =
1504 self.value_is_truthy(&self.eval_expression(&node.test, Rc::clone(&env))?)?;
1505 let should_run = if node.keyword == "if" { test } else { !test };
1506 if should_run {
1507 self.eval_statement(&node.statement, env)
1508 } else {
1509 Ok(ControlFlow::Normal)
1510 }
1511 }
1512 Statement::KeywordStatement(node) => {
1513 match node.keyword.as_str() {
1514 "say" => {
1515 let values = self.eval_arguments(&node.arguments, env)?;
1516 let line = values
1517 .iter()
1518 .map(|value| self.render_value(value))
1519 .collect::<Result<Vec<_>>>()?
1520 .join("");
1521 self.emit_stdout(&format!("{line}\n"))?;
1522 }
1523 "print" => {
1524 let values = self.eval_arguments(&node.arguments, env)?;
1525 let text = values
1526 .iter()
1527 .map(|value| self.render_value(value))
1528 .collect::<Result<Vec<_>>>()?
1529 .join("");
1530 self.emit_stdout(&text)?;
1531 }
1532 "warn" => {
1533 let values = self.eval_arguments(&node.arguments, env)?;
1534 let text = values
1535 .iter()
1536 .map(|value| self.render_value(value))
1537 .collect::<Result<Vec<_>>>()?
1538 .join("");
1539 self.emit_stderr(&format!("{text}\n"))?;
1540 }
1541 "debug" => {
1542 let level = if let Some(expr) = node.arguments.first() {
1543 self.value_to_number(&self.eval_expression(expr, Rc::clone(&env))?)?
1544 as u32
1545 } else {
1546 0
1547 };
1548 if level <= self.policy.debug_level {
1549 let message = if let Some(expr) = node.arguments.get(1) {
1550 self.render_value(&self.eval_expression(expr, env)?)?
1551 } else {
1552 String::new()
1553 };
1554 self.emit_stderr(&format!("{message}\n"))?;
1555 }
1556 }
1557 "assert" => {
1558 if self.policy.debug_level > 0 {
1559 let value = if let Some(expr) = node.arguments.first() {
1560 self.eval_expression(expr, env)?
1561 } else {
1562 Value::Null
1563 };
1564 if !self.value_is_truthy(&value)? {
1565 return Err(ZuzuRustError::thrown("Assertion failed"));
1566 }
1567 }
1568 }
1569 other => {
1570 return Err(ZuzuRustError::runtime(format!(
1571 "unsupported keyword statement '{}'",
1572 other
1573 )))
1574 }
1575 }
1576 Ok(ControlFlow::Normal)
1577 }
1578 Statement::ExpressionStatement(node) => {
1579 let _ = self.eval_expression(&node.expression, env)?;
1580 Ok(ControlFlow::Normal)
1581 }
1582 Statement::ForStatement(node) => self.eval_for_statement(node, env),
1583 Statement::SwitchStatement(node) => self.eval_switch_statement(node, env),
1584 }
1585 }
1586
1587 fn eval_variable_unpack_declaration(
1588 &self,
1589 node: &VariableUnpackDeclaration,
1590 env: Rc<Environment>,
1591 ) -> Result<Value> {
1592 let source = self.eval_expression(&node.init, Rc::clone(&env))?;
1593 let source_value = self.deref_value(&source)?;
1594 let mut resolved = Vec::new();
1595 for entry in node.pattern.entries() {
1596 let value = self.resolve_unpack_entry(entry, &source_value, Rc::clone(&env))?;
1597 if entry.runtime_typecheck_required != Some(false) {
1598 self.assert_declared_type(entry.declared_type.as_deref(), &value, &entry.name)?;
1599 }
1600 resolved.push((entry, value));
1601 }
1602 for (entry, value) in resolved {
1603 env.define_with_storage(
1604 entry.name.clone(),
1605 value,
1606 node.kind != "const",
1607 entry.is_weak_storage,
1608 );
1609 }
1610 Ok(source)
1611 }
1612
1613 fn resolve_unpack_entry(
1614 &self,
1615 entry: &DeclarationBindingEntry,
1616 source: &Value,
1617 env: Rc<Environment>,
1618 ) -> Result<Value> {
1619 let key = self.eval_dict_key(&entry.key, Rc::clone(&env))?;
1620 let value = match source {
1621 Value::Dict(map) | Value::SystemDict(map) => map.get(&key).cloned(),
1622 Value::PairList(values) => values
1623 .iter()
1624 .find(|(entry_key, _)| entry_key == &key)
1625 .map(|(_, value)| value.clone()),
1626 other => {
1627 return Err(ZuzuRustError::runtime(format!(
1628 "Declaration unpacking expects Dict or PairList, got {}",
1629 other.type_name()
1630 )))
1631 }
1632 };
1633 match value {
1634 Some(value) => Ok(value),
1635 None => match &entry.default_value {
1636 Some(default_value) => self.eval_expression(default_value, env),
1637 None => Ok(Value::Null),
1638 },
1639 }
1640 }
1641
1642 fn eval_block(&self, block: &BlockStatement, env: Rc<Environment>) -> Result<ControlFlow> {
1643 let block_env = if block.needs_lexical_scope {
1644 Rc::new(Environment::new(Some(env)))
1645 } else {
1646 env
1647 };
1648 self.push_special_props_scope();
1649 let result = self.eval_statements(&block.statements, Rc::clone(&block_env));
1650 if block.needs_lexical_scope {
1651 match &result {
1652 Ok(ControlFlow::Return(value)) | Ok(ControlFlow::Throw(value)) => {
1653 self.cleanup_scope_preserving(&block_env, &[value])?;
1654 }
1655 _ => self.cleanup_scope(&block_env)?,
1656 }
1657 }
1658 self.pop_special_props_scope();
1659 result
1660 }
1661
1662 fn eval_try_statement(&self, node: &TryStatement, env: Rc<Environment>) -> Result<ControlFlow> {
1663 match self.eval_block(&node.body, Rc::clone(&env)) {
1664 Err(ZuzuRustError::Thrown { value, token }) => {
1665 let thrown_value = self.lookup_thrown_value(token.as_deref());
1666 for handler in &node.handlers {
1667 if !self.catch_clause_matches(
1668 handler.binding.as_ref(),
1669 &value,
1670 thrown_value.as_ref(),
1671 ) {
1672 continue;
1673 }
1674 let catch_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
1675 let binding_name = handler
1676 .binding
1677 .as_ref()
1678 .and_then(|binding| binding.name.clone())
1679 .unwrap_or_else(|| "e".to_owned());
1680 let caught_value = self.make_catch_binding_value(
1681 handler.binding.as_ref(),
1682 &value,
1683 thrown_value.as_ref(),
1684 );
1685 catch_env.define(binding_name, caught_value, true);
1686 let flow = self.eval_block(&handler.body, catch_env)?;
1687 return Ok(flow);
1688 }
1689 match token {
1690 Some(token) => Err(ZuzuRustError::thrown_with_token(value, token)),
1691 None => Err(ZuzuRustError::thrown(value)),
1692 }
1693 }
1694 Err(err) => {
1695 let rendered = err.to_string();
1696 for handler in &node.handlers {
1697 if !self.catch_clause_matches(handler.binding.as_ref(), &rendered, None) {
1698 continue;
1699 }
1700 let catch_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
1701 let binding_name = handler
1702 .binding
1703 .as_ref()
1704 .and_then(|binding| binding.name.clone())
1705 .unwrap_or_else(|| "e".to_owned());
1706 let caught_value =
1707 self.make_catch_binding_value(handler.binding.as_ref(), &rendered, None);
1708 catch_env.define(binding_name, caught_value, true);
1709 let flow = self.eval_block(&handler.body, catch_env)?;
1710 return Ok(flow);
1711 }
1712 Err(err)
1713 }
1714 Ok(ControlFlow::Throw(value)) => {
1715 for handler in &node.handlers {
1716 if !self.catch_clause_matches(
1717 handler.binding.as_ref(),
1718 &value.render(),
1719 Some(&value),
1720 ) {
1721 continue;
1722 }
1723 let catch_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
1724 if let Some(binding) = &handler.binding {
1725 if let Some(name) = &binding.name {
1726 catch_env.define(name.clone(), value.clone(), true);
1727 }
1728 }
1729 let flow = self.eval_block(&handler.body, catch_env)?;
1730 return Ok(flow);
1731 }
1732 Ok(ControlFlow::Throw(value))
1733 }
1734 Ok(other) => Ok(other),
1735 }
1736 }
1737
1738 fn catch_clause_matches(
1739 &self,
1740 binding: Option<&crate::ast::CatchBinding>,
1741 thrown_value: &str,
1742 thrown_runtime_value: Option<&Value>,
1743 ) -> bool {
1744 let Some(binding) = binding else {
1745 return true;
1746 };
1747 let Some(declared_type) = binding.declared_type.as_deref() else {
1748 return true;
1749 };
1750 if declared_type == "Any" {
1751 return true;
1752 }
1753 if let Some(value) = thrown_runtime_value {
1754 return self.value_matches_declared_type(declared_type, value);
1755 }
1756 match declared_type {
1757 "Exception" => true,
1758 "BailOutException" => thrown_value.starts_with("Bail out!"),
1759 "TypeException" => thrown_value.starts_with("TypeException:"),
1760 "CancelledException" => thrown_value.starts_with("CancelledException:"),
1761 "TimeoutException" => thrown_value.starts_with("TimeoutException:"),
1762 "ChannelClosedException" => thrown_value.starts_with("ChannelClosedException:"),
1763 "MarshallingException" => thrown_value.starts_with("MarshallingException:"),
1764 "UnmarshallingException" => thrown_value.starts_with("UnmarshallingException:"),
1765 "ExhaustedException" => {
1766 thrown_value == "ExhaustedException"
1767 || thrown_value.starts_with("ExhaustedException:")
1768 }
1769 _ => false,
1770 }
1771 }
1772
1773 fn eval_for_statement(&self, node: &ForStatement, env: Rc<Environment>) -> Result<ControlFlow> {
1774 let iterable = self.eval_expression(&node.iterable, Rc::clone(&env))?;
1775 let items = self.iterable_items(iterable)?;
1776
1777 if items.is_empty() {
1778 if let Some(else_block) = &node.else_block {
1779 return self.eval_block(else_block, env);
1780 }
1781 return Ok(ControlFlow::Normal);
1782 }
1783
1784 for item in items {
1785 let loop_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
1786 loop_env.define(
1787 node.variable.clone(),
1788 item,
1789 node.binding_kind.as_deref() != Some("const"),
1790 );
1791 match self.eval_statements(&node.body.statements, loop_env)? {
1792 ControlFlow::Normal => {}
1793 ControlFlow::Continue => continue,
1794 ControlFlow::Break => break,
1795 other => return Ok(other),
1796 }
1797 }
1798 Ok(ControlFlow::Normal)
1799 }
1800
1801 fn eval_switch_statement(
1802 &self,
1803 node: &SwitchStatement,
1804 env: Rc<Environment>,
1805 ) -> Result<ControlFlow> {
1806 let discriminant = self.eval_expression(&node.discriminant, Rc::clone(&env))?;
1807 if let Some(index) = &node.index {
1808 for key in self.switch_index_keys(&discriminant) {
1809 if let Some(entry) = index.iter().find(|entry| entry.key == key) {
1810 return self.eval_switch_cases_from(node, entry.case_index, env);
1811 }
1812 }
1813 }
1814 let mut matched = false;
1815 for case in &node.cases {
1816 if !matched {
1817 for (index, value) in case.values.iter().enumerate() {
1818 let operator = case
1819 .operators
1820 .get(index)
1821 .and_then(|value| value.as_deref())
1822 .or(node.comparator.as_deref());
1823 if self.switch_matches(&discriminant, value, operator, Rc::clone(&env))? {
1824 matched = true;
1825 break;
1826 }
1827 }
1828 }
1829 if matched {
1830 let case_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
1831 match self.eval_statements(&case.consequent, case_env)? {
1832 ControlFlow::Normal => return Ok(ControlFlow::Normal),
1833 ControlFlow::Continue => continue,
1834 other => return Ok(other),
1835 }
1836 }
1837 }
1838 if matched {
1839 if let Some(default) = &node.default {
1840 let default_env = Rc::new(Environment::new(Some(env)));
1841 return self.eval_statements(default, default_env);
1842 }
1843 return Ok(ControlFlow::Normal);
1844 }
1845 if let Some(default) = &node.default {
1846 let default_env = Rc::new(Environment::new(Some(env)));
1847 return self.eval_statements(default, default_env);
1848 }
1849 Ok(ControlFlow::Normal)
1850 }
1851
1852 fn eval_switch_cases_from(
1853 &self,
1854 node: &SwitchStatement,
1855 start: usize,
1856 env: Rc<Environment>,
1857 ) -> Result<ControlFlow> {
1858 for case in node.cases.iter().skip(start) {
1859 let case_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
1860 match self.eval_statements(&case.consequent, case_env)? {
1861 ControlFlow::Normal => return Ok(ControlFlow::Normal),
1862 ControlFlow::Continue => continue,
1863 other => return Ok(other),
1864 }
1865 }
1866 if let Some(default) = &node.default {
1867 let default_env = Rc::new(Environment::new(Some(env)));
1868 return self.eval_statements(default, default_env);
1869 }
1870 Ok(ControlFlow::Normal)
1871 }
1872
1873 fn switch_index_keys(&self, value: &Value) -> Vec<String> {
1874 let mut keys = Vec::new();
1875 if let Ok(value) = self.deref_value(value) {
1876 match value {
1877 Value::Null => keys.push("n:".to_owned()),
1878 Value::Boolean(value) => keys.push(format!("b:{value}")),
1879 Value::Number(value) => keys.push(format!("f:{value}")),
1880 Value::String(value) => keys.push(format!("s:{value}")),
1881 _ => {}
1882 }
1883 }
1884 if let Ok(text) = self.value_to_operator_string(value) {
1885 keys.push(format!("q:{text}"));
1886 keys.push(format!("qi:{}", text.to_lowercase()));
1887 }
1888 if let Ok(number) = self.value_to_number(value) {
1889 if number.is_finite() && number.fract() == 0.0 {
1890 keys.push(format!("i:{}", number as i64));
1891 }
1892 }
1893 keys
1894 }
1895
1896 fn switch_matches(
1897 &self,
1898 discriminant: &Value,
1899 candidate: &Expression,
1900 comparator: Option<&str>,
1901 env: Rc<Environment>,
1902 ) -> Result<bool> {
1903 let compare_env = Rc::new(Environment::new(Some(env)));
1904 compare_env.define(
1905 "__zuzu_switch_value".to_owned(),
1906 discriminant.clone(),
1907 false,
1908 );
1909 let left = Expression::Identifier {
1910 line: candidate.line(),
1911 source_file: candidate.source_file().map(ToOwned::to_owned),
1912 name: "__zuzu_switch_value".to_owned(),
1913 inferred_type: None,
1914 binding_depth: None,
1915 };
1916 let result = self.eval_binary(comparator.unwrap_or("="), &left, candidate, compare_env)?;
1917 self.value_is_truthy(&result)
1918 }
1919
1920 fn eval_collection_elements(
1921 &self,
1922 elements: &[Expression],
1923 capacity_hint: Option<usize>,
1924 env: Rc<Environment>,
1925 kind: CollectionKind,
1926 ) -> Result<Vec<Value>> {
1927 let mut values = Vec::with_capacity(capacity_hint.unwrap_or(elements.len()));
1928 for element in elements {
1929 let value = self.eval_expression(element, Rc::clone(&env))?;
1930 if matches!(
1931 element,
1932 Expression::Binary { operator, .. } if operator == "..."
1933 ) {
1934 match value {
1935 Value::Array(items) => values.extend(items),
1936 other => values.push(other),
1937 }
1938 } else {
1939 values.push(value);
1940 }
1941 }
1942 if matches!(kind, CollectionKind::Set) {
1943 let mut unique = Vec::with_capacity(values.len());
1944 for value in values {
1945 push_unique(&mut unique, value);
1946 }
1947 return Ok(unique);
1948 }
1949 Ok(values)
1950 }
1951
1952 fn eval_import(&self, node: &ImportDeclaration, env: Rc<Environment>) -> Result<()> {
1953 if let Some(condition) = &node.condition {
1954 let test =
1955 self.value_is_truthy(&self.eval_expression(&condition.test, Rc::clone(&env))?)?;
1956 let should_import = if condition.keyword == "if" {
1957 test
1958 } else {
1959 !test
1960 };
1961 if !should_import {
1962 self.bind_null_imports(node, env);
1963 return Ok(());
1964 }
1965 }
1966
1967 let exports = match self.load_module_exports(&node.source) {
1968 Ok(exports) => exports,
1969 Err(_) if node.try_mode => {
1970 self.bind_null_imports(node, env);
1971 return Ok(());
1972 }
1973 Err(err) => return Err(err),
1974 };
1975 if node.import_all {
1976 for (name, value) in exports {
1977 if name.starts_with('_') {
1978 continue;
1979 }
1980 env.define(name, value, true);
1981 }
1982 } else {
1983 for specifier in &node.specifiers {
1984 let value = exports.get(&specifier.imported).cloned().ok_or_else(|| {
1985 ZuzuRustError::runtime(format!(
1986 "module '{}' does not export '{}'",
1987 node.source, specifier.imported
1988 ))
1989 })?;
1990 env.define(specifier.local.clone(), value, true);
1991 }
1992 }
1993 Ok(())
1994 }
1995
1996 fn bind_null_imports(&self, node: &ImportDeclaration, env: Rc<Environment>) {
1997 if node.import_all {
1998 return;
1999 }
2000 for specifier in &node.specifiers {
2001 env.define(specifier.local.clone(), Value::Null, false);
2002 }
2003 }
2004
2005 pub(in crate::runtime) fn load_module_exports(
2006 &self,
2007 name: &str,
2008 ) -> Result<HashMap<String, Value>> {
2009 if name.split('/').any(|segment| segment == "..") {
2010 return Err(ZuzuRustError::runtime(
2011 "import module path cannot contain '..' segments",
2012 ));
2013 }
2014 if self.module_denied_as_missing(name) {
2015 return Err(ZuzuRustError::runtime(format!(
2016 "module '{}' not found",
2017 name
2018 )));
2019 }
2020 if self.is_denied_module(name) {
2021 return Err(ZuzuRustError::runtime(format!(
2022 "module '{}' is denied by runtime policy",
2023 name
2024 )));
2025 }
2026 if let Some(cached) = self.module_cache.borrow().get(name) {
2027 return Ok(cached.exports.clone());
2028 }
2029 if self.module_loading.borrow().contains(name) {
2030 return Err(ZuzuRustError::thrown("circular module loading detected"));
2031 }
2032
2033 if name == "std/gui/objects" && self.is_denied("gui") {
2034 return Err(ZuzuRustError::thrown(
2035 "std/gui/objects is denied by runtime policy",
2036 ));
2037 }
2038
2039 if let Some(exports) = self.load_runtime_supported_module(name) {
2040 self.module_cache.borrow_mut().insert(
2041 name.to_owned(),
2042 ModuleRecord {
2043 exports: exports.clone(),
2044 },
2045 );
2046 return Ok(exports);
2047 }
2048
2049 self.module_loading.borrow_mut().insert(name.to_owned());
2050 let result = (|| {
2051 let path = self.resolve_module_path(name)?;
2052 let source = fs::read_to_string(&path)?;
2053 let source_file = path.display().to_string();
2054 let options = self.parse_options();
2055 let program = parse_program_with_compile_options_and_source_file(
2056 &source,
2057 &options,
2058 Some(&source_file),
2059 )?;
2060 self.emit_semantic_warnings(&program)?;
2061 let env = Rc::new(Environment::new(None));
2062 self.install_builtins(&env);
2063 self.define_file_const(&env, Some(&source_file), true);
2064 match self.eval_program(&program, Rc::clone(&env))? {
2065 ControlFlow::Normal => {}
2066 ControlFlow::Return(_) => {
2067 return Err(ZuzuRustError::runtime(format!(
2068 "module '{}' returned from top level",
2069 name
2070 )))
2071 }
2072 ControlFlow::Throw(value) => {
2073 return Err(ZuzuRustError::runtime(format!(
2074 "module '{}' threw during import: {}",
2075 name, value
2076 )))
2077 }
2078 ControlFlow::Continue | ControlFlow::Break => {
2079 return Err(ZuzuRustError::runtime(format!(
2080 "module '{}' used loop control at top level",
2081 name
2082 )))
2083 }
2084 }
2085
2086 let exports = env.export_public_aliases(Rc::clone(&env));
2087 self.module_cache.borrow_mut().insert(
2088 name.to_owned(),
2089 ModuleRecord {
2090 exports: exports.clone(),
2091 },
2092 );
2093 Ok(exports)
2094 })();
2095 self.module_loading.borrow_mut().remove(name);
2096 result
2097 }
2098
2099 fn resolve_module_path(&self, name: &str) -> Result<PathBuf> {
2100 for root in &self.module_roots {
2101 for ext in ["zzm", "zzs"] {
2102 let path = root.join(format!("{name}.{ext}"));
2103 if path.exists() {
2104 return Ok(path);
2105 }
2106 }
2107 }
2108 Err(ZuzuRustError::runtime(format!(
2109 "module '{}' not found",
2110 name
2111 )))
2112 }
2113
2114 pub(super) fn is_denied(&self, capability: &str) -> bool {
2115 if capability == "js" {
2116 return true;
2117 }
2118 self.policy.denied_capabilities.contains(capability)
2119 || matches!(
2120 self.get_special_prop(&format!("deny_{capability}")),
2121 Value::Boolean(true)
2122 )
2123 }
2124
2125 #[allow(dead_code)]
2126 pub(super) fn assert_capability(&self, capability: &str, message: &str) -> Result<()> {
2127 if self.is_denied(capability) {
2128 return Err(ZuzuRustError::runtime(message.to_owned()));
2129 }
2130 Ok(())
2131 }
2132
2133 fn is_denied_module(&self, name: &str) -> bool {
2134 self.policy.denied_modules.contains(name)
2135 }
2136
2137 fn module_denied_as_missing(&self, name: &str) -> bool {
2138 (self.is_denied("fs") && name.starts_with("std/io"))
2139 || (self.is_denied("net") && name.starts_with("std/net"))
2140 || (self.is_denied("net") && name == "std/io/socks")
2141 || (self.is_denied("proc") && name == "std/proc")
2142 || (self.is_denied("db") && name == "std/db")
2143 || (self.is_denied("clib") && name == "std/clib")
2144 || (self.is_denied("js") && name == "javascript")
2145 || (self.is_denied("worker") && name == "std/worker")
2146 }
2147
2148 pub(in crate::runtime) fn push_special_props_scope(&self) {
2149 self.special_props.borrow_mut().push(HashMap::new());
2150 }
2151
2152 pub(in crate::runtime) fn pop_special_props_scope(&self) {
2153 let mut props = self.special_props.borrow_mut();
2154 if props.len() > 1 {
2155 props.pop();
2156 }
2157 }
2158
2159 pub(in crate::runtime) fn is_effectively_denied(&self, capability: &str) -> bool {
2160 self.is_denied(capability)
2161 }
2162
2163 pub(in crate::runtime) fn denial_flag(&self, capability: &str) -> bool {
2164 matches!(capability, "perl" | "js") || self.is_denied(capability)
2165 }
2166
2167 pub(in crate::runtime) fn child_runtime_policy(
2168 &self,
2169 extra_denials: &[(String, bool)],
2170 ) -> RuntimePolicy {
2171 let mut policy = self.policy.clone();
2172 for capability in DENIAL_CAPABILITIES {
2173 if self.denial_flag(capability) {
2174 policy = policy.deny_capability(*capability);
2175 }
2176 }
2177 for (capability, denied) in extra_denials {
2178 if *denied {
2179 policy = policy.deny_capability(capability.clone());
2180 }
2181 }
2182 policy
2183 }
2184
2185 pub(in crate::runtime) fn module_roots_clone(&self) -> Vec<PathBuf> {
2186 self.module_roots.clone()
2187 }
2188
2189 pub(in crate::runtime) fn enter_async_context<T>(&self, f: impl FnOnce() -> T) -> T {
2190 self.async_executor.enter(f)
2191 }
2192
2193 pub(in crate::runtime) fn check_worker_cancelled(&self) -> Result<()> {
2194 if self
2195 .worker_cancel_requested
2196 .as_ref()
2197 .map(|flag| flag.load(Ordering::SeqCst))
2198 .unwrap_or(false)
2199 {
2200 return Err(ZuzuRustError::thrown(
2201 "CancelledException: worker cancelled",
2202 ));
2203 }
2204 Ok(())
2205 }
2206
2207 fn get_special_prop(&self, key: &str) -> Value {
2208 for frame in self.special_props.borrow().iter().rev() {
2209 if let Some(value) = frame.get(key) {
2210 return value.clone();
2211 }
2212 }
2213 Value::Null
2214 }
2215
2216 pub(in crate::runtime) fn set_special_prop(&self, key: &str, value: Value) -> Value {
2217 let mut props = self.special_props.borrow_mut();
2218 if let Some(frame) = props.last_mut() {
2219 frame.insert(key.to_owned(), value.clone());
2220 }
2221 value
2222 }
2223
2224 fn set_special_prop_at_level(&self, level: usize, key: &str, value: Value) -> Value {
2225 let mut props = self.special_props.borrow_mut();
2226 let Some(index) = props.len().checked_sub(1 + level) else {
2227 return value;
2228 };
2229 if let Some(frame) = props.get_mut(index) {
2230 frame.insert(key.to_owned(), value.clone());
2231 }
2232 value
2233 }
2234
2235 fn get_special_prop_at_level(&self, level: usize, key: &str) -> Value {
2236 let props = self.special_props.borrow();
2237 let Some(index) = props.len().checked_sub(1 + level) else {
2238 return Value::Null;
2239 };
2240 props
2241 .get(index)
2242 .and_then(|frame| frame.get(key))
2243 .cloned()
2244 .unwrap_or(Value::Null)
2245 }
2246
2247 pub(in crate::runtime) fn store_thrown_value(&self, value: Value) -> Result<String> {
2248 let mut next_id = self.next_thrown_id.borrow_mut();
2249 *next_id += 1;
2250 let token = format!("thrown:{}", *next_id);
2251 self.thrown_values.borrow_mut().insert(token.clone(), value);
2252 Ok(token)
2253 }
2254
2255 fn lookup_thrown_value(&self, token: Option<&str>) -> Option<Value> {
2256 token.and_then(|key| self.thrown_values.borrow().get(key).cloned())
2257 }
2258
2259 fn load_runtime_supported_module(&self, name: &str) -> Option<HashMap<String, Value>> {
2260 stdlib::load_runtime_supported_module(name)
2261 }
2262
2263 fn current_system_value(&self) -> Value {
2264 Value::SystemDict(HashMap::from([
2265 ("runtime".to_owned(), Value::String("zuzu-rust".to_owned())),
2266 ("language_version".to_owned(), Value::Number(0.0)),
2267 (
2268 "runtime_version".to_owned(),
2269 Value::String(env!("CARGO_PKG_VERSION").to_owned()),
2270 ),
2271 (
2272 "platform".to_owned(),
2273 Value::String(std::env::consts::OS.to_owned()),
2274 ),
2275 (
2276 "inc".to_owned(),
2277 Value::SystemArray(
2278 self.module_roots
2279 .iter()
2280 .map(|path| Value::String(path.to_string_lossy().into_owned()))
2281 .collect(),
2282 ),
2283 ),
2284 ("deny_fs".to_owned(), Value::Boolean(self.is_denied("fs"))),
2285 ("deny_net".to_owned(), Value::Boolean(self.is_denied("net"))),
2286 ("deny_perl".to_owned(), Value::Boolean(true)),
2287 ("deny_js".to_owned(), Value::Boolean(true)),
2288 (
2289 "deny_proc".to_owned(),
2290 Value::Boolean(self.is_denied("proc")),
2291 ),
2292 ("deny_db".to_owned(), Value::Boolean(self.is_denied("db"))),
2293 (
2294 "deny_clib".to_owned(),
2295 Value::Boolean(self.is_denied("clib")),
2296 ),
2297 ("deny_gui".to_owned(), Value::Boolean(self.is_denied("gui"))),
2298 (
2299 "deny_worker".to_owned(),
2300 Value::Boolean(self.is_denied("worker")),
2301 ),
2302 ]))
2303 }
2304
2305 fn make_function_from_decl(
2306 &self,
2307 node: &FunctionDeclaration,
2308 env: Rc<Environment>,
2309 ) -> FunctionValue {
2310 FunctionValue {
2311 name: Some(node.name.clone()),
2312 params: node.params.clone(),
2313 return_type: node.return_type.clone(),
2314 body: Rc::new(RefCell::new(if node.is_predeclared {
2315 FunctionBody::Bodyless
2316 } else {
2317 FunctionBody::Block(node.body.clone())
2318 })),
2319 env,
2320 is_async: node.is_async,
2321 current_method: None,
2322 }
2323 }
2324
2325 fn make_user_class_from_decl(
2326 &self,
2327 node: &ClassDeclaration,
2328 env: Rc<Environment>,
2329 ) -> Result<UserClassValue> {
2330 let base = match &node.base {
2331 Some(name) => match env.get(name)? {
2332 Value::UserClass(class) => Some(ClassBase::User(class)),
2333 Value::Class(name) => Some(ClassBase::Builtin(name.as_ref().clone())),
2334 _ => return Err(ZuzuRustError::runtime(format!("'{}' is not a class", name))),
2335 },
2336 None => None,
2337 };
2338
2339 let class_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
2340 let mut fields = Vec::new();
2341 let mut nested_classes = HashMap::new();
2342 for member in &node.body {
2343 match member {
2344 ClassMember::Field(field) => fields.push(self.make_field_spec(field)),
2345 ClassMember::Class(class) => {
2346 let mut nested_class =
2347 self.make_user_class_from_decl(class, Rc::clone(&class_env))?;
2348 nested_class.name = format!("{}{{\"{}\"}}", node.name, class.name);
2349 let nested = Rc::new(nested_class);
2350 class_env.define(
2351 class.name.clone(),
2352 Value::UserClass(Rc::clone(&nested)),
2353 false,
2354 );
2355 nested_classes.insert(class.name.clone(), nested);
2356 }
2357 ClassMember::Method(_) | ClassMember::Trait(_) => {}
2358 }
2359 }
2360
2361 let mut methods = HashMap::new();
2362 let mut static_methods = HashMap::new();
2363 for member in &node.body {
2364 match member {
2365 ClassMember::Method(method) => {
2366 if method.is_static {
2367 self.install_method_decl(
2368 &mut static_methods,
2369 method,
2370 Rc::clone(&class_env),
2371 )?;
2372 } else {
2373 self.install_method_decl(&mut methods, method, Rc::clone(&class_env))?;
2374 }
2375 }
2376 ClassMember::Field(_) | ClassMember::Class(_) | ClassMember::Trait(_) => {}
2377 }
2378 }
2379
2380 let mut traits = Vec::new();
2381 for trait_name in &node.traits {
2382 match env.get(trait_name)? {
2383 Value::Trait(trait_value) => traits.push(trait_value),
2384 _ => {
2385 return Err(ZuzuRustError::runtime(format!(
2386 "'{}' is not a trait",
2387 trait_name
2388 )))
2389 }
2390 }
2391 }
2392
2393 Ok(UserClassValue {
2394 name: node.name.clone(),
2395 base,
2396 traits,
2397 fields,
2398 methods,
2399 static_methods,
2400 nested_classes,
2401 source_decl: Some(node.clone()),
2402 closure_env: Some(env),
2403 })
2404 }
2405
2406 fn make_field_spec(&self, node: &FieldDeclaration) -> FieldSpec {
2407 FieldSpec {
2408 name: node.name.clone(),
2409 declared_type: node.declared_type.clone(),
2410 mutable: node.kind != "const",
2411 accessors: node.accessors.clone(),
2412 default_value: node.default_value.clone(),
2413 is_weak_storage: node.is_weak_storage,
2414 }
2415 }
2416
2417 fn make_method_from_decl(&self, node: &MethodDeclaration, env: Rc<Environment>) -> MethodValue {
2418 MethodValue {
2419 name: node.name.clone(),
2420 params: node.params.clone(),
2421 return_type: node.return_type.clone(),
2422 body: node.body.clone(),
2423 env,
2424 is_static: node.is_static,
2425 is_async: node.is_async,
2426 is_bodyless: node.is_predeclared,
2427 bound_receiver: None,
2428 bound_name: None,
2429 }
2430 }
2431
2432 fn install_method_decl(
2433 &self,
2434 methods: &mut HashMap<String, Rc<MethodValue>>,
2435 node: &MethodDeclaration,
2436 env: Rc<Environment>,
2437 ) -> Result<()> {
2438 if let Some(existing) = methods.get(&node.name) {
2439 if existing.is_bodyless && !node.is_predeclared {
2440 methods.insert(
2441 node.name.clone(),
2442 Rc::new(self.make_method_from_decl(node, env)),
2443 );
2444 return Ok(());
2445 }
2446 return Err(ZuzuRustError::runtime(format!(
2447 "Redeclaration of '{}' in the same scope",
2448 node.name
2449 )));
2450 }
2451 methods.insert(
2452 node.name.clone(),
2453 Rc::new(self.make_method_from_decl(node, env)),
2454 );
2455 Ok(())
2456 }
2457
2458 fn function_body_for_method(&self, method: &MethodValue) -> FunctionBody {
2459 if method.is_bodyless {
2460 FunctionBody::Bodyless
2461 } else {
2462 FunctionBody::Block(method.body.clone())
2463 }
2464 }
2465
2466 fn install_builtins(&self, env: &Environment) {
2467 for name in [
2468 "Any",
2469 "Class",
2470 "Null",
2471 "Object",
2472 "Collection",
2473 "Boolean",
2474 "Number",
2475 "String",
2476 "BinaryString",
2477 "Regexp",
2478 "Function",
2479 "Pair",
2480 "PairList",
2481 "Array",
2482 "Bag",
2483 "Set",
2484 "Dict",
2485 "ExhaustedException",
2486 "TypeException",
2487 "CancelledException",
2488 "TimeoutException",
2489 "ChannelClosedException",
2490 ] {
2491 env.define(
2492 name.to_owned(),
2493 Value::builtin_class(name.to_owned()),
2494 false,
2495 );
2496 }
2497 env.define(
2498 "Exception".to_owned(),
2499 Value::UserClass(Rc::new(UserClassValue {
2500 name: "Exception".to_owned(),
2501 base: None,
2502 traits: Vec::new(),
2503 fields: exception_field_specs(),
2504 methods: HashMap::new(),
2505 static_methods: HashMap::new(),
2506 nested_classes: HashMap::new(),
2507 source_decl: None,
2508 closure_env: None,
2509 })),
2510 false,
2511 );
2512 env.define(
2513 "DEBUG".to_owned(),
2514 Value::Number(self.policy.debug_level as f64),
2515 false,
2516 );
2517 for name in ["to_binary", "to_string"] {
2518 env.define(
2519 name.to_owned(),
2520 Value::native_function(name.to_owned()),
2521 false,
2522 );
2523 }
2524 env.define("__global__".to_owned(), Value::Dict(HashMap::new()), true);
2525 env.define("__system__".to_owned(), self.current_system_value(), false);
2526 }
2527
2528 fn file_value_for_source(&self, source_file: Option<&str>, force_absolute: bool) -> Value {
2529 let Some(source_file) = source_file else {
2530 return Value::Null;
2531 };
2532 if self.is_denied("fs") || source_file.is_empty() || source_file.starts_with('<') {
2533 return Value::Null;
2534 }
2535 let mut path = PathBuf::from(source_file);
2536 if force_absolute && !path.is_absolute() {
2537 let base = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
2538 path = absolutize_module_path(path, &base);
2539 }
2540 stdlib::path_value(path)
2541 }
2542
2543 fn define_file_const(
2544 &self,
2545 env: &Environment,
2546 source_file: Option<&str>,
2547 force_absolute: bool,
2548 ) {
2549 env.define(
2550 "__file__".to_owned(),
2551 self.file_value_for_source(source_file, force_absolute),
2552 false,
2553 );
2554 }
2555
2556 fn eval_arguments(&self, arguments: &[Expression], env: Rc<Environment>) -> Result<Vec<Value>> {
2557 arguments
2558 .iter()
2559 .map(|argument| self.eval_expression(argument, Rc::clone(&env)))
2560 .collect()
2561 }
2562
2563 fn eval_optional_expr(&self, expr: Option<&Expression>, env: Rc<Environment>) -> Result<Value> {
2564 match expr {
2565 Some(expr) => self.eval_expression(expr, env),
2566 None => Ok(Value::Null),
2567 }
2568 }
2569
2570 fn eval_expression(&self, expr: &Expression, env: Rc<Environment>) -> Result<Value> {
2571 match expr {
2572 Expression::Identifier {
2573 name,
2574 binding_depth,
2575 ..
2576 } => {
2577 if name == "__system__" {
2578 return Ok(self.current_system_value());
2579 }
2580 let value = env.get_resolved(*binding_depth, name)?;
2581 match value {
2582 Value::AliasRef(reference) => self.call_ref(reference, Vec::new(), Vec::new()),
2583 other => Ok(other),
2584 }
2585 }
2586 Expression::NumberLiteral { value, .. } => {
2587 Ok(Value::Number(value.parse::<f64>().map_err(|_| {
2588 ZuzuRustError::runtime(format!("invalid number literal '{}'", value))
2589 })?))
2590 }
2591 Expression::StringLiteral { value, .. } => Ok(Value::String(value.clone())),
2592 Expression::BinaryStringLiteral { bytes, .. } => Ok(Value::BinaryString(bytes.clone())),
2593 Expression::RegexLiteral {
2594 pattern,
2595 parts,
2596 flags,
2597 cache_key,
2598 ..
2599 } => {
2600 if parts.is_empty()
2601 && cache_key.is_some()
2602 && self.optimizations.enables(OptimizationPass::RegexCache)
2603 {
2604 let _ = self.compile_regex(pattern, flags)?;
2605 }
2606 let pattern = if parts.is_empty() {
2607 pattern.clone()
2608 } else {
2609 self.render_template_parts(parts, Rc::clone(&env))?
2610 };
2611 Ok(Value::Regex(pattern, flags.clone()))
2612 }
2613 Expression::BooleanLiteral { value, .. } => Ok(Value::Boolean(*value)),
2614 Expression::NullLiteral { .. } => Ok(Value::Null),
2615 Expression::ArrayLiteral {
2616 elements,
2617 capacity_hint,
2618 ..
2619 } => Ok(Value::Array(
2620 self.eval_collection_elements(
2621 elements,
2622 *capacity_hint,
2623 env,
2624 CollectionKind::Array,
2625 )?
2626 .into_iter()
2627 .map(Value::into_shared_if_composite)
2628 .collect(),
2629 )),
2630 Expression::SetLiteral {
2631 elements,
2632 capacity_hint,
2633 ..
2634 } => {
2635 let mut values = Vec::with_capacity(capacity_hint.unwrap_or(elements.len()));
2636 for value in self.eval_collection_elements(
2637 elements,
2638 *capacity_hint,
2639 env,
2640 CollectionKind::Set,
2641 )? {
2642 push_unique(&mut values, value.into_shared_if_composite());
2643 }
2644 Ok(Value::Set(values))
2645 }
2646 Expression::BagLiteral {
2647 elements,
2648 capacity_hint,
2649 ..
2650 } => Ok(Value::Bag(
2651 self.eval_collection_elements(elements, *capacity_hint, env, CollectionKind::Bag)?
2652 .into_iter()
2653 .map(Value::into_shared_if_composite)
2654 .collect(),
2655 )),
2656 Expression::DictLiteral {
2657 entries,
2658 capacity_hint,
2659 ..
2660 } => {
2661 let mut map = HashMap::with_capacity(capacity_hint.unwrap_or(entries.len()));
2662 for entry in entries {
2663 let key = self.eval_dict_key(&entry.key, Rc::clone(&env))?;
2664 let value = self.eval_expression(&entry.value, Rc::clone(&env))?;
2665 map.insert(key, value.into_shared_if_composite());
2666 }
2667 Ok(Value::Dict(map))
2668 }
2669 Expression::PairListLiteral {
2670 entries,
2671 capacity_hint,
2672 ..
2673 } => {
2674 let mut values = Vec::with_capacity(capacity_hint.unwrap_or(entries.len()));
2675 for entry in entries {
2676 let key = self.eval_dict_key(&entry.key, Rc::clone(&env))?;
2677 let value = self.eval_expression(&entry.value, Rc::clone(&env))?;
2678 values.push((key, value.into_shared_if_composite()));
2679 }
2680 Ok(Value::PairList(values))
2681 }
2682 Expression::TemplateLiteral { parts, .. } => {
2683 Ok(Value::String(self.render_template_parts(parts, env)?))
2684 }
2685 Expression::Unary {
2686 operator,
2687 argument,
2688 traits,
2689 ..
2690 } => match operator.as_str() {
2691 "new" => self.eval_new_expression(argument, traits, env),
2692 "not" | "!" | "¬" => Ok(Value::Boolean(
2693 !self.value_is_truthy(&self.eval_expression(argument, env)?)?,
2694 )),
2695 "+" => Ok(Value::Number(
2696 self.value_to_number(&self.eval_expression(argument, env)?)?,
2697 )),
2698 "-" => Ok(Value::Number(
2699 -self.value_to_number(&self.eval_expression(argument, env)?)?,
2700 )),
2701 "abs" => Ok(Value::Number(
2702 self.value_to_number(&self.eval_expression(argument, env)?)?
2703 .abs(),
2704 )),
2705 "sqrt" | "√" => Ok(Value::Number(
2706 self.value_to_number(&self.eval_expression(argument, env)?)?
2707 .sqrt(),
2708 )),
2709 "floor" => Ok(Value::Number(
2710 self.value_to_number(&self.eval_expression(argument, env)?)?
2711 .floor(),
2712 )),
2713 "ceil" => Ok(Value::Number(
2714 self.value_to_number(&self.eval_expression(argument, env)?)?
2715 .ceil(),
2716 )),
2717 "round" => Ok(Value::Number(
2718 self.value_to_number(&self.eval_expression(argument, env)?)?
2719 .round(),
2720 )),
2721 "int" => Ok(Value::Number(
2722 self.value_to_number(&self.eval_expression(argument, env)?)?
2723 .trunc(),
2724 )),
2725 "uc" => Ok(Value::String(
2726 self.value_to_operator_string(&self.eval_expression(argument, env)?)?
2727 .to_uppercase(),
2728 )),
2729 "lc" => Ok(Value::String(
2730 self.value_to_operator_string(&self.eval_expression(argument, env)?)?
2731 .to_lowercase(),
2732 )),
2733 "length" => Ok(Value::Number(
2734 match self.eval_expression(argument, env)? {
2735 Value::BinaryString(bytes) => bytes.len() as f64,
2736 value => self.value_to_operator_string(&value)?.chars().count() as f64,
2737 },
2738 )),
2739 "typeof" => Ok(Value::String(
2740 self.typeof_name(&self.eval_expression(argument, env)?),
2741 )),
2742 "~" => {
2743 let value = self.eval_expression(argument, env)?;
2744 match value {
2745 Value::BinaryString(bytes) => Ok(Value::BinaryString(
2746 bytes.into_iter().map(|byte| !byte).collect(),
2747 )),
2748 _ => Ok(Value::Number(
2749 !(self.value_to_number(&value)? as i64) as f64,
2750 )),
2751 }
2752 }
2753 "\\" if matches!(argument.as_ref(), Expression::Binary { operator, .. } if is_path_operator(operator)) => {
2754 self.eval_path_ref(argument, env)
2755 }
2756 "\\" => Ok(Value::Ref(Rc::new(LvalueRef::Expression {
2757 env,
2758 target: (**argument).clone(),
2759 }))),
2760 "++" if matches!(argument.as_ref(), Expression::Binary { operator, .. } if is_path_operator(operator)) => {
2761 self.eval_path_update(argument, env, 1.0, true)
2762 }
2763 "--" if matches!(argument.as_ref(), Expression::Binary { operator, .. } if is_path_operator(operator)) => {
2764 self.eval_path_update(argument, env, -1.0, true)
2765 }
2766 "++" => self.update_lvalue(argument, env, |value| {
2767 Ok(Value::Number(self.value_to_number(&value)? + 1.0))
2768 }),
2769 "--" => self.update_lvalue(argument, env, |value| {
2770 Ok(Value::Number(self.value_to_number(&value)? - 1.0))
2771 }),
2772 other => Err(ZuzuRustError::runtime(format!(
2773 "unsupported unary operator '{}'",
2774 other
2775 ))),
2776 },
2777 Expression::Binary {
2778 operator,
2779 left,
2780 right,
2781 ..
2782 } => self.eval_binary(operator, left, right, env),
2783 Expression::Ternary {
2784 test,
2785 consequent,
2786 alternate,
2787 ..
2788 } => {
2789 if self.value_is_truthy(&self.eval_expression(test, Rc::clone(&env))?)? {
2790 self.eval_expression(consequent, env)
2791 } else {
2792 self.eval_expression(alternate, env)
2793 }
2794 }
2795 Expression::DefinedOr { left, right, .. } => {
2796 let left_value = self.eval_expression(left, Rc::clone(&env))?;
2797 if self.value_is_nullish(&left_value)? {
2798 self.eval_expression(right, env)
2799 } else {
2800 Ok(left_value)
2801 }
2802 }
2803 Expression::Assignment {
2804 operator,
2805 left,
2806 right,
2807 is_weak_write,
2808 ..
2809 } => {
2810 if operator == "~=" {
2811 if let Expression::Binary {
2812 operator: path_operator,
2813 left: path_left,
2814 right: path_right,
2815 ..
2816 } = left.as_ref()
2817 {
2818 if is_path_operator(path_operator) {
2819 let payload = self.build_path_regex_payload(right, Rc::clone(&env))?;
2820 return self.assign_path_target(
2821 path_operator,
2822 path_left,
2823 path_right,
2824 operator,
2825 payload,
2826 false,
2827 env,
2828 );
2829 }
2830 }
2831 }
2832 if operator == "~=" {
2833 let current = self.eval_expression(left, Rc::clone(&env))?;
2834 let replacement =
2835 self.apply_regex_replacement(current, right, Rc::clone(&env))?;
2836 self.assign_lvalue(left, replacement, false, env)
2837 } else {
2838 let right_value = self.eval_expression(right, Rc::clone(&env))?;
2839 self.assign(operator, left, right_value, *is_weak_write, env)
2840 }
2841 }
2842 Expression::Call {
2843 callee, arguments, ..
2844 } => match callee.as_ref() {
2845 Expression::MemberAccess { object, member, .. } => {
2846 self.invoke_method_expression(object, member, arguments, env)
2847 }
2848 _ => {
2849 let callee = self.eval_expression(callee, Rc::clone(&env))?;
2850 let (values, named_args) =
2851 self.eval_call_arguments(arguments, Rc::clone(&env))?;
2852 self.with_current_env(env, || self.call_value(callee, values, named_args))
2853 }
2854 },
2855 Expression::DynamicMemberCall {
2856 object,
2857 member,
2858 arguments,
2859 ..
2860 } => {
2861 let receiver = self.eval_expression(object, Rc::clone(&env))?;
2862 let member_value = self.eval_expression(member, Rc::clone(&env))?;
2863 let method_name = match member_value {
2864 Value::Method(method) => method.name.clone(),
2865 other => self.render_value(&other)?,
2866 };
2867 let (values, named_args) =
2868 self.eval_method_call_arguments(arguments, Rc::clone(&env))?;
2869 let mut receiver = receiver;
2870 self.call_method_named(&mut receiver, &method_name, &values, named_args)
2871 }
2872 Expression::MemberAccess { object, member, .. } => {
2873 let mut object = self.eval_expression(object, env)?;
2874 self.call_method(&mut object, member, &[])
2875 }
2876 Expression::Index { object, index, .. } => {
2877 let object = self.eval_expression(object, Rc::clone(&env))?;
2878 let index = self.eval_expression(index, env)?;
2879 self.eval_index(object, index)
2880 }
2881 Expression::Slice {
2882 object, start, end, ..
2883 } => {
2884 let object = self.eval_expression(object, Rc::clone(&env))?;
2885 let start = self.eval_optional_expr(start.as_deref(), Rc::clone(&env))?;
2886 let end = self.eval_optional_expr(end.as_deref(), env)?;
2887 self.eval_slice(object, start, end)
2888 }
2889 Expression::DictAccess { object, key, .. } => {
2890 let object = self.deref_value(&self.eval_expression(object, Rc::clone(&env))?)?;
2891 let key = self.eval_dict_key(key, env)?;
2892 match object {
2893 Value::Dict(map) | Value::SystemDict(map) => {
2894 Ok(map.get(&key).cloned().unwrap_or(Value::Null))
2895 }
2896 Value::Pair(pair_key, value) => Ok(if key == "pair" {
2897 Value::Array(vec![Value::String(pair_key), *value])
2898 } else {
2899 Value::Null
2900 }),
2901 Value::PairList(values) => Ok(values
2902 .iter()
2903 .find(|(entry_key, _)| entry_key == &key)
2904 .map(|(_, value)| value.clone())
2905 .unwrap_or(Value::Null)),
2906 Value::Object(object) => Ok(object
2907 .borrow()
2908 .fields
2909 .get(&key)
2910 .cloned()
2911 .or_else(|| {
2912 self.find_method(&object.borrow().class, &key)
2913 .and_then(|_| {
2914 self.marshal_bind_method(
2915 Value::Object(Rc::clone(&object)),
2916 &key,
2917 )
2918 .ok()
2919 })
2920 })
2921 .or_else(|| {
2922 object
2923 .borrow()
2924 .class
2925 .nested_classes
2926 .get(&key)
2927 .map(|class| Value::UserClass(Rc::clone(class)))
2928 })
2929 .unwrap_or(Value::Null)),
2930 Value::UserClass(class) => Ok(class
2931 .methods
2932 .get(&key)
2933 .cloned()
2934 .map(Value::Method)
2935 .or_else(|| class.static_methods.get(&key).cloned().map(Value::Method))
2936 .or_else(|| {
2937 class
2938 .nested_classes
2939 .get(&key)
2940 .map(|nested| Value::UserClass(Rc::clone(nested)))
2941 })
2942 .unwrap_or(Value::Null)),
2943 _ => Err(ZuzuRustError::runtime(
2944 "dict access requires a Dict or object value",
2945 )),
2946 }
2947 }
2948 Expression::PostfixUpdate {
2949 operator, argument, ..
2950 } => {
2951 if matches!(argument.as_ref(), Expression::Binary { operator, .. } if is_path_operator(operator))
2952 {
2953 return self.eval_path_update(
2954 argument,
2955 env,
2956 if operator == "++" { 1.0 } else { -1.0 },
2957 false,
2958 );
2959 }
2960 let previous = self.eval_expression(argument, Rc::clone(&env))?;
2961 let delta = match operator.as_str() {
2962 "++" => 1.0,
2963 "--" => -1.0,
2964 other => {
2965 return Err(ZuzuRustError::runtime(format!(
2966 "unsupported postfix operator '{}'",
2967 other
2968 )))
2969 }
2970 };
2971 let _ = self.update_lvalue(argument, env, |value| {
2972 Ok(Value::Number(self.value_to_number(&value)? + delta))
2973 })?;
2974 Ok(previous)
2975 }
2976 Expression::FunctionExpression {
2977 params,
2978 return_type,
2979 body,
2980 is_async,
2981 ..
2982 } => Ok(Value::Function(Rc::new(FunctionValue {
2983 name: None,
2984 params: params.clone(),
2985 return_type: return_type.clone(),
2986 body: Rc::new(RefCell::new(FunctionBody::Block(body.clone()))),
2987 env,
2988 is_async: *is_async,
2989 current_method: None,
2990 }))),
2991 Expression::Lambda {
2992 params,
2993 body,
2994 is_async,
2995 ..
2996 } => Ok(Value::Function(Rc::new(FunctionValue {
2997 name: None,
2998 params: params.clone(),
2999 return_type: None,
3000 body: Rc::new(RefCell::new(FunctionBody::Expression((**body).clone()))),
3001 env,
3002 is_async: *is_async,
3003 current_method: None,
3004 }))),
3005 Expression::LetExpression {
3006 kind,
3007 name,
3008 init,
3009 is_weak_storage,
3010 ..
3011 } => {
3012 let value = match init {
3013 Some(init) => self.eval_expression(init, Rc::clone(&env))?,
3014 None => Value::Null,
3015 };
3016 env.define_with_storage(
3017 name.clone(),
3018 value.clone(),
3019 kind != "const",
3020 *is_weak_storage,
3021 );
3022 Ok(value)
3023 }
3024 Expression::DoExpression { body, .. } => self.eval_do_expression(body, env),
3025 Expression::AwaitExpression { body, .. } => {
3026 let value = self.eval_do_expression(body, env)?;
3027 self.await_value(value)
3028 }
3029 Expression::SpawnExpression { body, .. } => {
3030 let task = Rc::new(RefCell::new(TaskState {
3031 status: "pending".to_owned(),
3032 kind: TaskKind::Spawn {
3033 body: body.clone(),
3034 env,
3035 started: false,
3036 },
3037 outcome: None,
3038 }));
3039 self.background_tasks.borrow_mut().push(Rc::clone(&task));
3040 self.schedule_task_driver(Rc::clone(&task));
3041 Ok(Value::Task(task))
3042 }
3043 Expression::TryExpression { body, handlers, .. } => {
3044 self.eval_try_expression(body, handlers, env)
3045 }
3046 Expression::SuperCall { arguments, .. } => {
3047 let (values, named_args) = self.eval_call_arguments(arguments, Rc::clone(&env))?;
3048 if !named_args.is_empty() {
3049 return Err(ZuzuRustError::runtime(
3050 "named arguments are not implemented for super()",
3051 ));
3052 }
3053 self.eval_super_call(values, env)
3054 }
3055 }
3056 }
3057
3058 fn render_template_parts(
3059 &self,
3060 parts: &[TemplatePart],
3061 env: Rc<Environment>,
3062 ) -> Result<String> {
3063 let mut out = String::new();
3064 for part in parts {
3065 match part {
3066 TemplatePart::Text { value, .. } => out.push_str(value),
3067 TemplatePart::Expression { expression, .. } => {
3068 let value = self.eval_expression(expression, Rc::clone(&env))?;
3069 out.push_str(&self.render_value(&value)?);
3070 }
3071 }
3072 }
3073 Ok(out)
3074 }
3075
3076 fn eval_call_arguments(
3077 &self,
3078 arguments: &[CallArgument],
3079 env: Rc<Environment>,
3080 ) -> Result<(Vec<Value>, Vec<(String, Value)>)> {
3081 let mut positional = Vec::with_capacity(arguments.len());
3082 let mut named = Vec::new();
3083 for argument in arguments {
3084 match argument {
3085 CallArgument::Positional { value, .. } => {
3086 positional.push(self.eval_expression(value, Rc::clone(&env))?);
3087 }
3088 CallArgument::Spread { value, .. } => {
3089 let spread_value = self.eval_expression(value, Rc::clone(&env))?;
3090 self.expand_call_spread_argument(spread_value, &mut positional, &mut named)?;
3091 }
3092 CallArgument::Named { name, value, .. } => {
3093 named.push((
3094 self.eval_dict_key(name, Rc::clone(&env))?,
3095 self.eval_expression(value, Rc::clone(&env))?,
3096 ));
3097 }
3098 }
3099 }
3100 Ok((positional, named))
3101 }
3102
3103 fn eval_method_call_arguments(
3104 &self,
3105 arguments: &[CallArgument],
3106 env: Rc<Environment>,
3107 ) -> Result<(Vec<Value>, Vec<(String, Value)>)> {
3108 self.eval_call_arguments(arguments, env)
3109 }
3110
3111 fn expand_call_spread_argument(
3112 &self,
3113 value: Value,
3114 positional: &mut Vec<Value>,
3115 named: &mut Vec<(String, Value)>,
3116 ) -> Result<()> {
3117 let value = self.deref_value(&value)?;
3118 match value {
3119 Value::Array(values) | Value::SystemArray(values) => {
3120 positional.extend(values);
3121 Ok(())
3122 }
3123 Value::Dict(values) | Value::SystemDict(values) => {
3124 let mut keys: Vec<_> = values.keys().cloned().collect();
3125 keys.sort();
3126 for key in keys {
3127 named.push((
3128 key.clone(),
3129 values.get(&key).cloned().unwrap_or(Value::Null),
3130 ));
3131 }
3132 Ok(())
3133 }
3134 Value::PairList(values) => {
3135 named.extend(values);
3136 Ok(())
3137 }
3138 other => Err(ZuzuRustError::runtime(format!(
3139 "spread call argument expects Array, Dict, or PairList; got {}",
3140 other.type_name()
3141 ))),
3142 }
3143 }
3144
3145 fn eval_path_haystack_argument(
3146 &self,
3147 expr: &Expression,
3148 env: Rc<Environment>,
3149 ) -> Result<Value> {
3150 self.eval_expression(expr, env)
3151 }
3152
3153 fn eval_binary(
3154 &self,
3155 operator: &str,
3156 left: &Expression,
3157 right: &Expression,
3158 env: Rc<Environment>,
3159 ) -> Result<Value> {
3160 match operator {
3161 "and" | "⋀" => {
3162 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3163 if !self.value_is_truthy(&left_value)? {
3164 return Ok(Value::Boolean(false));
3165 }
3166 Ok(Value::Boolean(
3167 self.value_is_truthy(&self.eval_expression(right, env)?)?,
3168 ))
3169 }
3170 "and?" | "⋀?" => {
3171 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3172 if self.value_is_truthy(&left_value)? {
3173 return self.eval_expression(right, env);
3174 }
3175 Ok(left_value)
3176 }
3177 "or" | "⋁" => {
3178 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3179 if self.value_is_truthy(&left_value)? {
3180 return Ok(Value::Boolean(true));
3181 }
3182 Ok(Value::Boolean(
3183 self.value_is_truthy(&self.eval_expression(right, env)?)?,
3184 ))
3185 }
3186 "or?" | "⋁?" => {
3187 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3188 if self.value_is_truthy(&left_value)? {
3189 return Ok(left_value);
3190 }
3191 self.eval_expression(right, env)
3192 }
3193 "nor" | "⊽" => {
3194 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3195 if self.value_is_truthy(&left_value)? {
3196 return Ok(Value::Boolean(false));
3197 }
3198 Ok(Value::Boolean(
3199 !self.value_is_truthy(&self.eval_expression(right, env)?)?,
3200 ))
3201 }
3202 "nor?" | "⊽?" => {
3203 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3204 let right_value = self.eval_expression(right, env)?;
3205 if self.value_is_truthy(&left_value)? {
3206 if self.value_is_truthy(&right_value)? {
3207 Ok(Value::Boolean(false))
3208 } else {
3209 Ok(right_value)
3210 }
3211 } else if self.value_is_truthy(&right_value)? {
3212 Ok(left_value)
3213 } else {
3214 Ok(Value::Boolean(true))
3215 }
3216 }
3217 "xor" | "⊻" => {
3218 let lhs = self.value_is_truthy(&self.eval_expression(left, Rc::clone(&env))?)?;
3219 let rhs = self.value_is_truthy(&self.eval_expression(right, env)?)?;
3220 Ok(Value::Boolean(lhs ^ rhs))
3221 }
3222 "xor?" | "⊻?" => {
3223 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3224 let right_value = self.eval_expression(right, env)?;
3225 if self.value_is_truthy(&left_value)? {
3226 if self.value_is_truthy(&right_value)? {
3227 Ok(Value::Boolean(false))
3228 } else {
3229 Ok(left_value)
3230 }
3231 } else if self.value_is_truthy(&right_value)? {
3232 Ok(right_value)
3233 } else {
3234 Ok(Value::Boolean(false))
3235 }
3236 }
3237 "xnor" | "↔" => {
3238 let lhs = self.value_is_truthy(&self.eval_expression(left, Rc::clone(&env))?)?;
3239 let rhs = self.value_is_truthy(&self.eval_expression(right, env)?)?;
3240 Ok(Value::Boolean(lhs == rhs))
3241 }
3242 "xnor?" | "↔?" => {
3243 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3244 let right_value = self.eval_expression(right, env)?;
3245 if self.value_is_truthy(&left_value)? {
3246 Ok(right_value)
3247 } else if self.value_is_truthy(&right_value)? {
3248 Ok(left_value)
3249 } else {
3250 Ok(Value::Boolean(true))
3251 }
3252 }
3253 "nand" | "⊼" => {
3254 let lhs = self.value_is_truthy(&self.eval_expression(left, Rc::clone(&env))?)?;
3255 let rhs = self.value_is_truthy(&self.eval_expression(right, env)?)?;
3256 Ok(Value::Boolean(!(lhs && rhs)))
3257 }
3258 "nand?" | "⊼?" => {
3259 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3260 let right_value = self.eval_expression(right, env)?;
3261 if self.value_is_truthy(&left_value)? {
3262 if self.value_is_truthy(&right_value)? {
3263 Ok(Value::Boolean(false))
3264 } else {
3265 Ok(Value::Boolean(true))
3266 }
3267 } else if self.value_is_truthy(&right_value)? {
3268 Ok(right_value)
3269 } else {
3270 Ok(Value::Boolean(true))
3271 }
3272 }
3273 "onlyif" | "⊨" => {
3274 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3275 if !self.value_is_truthy(&left_value)? {
3276 return Ok(Value::Boolean(true));
3277 }
3278 Ok(Value::Boolean(
3279 self.value_is_truthy(&self.eval_expression(right, env)?)?,
3280 ))
3281 }
3282 "onlyif?" | "⊨?" => {
3283 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3284 if self.value_is_truthy(&left_value)? {
3285 return self.eval_expression(right, env);
3286 }
3287 Ok(Value::Boolean(true))
3288 }
3289 "butnot" | "⊭" => {
3290 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3291 if !self.value_is_truthy(&left_value)? {
3292 return Ok(Value::Boolean(false));
3293 }
3294 Ok(Value::Boolean(
3295 !self.value_is_truthy(&self.eval_expression(right, env)?)?,
3296 ))
3297 }
3298 "butnot?" | "⊭?" => {
3299 let left_value = self.eval_expression(left, Rc::clone(&env))?;
3300 if !self.value_is_truthy(&left_value)? {
3301 return Ok(left_value);
3302 }
3303 if self.value_is_truthy(&self.eval_expression(right, env)?)? {
3304 Ok(Value::Boolean(false))
3305 } else {
3306 Ok(left_value)
3307 }
3308 }
3309 "▷" | "|>" => {
3310 let value = self.eval_expression(left, Rc::clone(&env))?;
3311 let chain_env = Rc::new(Environment::new(Some(env)));
3312 chain_env.define("^^".to_owned(), value, false);
3313 self.eval_expression(right, chain_env)
3314 }
3315 "◁" | "<|" => {
3316 let value = self.eval_expression(right, Rc::clone(&env))?;
3317 let chain_env = Rc::new(Environment::new(Some(env)));
3318 chain_env.define("^^".to_owned(), value, false);
3319 self.eval_expression(left, chain_env)
3320 }
3321 "..." => {
3322 let start =
3323 self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)? as i64;
3324 let end = self.value_to_number(&self.eval_expression(right, env)?)? as i64;
3325 let mut values = Vec::new();
3326 if start <= end {
3327 for value in start..=end {
3328 values.push(Value::Number(value as f64));
3329 }
3330 } else {
3331 for value in (end..=start).rev() {
3332 values.push(Value::Number(value as f64));
3333 }
3334 }
3335 Ok(Value::Array(values))
3336 }
3337 "default" => {
3338 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3339 let rhs = self.eval_expression(right, env)?;
3340 self.eval_default_operator(lhs, rhs)
3341 }
3342 "_" => {
3343 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3344 let rhs = self.eval_expression(right, env)?;
3345 self.concat_values(lhs, rhs)
3346 }
3347 "+" | "-" | "*" | "×" | "/" | "÷" | "mod" | "**" => {
3348 let lhs = self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3349 let rhs = self.value_to_number(&self.eval_expression(right, env)?)?;
3350 let value = match operator {
3351 "+" => lhs + rhs,
3352 "-" => lhs - rhs,
3353 "*" | "×" => lhs * rhs,
3354 "/" | "÷" => lhs / rhs,
3355 "mod" => lhs % rhs,
3356 "**" => lhs.powf(rhs),
3357 _ => unreachable!(),
3358 };
3359 Ok(Value::Number(value))
3360 }
3361 ">" | "<" | ">=" | "≤" | "<=" | "≥" | "=" | "!=" | "≠" | "==" | "≡" | "≢" | "eq"
3362 | "ne" | "gt" | "ge" | "lt" | "le" | "eqi" | "nei" | "gti" | "gei" | "lti" | "lei" => {
3363 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3364 let rhs = self.eval_expression(right, env)?;
3365 let result = match operator {
3366 ">" => self.value_to_number(&lhs)? > self.value_to_number(&rhs)?,
3367 "<" => self.value_to_number(&lhs)? < self.value_to_number(&rhs)?,
3368 ">=" | "≥" => self.value_to_number(&lhs)? >= self.value_to_number(&rhs)?,
3369 "<=" | "≤" => self.value_to_number(&lhs)? <= self.value_to_number(&rhs)?,
3370 "=" => {
3371 if lhs.is_numeric_comparable() && rhs.is_numeric_comparable() {
3372 self.value_to_number(&lhs)? == self.value_to_number(&rhs)?
3373 } else {
3374 lhs.coerced_eq(&rhs)
3375 }
3376 }
3377 "!=" | "≠" => {
3378 if lhs.is_numeric_comparable() && rhs.is_numeric_comparable() {
3379 self.value_to_number(&lhs)? != self.value_to_number(&rhs)?
3380 } else {
3381 !lhs.strict_eq(&rhs)
3382 }
3383 }
3384 "==" | "≡" => lhs.strict_eq(&rhs),
3385 "≢" => !lhs.strict_eq(&rhs),
3386 "eq" => {
3387 self.value_to_operator_string(&lhs)?
3388 == self.value_to_operator_string(&rhs)?
3389 }
3390 "ne" => {
3391 self.value_to_operator_string(&lhs)?
3392 != self.value_to_operator_string(&rhs)?
3393 }
3394 "gt" => {
3395 self.value_to_operator_string(&lhs)?
3396 > self.value_to_operator_string(&rhs)?
3397 }
3398 "ge" => {
3399 self.value_to_operator_string(&lhs)?
3400 >= self.value_to_operator_string(&rhs)?
3401 }
3402 "lt" => {
3403 self.value_to_operator_string(&lhs)?
3404 < self.value_to_operator_string(&rhs)?
3405 }
3406 "le" => {
3407 self.value_to_operator_string(&lhs)?
3408 <= self.value_to_operator_string(&rhs)?
3409 }
3410 "eqi" => {
3411 self.value_to_operator_string(&lhs)?.to_lowercase()
3412 == self.value_to_operator_string(&rhs)?.to_lowercase()
3413 }
3414 "nei" => {
3415 self.value_to_operator_string(&lhs)?.to_lowercase()
3416 != self.value_to_operator_string(&rhs)?.to_lowercase()
3417 }
3418 "gti" => {
3419 self.value_to_operator_string(&lhs)?.to_lowercase()
3420 > self.value_to_operator_string(&rhs)?.to_lowercase()
3421 }
3422 "gei" => {
3423 self.value_to_operator_string(&lhs)?.to_lowercase()
3424 >= self.value_to_operator_string(&rhs)?.to_lowercase()
3425 }
3426 "lti" => {
3427 self.value_to_operator_string(&lhs)?.to_lowercase()
3428 < self.value_to_operator_string(&rhs)?.to_lowercase()
3429 }
3430 "lei" => {
3431 self.value_to_operator_string(&lhs)?.to_lowercase()
3432 <= self.value_to_operator_string(&rhs)?.to_lowercase()
3433 }
3434 _ => unreachable!(),
3435 };
3436 Ok(Value::Boolean(result))
3437 }
3438 "~" => {
3439 let target =
3440 self.value_to_operator_string(&self.eval_expression(left, Rc::clone(&env))?)?;
3441 let regex = self.eval_expression(right, env)?;
3442 self.eval_regex_match(&target, ®ex)
3443 }
3444 "<=>" | "≶" | "≷" => {
3445 let lhs = self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3446 let rhs = self.value_to_number(&self.eval_expression(right, env)?)?;
3447 let cmp = if lhs < rhs {
3448 -1.0
3449 } else if lhs > rhs {
3450 1.0
3451 } else {
3452 0.0
3453 };
3454 Ok(Value::Number(cmp))
3455 }
3456 "cmp" | "cmpi" => {
3457 let lhs =
3458 self.value_to_operator_string(&self.eval_expression(left, Rc::clone(&env))?)?;
3459 let rhs = self.value_to_operator_string(&self.eval_expression(right, env)?)?;
3460 let (lhs, rhs) = if operator == "cmpi" {
3461 (lhs.to_lowercase(), rhs.to_lowercase())
3462 } else {
3463 (lhs, rhs)
3464 };
3465 let cmp = if lhs < rhs {
3466 -1.0
3467 } else if lhs > rhs {
3468 1.0
3469 } else {
3470 0.0
3471 };
3472 Ok(Value::Number(cmp))
3473 }
3474 "&" | "|" | "^" => {
3475 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3476 let rhs = self.eval_expression(right, env)?;
3477 self.eval_bitwise(operator, lhs, rhs)
3478 }
3479 "<<" | "«" | ">>" | "»" => {
3480 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3481 let rhs = self.eval_expression(right, env)?;
3482 self.eval_shift(operator, lhs, rhs)
3483 }
3484 "∣" | "divides" | "∤" => {
3485 let lhs = self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3486 let rhs = self.value_to_number(&self.eval_expression(right, env)?)?;
3487 let remainder = rhs % lhs;
3489 Ok(if operator == "∤" {
3490 Value::Number(remainder)
3491 } else {
3492 Value::Boolean(remainder == 0.0)
3493 })
3494 }
3495 "instanceof" => {
3496 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3497 let rhs = self.eval_expression(right, env)?;
3498 Ok(Value::Boolean(self.value_instanceof(&lhs, &rhs)))
3499 }
3500 "does" => {
3501 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3502 let rhs = self.eval_expression(right, env)?;
3503 Ok(Value::Boolean(self.value_does_trait(&lhs, &rhs)))
3504 }
3505 "can" => {
3506 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3507 let member = self.member_name_operand(right, env)?;
3508 Ok(Value::Boolean(self.value_can_method(&lhs, &member)))
3509 }
3510 "@" | "@@" | "@?" => self.eval_path_operator(operator, left, right, env),
3511 "in" | "∈" | "∉" => {
3512 let needle = self.eval_expression(left, Rc::clone(&env))?;
3513 let haystack = self.eval_expression(right, env)?;
3514 let contains = match &haystack {
3515 Value::Object(object) => {
3516 self.object_builtin_collection_contains(object, &needle)
3517 }
3518 _ => collection_contains(&haystack, &needle),
3519 };
3520 if operator == "∉" {
3521 Ok(Value::Boolean(!contains))
3522 } else {
3523 Ok(Value::Boolean(contains))
3524 }
3525 }
3526 "union" | "⋃" => {
3527 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3528 let rhs = self.eval_expression(right, env)?;
3529 collection_union(lhs, rhs)
3530 }
3531 "intersection" | "⋂" => {
3532 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3533 let rhs = self.eval_expression(right, env)?;
3534 collection_intersection(lhs, rhs)
3535 }
3536 "\\" | "∖" => {
3537 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3538 let rhs = self.eval_expression(right, env)?;
3539 collection_difference(lhs, rhs)
3540 }
3541 "subsetof" | "⊂" => {
3542 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3543 let rhs = self.eval_expression(right, env)?;
3544 Ok(Value::Boolean(collection_subset(&lhs, &rhs)?))
3545 }
3546 "supersetof" | "⊃" => {
3547 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3548 let rhs = self.eval_expression(right, env)?;
3549 Ok(Value::Boolean(collection_subset(&rhs, &lhs)?))
3550 }
3551 "equivalentof" | "⊂⊃" => {
3552 let lhs = self.eval_expression(left, Rc::clone(&env))?;
3553 let rhs = self.eval_expression(right, env)?;
3554 Ok(Value::Boolean(
3555 collection_subset(&lhs, &rhs)? && collection_subset(&rhs, &lhs)?,
3556 ))
3557 }
3558 other => Err(ZuzuRustError::runtime(format!(
3559 "unsupported binary operator '{}'",
3560 other
3561 ))),
3562 }
3563 }
3564
3565 fn eval_default_operator(&self, lhs: Value, rhs: Value) -> Result<Value> {
3566 let lhs = self.deref_value(&lhs)?;
3567 let rhs = self.deref_value(&rhs)?;
3568 let rhs_type = rhs.type_name();
3569 match lhs {
3570 Value::Dict(mut values) | Value::SystemDict(mut values) => {
3571 match rhs {
3572 Value::Dict(defaults) | Value::SystemDict(defaults) => {
3573 let mut keys: Vec<_> = defaults.keys().cloned().collect();
3574 keys.sort();
3575 for key in keys {
3576 if !values.contains_key(&key) {
3577 values.insert(
3578 key.clone(),
3579 defaults.get(&key).cloned().unwrap_or(Value::Null),
3580 );
3581 }
3582 }
3583 }
3584 Value::PairList(defaults) => {
3585 for (key, value) in defaults {
3586 if !values.contains_key(&key) {
3587 values.insert(key, value);
3588 }
3589 }
3590 }
3591 _ => {
3592 return Err(ZuzuRustError::runtime(format!(
3593 "default operator right operand expects Dict or PairList, got {rhs_type}"
3594 )));
3595 }
3596 }
3597 Ok(Value::Dict(values))
3598 }
3599 Value::PairList(mut values) => {
3600 let original_keys: HashSet<_> = values.iter().map(|(key, _)| key.clone()).collect();
3601 self.append_pairlist_defaults(&mut values, &original_keys, rhs)?;
3602 Ok(Value::PairList(values))
3603 }
3604 Value::Null => {
3605 let original_keys = HashSet::new();
3606 let mut values = Vec::new();
3607 self.append_pairlist_defaults(&mut values, &original_keys, rhs)?;
3608 Ok(Value::PairList(values))
3609 }
3610 other => Err(ZuzuRustError::runtime(format!(
3611 "default operator left operand expects Dict, PairList, or Null, got {}",
3612 other.type_name()
3613 ))),
3614 }
3615 }
3616
3617 fn append_pairlist_defaults(
3618 &self,
3619 values: &mut Vec<(String, Value)>,
3620 original_keys: &HashSet<String>,
3621 defaults: Value,
3622 ) -> Result<()> {
3623 let defaults_type = defaults.type_name();
3624 match defaults {
3625 Value::Dict(defaults) | Value::SystemDict(defaults) => {
3626 let mut keys: Vec<_> = defaults.keys().cloned().collect();
3627 keys.sort();
3628 for key in keys {
3629 if !original_keys.contains(&key) {
3630 values.push((
3631 key.clone(),
3632 defaults.get(&key).cloned().unwrap_or(Value::Null),
3633 ));
3634 }
3635 }
3636 Ok(())
3637 }
3638 Value::PairList(defaults) => {
3639 values.extend(
3640 defaults
3641 .into_iter()
3642 .filter(|(key, _)| !original_keys.contains(key)),
3643 );
3644 Ok(())
3645 }
3646 _ => Err(ZuzuRustError::runtime(format!(
3647 "default operator right operand expects Dict or PairList, got {defaults_type}"
3648 ))),
3649 }
3650 }
3651
3652 fn assign(
3653 &self,
3654 operator: &str,
3655 left: &Expression,
3656 right: Value,
3657 weak_write: bool,
3658 env: Rc<Environment>,
3659 ) -> Result<Value> {
3660 if let Expression::Binary {
3661 operator: path_operator,
3662 left: path_left,
3663 right: path_right,
3664 ..
3665 } = left
3666 {
3667 if is_path_operator(path_operator) {
3668 return self.assign_path_target(
3669 path_operator,
3670 path_left,
3671 path_right,
3672 operator,
3673 right,
3674 weak_write,
3675 env,
3676 );
3677 }
3678 }
3679 match operator {
3680 ":=" => self.assign_lvalue(left, right, weak_write, env),
3681 "?:=" => {
3682 let current = self.eval_expression(left, Rc::clone(&env))?;
3683 if matches!(current, Value::Null) {
3684 self.assign_lvalue(left, right, false, env)
3685 } else {
3686 Ok(current)
3687 }
3688 }
3689 "+=" => {
3690 let current =
3691 self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3692 self.assign_lvalue(
3693 left,
3694 Value::Number(current + self.value_to_number(&right)?),
3695 false,
3696 env,
3697 )
3698 }
3699 "-=" => {
3700 let current =
3701 self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3702 self.assign_lvalue(
3703 left,
3704 Value::Number(current - self.value_to_number(&right)?),
3705 false,
3706 env,
3707 )
3708 }
3709 "*=" | "×=" => {
3710 let current =
3711 self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3712 self.assign_lvalue(
3713 left,
3714 Value::Number(current * self.value_to_number(&right)?),
3715 false,
3716 env,
3717 )
3718 }
3719 "/=" | "÷=" => {
3720 let current =
3721 self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3722 self.assign_lvalue(
3723 left,
3724 Value::Number(current / self.value_to_number(&right)?),
3725 false,
3726 env,
3727 )
3728 }
3729 "**=" => {
3730 let current =
3731 self.value_to_number(&self.eval_expression(left, Rc::clone(&env))?)?;
3732 self.assign_lvalue(
3733 left,
3734 Value::Number(current.powf(self.value_to_number(&right)?)),
3735 false,
3736 env,
3737 )
3738 }
3739 "_=" => {
3740 let current =
3741 self.value_to_operator_string(&self.eval_expression(left, Rc::clone(&env))?)?;
3742 self.assign_lvalue(
3743 left,
3744 Value::String(current + &self.value_to_operator_string(&right)?),
3745 false,
3746 env,
3747 )
3748 }
3749 other => Err(ZuzuRustError::runtime(format!(
3750 "unsupported assignment operator '{}'",
3751 other
3752 ))),
3753 }
3754 }
3755
3756 fn assign_lvalue(
3757 &self,
3758 target: &Expression,
3759 value: Value,
3760 weak_write: bool,
3761 env: Rc<Environment>,
3762 ) -> Result<Value> {
3763 match target {
3764 Expression::Binary {
3765 operator,
3766 left,
3767 right,
3768 ..
3769 } if is_path_operator(operator) => {
3770 self.assign_path_target(operator, left, right, ":=", value, weak_write, env)
3771 }
3772 Expression::Identifier {
3773 name,
3774 binding_depth,
3775 ..
3776 } => match env.get_resolved(*binding_depth, name) {
3777 Ok(Value::AliasRef(reference)) => {
3778 let _ = self.assign_reference_with_weak_write(
3779 reference,
3780 value.clone(),
3781 weak_write,
3782 )?;
3783 Ok(value)
3784 }
3785 Ok(Value::Ref(reference)) => {
3786 let _ = self.assign_reference_with_weak_write(
3787 reference,
3788 value.clone(),
3789 weak_write,
3790 )?;
3791 Ok(value)
3792 }
3793 Ok(_) => {
3794 env.assign_resolved_with_weak_write(
3795 *binding_depth,
3796 name,
3797 value.clone(),
3798 weak_write,
3799 )?;
3800 Ok(value)
3801 }
3802 Err(err) => Err(err),
3803 },
3804 Expression::Index { object, index, .. } => {
3805 self.assign_index_target(object, index, value, weak_write, env)
3806 }
3807 Expression::DictAccess { object, key, .. } => {
3808 self.assign_dict_target(object, key, value, weak_write, env)
3809 }
3810 Expression::Slice {
3811 object, start, end, ..
3812 } => self.assign_slice_target(object, start.as_deref(), end.as_deref(), value, env),
3813 _ => Err(ZuzuRustError::runtime("unsupported assignment target")),
3814 }
3815 }
3816
3817 fn update_lvalue<F>(
3818 &self,
3819 target: &Expression,
3820 env: Rc<Environment>,
3821 update: F,
3822 ) -> Result<Value>
3823 where
3824 F: FnOnce(Value) -> Result<Value>,
3825 {
3826 match target {
3827 Expression::Identifier {
3828 name,
3829 binding_depth,
3830 ..
3831 } => {
3832 let current = env.get_resolved(*binding_depth, name)?;
3833 let reference = match ¤t {
3834 Value::Ref(reference) | Value::AliasRef(reference) => {
3835 Some(Rc::clone(reference))
3836 }
3837 _ => None,
3838 };
3839 let current_value = if let Some(reference) = &reference {
3840 self.deref_value(&Value::AliasRef(Rc::clone(reference)))?
3841 } else {
3842 current
3843 };
3844 let updated = update(current_value)?;
3845 if let Some(reference) = reference {
3846 let _ = self.assign_reference(reference, updated.clone())?;
3847 } else {
3848 env.assign_resolved(*binding_depth, name, updated.clone())?;
3849 }
3850 Ok(updated)
3851 }
3852 Expression::Index { object, index, .. } => {
3853 let current = self.eval_expression(target, Rc::clone(&env))?;
3854 let updated = update(current)?;
3855 self.assign_index_target(object, index, updated, false, env)
3856 }
3857 Expression::DictAccess { object, key, .. } => {
3858 let current = self.eval_expression(target, Rc::clone(&env))?;
3859 let current_value = self.deref_value(¤t)?;
3860 let updated = update(current_value)?;
3861 self.assign_dict_target(object, key, updated, false, env)
3862 }
3863 Expression::Slice {
3864 object, start, end, ..
3865 } => {
3866 let current = self.eval_expression(target, Rc::clone(&env))?;
3867 let updated = update(current)?;
3868 self.assign_slice_target(object, start.as_deref(), end.as_deref(), updated, env)
3869 }
3870 _ => Err(ZuzuRustError::runtime("unsupported update target")),
3871 }
3872 }
3873
3874 fn eval_path_operator(
3875 &self,
3876 operator: &str,
3877 left: &Expression,
3878 right: &Expression,
3879 env: Rc<Environment>,
3880 ) -> Result<Value> {
3881 let haystack = self.eval_path_haystack_argument(left, Rc::clone(&env))?;
3882 let path = self.eval_expression(right, Rc::clone(&env))?;
3883 let mut path_object = self.resolve_path_operand(path)?;
3884 match operator {
3885 "@" => self.call_method(&mut path_object, "first", &[haystack, Value::Null]),
3886 "@@" => self.call_method(&mut path_object, "query", &[haystack]),
3887 "@?" => {
3888 let value = self.call_method(&mut path_object, "exists", &[haystack])?;
3889 Ok(Value::Boolean(value.is_truthy()))
3890 }
3891 _ => Err(ZuzuRustError::runtime(format!(
3892 "unsupported path operator '{}'",
3893 operator
3894 ))),
3895 }
3896 }
3897
3898 fn eval_path_ref(&self, argument: &Expression, env: Rc<Environment>) -> Result<Value> {
3899 let Expression::Binary {
3900 operator,
3901 left,
3902 right,
3903 ..
3904 } = argument
3905 else {
3906 return Err(ZuzuRustError::runtime("expected path expression"));
3907 };
3908 let path = self.eval_expression(right, Rc::clone(&env))?;
3909 let path_object = self.resolve_path_operand(path)?;
3910 let haystack = self.eval_path_haystack_argument(left, Rc::clone(&env))?;
3911 let mut path_object = path_object;
3912 match operator.as_str() {
3913 "@" => self.call_method(&mut path_object, "ref_first", &[haystack]),
3914 "@@" => self.call_method(&mut path_object, "ref_all", &[haystack]),
3915 "@?" => self.call_method(&mut path_object, "ref_maybe", &[haystack]),
3916 _ => Err(ZuzuRustError::runtime(format!(
3917 "unsupported path operator '{}'",
3918 operator
3919 ))),
3920 }
3921 }
3922
3923 fn eval_path_update(
3924 &self,
3925 argument: &Expression,
3926 env: Rc<Environment>,
3927 delta: f64,
3928 prefix: bool,
3929 ) -> Result<Value> {
3930 let Expression::Binary {
3931 operator,
3932 left,
3933 right,
3934 ..
3935 } = argument
3936 else {
3937 return Err(ZuzuRustError::runtime("expected path expression"));
3938 };
3939 let path = self.eval_expression(right, Rc::clone(&env))?;
3940 let path_object = self.resolve_path_operand(path)?;
3941 let haystack = self.eval_expression(left, Rc::clone(&env))?;
3942 let mut path_object = path_object;
3943 match operator.as_str() {
3944 "@" => {
3945 let current =
3946 self.call_method(&mut path_object, "first", &[haystack.clone(), Value::Null])?;
3947 let updated = Value::Number(self.value_to_number(¤t)? + delta);
3948 self.call_method(
3949 &mut path_object,
3950 "assign_first",
3951 &[haystack, updated.clone(), Value::String(":=".to_owned())],
3952 )?;
3953 if prefix {
3954 Ok(updated)
3955 } else {
3956 Ok(current)
3957 }
3958 }
3959 "@@" => {
3960 let current = self.call_method(&mut path_object, "query", &[haystack.clone()])?;
3961 let Value::Array(values) = current.clone() else {
3962 return Err(ZuzuRustError::runtime("@@ query did not return an Array"));
3963 };
3964 let updated_values = values
3965 .iter()
3966 .map(|value| Ok(Value::Number(self.value_to_number(value)? + delta)))
3967 .collect::<Result<Vec<_>>>()?;
3968 let op = if delta >= 0.0 { "+=" } else { "-=" };
3969 self.call_method(
3970 &mut path_object,
3971 "assign_all",
3972 &[
3973 haystack,
3974 Value::Number(delta.abs()),
3975 Value::String(op.to_owned()),
3976 ],
3977 )?;
3978 if prefix {
3979 Ok(Value::Array(updated_values))
3980 } else {
3981 Ok(Value::Array(values))
3982 }
3983 }
3984 "@?" => {
3985 let exists = self.call_method(&mut path_object, "exists", &[haystack.clone()])?;
3986 let matched = exists.is_truthy();
3987 if matched {
3988 let op = if delta >= 0.0 { "+=" } else { "-=" };
3989 self.call_method(
3990 &mut path_object,
3991 "assign_maybe",
3992 &[
3993 haystack,
3994 Value::Number(delta.abs()),
3995 Value::String(op.to_owned()),
3996 ],
3997 )?;
3998 }
3999 Ok(Value::Boolean(matched))
4000 }
4001 _ => Err(ZuzuRustError::runtime(format!(
4002 "unsupported path operator '{}'",
4003 operator
4004 ))),
4005 }
4006 }
4007
4008 fn assign_path_target(
4009 &self,
4010 path_operator: &str,
4011 path_left: &Expression,
4012 path_right: &Expression,
4013 assignment_operator: &str,
4014 value: Value,
4015 weak_write: bool,
4016 env: Rc<Environment>,
4017 ) -> Result<Value> {
4018 let path = self.eval_expression(path_right, Rc::clone(&env))?;
4019 let path_object = self.resolve_path_operand(path)?;
4020 let haystack = self.eval_path_haystack_argument(path_left, Rc::clone(&env))?;
4021 let mut path_object = path_object;
4022 let method = match path_operator {
4023 "@" => "assign_first",
4024 "@@" => "assign_all",
4025 "@?" => "assign_maybe",
4026 _ => {
4027 return Err(ZuzuRustError::runtime(format!(
4028 "unsupported path operator '{}'",
4029 path_operator
4030 )))
4031 }
4032 };
4033 self.call_method(
4034 &mut path_object,
4035 method,
4036 &[
4037 haystack,
4038 value,
4039 Value::String(assignment_operator.to_owned()),
4040 Value::Boolean(weak_write),
4041 ],
4042 )
4043 }
4044
4045 fn build_path_regex_payload(
4046 &self,
4047 replacement: &Expression,
4048 env: Rc<Environment>,
4049 ) -> Result<Value> {
4050 match replacement {
4051 Expression::Binary {
4052 operator,
4053 left,
4054 right,
4055 ..
4056 } if operator == "->" => {
4057 let regex_value = self.eval_expression(left, Rc::clone(&env))?;
4058 let (pattern, flags) = self.coerce_regex_operand(®ex_value).map_err(|_| {
4059 ZuzuRustError::runtime("~= expects a regexp -> replacement expression")
4060 })?;
4061 let callback = FunctionValue {
4062 name: None,
4063 params: vec![Parameter {
4064 line: right.line(),
4065 source_file: right.source_file().map(str::to_owned),
4066 declared_type: None,
4067 name: "m".to_owned(),
4068 optional: false,
4069 variadic: false,
4070 default_value: None,
4071 }],
4072 return_type: None,
4073 body: Rc::new(RefCell::new(FunctionBody::Expression((**right).clone()))),
4074 env,
4075 is_async: false,
4076 current_method: None,
4077 };
4078 Ok(Value::Array(vec![
4079 Value::Regex(pattern, flags),
4080 Value::Function(Rc::new(callback)),
4081 ]))
4082 }
4083 _ => Err(ZuzuRustError::runtime(
4084 "~= expects a regexp -> replacement expression",
4085 )),
4086 }
4087 }
4088
4089 fn resolve_path_operand(&self, path: Value) -> Result<Value> {
4090 match path {
4091 Value::Object(_) => Ok(path),
4092 Value::String(text) => {
4093 let class_value = match self.get_special_prop("paths") {
4094 Value::Null => self
4095 .load_module_exports("std/path/zz")?
4096 .get("ZZPath")
4097 .cloned()
4098 .ok_or_else(|| {
4099 ZuzuRustError::runtime("module 'std/path/zz' does not export 'ZZPath'")
4100 })?,
4101 value => value,
4102 };
4103 self.call_value(
4104 class_value,
4105 Vec::new(),
4106 vec![("path".to_owned(), Value::String(text))],
4107 )
4108 }
4109 other => Err(ZuzuRustError::runtime(format!(
4110 "path operand must be String or path object, got {}",
4111 other.type_name()
4112 ))),
4113 }
4114 }
4115
4116 pub(in crate::runtime) fn task_resolved(&self, value: Value) -> Value {
4117 Value::Task(Rc::new(RefCell::new(TaskState {
4118 status: "fulfilled".to_owned(),
4119 kind: TaskKind::Resolved,
4120 outcome: Some(TaskOutcome::Fulfilled(value)),
4121 })))
4122 }
4123
4124 pub(in crate::runtime) fn task_rejected(&self, message: impl Into<String>) -> Value {
4125 Value::Task(Rc::new(RefCell::new(TaskState {
4126 status: "rejected".to_owned(),
4127 kind: TaskKind::Resolved,
4128 outcome: Some(TaskOutcome::Rejected(message.into())),
4129 })))
4130 }
4131
4132 pub(in crate::runtime) fn task_sleep(&self, seconds: f64) -> Value {
4133 let seconds = if seconds.is_finite() && seconds > 0.0 {
4134 seconds
4135 } else {
4136 0.0
4137 };
4138 Value::Task(Rc::new(RefCell::new(TaskState {
4139 status: "sleeping".to_owned(),
4140 kind: TaskKind::Sleep {
4141 deadline: Instant::now() + Duration::from_secs_f64(seconds),
4142 },
4143 outcome: None,
4144 })))
4145 }
4146
4147 pub(in crate::runtime) fn task_yield(&self) -> Value {
4148 if self.check_worker_cancelled().is_err() {
4149 return self.task_rejected("CancelledException: worker cancelled");
4150 }
4151 self.task_sleep(0.0)
4152 }
4153
4154 pub(in crate::runtime) fn task_all(&self, tasks: Vec<Value>) -> Value {
4155 let task = Rc::new(RefCell::new(TaskState {
4156 status: "waiting".to_owned(),
4157 kind: TaskKind::All { tasks },
4158 outcome: None,
4159 }));
4160 self.schedule_task_driver(Rc::clone(&task));
4161 Value::Task(task)
4162 }
4163
4164 pub(in crate::runtime) fn task_race(&self, tasks: Vec<Value>) -> Value {
4165 let task = Rc::new(RefCell::new(TaskState {
4166 status: "waiting".to_owned(),
4167 kind: TaskKind::Race { tasks },
4168 outcome: None,
4169 }));
4170 self.schedule_task_driver(Rc::clone(&task));
4171 Value::Task(task)
4172 }
4173
4174 pub(in crate::runtime) fn task_timeout(&self, seconds: f64, task: Value) -> Value {
4175 let seconds = if seconds.is_finite() && seconds > 0.0 {
4176 seconds
4177 } else {
4178 0.0
4179 };
4180 let task = Rc::new(RefCell::new(TaskState {
4181 status: "waiting".to_owned(),
4182 kind: TaskKind::Timeout {
4183 deadline: Instant::now() + Duration::from_secs_f64(seconds),
4184 seconds,
4185 task,
4186 },
4187 outcome: None,
4188 }));
4189 self.schedule_task_driver(Rc::clone(&task));
4190 Value::Task(task)
4191 }
4192
4193 pub(in crate::runtime) fn task_channel_recv(
4194 &self,
4195 channel: Rc<RefCell<ChannelState>>,
4196 ) -> Value {
4197 Value::Task(Rc::new(RefCell::new(TaskState {
4198 status: "waiting".to_owned(),
4199 kind: TaskKind::ChannelRecv { channel },
4200 outcome: None,
4201 })))
4202 }
4203
4204 pub(in crate::runtime) fn task_native_async<F>(
4205 &self,
4206 future: F,
4207 cancel_requested: Option<Rc<Cell<bool>>>,
4208 ) -> Value
4209 where
4210 F: Future<Output = Result<Value>> + 'static,
4211 {
4212 let task = Rc::new(RefCell::new(TaskState {
4213 status: "pending".to_owned(),
4214 kind: TaskKind::NativeAsync { cancel_requested },
4215 outcome: None,
4216 }));
4217 self.async_executor
4218 .spawn_local(drive_native_async_task(Rc::clone(&task), future));
4219 Value::Task(task)
4220 }
4221
4222 pub(in crate::runtime) fn register_worker_endpoint(
4223 &self,
4224 endpoint: WorkerEndpointState,
4225 ) -> usize {
4226 let id = {
4227 let mut next_id = self.next_worker_endpoint_id.borrow_mut();
4228 let id = *next_id;
4229 *next_id += 1;
4230 id
4231 };
4232 self.worker_endpoints.borrow_mut().insert(id, endpoint);
4233 id
4234 }
4235
4236 fn task_from_function(
4237 &self,
4238 function: Rc<FunctionValue>,
4239 args: Vec<Value>,
4240 named_args: Vec<(String, Value)>,
4241 ) -> Value {
4242 Value::Task(Rc::new(RefCell::new(TaskState {
4243 status: "pending".to_owned(),
4244 kind: TaskKind::Function {
4245 function,
4246 args,
4247 named_args,
4248 started: false,
4249 },
4250 outcome: None,
4251 })))
4252 }
4253
4254 pub(in crate::runtime) fn await_if_task(&self, value: Value) -> Result<Value> {
4255 match value {
4256 Value::Task(task) => self.await_task(task),
4257 other => Ok(other),
4258 }
4259 }
4260
4261 fn await_value(&self, value: Value) -> Result<Value> {
4262 match value {
4263 Value::Task(task) => self.await_task(task),
4264 other => Err(ZuzuRustError::runtime(format!(
4265 "await block must return a Task, got {}",
4266 other.type_name()
4267 ))),
4268 }
4269 }
4270
4271 fn await_task(&self, task: Rc<RefCell<TaskState>>) -> Result<Value> {
4272 loop {
4273 self.check_worker_cancelled()?;
4274 if self.poll_task(&task)? {
4275 return self.task_result(&task);
4276 }
4277 self.check_worker_cancelled()?;
4278 self.wait_for_task_progress(&task);
4279 }
4280 }
4281
4282 fn schedule_task_driver(&self, task: Rc<RefCell<TaskState>>) {
4283 let runtime = Rc::downgrade(&self.inner);
4284 self.async_executor
4285 .spawn_local(drive_scheduled_task(runtime, task));
4286 }
4287
4288 fn wait_for_task_progress(&self, task: &Rc<RefCell<TaskState>>) {
4289 if let Some(deadline) = self.next_scheduler_deadline(Some(task)) {
4290 let deadline = if self.worker_cancel_requested.is_some() {
4291 deadline.min(Instant::now() + Duration::from_millis(10))
4292 } else {
4293 deadline
4294 };
4295 self.async_executor.sleep_until(deadline);
4296 } else {
4297 self.async_executor.sleep_for(Duration::from_millis(1));
4298 }
4299 }
4300
4301 fn next_scheduler_deadline(&self, target: Option<&Rc<RefCell<TaskState>>>) -> Option<Instant> {
4302 let mut deadline = target.and_then(|task| self.next_task_deadline(task));
4303 for task in self.background_tasks.borrow().iter() {
4304 if target
4305 .map(|target| Rc::ptr_eq(target, task))
4306 .unwrap_or(false)
4307 {
4308 continue;
4309 }
4310 deadline = earliest_deadline(deadline, self.next_task_deadline(task));
4311 }
4312 deadline
4313 }
4314
4315 fn next_task_deadline(&self, task: &Rc<RefCell<TaskState>>) -> Option<Instant> {
4316 enum Children {
4317 None,
4318 One(Rc<RefCell<TaskState>>),
4319 Many(Vec<Value>),
4320 }
4321
4322 let (deadline, children) = {
4323 let state = task.borrow();
4324 match &state.kind {
4325 TaskKind::Sleep { deadline } => (Some(*deadline), Children::None),
4326 TaskKind::Timeout {
4327 deadline,
4328 task: inner,
4329 ..
4330 } => (Some(*deadline), Children::Many(vec![inner.clone()])),
4331 TaskKind::FunctionWaiting { awaited, .. }
4332 | TaskKind::SpawnWaiting { awaited, .. } => {
4333 (None, Children::One(Rc::clone(awaited)))
4334 }
4335 TaskKind::All { tasks } | TaskKind::Race { tasks } => {
4336 (None, Children::Many(tasks.clone()))
4337 }
4338 TaskKind::Function { .. } | TaskKind::Spawn { .. } => {
4339 (Some(Instant::now()), Children::None)
4340 }
4341 TaskKind::Resolved
4342 | TaskKind::ChannelRecv { .. }
4343 | TaskKind::NativeAsync { .. } => (None, Children::None),
4344 }
4345 };
4346
4347 match children {
4348 Children::None => deadline,
4349 Children::One(child) => earliest_deadline(deadline, self.next_task_deadline(&child)),
4350 Children::Many(values) => values.into_iter().fold(deadline, |current, value| {
4351 let Value::Task(child) = value else {
4352 return current;
4353 };
4354 earliest_deadline(current, self.next_task_deadline(&child))
4355 }),
4356 }
4357 }
4358
4359 fn task_result(&self, task: &Rc<RefCell<TaskState>>) -> Result<Value> {
4360 match task.borrow().outcome.clone() {
4361 Some(TaskOutcome::Fulfilled(value)) => Ok(value),
4362 Some(TaskOutcome::Rejected(message)) => Err(ZuzuRustError::thrown(message)),
4363 Some(TaskOutcome::Cancelled(reason)) => Err(ZuzuRustError::thrown(format!(
4364 "CancelledException: {reason}"
4365 ))),
4366 None => Err(ZuzuRustError::runtime("task is not complete")),
4367 }
4368 }
4369
4370 fn task_outcome_value(&self, task: &Rc<RefCell<TaskState>>) -> Option<TaskOutcome> {
4371 task.borrow().outcome.clone()
4372 }
4373
4374 fn poll_task(&self, task: &Rc<RefCell<TaskState>>) -> Result<bool> {
4375 if task.borrow().outcome.is_some() {
4376 return Ok(true);
4377 }
4378
4379 let task_id = Rc::as_ptr(task) as usize;
4380 {
4381 let mut polling_tasks = self.polling_tasks.borrow_mut();
4382 if polling_tasks.contains(&task_id) {
4383 return Ok(false);
4384 }
4385 polling_tasks.push(task_id);
4386 }
4387 let _polling_guard = PollTaskGuard {
4388 stack: &self.polling_tasks,
4389 task_id,
4390 };
4391
4392 let mut complete = None;
4393 {
4394 let mut state = task.borrow_mut();
4395 match &mut state.kind {
4396 TaskKind::Resolved => {}
4397 TaskKind::Sleep { deadline } => {
4398 if Instant::now() >= *deadline {
4399 complete = Some(TaskOutcome::Fulfilled(Value::Null));
4400 }
4401 }
4402 TaskKind::Function {
4403 function,
4404 args,
4405 named_args,
4406 started,
4407 } => {
4408 *started = true;
4409 let function = Rc::clone(function);
4410 let args = args.clone();
4411 let named_args = named_args.clone();
4412 state.status = "running".to_owned();
4413 drop(state);
4414 let result = self.start_async_function_task(&function, args, named_args);
4415 let mut state = task.borrow_mut();
4416 match result {
4417 Ok(AsyncPoll::Complete(value)) => {
4418 complete = Some(TaskOutcome::Fulfilled(value));
4419 }
4420 Ok(AsyncPoll::Await {
4421 awaited,
4422 frames,
4423 disposition,
4424 }) => {
4425 state.status = "waiting".to_owned();
4426 state.kind = TaskKind::FunctionWaiting {
4427 awaited,
4428 frames,
4429 disposition,
4430 };
4431 return Ok(false);
4432 }
4433 Err(ZuzuRustError::Thrown { value, .. }) => {
4434 complete = Some(TaskOutcome::Rejected(value));
4435 }
4436 Err(err) => {
4437 complete = Some(TaskOutcome::Rejected(err.to_string()));
4438 }
4439 }
4440 state.status = "running".to_owned();
4441 }
4442 TaskKind::FunctionWaiting {
4443 awaited,
4444 frames,
4445 disposition,
4446 } => {
4447 let awaited = Rc::clone(awaited);
4448 let frames = std::mem::take(frames);
4449 let disposition = disposition.clone();
4450 drop(state);
4451 if !self.poll_task(&awaited)? {
4452 let mut state = task.borrow_mut();
4453 state.kind = TaskKind::FunctionWaiting {
4454 awaited,
4455 frames,
4456 disposition,
4457 };
4458 return Ok(false);
4459 }
4460 match self.task_result(&awaited) {
4461 Ok(awaited_value) => {
4462 if matches!(disposition, AwaitDisposition::Return) {
4463 let value = self.finish_async_frames(&frames, awaited_value);
4464 complete = Some(match value {
4465 Ok(value) => TaskOutcome::Fulfilled(value),
4466 Err(ZuzuRustError::Thrown { value, .. }) => {
4467 TaskOutcome::Rejected(value)
4468 }
4469 Err(err) => TaskOutcome::Rejected(err.to_string()),
4470 });
4471 } else {
4472 let result = self.poll_async_frames(frames);
4473 let mut state = task.borrow_mut();
4474 match result {
4475 Ok(AsyncPoll::Complete(value)) => {
4476 complete = Some(TaskOutcome::Fulfilled(value));
4477 }
4478 Ok(AsyncPoll::Await {
4479 awaited,
4480 frames,
4481 disposition,
4482 }) => {
4483 state.status = "waiting".to_owned();
4484 state.kind = TaskKind::FunctionWaiting {
4485 awaited,
4486 frames,
4487 disposition,
4488 };
4489 return Ok(false);
4490 }
4491 Err(ZuzuRustError::Thrown { value, .. }) => {
4492 complete = Some(TaskOutcome::Rejected(value));
4493 }
4494 Err(err) => {
4495 complete = Some(TaskOutcome::Rejected(err.to_string()));
4496 }
4497 }
4498 state.status = "running".to_owned();
4499 }
4500 }
4501 Err(ZuzuRustError::Thrown { value, .. }) => {
4502 self.cleanup_async_frames(&frames)?;
4503 complete = Some(TaskOutcome::Rejected(value));
4504 }
4505 Err(err) => {
4506 self.cleanup_async_frames(&frames)?;
4507 complete = Some(TaskOutcome::Rejected(err.to_string()));
4508 }
4509 }
4510 }
4511 TaskKind::Spawn { body, env, started } => {
4512 *started = true;
4513 let body = body.clone();
4514 let env = Rc::clone(env);
4515 state.status = "running".to_owned();
4516 drop(state);
4517 let needs_lexical_scope = body.needs_lexical_scope;
4518 let body_env = if needs_lexical_scope {
4519 Rc::new(Environment::new(Some(env)))
4520 } else {
4521 env
4522 };
4523 let result = self.poll_async_frames(vec![AsyncFrame::Do {
4524 statements: body.statements,
4525 index: 0,
4526 env: body_env,
4527 cleanup_env: needs_lexical_scope,
4528 last: Value::Null,
4529 }]);
4530 let mut state = task.borrow_mut();
4531 match result {
4532 Ok(AsyncPoll::Complete(value)) => {
4533 complete = Some(TaskOutcome::Fulfilled(value));
4534 }
4535 Ok(AsyncPoll::Await {
4536 awaited,
4537 frames,
4538 disposition,
4539 }) => {
4540 state.status = "waiting".to_owned();
4541 state.kind = TaskKind::SpawnWaiting {
4542 awaited,
4543 frames,
4544 disposition,
4545 };
4546 return Ok(false);
4547 }
4548 Err(ZuzuRustError::Thrown { value, .. }) => {
4549 complete = Some(TaskOutcome::Rejected(value));
4550 }
4551 Err(err) => {
4552 complete = Some(TaskOutcome::Rejected(err.to_string()));
4553 }
4554 }
4555 state.status = "running".to_owned();
4556 }
4557 TaskKind::SpawnWaiting {
4558 awaited,
4559 frames,
4560 disposition,
4561 } => {
4562 let awaited = Rc::clone(awaited);
4563 let mut frames = std::mem::take(frames);
4564 let disposition = disposition.clone();
4565 drop(state);
4566 if !self.poll_task(&awaited)? {
4567 let mut state = task.borrow_mut();
4568 state.kind = TaskKind::SpawnWaiting {
4569 awaited,
4570 frames,
4571 disposition,
4572 };
4573 return Ok(false);
4574 }
4575 match self.task_result(&awaited) {
4576 Ok(awaited_value) => {
4577 if matches!(disposition, AwaitDisposition::StoreLast) {
4578 if let Some(frame) = frames.last_mut() {
4579 frame.set_last(awaited_value);
4580 }
4581 }
4582 let result = self.poll_async_frames(frames);
4583 let mut state = task.borrow_mut();
4584 match result {
4585 Ok(AsyncPoll::Complete(value)) => {
4586 complete = Some(TaskOutcome::Fulfilled(value));
4587 }
4588 Ok(AsyncPoll::Await {
4589 awaited,
4590 frames,
4591 disposition,
4592 }) => {
4593 state.status = "waiting".to_owned();
4594 state.kind = TaskKind::SpawnWaiting {
4595 awaited,
4596 frames,
4597 disposition,
4598 };
4599 return Ok(false);
4600 }
4601 Err(ZuzuRustError::Thrown { value, .. }) => {
4602 complete = Some(TaskOutcome::Rejected(value));
4603 }
4604 Err(err) => {
4605 complete = Some(TaskOutcome::Rejected(err.to_string()));
4606 }
4607 }
4608 state.status = "running".to_owned();
4609 }
4610 Err(ZuzuRustError::Thrown { value, .. }) => {
4611 self.cleanup_async_frames(&frames)?;
4612 complete = Some(TaskOutcome::Rejected(value));
4613 }
4614 Err(err) => {
4615 self.cleanup_async_frames(&frames)?;
4616 complete = Some(TaskOutcome::Rejected(err.to_string()));
4617 }
4618 }
4619 }
4620 TaskKind::All { tasks } => {
4621 let tasks = tasks.clone();
4622 drop(state);
4623 let mut results = Vec::new();
4624 let mut all_done = true;
4625 let mut failed_child: Option<Rc<RefCell<TaskState>>> = None;
4626 for value in &tasks {
4627 match value {
4628 Value::Task(child) => {
4629 if !self.poll_task(child)? {
4630 all_done = false;
4631 results.push(Value::Null);
4632 continue;
4633 }
4634 match self.task_outcome_value(child) {
4635 Some(TaskOutcome::Fulfilled(value)) => results.push(value),
4636 Some(TaskOutcome::Rejected(message)) => {
4637 complete = Some(TaskOutcome::Rejected(message));
4638 failed_child = Some(Rc::clone(child));
4639 break;
4640 }
4641 Some(TaskOutcome::Cancelled(reason)) => {
4642 complete = Some(TaskOutcome::Cancelled(reason));
4643 failed_child = Some(Rc::clone(child));
4644 break;
4645 }
4646 None => all_done = false,
4647 }
4648 }
4649 other => results.push(other.clone()),
4650 }
4651 }
4652 if complete.is_some() {
4653 for value in tasks {
4654 if let Value::Task(child) = value {
4655 if failed_child
4656 .as_ref()
4657 .map(|failed| Rc::ptr_eq(failed, &child))
4658 .unwrap_or(false)
4659 {
4660 continue;
4661 }
4662 self.cancel_task(
4663 &child,
4664 Value::String("Task cancelled".to_owned()),
4665 );
4666 }
4667 }
4668 }
4669 if complete.is_none() && all_done {
4670 complete = Some(TaskOutcome::Fulfilled(Value::Array(results)));
4671 }
4672 }
4673 TaskKind::Race { tasks } => {
4674 let tasks = tasks.clone();
4675 drop(state);
4676 let mut winner: Option<Rc<RefCell<TaskState>>> = None;
4677 for value in &tasks {
4678 match value {
4679 Value::Task(child) => {
4680 if self.poll_task(&child)? {
4681 winner = Some(Rc::clone(&child));
4682 complete = self.task_outcome_value(&child);
4683 break;
4684 }
4685 }
4686 other => {
4687 complete = Some(TaskOutcome::Fulfilled(other.clone()));
4688 break;
4689 }
4690 }
4691 }
4692 if complete.is_some() {
4693 for value in tasks {
4694 if let Value::Task(child) = value {
4695 if winner
4696 .as_ref()
4697 .map(|winner| Rc::ptr_eq(winner, &child))
4698 .unwrap_or(false)
4699 {
4700 continue;
4701 }
4702 self.cancel_task(
4703 &child,
4704 Value::String("race loser cancelled".to_owned()),
4705 );
4706 }
4707 }
4708 }
4709 }
4710 TaskKind::Timeout {
4711 deadline,
4712 seconds,
4713 task: inner,
4714 } => {
4715 let expired = Instant::now() >= *deadline;
4716 let inner = inner.clone();
4717 let message = format!("timeout after {seconds}s");
4718 drop(state);
4719 if expired {
4720 if let Value::Task(child) = &inner {
4721 self.cancel_task(child, Value::String(message.clone()));
4722 }
4723 complete = Some(TaskOutcome::Rejected(format!(
4724 "TimeoutException: {message}"
4725 )));
4726 } else if let Value::Task(child) = inner {
4727 if self.poll_task(&child)? {
4728 complete = self.task_outcome_value(&child);
4729 }
4730 } else {
4731 complete = Some(TaskOutcome::Fulfilled(inner));
4732 }
4733 }
4734 TaskKind::ChannelRecv { channel } => {
4735 let mut channel = channel.borrow_mut();
4736 if !channel.messages.is_empty() {
4737 complete = Some(TaskOutcome::Fulfilled(channel.messages.remove(0)));
4738 } else if channel.closed {
4739 complete = Some(TaskOutcome::Fulfilled(Value::Null));
4740 }
4741 }
4742 TaskKind::NativeAsync { .. } => {}
4743 }
4744 }
4745
4746 if let Some(outcome) = complete {
4747 let mut state = task.borrow_mut();
4748 state.status = match &outcome {
4749 TaskOutcome::Fulfilled(_) => "fulfilled",
4750 TaskOutcome::Rejected(_) => "rejected",
4751 TaskOutcome::Cancelled(_) => "cancelled",
4752 }
4753 .to_owned();
4754 state.outcome = Some(outcome);
4755 return Ok(true);
4756 }
4757 Ok(false)
4758 }
4759
4760 fn cancel_task(&self, task: &Rc<RefCell<TaskState>>, reason: Value) {
4761 if task.borrow().outcome.is_some() {
4762 return;
4763 }
4764 let cancel_requested = {
4765 let state = task.borrow();
4766 match &state.kind {
4767 TaskKind::NativeAsync {
4768 cancel_requested: Some(cancel_requested),
4769 } => Some(Rc::clone(cancel_requested)),
4770 _ => None,
4771 }
4772 };
4773 if let Some(cancel_requested) = cancel_requested {
4774 cancel_requested.set(true);
4775 }
4776 let children = child_tasks_of(task);
4777 let frames = async_frames_of(task);
4778 let reason = reason.render();
4779 {
4780 let mut state = task.borrow_mut();
4781 state.status = "cancelled".to_owned();
4782 state.outcome = Some(TaskOutcome::Cancelled(reason.clone()));
4783 }
4784 for child in children {
4785 self.cancel_task(&child, Value::String(reason.clone()));
4786 }
4787 if let Some(frames) = frames {
4788 let _ = self.cleanup_async_frames(&frames);
4789 }
4790 }
4791
4792 fn cancel_background_tasks(&self, reason: Value) {
4793 let tasks = self.background_tasks.borrow().clone();
4794 for task in tasks {
4795 self.cancel_task(&task, reason.clone());
4796 }
4797 }
4798
4799 fn call_value(
4800 &self,
4801 callee: Value,
4802 args: Vec<Value>,
4803 named_args: Vec<(String, Value)>,
4804 ) -> Result<Value> {
4805 match callee {
4806 value if value.is_weak_value() => {
4807 self.call_value(value.resolve_weak_value(), args, named_args)
4808 }
4809 Value::Shared(value) => self.call_value(value.borrow().clone(), args, named_args),
4810 Value::Function(function) => self.call_function(&function, args, named_args),
4811 Value::NativeFunction(name) => self.call_native_function(&name, args, named_args),
4812 Value::Method(method) => self.call_bound_method(&method, args, named_args),
4813 Value::Iterator(state) => {
4814 if !args.is_empty() || !named_args.is_empty() {
4815 return Err(ZuzuRustError::runtime(
4816 "iterator values do not take arguments",
4817 ));
4818 }
4819 self.iterator_next(&state)
4820 }
4821 Value::Ref(reference) => self.call_ref(reference, args, named_args),
4822 Value::AliasRef(reference) => {
4823 let callee = self.deref_value(&Value::AliasRef(Rc::clone(&reference)))?;
4824 self.call_value(callee, args, named_args)
4825 }
4826 Value::Class(name) => self.construct_builtin_class(&name, args, named_args),
4827 Value::UserClass(class) => self.construct_user_class(class, args, named_args),
4828 _ => Err(ZuzuRustError::runtime(
4829 "attempted to call a non-function value",
4830 )),
4831 }
4832 }
4833
4834 fn call_native_function(
4835 &self,
4836 name: &str,
4837 args: Vec<Value>,
4838 named_args: Vec<(String, Value)>,
4839 ) -> Result<Value> {
4840 if matches!(name, "dump" | "safe_to_dump" | "ref_id") {
4841 return stdlib::call_native_function(self, name, args, named_args);
4842 }
4843 let args = args
4844 .into_iter()
4845 .map(|value| self.normalize_value(value))
4846 .collect::<Result<Vec<_>>>()?;
4847 let named_args = named_args
4848 .into_iter()
4849 .map(|(key, value)| {
4850 let value = self.normalize_value(value)?;
4851 Ok((key, value))
4852 })
4853 .collect::<Result<Vec<_>>>()?;
4854 stdlib::call_native_function(self, name, args, named_args)
4855 }
4856
4857 fn call_bound_method(
4858 &self,
4859 method: &Rc<MethodValue>,
4860 args: Vec<Value>,
4861 named_args: Vec<(String, Value)>,
4862 ) -> Result<Value> {
4863 let Some(receiver) = method.bound_receiver.clone() else {
4864 return Err(ZuzuRustError::runtime(
4865 "attempted to call an unbound method value",
4866 ));
4867 };
4868 let name = method.bound_name.as_deref().unwrap_or(&method.name);
4869 match receiver {
4870 Value::Object(object) => self.call_object_method(&object, name, &args, named_args),
4871 Value::UserClass(class) => {
4872 self.call_class_method(Rc::clone(&class), class, name, &args, named_args)
4873 }
4874 _ => Err(ZuzuRustError::runtime(
4875 "bound method receiver must be an Object or Class",
4876 )),
4877 }
4878 }
4879
4880 fn invoke_method_expression(
4881 &self,
4882 object: &Expression,
4883 name: &str,
4884 arguments: &[CallArgument],
4885 env: Rc<Environment>,
4886 ) -> Result<Value> {
4887 let receiver_value = self.eval_expression(object, Rc::clone(&env))?;
4888 let (args, named_args) = self.eval_method_call_arguments(arguments, Rc::clone(&env))?;
4889 if let Expression::Identifier { name: binding, .. } = object {
4890 let mut receiver = env.get(binding)?;
4891 let should_write_back = !matches!(receiver, Value::Ref(_) | Value::AliasRef(_))
4892 && is_mutating_collection_method(name)
4893 && matches!(
4894 receiver,
4895 Value::Array(_)
4896 | Value::Set(_)
4897 | Value::Bag(_)
4898 | Value::Dict(_)
4899 | Value::PairList(_)
4900 );
4901 let result = self.call_method_named(&mut receiver, name, &args, named_args.clone())?;
4902 if binding == "self" {
4903 if let Value::Object(object) = &receiver {
4904 self.refresh_method_field_bindings(&env, object);
4905 }
4906 }
4907 if should_write_back {
4908 env.assign(binding, receiver)?;
4909 }
4910 return Ok(result);
4911 }
4912
4913 let mut receiver = receiver_value;
4914 self.call_method_named(&mut receiver, name, &args, named_args)
4915 }
4916
4917 fn call_method(&self, receiver: &mut Value, name: &str, args: &[Value]) -> Result<Value> {
4918 self.call_method_named(receiver, name, args, Vec::new())
4919 }
4920
4921 fn refresh_method_field_bindings(
4922 &self,
4923 env: &Rc<Environment>,
4924 object: &Rc<RefCell<ObjectValue>>,
4925 ) {
4926 let fields = object.borrow().fields.clone();
4927 for (name, value) in fields {
4928 if !self.is_ref_backed_composite(&value) {
4929 continue;
4930 }
4931 if matches!(
4932 env.get_optional(&name),
4933 Some(Value::Ref(_)) | Some(Value::AliasRef(_))
4934 ) {
4935 continue;
4936 }
4937 env.refresh_existing_binding(&name, value.into_shared_if_composite());
4938 }
4939 }
4940
4941 fn deref_alias_method_args(
4942 &self,
4943 args: &[Value],
4944 named_args: &[(String, Value)],
4945 ) -> Result<(Vec<Value>, Vec<(String, Value)>)> {
4946 let args = args
4947 .iter()
4948 .cloned()
4949 .map(|value| self.normalize_value(value))
4950 .collect::<Result<Vec<_>>>()?;
4951 let named_args = named_args
4952 .iter()
4953 .cloned()
4954 .map(|(key, value)| {
4955 let value = self.normalize_value(value)?;
4956 Ok((key, value))
4957 })
4958 .collect::<Result<Vec<_>>>()?;
4959 Ok((args, named_args))
4960 }
4961
4962 fn preserve_shared_method_args(
4963 &self,
4964 args: &[Value],
4965 named_args: &[(String, Value)],
4966 ) -> Result<(Vec<Value>, Vec<(String, Value)>)> {
4967 let args = args
4968 .iter()
4969 .cloned()
4970 .map(|value| match value {
4971 Value::AliasRef(_) => self.deref_value(&value),
4972 other => Ok(other),
4973 })
4974 .collect::<Result<Vec<_>>>()?;
4975 let named_args = named_args
4976 .iter()
4977 .cloned()
4978 .map(|(key, value)| match value {
4979 Value::AliasRef(_) => Ok((key, self.deref_value(&value)?)),
4980 other => Ok((key, other)),
4981 })
4982 .collect::<Result<Vec<_>>>()?;
4983 Ok((args, named_args))
4984 }
4985
4986 fn call_method_named(
4987 &self,
4988 receiver: &mut Value,
4989 name: &str,
4990 args: &[Value],
4991 named_args: Vec<(String, Value)>,
4992 ) -> Result<Value> {
4993 if receiver.is_weak_value() {
4994 *receiver = receiver.resolve_weak_value();
4995 }
4996 if let Value::Ref(reference) | Value::AliasRef(reference) = receiver {
4997 let mut current = self.deref_value(&Value::AliasRef(Rc::clone(reference)))?;
4998 let result = self.call_method_named(&mut current, name, args, named_args.clone())?;
4999 if is_mutating_collection_method(name) && self.is_ref_backed_composite(¤t) {
5000 let _ = self.assign_reference(Rc::clone(reference), current)?;
5001 }
5002 return Ok(result);
5003 }
5004 if let Value::Shared(shared) = receiver {
5005 let mut current = shared.borrow().clone();
5006 let result = self.call_method_named(&mut current, name, args, named_args.clone())?;
5007 if is_mutating_collection_method(name) && self.is_ref_backed_composite(¤t) {
5008 *shared.borrow_mut() = current;
5009 }
5010 return Ok(result);
5011 }
5012 match receiver {
5013 Value::Array(values) => {
5014 let (args, named_args) = if is_mutating_collection_method(name) {
5015 self.preserve_shared_method_args(args, &named_args)?
5016 } else {
5017 self.deref_alias_method_args(args, &named_args)?
5018 };
5019 reject_named_args(name, &named_args)?;
5020 self.call_array_method(values, name, &args)
5021 }
5022 Value::SystemArray(values) => {
5023 if is_mutating_collection_method(name) {
5024 return Err(ZuzuRustError::runtime("Cannot modify __system__"));
5025 }
5026 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5027 reject_named_args(name, &named_args)?;
5028 let mut values = values.clone();
5029 self.call_array_method(&mut values, name, &args)
5030 }
5031 Value::Set(values) => {
5032 let (args, named_args) = if is_mutating_collection_method(name) {
5033 self.preserve_shared_method_args(args, &named_args)?
5034 } else {
5035 self.deref_alias_method_args(args, &named_args)?
5036 };
5037 reject_named_args(name, &named_args)?;
5038 self.call_set_method(values, name, &args)
5039 }
5040 Value::Bag(values) => {
5041 let (args, named_args) = if is_mutating_collection_method(name) {
5042 self.preserve_shared_method_args(args, &named_args)?
5043 } else {
5044 self.deref_alias_method_args(args, &named_args)?
5045 };
5046 reject_named_args(name, &named_args)?;
5047 self.call_bag_method(values, name, &args)
5048 }
5049 Value::Dict(values) => {
5050 let (args, named_args) = if is_mutating_collection_method(name) {
5051 self.preserve_shared_method_args(args, &named_args)?
5052 } else {
5053 self.deref_alias_method_args(args, &named_args)?
5054 };
5055 reject_named_args(name, &named_args)?;
5056 self.call_dict_method(values, name, &args)
5057 }
5058 Value::SystemDict(values) => {
5059 if is_mutating_collection_method(name) {
5060 return Err(ZuzuRustError::runtime("Cannot modify __system__"));
5061 }
5062 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5063 reject_named_args(name, &named_args)?;
5064 let mut values = values.clone();
5065 self.call_dict_method(&mut values, name, &args)
5066 }
5067 Value::PairList(values) => {
5068 let (args, named_args) = if is_mutating_collection_method(name) {
5069 self.preserve_shared_method_args(args, &named_args)?
5070 } else {
5071 self.deref_alias_method_args(args, &named_args)?
5072 };
5073 reject_named_args(name, &named_args)?;
5074 self.call_pairlist_method(values, name, &args)
5075 }
5076 Value::Pair(key, value) => {
5077 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5078 reject_named_args(name, &named_args)?;
5079 self.call_pair_method(key, value, name, &args)
5080 }
5081 Value::Iterator(state) => {
5082 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5083 reject_named_args(name, &named_args)?;
5084 self.call_iterator_method(state, name, &args)
5085 }
5086 Value::Class(class_name) => {
5087 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5088 if let Some(result) = stdlib::call_builtin_class_method_named(
5089 self,
5090 class_name,
5091 name,
5092 &args,
5093 &named_args,
5094 ) {
5095 return result;
5096 }
5097 reject_named_args(name, &named_args)?;
5098 if let Some(result) =
5099 stdlib::call_builtin_class_method(self, class_name, name, &args)
5100 {
5101 result
5102 } else {
5103 Err(ZuzuRustError::thrown(format!(
5104 "unsupported method '{}' for {}",
5105 name,
5106 receiver.type_name()
5107 )))
5108 }
5109 }
5110 Value::UserClass(class) => {
5111 self.call_class_method(Rc::clone(class), Rc::clone(class), name, args, named_args)
5112 }
5113 Value::Object(object) => self.call_object_method(object, name, args, named_args),
5114 Value::Task(task) => {
5115 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5116 reject_named_args(name, &named_args)?;
5117 self.call_task_method(task, name, &args)
5118 }
5119 Value::Channel(channel) => {
5120 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5121 reject_named_args(name, &named_args)?;
5122 self.call_channel_method(channel, name, &args)
5123 }
5124 Value::CancellationSource(source) => {
5125 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5126 reject_named_args(name, &named_args)?;
5127 self.call_cancellation_source_method(source, name, &args)
5128 }
5129 Value::CancellationToken(token) => {
5130 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5131 reject_named_args(name, &named_args)?;
5132 self.call_cancellation_token_method(token, name, &args)
5133 }
5134 Value::Null
5135 | Value::Boolean(_)
5136 | Value::Number(_)
5137 | Value::String(_)
5138 | Value::BinaryString(_)
5139 | Value::Regex(_, _) => {
5140 let (args, named_args) = self.deref_alias_method_args(args, &named_args)?;
5141 reject_named_args(name, &named_args)?;
5142 self.call_scalar_method(receiver, name, &args)
5143 }
5144 other => Err(ZuzuRustError::thrown(format!(
5145 "unsupported method '{}' for {}",
5146 name,
5147 other.type_name()
5148 ))),
5149 }
5150 }
5151
5152 fn call_scalar_method(&self, receiver: &Value, name: &str, args: &[Value]) -> Result<Value> {
5153 require_arity(name, args, 0)?;
5154 match name {
5155 "primitive_value" | "value" => Ok(receiver.clone()),
5156 "length" | "count" => match receiver {
5157 Value::String(text) => Ok(Value::Number(text.chars().count() as f64)),
5158 Value::BinaryString(bytes) => Ok(Value::Number(bytes.len() as f64)),
5159 Value::Null => Ok(Value::Number(0.0)),
5160 _ => Err(ZuzuRustError::thrown(format!(
5161 "unsupported method '{}' for {}",
5162 name,
5163 receiver.type_name()
5164 ))),
5165 },
5166 "string_value" => {
5167 if matches!(receiver, Value::Null) {
5168 Ok(Value::Null)
5169 } else {
5170 Ok(Value::String(self.render_value(receiver)?))
5171 }
5172 }
5173 "number_value" => {
5174 if matches!(receiver, Value::Null) {
5175 Ok(Value::Null)
5176 } else {
5177 match self.value_to_number(receiver) {
5178 Ok(number) => Ok(Value::Number(number)),
5179 Err(_) => Ok(Value::Null),
5180 }
5181 }
5182 }
5183 "type" => Ok(Value::String(self.typeof_name(receiver))),
5184 _ => Err(ZuzuRustError::thrown(format!(
5185 "unsupported method '{}' for {}",
5186 name,
5187 receiver.type_name()
5188 ))),
5189 }
5190 }
5191
5192 fn call_iterator_method(
5193 &self,
5194 state: &Rc<RefCell<IteratorState>>,
5195 name: &str,
5196 args: &[Value],
5197 ) -> Result<Value> {
5198 match name {
5199 "next" => {
5200 require_arity(name, args, 0)?;
5201 match self.iterator_next(state) {
5202 Ok(value) => Ok(value),
5203 Err(err) if err.is_iterator_exhausted() => Ok(Value::Null),
5204 Err(err) => Err(err),
5205 }
5206 }
5207 _ => Err(ZuzuRustError::thrown(format!(
5208 "unsupported method '{}' for Iterator",
5209 name
5210 ))),
5211 }
5212 }
5213
5214 fn call_task_method(
5215 &self,
5216 task: &Rc<RefCell<TaskState>>,
5217 name: &str,
5218 args: &[Value],
5219 ) -> Result<Value> {
5220 match name {
5221 "status" => {
5222 require_arity(name, args, 0)?;
5223 let _ = self.poll_task(task)?;
5224 Ok(Value::String(task.borrow().status.clone()))
5225 }
5226 "done" | "is_done" => {
5227 require_arity(name, args, 0)?;
5228 let _ = self.poll_task(task)?;
5229 Ok(Value::Boolean(task.borrow().outcome.is_some()))
5230 }
5231 "poll" => {
5232 require_arity(name, args, 0)?;
5233 Ok(Value::Boolean(self.poll_task(task)?))
5234 }
5235 "cancel" => {
5236 if args.len() > 1 {
5237 return Err(ZuzuRustError::runtime(
5238 "task.cancel() expects an optional reason",
5239 ));
5240 }
5241 self.cancel_task(
5242 task,
5243 args.first()
5244 .cloned()
5245 .unwrap_or_else(|| Value::String("Task cancelled".to_owned())),
5246 );
5247 Ok(Value::Task(Rc::clone(task)))
5248 }
5249 _ => Err(ZuzuRustError::thrown(format!(
5250 "unsupported method '{}' for Task",
5251 name
5252 ))),
5253 }
5254 }
5255
5256 fn call_channel_method(
5257 &self,
5258 channel: &Rc<RefCell<ChannelState>>,
5259 name: &str,
5260 args: &[Value],
5261 ) -> Result<Value> {
5262 match name {
5263 "send" => {
5264 require_arity(name, args, 1)?;
5265 let mut channel_ref = channel.borrow_mut();
5266 if channel_ref.closed {
5267 return Ok(self.task_rejected("ChannelClosedException: send on closed channel"));
5268 }
5269 channel_ref.messages.push(args[0].clone());
5270 Ok(self.task_resolved(args[0].clone()))
5271 }
5272 "recv" => {
5273 require_arity(name, args, 0)?;
5274 Ok(self.task_channel_recv(Rc::clone(channel)))
5275 }
5276 "close" => {
5277 require_arity(name, args, 0)?;
5278 channel.borrow_mut().closed = true;
5279 Ok(Value::Null)
5280 }
5281 _ => Err(ZuzuRustError::thrown(format!(
5282 "unsupported method '{}' for Channel",
5283 name
5284 ))),
5285 }
5286 }
5287
5288 fn call_cancellation_source_method(
5289 &self,
5290 source: &Rc<RefCell<CancellationState>>,
5291 name: &str,
5292 args: &[Value],
5293 ) -> Result<Value> {
5294 match name {
5295 "token" => {
5296 require_arity(name, args, 0)?;
5297 Ok(Value::CancellationToken(Rc::clone(source)))
5298 }
5299 "cancel" => {
5300 if args.len() > 1 {
5301 return Err(ZuzuRustError::runtime(
5302 "cancel() expects an optional reason",
5303 ));
5304 }
5305 let reason = args
5306 .first()
5307 .cloned()
5308 .unwrap_or_else(|| Value::String("Task cancelled".to_owned()));
5309 let watched = {
5310 let mut state = source.borrow_mut();
5311 state.cancelled = true;
5312 state.reason = reason.clone();
5313 state.watched.clone()
5314 };
5315 for task in watched {
5316 self.cancel_task(&task, reason.clone());
5317 }
5318 Ok(Value::Null)
5319 }
5320 "cancelled" => {
5321 require_arity(name, args, 0)?;
5322 Ok(Value::Boolean(source.borrow().cancelled))
5323 }
5324 "reason" => {
5325 require_arity(name, args, 0)?;
5326 Ok(source.borrow().reason.clone())
5327 }
5328 _ => Err(ZuzuRustError::thrown(format!(
5329 "unsupported method '{}' for CancellationSource",
5330 name
5331 ))),
5332 }
5333 }
5334
5335 fn call_cancellation_token_method(
5336 &self,
5337 token: &Rc<RefCell<CancellationState>>,
5338 name: &str,
5339 args: &[Value],
5340 ) -> Result<Value> {
5341 match name {
5342 "cancelled" => {
5343 require_arity(name, args, 0)?;
5344 Ok(Value::Boolean(token.borrow().cancelled))
5345 }
5346 "reason" => {
5347 require_arity(name, args, 0)?;
5348 Ok(token.borrow().reason.clone())
5349 }
5350 "throw_if_cancelled" => {
5351 require_arity(name, args, 0)?;
5352 let state = token.borrow();
5353 if state.cancelled {
5354 Err(ZuzuRustError::thrown(format!(
5355 "CancelledException: {}",
5356 state.reason.render()
5357 )))
5358 } else {
5359 Ok(Value::Null)
5360 }
5361 }
5362 "watch" => {
5363 require_arity(name, args, 1)?;
5364 if let Value::Task(task) = &args[0] {
5365 let mut state = token.borrow_mut();
5366 if state.cancelled {
5367 self.cancel_task(task, state.reason.clone());
5368 } else {
5369 state.watched.push(Rc::clone(task));
5370 }
5371 Ok(args[0].clone())
5372 } else {
5373 Err(ZuzuRustError::runtime("watch() expects a Task"))
5374 }
5375 }
5376 _ => Err(ZuzuRustError::thrown(format!(
5377 "unsupported method '{}' for CancellationToken",
5378 name
5379 ))),
5380 }
5381 }
5382
5383 fn call_class_method(
5384 &self,
5385 dispatch_class: Rc<UserClassValue>,
5386 receiver_class: Rc<UserClassValue>,
5387 name: &str,
5388 args: &[Value],
5389 named_args: Vec<(String, Value)>,
5390 ) -> Result<Value> {
5391 let method = self
5392 .find_static_method(&dispatch_class, name)
5393 .ok_or_else(|| {
5394 ZuzuRustError::thrown(format!(
5395 "unsupported static method '{}' for {}",
5396 name, dispatch_class.name
5397 ))
5398 })?;
5399 self.invoke_class_method_with_method(receiver_class, name, &method, args, named_args)
5400 }
5401
5402 fn invoke_class_method_with_method(
5403 &self,
5404 receiver_class: Rc<UserClassValue>,
5405 name: &str,
5406 method: &Rc<MethodValue>,
5407 args: &[Value],
5408 named_args: Vec<(String, Value)>,
5409 ) -> Result<Value> {
5410 let field_env = Rc::new(Environment::new(Some(Rc::clone(&method.env))));
5411 field_env.define(
5412 "self".to_owned(),
5413 Value::UserClass(Rc::clone(&receiver_class)),
5414 false,
5415 );
5416 field_env.define(
5417 "this".to_owned(),
5418 Value::UserClass(Rc::clone(&receiver_class)),
5419 false,
5420 );
5421 field_env.define(
5422 "__current_class__".to_owned(),
5423 Value::UserClass(Rc::clone(&receiver_class)),
5424 false,
5425 );
5426 field_env.define(
5427 "__method_name__".to_owned(),
5428 Value::String(name.to_owned()),
5429 false,
5430 );
5431 field_env.define(
5432 "__is_static_method__".to_owned(),
5433 Value::Boolean(true),
5434 false,
5435 );
5436
5437 let function = FunctionValue {
5438 name: Some(method.name.clone()),
5439 params: method.params.clone(),
5440 return_type: method.return_type.clone(),
5441 body: Rc::new(RefCell::new(self.function_body_for_method(method))),
5442 env: field_env,
5443 is_async: method.is_async,
5444 current_method: Some(Rc::clone(&method)),
5445 };
5446 self.call_function(&function, args.to_vec(), named_args)
5447 }
5448
5449 fn eval_super_call(&self, args: Vec<Value>, env: Rc<Environment>) -> Result<Value> {
5450 let _current_class = match env.get("__current_class__")? {
5451 Value::UserClass(class) => class,
5452 _ => {
5453 return Err(ZuzuRustError::runtime(
5454 "super() is only valid inside methods",
5455 ))
5456 }
5457 };
5458 let method_name = match env.get("__method_name__")? {
5459 Value::String(name) => name,
5460 _ => {
5461 return Err(ZuzuRustError::runtime(
5462 "super() is only valid inside methods",
5463 ))
5464 }
5465 };
5466 let is_static = matches!(env.get("__is_static_method__")?, Value::Boolean(true));
5467
5468 if is_static {
5469 let receiver_class = match env.get("self")? {
5470 Value::UserClass(class) => class,
5471 _ => {
5472 return Err(ZuzuRustError::runtime(
5473 "static super() requires class receiver",
5474 ))
5475 }
5476 };
5477 let method = self
5478 .find_next_method(&receiver_class, &method_name, true)
5479 .ok_or_else(|| {
5480 ZuzuRustError::runtime("super() has no static parent method to call")
5481 })?;
5482 return self.invoke_class_method_with_method(
5483 Rc::clone(&receiver_class),
5484 &method_name,
5485 &method,
5486 &args,
5487 Vec::new(),
5488 );
5489 }
5490
5491 let self_object = match env.get("self")? {
5492 Value::Object(object) => object,
5493 _ => return Err(ZuzuRustError::runtime("super() requires object receiver")),
5494 };
5495 let method = self
5496 .find_next_method(&self_object.borrow().class, &method_name, false)
5497 .ok_or_else(|| {
5498 ZuzuRustError::runtime(format!(
5499 "super() has no parent method '{}' to call",
5500 method_name
5501 ))
5502 })?;
5503 let object_class = self_object.borrow().class.clone();
5504 self.invoke_object_method_with_context(
5505 &self_object,
5506 object_class,
5507 &method_name,
5508 &method,
5509 &args,
5510 Vec::new(),
5511 )
5512 }
5513
5514 fn invoke_object_method_with_context(
5515 &self,
5516 object: &Rc<RefCell<ObjectValue>>,
5517 current_class: Rc<UserClassValue>,
5518 invoked_name: &str,
5519 method: &Rc<MethodValue>,
5520 args: &[Value],
5521 named_args: Vec<(String, Value)>,
5522 ) -> Result<Value> {
5523 let field_env = Rc::new(Environment::new(Some(Rc::clone(&method.env))));
5524 field_env.define("self".to_owned(), Value::Object(Rc::clone(object)), false);
5525 field_env.define("this".to_owned(), Value::Object(Rc::clone(object)), false);
5526 field_env.define(
5527 "__current_class__".to_owned(),
5528 Value::UserClass(Rc::clone(¤t_class)),
5529 false,
5530 );
5531 field_env.define(
5532 "__method_name__".to_owned(),
5533 Value::String(invoked_name.to_owned()),
5534 false,
5535 );
5536 field_env.define(
5537 "__is_static_method__".to_owned(),
5538 Value::Boolean(false),
5539 false,
5540 );
5541 let fields = self.collect_field_specs(¤t_class);
5542 let mut original_values = HashMap::new();
5543 for field in &fields {
5544 let value = {
5545 let mut object_mut = object.borrow_mut();
5546 let value = object_mut
5547 .fields
5548 .get(&field.name)
5549 .cloned()
5550 .unwrap_or(Value::Null);
5551 if self.is_ref_backed_composite(&value) && !matches!(value, Value::Shared(_)) {
5552 let shared = value.into_shared_if_composite();
5553 object_mut.fields.insert(field.name.clone(), shared.clone());
5554 shared
5555 } else {
5556 value
5557 }
5558 };
5559 original_values.insert(field.name.clone(), value.clone());
5560 if field.mutable {
5561 field_env.define(
5562 field.name.clone(),
5563 Value::AliasRef(Rc::new(LvalueRef::ObjectField {
5564 object: Rc::downgrade(object),
5565 name: field.name.clone(),
5566 })),
5567 false,
5568 );
5569 } else {
5570 field_env.define(field.name.clone(), value, false);
5571 }
5572 }
5573
5574 if let Some(result) = self.maybe_return_trivial_field_getter(object, method) {
5575 return result;
5576 }
5577
5578 let function = FunctionValue {
5579 name: Some(method.name.clone()),
5580 params: method.params.clone(),
5581 return_type: method.return_type.clone(),
5582 body: Rc::new(RefCell::new(self.function_body_for_method(method))),
5583 env: Rc::clone(&field_env),
5584 is_async: method.is_async,
5585 current_method: Some(Rc::clone(method)),
5586 };
5587 let result = self.call_function(&function, args.to_vec(), named_args)?;
5588
5589 let mut object_mut = object.borrow_mut();
5590 for field in &fields {
5591 if field.mutable {
5592 continue;
5593 }
5594 if let Ok(value) = field_env.get(&field.name) {
5595 let current_object_value = object_mut
5596 .fields
5597 .get(&field.name)
5598 .cloned()
5599 .unwrap_or(Value::Null);
5600 let original_value = original_values
5601 .get(&field.name)
5602 .cloned()
5603 .unwrap_or(Value::Null);
5604 if !current_object_value.coerced_eq(&original_value)
5605 && value.coerced_eq(&original_value)
5606 {
5607 continue;
5608 }
5609 object_mut.fields.insert(field.name.clone(), value);
5610 }
5611 }
5612 Ok(result)
5613 }
5614
5615 fn call_function(
5616 &self,
5617 function: &FunctionValue,
5618 args: Vec<Value>,
5619 named_args: Vec<(String, Value)>,
5620 ) -> Result<Value> {
5621 let forwarded = {
5622 let body = function.body.borrow();
5623 match &*body {
5624 FunctionBody::Forward(target) => Some(Rc::clone(target)),
5625 _ => None,
5626 }
5627 };
5628 if let Some(target) = forwarded {
5629 return self.call_function(&target, args, named_args);
5630 }
5631 let function_id = function as *const FunctionValue as usize;
5632 if function.is_async && !self.running_async_functions.borrow().contains(&function_id) {
5633 return Ok(self.task_from_function(Rc::new(function.clone()), args, named_args));
5634 }
5635 self.call_function_body(function, args, named_args)
5636 }
5637
5638 fn run_async_function_body(
5639 &self,
5640 function: &FunctionValue,
5641 args: Vec<Value>,
5642 named_args: Vec<(String, Value)>,
5643 ) -> Result<Value> {
5644 let function_id = function as *const FunctionValue as usize;
5645 self.running_async_functions.borrow_mut().push(function_id);
5646 let result = self.call_function_body(function, args, named_args);
5647 self.running_async_functions.borrow_mut().pop();
5648 result
5649 }
5650
5651 fn start_async_function_task(
5652 &self,
5653 function: &FunctionValue,
5654 args: Vec<Value>,
5655 named_args: Vec<(String, Value)>,
5656 ) -> Result<AsyncPoll> {
5657 let body = match &*function.body.borrow() {
5658 FunctionBody::Block(body) => body.clone(),
5659 FunctionBody::Forward(target) => {
5660 return self
5661 .run_async_function_body(target, args, named_args)
5662 .map(AsyncPoll::Complete);
5663 }
5664 FunctionBody::Expression(_) => {
5665 return self
5666 .run_async_function_body(function, args, named_args)
5667 .map(AsyncPoll::Complete);
5668 }
5669 FunctionBody::Bodyless => {
5670 return Err(ZuzuRustError::runtime(format!(
5671 "Function '{}' has no body",
5672 function.name.as_deref().unwrap_or("<anon>")
5673 )));
5674 }
5675 };
5676
5677 let call_env = Rc::new(Environment::new(Some(Rc::clone(&function.env))));
5678 let argc = args.len();
5679 self.bind_function_params(function, &call_env, args, named_args)?;
5680 call_env.define("__argc__".to_owned(), Value::Number(argc as f64), false);
5681
5682 self.poll_async_frames(vec![AsyncFrame::Function {
5683 statements: body.statements,
5684 index: 0,
5685 env: call_env,
5686 return_type: function.return_type.clone(),
5687 name: function.name.clone(),
5688 }])
5689 }
5690
5691 fn poll_async_frames(&self, mut frames: Vec<AsyncFrame>) -> Result<AsyncPoll> {
5692 loop {
5693 let Some(frame) = frames.last_mut() else {
5694 return Ok(AsyncPoll::Complete(Value::Null));
5695 };
5696
5697 if frame.is_complete() {
5698 let frame = frames.pop().expect("checked frame presence");
5699 let do_value = match &frame {
5700 AsyncFrame::Do { last, .. } => Some(last.clone()),
5701 _ => None,
5702 };
5703 self.cleanup_async_frame(&frame)?;
5704 if matches!(frame, AsyncFrame::Function { .. }) {
5705 return Ok(AsyncPoll::Complete(Value::Null));
5706 }
5707 if let Some(value) = do_value {
5708 if let Some(parent) = frames.last_mut() {
5709 parent.set_last(value);
5710 continue;
5711 }
5712 return Ok(AsyncPoll::Complete(value));
5713 }
5714 continue;
5715 }
5716
5717 let is_function_frame = matches!(frame, AsyncFrame::Function { .. });
5718 let is_do_frame = matches!(frame, AsyncFrame::Do { .. });
5719 let is_last = frame.index() + 1 == frame.statement_count();
5720 let env = frame.env();
5721 let statement = frame.current_statement().clone();
5722
5723 match statement {
5724 Statement::ExpressionStatement(node) => {
5725 if let Expression::AwaitExpression { body, .. } = node.expression {
5726 frame.advance();
5727 let awaited = self.eval_do_expression(&body, env)?;
5728 let Value::Task(awaited) = awaited else {
5729 return Err(ZuzuRustError::runtime(format!(
5730 "await block must return a Task, got {}",
5731 awaited.type_name()
5732 )));
5733 };
5734 let disposition = if is_function_frame && is_last {
5735 AwaitDisposition::Return
5736 } else if is_do_frame {
5737 AwaitDisposition::StoreLast
5738 } else {
5739 AwaitDisposition::Discard
5740 };
5741 return Ok(AsyncPoll::Await {
5742 awaited,
5743 frames,
5744 disposition,
5745 });
5746 }
5747 if is_function_frame && is_last {
5748 let value = self.eval_expression(&node.expression, env)?;
5749 let value = self.finish_async_frames(&frames, value)?;
5750 return Ok(AsyncPoll::Complete(value));
5751 }
5752 let value = self.eval_expression(&node.expression, env)?;
5753 if is_do_frame {
5754 frame.set_last(value);
5755 }
5756 frame.advance();
5757 }
5758 Statement::ReturnStatement(node) => {
5759 if let Some(Expression::AwaitExpression { body, .. }) = &node.argument {
5760 frame.advance();
5761 let awaited = self.eval_do_expression(&body, env)?;
5762 let Value::Task(awaited) = awaited else {
5763 return Err(ZuzuRustError::runtime(format!(
5764 "await block must return a Task, got {}",
5765 awaited.type_name()
5766 )));
5767 };
5768 return Ok(AsyncPoll::Await {
5769 awaited,
5770 frames,
5771 disposition: AwaitDisposition::Return,
5772 });
5773 }
5774 let value = self.eval_optional_expr(node.argument.as_ref(), env)?;
5775 let value = self.finish_async_frames(&frames, value)?;
5776 return Ok(AsyncPoll::Complete(value));
5777 }
5778 Statement::Block(block) => {
5779 frame.advance();
5780 let block_env = if block.needs_lexical_scope {
5781 Rc::new(Environment::new(Some(env)))
5782 } else {
5783 env
5784 };
5785 if is_do_frame {
5786 frames.push(AsyncFrame::Do {
5787 statements: block.statements,
5788 index: 0,
5789 env: block_env,
5790 cleanup_env: block.needs_lexical_scope,
5791 last: Value::Null,
5792 });
5793 } else {
5794 frames.push(AsyncFrame::Block {
5795 statements: block.statements,
5796 index: 0,
5797 env: block_env,
5798 cleanup_env: block.needs_lexical_scope,
5799 });
5800 }
5801 }
5802 other => {
5803 if is_do_frame {
5804 if let Some(value) =
5805 self.eval_statement_value_in_do(&other, Rc::clone(&env))?
5806 {
5807 frame.set_last(value);
5808 }
5809 frame.advance();
5810 let do_return = self.get_special_prop("__do_return__");
5811 if !matches!(do_return, Value::Null) {
5812 self.set_special_prop("__do_return__", Value::Null);
5813 let value = self.finish_async_frames(&frames, do_return)?;
5814 return Ok(AsyncPoll::Complete(value));
5815 }
5816 continue;
5817 }
5818 let flow = self.eval_statement(&other, Rc::clone(&env))?;
5819 frame.advance();
5820 match flow {
5821 ControlFlow::Normal => {
5822 let do_return = self.get_special_prop("__do_return__");
5823 if !matches!(do_return, Value::Null) {
5824 self.set_special_prop("__do_return__", Value::Null);
5825 let value = self.finish_async_frames(&frames, do_return)?;
5826 return Ok(AsyncPoll::Complete(value));
5827 }
5828 }
5829 ControlFlow::Return(value) => {
5830 let value = self.finish_async_frames(&frames, value)?;
5831 return Ok(AsyncPoll::Complete(value));
5832 }
5833 ControlFlow::Throw(value) => match &value {
5834 Value::String(text) => return Err(ZuzuRustError::thrown(text.clone())),
5835 _ => {
5836 return Err(ZuzuRustError::thrown_with_token(
5837 self.render_value(&value)?,
5838 self.store_thrown_value(value)?,
5839 ))
5840 }
5841 },
5842 ControlFlow::Continue | ControlFlow::Break => {
5843 return Err(ZuzuRustError::runtime(
5844 "loop control escaped function body",
5845 ))
5846 }
5847 }
5848 }
5849 }
5850 }
5851 }
5852
5853 fn finish_async_frames(&self, frames: &[AsyncFrame], value: Value) -> Result<Value> {
5854 self.cleanup_async_frames_preserving(frames, &[&value])?;
5855 if let Some((return_type, name)) = frames.iter().find_map(|frame| match frame {
5856 AsyncFrame::Function {
5857 return_type, name, ..
5858 } => Some((return_type.as_deref(), name.as_deref())),
5859 AsyncFrame::Block { .. } | AsyncFrame::Do { .. } => None,
5860 }) {
5861 self.assert_return_type(return_type, name, &value)?;
5862 }
5863 Ok(value)
5864 }
5865
5866 fn cleanup_async_frames(&self, frames: &[AsyncFrame]) -> Result<()> {
5867 for frame in frames.iter().rev() {
5868 self.cleanup_async_frame(frame)?;
5869 }
5870 Ok(())
5871 }
5872
5873 fn cleanup_async_frames_preserving(
5874 &self,
5875 frames: &[AsyncFrame],
5876 preserved: &[&Value],
5877 ) -> Result<()> {
5878 for frame in frames.iter().rev() {
5879 self.cleanup_async_frame_preserving(frame, preserved)?;
5880 }
5881 Ok(())
5882 }
5883
5884 fn cleanup_async_frame(&self, frame: &AsyncFrame) -> Result<()> {
5885 self.cleanup_async_frame_preserving(frame, &[])
5886 }
5887
5888 fn cleanup_async_frame_preserving(
5889 &self,
5890 frame: &AsyncFrame,
5891 preserved: &[&Value],
5892 ) -> Result<()> {
5893 match frame {
5894 AsyncFrame::Function { env, .. } => self.cleanup_scope_preserving(env, preserved),
5895 AsyncFrame::Block {
5896 env, cleanup_env, ..
5897 }
5898 | AsyncFrame::Do {
5899 env, cleanup_env, ..
5900 } => {
5901 if *cleanup_env {
5902 self.cleanup_scope_preserving(env, preserved)?;
5903 }
5904 Ok(())
5905 }
5906 }
5907 }
5908
5909 fn call_function_body(
5910 &self,
5911 function: &FunctionValue,
5912 args: Vec<Value>,
5913 named_args: Vec<(String, Value)>,
5914 ) -> Result<Value> {
5915 let forwarded = {
5916 let body = function.body.borrow();
5917 match &*body {
5918 FunctionBody::Forward(target) => Some(Rc::clone(target)),
5919 _ => None,
5920 }
5921 };
5922 if let Some(target) = forwarded {
5923 return self.call_function(&target, args, named_args);
5924 }
5925 let call_env = Rc::new(Environment::new(Some(Rc::clone(&function.env))));
5926 self.push_special_props_scope();
5927 if let Some(method) = &function.current_method {
5928 self.current_method_stack
5929 .borrow_mut()
5930 .push(Rc::clone(method));
5931 }
5932 let result = (|| -> Result<Value> {
5933 let argc = args.len();
5934 self.bind_function_params(function, &call_env, args, named_args)?;
5935 call_env.define("__argc__".to_owned(), Value::Number(argc as f64), false);
5936
5937 let body = function.body.borrow().clone();
5938 let flow = match body {
5939 FunctionBody::Bodyless => {
5940 return Err(ZuzuRustError::runtime(format!(
5941 "Function '{}' has no body",
5942 function.name.as_deref().unwrap_or("<anon>")
5943 )));
5944 }
5945 FunctionBody::Forward(_) => unreachable!(),
5946 FunctionBody::Block(body) => {
5947 self.eval_function_statements(&body.statements, Rc::clone(&call_env))?
5948 }
5949 FunctionBody::Expression(expr) => {
5950 ControlFlow::Return(self.eval_expression(&expr, Rc::clone(&call_env))?)
5951 }
5952 };
5953 match &flow {
5954 ControlFlow::Return(value) | ControlFlow::Throw(value) => {
5955 self.cleanup_scope_preserving(&call_env, &[value])?;
5956 }
5957 _ => self.cleanup_scope(&call_env)?,
5958 }
5959 let value = match flow {
5960 ControlFlow::Normal => Ok(Value::Null),
5961 ControlFlow::Return(value) => Ok(value),
5962 ControlFlow::Throw(value) => match &value {
5963 Value::String(text) => Err(ZuzuRustError::thrown(text.clone())),
5964 _ => Err(ZuzuRustError::thrown_with_token(
5965 self.render_value(&value)?,
5966 self.store_thrown_value(value)?,
5967 )),
5968 },
5969 ControlFlow::Continue | ControlFlow::Break => {
5970 Err(ZuzuRustError::runtime("loop control escaped function body"))
5971 }
5972 }?;
5973 self.assert_return_type(
5974 function.return_type.as_deref(),
5975 function.name.as_deref(),
5976 &value,
5977 )?;
5978 Ok(value)
5979 })();
5980 if function.current_method.is_some() {
5981 self.current_method_stack.borrow_mut().pop();
5982 }
5983 self.pop_special_props_scope();
5984 result
5985 }
5986
5987 fn eval_dict_key(&self, key: &DictKey, env: Rc<Environment>) -> Result<String> {
5988 match key {
5989 DictKey::Identifier { name, .. } => Ok(name.clone()),
5990 DictKey::StringLiteral { value, .. } => Ok(value.clone()),
5991 DictKey::Expression { expression, .. } => {
5992 Ok(self.render_value(&self.eval_expression(expression, env)?)?)
5993 }
5994 }
5995 }
5996
5997 fn eval_index(&self, object: Value, index: Value) -> Result<Value> {
5998 let object = self.deref_value(&object)?;
5999 let index = self.value_to_number(&index)? as isize;
6000 match object {
6001 Value::Array(values) | Value::SystemArray(values) => {
6002 Ok(resolve_index(values.len(), index)
6003 .and_then(|resolved| values.get(resolved).cloned())
6004 .unwrap_or(Value::Null))
6005 }
6006 Value::Set(values) => Ok(resolve_index(values.len(), index)
6007 .and_then(|resolved| values.get(resolved).cloned())
6008 .unwrap_or(Value::Null)),
6009 Value::Bag(values) => Ok(resolve_index(values.len(), index)
6010 .and_then(|resolved| values.get(resolved).cloned())
6011 .unwrap_or(Value::Null)),
6012 Value::PairList(values) => Ok(resolve_index(values.len(), index)
6013 .and_then(|resolved| values.get(resolved))
6014 .map(|(key, value)| Value::Pair(key.clone(), Box::new(value.clone())))
6015 .unwrap_or(Value::Null)),
6016 Value::String(text) => Ok(resolve_index(text.chars().count(), index)
6017 .and_then(|resolved| text.chars().nth(resolved))
6018 .map(|ch| Value::String(ch.to_string()))
6019 .unwrap_or(Value::Null)),
6020 Value::BinaryString(bytes) => Ok(resolve_index(bytes.len(), index)
6021 .and_then(|resolved| bytes.get(resolved).copied())
6022 .map(|byte| Value::BinaryString(vec![byte]))
6023 .unwrap_or(Value::Null)),
6024 _ => Err(ZuzuRustError::runtime(
6025 "index access requires an indexable value",
6026 )),
6027 }
6028 }
6029
6030 fn eval_slice(&self, object: Value, start: Value, end: Value) -> Result<Value> {
6031 let object = self.deref_value(&object)?;
6032 match object {
6033 Value::Array(values) | Value::SystemArray(values) => {
6034 let len = values.len() as isize;
6035 let mut start_index = match start {
6036 Value::Null => 0,
6037 other => self.value_to_number(&other)? as isize,
6038 };
6039 if start_index < 0 {
6040 start_index += len;
6041 }
6042 start_index = start_index.clamp(0, len);
6043
6044 let end_index = match end {
6045 Value::Null => len,
6046 other => {
6047 let raw_end = self.value_to_number(&other)? as isize;
6048 if raw_end < 0 {
6049 (len + raw_end).clamp(0, len)
6050 } else {
6051 (start_index + raw_end).clamp(0, len)
6052 }
6053 }
6054 };
6055 let from = start_index.min(end_index) as usize;
6056 let to = end_index.max(start_index) as usize;
6057 Ok(Value::Array(values[from..to].to_vec()))
6058 }
6059 Value::String(text) => {
6060 let chars = text.chars().collect::<Vec<_>>();
6061 let len = chars.len() as isize;
6062 let mut start_index = match start {
6063 Value::Null => 0,
6064 other => self.value_to_number(&other)? as isize,
6065 };
6066 if start_index < 0 {
6067 start_index += len;
6068 }
6069 start_index = start_index.clamp(0, len);
6070
6071 let end_index = match end {
6072 Value::Null => len,
6073 other => {
6074 let raw_end = self.value_to_number(&other)? as isize;
6075 if raw_end < 0 {
6076 (len + raw_end).clamp(0, len)
6077 } else {
6078 (start_index + raw_end).clamp(0, len)
6079 }
6080 }
6081 };
6082 let from = start_index.min(end_index) as usize;
6083 let to = end_index.max(start_index) as usize;
6084 Ok(Value::String(chars[from..to].iter().collect()))
6085 }
6086 Value::BinaryString(bytes) => {
6087 let len = bytes.len() as isize;
6088 let mut start_index = match start {
6089 Value::Null => 0,
6090 other => self.value_to_number(&other)? as isize,
6091 };
6092 if start_index < 0 {
6093 start_index += len;
6094 }
6095 start_index = start_index.clamp(0, len);
6096
6097 let end_index = match end {
6098 Value::Null => len,
6099 other => {
6100 let raw_end = self.value_to_number(&other)? as isize;
6101 if raw_end < 0 {
6102 (len + raw_end).clamp(0, len)
6103 } else {
6104 (start_index + raw_end).clamp(0, len)
6105 }
6106 }
6107 };
6108 let from = start_index.min(end_index) as usize;
6109 let to = end_index.max(start_index) as usize;
6110 Ok(Value::BinaryString(bytes[from..to].to_vec()))
6111 }
6112 _ => Err(ZuzuRustError::runtime(
6113 "slice access requires an Array, String, or BinaryString value",
6114 )),
6115 }
6116 }
6117
6118 fn iterable_items(&self, iterable: Value) -> Result<Vec<Value>> {
6119 let iterable = self.deref_value(&iterable)?;
6120 match iterable {
6121 Value::Array(items)
6122 | Value::SystemArray(items)
6123 | Value::Set(items)
6124 | Value::Bag(items) => Ok(items),
6125 Value::Dict(map) | Value::SystemDict(map) => {
6126 let mut keys: Vec<_> = map.keys().cloned().collect();
6127 keys.sort();
6128 Ok(keys.into_iter().map(Value::String).collect())
6129 }
6130 Value::PairList(values) => Ok(values
6131 .into_iter()
6132 .map(|(key, _)| Value::String(key))
6133 .collect()),
6134 Value::String(text) => Ok(text
6135 .chars()
6136 .map(|ch| Value::String(ch.to_string()))
6137 .collect()),
6138 Value::BinaryString(bytes) => Ok(bytes
6139 .into_iter()
6140 .map(|byte| Value::BinaryString(vec![byte]))
6141 .collect()),
6142 Value::Null => Ok(Vec::new()),
6143 Value::Function(function) => {
6144 let mut items = Vec::new();
6145 loop {
6146 match self.call_function(&function, Vec::new(), Vec::new()) {
6147 Ok(value) => items.push(value),
6148 Err(ZuzuRustError::Thrown { value, .. })
6149 if value == "ExhaustedException"
6150 || value.starts_with("ExhaustedException:") =>
6151 {
6152 break;
6153 }
6154 Err(err) => return Err(err),
6155 }
6156 }
6157 Ok(items)
6158 }
6159 Value::Object(object) => {
6160 if self.object_has_method(&object, "to_Iterator") {
6161 return self.iterable_items(self.call_object_method(
6162 &object,
6163 "to_Iterator",
6164 &[],
6165 Vec::new(),
6166 )?);
6167 }
6168 if self.object_has_method(&object, "to_Array") {
6169 return self.iterable_items(self.call_object_method(
6170 &object,
6171 "to_Array",
6172 &[],
6173 Vec::new(),
6174 )?);
6175 }
6176 Err(ZuzuRustError::runtime(format!(
6177 "for loop iterable is not supported yet: {}",
6178 self.typeof_name(&Value::Object(Rc::clone(&object)))
6179 )))
6180 }
6181 Value::Iterator(state) => {
6182 let mut items = Vec::new();
6183 loop {
6184 match self.iterator_next(&state) {
6185 Ok(value) => items.push(value),
6186 Err(err) if err.is_iterator_exhausted() => break,
6187 Err(err) => return Err(err),
6188 }
6189 }
6190 Ok(items)
6191 }
6192 other => Err(ZuzuRustError::runtime(format!(
6193 "for loop iterable is not supported yet: {}",
6194 other.type_name()
6195 ))),
6196 }
6197 }
6198
6199 fn iterator_next(&self, state: &Rc<RefCell<IteratorState>>) -> Result<Value> {
6200 let mut state = state.borrow_mut();
6201 if state.index >= state.items.len() {
6202 return Err(ZuzuRustError::runtime("iterator exhausted"));
6203 }
6204 let value = state.items[state.index].clone();
6205 state.index += 1;
6206 Ok(value)
6207 }
6208
6209 fn eval_new_expression(
6210 &self,
6211 argument: &Expression,
6212 traits: &[String],
6213 env: Rc<Environment>,
6214 ) -> Result<Value> {
6215 match argument {
6216 Expression::Call {
6217 callee, arguments, ..
6218 } if matches!(callee.as_ref(), Expression::MemberAccess { .. }) => {
6219 let (object, member) = match callee.as_ref() {
6220 Expression::MemberAccess { object, member, .. } => {
6221 (object.as_ref(), member.as_str())
6222 }
6223 _ => unreachable!(),
6224 };
6225 let (args, named_args) = self.eval_call_arguments(arguments, Rc::clone(&env))?;
6226 let mut receiver = self.eval_new_expression(object, &[], env)?;
6227 self.call_method_named(&mut receiver, member, &args, named_args)
6228 }
6229 Expression::MemberAccess { object, member, .. } => {
6230 let mut receiver = self.eval_new_expression(object, &[], env)?;
6231 self.call_method(&mut receiver, member, &[])
6232 }
6233 Expression::Call {
6234 callee, arguments, ..
6235 } => {
6236 let mut callee = self.eval_expression(callee, Rc::clone(&env))?;
6237 if !traits.is_empty() {
6238 callee = Value::UserClass(self.per_object_trait_class(
6239 callee,
6240 traits,
6241 Rc::clone(&env),
6242 )?);
6243 }
6244 let (args, named_args) = self.eval_call_arguments(arguments, env)?;
6245 self.call_value(callee, args, named_args)
6246 }
6247 _ => Err(ZuzuRustError::runtime(
6248 "new expects a constructor call expression",
6249 )),
6250 }
6251 }
6252
6253 fn per_object_trait_class(
6254 &self,
6255 base_value: Value,
6256 trait_names: &[String],
6257 env: Rc<Environment>,
6258 ) -> Result<Rc<UserClassValue>> {
6259 let (class_name, base, base_key) = match base_value {
6260 Value::UserClass(class) => (
6261 class.name.clone(),
6262 ClassBase::User(Rc::clone(&class)),
6263 format!("u:{:p}", Rc::as_ptr(&class)),
6264 ),
6265 Value::Class(name) => (
6266 name.as_ref().clone(),
6267 ClassBase::Builtin(name.as_ref().clone()),
6268 format!("b:{}", name),
6269 ),
6270 other => {
6271 return Err(ZuzuRustError::runtime(format!(
6272 "new with traits expects a Class, got {}",
6273 self.typeof_name(&other)
6274 )))
6275 }
6276 };
6277
6278 let mut traits = Vec::new();
6279 let mut key_parts = vec![base_key];
6280 for trait_name in trait_names {
6281 match env.get(trait_name)? {
6282 Value::Trait(trait_value) => {
6283 key_parts.push(format!("t:{:p}", Rc::as_ptr(&trait_value)));
6284 traits.push(trait_value);
6285 }
6286 other => {
6287 return Err(ZuzuRustError::runtime(format!(
6288 "'{}' is not a trait (got {})",
6289 trait_name,
6290 self.typeof_name(&other)
6291 )))
6292 }
6293 }
6294 }
6295 let cache_key = key_parts.join("\u{1f}");
6296 if let Some(class) = self.per_object_trait_class_cache.borrow().get(&cache_key) {
6297 return Ok(Rc::clone(class));
6298 }
6299
6300 let class_env = Rc::new(Environment::new(Some(env)));
6301 class_env.define(
6302 "__zuzu_per_object_base".to_owned(),
6303 match &base {
6304 ClassBase::User(class) => Value::UserClass(Rc::clone(class)),
6305 ClassBase::Builtin(name) => Value::Class(Rc::new(name.clone())),
6306 },
6307 false,
6308 );
6309 let source_trait_names = traits
6310 .iter()
6311 .enumerate()
6312 .map(|(index, trait_value)| {
6313 let name = format!("__zuzu_per_object_trait_{index}");
6314 class_env.define(name.clone(), Value::Trait(Rc::clone(trait_value)), false);
6315 name
6316 })
6317 .collect::<Vec<_>>();
6318
6319 let class = Rc::new(UserClassValue {
6320 name: class_name.clone(),
6321 base: Some(base),
6322 traits,
6323 fields: Vec::new(),
6324 methods: HashMap::new(),
6325 static_methods: HashMap::new(),
6326 nested_classes: HashMap::new(),
6327 source_decl: Some(ClassDeclaration {
6328 line: 0,
6329 source_file: None,
6330 name: class_name,
6331 base: Some("__zuzu_per_object_base".to_owned()),
6332 traits: source_trait_names,
6333 body: Vec::new(),
6334 shorthand: true,
6335 }),
6336 closure_env: Some(class_env),
6337 });
6338 self.per_object_trait_class_cache
6339 .borrow_mut()
6340 .insert(cache_key, Rc::clone(&class));
6341 Ok(class)
6342 }
6343
6344 fn construct_builtin_class(
6345 &self,
6346 name: &str,
6347 args: Vec<Value>,
6348 named_args: Vec<(String, Value)>,
6349 ) -> Result<Value> {
6350 match name {
6351 "Pair" => construct_pair(args, named_args),
6352 "PairList" => construct_pairlist(args, named_args),
6353 "Array" => {
6354 reject_named_args(name, &named_args)?;
6355 Ok(Value::Array(args))
6356 }
6357 "Bag" => {
6358 reject_named_args(name, &named_args)?;
6359 Ok(Value::Bag(args))
6360 }
6361 "Set" => {
6362 reject_named_args(name, &named_args)?;
6363 let mut items = Vec::new();
6364 for value in args {
6365 push_unique(&mut items, value);
6366 }
6367 Ok(Value::Set(items))
6368 }
6369 "Dict" => {
6370 reject_named_args(name, &named_args)?;
6371 let mut map = HashMap::new();
6372 for pair in args {
6373 let (key, value) = expect_pair_like(&pair)?;
6374 map.insert(key, value);
6375 }
6376 Ok(Value::Dict(map))
6377 }
6378 "Channel" => {
6379 reject_named_args(name, &named_args)?;
6380 if !args.is_empty() {
6381 return Err(ZuzuRustError::runtime("Channel() expects no arguments"));
6382 }
6383 Ok(Value::Channel(Rc::new(RefCell::new(ChannelState {
6384 messages: Vec::new(),
6385 closed: false,
6386 }))))
6387 }
6388 "CancellationSource" => {
6389 reject_named_args(name, &named_args)?;
6390 if !args.is_empty() {
6391 return Err(ZuzuRustError::runtime(
6392 "CancellationSource() expects no arguments",
6393 ));
6394 }
6395 Ok(Value::CancellationSource(Rc::new(RefCell::new(
6396 CancellationState {
6397 cancelled: false,
6398 reason: Value::Null,
6399 watched: Vec::new(),
6400 },
6401 ))))
6402 }
6403 "Path" | "JSON" | "YAML" | "CSV" | "Time" | "TimeZone" | "Duration" | "TimeFormat"
6404 | "TimeParser" | "CookieJar" | "UserAgent" | "Mailer" | "CLib" | "Widget"
6405 | "Window" | "VBox" | "HBox" | "Frame" | "Label" | "Text" | "RichText" | "Image"
6406 | "Input" | "DatePicker" | "Checkbox" | "Radio" | "RadioGroup" | "Select" | "Menu"
6407 | "MenuItem" | "Button" | "Separator" | "Slider" | "Progress" | "Tabs" | "Tab"
6408 | "ListView" | "TreeView" | "Event" | "ListenerToken" => {
6409 stdlib::construct_builtin_object(self, name, args, named_args)
6410 .unwrap_or_else(|| unreachable!())
6411 }
6412 "Exception"
6413 | "ExhaustedException"
6414 | "TypeException"
6415 | "CancelledException"
6416 | "TimeoutException"
6417 | "ChannelClosedException"
6418 | "MarshallingException"
6419 | "UnmarshallingException" => {
6420 let mut message = name.to_owned();
6421 for (key, value) in named_args {
6422 if key == "message" {
6423 message = format!("{name}: {}", self.render_value(&value)?);
6424 }
6425 }
6426 if args.len() == 1 {
6427 message = format!("{name}: {}", self.render_value(&args[0])?);
6428 }
6429 Ok(Value::String(message))
6430 }
6431 other => Err(ZuzuRustError::runtime(format!(
6432 "cannot call class '{}' yet",
6433 other
6434 ))),
6435 }
6436 }
6437
6438 fn construct_user_class(
6439 &self,
6440 class: Rc<UserClassValue>,
6441 args: Vec<Value>,
6442 named_args: Vec<(String, Value)>,
6443 ) -> Result<Value> {
6444 self.construct_user_class_inner(class, args, named_args, true)
6445 }
6446
6447 pub(in crate::runtime) fn make_user_instance_without_build(
6448 &self,
6449 class: Rc<UserClassValue>,
6450 slots: HashMap<String, Value>,
6451 ) -> Result<Value> {
6452 self.construct_user_class_inner(class, Vec::new(), slots.into_iter().collect(), false)
6453 }
6454
6455 fn construct_user_class_inner(
6456 &self,
6457 class: Rc<UserClassValue>,
6458 args: Vec<Value>,
6459 named_args: Vec<(String, Value)>,
6460 call_build: bool,
6461 ) -> Result<Value> {
6462 let builtin_value = match self.class_builtin_base_name(&class) {
6463 Some(base) if base == "Array" => {
6464 Some(self.construct_builtin_class("Array", args.clone(), Vec::new())?)
6465 }
6466 Some(base) if base == "Bag" => {
6467 Some(self.construct_builtin_class("Bag", args.clone(), Vec::new())?)
6468 }
6469 Some(base) if base == "Set" => {
6470 Some(self.construct_builtin_class("Set", args.clone(), Vec::new())?)
6471 }
6472 Some(base) if base == "Dict" => {
6473 Some(self.construct_builtin_class("Dict", args.clone(), Vec::new())?)
6474 }
6475 Some(_) => {
6476 if !args.is_empty() {
6477 return Err(ZuzuRustError::runtime(format!(
6478 "constructor for '{}' does not accept positional arguments yet",
6479 class.name
6480 )));
6481 }
6482 None
6483 }
6484 None => {
6485 if !args.is_empty() {
6486 return Err(ZuzuRustError::runtime(format!(
6487 "constructor for '{}' does not accept positional arguments yet",
6488 class.name
6489 )));
6490 }
6491 None
6492 }
6493 };
6494
6495 let object = Rc::new(RefCell::new(ObjectValue {
6496 class: Rc::clone(&class),
6497 fields: HashMap::new(),
6498 weak_fields: HashSet::new(),
6499 builtin_value,
6500 }));
6501
6502 let fields = self.collect_field_specs(&class);
6503 for field in &fields {
6504 let value = match &field.default_value {
6505 Some(default_value) => {
6506 self.eval_expression(default_value, Rc::clone(&self.class_decl_env(&class)))?
6507 }
6508 None => Value::Null,
6509 };
6510 self.object_set_field(&object, field, value)?;
6511 }
6512
6513 for (name, value) in named_args {
6514 let field = fields
6515 .iter()
6516 .find(|field| field.name == name)
6517 .ok_or_else(|| {
6518 ZuzuRustError::runtime(format!(
6519 "constructor for '{}' does not have a '{}' field",
6520 class.name, name
6521 ))
6522 })?;
6523 self.object_set_field(&object, field, value)?;
6524 }
6525
6526 if call_build && self.object_has_method(&object, "__build__") {
6527 let _ = self.call_object_method(&object, "__build__", &[], Vec::new())?;
6528 }
6529
6530 Ok(Value::Object(object))
6531 }
6532
6533 pub(in crate::runtime) fn marshal_builtin_env(&self) -> Rc<Environment> {
6534 let env = Rc::new(Environment::new(None));
6535 self.install_builtins(&env);
6536 env
6537 }
6538
6539 pub(in crate::runtime) fn marshal_current_or_builtin_env(&self) -> Rc<Environment> {
6540 self.current_env()
6541 .unwrap_or_else(|| self.marshal_builtin_env())
6542 }
6543
6544 pub(in crate::runtime) fn marshal_child_env(&self, parent: Rc<Environment>) -> Rc<Environment> {
6545 Rc::new(Environment::new(Some(parent)))
6546 }
6547
6548 pub(in crate::runtime) fn marshal_define_env(
6549 &self,
6550 env: &Rc<Environment>,
6551 name: &str,
6552 value: Value,
6553 mutable: bool,
6554 ) {
6555 env.define(name.to_owned(), value, mutable);
6556 }
6557
6558 pub(in crate::runtime) fn marshal_refresh_env(
6559 &self,
6560 env: &Rc<Environment>,
6561 name: &str,
6562 value: Value,
6563 ) -> bool {
6564 env.refresh_existing_binding(name, value)
6565 }
6566
6567 pub(in crate::runtime) fn marshal_load_module_export(
6568 &self,
6569 module_name: &str,
6570 export_name: &str,
6571 ) -> Result<Value> {
6572 self.load_module_exports(module_name)?
6573 .get(export_name)
6574 .cloned()
6575 .ok_or_else(|| {
6576 ZuzuRustError::runtime(format!(
6577 "module '{}' does not export '{}'",
6578 module_name, export_name
6579 ))
6580 })
6581 }
6582
6583 pub(in crate::runtime) fn marshal_binding(
6584 &self,
6585 env: &Rc<Environment>,
6586 name: &str,
6587 ) -> Option<(Value, bool)> {
6588 env.find_binding(name)
6589 .map(|binding| (binding.value.clone(), !binding.mutable))
6590 }
6591
6592 #[allow(dead_code)]
6593 pub(in crate::runtime) fn eval_marshal_code_value(
6594 &self,
6595 source: &str,
6596 binding_name: &str,
6597 ) -> Result<Value> {
6598 let parent = self
6599 .current_env()
6600 .unwrap_or_else(|| self.marshal_builtin_env());
6601 let env = self.marshal_child_env(parent);
6602 self.eval_marshal_code_value_in_env(source, binding_name, env, false)
6603 }
6604
6605 pub(in crate::runtime) fn eval_marshal_code_value_in_env(
6606 &self,
6607 source: &str,
6608 binding_name: &str,
6609 env: Rc<Environment>,
6610 expression_result: bool,
6611 ) -> Result<Value> {
6612 let source = if expression_result {
6613 format!("let __zuzu_marshal_value := {source}; __zuzu_marshal_value;")
6614 } else {
6615 source.to_owned()
6616 };
6617 let options = ParseOptions::new(false, self.infer_types, self.optimizations.clone());
6618 let program = parse_program_with_compile_options_and_source_file(
6619 &source,
6620 &options,
6621 Some("<std/marshal-code>"),
6622 )?;
6623 match self.eval_statements(&program.statements, Rc::clone(&env))? {
6624 ControlFlow::Normal => {
6625 if expression_result {
6626 env.get("__zuzu_marshal_value")
6627 } else {
6628 env.get(binding_name)
6629 }
6630 }
6631 ControlFlow::Return(_) => Err(ZuzuRustError::runtime(
6632 "return is not valid at top-level scope",
6633 )),
6634 ControlFlow::Throw(value) => Err(ZuzuRustError::thrown(self.render_value(&value)?)),
6635 ControlFlow::Break | ControlFlow::Continue => Err(ZuzuRustError::runtime(
6636 "loop control escaped marshal code record",
6637 )),
6638 }
6639 }
6640
6641 pub(in crate::runtime) fn marshal_bind_method(
6642 &self,
6643 receiver: Value,
6644 method_name: &str,
6645 ) -> Result<Value> {
6646 match receiver.clone() {
6647 Value::Object(object) => {
6648 let class = object.borrow().class.clone();
6649 let method = self.find_method(&class, method_name).ok_or_else(|| {
6650 ZuzuRustError::runtime(format!("method '{}' was not found", method_name))
6651 })?;
6652 Ok(Value::Method(Rc::new(MethodValue {
6653 name: method.name.clone(),
6654 params: method.params.clone(),
6655 return_type: method.return_type.clone(),
6656 body: method.body.clone(),
6657 env: Rc::clone(&method.env),
6658 is_static: method.is_static,
6659 is_async: method.is_async,
6660 is_bodyless: method.is_bodyless,
6661 bound_receiver: Some(receiver),
6662 bound_name: Some(method_name.to_owned()),
6663 })))
6664 }
6665 Value::UserClass(class) => {
6666 let method = self
6667 .find_static_method(&class, method_name)
6668 .ok_or_else(|| {
6669 ZuzuRustError::runtime(format!("method '{}' was not found", method_name))
6670 })?;
6671 Ok(Value::Method(Rc::new(MethodValue {
6672 name: method.name.clone(),
6673 params: method.params.clone(),
6674 return_type: method.return_type.clone(),
6675 body: method.body.clone(),
6676 env: Rc::clone(&method.env),
6677 is_static: method.is_static,
6678 is_async: method.is_async,
6679 is_bodyless: method.is_bodyless,
6680 bound_receiver: Some(receiver),
6681 bound_name: Some(method_name.to_owned()),
6682 })))
6683 }
6684 _ => Err(ZuzuRustError::runtime(
6685 "bound method receiver must be an Object or Class",
6686 )),
6687 }
6688 }
6689
6690 pub(in crate::runtime) fn marshal_set_object_field(
6691 &self,
6692 object: &Rc<RefCell<ObjectValue>>,
6693 name: &str,
6694 value: Value,
6695 is_weak_storage: bool,
6696 ) -> Result<()> {
6697 let class = object.borrow().class.clone();
6698 if let Some(field) = self.find_field_spec(&class, name) {
6699 return self.object_set_field_with_weak_write(object, &field, value, is_weak_storage);
6700 }
6701 self.object_store_slot(object, name, value, is_weak_storage)?;
6702 Ok(())
6703 }
6704
6705 fn object_store_slot(
6706 &self,
6707 object: &Rc<RefCell<ObjectValue>>,
6708 name: &str,
6709 value: Value,
6710 weak_write: bool,
6711 ) -> Result<()> {
6712 let class = object.borrow().class.clone();
6713 if let Some(field) = self.find_field_spec(&class, name) {
6714 return self.object_set_field_with_weak_write(object, &field, value, weak_write);
6715 }
6716 let mut object = object.borrow_mut();
6717 if weak_write {
6718 object.weak_fields.insert(name.to_owned());
6719 } else {
6720 object.weak_fields.remove(name);
6721 }
6722 object
6723 .fields
6724 .insert(name.to_owned(), value.stored_with_weak_policy(weak_write));
6725 Ok(())
6726 }
6727
6728 pub(in crate::runtime) fn marshal_call_object_hook(
6729 &self,
6730 object: &Rc<RefCell<ObjectValue>>,
6731 name: &str,
6732 ) -> Result<()> {
6733 if self.object_has_method(object, name) {
6734 let _ = self.call_object_method(object, name, &[], Vec::new())?;
6735 }
6736 Ok(())
6737 }
6738
6739 fn call_ref(
6740 &self,
6741 reference: Rc<LvalueRef>,
6742 args: Vec<Value>,
6743 named_args: Vec<(String, Value)>,
6744 ) -> Result<Value> {
6745 if !named_args.is_empty() {
6746 return Err(ZuzuRustError::runtime(
6747 "lvalue refs do not accept named arguments",
6748 ));
6749 }
6750 match reference.as_ref() {
6751 LvalueRef::Expression { env, target } => match args.len() {
6752 0 => self.eval_expression(target, Rc::clone(env)),
6753 1 => self.assign_lvalue(
6754 target,
6755 args.into_iter().next().unwrap(),
6756 false,
6757 Rc::clone(env),
6758 ),
6759 2 => {
6760 let mut args = args.into_iter();
6761 let value = args.next().unwrap();
6762 let weak_write = self.value_is_truthy(&args.next().unwrap())?;
6763 self.assign_lvalue(target, value, weak_write, Rc::clone(env))
6764 }
6765 _ => Err(ZuzuRustError::runtime(
6766 "lvalue refs accept zero, one, or two arguments",
6767 )),
6768 },
6769 LvalueRef::ObjectField { object, name } => match args.len() {
6770 0 => {
6771 let value = object
6772 .upgrade()
6773 .and_then(|object| object.borrow().fields.get(name).cloned())
6774 .unwrap_or(Value::Null);
6775 Ok(if value.is_weak_value() {
6776 value.resolve_weak_value()
6777 } else {
6778 value
6779 })
6780 }
6781 1 => {
6782 let Some(object) = object.upgrade() else {
6783 return Ok(Value::Null);
6784 };
6785 let value = args.into_iter().next().unwrap();
6786 self.object_store_slot(&object, name, value.clone(), false)?;
6787 Ok(value)
6788 }
6789 2 => {
6790 let Some(object) = object.upgrade() else {
6791 return Ok(Value::Null);
6792 };
6793 let mut args = args.into_iter();
6794 let value = args.next().unwrap();
6795 let weak_write = self.value_is_truthy(&args.next().unwrap())?;
6796 self.object_store_slot(&object, name, value.clone(), weak_write)?;
6797 Ok(value)
6798 }
6799 _ => Err(ZuzuRustError::runtime(
6800 "lvalue refs accept zero, one, or two arguments",
6801 )),
6802 },
6803 }
6804 }
6805
6806 fn bind_function_params(
6807 &self,
6808 function: &FunctionValue,
6809 env: &Environment,
6810 args: Vec<Value>,
6811 named_args: Vec<(String, Value)>,
6812 ) -> Result<()> {
6813 let mut arg_index = 0usize;
6814 let mut variadic_seen = false;
6815 let has_variadic_param = function.params.iter().any(|param| param.variadic);
6816 let named_pairlist_param = function
6817 .params
6818 .iter()
6819 .any(|param| has_variadic_param && param.declared_type.as_deref() == Some("PairList"));
6820 if !named_args.is_empty() && !named_pairlist_param {
6821 return Err(ZuzuRustError::thrown(
6822 "Named arguments are not accepted by this function call",
6823 ));
6824 }
6825 for (index, param) in function.params.iter().enumerate() {
6826 let fixed_remaining_after_current = function.params[index + 1..]
6827 .iter()
6828 .filter(|later| {
6829 !named_pairlist_param || later.declared_type.as_deref() != Some("PairList")
6830 })
6831 .count();
6832 let value = if has_variadic_param && param.declared_type.as_deref() == Some("PairList")
6833 {
6834 Value::PairList(named_args.clone())
6835 } else if named_pairlist_param
6836 && param.declared_type.as_deref() == Some("Array")
6837 && fixed_remaining_after_current == 0
6838 {
6839 let rest = args[arg_index..].to_vec();
6840 arg_index = args.len();
6841 Value::Array(rest)
6842 } else if param.variadic {
6843 variadic_seen = true;
6844 let rest = args[arg_index..].to_vec();
6845 arg_index = args.len();
6846 Value::Array(rest)
6847 } else if param.declared_type.as_deref() == Some("Array")
6848 && args.len().saturating_sub(arg_index) > fixed_remaining_after_current + 1
6849 {
6850 let take = args.len() - arg_index - fixed_remaining_after_current;
6851 let rest = args[arg_index..arg_index + take].to_vec();
6852 arg_index += take;
6853 Value::Array(rest)
6854 } else if let Some(value) = args.get(arg_index).cloned() {
6855 arg_index += 1;
6856 value
6857 } else if let Some(default) = ¶m.default_value {
6858 self.eval_expression(
6859 default,
6860 Rc::new(Environment::new(Some(Rc::clone(&function.env)))),
6861 )?
6862 } else if param.optional {
6863 Value::Null
6864 } else {
6865 return Err(ZuzuRustError::thrown(
6866 "Wrong number of arguments for function call",
6867 ));
6868 };
6869 if !(param.optional && matches!(value, Value::Null)) {
6870 self.assert_declared_type(param.declared_type.as_deref(), &value, ¶m.name)?;
6871 }
6872 env.define(param.name.clone(), value, false);
6873 }
6874 if arg_index < args.len() && !variadic_seen {
6875 return Err(ZuzuRustError::thrown(
6876 "Wrong number of arguments for function call",
6877 ));
6878 }
6879 Ok(())
6880 }
6881
6882 fn concat_values(&self, lhs: Value, rhs: Value) -> Result<Value> {
6883 match (lhs, rhs) {
6884 (Value::BinaryString(mut left), Value::BinaryString(right)) => {
6885 left.extend(right);
6886 Ok(Value::BinaryString(left))
6887 }
6888 (Value::String(left), Value::BinaryString(right)) => {
6889 Ok(Value::String(left + &self.binary_ascii_string(&right)?))
6890 }
6891 (Value::BinaryString(left), Value::String(right)) => {
6892 Ok(Value::String(self.binary_ascii_string(&left)? + &right))
6893 }
6894 (left, right) => Ok(Value::String(
6895 self.value_to_operator_string(&left)? + &self.value_to_operator_string(&right)?,
6896 )),
6897 }
6898 }
6899
6900 fn binary_ascii_string(&self, bytes: &[u8]) -> Result<String> {
6901 if bytes.iter().all(|byte| byte.is_ascii()) {
6902 Ok(bytes.iter().map(|byte| *byte as char).collect())
6903 } else {
6904 Err(ZuzuRustError::thrown(
6905 "Cannot implicitly concatenate non-ASCII BinaryString",
6906 ))
6907 }
6908 }
6909
6910 fn eval_bitwise(&self, operator: &str, lhs: Value, rhs: Value) -> Result<Value> {
6911 match (lhs, rhs) {
6912 (Value::BinaryString(left), Value::BinaryString(right)) => {
6913 if left.len() != right.len() {
6914 return Err(ZuzuRustError::thrown(
6915 "BinaryString bitwise operands must be equal length",
6916 ));
6917 }
6918 let op = match operator {
6919 "&" => |a, b| a & b,
6920 "|" => |a, b| a | b,
6921 "^" => |a, b| a ^ b,
6922 _ => unreachable!(),
6923 };
6924 Ok(Value::BinaryString(
6925 left.into_iter().zip(right).map(|(a, b)| op(a, b)).collect(),
6926 ))
6927 }
6928 (left, right) => {
6929 let lhs = self.value_to_number(&left)? as i64;
6930 let rhs = self.value_to_number(&right)? as i64;
6931 let value = match operator {
6932 "&" => lhs & rhs,
6933 "|" => lhs | rhs,
6934 "^" => lhs ^ rhs,
6935 _ => unreachable!(),
6936 };
6937 Ok(Value::Number(value as f64))
6938 }
6939 }
6940 }
6941
6942 fn eval_shift(&self, operator: &str, lhs: Value, rhs: Value) -> Result<Value> {
6943 fn shift_bytes(bytes: &[u8], count: u64, left: bool) -> Vec<u8> {
6946 let len = bytes.len();
6947 if len == 0 || count >= len as u64 * 8 {
6948 return vec![0; len];
6949 }
6950 let byte_shift = (count / 8) as usize;
6951 let bit_shift = (count % 8) as u32;
6952 let mut out = vec![0u8; len];
6953 for (i, slot) in out.iter_mut().enumerate() {
6954 let value = if left {
6955 let src = i + byte_shift;
6956 let hi = if src < len { bytes[src] as u16 } else { 0 };
6957 let lo = if src + 1 < len {
6958 bytes[src + 1] as u16
6959 } else {
6960 0
6961 };
6962 ((hi << 8 | lo) << bit_shift) >> 8
6963 } else {
6964 if i < byte_shift {
6965 continue;
6966 }
6967 let lo = bytes[i - byte_shift] as u16;
6968 let hi = if i > byte_shift {
6969 (bytes[i - byte_shift - 1] as u16) << 8
6970 } else {
6971 0
6972 };
6973 (hi | lo) >> bit_shift
6974 };
6975 *slot = (value & 0xFF) as u8;
6976 }
6977 out
6978 }
6979
6980 let left_shift = matches!(operator, "<<" | "«");
6981 let count = self.value_to_number(&rhs)?.trunc();
6982 if !(count >= 0.0) || !count.is_finite() {
6983 return Err(ZuzuRustError::thrown(
6984 "shift count must be a non-negative integer",
6985 ));
6986 }
6987 match lhs {
6988 Value::BinaryString(bytes) => Ok(Value::BinaryString(shift_bytes(
6989 &bytes,
6990 count.min(u64::MAX as f64) as u64,
6991 left_shift,
6992 ))),
6993 other => {
6994 let value = self.value_to_number(&other)?.trunc();
6995 let factor = 2f64.powf(count);
6996 let shifted = if left_shift {
6997 value * factor
6998 } else {
6999 (value / factor).floor()
7000 };
7001 Ok(Value::Number(shifted))
7002 }
7003 }
7004 }
7005
7006 fn assign_index_target(
7007 &self,
7008 object: &Expression,
7009 index: &Expression,
7010 value: Value,
7011 weak_write: bool,
7012 env: Rc<Environment>,
7013 ) -> Result<Value> {
7014 let index_value = self.eval_expression(index, Rc::clone(&env))?;
7015 let object_value = self.eval_expression(object, Rc::clone(&env))?;
7016 if let Value::Shared(shared) = &object_value {
7017 let mut current = shared.borrow().clone();
7018 return match &mut current {
7019 Value::Array(values) => {
7020 let idx = self.value_to_number(&index_value)? as usize;
7021 if idx >= values.len() {
7022 values.resize(idx + 1, Value::Null);
7023 }
7024 values[idx] = value.clone().stored_with_weak_policy(weak_write);
7025 *shared.borrow_mut() = current;
7026 Ok(value)
7027 }
7028 Value::String(text) => {
7029 let replacement = match value {
7030 Value::String(text) => text,
7031 _ => {
7032 return Err(ZuzuRustError::runtime(
7033 "string index assignment requires a String value",
7034 ))
7035 }
7036 };
7037 let (from, to) = self.string_index_range(text, &index_value)?;
7038 let updated = replace_char_range(text, from, to, replacement.chars());
7039 *shared.borrow_mut() = Value::String(updated);
7040 Ok(Value::String(replacement))
7041 }
7042 Value::BinaryString(bytes) => {
7043 let replacement = match value {
7044 Value::BinaryString(bytes) => bytes,
7045 _ => {
7046 return Err(ZuzuRustError::runtime(
7047 "binary string index assignment requires a BinaryString value",
7048 ))
7049 }
7050 };
7051 let (from, to) = self.binary_index_range(bytes, &index_value)?;
7052 bytes.splice(from..to, replacement.clone());
7053 *shared.borrow_mut() = current;
7054 Ok(Value::BinaryString(replacement))
7055 }
7056 Value::SystemArray(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7057 other => Err(ZuzuRustError::runtime(format!(
7058 "index assignment requires an Array, String, or BinaryString value, got {}",
7059 self.typeof_name(other)
7060 ))),
7061 };
7062 }
7063 if let Value::Ref(reference) | Value::AliasRef(reference) = object_value {
7064 return match self.deref_value(&Value::AliasRef(Rc::clone(&reference)))? {
7065 Value::Array(mut values) => {
7066 let idx = self.value_to_number(&index_value)? as usize;
7067 if idx >= values.len() {
7068 values.resize(idx + 1, Value::Null);
7069 }
7070 values[idx] = value.clone().stored_with_weak_policy(weak_write);
7071 let _ = self.assign_reference(reference, Value::Array(values))?;
7072 Ok(value)
7073 }
7074 Value::String(text) => {
7075 let replacement = match value {
7076 Value::String(text) => text,
7077 _ => {
7078 return Err(ZuzuRustError::runtime(
7079 "string index assignment requires a String value",
7080 ))
7081 }
7082 };
7083 let (from, to) = self.string_index_range(&text, &index_value)?;
7084 let updated = replace_char_range(&text, from, to, replacement.chars());
7085 let _ = self.assign_reference(reference, Value::String(updated))?;
7086 Ok(Value::String(replacement))
7087 }
7088 Value::BinaryString(mut bytes) => {
7089 let replacement = match value {
7090 Value::BinaryString(bytes) => bytes,
7091 _ => {
7092 return Err(ZuzuRustError::runtime(
7093 "binary string index assignment requires a BinaryString value",
7094 ))
7095 }
7096 };
7097 let (from, to) = self.binary_index_range(&bytes, &index_value)?;
7098 bytes.splice(from..to, replacement.clone());
7099 let _ = self.assign_reference(reference, Value::BinaryString(bytes))?;
7100 Ok(Value::BinaryString(replacement))
7101 }
7102 Value::SystemArray(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7103 other => Err(ZuzuRustError::runtime(format!(
7104 "index assignment requires an Array, String, or BinaryString value, got {}",
7105 self.typeof_name(&other)
7106 ))),
7107 };
7108 }
7109 match object_value {
7110 Value::Array(mut values) => {
7111 let idx = self.value_to_number(&index_value)? as usize;
7112 if idx >= values.len() {
7113 values.resize(idx + 1, Value::Null);
7114 }
7115 values[idx] = value.clone().stored_with_weak_policy(weak_write);
7116 match object {
7117 Expression::Identifier { name, .. } => {
7118 env.assign(name, Value::Array(values))?;
7119 Ok(value)
7120 }
7121 _ => {
7122 self.assign_lvalue(object, Value::Array(values), false, env)?;
7123 Ok(value)
7124 }
7125 }
7126 }
7127 Value::String(text) => {
7128 let replacement = match value {
7129 Value::String(text) => text,
7130 _ => {
7131 return Err(ZuzuRustError::runtime(
7132 "string index assignment requires a String value",
7133 ))
7134 }
7135 };
7136 let (from, to) = self.string_index_range(&text, &index_value)?;
7137 let updated = replace_char_range(&text, from, to, replacement.chars());
7138 match object {
7139 Expression::Identifier { name, .. } => {
7140 env.assign(name, Value::String(updated))?;
7141 Ok(Value::String(replacement))
7142 }
7143 _ => {
7144 self.assign_lvalue(object, Value::String(updated), false, env)?;
7145 Ok(Value::String(replacement))
7146 }
7147 }
7148 }
7149 Value::BinaryString(mut bytes) => {
7150 let replacement = match value {
7151 Value::BinaryString(bytes) => bytes,
7152 _ => {
7153 return Err(ZuzuRustError::runtime(
7154 "binary string index assignment requires a BinaryString value",
7155 ))
7156 }
7157 };
7158 let (from, to) = self.binary_index_range(&bytes, &index_value)?;
7159 bytes.splice(from..to, replacement.clone());
7160 match object {
7161 Expression::Identifier { name, .. } => {
7162 env.assign(name, Value::BinaryString(bytes))?;
7163 Ok(Value::BinaryString(replacement))
7164 }
7165 _ => {
7166 self.assign_lvalue(object, Value::BinaryString(bytes), false, env)?;
7167 Ok(Value::BinaryString(replacement))
7168 }
7169 }
7170 }
7171 Value::SystemArray(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7172 other => Err(ZuzuRustError::runtime(format!(
7173 "index assignment requires an Array, String, or BinaryString value, got {}",
7174 self.typeof_name(&other)
7175 ))),
7176 }
7177 }
7178
7179 fn assign_dict_target(
7180 &self,
7181 object: &Expression,
7182 key: &DictKey,
7183 value: Value,
7184 weak_write: bool,
7185 env: Rc<Environment>,
7186 ) -> Result<Value> {
7187 let key_name = self.eval_dict_key(key, Rc::clone(&env))?;
7188 let object_value = self.eval_expression(object, Rc::clone(&env))?;
7189 if let Value::Shared(shared) = &object_value {
7190 let mut current = shared.borrow().clone();
7191 return match &mut current {
7192 Value::Dict(map) => {
7193 map.insert(key_name, value.clone().stored_with_weak_policy(weak_write));
7194 *shared.borrow_mut() = current;
7195 Ok(value)
7196 }
7197 Value::SystemDict(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7198 Value::PairList(values) => {
7199 if let Some((_, entry_value)) = values
7200 .iter_mut()
7201 .find(|(entry_key, _)| entry_key == &key_name)
7202 {
7203 *entry_value = value.clone().stored_with_weak_policy(weak_write);
7204 } else {
7205 values.push((key_name, value.clone().stored_with_weak_policy(weak_write)));
7206 }
7207 *shared.borrow_mut() = current;
7208 Ok(value)
7209 }
7210 other => Err(ZuzuRustError::runtime(format!(
7211 "unsupported assignment target: {}",
7212 self.typeof_name(other)
7213 ))),
7214 };
7215 }
7216 if let Value::Ref(reference) | Value::AliasRef(reference) = object_value {
7217 return match self.deref_value(&Value::AliasRef(Rc::clone(&reference)))? {
7218 Value::Dict(mut map) => {
7219 map.insert(key_name, value.clone().stored_with_weak_policy(weak_write));
7220 let _ = self.assign_reference(reference, Value::Dict(map))?;
7221 Ok(value)
7222 }
7223 Value::SystemDict(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7224 Value::PairList(mut values) => {
7225 if let Some((_, entry_value)) = values
7226 .iter_mut()
7227 .find(|(entry_key, _)| entry_key == &key_name)
7228 {
7229 *entry_value = value.clone().stored_with_weak_policy(weak_write);
7230 } else {
7231 values.push((key_name, value.clone().stored_with_weak_policy(weak_write)));
7232 }
7233 let _ = self.assign_reference(reference, Value::PairList(values))?;
7234 Ok(value)
7235 }
7236 Value::Object(object) => {
7237 self.object_store_slot(&object, &key_name, value.clone(), weak_write)?;
7238 Ok(value)
7239 }
7240 _ => Err(ZuzuRustError::runtime("unsupported assignment target")),
7241 };
7242 }
7243 match object_value {
7244 Value::Dict(mut map) => {
7245 map.insert(key_name, value.clone().stored_with_weak_policy(weak_write));
7246 match object {
7247 Expression::Identifier { name, .. } => {
7248 env.assign(name, Value::Dict(map))?;
7249 Ok(value)
7250 }
7251 _ => {
7252 self.assign_lvalue(object, Value::Dict(map), false, env)?;
7253 Ok(value)
7254 }
7255 }
7256 }
7257 Value::SystemDict(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7258 Value::PairList(mut values) => {
7259 if let Some((_, entry_value)) = values
7260 .iter_mut()
7261 .find(|(entry_key, _)| entry_key == &key_name)
7262 {
7263 *entry_value = value.clone().stored_with_weak_policy(weak_write);
7264 } else {
7265 values.push((key_name, value.clone().stored_with_weak_policy(weak_write)));
7266 }
7267 match object {
7268 Expression::Identifier { name, .. } => {
7269 env.assign(name, Value::PairList(values))?;
7270 Ok(value)
7271 }
7272 _ => {
7273 self.assign_lvalue(object, Value::PairList(values), false, env)?;
7274 Ok(value)
7275 }
7276 }
7277 }
7278 Value::Object(object) => {
7279 let existing = object.borrow().fields.get(&key_name).cloned();
7280 if let Some(Value::Ref(reference) | Value::AliasRef(reference)) = existing {
7281 let _ = self.assign_reference_with_weak_write(
7282 reference,
7283 value.clone(),
7284 weak_write,
7285 )?;
7286 } else {
7287 self.object_store_slot(&object, &key_name, value.clone(), weak_write)?;
7288 }
7289 Ok(value)
7290 }
7291 _ => Err(ZuzuRustError::runtime("unsupported assignment target")),
7292 }
7293 }
7294
7295 fn assign_slice_target(
7296 &self,
7297 object: &Expression,
7298 start: Option<&Expression>,
7299 end: Option<&Expression>,
7300 value: Value,
7301 env: Rc<Environment>,
7302 ) -> Result<Value> {
7303 let start_value = self.eval_optional_expr(start, Rc::clone(&env))?;
7304 let count_value = self.eval_optional_expr(end, Rc::clone(&env))?;
7305 if let Expression::Identifier { name, .. } = object {
7306 match env.get(name)? {
7307 Value::Shared(shared) => {
7308 let mut current = shared.borrow().clone();
7309 match &mut current {
7310 Value::Array(values) => {
7311 let replacement = match value {
7312 Value::Array(values) => values,
7313 _ => {
7314 return Err(ZuzuRustError::runtime(
7315 "slice assignment requires an Array value",
7316 ))
7317 }
7318 };
7319 let start = match start_value {
7320 Value::Null => 0,
7321 ref other => self.value_to_number(other)? as usize,
7322 };
7323 let count = match count_value {
7324 Value::Null => values.len().saturating_sub(start),
7325 ref other => self.value_to_number(other)? as usize,
7326 };
7327 let from = start.min(values.len());
7328 let to = (from + count).min(values.len());
7329 values.splice(from..to, replacement.clone());
7330 *shared.borrow_mut() = current;
7331 Ok(Value::Array(replacement))
7332 }
7333 Value::String(text) => {
7334 let replacement = match value {
7335 Value::String(text) => text,
7336 _ => {
7337 return Err(ZuzuRustError::runtime(
7338 "string slice assignment requires a String value",
7339 ))
7340 }
7341 };
7342 let (from, to) =
7343 self.string_slice_range(text, &start_value, &count_value)?;
7344 let updated = replace_char_range(text, from, to, replacement.chars());
7345 *shared.borrow_mut() = Value::String(updated);
7346 Ok(Value::String(replacement))
7347 }
7348 Value::BinaryString(bytes) => {
7349 let replacement = match value {
7350 Value::BinaryString(bytes) => bytes,
7351 _ => return Err(ZuzuRustError::runtime(
7352 "binary string slice assignment requires a BinaryString value",
7353 )),
7354 };
7355 let (from, to) =
7356 self.binary_slice_range(bytes, &start_value, &count_value)?;
7357 bytes.splice(from..to, replacement.clone());
7358 *shared.borrow_mut() = current;
7359 Ok(Value::BinaryString(replacement))
7360 }
7361 Value::SystemArray(_) => {
7362 Err(ZuzuRustError::runtime("Cannot modify __system__"))
7363 }
7364 _ => Err(ZuzuRustError::runtime(
7365 "slice assignment requires an Array, String, or BinaryString value",
7366 )),
7367 }
7368 }
7369 Value::Array(mut values) => {
7370 let replacement = match value {
7371 Value::Array(values) => values,
7372 _ => {
7373 return Err(ZuzuRustError::runtime(
7374 "slice assignment requires an Array value",
7375 ))
7376 }
7377 };
7378 let start = match start_value {
7379 Value::Null => 0,
7380 ref other => self.value_to_number(other)? as usize,
7381 };
7382 let count = match count_value {
7383 Value::Null => values.len().saturating_sub(start),
7384 ref other => self.value_to_number(other)? as usize,
7385 };
7386 let from = start.min(values.len());
7387 let to = (from + count).min(values.len());
7388 values.splice(from..to, replacement.clone());
7389 env.assign(name, Value::Array(values))?;
7390 Ok(Value::Array(replacement))
7391 }
7392 Value::SystemArray(_) => Err(ZuzuRustError::runtime("Cannot modify __system__")),
7393 Value::String(text) => {
7394 let replacement = match value {
7395 Value::String(text) => text,
7396 _ => {
7397 return Err(ZuzuRustError::runtime(
7398 "string slice assignment requires a String value",
7399 ))
7400 }
7401 };
7402 let (from, to) = self.string_slice_range(&text, &start_value, &count_value)?;
7403 env.assign(
7404 name,
7405 Value::String(replace_char_range(&text, from, to, replacement.chars())),
7406 )?;
7407 Ok(Value::String(replacement))
7408 }
7409 Value::BinaryString(mut bytes) => {
7410 let replacement = match value {
7411 Value::BinaryString(bytes) => bytes,
7412 _ => {
7413 return Err(ZuzuRustError::runtime(
7414 "binary string slice assignment requires a BinaryString value",
7415 ))
7416 }
7417 };
7418 let (from, to) = self.binary_slice_range(&bytes, &start_value, &count_value)?;
7419 bytes.splice(from..to, replacement.clone());
7420 env.assign(name, Value::BinaryString(bytes))?;
7421 Ok(Value::BinaryString(replacement))
7422 }
7423 _ => Err(ZuzuRustError::runtime(
7424 "slice assignment requires an Array, String, or BinaryString value",
7425 )),
7426 }
7427 } else {
7428 Err(ZuzuRustError::runtime("unsupported assignment target"))
7429 }
7430 }
7431
7432 fn string_slice_range(
7433 &self,
7434 text: &str,
7435 start_value: &Value,
7436 count_value: &Value,
7437 ) -> Result<(usize, usize)> {
7438 let len = text.chars().count() as isize;
7439 let mut start = match start_value {
7440 Value::Null => 0,
7441 other => self.value_to_number(other)? as isize,
7442 };
7443 if start < 0 {
7444 start += len;
7445 }
7446 start = start.clamp(0, len);
7447 let count = match count_value {
7448 Value::Null => len - start,
7449 other => self.value_to_number(other)? as isize,
7450 }
7451 .max(0);
7452 let end = (start + count).clamp(0, len);
7453 Ok((start as usize, end as usize))
7454 }
7455
7456 fn string_index_range(&self, text: &str, index_value: &Value) -> Result<(usize, usize)> {
7457 let len = text.chars().count() as isize;
7458 let mut index = self.value_to_number(index_value)? as isize;
7459 if index < 0 {
7460 index += len;
7461 }
7462 index = index.clamp(0, len);
7463 let end = (index + 1).clamp(0, len);
7464 Ok((index as usize, end as usize))
7465 }
7466
7467 fn binary_slice_range(
7468 &self,
7469 bytes: &[u8],
7470 start_value: &Value,
7471 count_value: &Value,
7472 ) -> Result<(usize, usize)> {
7473 let len = bytes.len() as isize;
7474 let mut start = match start_value {
7475 Value::Null => 0,
7476 other => self.value_to_number(other)? as isize,
7477 };
7478 if start < 0 {
7479 start += len;
7480 }
7481 start = start.clamp(0, len);
7482 let count = match count_value {
7483 Value::Null => len - start,
7484 other => self.value_to_number(other)? as isize,
7485 }
7486 .max(0);
7487 let end = (start + count).clamp(0, len);
7488 Ok((start as usize, end as usize))
7489 }
7490
7491 fn binary_index_range(&self, bytes: &[u8], index_value: &Value) -> Result<(usize, usize)> {
7492 let len = bytes.len() as isize;
7493 let mut index = self.value_to_number(index_value)? as isize;
7494 if index < 0 {
7495 index += len;
7496 }
7497 index = index.clamp(0, len);
7498 let end = (index + 1).clamp(0, len);
7499 Ok((index as usize, end as usize))
7500 }
7501
7502 fn apply_regex_replacement(
7503 &self,
7504 current: Value,
7505 replacement: &Expression,
7506 env: Rc<Environment>,
7507 ) -> Result<Value> {
7508 let source = self.value_to_operator_string(¤t)?;
7509 let (regex_pattern, regex_flags, replacement_expr) = match replacement {
7510 Expression::Binary {
7511 operator,
7512 left,
7513 right,
7514 ..
7515 } if operator == "->" => {
7516 let regex_value = self.eval_expression(left, Rc::clone(&env))?;
7517 let (pattern, flags) = self.coerce_regex_operand(®ex_value).map_err(|_| {
7518 ZuzuRustError::runtime("~= expects a regexp -> replacement expression")
7519 })?;
7520 (pattern, flags, right.as_ref())
7521 }
7522 _ => {
7523 return Err(ZuzuRustError::runtime(
7524 "~= expects a regexp -> replacement expression",
7525 ))
7526 }
7527 };
7528 let compiled = self.compile_regex(®ex_pattern, ®ex_flags)?;
7529 let mut out = String::new();
7530 let mut cursor = 0usize;
7531 let global = regex_flags.contains('g');
7532
7533 while cursor <= source.len() {
7534 let Some(captures) = compiled.captures(&source[cursor..]) else {
7535 break;
7536 };
7537 let Some(full) = captures.get(0) else {
7538 break;
7539 };
7540 let start = cursor + full.start();
7541 let end = cursor + full.end();
7542 out.push_str(&source[cursor..start]);
7543 let match_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
7544 match_env.define(
7545 "m".to_owned(),
7546 Value::Array(
7547 captures
7548 .iter()
7549 .map(|item| {
7550 Value::String(item.map(|m| m.as_str()).unwrap_or("").to_owned())
7551 })
7552 .collect(),
7553 ),
7554 true,
7555 );
7556 let replacement_value =
7557 self.eval_expression(replacement_expr, Rc::clone(&match_env))?;
7558 out.push_str(&self.render_value(&replacement_value)?);
7559 cursor = end;
7560 if !global {
7561 break;
7562 }
7563 if end == start {
7564 break;
7565 }
7566 }
7567 out.push_str(&source[cursor..]);
7568 Ok(Value::String(out))
7569 }
7570
7571 pub(in crate::runtime) fn render_value(&self, value: &Value) -> Result<String> {
7572 let value = self.deref_value(value)?;
7573 match &value {
7574 Value::Object(object) if self.object_has_method(object, "to_String") => {
7575 let rendered = self.call_object_method(object, "to_String", &[], Vec::new())?;
7576 self.render_value(&rendered)
7577 }
7578 Value::Object(object) => {
7579 if let Some(rendered) = self.object_builtin_render(object)? {
7580 Ok(rendered)
7581 } else {
7582 Ok(value.render())
7583 }
7584 }
7585 _ => Ok(value.render()),
7586 }
7587 }
7588
7589 pub(in crate::runtime) fn value_to_operator_string(&self, value: &Value) -> Result<String> {
7590 let value = self.deref_value(value)?;
7591 match &value {
7592 Value::Null => Ok(String::new()),
7593 Value::Boolean(true) => Ok("true".to_owned()),
7594 Value::Boolean(false) => Ok("false".to_owned()),
7595 Value::Number(number) => Ok(render_number(*number)),
7596 Value::String(text) => Ok(text.clone()),
7597 Value::Regex(pattern, _) => Ok(pattern.clone()),
7598 Value::Object(object) if self.object_has_method(object, "to_String") => {
7599 let rendered = self.call_object_method(object, "to_String", &[], Vec::new())?;
7600 self.value_to_operator_string(&rendered)
7601 }
7602 _ => Err(ZuzuRustError::runtime(format!(
7603 "cannot coerce {} to String",
7604 self.typeof_name(&value)
7605 ))),
7606 }
7607 }
7608
7609 fn render_repl_value(&self, value: &Value) -> Result<String> {
7610 let value = self.deref_value(value)?;
7611 match &value {
7612 Value::Null => Ok("Null".to_owned()),
7613 Value::Boolean(_) | Value::Number(_) | Value::String(_) | Value::BinaryString(_) => {
7614 self.render_value(&value)
7615 }
7616 _ => Ok(self.typeof_name(&value)),
7617 }
7618 }
7619
7620 fn value_to_number(&self, value: &Value) -> Result<f64> {
7621 let value = self.deref_value(value)?;
7622 match &value {
7623 Value::Object(object) if self.object_has_method(object, "to_Number") => {
7624 let coerced = self.call_object_method(object, "to_Number", &[], Vec::new())?;
7625 self.value_to_number(&coerced)
7626 }
7627 _ => value.to_number(),
7628 }
7629 }
7630
7631 pub(in crate::runtime) fn value_is_truthy(&self, value: &Value) -> Result<bool> {
7632 let value = self.deref_value(value)?;
7633 match &value {
7634 Value::Object(object) if self.object_has_method(object, "to_Boolean") => {
7635 let coerced = self.call_object_method(object, "to_Boolean", &[], Vec::new())?;
7636 self.value_is_truthy(&coerced)
7637 }
7638 Value::Object(object) => {
7639 if let Some(result) = self.object_builtin_truthy(object) {
7640 Ok(result)
7641 } else {
7642 Ok(value.is_truthy())
7643 }
7644 }
7645 _ => Ok(value.is_truthy()),
7646 }
7647 }
7648
7649 fn typeof_name(&self, value: &Value) -> String {
7650 let value = self.deref_value(value).unwrap_or_else(|_| value.clone());
7651 match value {
7652 Value::Object(object) => object.borrow().class.name.clone(),
7653 Value::UserClass(_) | Value::Class(_) => "Class".to_owned(),
7654 Value::Trait(_) => "Trait".to_owned(),
7655 Value::Method(_) => "Method".to_owned(),
7656 _ => value.type_name().to_owned(),
7657 }
7658 }
7659
7660 fn member_name_operand(&self, expr: &Expression, env: Rc<Environment>) -> Result<String> {
7661 match expr {
7662 Expression::Identifier { name, .. } => Ok(name.clone()),
7663 Expression::StringLiteral { value, .. } => Ok(value.clone()),
7664 _ => self.render_value(&self.eval_expression(expr, env)?),
7665 }
7666 }
7667
7668 fn value_instanceof(&self, value: &Value, class_value: &Value) -> bool {
7669 let value = self.deref_value(value).unwrap_or_else(|_| value.clone());
7670 let class_value = self
7671 .deref_value(class_value)
7672 .unwrap_or_else(|_| class_value.clone());
7673 match (&value, &class_value) {
7674 (_, Value::Class(name)) if name.as_str() == "Any" => true,
7675 (Value::Class(_) | Value::UserClass(_), Value::Class(name)) => name.as_str() == "Class",
7676 (Value::Object(object), Value::UserClass(class)) => {
7677 self.class_matches_user(&object.borrow().class, class)
7678 }
7679 (Value::String(_), Value::UserClass(class)) => self.class_matches(class, "Exception"),
7680 (Value::Null, Value::Class(name)) => name.as_str() == "Null",
7681 (Value::Boolean(_), Value::Class(name)) => name.as_str() == "Boolean",
7682 (Value::Number(_), Value::Class(name)) => name.as_str() == "Number",
7683 (Value::String(_), Value::Class(name)) => name.as_str() == "String",
7684 (Value::BinaryString(_), Value::Class(name)) => name.as_str() == "BinaryString",
7685 (Value::Array(_) | Value::SystemArray(_), Value::Class(name)) => {
7686 matches!(name.as_str(), "Array" | "Collection" | "Object")
7687 }
7688 (Value::Set(_), Value::Class(name)) => {
7689 matches!(name.as_str(), "Set" | "Collection" | "Object")
7690 }
7691 (Value::Bag(_), Value::Class(name)) => {
7692 matches!(name.as_str(), "Bag" | "Collection" | "Object")
7693 }
7694 (Value::Dict(_) | Value::SystemDict(_), Value::Class(name)) => {
7695 matches!(name.as_str(), "Dict" | "Collection" | "Object")
7696 }
7697 (Value::PairList(_), Value::Class(name)) => name.as_str() == "PairList",
7698 (Value::Pair(_, _), Value::Class(name)) => name.as_str() == "Pair",
7699 (Value::Regex(_, _), Value::Class(name)) => name.as_str() == "Regexp",
7700 (Value::Object(object), Value::Class(name)) => {
7701 let object_class = &object.borrow().class;
7702 name.as_str() == "Object"
7703 || (object_class.source_decl.is_none() && object_class.name == name.as_str())
7704 || matches!(
7705 (self.class_builtin_base_name(object_class), name.as_str()),
7706 (Some(base), target) if base == target
7707 || (
7708 target == "Collection"
7709 && matches!(base.as_str(), "Array" | "Set" | "Bag" | "Dict")
7710 )
7711 )
7712 }
7713 (
7714 Value::Function(_) | Value::NativeFunction(_) | Value::Iterator(_),
7715 Value::Class(name),
7716 ) => name.as_str() == "Function",
7717 (Value::Task(_), Value::Class(name)) => name.as_str() == "Task",
7718 (Value::Channel(_), Value::Class(name)) => name.as_str() == "Channel",
7719 (Value::CancellationSource(_), Value::Class(name)) => {
7720 name.as_str() == "CancellationSource"
7721 }
7722 (Value::CancellationToken(_), Value::Class(name)) => {
7723 name.as_str() == "CancellationToken"
7724 }
7725 _ => false,
7726 }
7727 }
7728
7729 fn value_does_trait(&self, value: &Value, trait_value: &Value) -> bool {
7730 let value = self.deref_value(value).unwrap_or_else(|_| value.clone());
7731 let trait_value = self
7732 .deref_value(trait_value)
7733 .unwrap_or_else(|_| trait_value.clone());
7734 let trait_name = match &trait_value {
7735 Value::Trait(trait_value) => trait_value.name.as_str(),
7736 Value::UserClass(class) => class.name.as_str(),
7737 Value::Class(name) => name.as_str(),
7738 _ => return false,
7739 };
7740 match &value {
7741 Value::Object(object) => self.class_has_trait(&object.borrow().class, trait_name),
7742 _ => false,
7743 }
7744 }
7745
7746 fn value_can_method(&self, value: &Value, name: &str) -> bool {
7747 let value = self.deref_value(value).unwrap_or_else(|_| value.clone());
7748 match &value {
7749 Value::Class(class_name) => stdlib::has_builtin_class_method(class_name, name),
7750 Value::Object(object) => self.object_has_method(object, name),
7751 _ => false,
7752 }
7753 }
7754
7755 fn class_matches(&self, class: &Rc<UserClassValue>, name: &str) -> bool {
7756 if class.name == name {
7757 return true;
7758 }
7759 match &class.base {
7760 Some(ClassBase::User(base)) => self.class_matches(base, name),
7761 Some(ClassBase::Builtin(base)) => base == name,
7762 None => false,
7763 }
7764 }
7765
7766 fn class_matches_user(&self, class: &Rc<UserClassValue>, target: &Rc<UserClassValue>) -> bool {
7767 if Rc::ptr_eq(class, target) {
7768 return true;
7769 }
7770 if class.name == target.name
7771 && is_builtin_exception_class(&class.name)
7772 && is_builtin_exception_class(&target.name)
7773 {
7774 return true;
7775 }
7776 match &class.base {
7777 Some(ClassBase::User(base)) => self.class_matches_user(base, target),
7778 Some(ClassBase::Builtin(_)) | None => false,
7779 }
7780 }
7781
7782 fn class_has_trait(&self, class: &Rc<UserClassValue>, name: &str) -> bool {
7783 if class
7784 .traits
7785 .iter()
7786 .any(|trait_value| trait_value.name == name)
7787 {
7788 return true;
7789 }
7790 match &class.base {
7791 Some(ClassBase::User(base)) => self.class_has_trait(base, name),
7792 None => false,
7793 Some(ClassBase::Builtin(_)) => false,
7794 }
7795 }
7796
7797 fn class_decl_env(&self, class: &Rc<UserClassValue>) -> Rc<Environment> {
7798 if let Some(method) = class.methods.values().next() {
7799 return Rc::clone(&method.env);
7800 }
7801 if let Some(method) = class.static_methods.values().next() {
7802 return Rc::clone(&method.env);
7803 }
7804 if let Some(base) = &class.base {
7805 if let ClassBase::User(base) = base {
7806 return self.class_decl_env(base);
7807 }
7808 }
7809 if let Some(trait_value) = class.traits.first() {
7810 if let Some(method) = trait_value.methods.values().next() {
7811 return Rc::clone(&method.env);
7812 }
7813 }
7814 if let Some(class) = class.nested_classes.values().next() {
7815 return self.class_decl_env(class);
7816 }
7817 Rc::new(Environment::new(None))
7818 }
7819
7820 fn find_method(&self, class: &Rc<UserClassValue>, name: &str) -> Option<Rc<MethodValue>> {
7821 if let Some(method) = class.methods.get(name) {
7822 return Some(Rc::clone(method));
7823 }
7824 for trait_value in &class.traits {
7825 if let Some(method) = trait_value.methods.get(name) {
7826 return Some(Rc::clone(method));
7827 }
7828 }
7829 match &class.base {
7830 Some(ClassBase::User(base)) => self.find_method(base, name),
7831 None => None,
7832 Some(ClassBase::Builtin(_)) => None,
7833 }
7834 }
7835
7836 fn collect_method_candidates(
7837 &self,
7838 class: &Rc<UserClassValue>,
7839 name: &str,
7840 is_static: bool,
7841 candidates: &mut Vec<Rc<MethodValue>>,
7842 ) {
7843 if is_static {
7844 if let Some(method) = class.static_methods.get(name) {
7845 candidates.push(Rc::clone(method));
7846 }
7847 } else {
7848 if let Some(method) = class.methods.get(name) {
7849 candidates.push(Rc::clone(method));
7850 }
7851 for trait_value in &class.traits {
7852 if let Some(method) = trait_value.methods.get(name) {
7853 candidates.push(Rc::clone(method));
7854 }
7855 }
7856 }
7857
7858 if let Some(ClassBase::User(base)) = &class.base {
7859 self.collect_method_candidates(base, name, is_static, candidates);
7860 }
7861 }
7862
7863 fn find_next_method(
7864 &self,
7865 class: &Rc<UserClassValue>,
7866 name: &str,
7867 is_static: bool,
7868 ) -> Option<Rc<MethodValue>> {
7869 let current = self.current_method_stack.borrow().last().cloned()?;
7870 let mut candidates = Vec::new();
7871 self.collect_method_candidates(class, name, is_static, &mut candidates);
7872 for (index, candidate) in candidates.iter().enumerate() {
7873 if Rc::ptr_eq(candidate, ¤t) {
7874 return candidates.get(index + 1).cloned();
7875 }
7876 }
7877 None
7878 }
7879
7880 fn find_static_method(
7881 &self,
7882 class: &Rc<UserClassValue>,
7883 name: &str,
7884 ) -> Option<Rc<MethodValue>> {
7885 if let Some(method) = class.static_methods.get(name) {
7886 return Some(Rc::clone(method));
7887 }
7888 match &class.base {
7889 Some(ClassBase::User(base)) => self.find_static_method(base, name),
7890 None => None,
7891 Some(ClassBase::Builtin(_)) => None,
7892 }
7893 }
7894
7895 fn class_builtin_base_name(&self, class: &Rc<UserClassValue>) -> Option<String> {
7896 match &class.base {
7897 Some(ClassBase::Builtin(name)) => Some(name.clone()),
7898 Some(ClassBase::User(base)) => self.class_builtin_base_name(base),
7899 None => None,
7900 }
7901 }
7902
7903 fn object_builtin_value(&self, object: &Rc<RefCell<ObjectValue>>) -> Option<Value> {
7904 object.borrow().builtin_value.clone()
7905 }
7906
7907 fn object_builtin_collection_contains(
7908 &self,
7909 object: &Rc<RefCell<ObjectValue>>,
7910 needle: &Value,
7911 ) -> bool {
7912 match self.object_builtin_value(object) {
7913 Some(value) => collection_contains(&value, needle),
7914 None => false,
7915 }
7916 }
7917
7918 fn object_builtin_truthy(&self, object: &Rc<RefCell<ObjectValue>>) -> Option<bool> {
7919 self.object_builtin_value(object)
7920 .map(|value| value.is_truthy())
7921 }
7922
7923 fn object_builtin_render(&self, object: &Rc<RefCell<ObjectValue>>) -> Result<Option<String>> {
7924 match self.object_builtin_value(object) {
7925 Some(value) => Ok(Some(self.render_value(&value)?)),
7926 None => Ok(None),
7927 }
7928 }
7929
7930 fn collect_field_specs(&self, class: &Rc<UserClassValue>) -> Vec<FieldSpec> {
7931 let mut fields = match &class.base {
7932 Some(ClassBase::User(base)) => self.collect_field_specs(base),
7933 None => Vec::new(),
7934 Some(ClassBase::Builtin(_)) => Vec::new(),
7935 };
7936 fields.extend(class.fields.iter().cloned());
7937 fields
7938 }
7939
7940 fn find_field_spec<'a>(&self, class: &'a Rc<UserClassValue>, name: &str) -> Option<FieldSpec> {
7941 self.collect_field_specs(class)
7942 .into_iter()
7943 .find(|field| field.name == name)
7944 }
7945
7946 fn object_has_method(&self, object: &Rc<RefCell<ObjectValue>>, name: &str) -> bool {
7947 let object_ref = object.borrow();
7948 if self.class_matches(&object_ref.class, "Exception")
7949 && matches!(name, "to_String" | "message")
7950 {
7951 return true;
7952 }
7953 if self.find_method(&object_ref.class, name).is_some() {
7954 return true;
7955 }
7956 if stdlib::has_builtin_object_method(&object_ref.class.name, name) {
7957 return true;
7958 }
7959 self.find_field_spec(&object_ref.class, name.strip_prefix("get_").unwrap_or(""))
7960 .map(|field| {
7961 name.starts_with("get_") && field.accessors.iter().any(|item| item == "get")
7962 })
7963 .unwrap_or(false)
7964 || self
7965 .find_field_spec(&object_ref.class, name.strip_prefix("set_").unwrap_or(""))
7966 .map(|field| {
7967 name.starts_with("set_") && field.accessors.iter().any(|item| item == "set")
7968 })
7969 .unwrap_or(false)
7970 || self
7971 .find_field_spec(&object_ref.class, name.strip_prefix("clear_").unwrap_or(""))
7972 .map(|field| {
7973 name.starts_with("clear_") && field.accessors.iter().any(|item| item == "clear")
7974 })
7975 .unwrap_or(false)
7976 || self
7977 .find_field_spec(&object_ref.class, name.strip_prefix("has_").unwrap_or(""))
7978 .map(|field| {
7979 name.starts_with("has_") && field.accessors.iter().any(|item| item == "has")
7980 })
7981 .unwrap_or(false)
7982 }
7983
7984 fn call_object_method(
7985 &self,
7986 object: &Rc<RefCell<ObjectValue>>,
7987 name: &str,
7988 args: &[Value],
7989 named_args: Vec<(String, Value)>,
7990 ) -> Result<Value> {
7991 let class = Rc::clone(&object.borrow().class);
7992 if let Some(field_name) = name.strip_prefix("get_") {
7993 if let Some(field) = self.find_field_spec(&class, field_name) {
7994 if field.accessors.iter().any(|item| item == "get") {
7995 reject_named_args(name, &named_args)?;
7996 require_arity(name, args, 0)?;
7997 return Ok(object
7998 .borrow()
7999 .fields
8000 .get(field_name)
8001 .cloned()
8002 .unwrap_or(Value::Null));
8003 }
8004 }
8005 }
8006 if let Some(field_name) = name.strip_prefix("set_") {
8007 if let Some(field) = self.find_field_spec(&class, field_name) {
8008 if field.accessors.iter().any(|item| item == "set") {
8009 reject_named_args(name, &named_args)?;
8010 require_arity(name, args, 1)?;
8011 self.object_set_field(object, &field, args[0].clone())?;
8012 return Ok(Value::Object(Rc::clone(object)));
8013 }
8014 }
8015 }
8016 if let Some(field_name) = name.strip_prefix("clear_") {
8017 if let Some(field) = self.find_field_spec(&class, field_name) {
8018 if field.accessors.iter().any(|item| item == "clear") {
8019 reject_named_args(name, &named_args)?;
8020 require_arity(name, args, 0)?;
8021 self.object_set_field(object, &field, Value::Null)?;
8022 return Ok(Value::Object(Rc::clone(object)));
8023 }
8024 }
8025 }
8026 if let Some(field_name) = name.strip_prefix("has_") {
8027 if let Some(field) = self.find_field_spec(&class, field_name) {
8028 if field.accessors.iter().any(|item| item == "has") {
8029 reject_named_args(name, &named_args)?;
8030 require_arity(name, args, 0)?;
8031 let has_value = object
8032 .borrow()
8033 .fields
8034 .get(field_name)
8035 .map(|value| !matches!(value.resolve_weak_value(), Value::Null))
8036 .unwrap_or(false);
8037 return Ok(Value::Boolean(has_value));
8038 }
8039 }
8040 }
8041
8042 let Some(method) = self.find_method(&class, name) else {
8043 if self.class_matches(&class, "Exception") {
8044 reject_named_args(name, &named_args)?;
8045 match name {
8046 "message" => {
8047 require_arity(name, args, 0)?;
8048 return Ok(object
8049 .borrow()
8050 .fields
8051 .get("message")
8052 .cloned()
8053 .unwrap_or(Value::Null));
8054 }
8055 "to_String" => {
8056 require_arity(name, args, 0)?;
8057 let message = object
8058 .borrow()
8059 .fields
8060 .get("message")
8061 .cloned()
8062 .unwrap_or(Value::Null);
8063 let message = self.render_value(&message)?;
8064 let class_name = class.name.as_str();
8065 if message == class_name || message.starts_with(&format!("{class_name}:")) {
8066 return Ok(Value::String(message));
8067 }
8068 if message.is_empty() {
8069 return Ok(Value::String(class.name.clone()));
8070 }
8071 return Ok(Value::String(format!("{}: {message}", class.name)));
8072 }
8073 _ => {}
8074 }
8075 }
8076 if let Some(mut builtin_value) = self.object_builtin_value(object) {
8077 if let Some(result) = stdlib::call_builtin_object_method(
8078 self,
8079 object,
8080 &class.name,
8081 &builtin_value,
8082 name,
8083 args,
8084 &named_args,
8085 ) {
8086 return result;
8087 }
8088 return self.call_method_named(&mut builtin_value, name, args, named_args);
8089 }
8090 return Err(ZuzuRustError::thrown(format!(
8091 "unsupported method '{}' for {}",
8092 name, class.name
8093 )));
8094 };
8095
8096 self.invoke_object_method_with_context(object, class, name, &method, args, named_args)
8097 }
8098
8099 fn object_set_field(
8100 &self,
8101 object: &Rc<RefCell<ObjectValue>>,
8102 field: &FieldSpec,
8103 value: Value,
8104 ) -> Result<()> {
8105 self.object_set_field_with_weak_write(object, field, value, false)
8106 }
8107
8108 fn object_set_field_with_weak_write(
8109 &self,
8110 object: &Rc<RefCell<ObjectValue>>,
8111 field: &FieldSpec,
8112 value: Value,
8113 weak_write: bool,
8114 ) -> Result<()> {
8115 let is_weak_storage = field.is_weak_storage || weak_write;
8116 if matches!(value, Value::Null) && field.declared_type.is_some() {
8117 let mut object = object.borrow_mut();
8118 if is_weak_storage {
8119 object.weak_fields.insert(field.name.clone());
8120 } else {
8121 object.weak_fields.remove(&field.name);
8122 }
8123 object.fields.insert(field.name.clone(), Value::Null);
8124 return Ok(());
8125 }
8126 self.assert_declared_type(field.declared_type.as_deref(), &value, &field.name)?;
8127 let mut object = object.borrow_mut();
8128 if is_weak_storage {
8129 object.weak_fields.insert(field.name.clone());
8130 } else {
8131 object.weak_fields.remove(&field.name);
8132 }
8133 object.fields.insert(
8134 field.name.clone(),
8135 value.stored_with_weak_policy(is_weak_storage),
8136 );
8137 Ok(())
8138 }
8139
8140 fn eval_do_expression(&self, body: &BlockStatement, env: Rc<Environment>) -> Result<Value> {
8141 let block_env = if body.needs_lexical_scope {
8142 Rc::new(Environment::new(Some(env)))
8143 } else {
8144 env
8145 };
8146 self.push_special_props_scope();
8147 let mut last = Value::Null;
8148 for statement in &body.statements {
8149 if let Some(value) =
8150 self.eval_statement_value_in_do(statement, Rc::clone(&block_env))?
8151 {
8152 last = value;
8153 }
8154 if !matches!(self.get_special_prop("__do_return__"), Value::Null) {
8155 break;
8156 }
8157 }
8158 if body.needs_lexical_scope {
8159 self.cleanup_scope(&block_env)?;
8160 }
8161 self.pop_special_props_scope();
8162 Ok(last)
8163 }
8164
8165 fn eval_statement_value_in_do(
8166 &self,
8167 statement: &Statement,
8168 env: Rc<Environment>,
8169 ) -> Result<Option<Value>> {
8170 match statement {
8171 Statement::ExpressionStatement(node) => {
8172 Ok(Some(self.eval_expression(&node.expression, env)?))
8173 }
8174 Statement::Block(block) => Ok(Some(self.eval_do_expression(block, env)?)),
8175 Statement::IfStatement(node) => {
8176 if self.value_is_truthy(&self.eval_expression(&node.test, Rc::clone(&env))?)? {
8177 Ok(Some(self.eval_do_expression(&node.consequent, env)?))
8178 } else if let Some(alternate) = &node.alternate {
8179 self.eval_statement_value_in_do(alternate, env)
8180 } else {
8181 Ok(Some(Value::Null))
8182 }
8183 }
8184 other => match self.eval_statement(other, env)? {
8185 ControlFlow::Normal => Ok(None),
8186 ControlFlow::Return(value) => {
8187 self.set_special_prop_at_level(1, "__do_return__", value.clone());
8188 Ok(Some(value))
8189 }
8190 ControlFlow::Throw(value) => Err(ZuzuRustError::thrown(self.render_value(&value)?)),
8191 ControlFlow::Continue | ControlFlow::Break => {
8192 Err(ZuzuRustError::runtime("loop control escaped do expression"))
8193 }
8194 },
8195 }
8196 }
8197
8198 fn eval_try_expression(
8199 &self,
8200 body: &BlockStatement,
8201 handlers: &[crate::ast::CatchClause],
8202 env: Rc<Environment>,
8203 ) -> Result<Value> {
8204 match self.eval_do_expression(body, Rc::clone(&env)) {
8205 Ok(value) => Ok(value),
8206 Err(ZuzuRustError::Thrown { value, token }) => {
8207 let thrown_value = self.lookup_thrown_value(token.as_deref());
8208 for handler in handlers {
8209 if !self.catch_clause_matches(
8210 handler.binding.as_ref(),
8211 &value,
8212 thrown_value.as_ref(),
8213 ) {
8214 continue;
8215 }
8216 let catch_env = Rc::new(Environment::new(Some(Rc::clone(&env))));
8217 let binding_name = handler
8218 .binding
8219 .as_ref()
8220 .and_then(|binding| binding.name.clone())
8221 .unwrap_or_else(|| "e".to_owned());
8222 let caught_value = self.make_catch_binding_value(
8223 handler.binding.as_ref(),
8224 &value,
8225 thrown_value.as_ref(),
8226 );
8227 catch_env.define(binding_name, caught_value, true);
8228 return self.eval_do_expression(&handler.body, catch_env);
8229 }
8230 match token {
8231 Some(token) => Err(ZuzuRustError::thrown_with_token(value, token)),
8232 None => Err(ZuzuRustError::thrown(value)),
8233 }
8234 }
8235 Err(err) => Err(err),
8236 }
8237 }
8238
8239 fn cleanup_scope(&self, env: &Rc<Environment>) -> Result<()> {
8240 self.cleanup_scope_preserving(env, &[])
8241 }
8242
8243 fn cleanup_scope_preserving(&self, env: &Rc<Environment>, preserved: &[&Value]) -> Result<()> {
8244 let bindings = env.bindings.borrow();
8245 let roots = bindings
8246 .values()
8247 .map(|binding| &binding.value)
8248 .collect::<Vec<_>>();
8249 let mut protected_objects = HashSet::new();
8250 let mut seen_protected_shared = HashSet::new();
8251 let mut seen_protected_objects = HashSet::new();
8252 for value in preserved {
8253 Self::collect_protected_cleanup_objects(
8254 value,
8255 &mut protected_objects,
8256 &mut seen_protected_shared,
8257 &mut seen_protected_objects,
8258 );
8259 }
8260
8261 let mut shared_refs = HashMap::new();
8262 let mut seen_shared = HashSet::new();
8263 for value in &roots {
8264 self.count_cleanup_shared_refs(value, &mut shared_refs, &mut seen_shared);
8265 }
8266
8267 let mut object_refs = HashMap::new();
8268 let mut seen_shared = HashSet::new();
8269 for value in &roots {
8270 self.count_cleanup_object_refs(value, &shared_refs, &mut object_refs, &mut seen_shared);
8271 }
8272
8273 let mut finalizers = Vec::new();
8274 let mut seen_objects = HashSet::new();
8275 let mut seen_shared = HashSet::new();
8276 for value in &roots {
8277 self.collect_cleanup_finalizers(
8278 value,
8279 &shared_refs,
8280 &object_refs,
8281 &protected_objects,
8282 &mut finalizers,
8283 &mut seen_objects,
8284 &mut seen_shared,
8285 );
8286 }
8287 drop(bindings);
8288
8289 for object in finalizers {
8290 let _ = self.call_object_method(&object, "__demolish__", &[], Vec::new())?;
8291 }
8292 Ok(())
8293 }
8294
8295 fn collect_protected_cleanup_objects(
8296 value: &Value,
8297 protected: &mut HashSet<usize>,
8298 seen_shared: &mut HashSet<usize>,
8299 seen_objects: &mut HashSet<usize>,
8300 ) {
8301 match value {
8302 Value::Object(object) => {
8303 let id = Rc::as_ptr(object) as usize;
8304 protected.insert(id);
8305 if seen_objects.insert(id) {
8306 let fields = object.borrow();
8307 for field in fields.fields.values() {
8308 Self::collect_protected_cleanup_objects(
8309 field,
8310 protected,
8311 seen_shared,
8312 seen_objects,
8313 );
8314 }
8315 }
8316 }
8317 Value::Shared(shared) => {
8318 let id = Rc::as_ptr(shared) as usize;
8319 if seen_shared.insert(id) {
8320 Self::collect_protected_cleanup_objects(
8321 &shared.borrow(),
8322 protected,
8323 seen_shared,
8324 seen_objects,
8325 );
8326 }
8327 }
8328 Value::Array(values)
8329 | Value::SystemArray(values)
8330 | Value::Set(values)
8331 | Value::Bag(values) => {
8332 for value in values {
8333 Self::collect_protected_cleanup_objects(
8334 value,
8335 protected,
8336 seen_shared,
8337 seen_objects,
8338 );
8339 }
8340 }
8341 Value::Dict(values) | Value::SystemDict(values) => {
8342 for value in values.values() {
8343 Self::collect_protected_cleanup_objects(
8344 value,
8345 protected,
8346 seen_shared,
8347 seen_objects,
8348 );
8349 }
8350 }
8351 Value::PairList(values) => {
8352 for (_, value) in values {
8353 Self::collect_protected_cleanup_objects(
8354 value,
8355 protected,
8356 seen_shared,
8357 seen_objects,
8358 );
8359 }
8360 }
8361 Value::Pair(_, value) => {
8362 Self::collect_protected_cleanup_objects(
8363 value,
8364 protected,
8365 seen_shared,
8366 seen_objects,
8367 );
8368 }
8369 _ => {}
8370 }
8371 }
8372
8373 fn count_cleanup_shared_refs(
8374 &self,
8375 value: &Value,
8376 counts: &mut HashMap<usize, usize>,
8377 seen_shared: &mut HashSet<usize>,
8378 ) {
8379 self.walk_cleanup_value(value, counts, None, None, None, None, seen_shared);
8380 }
8381
8382 fn count_cleanup_object_refs(
8383 &self,
8384 value: &Value,
8385 shared_refs: &HashMap<usize, usize>,
8386 counts: &mut HashMap<usize, usize>,
8387 seen_shared: &mut HashSet<usize>,
8388 ) {
8389 self.walk_cleanup_value(
8390 value,
8391 counts,
8392 Some(shared_refs),
8393 None,
8394 None,
8395 None,
8396 seen_shared,
8397 );
8398 }
8399
8400 fn collect_cleanup_finalizers(
8401 &self,
8402 value: &Value,
8403 shared_refs: &HashMap<usize, usize>,
8404 object_refs: &HashMap<usize, usize>,
8405 protected_objects: &HashSet<usize>,
8406 out: &mut Vec<Rc<RefCell<ObjectValue>>>,
8407 seen_objects: &mut HashSet<usize>,
8408 seen_shared: &mut HashSet<usize>,
8409 ) {
8410 self.walk_cleanup_value(
8411 value,
8412 &mut HashMap::new(),
8413 Some(shared_refs),
8414 Some(object_refs),
8415 Some(protected_objects),
8416 Some((out, seen_objects)),
8417 seen_shared,
8418 );
8419 }
8420
8421 fn walk_cleanup_value(
8422 &self,
8423 value: &Value,
8424 counts: &mut HashMap<usize, usize>,
8425 shared_refs: Option<&HashMap<usize, usize>>,
8426 object_refs: Option<&HashMap<usize, usize>>,
8427 protected_objects: Option<&HashSet<usize>>,
8428 mut finalizers: Option<(&mut Vec<Rc<RefCell<ObjectValue>>>, &mut HashSet<usize>)>,
8429 seen_shared: &mut HashSet<usize>,
8430 ) {
8431 match value {
8432 Value::Object(object) => {
8433 let id = Rc::as_ptr(object) as usize;
8434 if let Some(object_refs) = object_refs {
8435 if object_refs.get(&id).copied().unwrap_or(0) == Rc::strong_count(object)
8436 && !protected_objects.is_some_and(|protected| protected.contains(&id))
8437 && self.object_has_method(object, "__demolish__")
8438 {
8439 if let Some((out, seen_objects)) = finalizers.as_mut() {
8440 if seen_objects.insert(id) {
8441 out.push(Rc::clone(object));
8442 }
8443 }
8444 }
8445 } else if shared_refs.is_some() {
8446 *counts.entry(id).or_insert(0) += 1;
8447 }
8448 }
8449 Value::Shared(shared) => {
8450 let id = Rc::as_ptr(shared) as usize;
8451 let counting_shared_refs =
8452 shared_refs.is_none() && object_refs.is_none() && finalizers.is_none();
8453 if counting_shared_refs {
8454 *counts.entry(id).or_insert(0) += 1;
8455 }
8456
8457 if let Some(shared_refs) = shared_refs {
8458 if shared_refs.get(&id).copied().unwrap_or(0) != Rc::strong_count(shared) {
8459 return;
8460 }
8461 }
8462
8463 if seen_shared.insert(id) {
8464 self.walk_cleanup_value(
8465 &shared.borrow(),
8466 counts,
8467 shared_refs,
8468 object_refs,
8469 protected_objects,
8470 finalizers,
8471 seen_shared,
8472 );
8473 }
8474 }
8475 Value::Array(values)
8476 | Value::SystemArray(values)
8477 | Value::Set(values)
8478 | Value::Bag(values) => {
8479 for value in values {
8480 self.walk_cleanup_value(
8481 value,
8482 counts,
8483 shared_refs,
8484 object_refs,
8485 protected_objects,
8486 finalizers
8487 .as_mut()
8488 .map(|(out, seen)| (&mut **out, &mut **seen)),
8489 seen_shared,
8490 );
8491 }
8492 }
8493 Value::Dict(values) | Value::SystemDict(values) => {
8494 for value in values.values() {
8495 self.walk_cleanup_value(
8496 value,
8497 counts,
8498 shared_refs,
8499 object_refs,
8500 protected_objects,
8501 finalizers
8502 .as_mut()
8503 .map(|(out, seen)| (&mut **out, &mut **seen)),
8504 seen_shared,
8505 );
8506 }
8507 }
8508 Value::PairList(values) => {
8509 for (_, value) in values {
8510 self.walk_cleanup_value(
8511 value,
8512 counts,
8513 shared_refs,
8514 object_refs,
8515 protected_objects,
8516 finalizers
8517 .as_mut()
8518 .map(|(out, seen)| (&mut **out, &mut **seen)),
8519 seen_shared,
8520 );
8521 }
8522 }
8523 Value::Pair(_, value) => {
8524 self.walk_cleanup_value(
8525 value,
8526 counts,
8527 shared_refs,
8528 object_refs,
8529 protected_objects,
8530 finalizers,
8531 seen_shared,
8532 );
8533 }
8534 _ => {}
8535 }
8536 }
8537
8538 fn make_catch_binding_value(
8539 &self,
8540 binding: Option<&crate::ast::CatchBinding>,
8541 thrown_value: &str,
8542 thrown_runtime_value: Option<&Value>,
8543 ) -> Value {
8544 if let Some(value) = thrown_runtime_value {
8545 return value.clone();
8546 }
8547 let declared_type = binding.and_then(|item| item.declared_type.as_deref());
8548 match declared_type {
8549 Some("Exception")
8550 | Some("BailOutException")
8551 | Some("TypeException")
8552 | Some("CancelledException")
8553 | Some("TimeoutException")
8554 | Some("ChannelClosedException")
8555 | Some("MarshallingException")
8556 | Some("UnmarshallingException")
8557 | Some("ExhaustedException") => {
8558 let class_name = inferred_exception_class(thrown_value)
8559 .or(declared_type)
8560 .unwrap_or("Exception");
8561 let class_value = if class_name == "Exception" {
8562 Value::UserClass(Rc::new(UserClassValue {
8563 name: "Exception".to_owned(),
8564 base: None,
8565 traits: Vec::new(),
8566 fields: exception_field_specs(),
8567 methods: HashMap::new(),
8568 static_methods: HashMap::new(),
8569 nested_classes: HashMap::new(),
8570 source_decl: None,
8571 closure_env: None,
8572 }))
8573 } else {
8574 Value::UserClass(Rc::new(UserClassValue {
8575 name: class_name.to_owned(),
8576 base: Some(ClassBase::User(Rc::new(UserClassValue {
8577 name: "Exception".to_owned(),
8578 base: None,
8579 traits: Vec::new(),
8580 fields: exception_field_specs(),
8581 methods: HashMap::new(),
8582 static_methods: HashMap::new(),
8583 nested_classes: HashMap::new(),
8584 source_decl: None,
8585 closure_env: None,
8586 }))),
8587 traits: Vec::new(),
8588 fields: Vec::new(),
8589 methods: HashMap::new(),
8590 static_methods: HashMap::new(),
8591 nested_classes: HashMap::new(),
8592 source_decl: None,
8593 closure_env: None,
8594 }))
8595 };
8596 let mut message = thrown_value.to_owned();
8597 if let Some(stripped) = thrown_value
8598 .strip_prefix(&format!("{class_name}: "))
8599 .or_else(|| thrown_value.strip_prefix("Exception: "))
8600 .or_else(|| thrown_value.strip_prefix("Bail out! "))
8601 {
8602 message = stripped.to_owned();
8603 }
8604 match class_value {
8605 Value::UserClass(class) => Value::Object(Rc::new(RefCell::new(ObjectValue {
8606 class,
8607 fields: HashMap::from([
8608 ("message".to_owned(), Value::String(message)),
8609 ("file".to_owned(), Value::String("<unknown>".to_owned())),
8610 ("line".to_owned(), Value::Number(1.0)),
8611 ("code".to_owned(), Value::Null),
8612 ]),
8613 weak_fields: HashSet::new(),
8614 builtin_value: None,
8615 }))),
8616 _ => Value::String(thrown_value.to_owned()),
8617 }
8618 }
8619 _ => Value::String(thrown_value.to_owned()),
8620 }
8621 }
8622
8623 fn annotate_exception_metadata(&self, value: &Value, source_file: Option<&str>, line: usize) {
8624 let resolved = self.deref_value(value).unwrap_or_else(|_| value.clone());
8625 let Value::Object(object) = resolved else {
8626 return;
8627 };
8628 if !self.class_matches(&object.borrow().class, "Exception") {
8629 return;
8630 }
8631 let mut object = object.borrow_mut();
8632 if matches!(object.fields.get("file"), None | Some(Value::Null)) {
8633 let file = source_file.unwrap_or("<unknown>");
8634 object
8635 .fields
8636 .insert("file".to_owned(), Value::String(file.to_owned()));
8637 }
8638 if matches!(object.fields.get("line"), None | Some(Value::Null)) {
8639 object
8640 .fields
8641 .insert("line".to_owned(), Value::Number(line as f64));
8642 }
8643 }
8644
8645 fn normalize_die_value(
8646 &self,
8647 value: Value,
8648 source_file: Option<&str>,
8649 line: usize,
8650 ) -> Result<Value> {
8651 let resolved = self.deref_value(&value).unwrap_or_else(|_| value.clone());
8652 if let Value::Object(object) = &resolved {
8653 if self.class_matches(&object.borrow().class, "Exception") {
8654 self.annotate_exception_metadata(&value, source_file, line);
8655 }
8656 return Ok(value);
8657 }
8658
8659 let message = self.render_value(&value)?;
8660 Ok(self.make_exception_object(message, source_file, line))
8661 }
8662
8663 fn make_exception_object(
8664 &self,
8665 message: String,
8666 source_file: Option<&str>,
8667 line: usize,
8668 ) -> Value {
8669 self.make_exception_object_with_code(message, source_file, line, Value::Null)
8670 }
8671
8672 pub(in crate::runtime) fn make_exception_object_with_code(
8673 &self,
8674 message: String,
8675 source_file: Option<&str>,
8676 line: usize,
8677 code: Value,
8678 ) -> Value {
8679 Value::Object(Rc::new(RefCell::new(ObjectValue {
8680 class: Rc::new(UserClassValue {
8681 name: "Exception".to_owned(),
8682 base: None,
8683 traits: Vec::new(),
8684 fields: exception_field_specs(),
8685 methods: HashMap::new(),
8686 static_methods: HashMap::new(),
8687 nested_classes: HashMap::new(),
8688 source_decl: None,
8689 closure_env: None,
8690 }),
8691 fields: HashMap::from([
8692 ("message".to_owned(), Value::String(message)),
8693 (
8694 "file".to_owned(),
8695 Value::String(source_file.unwrap_or("<unknown>").to_owned()),
8696 ),
8697 ("line".to_owned(), Value::Number(line as f64)),
8698 ("code".to_owned(), code),
8699 ]),
8700 weak_fields: HashSet::new(),
8701 builtin_value: None,
8702 })))
8703 }
8704
8705 fn assert_declared_type(
8706 &self,
8707 declared_type: Option<&str>,
8708 value: &Value,
8709 name: &str,
8710 ) -> Result<()> {
8711 let declared_type = declared_type.unwrap_or("Any");
8712 if declared_type == "Any" || self.value_matches_declared_type(declared_type, value) {
8713 return Ok(());
8714 }
8715 Err(ZuzuRustError::thrown(format!(
8716 "TypeException: '{name}' must be {declared_type}, got {}",
8717 self.typeof_name(value)
8718 )))
8719 }
8720
8721 fn assert_return_type(
8722 &self,
8723 declared_type: Option<&str>,
8724 name: Option<&str>,
8725 value: &Value,
8726 ) -> Result<()> {
8727 let Some(name) = name else {
8728 return self.assert_declared_type(declared_type, value, "return value");
8729 };
8730 self.assert_declared_type(declared_type, value, &format!("return value of '{name}'"))
8731 }
8732
8733 fn value_matches_declared_type(&self, declared_type: &str, value: &Value) -> bool {
8734 let resolved = match self.normalize_value(value.clone()) {
8735 Ok(value) => value,
8736 Err(_) => return false,
8737 };
8738 match declared_type {
8739 "Any" => true,
8740 "Class" => matches!(resolved, Value::Class(_) | Value::UserClass(_)),
8741 "Number" => resolved.type_name() == "Number",
8742 "String" => resolved.type_name() == "String",
8743 "BinaryString" => resolved.type_name() == "BinaryString",
8744 "Boolean" => resolved.type_name() == "Boolean",
8745 "Null" => resolved.type_name() == "Null",
8746 "Object" => matches!(
8747 resolved,
8748 Value::Array(_)
8749 | Value::SystemArray(_)
8750 | Value::Set(_)
8751 | Value::Bag(_)
8752 | Value::Dict(_)
8753 | Value::SystemDict(_)
8754 | Value::Object(_)
8755 ),
8756 "Collection" => matches!(
8757 resolved,
8758 Value::Array(_)
8759 | Value::SystemArray(_)
8760 | Value::Set(_)
8761 | Value::Bag(_)
8762 | Value::Dict(_)
8763 | Value::SystemDict(_)
8764 ),
8765 "Array" => matches!(resolved, Value::Array(_) | Value::SystemArray(_)),
8766 "Set" => matches!(resolved, Value::Set(_)),
8767 "Bag" => matches!(resolved, Value::Bag(_)),
8768 "Dict" => matches!(resolved, Value::Dict(_) | Value::SystemDict(_)),
8769 "PairList" => matches!(resolved, Value::PairList(_)),
8770 "Pair" => matches!(resolved, Value::Pair(_, _)),
8771 "Regexp" => matches!(resolved, Value::Regex(_, _)),
8772 "Function" => matches!(
8773 resolved,
8774 Value::Function(_) | Value::NativeFunction(_) | Value::Iterator(_)
8775 ),
8776 other => match &resolved {
8777 Value::Object(object) => self.class_matches(&object.borrow().class, other),
8778 Value::UserClass(class) => self.class_matches(class, other),
8779 _ => self.typeof_name(&resolved) == other,
8780 },
8781 }
8782 }
8783
8784 fn compile_regex(&self, pattern: &str, flags: &str) -> Result<Regex> {
8785 let compiled_pattern = if simple_negative_contains_regex(pattern).is_some() {
8786 "^"
8787 } else {
8788 pattern
8789 };
8790 if !self.optimizations.enables(OptimizationPass::RegexCache) {
8791 return RegexBuilder::new(compiled_pattern)
8792 .case_insensitive(flags.contains('i'))
8793 .build()
8794 .map_err(|err| ZuzuRustError::runtime(format!("invalid regexp: {err}")));
8795 }
8796 let key = (pattern.to_owned(), flags.to_owned());
8797 if let Some(regex) = self.regex_cache.borrow().get(&key) {
8798 return Ok(regex.clone());
8799 }
8800 RegexBuilder::new(compiled_pattern)
8801 .case_insensitive(flags.contains('i'))
8802 .build()
8803 .map_err(|err| ZuzuRustError::runtime(format!("invalid regexp: {err}")))
8804 .map(|regex| {
8805 self.regex_cache.borrow_mut().insert(key, regex.clone());
8806 regex
8807 })
8808 }
8809
8810 fn coerce_regex_operand(&self, regex: &Value) -> Result<(String, String)> {
8811 let regex = self.deref_value(regex)?;
8812 match ®ex {
8813 Value::Regex(pattern, flags) => Ok((pattern.clone(), flags.clone())),
8814 value => Ok((self.value_to_operator_string(value)?, String::new())),
8815 }
8816 }
8817
8818 fn eval_regex_match(&self, target: &str, regex: &Value) -> Result<Value> {
8819 let (pattern, flags) = self.coerce_regex_operand(regex)?;
8820 if let Some(needle) = simple_negative_contains_regex(&pattern) {
8821 let matched = if flags.contains('i') {
8822 !target.to_lowercase().contains(&needle.to_lowercase())
8823 } else {
8824 !target.contains(needle)
8825 };
8826 return if matched {
8827 Ok(Value::Array(vec![Value::String(String::new())]))
8828 } else {
8829 Ok(Value::Boolean(false))
8830 };
8831 }
8832
8833 let compiled = self.compile_regex(&pattern, &flags)?;
8834 if flags.contains('g') {
8835 let mut all = Vec::new();
8836 for captures in compiled.captures_iter(target) {
8837 let groups = captures
8838 .iter()
8839 .map(|item| Value::String(item.map(|m| m.as_str()).unwrap_or("").to_owned()))
8840 .collect();
8841 all.push(Value::Array(groups));
8842 }
8843 if all.is_empty() {
8844 Ok(Value::Boolean(false))
8845 } else {
8846 Ok(Value::Array(all))
8847 }
8848 } else if let Some(captures) = compiled.captures(target) {
8849 Ok(Value::Array(
8850 captures
8851 .iter()
8852 .map(|item| Value::String(item.map(|m| m.as_str()).unwrap_or("").to_owned()))
8853 .collect(),
8854 ))
8855 } else {
8856 Ok(Value::Boolean(false))
8857 }
8858 }
8859}
8860
8861fn simple_negative_contains_regex(pattern: &str) -> Option<&str> {
8862 pattern
8863 .strip_prefix("^(?!.*")
8864 .and_then(|rest| rest.strip_suffix(')'))
8865}
8866
8867impl ReplSession<'_> {
8868 pub fn eval_source(&self, source: &str) -> Result<ReplEvalResult> {
8869 self.runtime
8870 .async_executor
8871 .enter(|| self.eval_source_inner(source))
8872 }
8873
8874 fn eval_source_inner(&self, source: &str) -> Result<ReplEvalResult> {
8875 *self.runtime.output.borrow_mut() = ExecutionOutput::default();
8876 let mut special_props = self.runtime.special_props.borrow_mut();
8877 special_props.clear();
8878 special_props.push(HashMap::new());
8879 drop(special_props);
8880 self.runtime.thrown_values.borrow_mut().clear();
8881 *self.runtime.next_thrown_id.borrow_mut() = 0;
8882 self.runtime.path_line_cursors.borrow_mut().clear();
8883
8884 let options = ParseOptions::new(
8885 false,
8886 self.runtime.infer_types,
8887 self.runtime.optimizations.clone(),
8888 );
8889 let program = parse_program_with_compile_options(source, &options)?;
8890 let value = self
8891 .runtime
8892 .eval_repl_program(&program, Rc::clone(&self.env))?;
8893 Ok(ReplEvalResult {
8894 output: self.runtime.output.borrow().clone(),
8895 value: self.runtime.render_repl_value(&value)?,
8896 })
8897 }
8898}
8899
8900impl Environment {
8901 fn new(parent: Option<Rc<Environment>>) -> Self {
8902 Self {
8903 parent,
8904 bindings: RefCell::new(HashMap::new()),
8905 }
8906 }
8907
8908 fn define(&self, name: String, value: Value, mutable: bool) {
8909 self.define_with_storage(name, value, mutable, false);
8910 }
8911
8912 fn define_with_storage(
8913 &self,
8914 name: String,
8915 value: Value,
8916 mutable: bool,
8917 is_weak_storage: bool,
8918 ) {
8919 self.bindings.borrow_mut().insert(
8920 name,
8921 Binding {
8922 value: value.stored_with_weak_policy(is_weak_storage),
8923 mutable,
8924 is_weak_storage,
8925 },
8926 );
8927 }
8928
8929 fn get(&self, name: &str) -> Result<Value> {
8930 if let Some(binding) = self.bindings.borrow().get(name) {
8931 return Ok(binding.value.clone());
8932 }
8933 if let Some(parent) = &self.parent {
8934 return parent.get(name);
8935 }
8936 Err(ZuzuRustError::runtime(format!(
8937 "use of undeclared identifier '{}'",
8938 name
8939 )))
8940 }
8941
8942 fn get_at(&self, depth: usize, name: &str) -> Result<Value> {
8943 if depth == 0 {
8944 return self
8945 .bindings
8946 .borrow()
8947 .get(name)
8948 .map(|binding| binding.value.clone())
8949 .ok_or_else(|| {
8950 ZuzuRustError::runtime(format!("use of undeclared identifier '{}'", name))
8951 });
8952 }
8953 let Some(parent) = &self.parent else {
8954 return self.get(name);
8955 };
8956 parent.get_at(depth - 1, name)
8957 }
8958
8959 fn get_resolved(&self, depth: Option<usize>, name: &str) -> Result<Value> {
8960 match depth {
8961 Some(depth) => self.get_at(depth, name).or_else(|_| self.get(name)),
8962 None => self.get(name),
8963 }
8964 }
8965
8966 fn get_optional(&self, name: &str) -> Option<Value> {
8967 if let Some(binding) = self.bindings.borrow().get(name) {
8968 return Some(binding.value.clone());
8969 }
8970 self.parent
8971 .as_ref()
8972 .and_then(|parent| parent.get_optional(name))
8973 }
8974
8975 fn get_here(&self, name: &str) -> Option<Value> {
8976 self.bindings
8977 .borrow()
8978 .get(name)
8979 .map(|binding| binding.value.clone())
8980 }
8981
8982 fn find_binding(&self, name: &str) -> Option<Binding> {
8983 if let Some(binding) = self.bindings.borrow().get(name) {
8984 return Some(binding.clone());
8985 }
8986 self.parent
8987 .as_ref()
8988 .and_then(|parent| parent.find_binding(name))
8989 }
8990
8991 fn assign(&self, name: &str, value: Value) -> Result<()> {
8992 self.assign_with_weak_write(name, value, false)
8993 }
8994
8995 fn assign_with_weak_write(&self, name: &str, value: Value, weak_write: bool) -> Result<()> {
8996 let mut bindings = self.bindings.borrow_mut();
8997 if let Some(binding) = bindings.get_mut(name) {
8998 if !binding.mutable {
8999 return Err(ZuzuRustError::runtime(format!(
9000 "cannot assign to immutable binding '{}'",
9001 name
9002 )));
9003 }
9004 binding.value = value.stored_with_weak_policy(binding.is_weak_storage || weak_write);
9005 return Ok(());
9006 }
9007 drop(bindings);
9008 if let Some(parent) = &self.parent {
9009 return parent.assign_with_weak_write(name, value, weak_write);
9010 }
9011 Err(ZuzuRustError::runtime(format!(
9012 "assignment to undeclared identifier '{}'",
9013 name
9014 )))
9015 }
9016
9017 fn assign_at_with_weak_write(
9018 &self,
9019 depth: usize,
9020 name: &str,
9021 value: Value,
9022 weak_write: bool,
9023 ) -> Result<()> {
9024 if depth == 0 {
9025 let mut bindings = self.bindings.borrow_mut();
9026 if let Some(binding) = bindings.get_mut(name) {
9027 if !binding.mutable {
9028 return Err(ZuzuRustError::runtime(format!(
9029 "cannot assign to immutable binding '{}'",
9030 name
9031 )));
9032 }
9033 binding.value =
9034 value.stored_with_weak_policy(binding.is_weak_storage || weak_write);
9035 return Ok(());
9036 }
9037 return Err(ZuzuRustError::runtime(format!(
9038 "assignment to undeclared identifier '{}'",
9039 name
9040 )));
9041 }
9042 let Some(parent) = &self.parent else {
9043 return self.assign_with_weak_write(name, value, weak_write);
9044 };
9045 parent.assign_at_with_weak_write(depth - 1, name, value, weak_write)
9046 }
9047
9048 fn assign_resolved(&self, depth: Option<usize>, name: &str, value: Value) -> Result<()> {
9049 self.assign_resolved_with_weak_write(depth, name, value, false)
9050 }
9051
9052 fn assign_resolved_with_weak_write(
9053 &self,
9054 depth: Option<usize>,
9055 name: &str,
9056 value: Value,
9057 weak_write: bool,
9058 ) -> Result<()> {
9059 match depth {
9060 Some(depth) => self
9061 .assign_at_with_weak_write(depth, name, value.clone(), weak_write)
9062 .or_else(|_| self.assign_with_weak_write(name, value, weak_write)),
9063 None => self.assign_with_weak_write(name, value, weak_write),
9064 }
9065 }
9066
9067 fn refresh_existing_binding(&self, name: &str, value: Value) -> bool {
9068 let mut bindings = self.bindings.borrow_mut();
9069 if let Some(binding) = bindings.get_mut(name) {
9070 binding.value = value.stored_with_weak_policy(binding.is_weak_storage);
9071 return true;
9072 }
9073 drop(bindings);
9074 if let Some(parent) = &self.parent {
9075 return parent.refresh_existing_binding(name, value);
9076 }
9077 false
9078 }
9079
9080 fn export_public_aliases(&self, env: Rc<Environment>) -> HashMap<String, Value> {
9081 self.bindings
9082 .borrow()
9083 .iter()
9084 .filter(|(name, _)| !name.starts_with("__"))
9085 .map(|(name, binding)| {
9086 let value = if binding.mutable {
9087 Value::AliasRef(Rc::new(LvalueRef::Expression {
9088 env: Rc::clone(&env),
9089 target: Expression::Identifier {
9090 line: 0,
9091 source_file: None,
9092 name: name.clone(),
9093 inferred_type: None,
9094 binding_depth: None,
9095 },
9096 }))
9097 } else {
9098 binding.value.clone()
9099 };
9100 (name.clone(), value)
9101 })
9102 .collect()
9103 }
9104}
9105
9106impl Value {
9107 pub(in crate::runtime) fn builtin_class(name: impl Into<String>) -> Value {
9108 Value::Class(Rc::new(name.into()))
9109 }
9110
9111 pub(in crate::runtime) fn native_function(name: impl Into<String>) -> Value {
9112 Value::NativeFunction(Rc::new(name.into()))
9113 }
9114
9115 pub(in crate::runtime) fn stored_with_weak_policy(self, is_weak_storage: bool) -> Value {
9116 if is_weak_storage {
9117 let value = self
9118 .make_weak_value()
9119 .expect("weak storage conversion should not fail")
9120 .into_shared_if_composite();
9121 if value.is_weak_value() {
9122 value
9123 } else {
9124 Value::WeakStoredScalar(Box::new(value))
9125 }
9126 } else {
9127 self.into_shared_if_composite()
9128 }
9129 }
9130
9131 fn is_weak_value(&self) -> bool {
9132 matches!(
9133 self,
9134 Value::WeakFunction(_)
9135 | Value::WeakNativeFunction(_)
9136 | Value::WeakMethod(_)
9137 | Value::WeakIterator(_)
9138 | Value::WeakClass(_)
9139 | Value::WeakUserClass(_)
9140 | Value::WeakTrait(_)
9141 | Value::WeakObject(_)
9142 | Value::WeakTask(_)
9143 | Value::WeakChannel(_)
9144 | Value::WeakCancellationSource(_)
9145 | Value::WeakCancellationToken(_)
9146 | Value::WeakShared(_)
9147 | Value::WeakRef(_)
9148 | Value::WeakAliasRef(_)
9149 | Value::WeakStoredScalar(_)
9150 )
9151 }
9152
9153 fn into_shared_if_composite(self) -> Value {
9154 match self {
9155 Value::Shared(value) => Value::Shared(value),
9156 Value::Array(values) => Value::Shared(Rc::new(RefCell::new(Value::Array(
9157 values
9158 .into_iter()
9159 .map(Value::into_shared_if_composite)
9160 .collect(),
9161 )))),
9162 Value::SystemArray(_) => self,
9163 Value::Set(values) => Value::Shared(Rc::new(RefCell::new(Value::Set(
9164 values
9165 .into_iter()
9166 .map(Value::into_shared_if_composite)
9167 .collect(),
9168 )))),
9169 Value::Bag(values) => Value::Shared(Rc::new(RefCell::new(Value::Bag(
9170 values
9171 .into_iter()
9172 .map(Value::into_shared_if_composite)
9173 .collect(),
9174 )))),
9175 Value::Dict(values) => Value::Shared(Rc::new(RefCell::new(Value::Dict(
9176 values
9177 .into_iter()
9178 .map(|(key, value)| (key, value.into_shared_if_composite()))
9179 .collect(),
9180 )))),
9181 Value::SystemDict(_) => self,
9182 Value::PairList(values) => Value::Shared(Rc::new(RefCell::new(Value::PairList(
9183 values
9184 .into_iter()
9185 .map(|(key, value)| (key, value.into_shared_if_composite()))
9186 .collect(),
9187 )))),
9188 Value::Pair(key, value) => Value::Shared(Rc::new(RefCell::new(Value::Pair(
9189 key,
9190 Box::new((*value).into_shared_if_composite()),
9191 )))),
9192 other => other,
9193 }
9194 }
9195
9196 fn numeric_string_value(&self) -> Option<f64> {
9197 match self {
9198 Value::String(value) => value.parse::<f64>().ok(),
9199 _ => None,
9200 }
9201 }
9202
9203 fn is_numeric_comparable(&self) -> bool {
9204 matches!(self, Value::Null | Value::Boolean(_) | Value::Number(_))
9205 || self.numeric_string_value().is_some()
9206 }
9207
9208 fn scalar_type_name(&self) -> Option<&'static str> {
9209 match self {
9210 Value::Null => Some("Null"),
9211 Value::Boolean(_) => Some("Boolean"),
9212 Value::Number(_) => Some("Number"),
9213 Value::String(_) => Some("String"),
9214 Value::BinaryString(_) => Some("BinaryString"),
9215 Value::Regex(_, _) => Some("Regexp"),
9216 Value::Shared(value) => value.borrow().scalar_type_name(),
9217 _ => None,
9218 }
9219 }
9220
9221 #[allow(dead_code)]
9222 fn is_weakable_value(&self) -> bool {
9223 if self.is_weak_value() {
9224 return true;
9225 }
9226 self.scalar_type_name().is_none()
9227 }
9228
9229 #[allow(dead_code)]
9230 fn make_weak_value(&self) -> Result<Value> {
9231 if !self.is_weakable_value() {
9232 return Ok(self.clone());
9233 }
9234 let value = self.clone().into_shared_if_composite();
9235 Ok(match value {
9236 Value::Function(value) => Value::WeakFunction(Rc::downgrade(&value)),
9237 Value::NativeFunction(value) => Value::WeakNativeFunction(Rc::downgrade(&value)),
9238 Value::Method(value) => Value::WeakMethod(Rc::downgrade(&value)),
9239 Value::Iterator(value) => Value::WeakIterator(Rc::downgrade(&value)),
9240 Value::Class(value) => Value::WeakClass(Rc::downgrade(&value)),
9241 Value::UserClass(value) => Value::WeakUserClass(Rc::downgrade(&value)),
9242 Value::Trait(value) => Value::WeakTrait(Rc::downgrade(&value)),
9243 Value::Object(value) => Value::WeakObject(Rc::downgrade(&value)),
9244 Value::Task(value) => Value::WeakTask(Rc::downgrade(&value)),
9245 Value::Channel(value) => Value::WeakChannel(Rc::downgrade(&value)),
9246 Value::CancellationSource(value) => {
9247 Value::WeakCancellationSource(Rc::downgrade(&value))
9248 }
9249 Value::CancellationToken(value) => Value::WeakCancellationToken(Rc::downgrade(&value)),
9250 Value::Shared(value) => Value::WeakShared(Rc::downgrade(&value)),
9251 Value::Ref(value) => Value::WeakRef(Rc::downgrade(&value)),
9252 Value::AliasRef(value) => Value::WeakAliasRef(Rc::downgrade(&value)),
9253 value if value.is_weak_value() => value,
9254 scalar => scalar,
9255 })
9256 }
9257
9258 #[allow(dead_code)]
9259 fn resolve_weak_value(&self) -> Value {
9260 match self {
9261 Value::WeakFunction(value) => {
9262 value.upgrade().map(Value::Function).unwrap_or(Value::Null)
9263 }
9264 Value::WeakNativeFunction(value) => value
9265 .upgrade()
9266 .map(Value::NativeFunction)
9267 .unwrap_or(Value::Null),
9268 Value::WeakMethod(value) => value.upgrade().map(Value::Method).unwrap_or(Value::Null),
9269 Value::WeakIterator(value) => {
9270 value.upgrade().map(Value::Iterator).unwrap_or(Value::Null)
9271 }
9272 Value::WeakClass(value) => value.upgrade().map(Value::Class).unwrap_or(Value::Null),
9273 Value::WeakUserClass(value) => {
9274 value.upgrade().map(Value::UserClass).unwrap_or(Value::Null)
9275 }
9276 Value::WeakTrait(value) => value.upgrade().map(Value::Trait).unwrap_or(Value::Null),
9277 Value::WeakObject(value) => value.upgrade().map(Value::Object).unwrap_or(Value::Null),
9278 Value::WeakTask(value) => value.upgrade().map(Value::Task).unwrap_or(Value::Null),
9279 Value::WeakChannel(value) => value.upgrade().map(Value::Channel).unwrap_or(Value::Null),
9280 Value::WeakCancellationSource(value) => value
9281 .upgrade()
9282 .map(Value::CancellationSource)
9283 .unwrap_or(Value::Null),
9284 Value::WeakCancellationToken(value) => value
9285 .upgrade()
9286 .map(Value::CancellationToken)
9287 .unwrap_or(Value::Null),
9288 Value::WeakShared(value) => value.upgrade().map(Value::Shared).unwrap_or(Value::Null),
9289 Value::WeakRef(value) => value.upgrade().map(Value::Ref).unwrap_or(Value::Null),
9290 Value::WeakAliasRef(value) => {
9291 value.upgrade().map(Value::AliasRef).unwrap_or(Value::Null)
9292 }
9293 Value::WeakStoredScalar(value) => (**value).clone(),
9294 value => value.clone(),
9295 }
9296 }
9297
9298 fn is_truthy(&self) -> bool {
9299 if self.is_weak_value() {
9300 return self.resolve_weak_value().is_truthy();
9301 }
9302 match self {
9303 Value::Shared(value) => value.borrow().is_truthy(),
9304 Value::Null => false,
9305 Value::Boolean(value) => *value,
9306 Value::Number(value) => *value != 0.0,
9307 Value::String(value) => !value.is_empty(),
9308 Value::BinaryString(bytes) => !bytes.is_empty(),
9309 Value::Regex(_, _) => true,
9310 Value::Array(values) | Value::SystemArray(values) => !values.is_empty(),
9311 Value::Set(values) => !values.is_empty(),
9312 Value::Bag(values) => !values.is_empty(),
9313 Value::Dict(values) | Value::SystemDict(values) => !values.is_empty(),
9314 Value::PairList(values) => !values.is_empty(),
9315 Value::Pair(_, _)
9316 | Value::Function(_)
9317 | Value::NativeFunction(_)
9318 | Value::Method(_)
9319 | Value::Iterator(_)
9320 | Value::Class(_)
9321 | Value::UserClass(_)
9322 | Value::Trait(_)
9323 | Value::Object(_)
9324 | Value::Task(_)
9325 | Value::Channel(_)
9326 | Value::CancellationSource(_)
9327 | Value::CancellationToken(_)
9328 | Value::Ref(_)
9329 | Value::AliasRef(_) => true,
9330 _ => unreachable!("weak cases handled above"),
9331 }
9332 }
9333
9334 fn to_number(&self) -> Result<f64> {
9335 if self.is_weak_value() {
9336 return self.resolve_weak_value().to_number();
9337 }
9338 match self {
9339 Value::Shared(value) => value.borrow().to_number(),
9340 Value::Null => Ok(0.0),
9341 Value::Number(value) => Ok(*value),
9342 Value::Boolean(true) => Ok(1.0),
9343 Value::Boolean(false) => Ok(0.0),
9344 Value::String(value) => {
9345 let trimmed = value.trim();
9348 let unsigned = trimmed.strip_prefix(['+', '-']).unwrap_or(trimmed);
9349 let radix = match unsigned.get(..2) {
9350 Some("0x") | Some("0X") => Some(16),
9351 Some("0b") | Some("0B") => Some(2),
9352 Some("0o") | Some("0O") => Some(8),
9353 _ => None,
9354 };
9355 if let Some(radix) = radix {
9356 return u128::from_str_radix(&unsigned[2..], radix)
9357 .map(|parsed| {
9358 let magnitude = parsed as f64;
9359 if trimmed.starts_with('-') {
9360 -magnitude
9361 } else {
9362 magnitude
9363 }
9364 })
9365 .map_err(|_| {
9366 ZuzuRustError::runtime(format!("cannot coerce '{}' to Number", value))
9367 });
9368 }
9369 trimmed.parse::<f64>().map_err(|_| {
9370 ZuzuRustError::runtime(format!("cannot coerce '{}' to Number", value))
9371 })
9372 }
9373 _ => Err(ZuzuRustError::runtime("value cannot be coerced to Number")),
9374 }
9375 }
9376
9377 fn render(&self) -> String {
9378 if self.is_weak_value() {
9379 return self.resolve_weak_value().render();
9380 }
9381 match self {
9382 Value::Shared(value) => value.borrow().render(),
9383 Value::Null => "".to_owned(),
9384 Value::Boolean(true) => "true".to_owned(),
9385 Value::Boolean(false) => "false".to_owned(),
9386 Value::Number(value) => render_number(*value),
9387 Value::String(value) => value.clone(),
9388 Value::BinaryString(bytes) => String::from_utf8_lossy(bytes).into_owned(),
9389 Value::Regex(pattern, _) => pattern.clone(),
9390 Value::Array(values) | Value::SystemArray(values) => {
9391 let parts = values.iter().map(Value::render).collect::<Vec<_>>();
9392 format!("[{}]", parts.join(", "))
9393 }
9394 Value::Set(values) => {
9395 let parts = values.iter().map(Value::render).collect::<Vec<_>>();
9396 format!("<< {} >>", parts.join(", "))
9397 }
9398 Value::Bag(values) => {
9399 let parts = values.iter().map(Value::render).collect::<Vec<_>>();
9400 format!("<<< {} >>>", parts.join(", "))
9401 }
9402 Value::Dict(values) | Value::SystemDict(values) => {
9403 let mut parts = values
9404 .iter()
9405 .map(|(key, value)| format!("{key}: {}", value.render()))
9406 .collect::<Vec<_>>();
9407 parts.sort();
9408 format!("{{{}}}", parts.join(", "))
9409 }
9410 Value::PairList(values) => {
9411 let parts = values
9412 .iter()
9413 .map(|(key, value)| format!("{key}: {}", value.render()))
9414 .collect::<Vec<_>>();
9415 format!("{{{{{}}}}}", parts.join(", "))
9416 }
9417 Value::Pair(key, value) => format!("new Pair(pair:[\"{}\",{}])", key, value.render()),
9418 Value::Function(_) => "<Function>".to_owned(),
9419 Value::NativeFunction(name) => format!("<NativeFunction {}>", name.as_str()),
9420 Value::Method(method) => method.name.clone(),
9421 Value::Iterator(_) => "<Iterator>".to_owned(),
9422 Value::Class(name) => format!("<Class {}>", name.as_str()),
9423 Value::UserClass(class) => format!("<Class {}>", class.name),
9424 Value::Trait(trait_value) => format!("<Trait {}>", trait_value.name),
9425 Value::Object(object) => format!("<{} instance>", object.borrow().class.name),
9426 Value::Task(_) => "<Task>".to_owned(),
9427 Value::Channel(_) => "<Channel>".to_owned(),
9428 Value::CancellationSource(_) => "<CancellationSource>".to_owned(),
9429 Value::CancellationToken(_) => "<CancellationToken>".to_owned(),
9430 Value::Ref(_) | Value::AliasRef(_) => "<Ref>".to_owned(),
9431 _ => unreachable!("weak cases handled above"),
9432 }
9433 }
9434
9435 fn type_name(&self) -> &'static str {
9436 if self.is_weak_value() {
9437 return self.resolve_weak_value().type_name();
9438 }
9439 if let Some(name) = self.scalar_type_name() {
9440 return name;
9441 }
9442 match self {
9443 Value::Shared(value) => value.borrow().type_name(),
9444 Value::Array(_) | Value::SystemArray(_) => "Array",
9445 Value::Set(_) => "Set",
9446 Value::Bag(_) => "Bag",
9447 Value::Dict(_) | Value::SystemDict(_) => "Dict",
9448 Value::PairList(_) => "PairList",
9449 Value::Pair(_, _) => "Pair",
9450 Value::Method(_) => "Method",
9451 Value::Function(_) | Value::NativeFunction(_) | Value::Iterator(_) => "Function",
9452 Value::Class(_) | Value::UserClass(_) => "Class",
9453 Value::Trait(_) => "Trait",
9454 Value::Object(_) => "Object",
9455 Value::Task(_) => "Task",
9456 Value::Channel(_) => "Channel",
9457 Value::CancellationSource(_) => "CancellationSource",
9458 Value::CancellationToken(_) => "CancellationToken",
9459 Value::Ref(_) | Value::AliasRef(_) => "Ref",
9460 Value::Null
9461 | Value::Boolean(_)
9462 | Value::Number(_)
9463 | Value::String(_)
9464 | Value::BinaryString(_)
9465 | Value::Regex(_, _) => {
9466 unreachable!("scalar cases handled above")
9467 }
9468 _ => unreachable!("weak cases handled above"),
9469 }
9470 }
9471
9472 fn strict_eq(&self, other: &Value) -> bool {
9473 if self.is_weak_value() {
9474 return self.resolve_weak_value().strict_eq(other);
9475 }
9476 if other.is_weak_value() {
9477 return self.strict_eq(&other.resolve_weak_value());
9478 }
9479 match (self, other) {
9480 (Value::Shared(value), other) => return value.borrow().strict_eq(other),
9481 (this, Value::Shared(value)) => return this.strict_eq(&value.borrow()),
9482 _ => {}
9483 }
9484 match (self, other) {
9485 (Value::Null, Value::Null) => return true,
9486 (Value::Boolean(a), Value::Boolean(b)) => return a == b,
9487 (Value::Number(a), Value::Number(b)) => return a == b,
9488 (Value::String(a), Value::String(b)) => return a == b,
9489 (Value::BinaryString(a), Value::BinaryString(b)) => return a == b,
9490 _ => {}
9491 }
9492 match (self, other) {
9493 (Value::Array(a) | Value::SystemArray(a), Value::Array(b) | Value::SystemArray(b)) => {
9494 sequence_eq(a, b)
9495 }
9496 (Value::Set(a), Value::Set(b)) => collection_items_eq(a, b),
9497 (Value::Bag(a), Value::Bag(b)) => bag_items_eq(a, b),
9498 (Value::Pair(a_key, a_value), Value::Pair(b_key, b_value)) => {
9499 a_key == b_key && a_value.strict_eq(b_value)
9500 }
9501 (Value::Regex(a_pattern, a_flags), Value::Regex(b_pattern, b_flags)) => {
9502 a_pattern == b_pattern && a_flags == b_flags
9503 }
9504 (Value::Class(a), Value::Class(b)) => a == b,
9505 (Value::UserClass(a), Value::UserClass(b)) => Rc::ptr_eq(a, b),
9506 (Value::Trait(a), Value::Trait(b)) => Rc::ptr_eq(a, b),
9507 (Value::Function(a), Value::Function(b)) => Rc::ptr_eq(a, b),
9508 (Value::NativeFunction(a), Value::NativeFunction(b)) => a == b,
9509 (Value::Method(a), Value::Method(b)) => Rc::ptr_eq(a, b),
9510 (Value::Iterator(a), Value::Iterator(b)) => Rc::ptr_eq(a, b),
9511 (Value::Object(a), Value::Object(b)) => Rc::ptr_eq(a, b),
9512 (Value::Task(a), Value::Task(b)) => Rc::ptr_eq(a, b),
9513 (Value::Channel(a), Value::Channel(b)) => Rc::ptr_eq(a, b),
9514 (Value::CancellationSource(a), Value::CancellationSource(b))
9515 | (Value::CancellationToken(a), Value::CancellationToken(b))
9516 | (Value::CancellationSource(a), Value::CancellationToken(b))
9517 | (Value::CancellationToken(a), Value::CancellationSource(b)) => Rc::ptr_eq(a, b),
9518 (Value::Ref(a), Value::Ref(b))
9519 | (Value::AliasRef(a), Value::AliasRef(b))
9520 | (Value::Ref(a), Value::AliasRef(b))
9521 | (Value::AliasRef(a), Value::Ref(b)) => Rc::ptr_eq(a, b),
9522 (Value::Dict(a) | Value::SystemDict(a), Value::Dict(b) | Value::SystemDict(b)) => {
9523 dict_eq(a, b)
9524 }
9525 (Value::PairList(a), Value::PairList(b)) => pairlist_eq(a, b),
9526 _ => false,
9527 }
9528 }
9529
9530 fn coerced_eq(&self, other: &Value) -> bool {
9531 if self.is_weak_value() {
9532 return self.resolve_weak_value().coerced_eq(other);
9533 }
9534 if other.is_weak_value() {
9535 return self.coerced_eq(&other.resolve_weak_value());
9536 }
9537 match (self, other) {
9538 (Value::Shared(value), other) => return value.borrow().coerced_eq(other),
9539 (this, Value::Shared(value)) => return this.coerced_eq(&value.borrow()),
9540 _ => {}
9541 }
9542 if self.strict_eq(other) {
9543 return true;
9544 }
9545 match (self, other) {
9546 (Value::Boolean(a), Value::Number(b)) => (*a as i32 as f64) == *b,
9547 (Value::Number(a), Value::Boolean(b)) => *a == (*b as i32 as f64),
9548 _ => false,
9549 }
9550 }
9551}
9552
9553#[allow(dead_code)]
9554impl SimpleRegex {
9555 fn parse(pattern: &str, case_insensitive: bool) -> Result<Self> {
9556 let chars: Vec<char> = pattern.chars().collect();
9557 let mut index = 0usize;
9558 let parts = Self::parse_parts(&chars, &mut index, false)?;
9559 Ok(Self {
9560 parts,
9561 case_insensitive,
9562 })
9563 }
9564
9565 fn parse_parts(chars: &[char], index: &mut usize, in_group: bool) -> Result<Vec<RegexPart>> {
9566 let mut parts = Vec::new();
9567 let mut literal = String::new();
9568 while *index < chars.len() {
9569 let ch = chars[*index];
9570 if in_group && ch == ')' {
9571 break;
9572 }
9573 match ch {
9574 '(' => {
9575 if !literal.is_empty() {
9576 parts.push(RegexPart::Literal(std::mem::take(&mut literal)));
9577 }
9578 *index += 1;
9579 let inner = Self::parse_parts(chars, index, true)?;
9580 if *index >= chars.len() || chars[*index] != ')' {
9581 return Err(ZuzuRustError::runtime("unsupported regexp pattern"));
9582 }
9583 parts.push(RegexPart::Group(inner));
9584 }
9585 '[' => {
9586 if !literal.is_empty() {
9587 parts.push(RegexPart::Literal(std::mem::take(&mut literal)));
9588 }
9589 let part = if chars.get(*index..(*index + 5))
9590 == Some(&['[', '0', '-', '9', ']'])
9591 {
9592 RegexPart::DigitClassPlus
9593 } else if chars.get(*index..(*index + 5)) == Some(&['[', 'a', '-', 'z', ']']) {
9594 RegexPart::LowerAlphaClassPlus
9595 } else {
9596 return Err(ZuzuRustError::runtime("unsupported regexp character class"));
9597 };
9598 *index += 4;
9599 if chars.get(*index + 1) == Some(&'+') {
9600 *index += 1;
9601 } else {
9602 return Err(ZuzuRustError::runtime("unsupported regexp quantifier"));
9603 }
9604 parts.push(part);
9605 }
9606 ')' => break,
9607 _ => literal.push(ch),
9608 }
9609 *index += 1;
9610 }
9611 if !literal.is_empty() {
9612 parts.push(RegexPart::Literal(literal));
9613 }
9614 Ok(parts)
9615 }
9616
9617 fn find(&self, text: &str, start: usize) -> Option<RegexMatch> {
9618 let chars: Vec<char> = text.chars().collect();
9619 for offset in start..=chars.len() {
9620 let mut captures = Vec::new();
9621 if let Some(end) = self.match_parts(&self.parts, &chars, offset, &mut captures) {
9622 let full: String = chars[offset..end].iter().collect();
9623 let mut groups = vec![full];
9624 groups.extend(captures);
9625 return Some(RegexMatch {
9626 start: offset,
9627 end,
9628 groups,
9629 });
9630 }
9631 }
9632 None
9633 }
9634
9635 fn match_parts(
9636 &self,
9637 parts: &[RegexPart],
9638 chars: &[char],
9639 pos: usize,
9640 captures: &mut Vec<String>,
9641 ) -> Option<usize> {
9642 if parts.is_empty() {
9643 return Some(pos);
9644 }
9645 match &parts[0] {
9646 RegexPart::Literal(text) => {
9647 let lit_chars: Vec<char> = text.chars().collect();
9648 if pos + lit_chars.len() > chars.len() {
9649 return None;
9650 }
9651 for (offset, ch) in lit_chars.iter().enumerate() {
9652 if !self.chars_equal(chars[pos + offset], *ch) {
9653 return None;
9654 }
9655 }
9656 self.match_parts(&parts[1..], chars, pos + lit_chars.len(), captures)
9657 }
9658 RegexPart::DigitClassPlus => {
9659 let mut end = pos;
9660 while end < chars.len() && chars[end].is_ascii_digit() {
9661 end += 1;
9662 }
9663 if end == pos {
9664 return None;
9665 }
9666 for candidate_end in (pos + 1..=end).rev() {
9667 let mut cloned = captures.clone();
9668 if let Some(rest_end) =
9669 self.match_parts(&parts[1..], chars, candidate_end, &mut cloned)
9670 {
9671 *captures = cloned;
9672 return Some(rest_end);
9673 }
9674 }
9675 None
9676 }
9677 RegexPart::LowerAlphaClassPlus => {
9678 let mut end = pos;
9679 while end < chars.len() && chars[end].is_ascii_lowercase() {
9680 end += 1;
9681 }
9682 if end == pos {
9683 return None;
9684 }
9685 for candidate_end in (pos + 1..=end).rev() {
9686 let mut cloned = captures.clone();
9687 if let Some(rest_end) =
9688 self.match_parts(&parts[1..], chars, candidate_end, &mut cloned)
9689 {
9690 *captures = cloned;
9691 return Some(rest_end);
9692 }
9693 }
9694 None
9695 }
9696 RegexPart::Group(inner) => {
9697 let mut inner_captures = captures.clone();
9698 let end = self.match_parts(inner, chars, pos, &mut inner_captures)?;
9699 let capture: String = chars[pos..end].iter().collect();
9700 inner_captures.push(capture);
9701 let rest_end = self.match_parts(&parts[1..], chars, end, &mut inner_captures)?;
9702 *captures = inner_captures;
9703 Some(rest_end)
9704 }
9705 }
9706 }
9707
9708 fn chars_equal(&self, left: char, right: char) -> bool {
9709 if self.case_insensitive {
9710 left.to_lowercase().to_string() == right.to_lowercase().to_string()
9711 } else {
9712 left == right
9713 }
9714 }
9715}
9716
9717impl fmt::Display for Value {
9718 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9719 write!(f, "{}", self.render())
9720 }
9721}
9722
9723fn is_path_operator(operator: &str) -> bool {
9724 matches!(operator, "@" | "@@" | "@?")
9725}
9726
9727fn render_number(value: f64) -> String {
9728 if value.fract() == 0.0 {
9729 if value >= i64::MIN as f64 && value <= i64::MAX as f64 {
9730 format!("{}", value as i64)
9731 } else {
9732 format!("{value:.0}")
9733 }
9734 } else {
9735 value.to_string()
9736 }
9737}
9738
9739#[cfg(test)]
9740mod weak_classification_tests {
9741 use super::*;
9742
9743 fn empty_env() -> Rc<Environment> {
9744 Rc::new(Environment {
9745 parent: None,
9746 bindings: RefCell::new(HashMap::new()),
9747 })
9748 }
9749
9750 fn empty_block() -> BlockStatement {
9751 BlockStatement {
9752 line: 0,
9753 source_file: None,
9754 statements: Vec::new(),
9755 needs_lexical_scope: false,
9756 }
9757 }
9758
9759 fn identifier_expr() -> Expression {
9760 Expression::Identifier {
9761 line: 0,
9762 source_file: None,
9763 name: "x".to_owned(),
9764 inferred_type: None,
9765 binding_depth: None,
9766 }
9767 }
9768
9769 fn method_value(env: Rc<Environment>) -> Rc<MethodValue> {
9770 Rc::new(MethodValue {
9771 name: "m".to_owned(),
9772 params: Vec::new(),
9773 return_type: None,
9774 body: empty_block(),
9775 env,
9776 is_static: false,
9777 is_async: false,
9778 is_bodyless: false,
9779 bound_receiver: None,
9780 bound_name: None,
9781 })
9782 }
9783
9784 fn user_class(env: Rc<Environment>) -> Rc<UserClassValue> {
9785 Rc::new(UserClassValue {
9786 name: "C".to_owned(),
9787 base: None,
9788 traits: Vec::new(),
9789 fields: Vec::new(),
9790 methods: HashMap::new(),
9791 static_methods: HashMap::new(),
9792 nested_classes: HashMap::new(),
9793 source_decl: None,
9794 closure_env: Some(env),
9795 })
9796 }
9797
9798 #[test]
9799 fn scalar_values_are_not_weakable() {
9800 let values = vec![
9801 Value::Null,
9802 Value::Boolean(true),
9803 Value::Number(42.0),
9804 Value::String("hello".to_owned()),
9805 Value::BinaryString(vec![1, 2, 3]),
9806 Value::Regex("x".to_owned(), "i".to_owned()),
9807 Value::Shared(Rc::new(RefCell::new(Value::String("shared".to_owned())))),
9808 ];
9809
9810 for value in values {
9811 assert!(
9812 !value.is_weakable_value(),
9813 "{} should not be weakable",
9814 value.type_name()
9815 );
9816 assert!(value.make_weak_value().is_ok());
9817 assert!(value.strict_eq(&value.resolve_weak_value()));
9818 }
9819 }
9820
9821 #[test]
9822 fn reference_capable_values_are_weakable() {
9823 let env = empty_env();
9824 let function = Rc::new(FunctionValue {
9825 name: Some("f".to_owned()),
9826 params: Vec::new(),
9827 return_type: None,
9828 body: Rc::new(RefCell::new(FunctionBody::Block(empty_block()))),
9829 env: Rc::clone(&env),
9830 is_async: false,
9831 current_method: None,
9832 });
9833 let method = method_value(Rc::clone(&env));
9834 let trait_value = Rc::new(TraitValue {
9835 name: "T".to_owned(),
9836 methods: HashMap::new(),
9837 source_decl: None,
9838 closure_env: Some(Rc::clone(&env)),
9839 });
9840 let class = user_class(Rc::clone(&env));
9841 let object = Rc::new(RefCell::new(ObjectValue {
9842 class: Rc::clone(&class),
9843 fields: HashMap::new(),
9844 weak_fields: HashSet::new(),
9845 builtin_value: None,
9846 }));
9847 let task = Rc::new(RefCell::new(TaskState {
9848 status: "pending".to_owned(),
9849 kind: TaskKind::Resolved,
9850 outcome: None,
9851 }));
9852 let channel = Rc::new(RefCell::new(ChannelState {
9853 messages: Vec::new(),
9854 closed: false,
9855 }));
9856 let cancellation = Rc::new(RefCell::new(CancellationState {
9857 cancelled: false,
9858 reason: Value::Null,
9859 watched: Vec::new(),
9860 }));
9861 let lvalue = Rc::new(LvalueRef::Expression {
9862 env: Rc::clone(&env),
9863 target: identifier_expr(),
9864 });
9865
9866 let values = vec![
9867 Value::Array(Vec::new()),
9868 Value::Set(Vec::new()),
9869 Value::Bag(Vec::new()),
9870 Value::Dict(HashMap::new()),
9871 Value::PairList(Vec::new()),
9872 Value::Pair("key".to_owned(), Box::new(Value::Null)),
9873 Value::Function(function),
9874 Value::native_function("native".to_owned()),
9875 Value::Method(method),
9876 Value::Iterator(Rc::new(RefCell::new(IteratorState {
9877 items: Vec::new(),
9878 index: 0,
9879 }))),
9880 Value::builtin_class("Builtin".to_owned()),
9881 Value::UserClass(class),
9882 Value::Trait(trait_value),
9883 Value::Object(object),
9884 Value::Task(task),
9885 Value::Channel(channel),
9886 Value::CancellationSource(Rc::clone(&cancellation)),
9887 Value::CancellationToken(cancellation),
9888 Value::Shared(Rc::new(RefCell::new(Value::Array(Vec::new())))),
9889 Value::Ref(Rc::clone(&lvalue)),
9890 Value::AliasRef(lvalue),
9891 ];
9892
9893 for value in values {
9894 assert!(
9895 value.is_weakable_value(),
9896 "{} should be weakable",
9897 value.type_name()
9898 );
9899 let weak = value.make_weak_value().expect("weak wrapping should work");
9900 assert!(
9901 weak.is_weak_value(),
9902 "{} should become weak",
9903 value.type_name()
9904 );
9905 assert_eq!(value.resolve_weak_value().type_name(), value.type_name());
9906 }
9907 }
9908
9909 #[test]
9910 fn live_weak_values_resolve_for_core_value_behaviour() {
9911 let env = empty_env();
9912 let class = user_class(Rc::clone(&env));
9913 let object = Rc::new(RefCell::new(ObjectValue {
9914 class: Rc::clone(&class),
9915 fields: HashMap::new(),
9916 weak_fields: HashSet::new(),
9917 builtin_value: None,
9918 }));
9919 let object_value = Value::Object(Rc::clone(&object));
9920 let weak_object = object_value.make_weak_value().unwrap();
9921
9922 assert!(weak_object.strict_eq(&object_value));
9923 assert_eq!(weak_object.type_name(), "Object");
9924 assert_eq!(weak_object.render(), "<C instance>");
9925 assert!(weak_object.is_truthy());
9926
9927 let class_value = Value::builtin_class("Array");
9928 let weak_class = class_value.make_weak_value().unwrap();
9929 assert!(weak_class.strict_eq(&class_value));
9930 assert_eq!(weak_class.type_name(), "Class");
9931
9932 let native_value = Value::native_function("ref_id");
9933 let weak_native = native_value.make_weak_value().unwrap();
9934 assert!(weak_native.strict_eq(&native_value));
9935 assert_eq!(weak_native.type_name(), "Function");
9936 }
9937
9938 #[test]
9939 fn dead_weak_values_resolve_to_null() {
9940 let weak_object = {
9941 let env = empty_env();
9942 let class = user_class(env);
9943 let object = Rc::new(RefCell::new(ObjectValue {
9944 class,
9945 fields: HashMap::new(),
9946 weak_fields: HashSet::new(),
9947 builtin_value: None,
9948 }));
9949 Value::Object(object).make_weak_value().unwrap()
9950 };
9951
9952 assert!(matches!(weak_object.resolve_weak_value(), Value::Null));
9953 assert_eq!(weak_object.type_name(), "Null");
9954 assert_eq!(weak_object.render(), "");
9955 assert!(!weak_object.is_truthy());
9956 }
9957
9958 #[test]
9959 fn weak_values_participate_in_collections_and_type_checks() {
9960 let runtime = Runtime::new(Vec::new());
9961 let strong_array = Value::Array(vec![Value::Number(1.0)]).into_shared_if_composite();
9962 let weak_array = strong_array.make_weak_value().unwrap();
9963
9964 assert!(Value::Array(vec![weak_array.clone()])
9965 .strict_eq(&Value::Array(vec![strong_array.clone()])));
9966 runtime
9967 .assert_declared_type(Some("Array"), &weak_array, "weak array")
9968 .unwrap();
9969 assert!(runtime.value_instanceof(&weak_array, &Value::builtin_class("Array")));
9970 }
9971
9972 #[test]
9973 fn live_weak_values_can_be_called_or_receive_methods() {
9974 let runtime = Runtime::new(Vec::new());
9975
9976 let class_value = Value::builtin_class("Array");
9977 let weak_class = class_value.make_weak_value().unwrap();
9978 let constructed = runtime
9979 .call_value(weak_class, vec![Value::Number(7.0)], Vec::new())
9980 .unwrap();
9981 assert!(constructed.strict_eq(&Value::Array(vec![Value::Number(7.0)])));
9982
9983 let env = empty_env();
9984 let class = user_class(env);
9985 let object = Value::Object(Rc::new(RefCell::new(ObjectValue {
9986 class,
9987 fields: HashMap::new(),
9988 weak_fields: HashSet::new(),
9989 builtin_value: None,
9990 })));
9991 let native_value = Value::native_function("ref_id");
9992 let weak_native = native_value.make_weak_value().unwrap();
9993 let ref_id = runtime
9994 .call_value(weak_native, vec![object], Vec::new())
9995 .unwrap();
9996 assert_eq!(ref_id.type_name(), "String");
9997
9998 let shared_array = Value::Array(vec![Value::Number(1.0)]).into_shared_if_composite();
9999 let mut weak_receiver = shared_array.make_weak_value().unwrap();
10000 let length = runtime
10001 .call_method_named(&mut weak_receiver, "length", &[], Vec::new())
10002 .unwrap();
10003 assert!(length.strict_eq(&Value::Number(1.0)));
10004 }
10005}
10006
10007fn push_unique(values: &mut Vec<Value>, value: Value) {
10008 if !values.iter().any(|existing| existing.strict_eq(&value)) {
10009 values.push(value);
10010 }
10011}
10012
10013fn exception_field_specs() -> Vec<FieldSpec> {
10014 ["message", "file", "line", "code"]
10015 .into_iter()
10016 .map(|name| FieldSpec {
10017 name: name.to_owned(),
10018 declared_type: None,
10019 mutable: true,
10020 accessors: Vec::new(),
10021 default_value: None,
10022 is_weak_storage: false,
10023 })
10024 .collect()
10025}
10026
10027fn is_builtin_exception_class(name: &str) -> bool {
10028 matches!(
10029 name,
10030 "BailOutException"
10031 | "TypeException"
10032 | "CancelledException"
10033 | "TimeoutException"
10034 | "ChannelClosedException"
10035 | "MarshallingException"
10036 | "UnmarshallingException"
10037 | "ExhaustedException"
10038 | "Exception"
10039 )
10040}
10041
10042fn inferred_exception_class(message: &str) -> Option<&'static str> {
10043 [
10044 "BailOutException",
10045 "TypeException",
10046 "CancelledException",
10047 "TimeoutException",
10048 "ChannelClosedException",
10049 "MarshallingException",
10050 "UnmarshallingException",
10051 "ExhaustedException",
10052 "Exception",
10053 ]
10054 .into_iter()
10055 .find(|class_name| {
10056 message == *class_name
10057 || message.starts_with(&format!("{class_name}:"))
10058 || (*class_name == "BailOutException" && message.starts_with("Bail out!"))
10059 })
10060}
10061
10062fn sequence_eq(left: &[Value], right: &[Value]) -> bool {
10063 left.len() == right.len()
10064 && left
10065 .iter()
10066 .zip(right.iter())
10067 .all(|(left, right)| left.strict_eq(right))
10068}
10069
10070fn collection_items_eq(left: &[Value], right: &[Value]) -> bool {
10071 left.len() == right.len()
10072 && left
10073 .iter()
10074 .all(|item| right.iter().any(|other| other.strict_eq(item)))
10075}
10076
10077fn bag_items_eq(left: &[Value], right: &[Value]) -> bool {
10078 if left.len() != right.len() {
10079 return false;
10080 }
10081 let mut used = vec![false; right.len()];
10082 for item in left {
10083 let mut matched = false;
10084 for (index, candidate) in right.iter().enumerate() {
10085 if !used[index] && candidate.strict_eq(item) {
10086 used[index] = true;
10087 matched = true;
10088 break;
10089 }
10090 }
10091 if !matched {
10092 return false;
10093 }
10094 }
10095 true
10096}
10097
10098fn resolve_index(len: usize, index: isize) -> Option<usize> {
10099 let len = len as isize;
10100 let resolved = if index < 0 { len + index } else { index };
10101 if (0..len).contains(&resolved) {
10102 Some(resolved as usize)
10103 } else {
10104 None
10105 }
10106}
10107
10108fn replace_char_range(
10109 text: &str,
10110 from: usize,
10111 to: usize,
10112 replacement: impl IntoIterator<Item = char>,
10113) -> String {
10114 let mut chars = text.chars().collect::<Vec<_>>();
10115 chars.splice(from..to, replacement);
10116 chars.into_iter().collect()
10117}
10118
10119fn dict_eq(left: &HashMap<String, Value>, right: &HashMap<String, Value>) -> bool {
10120 left.len() == right.len()
10121 && left.iter().all(|(key, value)| {
10122 right
10123 .get(key)
10124 .map(|other| other.strict_eq(value))
10125 .unwrap_or(false)
10126 })
10127}
10128
10129fn child_tasks_of(task: &Rc<RefCell<TaskState>>) -> Vec<Rc<RefCell<TaskState>>> {
10130 let state = task.borrow();
10131 match &state.kind {
10132 TaskKind::All { tasks } | TaskKind::Race { tasks } => tasks
10133 .iter()
10134 .filter_map(|value| match value {
10135 Value::Task(task) => Some(Rc::clone(task)),
10136 _ => None,
10137 })
10138 .collect(),
10139 TaskKind::Timeout {
10140 task: Value::Task(task),
10141 ..
10142 } => vec![Rc::clone(task)],
10143 TaskKind::FunctionWaiting { awaited, .. } => vec![Rc::clone(awaited)],
10144 TaskKind::SpawnWaiting { awaited, .. } => vec![Rc::clone(awaited)],
10145 _ => Vec::new(),
10146 }
10147}
10148
10149fn earliest_deadline(left: Option<Instant>, right: Option<Instant>) -> Option<Instant> {
10150 match (left, right) {
10151 (Some(left), Some(right)) => Some(left.min(right)),
10152 (Some(deadline), None) | (None, Some(deadline)) => Some(deadline),
10153 (None, None) => None,
10154 }
10155}
10156
10157async fn drive_scheduled_task(runtime: Weak<RuntimeInner>, task: Rc<RefCell<TaskState>>) {
10158 loop {
10159 let Some(inner) = runtime.upgrade() else {
10160 break;
10161 };
10162 let runtime = Runtime { inner };
10163 if task.borrow().outcome.is_some() {
10164 break;
10165 }
10166
10167 match runtime.poll_task(&task) {
10168 Ok(true) => break,
10169 Ok(false) => {}
10170 Err(err) => {
10171 let mut state = task.borrow_mut();
10172 if state.outcome.is_none() {
10173 state.status = "rejected".to_owned();
10174 state.outcome = Some(TaskOutcome::Rejected(err.to_string()));
10175 }
10176 break;
10177 }
10178 }
10179
10180 let deadline = runtime.next_task_deadline(&task);
10181 drop(runtime);
10182 match deadline {
10183 Some(deadline) if deadline > Instant::now() => {
10184 tokio::time::sleep_until(tokio::time::Instant::from_std(deadline)).await;
10185 }
10186 Some(_) => {
10187 tokio::task::yield_now().await;
10188 }
10189 None => {
10190 tokio::time::sleep(Duration::from_millis(1)).await;
10191 }
10192 }
10193 }
10194}
10195
10196async fn drive_native_async_task<F>(task: Rc<RefCell<TaskState>>, future: F)
10197where
10198 F: Future<Output = Result<Value>>,
10199{
10200 {
10201 let mut state = task.borrow_mut();
10202 if state.outcome.is_none() {
10203 state.status = "running".to_owned();
10204 }
10205 }
10206
10207 let result = future.await;
10208 let mut state = task.borrow_mut();
10209 if state.outcome.is_some() {
10210 return;
10211 }
10212
10213 let outcome = match result {
10214 Ok(value) => TaskOutcome::Fulfilled(value),
10215 Err(ZuzuRustError::Thrown { value, .. }) => TaskOutcome::Rejected(value),
10216 Err(err) => TaskOutcome::Rejected(err.to_string()),
10217 };
10218 state.status = match &outcome {
10219 TaskOutcome::Fulfilled(_) => "fulfilled",
10220 TaskOutcome::Rejected(_) => "rejected",
10221 TaskOutcome::Cancelled(_) => "cancelled",
10222 }
10223 .to_owned();
10224 state.outcome = Some(outcome);
10225}
10226
10227fn async_frames_of(task: &Rc<RefCell<TaskState>>) -> Option<Vec<AsyncFrame>> {
10228 let state = task.borrow();
10229 match &state.kind {
10230 TaskKind::FunctionWaiting { frames, .. } | TaskKind::SpawnWaiting { frames, .. } => {
10231 Some(frames.clone())
10232 }
10233 _ => None,
10234 }
10235}
10236
10237struct PollTaskGuard<'a> {
10238 stack: &'a RefCell<Vec<usize>>,
10239 task_id: usize,
10240}
10241
10242impl Drop for PollTaskGuard<'_> {
10243 fn drop(&mut self) {
10244 let mut stack = self.stack.borrow_mut();
10245 if stack.last() == Some(&self.task_id) {
10246 stack.pop();
10247 } else if let Some(index) = stack.iter().rposition(|id| *id == self.task_id) {
10248 stack.remove(index);
10249 }
10250 }
10251}
10252
10253impl AsyncFrame {
10254 fn statement_count(&self) -> usize {
10255 match self {
10256 AsyncFrame::Function { statements, .. }
10257 | AsyncFrame::Block { statements, .. }
10258 | AsyncFrame::Do { statements, .. } => statements.len(),
10259 }
10260 }
10261
10262 fn index(&self) -> usize {
10263 match self {
10264 AsyncFrame::Function { index, .. }
10265 | AsyncFrame::Block { index, .. }
10266 | AsyncFrame::Do { index, .. } => *index,
10267 }
10268 }
10269
10270 fn advance(&mut self) {
10271 match self {
10272 AsyncFrame::Function { index, .. }
10273 | AsyncFrame::Block { index, .. }
10274 | AsyncFrame::Do { index, .. } => {
10275 *index += 1;
10276 }
10277 }
10278 }
10279
10280 fn is_complete(&self) -> bool {
10281 self.index() >= self.statement_count()
10282 }
10283
10284 fn env(&self) -> Rc<Environment> {
10285 match self {
10286 AsyncFrame::Function { env, .. }
10287 | AsyncFrame::Block { env, .. }
10288 | AsyncFrame::Do { env, .. } => Rc::clone(env),
10289 }
10290 }
10291
10292 fn set_last(&mut self, value: Value) {
10293 if let AsyncFrame::Do { last, .. } = self {
10294 *last = value;
10295 }
10296 }
10297
10298 fn current_statement(&self) -> &Statement {
10299 match self {
10300 AsyncFrame::Function {
10301 statements, index, ..
10302 }
10303 | AsyncFrame::Block {
10304 statements, index, ..
10305 }
10306 | AsyncFrame::Do {
10307 statements, index, ..
10308 } => &statements[*index],
10309 }
10310 }
10311}