Hyphae: add assembler and disassembler
Some checks failed
per-push tests / timed-decomposer-parse (push) Blocked by required conditions
per-push tests / test-backend (push) Blocked by required conditions
per-push tests / build (push) Successful in 1m50s
per-push tests / test-utility (push) Has been cancelled
per-push tests / test-frontend (push) Has been cancelled

This commit adds hyphae binaries for an assembler and a disassembler
As well as some fixes for observed misbehavior during manual
verification.

The new binaries are hphc for compiling assmbly files and hphdump for
inspecting compiled hyphae binary.

Signed-off-by: Ava Affine <ava@sunnypup.io>
This commit is contained in:
Ava Apples Affine 2025-12-15 18:28:28 +00:00
parent 141ba43362
commit ad39e26945
5 changed files with 185 additions and 24 deletions

View file

@ -153,16 +153,16 @@ impl FromStr for Operand {
"$oper4" => Ok(Operand(Address::Oper4, 0)),
"true" => Ok(Operand(Address::Bool, 1)),
"false" => Ok(Operand(Address::Bool, 0)),
a if a.chars().nth(0).unwrap() == '%' &&
a.len() > 1 &&
a[1..].parse::<usize>().is_ok() =>
a if a.len() > 1 &&
a.chars().nth(0).unwrap() == '%' &&
a[1..].parse::<usize>().is_ok() =>
Ok(Operand(Address::Stack, a[1..].parse::<usize>().unwrap())),
a if a.chars().nth(0).unwrap() == '@' &&
a.len() > 1 &&
a[1..].parse::<usize>().is_ok() =>
a if a.len() > 1 &&
a.chars().nth(0).unwrap() == '@' &&
a[1..].parse::<usize>().is_ok() =>
Ok(Operand(Address::Instr, a[1..].parse::<usize>().unwrap())),
a if a.chars().nth(0).unwrap() == '\'' &&
a.len() == 3 &&
a if a.len() == 3 &&
a.chars().nth(0).unwrap() == '\'' &&
a.chars().nth(2).unwrap() == '\'' =>
Ok(Operand(Address::Char, a.chars().nth(1).unwrap() as usize)),
a if a.parse::<usize>().is_ok() =>
@ -232,7 +232,11 @@ impl Into<Vec<u8>> for Instruction {
impl FromStr for Instruction {
type Err = &'static str;
fn from_str(v: &str) -> Result<Self, Self::Err> {
let toks: Vec<&str> = v.trim().split(' ').collect();
let toks: Vec<&str> = v
.trim()
.split(' ')
.filter(|x| x.len() > 0)
.collect();
if toks.len() < 1 {
return Err("empty string");
}
@ -256,7 +260,7 @@ impl FromStr for Instruction {
impl Display for Instruction {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), E> {
write!(f, "{}\t", self.0)?;
write!(f, "{} \t", self.0)?;
if self.1.len() > 0 {
write!(f, "{}", self.1[0])?;
}
@ -304,6 +308,7 @@ impl TryFrom<&[u8]> for Program {
}
cur += 1;
while cur < value.len() {
let instruction: Instruction = value[cur..].try_into()?;
cur += instruction.byte_length() as usize;
prog.push(instruction);
@ -318,9 +323,13 @@ impl TryFrom<&[u8]> for Program {
impl Into<Vec<u8>> for Program {
fn into(self) -> Vec<u8> {
let mut res: Vec<u8> = vec![];
for instr in self.0 {
res.append(&mut instr.into())
let mut res: Vec<u8> = vec![DeserializerControlCode::DataChunk as u8];
for dat in self.0 {
res.append(&mut dat.into());
}
res.push(DeserializerControlCode::CodeChunk as u8);
for instr in self.1 {
res.append(&mut instr.into());
}
res
}
@ -337,12 +346,12 @@ impl Display for Program {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), E> {
write!(f, "DATA:\n")?;
for i in self.0.iter() {
write!(f, " {}", i)?;
write!(f, " {}\n", i)?;
}
write!(f, "\nCODE:\n")?;
write!(f, "CODE:\n")?;
for i in self.1.iter() {
write!(f, " {}", i)?;
write!(f, " {}\n", i)?;
}
Ok(())
@ -354,7 +363,10 @@ impl FromStr for Program {
fn from_str(val: &str) -> Result<Self, Self::Err> {
//let mut datum = vec![];
let mut instrs = vec![];
let lines: Vec<&str> = val.split('\n').collect();
let lines: Vec<&str> = val
.split('\n')
.filter(|x| x.len() > 0)
.collect();
let mut cur = 0;
let mut toggle = 0;
@ -368,7 +380,7 @@ impl FromStr for Program {
match lines[cur] {
"DATA:" => return Err("datum parser unimplemented"),
"CODE:" => toggle = 1,
a => return Err("unknown section in document: "),
_ => return Err("unknown section in document: "),
}
}