Skip to content

Commit 9d117ed

Browse files
Feat: Add list OpCodes and IT.
1 parent 8c8cf63 commit 9d117ed

5 files changed

Lines changed: 178 additions & 2 deletions

File tree

compiler/src/modules/vm/handlers/attr.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ impl<'a> VM<'a> {
2626
("str", "endswith") => BuiltinMethodId::StrEndswith,
2727
("str", "find") => BuiltinMethodId::StrFind,
2828
("str", "count") => BuiltinMethodId::StrCount,
29+
("list", "sort") => BuiltinMethodId::ListSort,
30+
("list", "reverse") => BuiltinMethodId::ListReverse,
31+
("list", "pop") => BuiltinMethodId::ListPop,
32+
("list", "insert") => BuiltinMethodId::ListInsert,
33+
("list", "remove") => BuiltinMethodId::ListRemove,
34+
("list", "index") => BuiltinMethodId::ListIndex,
35+
("list", "count") => BuiltinMethodId::ListCount,
2936
(ty, attr) => {
3037
return Err(attr_not_found(ty, attr));
3138
}

compiler/src/modules/vm/handlers/function.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,154 @@ impl<'a> VM<'a> {
378378
self.push(Val::int(n));
379379
Ok(())
380380
}
381+
ListSort => {
382+
if !positional.is_empty() {
383+
return Err(VmErr::Type("sort() takes no arguments"));
384+
}
385+
let items = match self.heap.get(recv) {
386+
HeapObj::List(rc) => rc.borrow().clone(),
387+
_ => return Err(VmErr::Type("sort: receiver is not a list")),
388+
};
389+
let mut sorted = items;
390+
let mut sort_err: Option<VmErr> = None;
391+
sorted.sort_by(|&a, &b| {
392+
if sort_err.is_some() { return core::cmp::Ordering::Equal; }
393+
match self.lt_vals(a, b) {
394+
Ok(true) => core::cmp::Ordering::Less,
395+
Ok(false) => match self.lt_vals(b, a) {
396+
Ok(true) => core::cmp::Ordering::Greater,
397+
Ok(false) => core::cmp::Ordering::Equal,
398+
Err(e) => { sort_err = Some(e); core::cmp::Ordering::Equal }
399+
},
400+
Err(e) => { sort_err = Some(e); core::cmp::Ordering::Equal }
401+
}
402+
});
403+
if let Some(e) = sort_err { return Err(e); }
404+
match self.heap.get_mut(recv) {
405+
HeapObj::List(rc) => *rc.borrow_mut() = sorted,
406+
_ => return Err(VmErr::Type("sort: receiver is not a list")),
407+
}
408+
self.mark_impure();
409+
self.push(Val::none());
410+
Ok(())
411+
}
412+
ListReverse => {
413+
if !positional.is_empty() {
414+
return Err(VmErr::Type("reverse() takes no arguments"));
415+
}
416+
match self.heap.get_mut(recv) {
417+
HeapObj::List(rc) => rc.borrow_mut().reverse(),
418+
_ => return Err(VmErr::Type("reverse: receiver is not a list")),
419+
}
420+
self.mark_impure();
421+
self.push(Val::none());
422+
Ok(())
423+
}
424+
ListPop => {
425+
if positional.len() > 1 {
426+
return Err(VmErr::Type("pop() takes at most one argument"));
427+
}
428+
let popped = match self.heap.get_mut(recv) {
429+
HeapObj::List(rc) => {
430+
let mut b = rc.borrow_mut();
431+
if b.is_empty() {
432+
return Err(VmErr::Value("pop from empty list"));
433+
}
434+
if positional.is_empty() {
435+
b.pop().unwrap()
436+
} else {
437+
if !positional[0].is_int() {
438+
return Err(VmErr::Type("list indices must be integers"));
439+
}
440+
let i = positional[0].as_int();
441+
let ui = if i < 0 { (b.len() as i64 + i) as usize } else { i as usize };
442+
if ui >= b.len() {
443+
return Err(VmErr::Value("pop index out of range"));
444+
}
445+
b.remove(ui)
446+
}
447+
}
448+
_ => return Err(VmErr::Type("pop: receiver is not a list")),
449+
};
450+
self.mark_impure();
451+
self.push(popped);
452+
Ok(())
453+
}
454+
ListInsert => {
455+
if positional.len() != 2 {
456+
return Err(VmErr::Type("insert() takes exactly 2 arguments"));
457+
}
458+
if !positional[0].is_int() {
459+
return Err(VmErr::Type("list indices must be integers"));
460+
}
461+
let item = positional[1];
462+
match self.heap.get_mut(recv) {
463+
HeapObj::List(rc) => {
464+
let mut b = rc.borrow_mut();
465+
let i = positional[0].as_int();
466+
let ui = if i < 0 {
467+
(b.len() as i64 + i).max(0) as usize
468+
} else {
469+
(i as usize).min(b.len())
470+
};
471+
b.insert(ui, item);
472+
}
473+
_ => return Err(VmErr::Type("insert: receiver is not a list")),
474+
}
475+
self.mark_impure();
476+
self.push(Val::none());
477+
Ok(())
478+
}
479+
ListRemove => {
480+
if positional.len() != 1 {
481+
return Err(VmErr::Type("remove() takes exactly one argument"));
482+
}
483+
let target = positional[0];
484+
let items = match self.heap.get(recv) {
485+
HeapObj::List(rc) => rc.borrow().clone(),
486+
_ => return Err(VmErr::Type("remove: receiver is not a list")),
487+
};
488+
let pos = items.iter()
489+
.position(|&v| eq_vals_with_heap(v, target, &self.heap))
490+
.ok_or(VmErr::Value("list.remove: value not found"))?;
491+
match self.heap.get_mut(recv) {
492+
HeapObj::List(rc) => { rc.borrow_mut().remove(pos); }
493+
_ => return Err(VmErr::Type("remove: receiver is not a list")),
494+
}
495+
self.mark_impure();
496+
self.push(Val::none());
497+
Ok(())
498+
}
499+
ListIndex => {
500+
if positional.len() != 1 {
501+
return Err(VmErr::Type("index() takes exactly one argument"));
502+
}
503+
let target = positional[0];
504+
let idx = match self.heap.get(recv) {
505+
HeapObj::List(rc) => {
506+
rc.borrow().iter().position(|&v| eq_vals_with_heap(v, target, &self.heap))
507+
.map(|i| i as i64)
508+
.ok_or(VmErr::Value("value not found in list"))?
509+
}
510+
_ => return Err(VmErr::Type("index: receiver is not a list")),
511+
};
512+
self.push(Val::int(idx));
513+
Ok(())
514+
}
515+
ListCount => {
516+
if positional.len() != 1 {
517+
return Err(VmErr::Type("count() takes exactly one argument"));
518+
}
519+
let target = positional[0];
520+
let n = match self.heap.get(recv) {
521+
HeapObj::List(rc) => {
522+
rc.borrow().iter().filter(|&&v| eq_vals_with_heap(v, target, &self.heap)).count() as i64
523+
}
524+
_ => return Err(VmErr::Type("count: receiver is not a list")),
525+
};
526+
self.push(Val::int(n));
527+
Ok(())
528+
}
381529
}
382530
}
383531

compiler/src/modules/vm/ops.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,14 @@ impl<'a> VM<'a> {
135135
BuiltinMethodId::StrStartswith => "<built-in method startswith>".into(),
136136
BuiltinMethodId::StrEndswith => "<built-in method endswith>".into(),
137137
BuiltinMethodId::StrFind => "<built-in method find>".into(),
138-
BuiltinMethodId::StrCount => "<built-in method count>".into(),
138+
BuiltinMethodId::StrCount => "<built-in method count>".into(),
139+
BuiltinMethodId::ListSort => "<built-in method sort>".into(),
140+
BuiltinMethodId::ListReverse => "<built-in method reverse>".into(),
141+
BuiltinMethodId::ListPop => "<built-in method pop>".into(),
142+
BuiltinMethodId::ListInsert => "<built-in method insert>".into(),
143+
BuiltinMethodId::ListRemove => "<built-in method remove>".into(),
144+
BuiltinMethodId::ListIndex => "<built-in method index>".into(),
145+
BuiltinMethodId::ListCount => "<built-in method count>".into(),
139146
},
140147
HeapObj::Slice(s, e, st) => format!("slice({}, {}, {})",
141148
self.display(*s), self.display(*e), self.display(*st)),

compiler/src/modules/vm/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,13 @@ pub enum BuiltinMethodId {
479479
StrEndswith,
480480
StrFind,
481481
StrCount,
482+
ListSort,
483+
ListReverse,
484+
ListPop,
485+
ListInsert,
486+
ListRemove,
487+
ListIndex,
488+
ListCount,
482489
}
483490

484491
/*

compiler/tests/cases/vm.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,5 +359,12 @@
359359
{"src": "print('hello'.startswith('he'))", "output": ["True"], "result": "None"},
360360
{"src": "print('hello'.endswith('lo'))", "output": ["True"], "result": "None"},
361361
{"src": "print('hello'.find('ll'))", "output": ["2"], "result": "None"},
362-
{"src": "print('hello'.count('l'))", "output": ["2"], "result": "None"}
362+
{"src": "print('hello'.count('l'))", "output": ["2"], "result": "None"},
363+
{"src": "x = [3,1,2]\nx.sort()\nprint(x)", "output": ["[1, 2, 3]"], "result": "None"},
364+
{"src": "x = [1,2,3]\nx.reverse()\nprint(x)", "output": ["[3, 2, 1]"], "result": "None"},
365+
{"src": "x = [1,2,3]\nprint(x.pop())\nprint(x)", "output": ["3", "[1, 2]"], "result": "None"},
366+
{"src": "x = [1,2,3]\nx.insert(1, 99)\nprint(x)", "output": ["[1, 99, 2, 3]"], "result": "None"},
367+
{"src": "x = [1,2,2,3]\nx.remove(2)\nprint(x)", "output": ["[1, 2, 3]"], "result": "None"},
368+
{"src": "print([1,2,3].index(2))", "output": ["1"], "result": "None"},
369+
{"src": "print([1,2,2,3].count(2))", "output": ["2"], "result": "None"}
363370
]

0 commit comments

Comments
 (0)