String Instructions
All checks were successful
per-push tests / build (push) Successful in 47s
per-push tests / test-utility (push) Successful in 53s
per-push tests / test-frontend (push) Successful in 59s
per-push tests / test-backend (push) Successful in 43s
per-push tests / timed-decomposer-parse (push) Successful in 51s

The following instructions are modified to act on strings:
- INDEX: Now pulls a char out at index
- SUBSL: Now pulls a substring out of a source string
- INSER: Now inserts a char into a string at index
- LENGTH: Now returns length of a string

In addition to the above instructions, additional instructions
are now implemented to handle strings:
- CONCAT: appends a string onto another string
- S_APPEND: appends a char on to the end of a string

Fixes: #38

Signed-off-by: Ava Affine <ava@sunnypup.io>
This commit is contained in:
Ava Apples Affine 2025-07-29 18:16:10 +00:00
parent 63554191f8
commit ddb49788af
3 changed files with 81 additions and 43 deletions

View file

@ -24,7 +24,6 @@ use crate::instr as i;
use crate::util::{Operand, Program, Address};
use crate::heap::{Gc, Datum, Cons};
use core::cell::RefCell;
use core::ops::DerefMut;
use alloc::vec;
@ -345,8 +344,10 @@ impl VM {
Datum::Number(Number::Fra(Fraction(num as isize, 1))).into()
}),
i::MKVEC => self.expr = Datum::Vector(RefCell::from(vec![])).into(),
i::MKBVEC => self.expr = Datum::ByteVector(RefCell::from(vec![])).into(),
i::MKVEC => self.expr = Datum::Vector(vec![]).into(),
i::MKBVEC => self.expr = Datum::ByteVector(vec![]).into(),
i::INDEX => {
let Datum::Number(ref idx) = **access!(&instr.1[1]) else {
e!("illegal argument to INDEX instruction");
@ -357,31 +358,28 @@ impl VM {
}
let idx = idx.0.trunc() as usize;
match **access!(&instr.1[0]) {
Datum::Vector(ref v) => {
let a = (*v.borrow()[idx].clone()).clone();
self.expr = a.into();
},
Datum::ByteVector(ref bv) => {
let a = Datum::Char(bv.borrow()[idx]);
self.expr = a.into();
},
match *access!(&instr.1[0]).clone() {
Datum::Vector(ref v) =>
self.expr = (*v[idx].clone()).clone().into(),
Datum::ByteVector(ref bv) =>
self.expr = Datum::Char(bv[idx]).into(),
Datum::String(ref s) =>
self.expr = Datum::Char(s[idx]).into(),
Datum::Cons(ref l) => self.expr = l[idx].clone(),
_ => e!("illegal argument to INDEX instruction")
};
},
i::LENGTH => match **access!(&instr.1[0]) {
Datum::Vector(ref v) => {
let a = Datum::Number(Number::Fra(Fraction(
v.borrow().len() as isize, 1)));
self.expr = a.into();
},
Datum::ByteVector(ref bv) => {
let a = Datum::Number(Number::Fra(Fraction(
bv.borrow().len() as isize, 1)));
self.expr = a.into();
},
Datum::Vector(ref v) =>
self.expr = Datum::Number(Number::Fra(Fraction(
v.len() as isize, 1))).into(),
Datum::ByteVector(ref bv) =>
self.expr = Datum::Number(Number::Fra(Fraction(
bv.len() as isize, 1))).into(),
Datum::String(ref s) =>
self.expr = Datum::Number(Number::Fra(Fraction(
s.len() as isize, 1))).into(),
Datum::Cons(ref l) => self.expr =
Datum::Number(Number::Fra(Fraction(l.len() as isize, 1)))
.into(),
@ -411,17 +409,14 @@ impl VM {
let st = st.0.trunc() as usize;
let ed = ed.0.trunc() as usize;
match **access!(&instr.1[0]) {
Datum::Vector(ref v) => {
let a = Datum::Vector(RefCell::from(v.borrow()[st..ed].to_vec()));
self.expr = a.into();
},
Datum::ByteVector(ref bv) => {
let a = Datum::ByteVector(RefCell::from(bv.borrow()[st..ed].to_vec()));
self.expr = a.into();
},
Datum::Cons(ref a) => self.expr =
match access!(&instr.1[0]).clone().deref_mut() {
Datum::Vector(v) =>
self.expr = Datum::Vector(v[st..ed].to_vec()).into(),
Datum::ByteVector(bv) =>
self.expr = Datum::ByteVector(bv[st..ed].to_vec()).into(),
Datum::String(s) =>
self.expr = Datum::String(s[st..ed].to_vec()).into(),
Datum::Cons(a) => self.expr =
Datum::Cons(a.subsl(st as isize, ed as isize)).into(),
_ => e!("illegal argument to SUBSL instruction")
};
@ -439,18 +434,22 @@ impl VM {
let idx = idx.0.trunc() as usize;
match **access!(&instr.1[0]) {
Datum::Vector(ref v) => {
v.borrow_mut()
.insert(idx, access!(&instr.1[1])
.deep_copy());
match access!(&instr.1[0]).clone().deref_mut() {
Datum::Vector(v) => {
v.insert(idx, access!(&instr.1[1]).clone());
},
Datum::ByteVector(ref bv) => {
Datum::ByteVector(bv) => {
let Datum::Char(b) = **access!(&instr.1[1]) else {
e!("INSER instruction can only insert a byte into a bytevector");
};
bv.borrow_mut().insert(idx, b);
bv.insert(idx, b);
},
Datum::String(st) => {
let Datum::Char(b) = **access!(&instr.1[1]) else {
e!("INSER instruction can only insert a char into a string");
};
st.insert(idx, b);
}
_ => e!("illegal argument to INSER instruction")
}
},
@ -487,6 +486,34 @@ impl VM {
}
},
i::CONCAT => {
let Datum::String(ref left) = **access!(&instr.1[0]) else {
e!("illegal argument to CONCAT instruction");
};
let Datum::String(ref right) = **access!(&instr.1[1]) else {
e!("illegal argument to CONCAT instruction");
};
let (left, right) = unsafe { (str::from_utf8_unchecked(left).to_owned(),
str::from_utf8_unchecked(right)) };
self.expr = Datum::String((left + right).as_bytes().to_vec()).into();
},
i::S_APPEND => {
let mut left = access!(&instr.1[0]).clone();
let Datum::String(left) = left.deref_mut() else {
e!("illegal argument to S_APPEND instruction");
};
let Datum::Char(right) = **access!(&instr.1[1]) else {
e!("illegal argument to S_APPEND instruction");
};
left.push(right);
},
_ => {
e!("illegal instruction");
},