use crate::asm::data::literal::{Label, RoutineName}; use crate::asm::error::Error; use crate::asm::instr::Op; use crate::asm::instr::cond::parse_cond; use crate::asm::instr::op::{AsmModule, ParseOpResult}; use crate::asm::parse::arg_parser::ArgParser; use crate::asm::parse::parse_data::{parse_label, parse_rd}; use crate::asm::parse::sexp_expect::expect_string_atom; pub fn parse_op(keyword: &str, far: bool, mut arg_tokens: ArgParser, parsers: &[Box]) -> Result { Ok(match keyword { "j" => { let dest = parse_label(arg_tokens.next())?; if far { Op::FarJump(dest) } else { Op::Jump(dest) } } "call" => { let dest = RoutineName(arg_tokens.next_string()?); let mut args = vec![]; for t in arg_tokens { args.push(parse_rd(Some(t))?); } Op::Call(dest, args) } "ret" => { let mut args = vec![]; for t in arg_tokens { args.push(parse_rd(Some(t))?); } Op::Ret(args) } "routine" => { let dest = RoutineName(arg_tokens.next_string()?); Op::Routine(dest) } "s" => { Op::Skip(arg_tokens.next_rd()?) } "sif" => { let cond = parse_cond(&arg_tokens.next_string()?)?; let offs = arg_tokens.next_rd()?; Op::SkipIf(cond, offs) } "jif" => { let cond = parse_cond(&arg_tokens.next_string()?)?; let dest = parse_label(arg_tokens.next())?; Op::JumpIf(cond, dest) } "barrier" => { Op::Barrier(match arg_tokens.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), }) } "fault" => { Op::Fault(match arg_tokens.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), }) } "ld" => { Op::Move { dst: arg_tokens.next_wr()?, src: arg_tokens.next_rd()?, } } other => { if let Some(label) = other.strip_prefix(':') { let label = Label::Named(label.to_string()); if far { Op::FarLabel(label) } else { Op::Label(label) } } else { for p in parsers { arg_tokens = match p.parse_op(keyword, arg_tokens) { Ok(ParseOpResult::Parsed(op)) => return Ok(Op::Extension(op)), Ok(ParseOpResult::Unknown(to_reuse)) => { if to_reuse.parsing_started() { panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword); } to_reuse } Err(err) => { return Err(err); } } } return Err(Error::Parse(format!("Unknown instruction: {}", other).into())); } } }) }