use sexp::{Atom, Sexp}; use crate::asm::data::literal::{Label, RoutineName}; use crate::asm::error::Error; use crate::asm::instr::cond::parse_cond; use crate::asm::instr::Op; 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; use crate::builtin::defs::BuiltinOp; use crate::module::{CrsnExtension, ParseOpRes}; #[derive(Debug, Clone)] pub struct BuiltinOps { _internal: () } impl BuiltinOps { pub fn new() -> Box { Box::new(Self { _internal: () }) } } impl CrsnExtension for BuiltinOps { fn name(&self) -> &'static str { "builtin" } fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result { Ok(ParseOpRes::Parsed(Op::BuiltIn(match keyword { "nop" => { BuiltinOp::Nop } "halt" => { BuiltinOp::Halt } "j" => { let dest = parse_label(args.next())?; BuiltinOp::Jump(dest) } "fj" => { let dest = parse_label(args.next())?; BuiltinOp::FarJump(dest) } "call" => { let dest = RoutineName(args.next_string()?); let mut call_args = vec![]; for t in args { call_args.push(parse_rd(Some(t))?); } BuiltinOp::Call(dest, call_args) } "ret" => { let mut ret_vals = vec![]; for t in args { ret_vals.push(parse_rd(Some(t))?); } BuiltinOp::Ret(ret_vals) } "routine" => { let dest = RoutineName(args.next_string()?); BuiltinOp::Routine(dest) } "s" => { BuiltinOp::Skip(args.next_rd()?) } "sif" => { let cond = parse_cond(&args.next_string()?)?; let offs = args.next_rd()?; BuiltinOp::SkipIf(cond, offs) } "jif" => { let cond = parse_cond(&args.next_string()?)?; let dest = parse_label(args.next())?; BuiltinOp::JumpIf(cond, dest) } "fjif" => { let cond = parse_cond(&args.next_string()?)?; let dest = parse_label(args.next())?; BuiltinOp::FarJumpIf(cond, dest) } "barrier" => { BuiltinOp::Barrier(match args.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), }) } "fault" => { BuiltinOp::Fault(match args.next() { None => None, Some(s) => Some(expect_string_atom(Some(s))?.into()), }) } "ld" => { BuiltinOp::Move { dst: args.next_wr()?, src: args.next_rd()?, } } "sst" => { BuiltinOp::StoreStatus { dst: args.next_wr()?, } } "sld" => { BuiltinOp::LoadStatus { src: args.next_rd()?, } } "drop" => { BuiltinOp::Drop(args.next_rdobj()?) } "far" => { if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() { if let Some(label) = label.strip_prefix(':') { let label = Label::Named(label.to_string()); BuiltinOp::FarLabel(label) } else { return Ok(ParseOpRes::Unknown(args)); } } else { return Ok(ParseOpRes::Unknown(args)); } } other => { if let Some(label) = other.strip_prefix(':') { let label = Label::Named(label.to_string()); BuiltinOp::Label(label) } else { return Ok(ParseOpRes::Unknown(args)); } } }))) } }