String Instructions
Some checks failed
per-push tests / test-frontend (push) Blocked by required conditions
per-push tests / timed-decomposer-parse (push) Blocked by required conditions
per-push tests / test-utility (push) Blocked by required conditions
per-push tests / test-backend (push) Blocked by required conditions
per-push tests / build (push) Has been cancelled

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

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 0e21e4f822
3 changed files with 81 additions and 43 deletions

View file

@ -312,3 +312,15 @@ name = "cdr"
args = ["list"] args = ["list"]
output = "returns last element in cons cell" output = "returns last element in cons cell"
description = "takes an AST and returns last element in top level cons cell" description = "takes an AST and returns last element in top level cons cell"
[[instructions]]
name = "concat"
args = ["string_l", "string_r"]
output = "string_l+string_r"
description = "concatenates string r to string l and returns a new string"
[[instructions]]
name = "s_append"
args = ["parent", "child"]
output = ""
description = "append in place child character into parent string"

View file

@ -17,7 +17,6 @@
use core::ops::{Index, Deref, DerefMut}; use core::ops::{Index, Deref, DerefMut};
use core::ptr::NonNull; use core::ptr::NonNull;
use core::cell::RefCell;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec; use alloc::vec::Vec;
@ -141,8 +140,8 @@ pub enum Datum {
Symbol(String), Symbol(String),
Char(u8), Char(u8),
String(Vec<u8>), String(Vec<u8>),
Vector(RefCell<Vec<Gc<Datum>>>), Vector(Vec<Gc<Datum>>),
ByteVector(RefCell<Vec<u8>>), ByteVector(Vec<u8>),
None None
} }

View file

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