|
|
|
use sexp::{Atom, Sexp};
|
|
|
|
|
|
|
|
use crate::asm::data::literal::{Label, RoutineName};
|
|
|
|
use crate::asm::error::CrsnError;
|
|
|
|
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<dyn CrsnExtension> {
|
|
|
|
Box::new(Self {
|
|
|
|
_internal: ()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CrsnExtension for BuiltinOps {
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
"builtin"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})))
|
|
|
|
}
|
|
|
|
}
|