Skip to content

Commit f13d136

Browse files
Refactor: Unify collections whit builtins.
1 parent 77a2c32 commit f13d136

3 files changed

Lines changed: 219 additions & 251 deletions

File tree

compiler/src/modules/vm/builtins.rs

Lines changed: 219 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,24 @@ use super::VM;
66
use super::types::*;
77

88
use core::cell::RefCell;
9-
use alloc::{string::String, vec::Vec, vec, rc::Rc};
9+
use alloc::{string::{String, ToString}, vec::Vec, vec, rc::Rc};
10+
use crate::modules::fx::FxHashSet as HashSet;
11+
12+
fn normalize_index(i: i64, len: usize) -> usize {
13+
(if i < 0 { len as i64 + i } else { i }) as usize
14+
}
15+
16+
enum SliceSource { List(Vec<Val>), Tuple(Vec<Val>), Str(Vec<char>) }
17+
18+
impl SliceSource {
19+
fn len(&self) -> i64 {
20+
match self {
21+
Self::List(v) => v.len() as i64,
22+
Self::Tuple(v) => v.len() as i64,
23+
Self::Str(v) => v.len() as i64,
24+
}
25+
}
26+
}
1027

1128
impl<'a> VM<'a> {
1229

@@ -399,4 +416,205 @@ impl<'a> VM<'a> {
399416
_ => return Err(VmErr::Type("list() argument must be iterable")),
400417
})
401418
}
419+
420+
fn alloc_set(&mut self, items: Vec<Val>) -> Result<Val, VmErr> {
421+
let mut set = HashSet::with_capacity_and_hasher(items.len(), Default::default());
422+
for v in items { set.insert(v); }
423+
self.heap.alloc(HeapObj::Set(Rc::new(RefCell::new(set))))
424+
}
425+
426+
pub fn build_set(&mut self, op: u16) -> Result<(), VmErr> {
427+
let items = self.pop_n(op as usize)?;
428+
let val = self.alloc_set(items)?;
429+
self.push(val); Ok(())
430+
}
431+
432+
pub fn build_slice(&mut self, op: u16) -> Result<(), VmErr> {
433+
let step = if op == 3 { self.pop()? } else { Val::none() };
434+
let stop = self.pop()?;
435+
let start = self.pop()?;
436+
let val = self.heap.alloc(HeapObj::Slice(start, stop, step))?;
437+
self.push(val); Ok(())
438+
}
439+
440+
pub fn unpack_ex(&mut self, op: u16) -> Result<(), VmErr> {
441+
let obj = self.pop()?;
442+
if !obj.is_heap() { return Err(cold_type("cannot unpack non-iterable")); }
443+
let items: Vec<Val> = match self.heap.get(obj) {
444+
HeapObj::List(v) => v.borrow().clone(),
445+
HeapObj::Tuple(v) => v.clone(),
446+
_ => return Err(cold_type("cannot unpack non-iterable")),
447+
};
448+
let before = (op >> 8) as usize;
449+
let after = (op & 0xFF) as usize;
450+
if items.len() < before + after {
451+
return Err(cold_value("not enough values to unpack"));
452+
}
453+
let mid = items.len() - after;
454+
for &v in items[mid..].iter().rev() { self.push(v); }
455+
let star = self.heap.alloc(HeapObj::List(Rc::new(RefCell::new(
456+
items[before..mid].to_vec()
457+
))))?;
458+
self.push(star);
459+
for &v in items[..before].iter().rev() { self.push(v); }
460+
Ok(())
461+
}
462+
463+
pub fn call_dict(&mut self, op: u16) -> Result<(), VmErr> {
464+
if op == 0 {
465+
let val = self.heap.alloc(HeapObj::Dict(Rc::new(RefCell::new(DictMap::new()))))?;
466+
self.push(val);
467+
} else {
468+
let args = self.pop_n((op as usize) * 2)?;
469+
let mut dm = DictMap::with_capacity(op as usize);
470+
for pair in args.chunks(2) { dm.insert(pair[0], pair[1]); }
471+
let val = self.heap.alloc(HeapObj::Dict(Rc::new(RefCell::new(dm))))?;
472+
self.push(val);
473+
}
474+
Ok(())
475+
}
476+
477+
pub fn call_set(&mut self, op: u16) -> Result<(), VmErr> {
478+
if op == 0 {
479+
let val = self.alloc_set(Vec::new())?;
480+
self.push(val);
481+
} else {
482+
let o = self.pop()?;
483+
let src: Vec<Val> = if o.is_heap() {
484+
match self.heap.get(o) {
485+
HeapObj::List(v) => v.borrow().clone(),
486+
HeapObj::Tuple(v) => v.clone(),
487+
HeapObj::Set(v) => v.borrow().iter().cloned().collect(),
488+
HeapObj::Str(s) => {
489+
let s = s.clone();
490+
self.str_to_char_vals(&s)?
491+
},
492+
_ => return Err(cold_type("set() argument must be iterable")),
493+
}
494+
} else {
495+
return Err(cold_type("set() argument must be iterable"));
496+
};
497+
let val = self.alloc_set(src)?;
498+
self.push(val);
499+
}
500+
Ok(())
501+
}
502+
503+
pub fn get_item(&mut self) -> Result<bool, VmErr> {
504+
let idx = self.pop()?;
505+
let obj = self.pop()?;
506+
507+
if idx.is_heap()
508+
&& let HeapObj::Slice(start, stop, step) = self.heap.get(idx).clone() {
509+
let v = self.slice_val(obj, start, stop, step)?;
510+
self.push(v);
511+
return Ok(true);
512+
}
513+
514+
if obj.is_heap() && idx.is_int()
515+
&& let HeapObj::Str(s) = self.heap.get(obj) {
516+
let chars: Vec<char> = s.chars().collect();
517+
let i = idx.as_int();
518+
let ui = normalize_index(i, chars.len());
519+
let c = chars.get(ui).copied().ok_or(cold_value("string index out of range"))?;
520+
let val = self.heap.alloc(HeapObj::Str(c.to_string()))?;
521+
self.push(val);
522+
return Ok(true);
523+
}
524+
525+
let v = self.getitem_val(obj, idx)?;
526+
self.push(v);
527+
Ok(false)
528+
}
529+
530+
fn slice_val(&mut self, obj: Val, start: Val, stop: Val, step: Val) -> Result<Val, VmErr> {
531+
if !obj.is_heap() { return Err(cold_type("slice requires a sequence")); }
532+
let st = if step.is_none() { 1 } else if step.is_int() { step.as_int() } else {
533+
return Err(cold_type("slice step must be an integer"));
534+
};
535+
if st == 0 { return Err(cold_value("slice step cannot be zero")); }
536+
537+
let source = match self.heap.get(obj) {
538+
HeapObj::List(v) => SliceSource::List(v.borrow().clone()),
539+
HeapObj::Tuple(v) => SliceSource::Tuple(v.clone()),
540+
HeapObj::Str(s) => SliceSource::Str(s.chars().collect()),
541+
_ => return Err(cold_type("object is not sliceable")),
542+
};
543+
544+
let len = source.len();
545+
546+
let clamp = |v: Val, def: i64| -> i64 {
547+
if v.is_none() { def }
548+
else if v.is_int() { let i = v.as_int(); if i < 0 { (len+i).max(0) } else { i.min(len) } }
549+
else { def }
550+
};
551+
552+
let (s, e) = if st > 0 {
553+
(clamp(start, 0), clamp(stop, len))
554+
} else {
555+
(clamp(start, len - 1), clamp(stop, -1))
556+
};
557+
558+
let mut indices = Vec::new();
559+
let mut cur = s;
560+
if st > 0 { while cur < e { indices.push(cur as usize); cur += st; } }
561+
else { while cur > e { indices.push(cur as usize); cur += st; } }
562+
563+
let pick = |v: &[Val]| -> Vec<Val> {
564+
indices.iter().filter_map(|&i| v.get(i).copied()).collect()
565+
};
566+
567+
match source {
568+
SliceSource::List(v) => self.heap.alloc(HeapObj::List(Rc::new(RefCell::new(pick(&v))))),
569+
SliceSource::Tuple(v) => self.heap.alloc(HeapObj::Tuple(pick(&v))),
570+
SliceSource::Str(chars) => {
571+
let sliced: String = indices.iter().filter_map(|&i| chars.get(i)).collect();
572+
self.heap.alloc(HeapObj::Str(sliced))
573+
}
574+
}
575+
}
576+
577+
pub fn getitem_val(&self, obj: Val, idx: Val) -> Result<Val, VmErr> {
578+
if !obj.is_heap() { return Err(cold_type("object is not subscriptable")); }
579+
match self.heap.get(obj) {
580+
HeapObj::List(v) => {
581+
if !idx.is_int() { return Err(cold_type("list indices must be integers")); }
582+
let b = v.borrow(); let i = idx.as_int();
583+
let ui = normalize_index(i, b.len());
584+
b.get(ui).copied().ok_or(cold_value("list index out of range"))
585+
}
586+
HeapObj::Tuple(v) => {
587+
if !idx.is_int() { return Err(cold_type("tuple indices must be integers")); }
588+
let i = idx.as_int();
589+
let ui = normalize_index(i, v.len());
590+
v.get(ui).copied().ok_or(cold_value("tuple index out of range"))
591+
}
592+
HeapObj::Dict(p) => {
593+
p.borrow().get(&idx).copied()
594+
.ok_or(cold_value("key not found"))
595+
}
596+
_ => Err(cold_type("object is not subscriptable")),
597+
}
598+
}
599+
600+
pub fn store_item(&mut self) -> Result<(), VmErr> {
601+
let value = self.pop()?;
602+
let idx_val = self.pop()?;
603+
let cont = self.pop()?;
604+
if !cont.is_heap() { return Err(cold_type("object does not support item assignment")); }
605+
match self.heap.get_mut(cont) {
606+
HeapObj::List(v) => {
607+
if !idx_val.is_int() { return Err(cold_type("list indices must be integers")); }
608+
let mut b = v.borrow_mut();
609+
let i = idx_val.as_int();
610+
let ui = normalize_index(i, b.len());
611+
if ui >= b.len() { return Err(cold_value("list assignment index out of range")); }
612+
b[ui] = value;
613+
}
614+
HeapObj::Dict(p) => { p.borrow_mut().insert(idx_val, value); }
615+
HeapObj::Tuple(_) => return Err(cold_type("tuple does not support item assignment")),
616+
_ => return Err(cold_type("object does not support item assignment")),
617+
}
618+
Ok(())
619+
}
402620
}

0 commit comments

Comments
 (0)