forked from MightyPork/crsn
refactors
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
|
|
||||||
/// Register name
|
/// Register name
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -34,6 +34,6 @@ pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
|
|||||||
let val: u8 = rn.parse()?;
|
let val: u8 = rn.parse()?;
|
||||||
Ok(Register::Gen(val))
|
Ok(Register::Gen(val))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Parse(format!("Bad reg name: {}", name).into()))?
|
Err(CrsnError::Parse(format!("Bad reg name: {}", name).into()))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::asm::instr::Cond;
|
|||||||
|
|
||||||
/// csn_asm unified error type
|
/// csn_asm unified error type
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum CrsnError {
|
||||||
#[error("S-expression syntax error: {0:?}")]
|
#[error("S-expression syntax error: {0:?}")]
|
||||||
PreParse(#[from] Box<sexp::Error>),
|
PreParse(#[from] Box<sexp::Error>),
|
||||||
#[error("Parse error: {0:?}")]
|
#[error("Parse error: {0:?}")]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
|
|
||||||
/// Condition flag
|
/// Condition flag
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
@@ -45,7 +45,7 @@ pub enum Cond {
|
|||||||
NotCarry,
|
NotCarry,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cond(text: &str) -> Result<Cond, Error> {
|
pub fn parse_cond(text: &str) -> Result<Cond, CrsnError> {
|
||||||
Ok(match text.trim_end_matches('?') {
|
Ok(match text.trim_end_matches('?') {
|
||||||
"eq" | "=" | "==" => Cond::Equal,
|
"eq" | "=" | "==" => Cond::Equal,
|
||||||
"ne" | "<>" | "!=" | "≠" => Cond::NotEqual,
|
"ne" | "<>" | "!=" | "≠" => Cond::NotEqual,
|
||||||
@@ -66,7 +66,7 @@ pub fn parse_cond(text: &str) -> Result<Cond, Error> {
|
|||||||
"ov" | "^" => Cond::Overflow,
|
"ov" | "^" => Cond::Overflow,
|
||||||
"nov" | "!ov" | "!^" => Cond::NotOverflow,
|
"nov" | "!ov" | "!^" => Cond::NotOverflow,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Parse(format!("Unknown cond: {}", text).into()));
|
return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into()));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ use std::sync::atomic::AtomicU32;
|
|||||||
|
|
||||||
use crate::asm::data::{Rd, RdData};
|
use crate::asm::data::{Rd, RdData};
|
||||||
use crate::asm::data::literal::{Label, Value};
|
use crate::asm::data::literal::{Label, Value};
|
||||||
use crate::asm::error::{AsmError, Error};
|
use crate::asm::error::{AsmError, CrsnError};
|
||||||
use crate::asm::instr::{Cond, Instr, Op, Routine};
|
use crate::asm::instr::{Cond, Instr, Op, Routine};
|
||||||
use crate::builtin::defs::BuiltinOp;
|
use crate::builtin::defs::BuiltinOp;
|
||||||
|
|
||||||
/// A trait for something that can turn into multiple instructions
|
/// A trait for something that can turn into multiple instructions
|
||||||
pub trait Flatten {
|
pub trait Flatten {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error>;
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for Instr {
|
impl Flatten for Instr {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||||
let mut ops = vec![self.op];
|
let mut ops = vec![self.op];
|
||||||
|
|
||||||
if let Some(branches) = self.branches {
|
if let Some(branches) = self.branches {
|
||||||
@@ -22,7 +22,7 @@ impl Flatten for Instr {
|
|||||||
let end_lbl = Label::unique(label_num);
|
let end_lbl = Label::unique(label_num);
|
||||||
for (cnt, (cond, branch)) in branches.into_iter().enumerate() {
|
for (cnt, (cond, branch)) in branches.into_iter().enumerate() {
|
||||||
if labels.contains_key(&cond) {
|
if labels.contains_key(&cond) {
|
||||||
return Err(Error::Asm(AsmError::ConditionalAlreadyUsed(cond)));
|
return Err(CrsnError::Asm(AsmError::ConditionalAlreadyUsed(cond)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_lbl = if cnt == branch_count - 1 {
|
let next_lbl = if cnt == branch_count - 1 {
|
||||||
@@ -49,7 +49,7 @@ impl Flatten for Instr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for Routine {
|
impl Flatten for Routine {
|
||||||
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, Error> {
|
fn flatten(self, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||||
let mut ops = vec![
|
let mut ops = vec![
|
||||||
BuiltinOp::Routine(self.name.clone()).into(),
|
BuiltinOp::Routine(self.name.clone()).into(),
|
||||||
];
|
];
|
||||||
@@ -65,7 +65,7 @@ impl Flatten for Routine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert jumps to relative skips
|
/// Convert jumps to relative skips
|
||||||
fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
|
fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
|
||||||
let mut label_positions = HashMap::<Label, usize>::new();
|
let mut label_positions = HashMap::<Label, usize>::new();
|
||||||
for (n, op) in ops.iter().enumerate() {
|
for (n, op) in ops.iter().enumerate() {
|
||||||
if let Op::BuiltIn(BuiltinOp::Label(name @ Label::Numbered(_))) = op {
|
if let Op::BuiltIn(BuiltinOp::Label(name @ Label::Numbered(_))) = op {
|
||||||
@@ -85,7 +85,7 @@ fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
|
|||||||
let skip = *dest as isize - n as isize + skipped;
|
let skip = *dest as isize - n as isize + skipped;
|
||||||
cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))));
|
cleaned.push(Op::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))));
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
|
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Op::BuiltIn(BuiltinOp::JumpIf(cond, target @ Label::Numbered(_))) => {
|
Op::BuiltIn(BuiltinOp::JumpIf(cond, target @ Label::Numbered(_))) => {
|
||||||
@@ -93,7 +93,7 @@ fn numbered_labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, Error> {
|
|||||||
let skip = *dest as isize - n as isize + skipped;
|
let skip = *dest as isize - n as isize + skipped;
|
||||||
cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(RdData::Immediate(skip as Value)))));
|
cleaned.push(Op::BuiltIn(BuiltinOp::SkipIf(cond, Rd::new(RdData::Immediate(skip as Value)))));
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Asm(AsmError::LabelNotDefined(target)));
|
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ pub mod parse;
|
|||||||
pub mod patches;
|
pub mod patches;
|
||||||
|
|
||||||
/// Parse a program from string and assemble a low level instruction sequence from it.
|
/// Parse a program from string and assemble a low level instruction sequence from it.
|
||||||
pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Program>, error::Error> {
|
pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Program>, error::CrsnError> {
|
||||||
let ops = parse::parse(source, &parsers)?;
|
let ops = parse::parse(source, &parsers)?;
|
||||||
|
|
||||||
trace!("--- Compiled program ---");
|
trace!("--- Compiled program ---");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::sync::atomic::AtomicU32;
|
|||||||
pub use parse_instr::parse_instructions;
|
pub use parse_instr::parse_instructions;
|
||||||
use parse_routines::parse_routines;
|
use parse_routines::parse_routines;
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::{Flatten, Op, Routine};
|
use crate::asm::instr::{Flatten, Op, Routine};
|
||||||
use crate::asm::parse::sexp_expect::expect_list;
|
use crate::asm::parse::sexp_expect::expect_list;
|
||||||
use crate::module::CrsnExtension;
|
use crate::module::CrsnExtension;
|
||||||
@@ -17,7 +17,7 @@ mod parse_op;
|
|||||||
|
|
||||||
pub mod arg_parser;
|
pub mod arg_parser;
|
||||||
|
|
||||||
pub fn parse(source: &str, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Op>, Error> {
|
pub fn parse(source: &str, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Op>, CrsnError> {
|
||||||
let root = sexp::parse(source)?;
|
let root = sexp::parse(source)?;
|
||||||
|
|
||||||
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?;
|
let subs: Vec<Routine> = parse_routines(expect_list(Some(root), true)?, parsers)?;
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use sexp::Sexp;
|
use sexp::Sexp;
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::{Cond, cond, Instr};
|
use crate::asm::instr::{Cond, cond, Instr};
|
||||||
use crate::asm::parse::parse_instr::parse_instructions;
|
use crate::asm::parse::parse_instr::parse_instructions;
|
||||||
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
||||||
use crate::asm::patches::TryRemove;
|
use crate::asm::patches::TryRemove;
|
||||||
use crate::module::CrsnExtension;
|
use crate::module::CrsnExtension;
|
||||||
|
|
||||||
pub fn parse_cond_branch(tok: Sexp, parsers: &[Box<dyn CrsnExtension>]) -> Result<(Cond, Vec<Instr>), Error> {
|
pub fn parse_cond_branch(tok: Sexp, parsers: &[Box<dyn CrsnExtension>]) -> Result<(Cond, Vec<Instr>), CrsnError> {
|
||||||
let mut list = expect_list(Some(tok), false)?;
|
let mut list = expect_list(Some(tok), false)?;
|
||||||
let kw = expect_string_atom(list.try_remove(0))?;
|
let kw = expect_string_atom(list.try_remove(0))?;
|
||||||
|
|
||||||
if !kw.ends_with('?') {
|
if !kw.ends_with('?') {
|
||||||
return Err(Error::Parse(format!("Condition must end with '?': {}", kw).into()));
|
return Err(CrsnError::Parse(format!("Condition must end with '?': {}", kw).into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((cond::parse_cond(&kw)?, parse_instructions(list, parsers)?))
|
Ok((cond::parse_cond(&kw)?, parse_instructions(list, parsers)?))
|
||||||
|
|||||||
@@ -4,21 +4,21 @@ use sexp::{Atom, Sexp};
|
|||||||
|
|
||||||
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData};
|
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData};
|
||||||
use crate::asm::data::literal::Label;
|
use crate::asm::data::literal::Label;
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
|
||||||
/// Parse a label
|
/// Parse a label
|
||||||
pub fn parse_label(name: Option<Sexp>) -> Result<Label, Error> {
|
pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
|
||||||
let name = expect_string_atom(name)?;
|
let name = expect_string_atom(name)?;
|
||||||
Ok(Label::Named(name.trim_start_matches(':').into()))
|
Ok(Label::Named(name.trim_start_matches(':').into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse data disposition (address/value, without the read/write restriction)
|
/// Parse data disposition (address/value, without the read/write restriction)
|
||||||
pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, Error> {
|
pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, CrsnError> {
|
||||||
let tok = if let Some(tok) = tok {
|
let tok = if let Some(tok) = tok {
|
||||||
tok
|
tok
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Parse("Expected data disposition token".into()));
|
return Err(CrsnError::Parse("Expected data disposition token".into()));
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO implement masks
|
// TODO implement masks
|
||||||
@@ -41,7 +41,7 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Err(Error::Parse(format!("bad data disp: {:?}", tok).into()))
|
Err(CrsnError::Parse(format!("bad data disp: {:?}", tok).into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use sexp::Sexp;
|
use sexp::Sexp;
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::Instr;
|
use crate::asm::instr::Instr;
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::asm::parse::parse_cond::parse_cond_branch;
|
use crate::asm::parse::parse_cond::parse_cond_branch;
|
||||||
@@ -10,7 +10,7 @@ use crate::module::CrsnExtension;
|
|||||||
|
|
||||||
use super::parse_op::parse_op;
|
use super::parse_op::parse_op;
|
||||||
|
|
||||||
pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Instr>, Error> {
|
pub fn parse_instructions(instrs: Vec<Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Instr>, CrsnError> {
|
||||||
let mut parsed = vec![];
|
let mut parsed = vec![];
|
||||||
for expr in instrs {
|
for expr in instrs {
|
||||||
let tokens = expect_list(Some(expr), false)?;
|
let tokens = expect_list(Some(expr), false)?;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::builtin::parse::BuiltinOps;
|
use crate::builtin::parse::BuiltinOps;
|
||||||
use crate::module::{CrsnExtension, ParseOpRes};
|
use crate::module::{CrsnExtension, ParseOpRes};
|
||||||
|
|
||||||
pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn CrsnExtension>]) -> Result<Op, Error> {
|
pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn CrsnExtension>]) -> Result<Op, CrsnError> {
|
||||||
// Include built-in instructions
|
// Include built-in instructions
|
||||||
let builtins = [BuiltinOps::new()];
|
let builtins = [BuiltinOps::new()];
|
||||||
|
|
||||||
@@ -23,5 +23,5 @@ pub fn parse_op(keyword: &str, mut arg_tokens: ArgParser, parsers: &[Box<dyn Crs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(Error::Parse(format!("Unknown instruction: {}", keyword).into()));
|
return Err(CrsnError::Parse(format!("Unknown instruction: {}", keyword).into()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use sexp::Sexp;
|
use sexp::Sexp;
|
||||||
|
|
||||||
use crate::asm::data::literal::RoutineName;
|
use crate::asm::data::literal::RoutineName;
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::Routine;
|
use crate::asm::instr::Routine;
|
||||||
use crate::asm::parse::parse_instr::parse_instructions;
|
use crate::asm::parse::parse_instr::parse_instructions;
|
||||||
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
||||||
use crate::asm::patches::TryRemove;
|
use crate::asm::patches::TryRemove;
|
||||||
use crate::module::CrsnExtension;
|
use crate::module::CrsnExtension;
|
||||||
|
|
||||||
pub fn parse_routines(routines: Vec<Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Routine>, Error> {
|
pub fn parse_routines(routines: Vec<Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Routine>, CrsnError> {
|
||||||
let mut parsed = vec![];
|
let mut parsed = vec![];
|
||||||
for rt in routines {
|
for rt in routines {
|
||||||
let mut def = expect_list(Some(rt), false)?;
|
let mut def = expect_list(Some(rt), false)?;
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp};
|
||||||
|
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
|
|
||||||
pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, Error> {
|
pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, CrsnError> {
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
match &expr {
|
match &expr {
|
||||||
Sexp::Atom(_) => {
|
Sexp::Atom(_) => {
|
||||||
return Err(Error::ParseIn("Expected a list".into(), expr));
|
return Err(CrsnError::ParseIn("Expected a list".into(), expr));
|
||||||
}
|
}
|
||||||
Sexp::List(list) => {
|
Sexp::List(list) => {
|
||||||
if !allow_empty && list.is_empty() {
|
if !allow_empty && list.is_empty() {
|
||||||
return Err(Error::ParseIn("Routine: Empty list".into(), expr));
|
return Err(CrsnError::ParseIn("Routine: Empty list".into(), expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Sexp::List(list) = expr {
|
if let Sexp::List(list) = expr {
|
||||||
@@ -22,10 +22,10 @@ pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Error::Parse("Expected a list, got nothing".into()))
|
Err(CrsnError::Parse("Expected a list, got nothing".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_atom(expr: Option<Sexp>) -> Result<Atom, Error> {
|
pub fn expect_atom(expr: Option<Sexp>) -> Result<Atom, CrsnError> {
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
match &expr {
|
match &expr {
|
||||||
Sexp::Atom(_atom) => {
|
Sexp::Atom(_atom) => {
|
||||||
@@ -36,18 +36,18 @@ pub fn expect_atom(expr: Option<Sexp>) -> Result<Atom, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Sexp::List(_) => {
|
Sexp::List(_) => {
|
||||||
return Err(Error::ParseIn("Expected atom got list".into(), expr));
|
return Err(CrsnError::ParseIn("Expected atom got list".into(), expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Error::Parse("Expected atom, got nothing".into()))
|
Err(CrsnError::Parse("Expected atom, got nothing".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_string_atom(expr: Option<Sexp>) -> Result<String, Error> {
|
pub fn expect_string_atom(expr: Option<Sexp>) -> Result<String, CrsnError> {
|
||||||
match expect_atom(expr) {
|
match expect_atom(expr) {
|
||||||
Ok(Atom::S(s)) => Ok(s),
|
Ok(Atom::S(s)) => Ok(s),
|
||||||
Ok(atom) => Err(Error::ParseIn("Expected string atom".into(), Sexp::Atom(atom))),
|
Ok(atom) => Err(CrsnError::ParseIn("Expected string atom".into(), Sexp::Atom(atom))),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp};
|
||||||
|
|
||||||
use crate::asm::data::literal::{Label, RoutineName};
|
use crate::asm::data::literal::{Label, RoutineName};
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::cond::parse_cond;
|
use crate::asm::instr::cond::parse_cond;
|
||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
@@ -28,7 +28,7 @@ impl CrsnExtension for BuiltinOps {
|
|||||||
"builtin"
|
"builtin"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, Error> {
|
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||||
Ok(ParseOpRes::Parsed(Op::BuiltIn(match keyword {
|
Ok(ParseOpRes::Parsed(Op::BuiltIn(match keyword {
|
||||||
"nop" => {
|
"nop" => {
|
||||||
BuiltinOp::Nop
|
BuiltinOp::Nop
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ pub use eval_res::EvalRes;
|
|||||||
|
|
||||||
use crate::asm::data::literal::Value;
|
use crate::asm::data::literal::Value;
|
||||||
use crate::asm::data::Mask;
|
use crate::asm::data::Mask;
|
||||||
use crate::asm::error::Error;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::parse::arg_parser::ArgParser;
|
use crate::asm::parse::arg_parser::ArgParser;
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
@@ -23,7 +23,7 @@ pub enum ParseOpRes<T> {
|
|||||||
|
|
||||||
impl ParseOpRes<Op> {
|
impl ParseOpRes<Op> {
|
||||||
/// Helper to construct an extension op
|
/// Helper to construct an extension op
|
||||||
pub fn parsed(op : impl OpTrait) -> Self {
|
pub fn ext(op : impl OpTrait) -> Self {
|
||||||
Self::Parsed(Op::Ext(Box::new(op)))
|
Self::Parsed(Op::Ext(Box::new(op)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
|
|||||||
/// the argument list and either return Ok or Err.
|
/// the argument list and either return Ok or Err.
|
||||||
///
|
///
|
||||||
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
|
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
|
||||||
fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpRes<Op>, Error>;
|
fn parse_op(&self, keyword: &str, arg_tokens: ArgParser) -> Result<ParseOpRes<Op>, CrsnError>;
|
||||||
|
|
||||||
/// Drop an object referenced by a handle
|
/// Drop an object referenced by a handle
|
||||||
fn drop_obj(&self,
|
fn drop_obj(&self,
|
||||||
|
|||||||
+22
-1
@@ -1,6 +1,27 @@
|
|||||||
pub use parse::ArithOps;
|
use crsn::module::{CrsnExtension, ParseOpRes};
|
||||||
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
|
use crsn::asm::error::CrsnError;
|
||||||
|
use crsn::asm::instr::Op;
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod exec;
|
mod exec;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ArithOps;
|
||||||
|
|
||||||
|
impl ArithOps {
|
||||||
|
pub fn new() -> Box<dyn CrsnExtension> {
|
||||||
|
Box::new(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CrsnExtension for ArithOps {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"arith"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_op(&self, keyword: &str, args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||||
|
parse::parse(keyword, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+429
-447
@@ -1,455 +1,437 @@
|
|||||||
use crsn::asm::data::{Rd, Wr};
|
use crsn::asm::data::{Rd, Wr};
|
||||||
use crsn::asm::error::Error;
|
use crsn::asm::error::CrsnError;
|
||||||
use crsn::asm::instr::Op;
|
use crsn::asm::instr::Op;
|
||||||
use crsn::asm::parse::arg_parser::ArgParser;
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
use crsn::module::{CrsnExtension, ParseOpRes};
|
use crsn::module::{ParseOpRes};
|
||||||
|
|
||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||||
pub struct ArithOps {
|
Ok(ParseOpRes::ext(match keyword {
|
||||||
_internal: ()
|
"cmp" => {
|
||||||
|
ArithOp::Compare {
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"tst" => {
|
||||||
|
let arg = args.next_rd()?;
|
||||||
|
ArithOp::Test { a: arg }
|
||||||
|
}
|
||||||
|
|
||||||
|
"inc" => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Add {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"dec" => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Sub {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"add" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Add {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Add {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"sub" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Sub {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Sub {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"mul" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Mul {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Mul {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"divr" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
let rem = args.next_wr()?;
|
||||||
|
let div = args.next_rd()?;
|
||||||
|
ArithOp::Div {
|
||||||
|
dst,
|
||||||
|
rem,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
div,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
ArithOp::Div {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
rem: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
div: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"div" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Div {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
rem: Wr::discard(),
|
||||||
|
a: args.next_rd()?,
|
||||||
|
div: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
let div = args.next_rd()?;
|
||||||
|
ArithOp::Div {
|
||||||
|
dst,
|
||||||
|
rem: Wr::discard(),
|
||||||
|
a: dst.as_rd(),
|
||||||
|
div,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"mod" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Mod {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
div: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
let div = args.next_rd()?;
|
||||||
|
ArithOp::Mod {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
div,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"and" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::And {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::And {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"or" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Or {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Or {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"xor" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Xor {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Xor {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
b: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"cpl" => {
|
||||||
|
match args.len() {
|
||||||
|
2 => {
|
||||||
|
ArithOp::Cpl {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Cpl {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"rol" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Rol {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Rol {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Rol {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"ror" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Ror {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Ror {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Ror {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"lsl" | "asl" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Lsl {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Lsl {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Lsl {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"lsr" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Lsr {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Lsr {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Lsr {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"asr" => {
|
||||||
|
match args.len() {
|
||||||
|
3 => {
|
||||||
|
ArithOp::Asr {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
a: args.next_rd()?,
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Asr {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: args.next_rd()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
let dst = args.next_wr()?;
|
||||||
|
ArithOp::Asr {
|
||||||
|
dst,
|
||||||
|
a: dst.as_rd(),
|
||||||
|
n: Rd::immediate(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_other => {
|
||||||
|
return Ok(ParseOpRes::Unknown(args));
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArithOps {
|
|
||||||
pub fn new() -> Box<dyn CrsnExtension> {
|
|
||||||
Box::new(Self {
|
|
||||||
_internal: ()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CrsnExtension for ArithOps {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"arith"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, Error> {
|
|
||||||
Ok(ParseOpRes::parsed(match keyword {
|
|
||||||
"cmp" => {
|
|
||||||
ArithOp::Compare {
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"tst" => {
|
|
||||||
let arg = args.next_rd()?;
|
|
||||||
ArithOp::Test { a: arg }
|
|
||||||
}
|
|
||||||
|
|
||||||
"inc" => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Add {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"dec" => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Sub {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"add" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Add {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Add {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Add requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"sub" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Sub {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Sub {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Sub requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"mul" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Mul {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Mul {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Mul requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"divr" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
let rem = args.next_wr()?;
|
|
||||||
let div = args.next_rd()?;
|
|
||||||
ArithOp::Div {
|
|
||||||
dst,
|
|
||||||
rem,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
div,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4 => {
|
|
||||||
ArithOp::Div {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
rem: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
div: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("DivR requires 3 or 4 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"div" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Div {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
rem: Wr::discard(),
|
|
||||||
a: args.next_rd()?,
|
|
||||||
div: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
let div = args.next_rd()?;
|
|
||||||
ArithOp::Div {
|
|
||||||
dst,
|
|
||||||
rem: Wr::discard(),
|
|
||||||
a: dst.as_rd(),
|
|
||||||
div,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Div requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"mod" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Mod {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
div: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
let div = args.next_rd()?;
|
|
||||||
ArithOp::Mod {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
div,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Mod requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"and" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::And {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::And {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("And requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"or" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Or {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Or {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Or requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"xor" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Xor {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Xor {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
b: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Xor requires 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"cpl" => {
|
|
||||||
match args.len() {
|
|
||||||
2 => {
|
|
||||||
ArithOp::Cpl {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Cpl {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Cpl requires 1 or 2 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"rol" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Rol {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Rol {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Rol {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Rol requires 1, 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"ror" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Ror {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Ror {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Ror {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Ror requires 1, 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"lsl" | "asl" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Lsl {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Lsl {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Lsl {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Lsl requires 1, 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"lsr" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Lsr {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Lsr {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Lsr {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Lsr requires 1, 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"asr" => {
|
|
||||||
match args.len() {
|
|
||||||
3 => {
|
|
||||||
ArithOp::Asr {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
a: args.next_rd()?,
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Asr {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let dst = args.next_wr()?;
|
|
||||||
ArithOp::Asr {
|
|
||||||
dst,
|
|
||||||
a: dst.as_rd(),
|
|
||||||
n: Rd::immediate(1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Parse("Asr requires 1, 2 or 3 arguments".into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_other => {
|
|
||||||
return Ok(ParseOpRes::Unknown(args));
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ impl OpTrait for StackOp {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn drop_stack(state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
pub(crate) fn drop_obj(state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
||||||
let stacks: &mut Stacks = state.ext_mut();
|
let stacks: &mut Stacks = state.ext_mut();
|
||||||
Ok(stacks.store.remove(&handle).map(|_| ()))
|
Ok(stacks.store.remove(&handle).map(|_| ()))
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-1
@@ -1,6 +1,27 @@
|
|||||||
pub use parse::StackOps;
|
use crsn::module::{CrsnExtension, ParseOpRes};
|
||||||
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
|
use crsn::asm::instr::Op;
|
||||||
|
use crsn::asm::error::CrsnError;
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod exec;
|
mod exec;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct StackOps;
|
||||||
|
|
||||||
|
impl StackOps {
|
||||||
|
pub fn new() -> Box<dyn CrsnExtension> {
|
||||||
|
Box::new(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CrsnExtension for StackOps {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"stacks"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_op(&self, keyword: &str, args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||||
|
parse::parse(keyword, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+25
-49
@@ -1,61 +1,37 @@
|
|||||||
use crsn::asm::data::literal::Value;
|
|
||||||
use crsn::asm::error::Error;
|
use crsn::asm::error::CrsnError;
|
||||||
use crsn::asm::instr::Op;
|
use crsn::asm::instr::Op;
|
||||||
use crsn::asm::parse::arg_parser::ArgParser;
|
use crsn::asm::parse::arg_parser::ArgParser;
|
||||||
use crsn::module::{CrsnExtension, ParseOpRes};
|
use crsn::module::{ParseOpRes};
|
||||||
use crsn::runtime::fault::Fault;
|
|
||||||
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
|
||||||
|
|
||||||
use crate::defs::StackOp;
|
use crate::defs::StackOp;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||||
pub struct StackOps {
|
Ok(ParseOpRes::ext(match keyword {
|
||||||
_internal: ()
|
"stack" => {
|
||||||
}
|
StackOp::NewStack {
|
||||||
|
dst: args.next_wr()?,
|
||||||
impl StackOps {
|
|
||||||
pub fn new() -> Box<dyn CrsnExtension> {
|
|
||||||
Box::new(Self {
|
|
||||||
_internal: ()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CrsnExtension for StackOps {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"stacks"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_op(&self, keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, Error> {
|
|
||||||
Ok(ParseOpRes::parsed(match keyword {
|
|
||||||
"stack" => {
|
|
||||||
StackOp::NewStack {
|
|
||||||
dst: args.next_wr()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"push" => {
|
|
||||||
StackOp::Push {
|
|
||||||
obj: args.next_rdobj()?,
|
|
||||||
src: args.next_rd()?,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"pop" => {
|
"push" => {
|
||||||
StackOp::Pop {
|
StackOp::Push {
|
||||||
dst: args.next_wr()?,
|
obj: args.next_rdobj()?,
|
||||||
obj: args.next_rdobj()?,
|
src: args.next_rd()?,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_other => {
|
"pop" => {
|
||||||
return Ok(ParseOpRes::Unknown(args));
|
StackOp::Pop {
|
||||||
|
dst: args.next_wr()?,
|
||||||
|
obj: args.next_rdobj()?,
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault>
|
_other => {
|
||||||
{
|
return Ok(ParseOpRes::Unknown(args));
|
||||||
crate::exec::drop_stack(state, handle)
|
}
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user