forked from MightyPork/crsn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
7.6 KiB
245 lines
7.6 KiB
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::cond::parse_cond;
|
|
use crate::asm::instr::Op;
|
|
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::{BuiltinOp, Barrier};
|
|
use crate::module::{CrsnExtension, ParseRes};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct BuiltinOps {
|
|
_internal: ()
|
|
}
|
|
|
|
impl BuiltinOps {
|
|
pub fn new() -> Box<dyn CrsnExtension> {
|
|
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<ParseRes<'a, Op>, CrsnError> {
|
|
let pcx = args.pcx;
|
|
|
|
Ok(ParseRes::Parsed(Op::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)?)
|
|
}
|
|
|
|
"sk" => {
|
|
BuiltinOp::Skip(args.next_rd()?)
|
|
}
|
|
|
|
// TODO add jne-style names for jif ne ...
|
|
|
|
"skif" => {
|
|
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 {
|
|
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<RoutineName, CrsnError> {
|
|
let (name, arity) = if let Some(n) = name.find('/') {
|
|
(
|
|
(&name[0..n]).to_string(),
|
|
(&name[(n+1)..]).parse::<u8>()?
|
|
)
|
|
} else {
|
|
(name, 0)
|
|
};
|
|
|
|
Ok(RoutineName { name, arity })
|
|
}
|
|
|