use sexp::{Atom, Sexp}; use crate::asm::data::literal::{Label, RoutineName}; use crate::asm::data::reg::parse_reg; use crate::asm::error::CrsnError; use crate::asm::instr::op::OpKind; use crate::asm::parse::arg_parser::TokenParser; use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_rd, parse_reg_alias, parse_value}; use crate::asm::parse::sexp_expect::expect_string_atom; use crate::builtin::defs::{Barrier, BuiltinOp}; use crate::module::{CrsnExtension, ParseRes}; #[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<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result, CrsnError> { let pcx = args.pcx; Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword { "nop" => { BuiltinOp::Nop } "halt" => { BuiltinOp::Halt } "sleep" => { BuiltinOp::Sleep { micros: args.next_rd()?, } } "sym" => { let alias = parse_reg_alias(args.next())?; trace!("alias={:?}", alias); let register = parse_reg(&args.next_string()?)?; trace!("register={:?}", alias); let mut pstate = pcx.state.borrow_mut(); if pstate.reg_aliases.contains_key(&alias) { return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into())); } if pstate.constants.contains_key(&alias) { return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into())); } if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).is_some() { return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into())); } pstate.reg_aliases.insert(alias, register); return Ok(ParseRes::ParsedNone); } "unsym" => { let alias = parse_reg_alias(args.next())?; let mut pstate = pcx.state.borrow_mut(); if pstate.reg_aliases.remove(&alias).is_none() { return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias).into())); } return Ok(ParseRes::ParsedNone); } "def" => { let name = parse_constant_name(args.next())?; let value = parse_value(args.next())?; let mut pstate = pcx.state.borrow_mut(); if pstate.constants.contains_key(&name) { return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into())); } if pstate.reg_aliases.contains_key(&name) { return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into())); } pstate.constants.insert(name, value); return Ok(ParseRes::ParsedNone); } "undef" => { let name = parse_constant_name(args.next())?; let mut pstate = pcx.state.borrow_mut(); if pstate.constants.remove(&name).is_none() { return Err(CrsnError::Parse(format!("Constant \"{}\" not defined!", name).into())); } return Ok(ParseRes::ParsedNone); } "j" => { let dest = parse_label(args.next())?; BuiltinOp::Jump(dest) } "fj" => { let dest = parse_label(args.next())?; BuiltinOp::FarJump(dest) } "call" => { let dest = RoutineName { name: args.next_string()?, arity: args.len() as u8 }; let mut call_args = vec![]; for t in args { call_args.push(parse_rd(Some(t), pcx)?); } BuiltinOp::Call(dest, call_args) } "ret" => { let mut ret_vals = vec![]; for t in args { ret_vals.push(parse_rd(Some(t), pcx)?); } BuiltinOp::Ret(ret_vals) } "routine" => { let name = args.next_string()?; BuiltinOp::Routine(parse_routine_name(name)?) } "skip" => { BuiltinOp::Skip(args.next_rd()?) } "barrier" => { BuiltinOp::Barrier { kind: Barrier::Standalone, msg: 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(ParseRes::Unknown(args)); } } else { return Ok(ParseRes::Unknown(args)); } } other => { if let Some(label) = other.strip_prefix(':') { let label = Label::Named(label.to_string()); BuiltinOp::Label(label) } else { return Ok(ParseRes::Unknown(args)); } } }))) } } pub(crate) fn parse_routine_name(name: String) -> Result { let (name, arity) = if let Some(n) = name.find('/') { ( (&name[0..n]).to_string(), (&name[(n + 1)..]).parse::()? ) } else { (name, 0) }; Ok(RoutineName { name, arity }) }