1use indexmap::IndexMap;
4
5use crate::bytecode::{Chunk, Op};
6use crate::env::Env;
7use crate::error::IonError;
8use crate::host_types::TypeRegistry;
9use crate::stdlib::{OutputHandler, OutputStream};
10use crate::value::Value;
11use std::sync::Arc;
12
13#[derive(Debug, Clone)]
15struct LocalSlot {
16 value: Value,
17 mutable: bool,
18}
19
20#[derive(Debug, Clone)]
22struct ExceptionHandler {
23 catch_ip: usize,
25 stack_depth: usize,
27 local_frames_depth: usize,
29 locals_depth: usize,
31}
32
33pub struct Vm {
35 stack: Vec<Value>,
37 env: Env,
39 ip: usize,
41 iterators: Vec<Box<dyn Iterator<Item = Value>>>,
43 fn_cache: std::collections::HashMap<u64, crate::bytecode::Chunk>,
45 pending_tail_call: Option<(Value, Vec<Value>)>,
47 locals: Vec<LocalSlot>,
49 local_frames: Vec<usize>,
51 locals_base: usize,
53 types: TypeRegistry,
55 exception_handlers: Vec<ExceptionHandler>,
57 output: Arc<dyn OutputHandler>,
59}
60
61impl Default for Vm {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl Vm {
68 pub fn new() -> Self {
69 Self {
70 stack: Vec::with_capacity(256),
71 env: Env::new(),
72 ip: 0,
73 iterators: Vec::new(),
74 fn_cache: std::collections::HashMap::new(),
75 pending_tail_call: None,
76 locals: Vec::with_capacity(64),
77 local_frames: Vec::with_capacity(16),
78 locals_base: 0,
79 types: TypeRegistry::default(),
80 exception_handlers: Vec::new(),
81 output: crate::stdlib::missing_output_handler(),
82 }
83 }
84
85 pub fn with_env(env: Env) -> Self {
87 Self::with_env_and_output(env, crate::stdlib::missing_output_handler())
88 }
89
90 pub fn with_env_and_output(env: Env, output: Arc<dyn OutputHandler>) -> Self {
92 Self {
93 stack: Vec::with_capacity(256),
94 env,
95 ip: 0,
96 iterators: Vec::new(),
97 fn_cache: std::collections::HashMap::new(),
98 pending_tail_call: None,
99 locals: Vec::with_capacity(64),
100 local_frames: Vec::with_capacity(16),
101 locals_base: 0,
102 types: TypeRegistry::default(),
103 exception_handlers: Vec::new(),
104 output,
105 }
106 }
107
108 pub fn set_output_handler(&mut self, output: Arc<dyn OutputHandler>) {
110 self.output = output;
111 }
112
113 pub fn set_types(&mut self, types: TypeRegistry) {
115 self.types = types;
116 }
117
118 pub fn env(&self) -> &Env {
120 &self.env
121 }
122
123 pub fn env_mut(&mut self) -> &mut Env {
125 &mut self.env
126 }
127
128 pub fn preload_fn_chunks(&mut self, chunks: crate::value::FnChunkCache) {
130 self.fn_cache.extend(chunks);
131 }
132
133 pub fn execute(&mut self, chunk: &Chunk) -> Result<Value, IonError> {
135 self.ip = 0;
136 self.stack.clear();
137 match self.run_chunk(chunk) {
138 Ok(v) => Ok(v),
139 Err(e) if e.kind == crate::error::ErrorKind::PropagatedErr => {
140 Ok(Value::Result(Err(Box::new(Value::Str(e.message.clone())))))
141 }
142 Err(e) if e.kind == crate::error::ErrorKind::PropagatedNone => Ok(Value::Option(None)),
143 Err(e) => Err(e),
144 }
145 }
146
147 fn run_chunk(&mut self, chunk: &Chunk) -> Result<Value, IonError> {
149 while self.ip < chunk.code.len() {
150 let op_byte = chunk.code[self.ip];
151 let line = chunk.lines[self.ip];
152 let col = chunk.cols[self.ip];
153 self.ip += 1;
154
155 let op = match self.decode_op(op_byte, line, col) {
156 Ok(op) => op,
157 Err(e) => {
158 if let Some(handler) = self.exception_handlers.pop() {
159 self.stack.truncate(handler.stack_depth);
160 self.locals.truncate(handler.locals_depth);
161 self.local_frames.truncate(handler.local_frames_depth);
162 self.stack.push(Value::Str(e.message.clone()));
163 self.ip = handler.catch_ip;
164 continue;
165 }
166 return Err(e);
167 }
168 };
169
170 match op {
172 Op::TryBegin => {
173 let offset = chunk.read_u16(self.ip) as usize;
174 self.ip += 2;
175 let catch_ip = self.ip + offset;
176 self.exception_handlers.push(ExceptionHandler {
177 catch_ip,
178 stack_depth: self.stack.len(),
179 local_frames_depth: self.local_frames.len(),
180 locals_depth: self.locals.len(),
181 });
182 continue;
183 }
184 Op::TryEnd => {
185 let offset = chunk.read_u16(self.ip) as usize;
186 self.ip += 2;
187 self.exception_handlers.pop();
188 self.ip += offset; continue;
190 }
191 _ => {}
192 }
193
194 match self.dispatch_instruction(op, chunk, line, col) {
195 Ok(Some(val)) => return Ok(val),
196 Ok(None) => {}
197 Err(e) => {
198 if e.kind != crate::error::ErrorKind::PropagatedErr
200 && e.kind != crate::error::ErrorKind::PropagatedNone
201 {
202 if let Some(handler) = self.exception_handlers.pop() {
203 self.stack.truncate(handler.stack_depth);
204 self.locals.truncate(handler.locals_depth);
205 self.local_frames.truncate(handler.local_frames_depth);
206 self.stack.push(Value::Str(e.message.clone()));
207 self.ip = handler.catch_ip;
208 continue;
209 }
210 }
211 return Err(e);
212 }
213 }
214 }
215 Ok(self.stack.pop().unwrap_or(Value::Unit))
216 }
217
218 fn dispatch_instruction(
220 &mut self,
221 op: Op,
222 chunk: &Chunk,
223 line: usize,
224 col: usize,
225 ) -> Result<Option<Value>, IonError> {
226 match op {
227 Op::Constant => {
228 let idx = chunk.read_u16(self.ip) as usize;
229 self.ip += 2;
230 let val = chunk.constants[idx].clone();
231 self.stack.push(val);
232 }
233
234 Op::True => self.stack.push(Value::Bool(true)),
235 Op::False => self.stack.push(Value::Bool(false)),
236 Op::Unit => self.stack.push(Value::Unit),
237 Op::None => self.stack.push(Value::Option(None)),
238
239 Op::Add => {
241 let b = self.pop(line, col)?;
242 let a = self.pop(line, col)?;
243 self.stack.push(self.op_add(a, b, line, col)?);
244 }
245 Op::Sub => {
246 let b = self.pop(line, col)?;
247 let a = self.pop(line, col)?;
248 self.stack.push(self.op_sub(a, b, line, col)?);
249 }
250 Op::Mul => {
251 let b = self.pop(line, col)?;
252 let a = self.pop(line, col)?;
253 self.stack.push(self.op_mul(a, b, line, col)?);
254 }
255 Op::Div => {
256 let b = self.pop(line, col)?;
257 let a = self.pop(line, col)?;
258 self.stack.push(self.op_div(a, b, line, col)?);
259 }
260 Op::Mod => {
261 let b = self.pop(line, col)?;
262 let a = self.pop(line, col)?;
263 self.stack.push(self.op_mod(a, b, line, col)?);
264 }
265 Op::Neg => {
266 let val = self.pop(line, col)?;
267 self.stack.push(self.op_neg(val, line, col)?);
268 }
269
270 Op::BitAnd => {
272 let b = self.pop(line, col)?;
273 let a = self.pop(line, col)?;
274 match (a, b) {
275 (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x & y)),
276 (a, b) => {
277 return Err(IonError::type_err(
278 format!(
279 "{}{} and {}",
280 ion_str!("'&' expects int, got "),
281 a.type_name(),
282 b.type_name()
283 ),
284 line,
285 col,
286 ))
287 }
288 }
289 }
290 Op::BitOr => {
291 let b = self.pop(line, col)?;
292 let a = self.pop(line, col)?;
293 match (a, b) {
294 (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x | y)),
295 (a, b) => {
296 return Err(IonError::type_err(
297 format!(
298 "{}{} and {}",
299 ion_str!("'|' expects int, got "),
300 a.type_name(),
301 b.type_name()
302 ),
303 line,
304 col,
305 ))
306 }
307 }
308 }
309 Op::BitXor => {
310 let b = self.pop(line, col)?;
311 let a = self.pop(line, col)?;
312 match (a, b) {
313 (Value::Int(x), Value::Int(y)) => self.stack.push(Value::Int(x ^ y)),
314 (a, b) => {
315 return Err(IonError::type_err(
316 format!(
317 "{}{} and {}",
318 ion_str!("'^' expects int, got "),
319 a.type_name(),
320 b.type_name()
321 ),
322 line,
323 col,
324 ))
325 }
326 }
327 }
328 Op::Shl => {
329 let b = self.pop(line, col)?;
330 let a = self.pop(line, col)?;
331 match (a, b) {
332 (Value::Int(x), Value::Int(y)) if (0..64).contains(&y) => {
333 self.stack.push(Value::Int(x << y))
334 }
335 (Value::Int(_), Value::Int(y)) => {
336 return Err(IonError::runtime(
337 format!("shift count {} is out of range 0..64", y),
338 line,
339 col,
340 ))
341 }
342 (a, b) => {
343 return Err(IonError::type_err(
344 format!(
345 "{}{} and {}",
346 ion_str!("'<<' expects int, got "),
347 a.type_name(),
348 b.type_name()
349 ),
350 line,
351 col,
352 ))
353 }
354 }
355 }
356 Op::Shr => {
357 let b = self.pop(line, col)?;
358 let a = self.pop(line, col)?;
359 match (a, b) {
360 (Value::Int(x), Value::Int(y)) if (0..64).contains(&y) => {
361 self.stack.push(Value::Int(x >> y))
362 }
363 (Value::Int(_), Value::Int(y)) => {
364 return Err(IonError::runtime(
365 format!("shift count {} is out of range 0..64", y),
366 line,
367 col,
368 ))
369 }
370 (a, b) => {
371 return Err(IonError::type_err(
372 format!(
373 "{}{} and {}",
374 ion_str!("'>>' expects int, got "),
375 a.type_name(),
376 b.type_name()
377 ),
378 line,
379 col,
380 ))
381 }
382 }
383 }
384
385 Op::Eq => {
387 let b = self.pop(line, col)?;
388 let a = self.pop(line, col)?;
389 self.stack.push(Value::Bool(a == b));
390 }
391 Op::NotEq => {
392 let b = self.pop(line, col)?;
393 let a = self.pop(line, col)?;
394 self.stack.push(Value::Bool(a != b));
395 }
396 Op::Lt => {
397 let b = self.pop(line, col)?;
398 let a = self.pop(line, col)?;
399 self.stack
400 .push(Value::Bool(self.compare_lt(&a, &b, line, col)?));
401 }
402 Op::Gt => {
403 let b = self.pop(line, col)?;
404 let a = self.pop(line, col)?;
405 self.stack
406 .push(Value::Bool(self.compare_lt(&b, &a, line, col)?));
407 }
408 Op::LtEq => {
409 let b = self.pop(line, col)?;
410 let a = self.pop(line, col)?;
411 self.stack
412 .push(Value::Bool(!self.compare_lt(&b, &a, line, col)?));
413 }
414 Op::GtEq => {
415 let b = self.pop(line, col)?;
416 let a = self.pop(line, col)?;
417 self.stack
418 .push(Value::Bool(!self.compare_lt(&a, &b, line, col)?));
419 }
420
421 Op::Not => {
423 let val = self.pop(line, col)?;
424 self.stack.push(Value::Bool(!val.is_truthy()));
425 }
426 Op::And => {
427 let offset = chunk.read_u16(self.ip) as usize;
428 self.ip += 2;
429 if !self.is_top_truthy(line, col)? {
430 self.ip += offset; }
432 }
434 Op::Or => {
435 let offset = chunk.read_u16(self.ip) as usize;
436 self.ip += 2;
437 if self.is_top_truthy(line, col)? {
438 self.ip += offset; }
440 }
441
442 Op::DefineLocal => {
444 let name_idx = chunk.read_u16(self.ip) as usize;
445 self.ip += 2;
446 let mutable = chunk.read_u8(self.ip) != 0;
447 self.ip += 1;
448 let sym = self.const_to_sym(&chunk.constants[name_idx], line, col)?;
449 let val = self.pop(line, col)?;
450 self.env.define_sym(sym, val, mutable);
451 }
452 Op::GetLocal => {
453 let name_idx = chunk.read_u16(self.ip) as usize;
454 self.ip += 2;
455 let sym = self.const_to_sym(&chunk.constants[name_idx], line, col)?;
456 let val = self.env.get_sym(sym).cloned().ok_or_else(|| {
457 let name = self.env.resolve(sym);
458 IonError::name(
459 format!("{}{}", ion_str!("undefined variable: "), name),
460 line,
461 col,
462 )
463 })?;
464 self.stack.push(val);
465 }
466 Op::SetLocal => {
467 let name_idx = chunk.read_u16(self.ip) as usize;
468 self.ip += 2;
469 let sym = self.const_to_sym(&chunk.constants[name_idx], line, col)?;
470 let val = self.pop(line, col)?;
471 self.env
472 .set_sym(sym, val.clone())
473 .map_err(|e| IonError::runtime(e, line, col))?;
474 self.stack.push(val); }
476 Op::GetGlobal => {
477 let name_idx = chunk.read_u16(self.ip) as usize;
478 self.ip += 2;
479 let sym = self.const_to_sym(&chunk.constants[name_idx], line, col)?;
480 let val = self.env.get_sym(sym).cloned().ok_or_else(|| {
481 let name = self.env.resolve(sym);
482 IonError::name(
483 format!("{}{}", ion_str!("undefined variable: "), name),
484 line,
485 col,
486 )
487 })?;
488 self.stack.push(val);
489 }
490 Op::SetGlobal => {
491 let name_idx = chunk.read_u16(self.ip) as usize;
492 self.ip += 2;
493 let sym = self.const_to_sym(&chunk.constants[name_idx], line, col)?;
494 let val = self.pop(line, col)?;
495 self.env
496 .set_sym(sym, val.clone())
497 .map_err(|e| IonError::runtime(e, line, col))?;
498 self.stack.push(val);
499 }
500
501 Op::DefineLocalSlot => {
503 let mutable = chunk.read_u8(self.ip) != 0;
504 self.ip += 1;
505 let val = self.pop(line, col)?;
506 self.locals.push(LocalSlot {
507 value: val,
508 mutable,
509 });
510 }
511 Op::GetLocalSlot => {
512 let slot = self.locals_base + chunk.read_u16(self.ip) as usize;
513 self.ip += 2;
514 let val = self.locals[slot].value.clone();
515 self.stack.push(val);
516 }
517 Op::SetLocalSlot => {
518 let slot = self.locals_base + chunk.read_u16(self.ip) as usize;
519 self.ip += 2;
520 let val = self.pop(line, col)?;
521 if !self.locals[slot].mutable {
522 return Err(IonError::runtime(
523 ion_str!("cannot assign to immutable variable"),
524 line,
525 col,
526 ));
527 }
528 self.locals[slot].value = val.clone();
529 self.stack.push(val); }
531
532 Op::Jump => {
534 let offset = chunk.read_u16(self.ip) as usize;
535 self.ip += 2;
536 self.ip += offset;
537 }
538 Op::JumpIfFalse => {
539 let offset = chunk.read_u16(self.ip) as usize;
540 self.ip += 2;
541 if !self.is_top_truthy(line, col)? {
542 self.ip += offset;
543 }
544 }
545 Op::Loop => {
546 let offset = chunk.read_u16(self.ip) as usize;
547 self.ip += 2;
548 self.ip -= offset;
549 }
550
551 Op::Call => {
553 let arg_count = chunk.read_u8(self.ip) as usize;
554 self.ip += 1;
555 self.call_function(arg_count, line, col)?;
556 }
557 Op::CallNamed => {
558 let arg_count = chunk.read_u8(self.ip) as usize;
559 self.ip += 1;
560 let named_count = chunk.read_u8(self.ip) as usize;
561 self.ip += 1;
562 let mut named_map: Vec<(usize, String)> = Vec::with_capacity(named_count);
564 for _ in 0..named_count {
565 let pos = chunk.read_u8(self.ip) as usize;
566 self.ip += 1;
567 let name_idx = chunk.read_u16(self.ip) as usize;
568 self.ip += 2;
569 if let Value::Str(name) = &chunk.constants[name_idx] {
570 named_map.push((pos, name.clone()));
571 }
572 }
573 self.call_function_named(arg_count, &named_map, line, col)?;
574 }
575 Op::TailCall => {
576 let arg_count = chunk.read_u8(self.ip) as usize;
577 self.ip += 1;
578 let args_start = self.stack.len() - arg_count;
580 let func_idx = args_start - 1;
581 let func = self.stack[func_idx].clone();
582 let args: Vec<Value> = self.stack[args_start..].to_vec();
583 self.stack.truncate(func_idx);
584 self.pending_tail_call = Some((func, args));
585 return Ok(Some(Value::Unit)); }
587 Op::Return => {
588 let val = if self.stack.is_empty() {
590 Value::Unit
591 } else {
592 self.pop(line, col)?
593 };
594 return Ok(Some(val));
595 }
596
597 Op::Pop => {
599 self.pop(line, col)?;
600 }
601 Op::Dup => {
602 let val = self.peek(line, col)?;
603 self.stack.push(val);
604 }
605
606 Op::BuildList => {
608 let count = chunk.read_u16(self.ip) as usize;
609 self.ip += 2;
610 let start = self.stack.len() - count;
611 let items: Vec<Value> = self.stack.drain(start..).collect();
612 self.stack.push(Value::List(items));
613 }
614 Op::BuildTuple => {
615 let count = chunk.read_u16(self.ip) as usize;
616 self.ip += 2;
617 let start = self.stack.len() - count;
618 let items: Vec<Value> = self.stack.drain(start..).collect();
619 self.stack.push(Value::Tuple(items));
620 }
621 Op::BuildDict => {
622 let count = chunk.read_u16(self.ip) as usize;
623 self.ip += 2;
624 let mut map = IndexMap::new();
625 let start = self.stack.len() - count * 2;
627 let items: Vec<Value> = self.stack.drain(start..).collect();
628 for pair in items.chunks(2) {
629 let key = match &pair[0] {
630 Value::Str(s) => s.clone(),
631 other => other.to_string(),
632 };
633 map.insert(key, pair[1].clone());
634 }
635 self.stack.push(Value::Dict(map));
636 }
637
638 Op::GetField => {
640 let field_idx = chunk.read_u16(self.ip) as usize;
641 self.ip += 2;
642 let field = self.const_as_str(&chunk.constants[field_idx], line, col)?;
643 let obj = self.pop(line, col)?;
644 self.stack.push(self.get_field(obj, &field, line, col)?);
645 }
646 Op::GetIndex => {
647 let index = self.pop(line, col)?;
648 let obj = self.pop(line, col)?;
649 self.stack.push(self.get_index(obj, index, line, col)?);
650 }
651 Op::SetField => {
652 let field_idx = chunk.read_u16(self.ip) as usize;
653 self.ip += 2;
654 let field = self.const_as_str(&chunk.constants[field_idx], line, col)?;
655 let value = self.pop(line, col)?;
656 let obj = self.pop(line, col)?;
657 let result = self.set_field(obj, &field, value, line, col)?;
658 self.stack.push(result);
659 }
660 Op::SetIndex => {
661 let value = self.pop(line, col)?;
662 let index = self.pop(line, col)?;
663 let obj = self.pop(line, col)?;
664 let result = self.set_index(obj, index, value, line, col)?;
665 self.stack.push(result);
666 }
667 Op::MethodCall => {
668 let method_idx = chunk.read_u16(self.ip) as usize;
669 self.ip += 2;
670 let arg_count = chunk.read_u8(self.ip) as usize;
671 self.ip += 1;
672 let method = self.const_as_str(&chunk.constants[method_idx], line, col)?;
673 let start = self.stack.len() - arg_count;
675 let args: Vec<Value> = self.stack.drain(start..).collect();
676 let receiver = self.pop(line, col)?;
677 let result = self.call_method(receiver, &method, &args, line, col)?;
678 self.stack.push(result);
679 }
680
681 Op::Closure => {
683 let fn_idx = chunk.read_u16(self.ip) as usize;
684 self.ip += 2;
685 let val = chunk.constants[fn_idx].clone();
686 if let Value::Fn(mut f) = val {
688 f.captures = self.env.capture();
689 self.stack.push(Value::Fn(f));
690 } else {
691 self.stack.push(val);
692 }
693 }
694
695 Op::WrapSome => {
697 let val = self.pop(line, col)?;
698 self.stack.push(Value::Option(Some(Box::new(val))));
699 }
700 Op::WrapOk => {
701 let val = self.pop(line, col)?;
702 self.stack.push(Value::Result(Ok(Box::new(val))));
703 }
704 Op::WrapErr => {
705 let val = self.pop(line, col)?;
706 self.stack.push(Value::Result(Err(Box::new(val))));
707 }
708 Op::Try => {
709 let val = self.pop(line, col)?;
710 match val {
711 Value::Option(Some(v)) => self.stack.push(*v),
712 Value::Option(None) => {
713 return Err(IonError::propagated_none(line, 0));
714 }
715 Value::Result(Ok(v)) => self.stack.push(*v),
716 Value::Result(Err(e)) => {
717 return Err(IonError::propagated_err(e.to_string(), line, col));
718 }
719 other => {
720 return Err(IonError::type_err(
721 format!(
722 "{}{}",
723 ion_str!("? operator requires Option or Result, got "),
724 other.type_name()
725 ),
726 line,
727 col,
728 ));
729 }
730 }
731 }
732
733 Op::PushScope => {
735 self.env.push_scope();
736 self.local_frames.push(self.locals.len());
737 }
738 Op::PopScope => {
739 self.env.pop_scope();
740 if let Some(base) = self.local_frames.pop() {
741 self.locals.truncate(base);
742 }
743 }
744
745 Op::BuildFString => {
747 let count = chunk.read_u16(self.ip) as usize;
748 self.ip += 2;
749 let start = self.stack.len() - count;
750 let parts: Vec<Value> = self.stack.drain(start..).collect();
751 let mut s = String::with_capacity(count * 8);
752 for part in &parts {
753 use std::fmt::Write;
754 let _ = write!(s, "{}", part);
755 }
756 self.stack.push(Value::Str(s));
757 }
758
759 Op::Pipe => {
761 let _arg_count = chunk.read_u8(self.ip);
762 self.ip += 1;
763 return Err(IonError::runtime(
765 ion_str!("pipe opcode should not be executed directly"),
766 line,
767 col,
768 ));
769 }
770
771 Op::MatchBegin => {
773 let kind = chunk.read_u8(self.ip);
775 self.ip += 1;
776 let val = self.pop(line, col)?;
777 let result = match kind {
778 1 => matches!(val, Value::Option(Some(_))),
779 2 => matches!(val, Value::Result(Ok(_))),
780 3 => matches!(val, Value::Result(Err(_))),
781 4 => {
782 let expected_len = chunk.read_u8(self.ip) as usize;
783 self.ip += 1;
784 match &val {
785 Value::Tuple(items) => items.len() == expected_len,
786 _ => false,
787 }
788 }
789 5 => {
790 let min_len = chunk.read_u8(self.ip) as usize;
791 self.ip += 1;
792 let has_rest = chunk.read_u8(self.ip) != 0;
793 self.ip += 1;
794 match &val {
795 Value::List(items) => {
796 if has_rest {
797 items.len() >= min_len
798 } else {
799 items.len() == min_len
800 }
801 }
802 _ => false,
803 }
804 }
805 _ => false,
806 };
807 self.stack.push(val);
809 self.stack.push(Value::Bool(result));
810 }
811 Op::MatchArm => {
812 let kind = chunk.read_u8(self.ip);
814 self.ip += 1;
815 match kind {
816 1 => {
817 let val = self.pop(line, col)?;
819 match val {
820 Value::Option(Some(v)) => self.stack.push(*v),
821 other => self.stack.push(other),
822 }
823 }
824 2 => {
825 let val = self.pop(line, col)?;
826 match val {
827 Value::Result(Ok(v)) => self.stack.push(*v),
828 other => self.stack.push(other),
829 }
830 }
831 3 => {
832 let val = self.pop(line, col)?;
833 match val {
834 Value::Result(Err(v)) => self.stack.push(*v),
835 other => self.stack.push(other),
836 }
837 }
838 4 | 5 => {
839 let idx = chunk.read_u8(self.ip) as usize;
841 self.ip += 1;
842 let val = self.peek(line, col)?;
843 match val {
844 Value::Tuple(items) | Value::List(items) => {
845 self.stack
846 .push(items.get(idx).cloned().unwrap_or(Value::Unit));
847 }
848 _ => self.stack.push(Value::Unit),
849 }
850 }
851 _ => {}
852 }
853 }
854 Op::MatchEnd => {
855 return Err(IonError::runtime(
856 ion_str!("non-exhaustive match").to_string(),
857 line,
858 col,
859 ));
860 }
861
862 Op::BuildRange => {
864 let inclusive = chunk.read_u8(self.ip) != 0;
865 self.ip += 1;
866 let end = self.pop(line, col)?;
867 let start = self.pop(line, col)?;
868 let s = start.as_int().ok_or_else(|| {
869 IonError::type_err(ion_str!("range start must be int"), line, col)
870 })?;
871 let e = end.as_int().ok_or_else(|| {
872 IonError::type_err(ion_str!("range end must be int"), line, col)
873 })?;
874 self.stack.push(Value::Range {
875 start: s,
876 end: e,
877 inclusive,
878 });
879 }
880
881 Op::ConstructStruct => {
883 let type_name_idx = chunk.read_u16(self.ip) as usize;
884 self.ip += 2;
885 let raw_count = chunk.read_u16(self.ip) as usize;
886 self.ip += 2;
887 let type_name = match &chunk.constants[type_name_idx] {
888 Value::Str(s) => s.clone(),
889 _ => return Err(IonError::runtime(ion_str!("invalid type name"), line, col)),
890 };
891 let has_spread = raw_count & 0x8000 != 0;
892 let field_count = raw_count & 0x7FFF;
893 let mut fields = IndexMap::new();
894 if has_spread {
895 let override_start = self.stack.len() - field_count * 2;
898 let overrides: Vec<Value> = self.stack.drain(override_start..).collect();
899 let spread_val = self.pop(line, col)?;
901 match spread_val {
902 Value::HostStruct { fields: sf, .. } => {
903 for (k, v) in sf {
904 fields.insert(k, v);
905 }
906 }
907 _ => {
908 return Err(IonError::type_err(
909 ion_str!("spread in struct constructor requires a struct"),
910 line,
911 col,
912 ))
913 }
914 }
915 for pair in overrides.chunks(2) {
917 let fname = match &pair[0] {
918 Value::Str(s) => s.clone(),
919 _ => {
920 return Err(IonError::runtime(
921 ion_str!("invalid field name"),
922 line,
923 col,
924 ))
925 }
926 };
927 fields.insert(fname, pair[1].clone());
928 }
929 } else {
930 let start = self.stack.len() - field_count * 2;
932 let items: Vec<Value> = self.stack.drain(start..).collect();
933 for pair in items.chunks(2) {
934 let fname = match &pair[0] {
935 Value::Str(s) => s.clone(),
936 _ => {
937 return Err(IonError::runtime(
938 ion_str!("invalid field name"),
939 line,
940 col,
941 ))
942 }
943 };
944 fields.insert(fname, pair[1].clone());
945 }
946 }
947 match self.types.construct_struct(&type_name, fields) {
948 Ok(val) => self.stack.push(val),
949 Err(msg) => return Err(IonError::runtime(msg, line, col)),
950 }
951 }
952 Op::ConstructEnum => {
953 let enum_name_idx = chunk.read_u16(self.ip) as usize;
954 self.ip += 2;
955 let variant_name_idx = chunk.read_u16(self.ip) as usize;
956 self.ip += 2;
957 let arg_count = chunk.read_u8(self.ip) as usize;
958 self.ip += 1;
959 let enum_name = match &chunk.constants[enum_name_idx] {
960 Value::Str(s) => s.clone(),
961 _ => return Err(IonError::runtime(ion_str!("invalid enum name"), line, col)),
962 };
963 let variant_name = match &chunk.constants[variant_name_idx] {
964 Value::Str(s) => s.clone(),
965 _ => {
966 return Err(IonError::runtime(
967 ion_str!("invalid variant name"),
968 line,
969 col,
970 ))
971 }
972 };
973 let start = self.stack.len() - arg_count;
974 let args: Vec<Value> = self.stack.drain(start..).collect();
975 match self.types.construct_enum(&enum_name, &variant_name, args) {
976 Ok(val) => self.stack.push(val),
977 Err(msg) => return Err(IonError::runtime(msg, line, col)),
978 }
979 }
980
981 Op::IterInit => {
983 let val = self.pop(line, col)?;
984 let iter: Box<dyn Iterator<Item = Value>> = match val {
985 Value::List(items) => Box::new(items.into_iter()),
986 Value::Set(items) => Box::new(items.into_iter()),
987 Value::Tuple(items) => Box::new(items.into_iter()),
988 Value::Dict(map) => Box::new(
989 map.into_iter()
990 .map(|(k, v)| Value::Tuple(vec![Value::Str(k), v])),
991 ),
992 Value::Str(s) => {
993 let chars: Vec<Value> =
994 s.chars().map(|c| Value::Str(c.to_string())).collect();
995 Box::new(chars.into_iter())
996 }
997 Value::Bytes(bytes) => {
998 let vals: Vec<Value> =
999 bytes.into_iter().map(|b| Value::Int(b as i64)).collect();
1000 Box::new(vals.into_iter())
1001 }
1002 Value::Range {
1003 start,
1004 end,
1005 inclusive,
1006 } => {
1007 if inclusive {
1008 Box::new((start..=end).map(Value::Int))
1009 } else {
1010 if end > start {
1012 Box::new((start..=(end - 1)).map(Value::Int))
1013 } else {
1014 Box::new(std::iter::empty())
1015 }
1016 }
1017 }
1018 other => {
1019 return Err(IonError::type_err(
1020 format!("{}{}", ion_str!("cannot iterate over "), other.type_name()),
1021 line,
1022 col,
1023 ));
1024 }
1025 };
1026 self.iterators.push(iter);
1027 self.stack.push(Value::Unit);
1029 }
1030 Op::IterNext => {
1031 let offset = chunk.read_u16(self.ip) as usize;
1032 self.ip += 2;
1033 self.pop(line, col)?;
1035 let iter = self
1036 .iterators
1037 .last_mut()
1038 .ok_or_else(|| IonError::runtime(ion_str!("no active iterator"), line, col))?;
1039 match iter.next() {
1040 Some(val) => {
1041 self.stack.push(val);
1042 }
1043 None => {
1044 self.iterators.pop();
1045 self.stack.push(Value::Unit); self.ip += offset;
1047 }
1048 }
1049 }
1050 Op::IterDrop => {
1051 self.iterators.pop();
1052 }
1053 Op::ListAppend => {
1054 let item = self.pop(line, col)?;
1057 let mut found = false;
1065 for i in (0..self.stack.len()).rev() {
1066 if let Value::List(_) = &self.stack[i] {
1067 if let Value::List(ref mut items) = self.stack[i] {
1068 items.push(item.clone());
1069 }
1070 found = true;
1071 break;
1072 }
1073 }
1074 if !found {
1075 return Err(IonError::runtime(
1076 ion_str!("ListAppend: no list on stack"),
1077 line,
1078 col,
1079 ));
1080 }
1081 }
1082 Op::ListExtend => {
1083 let source = self.pop(line, col)?;
1085 match source {
1086 Value::List(other) => {
1087 let mut found = false;
1088 for i in (0..self.stack.len()).rev() {
1089 if let Value::List(ref mut items) = self.stack[i] {
1090 items.extend(other);
1091 found = true;
1092 break;
1093 }
1094 }
1095 if !found {
1096 return Err(IonError::runtime(
1097 ion_str!("ListExtend: no list on stack"),
1098 line,
1099 col,
1100 ));
1101 }
1102 }
1103 other => {
1104 return Err(IonError::type_err(
1105 format!(
1106 "{}{}",
1107 ion_str!("spread requires a list, got "),
1108 other.type_name()
1109 ),
1110 line,
1111 col,
1112 ));
1113 }
1114 }
1115 }
1116 Op::DictInsert => {
1117 let value = self.pop(line, col)?;
1119 let key = self.pop(line, col)?;
1120 let key_str = match key {
1121 Value::Str(s) => s,
1122 other => other.to_string(),
1123 };
1124 let mut found = false;
1125 for i in (0..self.stack.len()).rev() {
1126 if let Value::Dict(_) = &self.stack[i] {
1127 if let Value::Dict(ref mut map) = self.stack[i] {
1128 map.insert(key_str.clone(), value.clone());
1129 }
1130 found = true;
1131 break;
1132 }
1133 }
1134 if !found {
1135 return Err(IonError::runtime(
1136 ion_str!("DictInsert: no dict on stack"),
1137 line,
1138 col,
1139 ));
1140 }
1141 }
1142 Op::DictMerge => {
1143 let source = self.pop(line, col)?;
1145 match source {
1146 Value::Dict(other) => {
1147 let mut found = false;
1149 for i in (0..self.stack.len()).rev() {
1150 if let Value::Dict(ref mut map) = self.stack[i] {
1151 for (k, v) in other {
1152 map.insert(k, v);
1153 }
1154 found = true;
1155 break;
1156 }
1157 }
1158 if !found {
1159 return Err(IonError::runtime(
1160 ion_str!("DictMerge: no dict on stack"),
1161 line,
1162 col,
1163 ));
1164 }
1165 }
1166 _ => {
1167 return Err(IonError::type_err(
1168 ion_str!("spread requires a dict").to_string(),
1169 line,
1170 col,
1171 ))
1172 }
1173 }
1174 }
1175
1176 Op::CheckType => {
1178 let idx = chunk.read_u16(self.ip) as usize;
1179 self.ip += 2;
1180 let type_name = match &chunk.constants[idx] {
1181 Value::Str(s) => s.clone(),
1182 _ => unreachable!(),
1183 };
1184 let val = self.stack.last().ok_or_else(|| {
1186 IonError::runtime(ion_str!("CheckType: empty stack"), line, col)
1187 })?;
1188 let ok = match type_name.as_str() {
1189 "int" => matches!(val, Value::Int(_)),
1190 "float" => matches!(val, Value::Float(_)),
1191 "bool" => matches!(val, Value::Bool(_)),
1192 "string" => matches!(val, Value::Str(_)),
1193 "bytes" => matches!(val, Value::Bytes(_)),
1194 "list" => matches!(val, Value::List(_)),
1195 "dict" => matches!(val, Value::Dict(_)),
1196 "tuple" => matches!(val, Value::Tuple(_)),
1197 "set" => matches!(val, Value::Set(_)),
1198 "fn" => matches!(
1199 val,
1200 Value::Fn(_) | Value::BuiltinFn(_, _) | Value::BuiltinClosure(_, _)
1201 ),
1202 "cell" => matches!(val, Value::Cell(_)),
1203 "any" => true,
1204 s if s.starts_with("Option") => matches!(val, Value::Option(_)),
1205 s if s.starts_with("Result") => matches!(val, Value::Result(_)),
1206 s if s.starts_with("list<") => matches!(val, Value::List(_)),
1207 s if s.starts_with("dict<") => matches!(val, Value::Dict(_)),
1208 _ => true,
1209 };
1210 if !ok {
1211 return Err(IonError::type_err(
1212 format!(
1213 "{}{}, {}{}",
1214 ion_str!("type mismatch: expected "),
1215 type_name,
1216 ion_str!("got "),
1217 val.type_name()
1218 ),
1219 line,
1220 col,
1221 ));
1222 }
1223 }
1224 Op::Slice => {
1225 let flags = chunk.read_u8(self.ip);
1226 self.ip += 1;
1227 let has_start = flags & 1 != 0;
1228 let has_end = flags & 2 != 0;
1229 let inclusive = flags & 4 != 0;
1230 let end_val = if has_end {
1231 Some(self.pop(line, col)?)
1232 } else {
1233 None
1234 };
1235 let start_val = if has_start {
1236 Some(self.pop(line, col)?)
1237 } else {
1238 None
1239 };
1240 let obj = self.pop(line, col)?;
1241 let result = self.slice_access(obj, start_val, end_val, inclusive, line, col)?;
1242 self.stack.push(result);
1243 }
1244
1245 Op::Print => {
1247 let newline = chunk.read_u8(self.ip) != 0;
1248 self.ip += 1;
1249 let val = self.pop(line, col)?;
1250 if newline {
1251 let text = format!("{}\n", val);
1252 self.output
1253 .write(OutputStream::Stdout, &text)
1254 .map_err(|e| IonError::runtime(e, line, col))?;
1255 } else {
1256 let text = val.to_string();
1257 self.output
1258 .write(OutputStream::Stdout, &text)
1259 .map_err(|e| IonError::runtime(e, line, col))?;
1260 }
1261 self.stack.push(Value::Unit);
1262 }
1263
1264 Op::TryBegin | Op::TryEnd => {
1265 unreachable!()
1267 }
1268 }
1269 Ok(None)
1270 }
1271
1272 fn decode_op(&self, byte: u8, line: usize, col: usize) -> Result<Op, IonError> {
1275 if byte > Op::Print as u8 {
1276 return Err(IonError::runtime(
1277 format!("{}{}", ion_str!("invalid opcode: "), byte),
1278 line,
1279 col,
1280 ));
1281 }
1282 Ok(unsafe { std::mem::transmute::<u8, crate::bytecode::Op>(byte) })
1284 }
1285
1286 fn slice_access(
1287 &self,
1288 obj: Value,
1289 start: Option<Value>,
1290 end: Option<Value>,
1291 inclusive: bool,
1292 line: usize,
1293 col: usize,
1294 ) -> Result<Value, IonError> {
1295 let get_idx = |v: Option<Value>, default: i64| -> Result<i64, IonError> {
1296 match v {
1297 Some(Value::Int(n)) => Ok(n),
1298 None => Ok(default),
1299 Some(other) => Err(IonError::type_err(
1300 format!(
1301 "{}{}",
1302 ion_str!("slice index must be int, got "),
1303 other.type_name()
1304 ),
1305 line,
1306 col,
1307 )),
1308 }
1309 };
1310 match &obj {
1311 Value::List(items) => {
1312 let len = items.len() as i64;
1313 let s = get_idx(start, 0)?.max(0).min(len) as usize;
1314 let e_raw = get_idx(end, len)?;
1315 let e = if inclusive {
1316 (e_raw + 1).max(0).min(len) as usize
1317 } else {
1318 e_raw.max(0).min(len) as usize
1319 };
1320 Ok(Value::List(items[s..e].to_vec()))
1321 }
1322 Value::Str(string) => {
1323 let chars: Vec<char> = string.chars().collect();
1324 let len = chars.len() as i64;
1325 let s = get_idx(start, 0)?.max(0).min(len) as usize;
1326 let e_raw = get_idx(end, len)?;
1327 let e = if inclusive {
1328 (e_raw + 1).max(0).min(len) as usize
1329 } else {
1330 e_raw.max(0).min(len) as usize
1331 };
1332 Ok(Value::Str(chars[s..e].iter().collect()))
1333 }
1334 Value::Bytes(bytes) => {
1335 let len = bytes.len() as i64;
1336 let s = get_idx(start, 0)?.max(0).min(len) as usize;
1337 let e_raw = get_idx(end, len)?;
1338 let e = if inclusive {
1339 (e_raw + 1).max(0).min(len) as usize
1340 } else {
1341 e_raw.max(0).min(len) as usize
1342 };
1343 Ok(Value::Bytes(bytes[s..e].to_vec()))
1344 }
1345 _ => Err(IonError::type_err(
1346 format!("{}{}", ion_str!("cannot slice "), obj.type_name()),
1347 line,
1348 col,
1349 )),
1350 }
1351 }
1352
1353 fn pop(&mut self, line: usize, col: usize) -> Result<Value, IonError> {
1354 self.stack
1355 .pop()
1356 .ok_or_else(|| IonError::runtime(ion_str!("stack underflow"), line, col))
1357 }
1358
1359 fn peek(&self, line: usize, col: usize) -> Result<Value, IonError> {
1360 self.stack
1361 .last()
1362 .cloned()
1363 .ok_or_else(|| IonError::runtime(ion_str!("stack underflow (peek)"), line, col))
1364 }
1365
1366 fn is_top_truthy(&self, line: usize, col: usize) -> Result<bool, IonError> {
1368 self.stack
1369 .last()
1370 .map(|v| v.is_truthy())
1371 .ok_or_else(|| IonError::runtime(ion_str!("stack underflow (peek)"), line, col))
1372 }
1373
1374 fn const_as_str(&self, val: &Value, line: usize, col: usize) -> Result<String, IonError> {
1375 match val {
1376 Value::Str(s) => Ok(s.clone()),
1377 _ => Err(IonError::runtime(
1378 ion_str!("expected string constant"),
1379 line,
1380 col,
1381 )),
1382 }
1383 }
1384
1385 fn const_to_sym(
1387 &mut self,
1388 val: &Value,
1389 line: usize,
1390 col: usize,
1391 ) -> Result<crate::intern::Symbol, IonError> {
1392 match val {
1393 Value::Str(s) => Ok(self.env.intern(s)),
1394 _ => Err(IonError::runtime(
1395 ion_str!("expected string constant"),
1396 line,
1397 col,
1398 )),
1399 }
1400 }
1401
1402 fn op_add(&self, a: Value, b: Value, line: usize, col: usize) -> Result<Value, IonError> {
1405 match (&a, &b) {
1406 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
1407 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
1408 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 + y)),
1409 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x + *y as f64)),
1410 (Value::Str(x), Value::Str(y)) => {
1411 let mut s = String::with_capacity(x.len() + y.len());
1412 s.push_str(x);
1413 s.push_str(y);
1414 Ok(Value::Str(s))
1415 }
1416 (Value::List(x), Value::List(y)) => {
1417 let mut r = x.clone();
1418 r.extend(y.clone());
1419 Ok(Value::List(r))
1420 }
1421 (Value::Bytes(x), Value::Bytes(y)) => {
1422 let mut r = x.clone();
1423 r.extend(y);
1424 Ok(Value::Bytes(r))
1425 }
1426 _ => Err(IonError::type_err(
1427 format!(
1428 "{}{} and {}",
1429 ion_str!("cannot add "),
1430 a.type_name(),
1431 b.type_name()
1432 ),
1433 line,
1434 col,
1435 )),
1436 }
1437 }
1438
1439 fn op_sub(&self, a: Value, b: Value, line: usize, col: usize) -> Result<Value, IonError> {
1440 match (&a, &b) {
1441 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
1442 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
1443 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 - y)),
1444 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x - *y as f64)),
1445 _ => Err(IonError::type_err(
1446 format!(
1447 "{}{} from {}",
1448 ion_str!("cannot subtract "),
1449 b.type_name(),
1450 a.type_name()
1451 ),
1452 line,
1453 col,
1454 )),
1455 }
1456 }
1457
1458 fn op_mul(&self, a: Value, b: Value, line: usize, col: usize) -> Result<Value, IonError> {
1459 match (&a, &b) {
1460 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
1461 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
1462 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 * y)),
1463 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * *y as f64)),
1464 (Value::Str(s), Value::Int(n)) | (Value::Int(n), Value::Str(s)) => {
1465 Ok(Value::Str(s.repeat(*n as usize)))
1466 }
1467 _ => Err(IonError::type_err(
1468 format!(
1469 "{}{} and {}",
1470 ion_str!("cannot multiply "),
1471 a.type_name(),
1472 b.type_name()
1473 ),
1474 line,
1475 col,
1476 )),
1477 }
1478 }
1479
1480 fn op_div(&self, a: Value, b: Value, line: usize, col: usize) -> Result<Value, IonError> {
1481 match (&a, &b) {
1482 (Value::Int(_), Value::Int(0)) => {
1483 Err(IonError::runtime(ion_str!("division by zero"), line, col))
1484 }
1485 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x / y)),
1486 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x / y)),
1487 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 / y)),
1488 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x / *y as f64)),
1489 _ => Err(IonError::type_err(
1490 format!(
1491 "{}{} by {}",
1492 ion_str!("cannot divide "),
1493 a.type_name(),
1494 b.type_name()
1495 ),
1496 line,
1497 col,
1498 )),
1499 }
1500 }
1501
1502 fn op_mod(&self, a: Value, b: Value, line: usize, col: usize) -> Result<Value, IonError> {
1503 match (&a, &b) {
1504 (Value::Int(_), Value::Int(0)) => {
1505 Err(IonError::runtime(ion_str!("modulo by zero"), line, col))
1506 }
1507 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x % y)),
1508 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x % y)),
1509 (Value::Int(x), Value::Float(y)) => Ok(Value::Float(*x as f64 % y)),
1510 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x % *y as f64)),
1511 _ => Err(IonError::type_err(
1512 format!(
1513 "{}{} by {}",
1514 ion_str!("cannot modulo "),
1515 a.type_name(),
1516 b.type_name()
1517 ),
1518 line,
1519 col,
1520 )),
1521 }
1522 }
1523
1524 fn op_neg(&self, val: Value, line: usize, col: usize) -> Result<Value, IonError> {
1525 match val {
1526 Value::Int(n) => Ok(Value::Int(-n)),
1527 Value::Float(n) => Ok(Value::Float(-n)),
1528 _ => Err(IonError::type_err(
1529 format!("{}{}", ion_str!("cannot negate "), val.type_name()),
1530 line,
1531 col,
1532 )),
1533 }
1534 }
1535
1536 fn compare_lt(&self, a: &Value, b: &Value, line: usize, col: usize) -> Result<bool, IonError> {
1537 match (a, b) {
1538 (Value::Int(x), Value::Int(y)) => Ok(x < y),
1539 (Value::Float(x), Value::Float(y)) => Ok(x < y),
1540 (Value::Int(x), Value::Float(y)) => Ok((*x as f64) < *y),
1541 (Value::Float(x), Value::Int(y)) => Ok(*x < (*y as f64)),
1542 (Value::Str(x), Value::Str(y)) => Ok(x < y),
1543 _ => Err(IonError::type_err(
1544 format!(
1545 "{}{} and {}",
1546 ion_str!("cannot compare "),
1547 a.type_name(),
1548 b.type_name()
1549 ),
1550 line,
1551 col,
1552 )),
1553 }
1554 }
1555
1556 fn get_field(
1559 &self,
1560 obj: Value,
1561 field: &str,
1562 line: usize,
1563 col: usize,
1564 ) -> Result<Value, IonError> {
1565 match &obj {
1566 Value::Dict(map) => Ok(match map.get(field) {
1567 Some(v) => v.clone(),
1568 None => Value::Option(None),
1569 }),
1570 Value::HostStruct { fields, .. } => fields.get(field).cloned().ok_or_else(|| {
1571 IonError::runtime(
1572 format!(
1573 "{}{}{}",
1574 ion_str!("field '"),
1575 field,
1576 ion_str!("' not found")
1577 ),
1578 line,
1579 col,
1580 )
1581 }),
1582 Value::List(items) => match field {
1583 "len" => Ok(Value::Int(items.len() as i64)),
1584 _ => Err(IonError::runtime(
1585 format!(
1586 "{}{}{}",
1587 ion_str!("list has no field '"),
1588 field,
1589 ion_str!("'")
1590 ),
1591 line,
1592 col,
1593 )),
1594 },
1595 Value::Str(s) => match field {
1596 "len" => Ok(Value::Int(s.len() as i64)),
1597 _ => Err(IonError::runtime(
1598 format!(
1599 "{}{}{}",
1600 ion_str!("string has no field '"),
1601 field,
1602 ion_str!("'")
1603 ),
1604 line,
1605 col,
1606 )),
1607 },
1608 Value::Tuple(items) => match field {
1609 "len" => Ok(Value::Int(items.len() as i64)),
1610 _ => Err(IonError::runtime(
1611 format!(
1612 "{}{}{}",
1613 ion_str!("tuple has no field '"),
1614 field,
1615 ion_str!("'")
1616 ),
1617 line,
1618 col,
1619 )),
1620 },
1621 _ => Err(IonError::type_err(
1622 format!(
1623 "{}{}{}{}",
1624 ion_str!("cannot access field '"),
1625 field,
1626 ion_str!("' on "),
1627 obj.type_name()
1628 ),
1629 line,
1630 col,
1631 )),
1632 }
1633 }
1634
1635 fn get_index(
1636 &self,
1637 obj: Value,
1638 index: Value,
1639 line: usize,
1640 col: usize,
1641 ) -> Result<Value, IonError> {
1642 match (&obj, &index) {
1643 (Value::List(items), Value::Int(i)) => {
1644 let idx = if *i < 0 { items.len() as i64 + i } else { *i } as usize;
1645 items.get(idx).cloned().ok_or_else(|| {
1646 IonError::runtime(
1647 format!("{}{}{}", ion_str!("index "), i, ion_str!(" out of range")),
1648 line,
1649 col,
1650 )
1651 })
1652 }
1653 (Value::Tuple(items), Value::Int(i)) => {
1654 let idx = if *i < 0 { items.len() as i64 + i } else { *i } as usize;
1655 items.get(idx).cloned().ok_or_else(|| {
1656 IonError::runtime(
1657 format!("{}{}{}", ion_str!("index "), i, ion_str!(" out of range")),
1658 line,
1659 col,
1660 )
1661 })
1662 }
1663 (Value::Dict(map), Value::Str(key)) => Ok(match map.get(key) {
1664 Some(v) => v.clone(),
1665 None => Value::Option(None),
1666 }),
1667 (Value::Str(s), Value::Int(i)) => {
1668 let char_count = s.chars().count() as i64;
1669 let idx = if *i < 0 { char_count + i } else { *i } as usize;
1670 s.chars()
1671 .nth(idx)
1672 .map(|c| Value::Str(c.to_string()))
1673 .ok_or_else(|| {
1674 IonError::runtime(
1675 format!("{}{}{}", ion_str!("index "), i, ion_str!(" out of range")),
1676 line,
1677 col,
1678 )
1679 })
1680 }
1681 (Value::Bytes(bytes), Value::Int(i)) => {
1682 let idx = if *i < 0 { bytes.len() as i64 + i } else { *i } as usize;
1683 bytes
1684 .get(idx)
1685 .map(|&b| Value::Int(b as i64))
1686 .ok_or_else(|| {
1687 IonError::runtime(
1688 format!("{}{}{}", ion_str!("index "), i, ion_str!(" out of range")),
1689 line,
1690 col,
1691 )
1692 })
1693 }
1694 _ => Err(IonError::type_err(
1695 format!(
1696 "{}{}{}{}",
1697 ion_str!("cannot index "),
1698 obj.type_name(),
1699 ion_str!(" with "),
1700 index.type_name()
1701 ),
1702 line,
1703 col,
1704 )),
1705 }
1706 }
1707
1708 fn set_index(
1710 &self,
1711 obj: Value,
1712 index: Value,
1713 value: Value,
1714 line: usize,
1715 col: usize,
1716 ) -> Result<Value, IonError> {
1717 match (obj, &index) {
1718 (Value::List(mut items), Value::Int(i)) => {
1719 let idx = if *i < 0 { items.len() as i64 + i } else { *i } as usize;
1720 if idx >= items.len() {
1721 return Err(IonError::runtime(
1722 format!("{}{}{}", ion_str!("index "), i, ion_str!(" out of range")),
1723 line,
1724 col,
1725 ));
1726 }
1727 items[idx] = value;
1728 Ok(Value::List(items))
1729 }
1730 (Value::Dict(mut map), Value::Str(key)) => {
1731 map.insert(key.clone(), value);
1732 Ok(Value::Dict(map))
1733 }
1734 (obj, _) => Err(IonError::type_err(
1735 format!("{}{}", ion_str!("cannot set index on "), obj.type_name()),
1736 line,
1737 col,
1738 )),
1739 }
1740 }
1741
1742 fn set_field(
1744 &self,
1745 obj: Value,
1746 field: &str,
1747 value: Value,
1748 line: usize,
1749 col: usize,
1750 ) -> Result<Value, IonError> {
1751 match obj {
1752 Value::Dict(mut map) => {
1753 map.insert(field.to_string(), value);
1754 Ok(Value::Dict(map))
1755 }
1756 Value::HostStruct {
1757 type_name,
1758 mut fields,
1759 } => {
1760 if fields.contains_key(field) {
1761 fields.insert(field.to_string(), value);
1762 Ok(Value::HostStruct { type_name, fields })
1763 } else {
1764 Err(IonError::runtime(
1765 format!(
1766 "{}{}{}{}",
1767 ion_str!("field '"),
1768 field,
1769 ion_str!("' not found on "),
1770 type_name
1771 ),
1772 line,
1773 col,
1774 ))
1775 }
1776 }
1777 _ => Err(IonError::type_err(
1778 format!("{}{}", ion_str!("cannot set field on "), obj.type_name()),
1779 line,
1780 col,
1781 )),
1782 }
1783 }
1784
1785 fn call_method(
1788 &mut self,
1789 receiver: Value,
1790 method: &str,
1791 args: &[Value],
1792 line: usize,
1793 col: usize,
1794 ) -> Result<Value, IonError> {
1795 if method == "to_string" {
1797 return Ok(Value::Str(format!("{}", receiver)));
1798 }
1799 match (&receiver, method) {
1801 (Value::List(items), "map") => {
1803 let func = args.first().ok_or_else(|| {
1804 IonError::runtime(ion_str!("map requires a function argument"), line, col)
1805 })?;
1806 let mut result = Vec::new();
1807 for item in items {
1808 result.push(self.invoke_value(func, std::slice::from_ref(item), line, col)?);
1809 }
1810 return Ok(Value::List(result));
1811 }
1812 (Value::List(items), "filter") => {
1813 let func = args.first().ok_or_else(|| {
1814 IonError::runtime(ion_str!("filter requires a function argument"), line, col)
1815 })?;
1816 let mut result = Vec::new();
1817 for item in items {
1818 let keep = self.invoke_value(func, std::slice::from_ref(item), line, col)?;
1819 if keep.is_truthy() {
1820 result.push(item.clone());
1821 }
1822 }
1823 return Ok(Value::List(result));
1824 }
1825 (Value::List(items), "fold") => {
1826 let init = args.first().cloned().unwrap_or(Value::Unit);
1827 let func = args.get(1).ok_or_else(|| {
1828 IonError::runtime(
1829 ion_str!("fold requires an initial value and a function"),
1830 line,
1831 col,
1832 )
1833 })?;
1834 let mut acc = init;
1835 for item in items {
1836 acc = self.invoke_value(func, &[acc, item.clone()], line, col)?;
1837 }
1838 return Ok(acc);
1839 }
1840 (Value::List(items), "reduce") => {
1841 if items.is_empty() {
1842 return Err(IonError::runtime(
1843 ion_str!("reduce on empty list"),
1844 line,
1845 col,
1846 ));
1847 }
1848 let func = args.first().ok_or_else(|| {
1849 IonError::runtime(ion_str!("reduce requires a function argument"), line, col)
1850 })?;
1851 let mut acc = items[0].clone();
1852 for item in items.iter().skip(1) {
1853 acc = self.invoke_value(func, &[acc, item.clone()], line, col)?;
1854 }
1855 return Ok(acc);
1856 }
1857 (Value::List(items), "flat_map") => {
1858 let func = args.first().ok_or_else(|| {
1859 IonError::runtime(ion_str!("flat_map requires a function argument"), line, col)
1860 })?;
1861 let mut result = Vec::new();
1862 for item in items {
1863 let mapped = self.invoke_value(func, std::slice::from_ref(item), line, col)?;
1864 match mapped {
1865 Value::List(sub) => result.extend(sub),
1866 other => result.push(other),
1867 }
1868 }
1869 return Ok(Value::List(result));
1870 }
1871 (Value::List(items), "any") => {
1872 let func = args.first().ok_or_else(|| {
1873 IonError::runtime(ion_str!("any requires a function argument"), line, col)
1874 })?;
1875 for item in items {
1876 if self
1877 .invoke_value(func, std::slice::from_ref(item), line, col)?
1878 .is_truthy()
1879 {
1880 return Ok(Value::Bool(true));
1881 }
1882 }
1883 return Ok(Value::Bool(false));
1884 }
1885 (Value::List(items), "all") => {
1886 let func = args.first().ok_or_else(|| {
1887 IonError::runtime(ion_str!("all requires a function argument"), line, col)
1888 })?;
1889 for item in items {
1890 if !self
1891 .invoke_value(func, std::slice::from_ref(item), line, col)?
1892 .is_truthy()
1893 {
1894 return Ok(Value::Bool(false));
1895 }
1896 }
1897 return Ok(Value::Bool(true));
1898 }
1899 (Value::List(items), "sort_by") => {
1900 let func = args.first().ok_or_else(|| {
1901 IonError::runtime(ion_str!("sort_by requires a function argument"), line, col)
1902 })?;
1903 let mut result = items.to_vec();
1904 let mut err: Option<IonError> = None;
1905 let func_clone = func.clone();
1906 result.sort_by(|a, b| {
1907 if err.is_some() {
1908 return std::cmp::Ordering::Equal;
1909 }
1910 match self.invoke_value(&func_clone, &[a.clone(), b.clone()], line, col) {
1911 Ok(Value::Int(n)) => {
1912 if n < 0 {
1913 std::cmp::Ordering::Less
1914 } else if n > 0 {
1915 std::cmp::Ordering::Greater
1916 } else {
1917 std::cmp::Ordering::Equal
1918 }
1919 }
1920 Ok(_) => {
1921 err = Some(IonError::type_err(
1922 ion_str!("sort_by function must return int"),
1923 line,
1924 col,
1925 ));
1926 std::cmp::Ordering::Equal
1927 }
1928 Err(e) => {
1929 err = Some(e);
1930 std::cmp::Ordering::Equal
1931 }
1932 }
1933 });
1934 if let Some(e) = err {
1935 return Err(e);
1936 }
1937 return Ok(Value::List(result));
1938 }
1939
1940 (
1942 Value::Range {
1943 start,
1944 end,
1945 inclusive,
1946 },
1947 "map",
1948 )
1949 | (
1950 Value::Range {
1951 start,
1952 end,
1953 inclusive,
1954 },
1955 "filter",
1956 )
1957 | (
1958 Value::Range {
1959 start,
1960 end,
1961 inclusive,
1962 },
1963 "fold",
1964 )
1965 | (
1966 Value::Range {
1967 start,
1968 end,
1969 inclusive,
1970 },
1971 "reduce",
1972 )
1973 | (
1974 Value::Range {
1975 start,
1976 end,
1977 inclusive,
1978 },
1979 "flat_map",
1980 )
1981 | (
1982 Value::Range {
1983 start,
1984 end,
1985 inclusive,
1986 },
1987 "any",
1988 )
1989 | (
1990 Value::Range {
1991 start,
1992 end,
1993 inclusive,
1994 },
1995 "all",
1996 )
1997 | (
1998 Value::Range {
1999 start,
2000 end,
2001 inclusive,
2002 },
2003 "sort_by",
2004 ) => {
2005 let items = Value::range_to_list(*start, *end, *inclusive);
2006 let list_receiver = Value::List(items);
2007 return self.call_method(list_receiver, method, args, line, col);
2008 }
2009
2010 (Value::Dict(map), "map") => {
2012 let func = args.first().ok_or_else(|| {
2013 IonError::runtime(ion_str!("map requires a function argument"), line, col)
2014 })?;
2015 let mut result = indexmap::IndexMap::new();
2016 for (k, v) in map {
2017 let mapped =
2018 self.invoke_value(func, &[Value::Str(k.clone()), v.clone()], line, col)?;
2019 result.insert(k.clone(), mapped);
2020 }
2021 return Ok(Value::Dict(result));
2022 }
2023 (Value::Dict(map), "filter") => {
2024 let func = args.first().ok_or_else(|| {
2025 IonError::runtime(ion_str!("filter requires a function argument"), line, col)
2026 })?;
2027 let mut result = indexmap::IndexMap::new();
2028 for (k, v) in map {
2029 let keep =
2030 self.invoke_value(func, &[Value::Str(k.clone()), v.clone()], line, col)?;
2031 if keep.is_truthy() {
2032 result.insert(k.clone(), v.clone());
2033 }
2034 }
2035 return Ok(Value::Dict(result));
2036 }
2037
2038 (Value::Option(opt), "map") => {
2040 let func = args.first().ok_or_else(|| {
2041 IonError::runtime(ion_str!("map requires a function argument"), line, col)
2042 })?;
2043 return match opt {
2044 Some(v) => {
2045 let result = self.invoke_value(func, &[*v.clone()], line, col)?;
2046 Ok(Value::Option(Some(Box::new(result))))
2047 }
2048 None => Ok(Value::Option(None)),
2049 };
2050 }
2051 (Value::Option(opt), "and_then") => {
2052 let func = args.first().ok_or_else(|| {
2053 IonError::runtime(ion_str!("and_then requires a function argument"), line, col)
2054 })?;
2055 return match opt {
2056 Some(v) => self.invoke_value(func, &[*v.clone()], line, col),
2057 None => Ok(Value::Option(None)),
2058 };
2059 }
2060 (Value::Option(opt), "or_else") => {
2061 let func = args.first().ok_or_else(|| {
2062 IonError::runtime(ion_str!("or_else requires a function argument"), line, col)
2063 })?;
2064 return match opt {
2065 Some(v) => Ok(Value::Option(Some(v.clone()))),
2066 None => self.invoke_value(func, &[], line, col),
2067 };
2068 }
2069 (Value::Option(opt), "unwrap_or_else") => {
2070 let func = args.first().ok_or_else(|| {
2071 IonError::runtime(
2072 ion_str!("unwrap_or_else requires a function argument"),
2073 line,
2074 col,
2075 )
2076 })?;
2077 return match opt {
2078 Some(v) => Ok(*v.clone()),
2079 None => self.invoke_value(func, &[], line, col),
2080 };
2081 }
2082
2083 (Value::Result(res), "map") => {
2085 let func = args.first().ok_or_else(|| {
2086 IonError::runtime(ion_str!("map requires a function argument"), line, col)
2087 })?;
2088 return match res {
2089 Ok(v) => {
2090 let result = self.invoke_value(func, &[*v.clone()], line, col)?;
2091 Ok(Value::Result(Ok(Box::new(result))))
2092 }
2093 Err(e) => Ok(Value::Result(Err(e.clone()))),
2094 };
2095 }
2096 (Value::Result(res), "map_err") => {
2097 let func = args.first().ok_or_else(|| {
2098 IonError::runtime(ion_str!("map_err requires a function argument"), line, col)
2099 })?;
2100 return match res {
2101 Ok(v) => Ok(Value::Result(Ok(v.clone()))),
2102 Err(e) => {
2103 let result = self.invoke_value(func, &[*e.clone()], line, col)?;
2104 Ok(Value::Result(Err(Box::new(result))))
2105 }
2106 };
2107 }
2108 (Value::Result(res), "and_then") => {
2109 let func = args.first().ok_or_else(|| {
2110 IonError::runtime(ion_str!("and_then requires a function argument"), line, col)
2111 })?;
2112 return match res {
2113 Ok(v) => self.invoke_value(func, &[*v.clone()], line, col),
2114 Err(e) => Ok(Value::Result(Err(e.clone()))),
2115 };
2116 }
2117 (Value::Result(res), "or_else") => {
2118 let func = args.first().ok_or_else(|| {
2119 IonError::runtime(ion_str!("or_else requires a function argument"), line, col)
2120 })?;
2121 return match res {
2122 Ok(v) => Ok(Value::Result(Ok(v.clone()))),
2123 Err(e) => self.invoke_value(func, &[*e.clone()], line, col),
2124 };
2125 }
2126 (Value::Result(res), "unwrap_or_else") => {
2127 let func = args.first().ok_or_else(|| {
2128 IonError::runtime(
2129 ion_str!("unwrap_or_else requires a function argument"),
2130 line,
2131 col,
2132 )
2133 })?;
2134 return match res {
2135 Ok(v) => Ok(*v.clone()),
2136 Err(e) => self.invoke_value(func, &[*e.clone()], line, col),
2137 };
2138 }
2139
2140 (Value::Cell(cell), "update") => {
2142 let func = args.first().ok_or_else(|| {
2143 IonError::runtime(
2144 ion_str!("cell.update() requires a function argument"),
2145 line,
2146 col,
2147 )
2148 })?;
2149 let current = { cell.lock().unwrap().clone() };
2150 let new_val = self.invoke_value(func, &[current], line, col)?;
2151 let mut inner = cell.lock().unwrap();
2152 *inner = new_val.clone();
2153 return Ok(new_val);
2154 }
2155
2156 _ => {}
2157 }
2158
2159 match &receiver {
2161 Value::List(items) => self.list_method(items, method, args, line, col),
2162 Value::Tuple(items) => self.tuple_method(items, method, args, line, col),
2163 Value::Str(s) => self.str_method(s, method, args, line, col),
2164 Value::Dict(map) => self.dict_method(map, method, args, line, col),
2165 Value::Bytes(b) => self.bytes_method(b, method, args, line, col),
2166 Value::Set(items) => self.set_method(items, method, args, line, col),
2167 Value::Option(_) => self.option_method(&receiver, method, args, line, col),
2168 Value::Result(_) => self.result_method(&receiver, method, args, line, col),
2169 Value::Range {
2170 start,
2171 end,
2172 inclusive,
2173 } => match method {
2174 "len" => Ok(Value::Int(Value::range_len(*start, *end, *inclusive))),
2175 "contains" => {
2176 let val = args[0].as_int().ok_or_else(|| {
2177 IonError::type_err(ion_str!("range.contains requires int"), line, col)
2178 })?;
2179 let in_range = if *inclusive {
2180 val >= *start && val <= *end
2181 } else {
2182 val >= *start && val < *end
2183 };
2184 Ok(Value::Bool(in_range))
2185 }
2186 "to_list" => Ok(Value::List(Value::range_to_list(*start, *end, *inclusive))),
2187 _ => {
2188 let items = Value::range_to_list(*start, *end, *inclusive);
2189 self.list_method(&items, method, args, line, col)
2190 }
2191 },
2192 Value::Cell(cell) => match method {
2193 "get" => Ok(cell.lock().unwrap().clone()),
2194 "set" => {
2195 if let Some(val) = args.first() {
2196 let mut inner = cell.lock().unwrap();
2197 *inner = val.clone();
2198 Ok(Value::Unit)
2199 } else {
2200 Err(IonError::runtime(
2201 ion_str!("cell.set() requires 1 argument"),
2202 line,
2203 col,
2204 ))
2205 }
2206 }
2207 _ => Err(IonError::type_err(
2208 format!(
2209 "{}{}{}",
2210 ion_str!("no method '"),
2211 method,
2212 ion_str!("' on cell")
2213 ),
2214 line,
2215 col,
2216 )),
2217 },
2218 _ => Err(IonError::type_err(
2219 format!(
2220 "{}{}{}{}",
2221 receiver.type_name(),
2222 ion_str!(" has no method '"),
2223 method,
2224 ion_str!("'")
2225 ),
2226 line,
2227 col,
2228 )),
2229 }
2230 }
2231
2232 fn list_method(
2233 &self,
2234 items: &[Value],
2235 method: &str,
2236 args: &[Value],
2237 line: usize,
2238 col: usize,
2239 ) -> Result<Value, IonError> {
2240 match method {
2241 "len" => Ok(Value::Int(items.len() as i64)),
2242 "push" => {
2243 let mut new = items.to_vec();
2244 for a in args {
2245 new.push(a.clone());
2246 }
2247 Ok(Value::List(new))
2248 }
2249 "pop" => {
2250 if items.is_empty() {
2251 Ok(Value::Tuple(vec![Value::List(vec![]), Value::Option(None)]))
2252 } else {
2253 let mut new = items.to_vec();
2254 let popped = new.pop().unwrap();
2255 Ok(Value::Tuple(vec![
2256 Value::List(new),
2257 Value::Option(Some(Box::new(popped))),
2258 ]))
2259 }
2260 }
2261 "contains" => Ok(Value::Bool(
2262 args.first().map(|a| items.contains(a)).unwrap_or(false),
2263 )),
2264 "is_empty" => Ok(Value::Bool(items.is_empty())),
2265 "reverse" => {
2266 let mut new = items.to_vec();
2267 new.reverse();
2268 Ok(Value::List(new))
2269 }
2270 "join" => {
2271 let sep = args.first().and_then(|a| a.as_str()).unwrap_or("");
2272 let s: String = items
2273 .iter()
2274 .map(|v| v.to_string())
2275 .collect::<Vec<_>>()
2276 .join(sep);
2277 Ok(Value::Str(s))
2278 }
2279 "enumerate" => {
2280 let pairs: Vec<Value> = items
2281 .iter()
2282 .enumerate()
2283 .map(|(i, v)| Value::Tuple(vec![Value::Int(i as i64), v.clone()]))
2284 .collect();
2285 Ok(Value::List(pairs))
2286 }
2287 "first" => Ok(match items.first() {
2288 Some(v) => Value::Option(Some(Box::new(v.clone()))),
2289 None => Value::Option(None),
2290 }),
2291 "last" => Ok(match items.last() {
2292 Some(v) => Value::Option(Some(Box::new(v.clone()))),
2293 None => Value::Option(None),
2294 }),
2295 "sort" => {
2296 if !items.is_empty() {
2297 let first_type = std::mem::discriminant(&items[0]);
2298 for item in items.iter().skip(1) {
2299 if std::mem::discriminant(item) != first_type {
2300 return Err(IonError::type_err(
2301 ion_str!("sort() requires all elements to be the same type"),
2302 line,
2303 col,
2304 ));
2305 }
2306 }
2307 }
2308 let mut sorted = items.to_vec();
2309 sorted.sort_by(|a, b| match (a, b) {
2310 (Value::Int(x), Value::Int(y)) => x.cmp(y),
2311 (Value::Float(x), Value::Float(y)) => {
2312 x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal)
2313 }
2314 (Value::Str(x), Value::Str(y)) => x.cmp(y),
2315 _ => std::cmp::Ordering::Equal,
2316 });
2317 Ok(Value::List(sorted))
2318 }
2319 "flatten" => {
2320 let mut result = Vec::new();
2321 for item in items {
2322 if let Value::List(inner) = item {
2323 result.extend(inner.iter().cloned());
2324 } else {
2325 result.push(item.clone());
2326 }
2327 }
2328 Ok(Value::List(result))
2329 }
2330 "zip" => {
2331 if let Some(Value::List(other)) = args.first() {
2332 let result: Vec<Value> = items
2333 .iter()
2334 .zip(other.iter())
2335 .map(|(a, b)| Value::Tuple(vec![a.clone(), b.clone()]))
2336 .collect();
2337 Ok(Value::List(result))
2338 } else {
2339 Err(IonError::type_err(
2340 ion_str!("zip requires a list argument"),
2341 line,
2342 col,
2343 ))
2344 }
2345 }
2346 "index" => {
2347 let target = args.first().ok_or_else(|| {
2348 IonError::type_err(ion_str!("index requires an argument"), line, col)
2349 })?;
2350 Ok(match items.iter().position(|v| v == target) {
2351 Some(i) => Value::Option(Some(Box::new(Value::Int(i as i64)))),
2352 None => Value::Option(None),
2353 })
2354 }
2355 "count" => {
2356 let target = args.first().ok_or_else(|| {
2357 IonError::type_err(ion_str!("count requires an argument"), line, col)
2358 })?;
2359 Ok(Value::Int(
2360 items.iter().filter(|v| *v == target).count() as i64
2361 ))
2362 }
2363 "slice" => {
2364 let start = args.first().and_then(|a| a.as_int()).unwrap_or(0) as usize;
2365 let end = args
2366 .get(1)
2367 .and_then(|a| a.as_int())
2368 .map(|n| n as usize)
2369 .unwrap_or(items.len());
2370 let start = start.min(items.len());
2371 let end = end.min(items.len());
2372 Ok(Value::List(items[start..end].to_vec()))
2373 }
2374 "dedup" => {
2375 let mut result: Vec<Value> = Vec::new();
2376 for item in items {
2377 if result.last() != Some(item) {
2378 result.push(item.clone());
2379 }
2380 }
2381 Ok(Value::List(result))
2382 }
2383 "unique" => {
2384 let mut seen = Vec::new();
2385 let mut result = Vec::new();
2386 for item in items {
2387 if !seen.contains(item) {
2388 seen.push(item.clone());
2389 result.push(item.clone());
2390 }
2391 }
2392 Ok(Value::List(result))
2393 }
2394 "min" => {
2395 if items.is_empty() {
2396 return Ok(Value::Option(None));
2397 }
2398 let mut min = &items[0];
2399 for item in items.iter().skip(1) {
2400 match (min, item) {
2401 (Value::Int(a), Value::Int(b)) if b < a => min = item,
2402 (Value::Float(a), Value::Float(b)) if b < a => min = item,
2403 (Value::Str(a), Value::Str(b)) if b < a => min = item,
2404 (Value::Int(_), Value::Int(_))
2405 | (Value::Float(_), Value::Float(_))
2406 | (Value::Str(_), Value::Str(_)) => {}
2407 _ => {
2408 return Err(IonError::type_err(
2409 ion_str!("min() requires homogeneous comparable elements"),
2410 line,
2411 col,
2412 ))
2413 }
2414 }
2415 }
2416 Ok(Value::Option(Some(Box::new(min.clone()))))
2417 }
2418 "max" => {
2419 if items.is_empty() {
2420 return Ok(Value::Option(None));
2421 }
2422 let mut max = &items[0];
2423 for item in items.iter().skip(1) {
2424 match (max, item) {
2425 (Value::Int(a), Value::Int(b)) if b > a => max = item,
2426 (Value::Float(a), Value::Float(b)) if b > a => max = item,
2427 (Value::Str(a), Value::Str(b)) if b > a => max = item,
2428 (Value::Int(_), Value::Int(_))
2429 | (Value::Float(_), Value::Float(_))
2430 | (Value::Str(_), Value::Str(_)) => {}
2431 _ => {
2432 return Err(IonError::type_err(
2433 ion_str!("max() requires homogeneous comparable elements"),
2434 line,
2435 col,
2436 ))
2437 }
2438 }
2439 }
2440 Ok(Value::Option(Some(Box::new(max.clone()))))
2441 }
2442 "sum" => {
2443 let mut int_sum: i64 = 0;
2444 let mut float_sum: f64 = 0.0;
2445 let mut has_float = false;
2446 for item in items {
2447 match item {
2448 Value::Int(n) => int_sum += n,
2449 Value::Float(f) => {
2450 has_float = true;
2451 float_sum += f;
2452 }
2453 _ => {
2454 return Err(IonError::type_err(
2455 ion_str!("sum() requires numeric elements"),
2456 line,
2457 col,
2458 ))
2459 }
2460 }
2461 }
2462 if has_float {
2463 Ok(Value::Float(float_sum + int_sum as f64))
2464 } else {
2465 Ok(Value::Int(int_sum))
2466 }
2467 }
2468 "window" => {
2469 let n = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2470 IonError::type_err(ion_str!("window requires int argument"), line, col)
2471 })? as usize;
2472 if n == 0 {
2473 return Err(IonError::runtime(
2474 ion_str!("window size must be > 0"),
2475 line,
2476 col,
2477 ));
2478 }
2479 let result: Vec<Value> =
2480 items.windows(n).map(|w| Value::List(w.to_vec())).collect();
2481 Ok(Value::List(result))
2482 }
2483 "chunk" => {
2484 let n = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2485 IonError::type_err(ion_str!("chunk requires int argument"), line, col)
2486 })? as usize;
2487 if n == 0 {
2488 return Err(IonError::type_err(
2489 ion_str!("chunk size must be > 0"),
2490 line,
2491 col,
2492 ));
2493 }
2494 let result: Vec<Value> = items.chunks(n).map(|c| Value::List(c.to_vec())).collect();
2495 Ok(Value::List(result))
2496 }
2497 _ => Err(IonError::type_err(
2498 format!(
2499 "{}{}{}",
2500 ion_str!("list has no method '"),
2501 method,
2502 ion_str!("'")
2503 ),
2504 line,
2505 col,
2506 )),
2507 }
2508 }
2509
2510 fn set_method(
2511 &self,
2512 items: &[Value],
2513 method: &str,
2514 args: &[Value],
2515 line: usize,
2516 col: usize,
2517 ) -> Result<Value, IonError> {
2518 match method {
2519 "len" => Ok(Value::Int(items.len() as i64)),
2520 "contains" => Ok(Value::Bool(
2521 args.first().map(|a| items.contains(a)).unwrap_or(false),
2522 )),
2523 "is_empty" => Ok(Value::Bool(items.is_empty())),
2524 "add" => {
2525 let val = &args[0];
2526 let mut new = items.to_vec();
2527 if !new.iter().any(|v| v == val) {
2528 new.push(val.clone());
2529 }
2530 Ok(Value::Set(new))
2531 }
2532 "remove" => {
2533 let val = &args[0];
2534 let new: Vec<Value> = items.iter().filter(|v| *v != val).cloned().collect();
2535 Ok(Value::Set(new))
2536 }
2537 "union" => {
2538 if let Some(Value::Set(other)) = args.first() {
2539 let mut new = items.to_vec();
2540 for v in other {
2541 if !new.iter().any(|x| x == v) {
2542 new.push(v.clone());
2543 }
2544 }
2545 Ok(Value::Set(new))
2546 } else {
2547 Err(IonError::type_err(
2548 ion_str!("union requires a set argument"),
2549 line,
2550 col,
2551 ))
2552 }
2553 }
2554 "intersection" => {
2555 if let Some(Value::Set(other)) = args.first() {
2556 let new: Vec<Value> = items
2557 .iter()
2558 .filter(|v| other.iter().any(|x| x == *v))
2559 .cloned()
2560 .collect();
2561 Ok(Value::Set(new))
2562 } else {
2563 Err(IonError::type_err(
2564 ion_str!("intersection requires a set argument"),
2565 line,
2566 col,
2567 ))
2568 }
2569 }
2570 "difference" => {
2571 if let Some(Value::Set(other)) = args.first() {
2572 let new: Vec<Value> = items
2573 .iter()
2574 .filter(|v| !other.iter().any(|x| x == *v))
2575 .cloned()
2576 .collect();
2577 Ok(Value::Set(new))
2578 } else {
2579 Err(IonError::type_err(
2580 ion_str!("difference requires a set argument"),
2581 line,
2582 col,
2583 ))
2584 }
2585 }
2586 "to_list" => Ok(Value::List(items.to_vec())),
2587 _ => Err(IonError::type_err(
2588 format!(
2589 "{}{}{}",
2590 ion_str!("set has no method '"),
2591 method,
2592 ion_str!("'")
2593 ),
2594 line,
2595 col,
2596 )),
2597 }
2598 }
2599
2600 fn tuple_method(
2601 &self,
2602 items: &[Value],
2603 method: &str,
2604 args: &[Value],
2605 line: usize,
2606 col: usize,
2607 ) -> Result<Value, IonError> {
2608 match method {
2609 "len" => Ok(Value::Int(items.len() as i64)),
2610 "contains" => Ok(Value::Bool(
2611 args.first().map(|a| items.contains(a)).unwrap_or(false),
2612 )),
2613 "to_list" => Ok(Value::List(items.to_vec())),
2614 _ => Err(IonError::type_err(
2615 format!(
2616 "{}{}{}",
2617 ion_str!("tuple has no method '"),
2618 method,
2619 ion_str!("'")
2620 ),
2621 line,
2622 col,
2623 )),
2624 }
2625 }
2626
2627 fn str_method(
2628 &self,
2629 s: &str,
2630 method: &str,
2631 args: &[Value],
2632 line: usize,
2633 col: usize,
2634 ) -> Result<Value, IonError> {
2635 match method {
2636 "len" => Ok(Value::Int(s.len() as i64)),
2637 "to_upper" => Ok(Value::Str(s.to_uppercase())),
2638 "to_lower" => Ok(Value::Str(s.to_lowercase())),
2639 "trim" => Ok(Value::Str(s.trim().to_string())),
2640 "contains" => match args.first() {
2641 Some(Value::Str(sub)) => Ok(Value::Bool(s.contains(sub.as_str()))),
2642 Some(Value::Int(code)) => {
2643 let ch = char::from_u32(*code as u32).ok_or_else(|| {
2644 IonError::type_err(ion_str!("invalid char code"), line, col)
2645 })?;
2646 Ok(Value::Bool(s.contains(ch)))
2647 }
2648 _ => Err(IonError::type_err(
2649 ion_str!("contains requires string or int argument"),
2650 line,
2651 col,
2652 )),
2653 },
2654 "starts_with" => {
2655 let prefix = args.first().and_then(|a| a.as_str()).unwrap_or("");
2656 Ok(Value::Bool(s.starts_with(prefix)))
2657 }
2658 "ends_with" => {
2659 let suffix = args.first().and_then(|a| a.as_str()).unwrap_or("");
2660 Ok(Value::Bool(s.ends_with(suffix)))
2661 }
2662 "split" => {
2663 let sep = args.first().and_then(|a| a.as_str()).unwrap_or(" ");
2664 let parts: Vec<Value> = s.split(sep).map(|p| Value::Str(p.to_string())).collect();
2665 Ok(Value::List(parts))
2666 }
2667 "replace" => {
2668 let from = args.first().and_then(|a| a.as_str()).unwrap_or("");
2669 let to = args.get(1).and_then(|a| a.as_str()).unwrap_or("");
2670 Ok(Value::Str(s.replace(from, to)))
2671 }
2672 "chars" => {
2673 let chars: Vec<Value> = s.chars().map(|c| Value::Str(c.to_string())).collect();
2674 Ok(Value::List(chars))
2675 }
2676 "char_len" => Ok(Value::Int(s.chars().count() as i64)),
2677 "is_empty" => Ok(Value::Bool(s.is_empty())),
2678 "trim_start" => Ok(Value::Str(s.trim_start().to_string())),
2679 "trim_end" => Ok(Value::Str(s.trim_end().to_string())),
2680 "repeat" => {
2681 let n = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2682 IonError::type_err(ion_str!("repeat requires int argument"), line, col)
2683 })?;
2684 Ok(Value::Str(s.repeat(n as usize)))
2685 }
2686 "find" => {
2687 let sub = args.first().and_then(|a| a.as_str()).unwrap_or("");
2688 Ok(match s.find(sub) {
2689 Some(byte_idx) => {
2690 let char_idx = s[..byte_idx].chars().count();
2691 Value::Option(Some(Box::new(Value::Int(char_idx as i64))))
2692 }
2693 None => Value::Option(None),
2694 })
2695 }
2696 "to_int" => Ok(match s.trim().parse::<i64>() {
2697 std::result::Result::Ok(n) => Value::Result(Ok(Box::new(Value::Int(n)))),
2698 std::result::Result::Err(e) => {
2699 Value::Result(Err(Box::new(Value::Str(e.to_string()))))
2700 }
2701 }),
2702 "to_float" => Ok(match s.trim().parse::<f64>() {
2703 std::result::Result::Ok(f) => Value::Result(Ok(Box::new(Value::Float(f)))),
2704 std::result::Result::Err(e) => {
2705 Value::Result(Err(Box::new(Value::Str(e.to_string()))))
2706 }
2707 }),
2708 "bytes" => {
2709 let bytes: Vec<Value> = s.bytes().map(|b| Value::Int(b as i64)).collect();
2710 Ok(Value::List(bytes))
2711 }
2712 "strip_prefix" => {
2713 let pre = args.first().and_then(|a| a.as_str()).unwrap_or("");
2714 Ok(Value::Str(s.strip_prefix(pre).unwrap_or(s).to_string()))
2715 }
2716 "strip_suffix" => {
2717 let suf = args.first().and_then(|a| a.as_str()).unwrap_or("");
2718 Ok(Value::Str(s.strip_suffix(suf).unwrap_or(s).to_string()))
2719 }
2720 "pad_start" => {
2721 let width = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2722 IonError::type_err(ion_str!("pad_start requires int argument"), line, col)
2723 })? as usize;
2724 let ch = args
2725 .get(1)
2726 .and_then(|a| a.as_str())
2727 .and_then(|s| s.chars().next())
2728 .unwrap_or(' ');
2729 let char_len = s.chars().count();
2730 if char_len >= width {
2731 Ok(Value::Str(s.to_string()))
2732 } else {
2733 let pad: String = std::iter::repeat_n(ch, width - char_len).collect();
2734 Ok(Value::Str(format!("{}{}", pad, s)))
2735 }
2736 }
2737 "pad_end" => {
2738 let width = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2739 IonError::type_err(ion_str!("pad_end requires int argument"), line, col)
2740 })? as usize;
2741 let ch = args
2742 .get(1)
2743 .and_then(|a| a.as_str())
2744 .and_then(|s| s.chars().next())
2745 .unwrap_or(' ');
2746 let char_len = s.chars().count();
2747 if char_len >= width {
2748 Ok(Value::Str(s.to_string()))
2749 } else {
2750 let pad: String = std::iter::repeat_n(ch, width - char_len).collect();
2751 Ok(Value::Str(format!("{}{}", s, pad)))
2752 }
2753 }
2754 "reverse" => Ok(Value::Str(s.chars().rev().collect())),
2755 "slice" => {
2756 let chars: Vec<char> = s.chars().collect();
2757 let char_count = chars.len();
2758 let start = args.first().and_then(|a| a.as_int()).unwrap_or(0) as usize;
2759 let end = args
2760 .get(1)
2761 .and_then(|a| a.as_int())
2762 .map(|n| n as usize)
2763 .unwrap_or(char_count);
2764 let start = start.min(char_count);
2765 let end = end.min(char_count);
2766 Ok(Value::Str(chars[start..end].iter().collect()))
2767 }
2768 _ => Err(IonError::type_err(
2769 format!(
2770 "{}{}{}",
2771 ion_str!("string has no method '"),
2772 method,
2773 ion_str!("'")
2774 ),
2775 line,
2776 col,
2777 )),
2778 }
2779 }
2780
2781 fn bytes_method(
2782 &self,
2783 bytes: &[u8],
2784 method: &str,
2785 args: &[Value],
2786 line: usize,
2787 col: usize,
2788 ) -> Result<Value, IonError> {
2789 match method {
2790 "len" => Ok(Value::Int(bytes.len() as i64)),
2791 "is_empty" => Ok(Value::Bool(bytes.is_empty())),
2792 "contains" => {
2793 let byte = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2794 IonError::type_err(ion_str!("bytes.contains() requires an int"), line, col)
2795 })?;
2796 Ok(Value::Bool(bytes.contains(&(byte as u8))))
2797 }
2798 "slice" => {
2799 let start = args.first().and_then(|a| a.as_int()).unwrap_or(0) as usize;
2800 let end = args
2801 .get(1)
2802 .and_then(|a| a.as_int())
2803 .map(|n| n as usize)
2804 .unwrap_or(bytes.len());
2805 let start = start.min(bytes.len());
2806 let end = end.min(bytes.len());
2807 Ok(Value::Bytes(bytes[start..end].to_vec()))
2808 }
2809 "to_list" => Ok(Value::List(
2810 bytes.iter().map(|&b| Value::Int(b as i64)).collect(),
2811 )),
2812 "to_str" => match std::str::from_utf8(bytes) {
2813 std::result::Result::Ok(s) => {
2814 Ok(Value::Result(Ok(Box::new(Value::Str(s.to_string())))))
2815 }
2816 std::result::Result::Err(e) => {
2817 Ok(Value::Result(Err(Box::new(Value::Str(format!("{}", e))))))
2818 }
2819 },
2820 "to_hex" => {
2821 let hex: String = bytes.iter().map(|b| format!("{:02x}", b)).collect();
2822 Ok(Value::Str(hex))
2823 }
2824 "find" => {
2825 let needle = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2826 IonError::type_err(ion_str!("bytes.find() requires an int"), line, col)
2827 })?;
2828 let pos = bytes.iter().position(|&b| b == needle as u8);
2829 Ok(match pos {
2830 Some(i) => Value::Option(Some(Box::new(Value::Int(i as i64)))),
2831 None => Value::Option(None),
2832 })
2833 }
2834 "reverse" => {
2835 let mut rev = bytes.to_vec();
2836 rev.reverse();
2837 Ok(Value::Bytes(rev))
2838 }
2839 "push" => {
2840 let byte = args.first().and_then(|a| a.as_int()).ok_or_else(|| {
2841 IonError::type_err(ion_str!("bytes.push() requires an int"), line, col)
2842 })?;
2843 let mut new = bytes.to_vec();
2844 new.push(byte as u8);
2845 Ok(Value::Bytes(new))
2846 }
2847 _ => Err(IonError::type_err(
2848 format!(
2849 "{}{}{}",
2850 ion_str!("bytes has no method '"),
2851 method,
2852 ion_str!("'")
2853 ),
2854 line,
2855 col,
2856 )),
2857 }
2858 }
2859
2860 fn dict_method(
2861 &self,
2862 map: &IndexMap<String, Value>,
2863 method: &str,
2864 args: &[Value],
2865 line: usize,
2866 col: usize,
2867 ) -> Result<Value, IonError> {
2868 match method {
2869 "len" => Ok(Value::Int(map.len() as i64)),
2870 "keys" => {
2871 let keys: Vec<Value> = map.keys().map(|k| Value::Str(k.clone())).collect();
2872 Ok(Value::List(keys))
2873 }
2874 "values" => {
2875 let vals: Vec<Value> = map.values().cloned().collect();
2876 Ok(Value::List(vals))
2877 }
2878 "contains_key" => {
2879 let key = args.first().and_then(|a| a.as_str()).unwrap_or("");
2880 Ok(Value::Bool(map.contains_key(key)))
2881 }
2882 "get" => {
2883 let key = args.first().and_then(|a| a.as_str()).unwrap_or("");
2884 Ok(match map.get(key) {
2885 Some(v) => Value::Option(Some(Box::new(v.clone()))),
2886 None => Value::Option(None),
2887 })
2888 }
2889 "is_empty" => Ok(Value::Bool(map.is_empty())),
2890 "entries" => Ok(Value::List(
2891 map.iter()
2892 .map(|(k, v)| Value::Tuple(vec![Value::Str(k.clone()), v.clone()]))
2893 .collect(),
2894 )),
2895 "insert" => {
2896 let key = args.first().and_then(|a| a.as_str()).unwrap_or("");
2897 let val = args.get(1).cloned().unwrap_or(Value::Unit);
2898 let mut new_map = map.clone();
2899 new_map.insert(key.to_string(), val);
2900 Ok(Value::Dict(new_map))
2901 }
2902 "remove" => {
2903 let key = args.first().and_then(|a| a.as_str()).unwrap_or("");
2904 let mut new_map = map.clone();
2905 new_map.shift_remove(key);
2906 Ok(Value::Dict(new_map))
2907 }
2908 "merge" => {
2909 if let Some(Value::Dict(other)) = args.first() {
2910 let mut new_map = map.clone();
2911 for (k, v) in other {
2912 new_map.insert(k.clone(), v.clone());
2913 }
2914 Ok(Value::Dict(new_map))
2915 } else {
2916 Err(IonError::type_err(
2917 ion_str!("merge requires a dict argument"),
2918 line,
2919 col,
2920 ))
2921 }
2922 }
2923 "update" => {
2924 if let Some(Value::Dict(other)) = args.first() {
2925 let mut new_map = map.clone();
2926 for (k, v) in other {
2927 new_map.insert(k.clone(), v.clone());
2928 }
2929 Ok(Value::Dict(new_map))
2930 } else {
2931 Err(IonError::type_err(
2932 ion_str!("update requires a dict argument"),
2933 line,
2934 col,
2935 ))
2936 }
2937 }
2938 "keys_of" => {
2939 let target = args.first().ok_or_else(|| {
2940 IonError::type_err(ion_str!("keys_of requires an argument"), line, col)
2941 })?;
2942 let keys: Vec<Value> = map
2943 .iter()
2944 .filter(|(_, v)| *v == target)
2945 .map(|(k, _)| Value::Str(k.clone()))
2946 .collect();
2947 Ok(Value::List(keys))
2948 }
2949 "zip" => {
2950 if let Some(Value::Dict(other)) = args.first() {
2951 let mut result = indexmap::IndexMap::new();
2952 for (k, v) in map {
2953 if let Some(ov) = other.get(k) {
2954 result.insert(k.clone(), Value::Tuple(vec![v.clone(), ov.clone()]));
2955 }
2956 }
2957 Ok(Value::Dict(result))
2958 } else {
2959 Err(IonError::type_err(
2960 ion_str!("zip requires a dict argument"),
2961 line,
2962 col,
2963 ))
2964 }
2965 }
2966 _ => Err(IonError::type_err(
2967 format!(
2968 "{}{}{}",
2969 ion_str!("dict has no method '"),
2970 method,
2971 ion_str!("'")
2972 ),
2973 line,
2974 col,
2975 )),
2976 }
2977 }
2978
2979 fn option_method(
2980 &self,
2981 val: &Value,
2982 method: &str,
2983 args: &[Value],
2984 line: usize,
2985 col: usize,
2986 ) -> Result<Value, IonError> {
2987 let opt = match val {
2988 Value::Option(o) => o,
2989 _ => return Err(IonError::type_err(ion_str!("expected Option"), line, col)),
2990 };
2991 match method {
2992 "is_some" => Ok(Value::Bool(opt.is_some())),
2993 "is_none" => Ok(Value::Bool(opt.is_none())),
2994 "unwrap" => match opt {
2995 Some(v) => Ok(*v.clone()),
2996 None => Err(IonError::runtime(
2997 ion_str!("called unwrap on None"),
2998 line,
2999 col,
3000 )),
3001 },
3002 "unwrap_or" => Ok(opt
3003 .as_ref()
3004 .map(|v| *v.clone())
3005 .unwrap_or_else(|| args.first().cloned().unwrap_or(Value::Unit))),
3006 "expect" => match opt {
3007 Some(v) => Ok(*v.clone()),
3008 None => {
3009 let msg = args
3010 .first()
3011 .and_then(|a| a.as_str())
3012 .unwrap_or("called expect on None");
3013 Err(IonError::runtime(msg.to_string(), line, col))
3014 }
3015 },
3016 _ => Err(IonError::type_err(
3017 format!(
3018 "{}{}{}",
3019 ion_str!("Option has no method '"),
3020 method,
3021 ion_str!("'")
3022 ),
3023 line,
3024 col,
3025 )),
3026 }
3027 }
3028
3029 fn result_method(
3030 &self,
3031 val: &Value,
3032 method: &str,
3033 args: &[Value],
3034 line: usize,
3035 col: usize,
3036 ) -> Result<Value, IonError> {
3037 let res = match val {
3038 Value::Result(r) => r,
3039 _ => return Err(IonError::type_err(ion_str!("expected Result"), line, col)),
3040 };
3041 match method {
3042 "is_ok" => Ok(Value::Bool(res.is_ok())),
3043 "is_err" => Ok(Value::Bool(res.is_err())),
3044 "unwrap" => match res {
3045 Ok(v) => Ok(*v.clone()),
3046 Err(e) => Err(IonError::runtime(
3047 format!("{}{}", ion_str!("called unwrap on Err: "), e),
3048 line,
3049 col,
3050 )),
3051 },
3052 "unwrap_or" => Ok(match res {
3053 Ok(v) => *v.clone(),
3054 Err(_) => args.first().cloned().unwrap_or(Value::Unit),
3055 }),
3056 "expect" => match res {
3057 Ok(v) => Ok(*v.clone()),
3058 Err(e) => {
3059 let msg = args
3060 .first()
3061 .and_then(|a| a.as_str())
3062 .unwrap_or("called expect on Err");
3063 Err(IonError::runtime(format!("{}: {}", msg, e), line, col))
3064 }
3065 },
3066 _ => Err(IonError::type_err(
3067 format!(
3068 "{}{}{}",
3069 ion_str!("Result has no method '"),
3070 method,
3071 ion_str!("'")
3072 ),
3073 line,
3074 col,
3075 )),
3076 }
3077 }
3078
3079 fn invoke_value(
3083 &mut self,
3084 func: &Value,
3085 args: &[Value],
3086 line: usize,
3087 col: usize,
3088 ) -> Result<Value, IonError> {
3089 self.stack.push(func.clone());
3091 for arg in args {
3092 self.stack.push(arg.clone());
3093 }
3094 self.call_function(args.len(), line, col)?;
3095 self.pop(line, col)
3096 }
3097
3098 fn eval_default_arg(
3099 &self,
3100 param_name: &str,
3101 default: &crate::ast::Expr,
3102 line: usize,
3103 col: usize,
3104 ) -> Result<Value, IonError> {
3105 let mut interp = crate::interpreter::Interpreter::with_env(self.env.clone());
3106 interp.types = self.types.clone();
3107 interp.eval_single_expr(default).map_err(|e| {
3108 IonError::runtime(
3109 format!(
3110 "{}'{}': {}",
3111 ion_str!("error evaluating default for "),
3112 param_name,
3113 e.message
3114 ),
3115 line,
3116 col,
3117 )
3118 })
3119 }
3120
3121 fn prepare_positional_function_args(
3122 &mut self,
3123 ion_fn: &crate::value::IonFn,
3124 args: &[Value],
3125 line: usize,
3126 col: usize,
3127 ) -> Result<Vec<Value>, IonError> {
3128 let mut prepared = Vec::with_capacity(ion_fn.params.len());
3129 for (i, param) in ion_fn.params.iter().enumerate() {
3130 let val = if i < args.len() {
3131 args[i].clone()
3132 } else if let Some(default) = ¶m.default {
3133 self.eval_default_arg(¶m.name, default, line, col)?
3134 } else {
3135 return Err(IonError::runtime(
3136 format!(
3137 "{}{}{}{}{}{}",
3138 ion_str!("function '"),
3139 ion_fn.name,
3140 ion_str!("' expected "),
3141 ion_fn.params.len(),
3142 ion_str!(" arguments, got "),
3143 args.len(),
3144 ),
3145 line,
3146 col,
3147 ));
3148 };
3149 self.env.define(param.name.clone(), val.clone(), false);
3150 prepared.push(val);
3151 }
3152 Ok(prepared)
3153 }
3154
3155 fn prepare_named_function_args(
3156 &mut self,
3157 ion_fn: &crate::value::IonFn,
3158 ordered: &[Option<Value>],
3159 line: usize,
3160 col: usize,
3161 ) -> Result<Vec<Value>, IonError> {
3162 let mut prepared = Vec::with_capacity(ion_fn.params.len());
3163 for (i, param) in ion_fn.params.iter().enumerate() {
3164 let val = if let Some(Some(val)) = ordered.get(i) {
3165 val.clone()
3166 } else if let Some(default) = ¶m.default {
3167 self.eval_default_arg(¶m.name, default, line, col)?
3168 } else {
3169 return Err(IonError::runtime(
3170 format!(
3171 "{}{}{}",
3172 ion_str!("missing argument '"),
3173 param.name,
3174 ion_str!("'"),
3175 ),
3176 line,
3177 col,
3178 ));
3179 };
3180 self.env.define(param.name.clone(), val.clone(), false);
3181 prepared.push(val);
3182 }
3183 Ok(prepared)
3184 }
3185
3186 fn call_function(&mut self, arg_count: usize, line: usize, col: usize) -> Result<(), IonError> {
3187 let args_start = self.stack.len() - arg_count;
3189 let func_idx = args_start - 1;
3190 let mut func = self.stack[func_idx].clone();
3191 let mut args: Vec<Value> = self.stack[args_start..].to_vec();
3192 self.stack.truncate(func_idx);
3193
3194 loop {
3196 match func {
3197 #[cfg(feature = "concurrency")]
3198 Value::BuiltinFn(ref name, _) if name == "timeout" => {
3199 let result = self.builtin_timeout(&args, line, col)?;
3200 self.stack.push(result);
3201 return Ok(());
3202 }
3203 Value::BuiltinFn(_name, f) => {
3204 let result = f(&args).map_err(|e| IonError::runtime(e, line, col))?;
3205 self.stack.push(result);
3206 return Ok(());
3207 }
3208 Value::BuiltinClosure(_name, f) => {
3209 let result = f.call(&args).map_err(|e| IonError::runtime(e, line, col))?;
3210 self.stack.push(result);
3211 return Ok(());
3212 }
3213 Value::Fn(ion_fn) => {
3214 self.env.push_scope();
3215
3216 for (name, val) in &ion_fn.captures {
3217 self.env.define(name.clone(), val.clone(), false);
3218 }
3219
3220 let saved_locals_base = self.locals_base;
3222 let saved_locals_len = self.locals.len();
3223 let saved_frames_len = self.local_frames.len();
3224 let prepared_args =
3225 match self.prepare_positional_function_args(&ion_fn, &args, line, col) {
3226 Ok(args) => args,
3227 Err(e) => {
3228 self.env.pop_scope();
3229 return Err(e);
3230 }
3231 };
3232
3233 self.locals_base = self.locals.len(); for val in prepared_args {
3237 self.locals.push(LocalSlot {
3238 value: val,
3239 mutable: false,
3240 });
3241 }
3242
3243 let fn_id = ion_fn.fn_id;
3244 let chunk_opt = if let Some(chunk) = self.fn_cache.get(&fn_id) {
3245 Some(chunk.clone())
3246 } else {
3247 let compiler = crate::compiler::Compiler::new();
3248 compiler
3249 .compile_fn_body(&ion_fn.params, &ion_fn.body, line)
3250 .ok()
3251 };
3252 if let Some(chunk) = chunk_opt {
3253 self.fn_cache.entry(fn_id).or_insert_with(|| chunk.clone());
3254 let saved_ip = self.ip;
3255 let saved_iters = std::mem::take(&mut self.iterators);
3256 self.ip = 0;
3257 let result = self.run_chunk(&chunk);
3258 self.ip = saved_ip;
3259 self.iterators = saved_iters;
3260 self.locals.truncate(saved_locals_len);
3262 self.local_frames.truncate(saved_frames_len);
3263 self.locals_base = saved_locals_base;
3264 self.env.pop_scope();
3265
3266 if let Some((tail_func, tail_args)) = self.pending_tail_call.take() {
3268 func = tail_func;
3269 args = tail_args;
3270 continue; }
3272
3273 match result {
3274 Ok(val) => self.stack.push(val),
3275 Err(e) if e.kind == crate::error::ErrorKind::PropagatedErr => {
3276 self.stack.push(Value::Result(Err(Box::new(Value::Str(
3277 e.message.clone(),
3278 )))));
3279 }
3280 Err(e) if e.kind == crate::error::ErrorKind::PropagatedNone => {
3281 self.stack.push(Value::Option(None));
3282 }
3283 Err(e) => return Err(e),
3284 }
3285 } else {
3286 self.locals.truncate(saved_locals_len);
3288 self.local_frames.truncate(saved_frames_len);
3289 self.locals_base = saved_locals_base;
3290 let mut interp =
3291 crate::interpreter::Interpreter::with_env(self.env.clone());
3292 let result = interp.eval_block(&ion_fn.body);
3293 self.env = interp.take_env();
3294 self.env.pop_scope();
3295 match result {
3296 Ok(val) => self.stack.push(val),
3297 Err(e) if e.kind == crate::error::ErrorKind::PropagatedErr => {
3298 self.stack.push(Value::Result(Err(Box::new(Value::Str(
3299 e.message.clone(),
3300 )))));
3301 }
3302 Err(e) if e.kind == crate::error::ErrorKind::PropagatedNone => {
3303 self.stack.push(Value::Option(None));
3304 }
3305 Err(e) => return Err(e),
3306 }
3307 }
3308 return Ok(());
3309 }
3310 _ => {
3311 return Err(IonError::type_err(
3312 format!("{}{}", ion_str!("cannot call "), func.type_name()),
3313 line,
3314 col,
3315 ));
3316 }
3317 }
3318 }
3319 }
3320
3321 fn call_function_named(
3322 &mut self,
3323 arg_count: usize,
3324 named_map: &[(usize, String)],
3325 line: usize,
3326 col: usize,
3327 ) -> Result<(), IonError> {
3328 let args_start = self.stack.len() - arg_count;
3330 let func_idx = args_start - 1;
3331 let func = self.stack[func_idx].clone();
3332 let raw_args: Vec<Value> = self.stack[args_start..].to_vec();
3333 self.stack.truncate(func_idx);
3334
3335 match &func {
3336 Value::Fn(ion_fn) => {
3337 let mut ordered = vec![None; ion_fn.params.len()];
3339 let mut pos_idx = 0;
3340 for (i, val) in raw_args.into_iter().enumerate() {
3341 if let Some((_, ref name)) = named_map.iter().find(|(pos, _)| *pos == i) {
3342 let param_idx = ion_fn
3344 .params
3345 .iter()
3346 .position(|p| &p.name == name)
3347 .ok_or_else(|| {
3348 IonError::runtime(
3349 format!(
3350 "{}'{}'{}'{}'",
3351 ion_str!("unknown parameter '"),
3352 name,
3353 ion_str!("' for function '"),
3354 ion_fn.name
3355 ),
3356 line,
3357 col,
3358 )
3359 })?;
3360 ordered[param_idx] = Some(val);
3361 } else {
3362 while pos_idx < ordered.len() && ordered[pos_idx].is_some() {
3364 pos_idx += 1;
3365 }
3366 if pos_idx < ordered.len() {
3367 ordered[pos_idx] = Some(val);
3368 pos_idx += 1;
3369 }
3370 }
3371 }
3372 self.env.push_scope();
3374 for (name, val) in &ion_fn.captures {
3375 self.env.define(name.clone(), val.clone(), false);
3376 }
3377 let reordered = match self.prepare_named_function_args(ion_fn, &ordered, line, col)
3378 {
3379 Ok(args) => args,
3380 Err(e) => {
3381 self.env.pop_scope();
3382 return Err(e);
3383 }
3384 };
3385 self.env.pop_scope();
3386 self.stack.push(func.clone());
3388 for arg in &reordered {
3389 self.stack.push(arg.clone());
3390 }
3391 self.call_function(reordered.len(), line, col)
3392 }
3393 Value::BuiltinFn(_, f) => {
3394 let result = f(&raw_args).map_err(|e| IonError::runtime(e, line, col))?;
3396 self.stack.push(result);
3397 Ok(())
3398 }
3399 Value::BuiltinClosure(_, f) => {
3400 let result = f
3401 .call(&raw_args)
3402 .map_err(|e| IonError::runtime(e, line, col))?;
3403 self.stack.push(result);
3404 Ok(())
3405 }
3406 _ => Err(IonError::type_err(
3407 format!("cannot call {}", func.type_name()),
3408 line,
3409 col,
3410 )),
3411 }
3412 }
3413
3414 #[cfg(feature = "concurrency")]
3415 fn builtin_timeout(&self, args: &[Value], line: usize, col: usize) -> Result<Value, IonError> {
3416 if args.len() < 2 {
3417 return Err(IonError::runtime(
3418 ion_str!("timeout(ms, fn) requires 2 arguments"),
3419 line,
3420 col,
3421 ));
3422 }
3423 let ms = args[0].as_int().ok_or_else(|| {
3424 IonError::runtime(
3425 ion_str!("timeout: first argument must be int (ms)"),
3426 line,
3427 col,
3428 )
3429 })?;
3430 let func = args[1].clone();
3431 let captured_env = self.env.capture();
3432 let cancel_flag = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
3433 let task = crate::async_rt::spawn_task_with_cancel(cancel_flag, move |flag| {
3434 let mut child = crate::interpreter::Interpreter::new();
3435 child.cancel_flag = Some(flag);
3436 for (name, val) in captured_env {
3437 child.env.define(name, val, false);
3438 }
3439 let program = crate::ast::Program {
3441 stmts: vec![crate::ast::Stmt {
3442 kind: crate::ast::StmtKind::ExprStmt {
3443 expr: crate::ast::Expr {
3444 kind: crate::ast::ExprKind::Call {
3445 func: Box::new(crate::ast::Expr {
3446 kind: crate::ast::ExprKind::Ident("__timeout_fn__".to_string()),
3447 span: crate::ast::Span { line: 0, col: 0 },
3448 }),
3449 args: vec![],
3450 },
3451 span: crate::ast::Span { line: 0, col: 0 },
3452 },
3453 has_semi: false,
3454 },
3455 span: crate::ast::Span { line: 0, col: 0 },
3456 }],
3457 };
3458 child.env.define("__timeout_fn__".to_string(), func, false);
3459 child.eval_program(&program)
3460 });
3461 match task.join_timeout(std::time::Duration::from_millis(ms as u64)) {
3462 Some(Ok(val)) => Ok(Value::Option(Some(Box::new(val)))),
3463 Some(Err(e)) => Err(e),
3464 None => {
3465 task.cancel();
3466 Ok(Value::Option(None))
3467 }
3468 }
3469 }
3470}