use sexp::Sexp; use crate::asm::data::literal::{Label, RoutineName}; use crate::asm::error::{AsmError, Error}; use crate::asm::instr::{OpWrapper, Op}; use crate::asm::instr::cond::parse_cond; use crate::asm::instr::op::{AsmModule, ParseOpResult}; use crate::asm::parse::parse_data::{parse_label, parse_rd, parse_wr}; use crate::asm::parse::sexp_expect::expect_string_atom; use crate::asm::parse::arg_parser::ArgParser; 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 { OpWrapper::Op(Op::FarJump(dest)) } else { OpWrapper::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))?); } OpWrapper::Op(Op::Call(dest, args)) } "ret" => { let mut args = vec![]; for t in arg_tokens { args.push(parse_rd(Some(t))?); } OpWrapper::Op(Op::Ret(args)) } "routine" => { let dest = RoutineName(arg_tokens.next_string()?); OpWrapper::Op(Op::Routine(dest)) } "s" => { OpWrapper::Op(Op::Skip(arg_tokens.next_rd()?)) } "sif" => { let cond = parse_cond(&arg_tokens.next_string()?)?; let offs = arg_tokens.next_rd()?; OpWrapper::Op(Op::SkipIf(cond, offs)) } "jif" => { let cond = parse_cond(&arg_tokens.next_string()?)?; let dest = parse_label(arg_tokens.next())?; OpWrapper::JumpIf(cond, dest) } "barrier" => { OpWrapper::Op(Op::Barrier(match arg_tokens.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), })) } "fault" => { OpWrapper::Op(Op::Fault(match arg_tokens.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), })) } "ld" => { OpWrapper::Op(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 { OpWrapper::Op(Op::FarLabel(label)) } else { OpWrapper::Label(label) } } else { for p in parsers { arg_tokens = match p.parse_op(keyword, arg_tokens) { Ok(ParseOpResult::Parsed(op)) => return Ok(OpWrapper::Op(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())); } } }) }