use std::collections::VecDeque;
use crate::errors::lpanic;
use crate::bbu::SymConv;
use crate::parser::ParsedOperation;
pub enum LexOperation<T: SymConv> {
Instruction(Box<dyn crate::bbu::ArchMcrInst<T>>),
}
impl<T: SymConv> std::fmt::Debug for LexOperation<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LexOperation::Instruction(ref i) => {
write!(f, "ArchMcrInst: {:02x?}", i.get_output_bytes())
}
}
}
}
impl<T: SymConv> LexOperation<T> {
pub fn extract_bytes(&self) -> Vec<u8> {
match self {
LexOperation::Instruction(a) => a.get_output_bytes(),
}
}
}
pub type LexIdLabel<T> = Vec<LexOperation<T>>;
#[derive(Debug)]
pub struct LexLabel<T: SymConv> {
pub name: String,
pub ops: LexIdLabel<T>,
}
#[derive(Debug)]
pub enum LexLabelType<T: SymConv> {
Base(LexIdLabel<T>),
Std(LexLabel<T>),
}
impl<T: SymConv> LexLabelType<T> {
pub fn extract(self) -> (LexIdLabel<T>, Option<String>) {
match self {
LexLabelType::Base(a) => (a, None),
LexLabelType::Std(b) => (b.ops, Some(b.name)),
}
}
}
#[derive(Debug)]
pub struct LexSection<T: SymConv> {
pub name: String,
pub labels: Vec<LexLabelType<T>>,
}
#[derive(Debug)]
pub struct Lexer<T: SymConv> {
q: VecDeque<ParsedOperation>,
d: Vec<LexSection<T>>,
cs: Option<LexSection<T>>,
cl: Option<LexLabelType<T>>,
p: crate::platform::Platform,
}
impl<T: SymConv> Lexer<T> {
fn push_label(&mut self) -> () {
if let Some(n) = self.cl.take() {
if let Some(ref mut p) = &mut self.cs {
p.labels.push(n);
}
}
}
fn gen_label(&mut self, name: String) -> () {
self.cl = Some(LexLabelType::Std(LexLabel {
name: name,
ops: vec![],
}));
}
fn push_section(&mut self) -> () {
self.push_label();
if let Some(n) = self.cs.take() {
self.d.push(n);
}
}
fn gen_section(&mut self, name: Option<Vec<String>>) -> () {
if let Some(mut n) = name {
if n.len() == 0 {
lpanic("improper arg amount passed");
}
self.cs = Some(LexSection {
name: n.remove(0),
labels: vec![],
});
self.cl = Some(LexLabelType::Base(vec![]));
} else {
lpanic("improper arg amount passed");
}
}
pub fn from_vdq(
q: VecDeque<ParsedOperation>,
p: crate::platform::Platform,
) -> Self {
Lexer {
q: q,
d: vec![],
cs: None,
cl: None,
p: p,
}
}
pub fn pop_vdq(&mut self) -> Vec<LexSection<T>> {
std::mem::replace(&mut self.d, Vec::new())
}
pub fn lex_full_queue(&mut self) -> Result<(), Box<dyn std::error::Error>> {
if self.cs.is_none() {
self.gen_section(Some(vec![".__defsection".to_string()]))
}
while let Some(i) = self.q.pop_front() {
if let ParsedOperation::Macro(j) = i {
if j.mcr.chars().last().unwrap() == ':' {
self.push_label();
let mut z = j.mcr.chars();
z.next_back();
self.gen_label(z.collect::<String>());
continue;
}
match j.mcr.to_lowercase().as_str() {
"byte" | "word" => {
self.push_macro(j);
}
"label" | "lbl" => {
self.push_label();
self.gen_label(j.args.unwrap()[0].clone());
}
"section" | "sec" => {
self.push_section();
self.gen_section(j.args);
}
"text" | "code" => {
self.push_section();
self.gen_section(Some(vec![".text".to_string()]));
}
"bss" | "data?" => {
self.push_section();
self.gen_section(Some(vec![".bss".to_string()]));
}
"rodata" | "const" => {
self.push_section();
self.gen_section(Some(vec![".rodata".to_string()]));
}
"data" | "dat" => {
self.push_section();
self.gen_section(Some(vec![".data".to_string()]));
}
_ => lpanic("lexer: unknown macro"),
}
} else if let ParsedOperation::Instruction(j) = i {
self.push_instruction(j);
}
}
self.push_section();
Ok(())
}
fn push_macro(&mut self, i: crate::parser::ParsedMacro) {
if let Some(ref mut j) = &mut self.cl {
let op: LexOperation<T> = match self.p.arch {
#[cfg(feature = "chip8-raw")]
crate::platform::PlatformArch::ChipEightRaw => {
LexOperation::Instruction(crate::bbu::chip8_raw::get_macro(i))
}
#[cfg(feature = "chip8")]
crate::platform::PlatformArch::ChipEight => {
LexOperation::Instruction(crate::bbu::chip8::get_macro(i))
} };
match j {
LexLabelType::Base(ref mut a) => a,
LexLabelType::Std(ref mut b) => &mut b.ops,
}
.push(op);
}
}
fn push_instruction(&mut self, i: crate::parser::ParsedInstruction) -> () {
if let Some(ref mut j) = &mut self.cl {
let op: LexOperation<T> = match self.p.arch {
#[cfg(feature = "chip8-raw")]
crate::platform::PlatformArch::ChipEightRaw => {
LexOperation::Instruction(crate::bbu::chip8_raw::get_instruction::<T>(i))
}
#[cfg(feature = "chip8")]
crate::platform::PlatformArch::ChipEight => {
LexOperation::Instruction(crate::bbu::chip8::get_instruction::<T>(i))
} };
match j {
LexLabelType::Base(ref mut a) => a,
LexLabelType::Std(ref mut b) => &mut b.ops,
}
.push(op);
}
}
}