use crate::tree::AsmNode::*;
use crate::tree::*;
use crate::Assembler;
use std::collections::HashMap;
pub fn expand_constants(asm: &mut Assembler) {
let mut all_constants: Vec<String> = vec![];
let mut had_error = false;
let mut register_constants_in_list = | node: &AsmNode | -> Option<AsmNode> {
match node {
Source{code, meta} => {
if &code[0] == "@constant" {
if code.len() == 2 {
all_constants.push(code[1].clone());
None
} else {
had_error = true;
Some(Error{msg: "Error, @constant directive should have a single argument that is its constant.".to_string(), meta: meta.clone()})
}
} else {
None
}
},
_ => None,
}
};
asm.root.traverse_tree(&mut register_constants_in_list);
if had_error {
return;
}
let mut computed_constants: HashMap<String, Result<Vec<u8>, &str>> = HashMap::new();
for constant in all_constants {
if !computed_constants.contains_key(&constant) {
computed_constants.insert(constant.clone(), match asm.format_string_into_number(&constant) {
Some(num) => Ok(num),
None => Err("Error, unable to read number."),
});
}
}
let mut apply_computed_constants = | node: &AsmNode | -> Option<AsmNode> {
match node {
Source{code, meta} => {
if &code[0] == "@constant" {
match computed_constants.get(&code[1]).unwrap() {
Ok(num) => Some(Raw(num.clone())),
Err(s) => Some(Error{msg: s.to_string(), meta: meta.clone()}),
}
} else {
None
}
},
_ => None
}
};
asm.root.traverse_tree(&mut apply_computed_constants);
}
pub fn decode_raw_bytes(asm: &mut Assembler) {
fn decoding_raw_bytes(node: &AsmNode) -> Option<AsmNode> {
match node {
Source{code, meta} => {
if &code[0] == "@rawbytes" {
let mut data: Vec<u8> = vec![];
for byte in code.iter().skip(1) {
match u8::from_str_radix(byte, 16) {
Ok(num) => {data.push(num);},
Err(_) => {
return Some(Error{msg: format!("Error, unable to read byte {} in @rawbyte directive.", byte), meta: meta.clone()});
},
}
}
Some(Raw(data))
} else {
None
}
},
_ => None,
}
}
asm.root.traverse_tree(&mut decoding_raw_bytes);
}
#[test]
fn test_constants() {
let mut asm = Assembler::from_text("@constant 10\n@constant 0x10");
assert_eq!(asm.set_word_size(8), None);
expand_constants(&mut asm);
assert_eq!(asm.root.to_string(), "0x0A \n0x10 \n")
}
#[test]
fn test_raw_bytes() {
let mut asm = Assembler::from_text("@rawbytes 10 1 99");
decode_raw_bytes(&mut asm);
assert_eq!(asm.root.to_string(), "0x10 0x01 0x99 \n");
}