forked from MightyPork/crsn
all errors now contain source location
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
use crate::asm::patches::ErrWithPos;
|
||||||
|
|
||||||
/// Register name
|
/// Register name
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
@@ -23,27 +25,27 @@ impl Display for Register {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
|
pub fn parse_reg(name: &str, at: SourcePosition) -> Result<Register, CrsnError> {
|
||||||
// TODO deduplicate code
|
// TODO deduplicate code
|
||||||
if let Some(rn) = name.strip_prefix("arg") {
|
if let Some(rn) = name.strip_prefix("arg") {
|
||||||
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
|
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
|
||||||
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
|
return Err(CrsnError::Parse(format!("Bad register: {}", name).into(), at))?;
|
||||||
}
|
}
|
||||||
let val: u8 = rn.parse()?;
|
let val: u8 = rn.parse().err_pos(at)?;
|
||||||
Ok(Register::Arg(val))
|
Ok(Register::Arg(val))
|
||||||
} else if let Some(rn) = name.strip_prefix("res") {
|
} else if let Some(rn) = name.strip_prefix("res") {
|
||||||
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
|
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
|
||||||
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
|
return Err(CrsnError::Parse(format!("Bad register: {}", name).into(), at))?;
|
||||||
}
|
}
|
||||||
let val: u8 = rn.parse()?;
|
let val: u8 = rn.parse().err_pos(at)?;
|
||||||
Ok(Register::Res(val))
|
Ok(Register::Res(val))
|
||||||
} else if let Some(rn) = name.strip_prefix("r") {
|
} else if let Some(rn) = name.strip_prefix("r") {
|
||||||
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
|
if rn.chars().find(|c: &char| !c.is_ascii_digit()).is_some() {
|
||||||
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
|
return Err(CrsnError::Parse(format!("Bad register: {}", name).into(), at))?;
|
||||||
}
|
}
|
||||||
let val: u8 = rn.parse()?;
|
let val: u8 = rn.parse().err_pos(at)?;
|
||||||
Ok(Register::Gen(val))
|
Ok(Register::Gen(val))
|
||||||
} else {
|
} else {
|
||||||
Err(CrsnError::Parse(format!("Bad reg name: {}", name).into()))?
|
Err(CrsnError::Parse(format!("Bad reg name: {}", name).into(), at))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-29
@@ -6,28 +6,20 @@ use thiserror::Error;
|
|||||||
use crate::asm::data::{Mask, Register};
|
use crate::asm::data::{Mask, Register};
|
||||||
use crate::asm::data::literal::Label;
|
use crate::asm::data::literal::Label;
|
||||||
use crate::asm::instr::Cond;
|
use crate::asm::instr::Cond;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
/// csn_asm unified error type
|
/// csn_asm unified error type
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum CrsnError {
|
pub enum CrsnError {
|
||||||
#[error("S-expression syntax error: {0:?}")]
|
#[error("S-expression parsing error: {0:?}")]
|
||||||
PreParse(#[from] Box<sexp::Error>),
|
Sexp(#[from] Box<sexp::Error>),
|
||||||
#[error("Parse error: {0:?}")]
|
#[error("Parse error: {0:?} at {1:?}")]
|
||||||
Parse(Cow<'static, str>),
|
Parse(Cow<'static, str>, SourcePosition),
|
||||||
#[error("Parse error in {1:?}: {0:?}")]
|
#[error("Parse error: {0:?} at {1:?}")]
|
||||||
ParseIn(Cow<'static, str>, sexp::Sexp),
|
ParseOther(Box<dyn Error + Send + Sync>, SourcePosition),
|
||||||
#[error("Assembler error: {0:?}")]
|
#[error("Assembler error: {0:?} at {1:?}")]
|
||||||
Asm(AsmError),
|
Asm(AsmError, SourcePosition),
|
||||||
#[error("Architecture error: {0:?}")]
|
|
||||||
Arch(ArchError),
|
|
||||||
#[error(transparent)]
|
|
||||||
Other(#[from] anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::num::ParseIntError> for CrsnError {
|
|
||||||
fn from(e: ParseIntError) -> Self {
|
|
||||||
CrsnError::Other(anyhow::anyhow!(e))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error from the assembler stage (after parsing S-expressions and basic validation)
|
/// Error from the assembler stage (after parsing S-expressions and basic validation)
|
||||||
@@ -50,14 +42,3 @@ pub enum AsmError {
|
|||||||
#[error("Bad register type: {0}")]
|
#[error("Bad register type: {0}")]
|
||||||
BadRegisterType(Register),
|
BadRegisterType(Register),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Architectural error - the code is syntactically OK, but cannot run
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum ArchError {
|
|
||||||
#[error("Register {0} does not exist")]
|
|
||||||
RegisterNotExist(Register),
|
|
||||||
#[error("Register {0} is not writable")]
|
|
||||||
RegisterNotWritable(Register),
|
|
||||||
#[error("Register {0} is not readable")]
|
|
||||||
RegisterNotReadable(Register),
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
/// Condition flag
|
/// Condition flag
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
@@ -45,7 +46,7 @@ pub enum Cond {
|
|||||||
NotCarry,
|
NotCarry,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cond(text: &str) -> Result<Cond, CrsnError> {
|
pub fn parse_cond(text: &str, pos : SourcePosition) -> 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 +67,7 @@ pub fn parse_cond(text: &str) -> Result<Cond, CrsnError> {
|
|||||||
"ov" | "^" => Cond::Overflow,
|
"ov" | "^" => Cond::Overflow,
|
||||||
"nov" | "!ov" | "!^" => Cond::NotOverflow,
|
"nov" | "!ov" | "!^" => Cond::NotOverflow,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into()));
|
return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,21 +9,33 @@ use crate::asm::instr::op::OpKind;
|
|||||||
use crate::builtin::defs::Barrier;
|
use crate::builtin::defs::Barrier;
|
||||||
use crate::builtin::defs::BuiltinOp;
|
use crate::builtin::defs::BuiltinOp;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
/// A trait for something that can turn into multiple instructions
|
/// A trait for something that can turn into multiple instructions
|
||||||
pub trait Flatten : Debug {
|
pub trait Flatten : Debug {
|
||||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError>;
|
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError>;
|
||||||
|
|
||||||
|
fn pos(&self) -> SourcePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for () {
|
impl Flatten for () {
|
||||||
fn flatten(self: Box<Self>, _label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
fn flatten(self: Box<Self>, _label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pos(&self) -> SourcePosition {
|
||||||
|
SourcePosition::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for InstrWithBranches {
|
impl Flatten for InstrWithBranches {
|
||||||
|
fn pos(&self) -> SourcePosition {
|
||||||
|
self.pos.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||||
let mut ops = vec![self.op];
|
let mut ops = vec![self.op];
|
||||||
|
let parent_pos = self.pos;
|
||||||
|
|
||||||
if let Some(branches) = self.branches {
|
if let Some(branches) = self.branches {
|
||||||
let labels = HashMap::<Cond, u32>::new();
|
let labels = HashMap::<Cond, u32>::new();
|
||||||
@@ -31,7 +43,7 @@ impl Flatten for InstrWithBranches {
|
|||||||
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(CrsnError::Asm(AsmError::ConditionalAlreadyUsed(cond)));
|
return Err(CrsnError::Asm(AsmError::ConditionalAlreadyUsed(cond), branch.pos()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_lbl = if cnt == branch_count - 1 {
|
let next_lbl = if cnt == branch_count - 1 {
|
||||||
@@ -40,27 +52,29 @@ impl Flatten for InstrWithBranches {
|
|||||||
Label::unique(label_num)
|
Label::unique(label_num)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pos = branch.pos().clone();
|
||||||
let mut flattened = branch.flatten(label_num)?;
|
let mut flattened = branch.flatten(label_num)?;
|
||||||
|
|
||||||
if flattened.len() == 0 {
|
if flattened.len() == 0 {
|
||||||
ops.push(Op { cond: Some(cond), kind: BuiltinOp::Jump(end_lbl.clone()).into() });
|
ops.push(Op { cond: Some(cond), pos: pos.clone(), kind: BuiltinOp::Jump(end_lbl.clone()).into() });
|
||||||
} else if flattened.len() == 1 && flattened[0].cond.is_none() && branch_count == 1 {
|
} else if flattened.len() == 1 && flattened[0].cond.is_none() && branch_count == 1 {
|
||||||
// optimization for single-branch conditionals with a single instruction
|
// optimization for single-branch conditionals with a single instruction
|
||||||
ops.push(Op { cond: Some(cond), kind: flattened.remove(0).kind });
|
ops.push(Op { cond: Some(cond), pos: pos.clone(), kind: flattened.remove(0).kind });
|
||||||
} else {
|
} else {
|
||||||
ops.push(Op {
|
ops.push(Op {
|
||||||
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
|
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
|
||||||
|
pos: pos.clone(),
|
||||||
cond: Some(!cond),
|
cond: Some(!cond),
|
||||||
});
|
});
|
||||||
ops.extend(flattened);
|
ops.extend(flattened);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cnt != branch_count - 1 {
|
if cnt != branch_count - 1 {
|
||||||
ops.push(BuiltinOp::Jump(end_lbl.clone()).into());
|
ops.push(BuiltinOp::Jump(end_lbl.clone()).into_op(pos.clone()));
|
||||||
ops.push(BuiltinOp::Label(next_lbl).into());
|
ops.push(BuiltinOp::Label(next_lbl).into_op(pos.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ops.push(BuiltinOp::Label(end_lbl).into());
|
ops.push(BuiltinOp::Label(end_lbl).into_op(parent_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ops)
|
Ok(ops)
|
||||||
@@ -68,6 +82,17 @@ impl Flatten for InstrWithBranches {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for Vec<Box<dyn Flatten>> {
|
impl Flatten for Vec<Box<dyn Flatten>> {
|
||||||
|
fn pos(&self) -> SourcePosition {
|
||||||
|
match self.first() {
|
||||||
|
None => {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
Some(f) => {
|
||||||
|
f.pos()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||||
let mut ops = vec![];
|
let mut ops = vec![];
|
||||||
for item in self.into_iter() {
|
for item in self.into_iter() {
|
||||||
@@ -78,15 +103,21 @@ impl Flatten for Vec<Box<dyn Flatten>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Flatten for Routine {
|
impl Flatten for Routine {
|
||||||
|
fn pos(&self) -> SourcePosition {
|
||||||
|
self.pos.clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||||
let skip_label = Label::unique(label_num);
|
let skip_label = Label::unique(label_num);
|
||||||
|
|
||||||
|
let self_pos = self.pos();
|
||||||
|
|
||||||
let mut ops: Vec<Op> = vec![
|
let mut ops: Vec<Op> = vec![
|
||||||
BuiltinOp::Barrier {
|
BuiltinOp::Barrier {
|
||||||
kind: Barrier::Open(skip_label.clone()),
|
kind: Barrier::Open(skip_label.clone()),
|
||||||
msg: Some(format!("proc {} start", self.name).into()),
|
msg: Some(format!("proc {} start", self.name).into()),
|
||||||
}.into(),
|
}.into_op(self.pos()),
|
||||||
BuiltinOp::Routine(self.name.clone()).into(),
|
BuiltinOp::Routine(self.name.clone()).into_op(self.pos()),
|
||||||
];
|
];
|
||||||
|
|
||||||
ops.extend(self.body.flatten(label_num)?);
|
ops.extend(self.body.flatten(label_num)?);
|
||||||
@@ -95,7 +126,7 @@ impl Flatten for Routine {
|
|||||||
BuiltinOp::Barrier {
|
BuiltinOp::Barrier {
|
||||||
kind: Barrier::Close(skip_label.clone()),
|
kind: Barrier::Close(skip_label.clone()),
|
||||||
msg: Some(format!("proc {} end", self.name).into()),
|
msg: Some(format!("proc {} end", self.name).into()),
|
||||||
}.into()
|
}.into_op(self_pos)
|
||||||
);
|
);
|
||||||
|
|
||||||
labels_to_skips(ops)
|
labels_to_skips(ops)
|
||||||
@@ -123,10 +154,11 @@ pub fn labels_to_skips(ops: Vec<Op>) -> Result<Vec<Op>, CrsnError> {
|
|||||||
let skip = *dest as isize - n as isize + skipped;
|
let skip = *dest as isize - n as isize + skipped;
|
||||||
cleaned.push(Op {
|
cleaned.push(Op {
|
||||||
cond: op.cond,
|
cond: op.cond,
|
||||||
|
pos : op.pos.clone(),
|
||||||
kind: OpKind::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))),
|
kind: OpKind::BuiltIn(BuiltinOp::Skip(Rd::new(RdData::Immediate(skip as Value)))),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target)));
|
return Err(CrsnError::Asm(AsmError::LabelNotDefined(target), op.pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pub use flatten::Flatten;
|
|||||||
pub use op::Op;
|
pub use op::Op;
|
||||||
|
|
||||||
use crate::asm::data::literal::RoutineName;
|
use crate::asm::data::literal::RoutineName;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
pub mod op;
|
pub mod op;
|
||||||
pub mod cond;
|
pub mod cond;
|
||||||
@@ -12,6 +13,7 @@ pub mod flatten;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstrWithBranches {
|
pub struct InstrWithBranches {
|
||||||
pub op: Op,
|
pub op: Op,
|
||||||
|
pub pos: SourcePosition,
|
||||||
pub branches: Option<Vec<(Cond, Box<dyn Flatten>)>>,
|
pub branches: Option<Vec<(Cond, Box<dyn Flatten>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,5 +21,6 @@ pub struct InstrWithBranches {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Routine {
|
pub struct Routine {
|
||||||
pub name: RoutineName,
|
pub name: RoutineName,
|
||||||
|
pub pos: SourcePosition,
|
||||||
pub body: Box<dyn Flatten>,
|
pub body: Box<dyn Flatten>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::builtin::defs::BuiltinOp;
|
|||||||
use crate::module::{EvalRes, OpTrait};
|
use crate::module::{EvalRes, OpTrait};
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::run_thread::{info::ThreadInfo, state::RunState};
|
use crate::runtime::run_thread::{info::ThreadInfo, state::RunState};
|
||||||
use sexp::{Sexp, Atom};
|
use sexp::{Sexp, Atom, SourcePosition};
|
||||||
|
|
||||||
/// A higher level simple opration
|
/// A higher level simple opration
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -18,6 +18,7 @@ pub enum OpKind {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Op {
|
pub struct Op {
|
||||||
pub cond: Option<Cond>,
|
pub cond: Option<Cond>,
|
||||||
|
pub pos : SourcePosition,
|
||||||
pub kind: OpKind,
|
pub kind: OpKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +50,8 @@ impl OpTrait for Op {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(cond) = self.cond {
|
if let Some(cond) = self.cond {
|
||||||
if let Sexp::List(items) = &mut se {
|
if let Sexp::List(items, _) = &mut se {
|
||||||
if let Some(Sexp::Atom(Atom::S(s))) = &mut items.get_mut(0) {
|
if let Some(Sexp::Atom(Atom::S(s), _)) = &mut items.get_mut(0) {
|
||||||
s.push('.');
|
s.push('.');
|
||||||
s.push_str(&cond.to_string());
|
s.push_str(&cond.to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ use crate::asm::parse::{ParserContext, ParserState};
|
|||||||
use crate::module::CrsnExtension;
|
use crate::module::CrsnExtension;
|
||||||
use crate::runtime::program::Program;
|
use crate::runtime::program::Program;
|
||||||
use crate::asm::instr::flatten::labels_to_skips;
|
use crate::asm::instr::flatten::labels_to_skips;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
pub mod data;
|
pub mod data;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
@@ -23,7 +24,7 @@ pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Resu
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ops = parse::parse(source, &pcx)?;
|
let ops = parse::parse(source, SourcePosition::default(), &pcx)?;
|
||||||
let ops = labels_to_skips(ops)?;
|
let ops = labels_to_skips(ops)?;
|
||||||
|
|
||||||
Ok(Program::new(ops, parsers)?)
|
Ok(Program::new(ops, parsers)?)
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
use sexp::Sexp;
|
use sexp::{Sexp, SourcePosition};
|
||||||
|
|
||||||
use crate::asm::data::{Mask, Rd, RdData, RdObj, Wr};
|
use crate::asm::data::{Mask, Rd, RdData, RdObj, Wr};
|
||||||
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
||||||
use crate::asm::parse::ParserContext;
|
use crate::asm::parse::ParserContext;
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
use crate::asm::patches::NextOrErr;
|
||||||
|
|
||||||
/// Utility for argument parsing
|
/// Utility for argument parsing
|
||||||
pub struct TokenParser<'a> {
|
pub struct TokenParser<'a> {
|
||||||
orig_len: usize,
|
orig_len: usize,
|
||||||
args: Vec<Sexp>,
|
args: Vec<Sexp>,
|
||||||
|
start_pos: SourcePosition,
|
||||||
pub pcx: &'a ParserContext<'a>,
|
pub pcx: &'a ParserContext<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,10 +29,11 @@ impl<'a> IntoIterator for TokenParser<'a> {
|
|||||||
|
|
||||||
impl<'a> TokenParser<'a> {
|
impl<'a> TokenParser<'a> {
|
||||||
/// Create a new argument parser
|
/// Create a new argument parser
|
||||||
pub fn new(mut args: Vec<Sexp>, pcx: &'a ParserContext) -> Self {
|
pub fn new(mut args: Vec<Sexp>, start_pos: SourcePosition, pcx: &'a ParserContext) -> Self {
|
||||||
args.reverse();
|
args.reverse();
|
||||||
Self {
|
Self {
|
||||||
orig_len: args.len(),
|
orig_len: args.len(),
|
||||||
|
start_pos,
|
||||||
args,
|
args,
|
||||||
pcx,
|
pcx,
|
||||||
}
|
}
|
||||||
@@ -59,37 +63,51 @@ impl<'a> TokenParser<'a> {
|
|||||||
self.args.pop()
|
self.args.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the next entry, or raise an error
|
||||||
|
pub fn next_or_err(&mut self) -> Result<Sexp, CrsnError> {
|
||||||
|
match self.next() {
|
||||||
|
None => {
|
||||||
|
Err(CrsnError::Parse("Unexpected end of token list".into(), self.start_pos.clone()))
|
||||||
|
}
|
||||||
|
Some(removed) => Ok(removed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Look at the next entry
|
/// Look at the next entry
|
||||||
pub fn peek(&mut self) -> Option<&Sexp> {
|
pub fn peek(&mut self) -> Option<&Sexp> {
|
||||||
self.args.last()
|
self.args.last()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next string entry
|
/// Get the next string entry
|
||||||
pub fn next_string(&mut self) -> anyhow::Result<String> {
|
pub fn next_string(&mut self) -> Result<(String, SourcePosition), CrsnError> {
|
||||||
let next = self.next();
|
let next = self.next_or_err()?;
|
||||||
let esa = expect_string_atom(next)?;
|
let esa = expect_string_atom(next)?;
|
||||||
Ok(esa)
|
Ok(esa)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next entry as read location
|
/// Get the next entry as read location
|
||||||
pub fn next_rd(&mut self) -> anyhow::Result<Rd> {
|
pub fn next_rd(&mut self) -> Result<Rd, CrsnError> {
|
||||||
parse_rd(self.next(), self.pcx)
|
let next = self.next_or_err()?;
|
||||||
|
parse_rd(next, self.pcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next entry as read location
|
/// Get the next entry as read location
|
||||||
pub fn next_rdobj(&mut self) -> anyhow::Result<RdObj> {
|
pub fn next_rdobj(&mut self) -> Result<RdObj, CrsnError> {
|
||||||
match parse_rd(self.next(), self.pcx)? {
|
match parse_rd(self.next_or_err()?, self.pcx)? {
|
||||||
Rd(RdData::ObjectPtr(reg), Mask::FULL) => {
|
Rd(RdData::ObjectPtr(reg), Mask::FULL) => {
|
||||||
return Ok(RdObj::new(reg));
|
Ok(RdObj::new(reg))
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
anyhow::bail!("Not a valid object handle syntax: {:?}", other);
|
Err(CrsnError::Parse(
|
||||||
|
format!("Not a valid object handle syntax: {:?}", other).into(),
|
||||||
|
self.start_pos.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next entry as write location
|
/// Get the next entry as write location
|
||||||
pub fn next_wr(&mut self) -> anyhow::Result<Wr> {
|
pub fn next_wr(&mut self) -> Result<Wr, CrsnError> {
|
||||||
parse_wr(self.next(), self.pcx)
|
parse_wr(self.next_or_err()?, self.pcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::asm::error::CrsnError;
|
|||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::parse::sexp_expect::expect_list;
|
use crate::asm::parse::sexp_expect::expect_list;
|
||||||
use crate::module::CrsnExtension;
|
use crate::module::CrsnExtension;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
pub mod parse_cond;
|
pub mod parse_cond;
|
||||||
pub mod parse_instr;
|
pub mod parse_instr;
|
||||||
@@ -38,12 +39,12 @@ pub struct ParserState {
|
|||||||
pub constants: HashMap<ConstantName, Value>,
|
pub constants: HashMap<ConstantName, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(source: &str, parsers: &ParserContext) -> Result<Vec<Op>, CrsnError> {
|
pub fn parse(source: &str, pos: SourcePosition, parsers: &ParserContext) -> Result<Vec<Op>, CrsnError> {
|
||||||
let items = expect_list(Some(sexp::parse(source)?), true)?;
|
let (items, _pos) = expect_list(sexp::parse(source)?, true)?;
|
||||||
|
|
||||||
/* numbered labels start with a weird high number
|
/* numbered labels start with a weird high number
|
||||||
to avoid conflicts with user-defined numbered labels */
|
to avoid conflicts with user-defined numbered labels */
|
||||||
let label_num = AtomicU32::new(0x7890_0000);
|
let label_num = AtomicU32::new(0x7890_0000);
|
||||||
parse_instructions(items.into_iter(), parsers)?
|
parse_instructions(items.into_iter(), pos, parsers)?
|
||||||
.flatten(&label_num)
|
.flatten(&label_num)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
|||||||
use crate::asm::patches::TryRemove;
|
use crate::asm::patches::TryRemove;
|
||||||
|
|
||||||
pub fn parse_cond_branch(tok: Sexp, parsers: &ParserContext) -> Result<(Cond, Box<dyn Flatten>), CrsnError> {
|
pub fn parse_cond_branch(tok: Sexp, parsers: &ParserContext) -> Result<(Cond, Box<dyn Flatten>), CrsnError> {
|
||||||
let mut list = expect_list(Some(tok), false)?;
|
let (mut list, pos) = expect_list(tok, false)?;
|
||||||
let kw = expect_string_atom(list.try_remove(0))?;
|
let (kw, kw_pos) = expect_string_atom(list.remove_or_err(0, pos.clone(), "Missing \"cond?\" keyword in conditional branch")?)?;
|
||||||
|
|
||||||
if !kw.ends_with('?') {
|
if !kw.ends_with('?') {
|
||||||
return Err(CrsnError::Parse(format!("Condition must end with '?': {}", kw).into()));
|
return Err(CrsnError::Parse(format!("Condition must end with '?': {}", kw).into(), kw_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((cond::parse_cond(&kw)?, parse_instructions(list.into_iter(), parsers)?))
|
Ok((cond::parse_cond(&kw, kw_pos)?, parse_instructions(list.into_iter(), pos, parsers)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp, SourcePosition};
|
||||||
|
|
||||||
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::{ConstantName, Label, RegisterAlias, Value};
|
use crate::asm::data::literal::{ConstantName, Label, RegisterAlias, Value};
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::parse::ParserContext;
|
use crate::asm::parse::ParserContext;
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
|
use std::num::TryFromIntError;
|
||||||
|
use crate::asm::patches::ErrWithPos;
|
||||||
|
|
||||||
fn is_valid_identifier(name: &str) -> bool {
|
fn is_valid_identifier(name: &str) -> bool {
|
||||||
name.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_')
|
name.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_')
|
||||||
@@ -15,65 +17,60 @@ fn is_valid_identifier(name: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse register alias
|
/// Parse register alias
|
||||||
pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> {
|
pub fn parse_reg_alias(name: Sexp) -> Result<(RegisterAlias, SourcePosition), CrsnError> {
|
||||||
// trace!("parse reg alias: {:?}", name);
|
// trace!("parse reg alias: {:?}", name);
|
||||||
|
|
||||||
let name = expect_string_atom(name)?;
|
let (name, namepos) = expect_string_atom(name)?;
|
||||||
|
|
||||||
if !is_valid_identifier(&name) {
|
if !is_valid_identifier(&name) {
|
||||||
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed register alias.", name).into()));
|
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed register alias.", name).into(), namepos));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(name)
|
Ok((name, namepos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse constant name
|
/// Parse constant name
|
||||||
pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError> {
|
pub fn parse_constant_name(name: Sexp) -> Result<(ConstantName, SourcePosition), CrsnError> {
|
||||||
// trace!("parse const name: {:?}", name);
|
// trace!("parse const name: {:?}", name);
|
||||||
|
|
||||||
let name = expect_string_atom(name)?;
|
let (name, namepos) = expect_string_atom(name)?;
|
||||||
|
|
||||||
if !is_valid_identifier(&name) {
|
if !is_valid_identifier(&name) {
|
||||||
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed constant name.", name).into()));
|
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed constant name.", name).into(), namepos));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(name)
|
Ok((name, namepos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a label
|
/// Parse a label
|
||||||
pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
|
pub fn parse_label(name: Sexp) -> Result<Label, CrsnError> {
|
||||||
// trace!("parse label: {:?}", name);
|
// trace!("parse label: {:?}", name);
|
||||||
let name = expect_string_atom(name)?;
|
let (name, namepos) = expect_string_atom(name)?;
|
||||||
Ok(parse_label_str(&name)?)
|
Ok(parse_label_str(&name, namepos)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_label_str(name: &str) -> Result<Label, CrsnError> {
|
pub fn parse_label_str(name: &str, pos: SourcePosition) -> Result<Label, CrsnError> {
|
||||||
let label = name.trim_start_matches(':');
|
let label = name.trim_start_matches(':');
|
||||||
|
|
||||||
Ok(if label.starts_with('#') {
|
Ok(if label.starts_with('#') {
|
||||||
Label::Numbered(u32::try_from(parse_u64(&label[1..])?).expect("numbered label fit in u32"))
|
let val = parse_u64(&label[1..], pos.clone())?;
|
||||||
|
Label::Numbered(u32::try_from(val).err_pos(pos)?)
|
||||||
} else {
|
} else {
|
||||||
Label::Named(label.to_string())
|
Label::Named(label.to_string())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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>, pcx: &ParserContext) -> Result<DataDisp, CrsnError> {
|
pub fn parse_data_disp(tok: Sexp, pcx: &ParserContext) -> Result<DataDisp, CrsnError> {
|
||||||
// trace!("parse data: {:?}", tok);
|
// trace!("parse data: {:?}", tok);
|
||||||
|
|
||||||
let tok = if let Some(tok) = tok {
|
|
||||||
tok
|
|
||||||
} else {
|
|
||||||
return Err(CrsnError::Parse("Expected data disposition token".into()));
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO implement masks
|
// TODO implement masks
|
||||||
|
|
||||||
match &tok {
|
match tok {
|
||||||
Sexp::Atom(Atom::I(val)) => {
|
Sexp::Atom(Atom::I(val), pos) => {
|
||||||
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(*val) }))
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(val) }))
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::S(s)) => {
|
Sexp::Atom(Atom::S(s), pos) => {
|
||||||
if s == "_" {
|
if s == "_" {
|
||||||
return Ok(DataDisp::Discard);
|
return Ok(DataDisp::Discard);
|
||||||
}
|
}
|
||||||
@@ -81,11 +78,11 @@ pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDis
|
|||||||
// check if we have an alias defined
|
// check if we have an alias defined
|
||||||
{
|
{
|
||||||
let pstate = pcx.state.borrow();
|
let pstate = pcx.state.borrow();
|
||||||
if let Some(val) = pstate.constants.get(s) {
|
if let Some(val) = pstate.constants.get(&s) {
|
||||||
return Ok(DataDisp::Immediate(*val));
|
return Ok(DataDisp::Immediate(*val));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(val) = pstate.reg_aliases.get(s) {
|
if let Some(val) = pstate.reg_aliases.get(&s) {
|
||||||
return Ok(DataDisp::Register(*val));
|
return Ok(DataDisp::Register(*val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,63 +92,55 @@ pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDis
|
|||||||
if let Some(val) = pstate.reg_aliases.get(reference) {
|
if let Some(val) = pstate.reg_aliases.get(reference) {
|
||||||
Ok(DataDisp::ObjectPtr(*val))
|
Ok(DataDisp::ObjectPtr(*val))
|
||||||
} else {
|
} else {
|
||||||
let reg = reg::parse_reg(reference)?;
|
let reg = reg::parse_reg(reference, pos.clone())?;
|
||||||
|
|
||||||
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
|
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
|
||||||
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into()))
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
|
||||||
} else {
|
} else {
|
||||||
Ok(DataDisp::ObjectPtr(reg))
|
Ok(DataDisp::ObjectPtr(reg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if s.starts_with(|c: char| c.is_ascii_digit()) {
|
} else if s.starts_with(|c: char| c.is_ascii_digit()) {
|
||||||
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(s)?) }))
|
Ok(DataDisp::Immediate(unsafe { std::mem::transmute(parse_i64(&s, pos)?) }))
|
||||||
} else {
|
} else {
|
||||||
let reg = reg::parse_reg(s)?;
|
let reg = reg::parse_reg(&s, pos.clone())?;
|
||||||
|
|
||||||
let pstate = pcx.state.borrow();
|
let pstate = pcx.state.borrow();
|
||||||
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
|
if pstate.reg_aliases.values().find(|v| **v == reg).is_some() {
|
||||||
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into()))
|
Err(CrsnError::Parse(format!("Sym exists for register {}, direct access denied. Unsym it if needed.", reg).into(), pos))
|
||||||
} else {
|
} else {
|
||||||
Ok(DataDisp::Register(reg))
|
Ok(DataDisp::Register(reg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
other => {
|
||||||
Err(CrsnError::Parse(format!("bad data disp: {:?}", tok).into()))
|
Err(CrsnError::Parse(format!("bad data disp: {:?}", other).into(), other.pos().clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse immediate value
|
/// Parse immediate value
|
||||||
pub fn parse_value(tok: Option<Sexp>, pcx: &ParserContext) -> Result<Value, CrsnError> {
|
pub fn parse_value(tok: Sexp, pcx: &ParserContext) -> Result<Value, CrsnError> {
|
||||||
let tok = if let Some(tok) = tok {
|
match tok {
|
||||||
tok
|
Sexp::Atom(Atom::I(val), pos) => {
|
||||||
} else {
|
Ok(unsafe { std::mem::transmute(val) })
|
||||||
return Err(CrsnError::Parse("Expected value token".into()));
|
|
||||||
};
|
|
||||||
|
|
||||||
// trace!("parse value: {:?}", tok);
|
|
||||||
|
|
||||||
match &tok {
|
|
||||||
Sexp::Atom(Atom::I(val)) => {
|
|
||||||
Ok(unsafe { std::mem::transmute(*val) })
|
|
||||||
}
|
}
|
||||||
Sexp::Atom(Atom::S(s)) => {
|
Sexp::Atom(Atom::S(s), pos) => {
|
||||||
let pstate = pcx.state.borrow();
|
let pstate = pcx.state.borrow();
|
||||||
if let Some(val) = pstate.constants.get(s) {
|
if let Some(val) = pstate.constants.get(&s) {
|
||||||
return Ok(*val);
|
return Ok(*val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(unsafe { std::mem::transmute(parse_i64(s)?) })
|
Ok(unsafe { std::mem::transmute(parse_i64(&s, pos)?) })
|
||||||
}
|
}
|
||||||
_ => {
|
other => {
|
||||||
Err(CrsnError::Parse(format!("bad value format: {:?}", tok).into()))
|
Err(CrsnError::Parse(format!("bad value format: {:?}", other).into(), other.pos().clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
|
pub fn parse_u64(literal: &str, pos: SourcePosition) -> Result<u64, CrsnError> {
|
||||||
// trace!("parse u64 from {}", literal);
|
// trace!("parse u64 from {}", literal);
|
||||||
let mut without_underscores = Cow::Borrowed(literal);
|
let mut without_underscores = Cow::Borrowed(literal);
|
||||||
if without_underscores.contains('_') {
|
if without_underscores.contains('_') {
|
||||||
@@ -159,27 +148,29 @@ pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hex) = without_underscores.strip_prefix("0x") {
|
if let Some(hex) = without_underscores.strip_prefix("0x") {
|
||||||
Ok(u64::from_str_radix(hex, 16)?)
|
Ok(u64::from_str_radix(hex, 16).err_pos(pos)?)
|
||||||
} else if let Some(hex) = without_underscores.strip_prefix("0b") {
|
} else if let Some(hex) = without_underscores.strip_prefix("0b") {
|
||||||
Ok(u64::from_str_radix(hex, 2)?)
|
Ok(u64::from_str_radix(hex, 2).err_pos(pos)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(u64::from_str_radix(&without_underscores, 10)?)
|
Ok(u64::from_str_radix(&without_underscores, 10).err_pos(pos)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
|
pub fn parse_i64(literal: &str, pos: SourcePosition) -> Result<i64, CrsnError> {
|
||||||
// trace!("parse i64 from {}", literal);
|
// trace!("parse i64 from {}", literal);
|
||||||
if let Some(_value) = literal.strip_prefix("-") {
|
if let Some(_value) = literal.strip_prefix("-") {
|
||||||
Ok(-1 * i64::try_from(parse_u64(literal)?)?)
|
Ok(-1 * i64::try_from(parse_u64(literal, pos.clone())?).err_pos(pos)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(i64::try_from(parse_u64(literal)?)?)
|
Ok(i64::try_from(parse_u64(literal, pos.clone())?).err_pos(pos)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_rd(tok: Option<Sexp>, pcx: &ParserContext) -> anyhow::Result<Rd> {
|
pub fn parse_rd(tok: Sexp, pcx: &ParserContext) -> Result<Rd, CrsnError> {
|
||||||
Ok(Rd::new(RdData::try_from(parse_data_disp(tok, pcx)?)?))
|
let pos = tok.pos().clone();
|
||||||
|
Ok(Rd::new(RdData::try_from(parse_data_disp(tok, pcx)?).err_pos(pos)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_wr(tok: Option<Sexp>, pcx: &ParserContext) -> anyhow::Result<Wr> {
|
pub fn parse_wr(tok: Sexp, pcx: &ParserContext) -> Result<Wr, CrsnError> {
|
||||||
Ok(Wr::new(WrData::try_from(parse_data_disp(tok, pcx)?)?))
|
let pos = tok.pos().clone();
|
||||||
|
Ok(Wr::new(WrData::try_from(parse_data_disp(tok, pcx)?).err_pos(pos)?))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use sexp::Sexp;
|
use sexp::{Sexp, SourcePosition};
|
||||||
|
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
use crate::asm::instr::{Flatten, InstrWithBranches};
|
use crate::asm::instr::{Flatten, InstrWithBranches};
|
||||||
@@ -7,27 +7,27 @@ use crate::asm::parse::parse_cond::parse_cond_branch;
|
|||||||
use crate::asm::parse::parse_routine::parse_routine;
|
use crate::asm::parse::parse_routine::parse_routine;
|
||||||
use crate::asm::parse::ParserContext;
|
use crate::asm::parse::ParserContext;
|
||||||
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::SexpIsA;
|
|
||||||
use crate::module::ParseRes;
|
use crate::module::ParseRes;
|
||||||
|
|
||||||
use super::parse_op::parse_op;
|
use super::parse_op::parse_op;
|
||||||
|
use crate::asm::patches::NextOrErr;
|
||||||
|
|
||||||
pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
|
pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pos: SourcePosition, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
|
||||||
let mut parsed = vec![];
|
let mut parsed = vec![];
|
||||||
for expr in items {
|
for expr in items {
|
||||||
let tokens = expect_list(Some(expr), false)?;
|
let (tokens, listpos) = expect_list(expr, false)?;
|
||||||
|
|
||||||
let mut toki = tokens.into_iter();
|
let mut toki = tokens.into_iter();
|
||||||
let name = expect_string_atom(toki.next())?;
|
let (name, namepos) = expect_string_atom(toki.next_or_err(listpos.clone(), "Expected instruction name token")?)?;
|
||||||
|
|
||||||
if name == "proc" {
|
if name == "proc" {
|
||||||
parsed.push(parse_routine(toki, pcx)?);
|
parsed.push(parse_routine(toki, pos.clone(), pcx)?);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut token_parser = TokenParser::new(toki.collect(), pcx);
|
let mut token_parser = TokenParser::new(toki.collect(), listpos.clone(), pcx);
|
||||||
for p in pcx.parsers {
|
for p in pcx.parsers {
|
||||||
token_parser = match p.parse_syntax(&name, token_parser) {
|
token_parser = match p.parse_syntax(pos.clone(), &name, token_parser) {
|
||||||
Ok(ParseRes::Parsed(op)) => return Ok(op),
|
Ok(ParseRes::Parsed(op)) => return Ok(op),
|
||||||
Ok(ParseRes::ParsedNone) => return Ok(Box::new(())),
|
Ok(ParseRes::ParsedNone) => return Ok(Box::new(())),
|
||||||
Ok(ParseRes::Unknown(to_reuse)) => {
|
Ok(ParseRes::Unknown(to_reuse)) => {
|
||||||
@@ -45,7 +45,7 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext)
|
|||||||
// Get back the original iterator
|
// Get back the original iterator
|
||||||
let toki = token_parser.into_iter();
|
let toki = token_parser.into_iter();
|
||||||
|
|
||||||
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), pcx);
|
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), listpos.clone(), pcx);
|
||||||
let branch_tokens = toki
|
let branch_tokens = toki
|
||||||
.skip_while(|e| e.is_atom())
|
.skip_while(|e| e.is_atom())
|
||||||
.take_while(|e| e.is_list());
|
.take_while(|e| e.is_list());
|
||||||
@@ -62,9 +62,10 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(op) = parse_op(name.as_str(), arg_tokens)? {
|
if let Some(op) = parse_op(name.as_str(), arg_tokens, namepos.clone())? {
|
||||||
parsed.push(Box::new(InstrWithBranches {
|
parsed.push(Box::new(InstrWithBranches {
|
||||||
op,
|
op,
|
||||||
|
pos: namepos,
|
||||||
branches,
|
branches,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,29 @@ use crate::asm::instr::Op;
|
|||||||
use crate::asm::parse::arg_parser::TokenParser;
|
use crate::asm::parse::arg_parser::TokenParser;
|
||||||
use crate::module::ParseRes;
|
use crate::module::ParseRes;
|
||||||
use crate::builtin::BuiltinOps;
|
use crate::builtin::BuiltinOps;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result<Option<Op>, CrsnError> {
|
pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>, spos: SourcePosition) -> Result<Option<Op>, CrsnError> {
|
||||||
// Include built-in instructions
|
// Include built-in instructions
|
||||||
let builtins = [BuiltinOps::new()];
|
let builtins = [BuiltinOps::new()];
|
||||||
let mut cond = None;
|
let mut cond = None;
|
||||||
|
|
||||||
if let Some(pos) = keyword.find('.') {
|
if let Some(pos) = keyword.find('.') {
|
||||||
cond = Some(parse_cond(&keyword[(pos + 1)..])?);
|
cond = Some(parse_cond(&keyword[(pos + 1)..], spos.clone())?);
|
||||||
keyword = &keyword[..pos];
|
keyword = &keyword[..pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
|
for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
|
||||||
arg_tokens = match p.parse_op(keyword, arg_tokens) {
|
arg_tokens = match p.parse_op(spos.clone(), keyword, arg_tokens) {
|
||||||
Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op {
|
Ok(ParseRes::Parsed(kind)) => return Ok(Some(Op {
|
||||||
cond,
|
cond,
|
||||||
|
pos: spos,
|
||||||
kind,
|
kind,
|
||||||
})),
|
})),
|
||||||
Ok(ParseRes::ParsedNone) => return Ok(None),
|
Ok(ParseRes::ParsedNone) => return Ok(None),
|
||||||
Ok(ParseRes::Unknown(to_reuse)) => {
|
Ok(ParseRes::Unknown(to_reuse)) => {
|
||||||
if to_reuse.parsing_started() {
|
if to_reuse.parsing_started() {
|
||||||
panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword);
|
return Err(CrsnError::Parse(format!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword).into(), spos));
|
||||||
}
|
}
|
||||||
to_reuse
|
to_reuse
|
||||||
}
|
}
|
||||||
@@ -34,5 +36,5 @@ pub fn parse_op<'a>(mut keyword: &str, mut arg_tokens: TokenParser<'a>) -> Resul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(CrsnError::Parse(format!("Unknown instruction: {}", keyword).into()));
|
return Err(CrsnError::Parse(format!("Unknown instruction: {}", keyword).into(), spos));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use sexp::Sexp;
|
use sexp::{Sexp, SourcePosition};
|
||||||
|
|
||||||
use crate::asm::data::Register;
|
use crate::asm::data::Register;
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
@@ -7,14 +7,14 @@ use crate::asm::parse::{parse_instructions, ParserContext};
|
|||||||
use crate::asm::parse::arg_parser::TokenParser;
|
use crate::asm::parse::arg_parser::TokenParser;
|
||||||
use crate::asm::parse::parse_data::parse_reg_alias;
|
use crate::asm::parse::parse_data::parse_reg_alias;
|
||||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||||
use crate::asm::patches::SexpIsA;
|
|
||||||
use crate::builtin::parse::parse_routine_name;
|
use crate::builtin::parse::parse_routine_name;
|
||||||
|
use crate::asm::patches::NextOrErr;
|
||||||
|
|
||||||
pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
|
pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, rt_pos: SourcePosition, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
|
||||||
let name = expect_string_atom(toki.next())?;
|
let (name, namepos) = expect_string_atom(toki.next_or_err(rt_pos.clone(), "Expected routine name")?)?;
|
||||||
let mut name = parse_routine_name(name)?;
|
let mut name = parse_routine_name(name, namepos)?;
|
||||||
|
|
||||||
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), pcx);
|
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), rt_pos.clone(), pcx);
|
||||||
|
|
||||||
// If arity is explicitly given, then either no named argument must be provided,
|
// If arity is explicitly given, then either no named argument must be provided,
|
||||||
// or their count must match the arity. If no arity is given, then arity is determined
|
// or their count must match the arity. If no arity is given, then arity is determined
|
||||||
@@ -22,7 +22,7 @@ pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserCon
|
|||||||
if name.arity == 0 && arg_tokens.len() != 0 {
|
if name.arity == 0 && arg_tokens.len() != 0 {
|
||||||
name.arity = arg_tokens.len() as u8;
|
name.arity = arg_tokens.len() as u8;
|
||||||
} else if arg_tokens.len() != 0 && name.arity as usize != arg_tokens.len() {
|
} else if arg_tokens.len() != 0 && name.arity as usize != arg_tokens.len() {
|
||||||
return Err(CrsnError::Parse(format!("arity mismatch in routine {}", name.name).into()));
|
return Err(CrsnError::Parse(format!("arity mismatch in routine {}", name.name).into(), rt_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
let toki = toki.skip_while(|e| e.is_atom());
|
let toki = toki.skip_while(|e| e.is_atom());
|
||||||
@@ -34,17 +34,17 @@ pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserCon
|
|||||||
pstate.reg_alias_stack.push(old);
|
pstate.reg_alias_stack.push(old);
|
||||||
|
|
||||||
for (n, tok) in arg_tokens.into_iter().enumerate() {
|
for (n, tok) in arg_tokens.into_iter().enumerate() {
|
||||||
let alias = parse_reg_alias(Some(tok))?;
|
let alias = parse_reg_alias(tok)?;
|
||||||
|
|
||||||
if pstate.constants.contains_key(&alias) {
|
if pstate.constants.contains_key(&alias.0) {
|
||||||
return Err(CrsnError::Parse(format!("Symbol \"{}\" already used for a constant.", alias).into()));
|
return Err(CrsnError::Parse(format!("Symbol \"{}\" already used for a constant.", alias.0).into(), alias.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
pstate.reg_aliases.insert(alias, Register::Arg(n as u8));
|
pstate.reg_aliases.insert(alias.0, Register::Arg(n as u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = parse_instructions(toki, pcx)?;
|
let body = parse_instructions(toki, rt_pos.clone(), pcx)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut pstate = pcx.state.borrow_mut();
|
let mut pstate = pcx.state.borrow_mut();
|
||||||
@@ -54,6 +54,7 @@ pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserCon
|
|||||||
|
|
||||||
return Ok(Box::new(Routine {
|
return Ok(Box::new(Routine {
|
||||||
name,
|
name,
|
||||||
|
pos: rt_pos,
|
||||||
body,
|
body,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,37 @@
|
|||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp, SourcePosition};
|
||||||
|
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
|
|
||||||
pub fn expect_list(expr: Option<Sexp>, allow_empty: bool) -> Result<Vec<Sexp>, CrsnError> {
|
pub fn expect_list(expr: Sexp, allow_empty: bool) -> Result<(Vec<Sexp>, SourcePosition), CrsnError> {
|
||||||
if let Some(expr) = expr {
|
match expr {
|
||||||
match &expr {
|
Sexp::Atom(_, pos) => {
|
||||||
Sexp::Atom(_) => {
|
return Err(CrsnError::Parse("Expected a list".into(), pos));
|
||||||
return Err(CrsnError::ParseIn("Expected a list".into(), expr));
|
}
|
||||||
|
Sexp::List(list, pos) => {
|
||||||
|
if !allow_empty && list.is_empty() {
|
||||||
|
return Err(CrsnError::Parse("Routine: Empty list".into(), pos));
|
||||||
}
|
}
|
||||||
Sexp::List(list) => {
|
|
||||||
if !allow_empty && list.is_empty() {
|
|
||||||
return Err(CrsnError::ParseIn("Routine: Empty list".into(), expr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Sexp::List(list) = expr {
|
Ok((list, pos))
|
||||||
return Ok(list);
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(CrsnError::Parse("Expected a list, got nothing".into()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_atom(expr: Option<Sexp>) -> Result<Atom, CrsnError> {
|
pub fn expect_atom(expr: Sexp) -> Result<(Atom, SourcePosition), CrsnError> {
|
||||||
if let Some(expr) = expr {
|
match expr {
|
||||||
match &expr {
|
Sexp::Atom(a, pos) => {
|
||||||
Sexp::Atom(_atom) => {
|
Ok((a, pos))
|
||||||
if let Sexp::Atom(a) = expr {
|
}
|
||||||
return Ok(a);
|
Sexp::List(_, pos) => {
|
||||||
} else {
|
return Err(CrsnError::Parse("Expected atom got list".into(), pos));
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Sexp::List(_) => {
|
|
||||||
return Err(CrsnError::ParseIn("Expected atom got list".into(), expr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(CrsnError::Parse("Expected atom, got nothing".into()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_string_atom(expr: Option<Sexp>) -> Result<String, CrsnError> {
|
pub fn expect_string_atom(expr: Sexp) -> Result<(String, SourcePosition), CrsnError> {
|
||||||
match expect_atom(expr) {
|
match expect_atom(expr) {
|
||||||
Ok(Atom::S(s)) => Ok(s),
|
Ok((Atom::S(s), pos)) => Ok((s, pos)),
|
||||||
Ok(atom) => Err(CrsnError::ParseIn("Expected string atom".into(), Sexp::Atom(atom))),
|
Ok((_, pos)) => Err(CrsnError::Parse("Expected string atom".into(), pos)),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,59 @@
|
|||||||
pub use sexp_is_a::SexpIsA;
|
use sexp::SourcePosition;
|
||||||
pub use try_remove::TryRemove;
|
use crate::asm::error::CrsnError;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
mod try_remove;
|
pub trait TryRemove {
|
||||||
mod sexp_is_a;
|
type Item;
|
||||||
|
fn try_remove(&mut self, index: usize) -> Option<Self::Item>;
|
||||||
|
|
||||||
|
fn remove_or_err(&mut self, index: usize, pos: SourcePosition, err : &'static str) -> Result<Self::Item, CrsnError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TryRemove for Vec<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn try_remove(&mut self, index: usize) -> Option<T> {
|
||||||
|
if self.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.remove(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_or_err(&mut self, index: usize, pos: SourcePosition, err : &'static str) -> Result<Self::Item, CrsnError> {
|
||||||
|
match self.try_remove(index) {
|
||||||
|
None => {
|
||||||
|
Err(CrsnError::Parse(err.into(), pos))
|
||||||
|
}
|
||||||
|
Some(removed) => Ok(removed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NextOrErr<T> {
|
||||||
|
fn next_or_err(&mut self, pos: SourcePosition, err : &'static str) -> Result<T, CrsnError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, K : Iterator<Item=T>> NextOrErr<T> for K {
|
||||||
|
fn next_or_err(&mut self, pos: SourcePosition, err: &'static str) -> Result<T, CrsnError> {
|
||||||
|
match self.next() {
|
||||||
|
None => {
|
||||||
|
Err(CrsnError::Parse(err.into(), pos))
|
||||||
|
}
|
||||||
|
Some(removed) => Ok(removed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ErrWithPos<T> {
|
||||||
|
fn err_pos(self, pos : SourcePosition) -> Result<T, CrsnError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E : std::error::Error + Send + Sync + 'static> ErrWithPos<T> for Result<T, E> {
|
||||||
|
fn err_pos(self, pos : SourcePosition) -> Result<T, CrsnError> {
|
||||||
|
match self {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(e) => Err(CrsnError::ParseOther(Box::new(e), pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
use sexp::Sexp;
|
|
||||||
|
|
||||||
pub trait SexpIsA {
|
|
||||||
fn is_atom(&self) -> bool;
|
|
||||||
|
|
||||||
fn is_list(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SexpIsA for Sexp {
|
|
||||||
fn is_atom(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Sexp::Atom(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_list(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Sexp::List(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
pub trait TryRemove {
|
|
||||||
type Item;
|
|
||||||
fn try_remove(&mut self, index: usize) -> Option<Self::Item>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TryRemove for Vec<T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn try_remove(&mut self, index: usize) -> Option<T> {
|
|
||||||
if self.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(self.remove(index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@ use crate::asm::data::{Rd, RdObj, Wr};
|
|||||||
use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
|
use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
|
||||||
use crate::asm::instr::Op;
|
use crate::asm::instr::Op;
|
||||||
use crate::asm::instr::op::OpKind;
|
use crate::asm::instr::op::OpKind;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Barrier {
|
pub enum Barrier {
|
||||||
@@ -60,10 +61,11 @@ pub enum BuiltinOp {
|
|||||||
LoadStatus { src: Rd },
|
LoadStatus { src: Rd },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BuiltinOp> for Op {
|
impl BuiltinOp {
|
||||||
fn from(bo: BuiltinOp) -> Self {
|
pub fn into_op(self: BuiltinOp, pos: SourcePosition) -> Op {
|
||||||
Op {
|
Op {
|
||||||
kind: bo.into(),
|
kind: self.into(),
|
||||||
|
pos,
|
||||||
cond: None,
|
cond: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::module::{CrsnExtension, ParseRes};
|
|||||||
use crate::asm::parse::arg_parser::TokenParser;
|
use crate::asm::parse::arg_parser::TokenParser;
|
||||||
use crate::asm::instr::op::OpKind;
|
use crate::asm::instr::op::OpKind;
|
||||||
use crate::asm::error::CrsnError;
|
use crate::asm::error::CrsnError;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
|
||||||
pub mod defs;
|
pub mod defs;
|
||||||
pub mod exec;
|
pub mod exec;
|
||||||
@@ -21,7 +22,7 @@ impl CrsnExtension for BuiltinOps {
|
|||||||
"builtin"
|
"builtin"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
fn parse_op<'a>(&self, pos: SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
parse::parse_op(keyword, args)
|
parse::parse_op(pos, keyword, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-30
@@ -1,4 +1,4 @@
|
|||||||
use sexp::{Atom, Sexp};
|
use sexp::{Atom, Sexp, SourcePosition};
|
||||||
|
|
||||||
use crate::asm::data::literal::{Label, RoutineName};
|
use crate::asm::data::literal::{Label, RoutineName};
|
||||||
use crate::asm::data::reg::parse_reg;
|
use crate::asm::data::reg::parse_reg;
|
||||||
@@ -10,9 +10,10 @@ use crate::asm::parse::sexp_expect::expect_string_atom;
|
|||||||
use crate::builtin::defs::{Barrier, BuiltinOp};
|
use crate::builtin::defs::{Barrier, BuiltinOp};
|
||||||
use crate::module::{ParseRes};
|
use crate::module::{ParseRes};
|
||||||
use crate::utils::A;
|
use crate::utils::A;
|
||||||
|
use crate::asm::patches::ErrWithPos;
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse_op<'a>(op_pos: SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
let pcx = args.pcx;
|
let pcx = args.pcx;
|
||||||
|
|
||||||
Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword {
|
Ok(ParseRes::Parsed(OpKind::BuiltIn(match keyword {
|
||||||
@@ -31,22 +32,23 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
}
|
}
|
||||||
|
|
||||||
"sym" => {
|
"sym" => {
|
||||||
let alias = parse_reg_alias(args.next())?;
|
let (alias, aliaspos) = parse_reg_alias(args.next_or_err()?)?;
|
||||||
trace!("alias={:?}", alias);
|
trace!("alias={:?}", alias);
|
||||||
let register = parse_reg(&args.next_string()?)?;
|
let (rn, rpos) = args.next_string()?;
|
||||||
|
let register = parse_reg(&rn, rpos.clone())?;
|
||||||
trace!("register={:?}", alias);
|
trace!("register={:?}", alias);
|
||||||
|
|
||||||
let mut pstate = pcx.state.borrow_mut();
|
let mut pstate = pcx.state.borrow_mut();
|
||||||
if pstate.reg_aliases.contains_key(&alias) {
|
if pstate.reg_aliases.contains_key(&alias) {
|
||||||
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into()));
|
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into(), rpos));
|
||||||
}
|
}
|
||||||
|
|
||||||
if pstate.constants.contains_key(&alias) {
|
if pstate.constants.contains_key(&alias) {
|
||||||
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into()));
|
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into(), aliaspos));
|
||||||
}
|
}
|
||||||
|
|
||||||
if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).is_some() {
|
if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).is_some() {
|
||||||
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into()));
|
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into(), rpos));
|
||||||
}
|
}
|
||||||
|
|
||||||
pstate.reg_aliases.insert(alias, register);
|
pstate.reg_aliases.insert(alias, register);
|
||||||
@@ -55,26 +57,26 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
}
|
}
|
||||||
|
|
||||||
"unsym" => {
|
"unsym" => {
|
||||||
let alias = parse_reg_alias(args.next())?;
|
let alias = parse_reg_alias(args.next_or_err()?)?;
|
||||||
|
|
||||||
let mut pstate = pcx.state.borrow_mut();
|
let mut pstate = pcx.state.borrow_mut();
|
||||||
if pstate.reg_aliases.remove(&alias).is_none() {
|
if pstate.reg_aliases.remove(&alias.0).is_none() {
|
||||||
return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias).into()));
|
return Err(CrsnError::Parse(format!("Register alias \"{}\" not defined!", alias.0).into(), alias.1));
|
||||||
}
|
}
|
||||||
return Ok(ParseRes::ParsedNone);
|
return Ok(ParseRes::ParsedNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
"def" => {
|
"def" => {
|
||||||
let name = parse_constant_name(args.next())?;
|
let (name, namepos) = parse_constant_name(args.next_or_err()?)?;
|
||||||
let value = parse_value(args.next(), pcx)?;
|
let value = parse_value(args.next_or_err()?, pcx)?;
|
||||||
|
|
||||||
let mut pstate = pcx.state.borrow_mut();
|
let mut pstate = pcx.state.borrow_mut();
|
||||||
if pstate.constants.contains_key(&name) {
|
if pstate.constants.contains_key(&name) {
|
||||||
return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into()));
|
return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into(), namepos));
|
||||||
}
|
}
|
||||||
|
|
||||||
if pstate.reg_aliases.contains_key(&name) {
|
if pstate.reg_aliases.contains_key(&name) {
|
||||||
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into()));
|
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into(), namepos));
|
||||||
}
|
}
|
||||||
|
|
||||||
pstate.constants.insert(name, value);
|
pstate.constants.insert(name, value);
|
||||||
@@ -83,31 +85,31 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
}
|
}
|
||||||
|
|
||||||
"undef" => {
|
"undef" => {
|
||||||
let name = parse_constant_name(args.next())?;
|
let (name, namepos) = parse_constant_name(args.next_or_err()?)?;
|
||||||
|
|
||||||
let mut pstate = pcx.state.borrow_mut();
|
let mut pstate = pcx.state.borrow_mut();
|
||||||
if pstate.constants.remove(&name).is_none() {
|
if pstate.constants.remove(&name).is_none() {
|
||||||
return Err(CrsnError::Parse(format!("Constant \"{}\" not defined!", name).into()));
|
return Err(CrsnError::Parse(format!("Constant \"{}\" not defined!", name).into(), namepos));
|
||||||
}
|
}
|
||||||
return Ok(ParseRes::ParsedNone);
|
return Ok(ParseRes::ParsedNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
"j" => {
|
"j" => {
|
||||||
let dest = parse_label(args.next())?;
|
let dest = parse_label(args.next_or_err()?)?;
|
||||||
BuiltinOp::Jump(dest)
|
BuiltinOp::Jump(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
"fj" => {
|
"fj" => {
|
||||||
let dest = parse_label(args.next())?;
|
let dest = parse_label(args.next_or_err()?)?;
|
||||||
BuiltinOp::FarJump(dest)
|
BuiltinOp::FarJump(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
"call" => {
|
"call" => {
|
||||||
let dest = RoutineName { name: args.next_string()?, arity: args.len() as u8 };
|
let dest = RoutineName { name: args.next_string()?.0, arity: args.len() as u8 };
|
||||||
|
|
||||||
let mut call_args = vec![];
|
let mut call_args = vec![];
|
||||||
for t in args {
|
for t in args {
|
||||||
call_args.push(parse_rd(Some(t), pcx)?);
|
call_args.push(parse_rd(t, pcx)?);
|
||||||
}
|
}
|
||||||
BuiltinOp::Call(dest, call_args)
|
BuiltinOp::Call(dest, call_args)
|
||||||
}
|
}
|
||||||
@@ -115,14 +117,14 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
"ret" => {
|
"ret" => {
|
||||||
let mut ret_vals = vec![];
|
let mut ret_vals = vec![];
|
||||||
for t in args {
|
for t in args {
|
||||||
ret_vals.push(parse_rd(Some(t), pcx)?);
|
ret_vals.push(parse_rd(t, pcx)?);
|
||||||
}
|
}
|
||||||
BuiltinOp::Ret(ret_vals)
|
BuiltinOp::Ret(ret_vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
"routine" => {
|
"routine" => {
|
||||||
let name = args.next_string()?;
|
let name = args.next_string()?;
|
||||||
BuiltinOp::Routine(parse_routine_name(name)?)
|
BuiltinOp::Routine(parse_routine_name(name.0, name.1)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
"skip" => {
|
"skip" => {
|
||||||
@@ -134,21 +136,21 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
kind: Barrier::Standalone,
|
kind: Barrier::Standalone,
|
||||||
msg: match args.next() {
|
msg: match args.next() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
Some(s) => Some(expect_string_atom(s)?.0.into()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"barrier-open" => {
|
"barrier-open" => {
|
||||||
BuiltinOp::Barrier {
|
BuiltinOp::Barrier {
|
||||||
kind: Barrier::Open(parse_label(args.next())?),
|
kind: Barrier::Open(parse_label(args.next_or_err()?)?),
|
||||||
msg: None,
|
msg: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"barrier-close" => {
|
"barrier-close" => {
|
||||||
BuiltinOp::Barrier {
|
BuiltinOp::Barrier {
|
||||||
kind: Barrier::Close(parse_label(args.next())?),
|
kind: Barrier::Close(parse_label(args.next_or_err()?)?),
|
||||||
msg: None,
|
msg: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +158,7 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
"fault" => {
|
"fault" => {
|
||||||
BuiltinOp::Fault(match args.next() {
|
BuiltinOp::Fault(match args.next() {
|
||||||
None => None,
|
None => None,
|
||||||
Some(s) => Some(expect_string_atom(Some(s))?.into()),
|
Some(s) => Some(expect_string_atom(s)?.0.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
}
|
}
|
||||||
|
|
||||||
"far" => {
|
"far" => {
|
||||||
if let Some(Sexp::Atom(Atom::S(ref label))) = args.peek() {
|
if let Some(Sexp::Atom(Atom::S(ref label), _)) = args.peek() {
|
||||||
if let Some(label) = label.strip_prefix(':') {
|
if let Some(label) = label.strip_prefix(':') {
|
||||||
let label = Label::Named(label.to_string());
|
let label = Label::Named(label.to_string());
|
||||||
BuiltinOp::FarLabel(label)
|
BuiltinOp::FarLabel(label)
|
||||||
@@ -198,7 +200,7 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
|
|
||||||
other => {
|
other => {
|
||||||
if let Some(label) = other.strip_prefix(':') {
|
if let Some(label) = other.strip_prefix(':') {
|
||||||
BuiltinOp::Label(parse_label_str(label)?)
|
BuiltinOp::Label(parse_label_str(label, op_pos)?)
|
||||||
} else {
|
} else {
|
||||||
return Ok(ParseRes::Unknown(args));
|
return Ok(ParseRes::Unknown(args));
|
||||||
}
|
}
|
||||||
@@ -206,11 +208,11 @@ pub(crate) fn parse_op<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<P
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_routine_name(name: String) -> Result<RoutineName, CrsnError> {
|
pub(crate) fn parse_routine_name(name: String, pos: SourcePosition) -> Result<RoutineName, CrsnError> {
|
||||||
let (name, arity) = if let Some(n) = name.find('/') {
|
let (name, arity) = if let Some(n) = name.find('/') {
|
||||||
(
|
(
|
||||||
(&name[0..n]).to_string(),
|
(&name[0..n]).to_string(),
|
||||||
(&name[(n + 1)..]).parse::<u8>()?
|
(&name[(n + 1)..]).parse::<u8>().err_pos(pos)?
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(name, 0)
|
(name, 0)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use crate::asm::parse::arg_parser::TokenParser;
|
|||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
use crate::runtime::run_thread::state::RunState;
|
use crate::runtime::run_thread::state::RunState;
|
||||||
use crate::runtime::run_thread::ThreadInfo;
|
use crate::runtime::run_thread::ThreadInfo;
|
||||||
use sexp::Sexp;
|
use sexp::{Sexp, SourcePosition};
|
||||||
|
|
||||||
|
|
||||||
mod eval_res;
|
mod eval_res;
|
||||||
@@ -53,12 +53,12 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
|
|||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// pcx is available on the arg_tokens parser
|
/// pcx is available on the arg_tokens parser
|
||||||
fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError>;
|
fn parse_op<'a>(&self, pos: SourcePosition, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError>;
|
||||||
|
|
||||||
/// Parse a generic S-expression (non-op)
|
/// Parse a generic S-expression (non-op)
|
||||||
///
|
///
|
||||||
/// pcx is available on the arg_tokens parser
|
/// pcx is available on the arg_tokens parser
|
||||||
fn parse_syntax<'a>(&self, keyword: &str, tokens: TokenParser<'a>)
|
fn parse_syntax<'a>(&self, pos: SourcePosition, keyword: &str, tokens: TokenParser<'a>)
|
||||||
-> Result<ParseRes<'a, Box<dyn Flatten>>, CrsnError>
|
-> Result<ParseRes<'a, Box<dyn Flatten>>, CrsnError>
|
||||||
{
|
{
|
||||||
Ok(ParseRes::Unknown(tokens))
|
Ok(ParseRes::Unknown(tokens))
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use crate::asm::instr::op::OpKind;
|
|||||||
use crate::builtin::defs::{Barrier, BuiltinOp};
|
use crate::builtin::defs::{Barrier, BuiltinOp};
|
||||||
use crate::module::CrsnExtension;
|
use crate::module::CrsnExtension;
|
||||||
use crate::runtime::fault::Fault;
|
use crate::runtime::fault::Fault;
|
||||||
|
use sexp::SourcePosition;
|
||||||
|
use crate::asm::error::CrsnError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
@@ -20,7 +22,7 @@ pub struct Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
pub fn new(ops: Vec<Op>, extensions: Arc<Vec<Box<dyn CrsnExtension>>>) -> anyhow::Result<Arc<Self>> {
|
pub fn new(ops: Vec<Op>, extensions: Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Self>, CrsnError> {
|
||||||
let mut p = Self {
|
let mut p = Self {
|
||||||
ops,
|
ops,
|
||||||
extensions,
|
extensions,
|
||||||
@@ -33,7 +35,7 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find all the named things
|
/// Find all the named things
|
||||||
fn scan(&mut self) -> anyhow::Result<()> {
|
fn scan(&mut self) -> Result<(), CrsnError> {
|
||||||
let mut barrier_starts: HashMap<&Label, Addr> = HashMap::new();
|
let mut barrier_starts: HashMap<&Label, Addr> = HashMap::new();
|
||||||
for (pos, op) in self.ops.iter().enumerate() {
|
for (pos, op) in self.ops.iter().enumerate() {
|
||||||
match &op.kind {
|
match &op.kind {
|
||||||
@@ -60,7 +62,7 @@ impl Program {
|
|||||||
self.barriers.push((start_pos, pos.into()));
|
self.barriers.push((start_pos, pos.into()));
|
||||||
self.far_labels.insert(lbl.clone(), pos.into());
|
self.far_labels.insert(lbl.clone(), pos.into());
|
||||||
} else {
|
} else {
|
||||||
anyhow::bail!("Block barrier \"{:?}\" closed without being open!", msg);
|
return Err(CrsnError::Parse(format!("Block barrier \"{:?}\" closed without being open!", msg).into(), op.pos.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpKind::BuiltIn(
|
OpKind::BuiltIn(
|
||||||
@@ -76,7 +78,9 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !barrier_starts.is_empty() {
|
if !barrier_starts.is_empty() {
|
||||||
anyhow::bail!("Some block barriers open without being closed!");
|
return Err(CrsnError::Parse(format!("Block barrier open without being closed: {}",
|
||||||
|
barrier_starts.iter().next().unwrap().0).into(),
|
||||||
|
Default::default()));
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Program scanned: {:?}", self);
|
trace!("Program scanned: {:?}", self);
|
||||||
@@ -87,7 +91,15 @@ impl Program {
|
|||||||
/// Read a program instruction at address
|
/// Read a program instruction at address
|
||||||
pub fn read(&self, addr: Addr) -> &Op {
|
pub fn read(&self, addr: Addr) -> &Op {
|
||||||
if addr.0 >= self.ops.len() as u64 {
|
if addr.0 >= self.ops.len() as u64 {
|
||||||
&Op { kind: OpKind::BuiltIn(BuiltinOp::Halt), cond: None }
|
&Op {
|
||||||
|
kind: OpKind::BuiltIn(BuiltinOp::Halt),
|
||||||
|
pos: SourcePosition {
|
||||||
|
line: 0,
|
||||||
|
column: 0,
|
||||||
|
index: 0
|
||||||
|
},
|
||||||
|
cond: None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
&self.ops[addr.0 as usize]
|
&self.ops[addr.0 as usize]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ pub fn A(s: impl Display) -> Sexp {
|
|||||||
|
|
||||||
let x: Result<i64, _> = FromStr::from_str(&s);
|
let x: Result<i64, _> = FromStr::from_str(&s);
|
||||||
if let Ok(x) = x {
|
if let Ok(x) = x {
|
||||||
return Sexp::Atom(Atom::I(x));
|
return Sexp::Atom(Atom::I(x), Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
let y: Result<f64, _> = FromStr::from_str(&s);
|
let y: Result<f64, _> = FromStr::from_str(&s);
|
||||||
if let Ok(y) = y {
|
if let Ok(y) = y {
|
||||||
return Sexp::Atom(Atom::F(y));
|
return Sexp::Atom(Atom::F(y), Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
Sexp::Atom(Atom::S(s))
|
Sexp::Atom(Atom::S(s), Default::default())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crsn::asm::error::CrsnError;
|
|||||||
use crsn::asm::instr::op::OpKind;
|
use crsn::asm::instr::op::OpKind;
|
||||||
use crsn::asm::parse::arg_parser::TokenParser;
|
use crsn::asm::parse::arg_parser::TokenParser;
|
||||||
use crsn::module::{CrsnExtension, ParseRes};
|
use crsn::module::{CrsnExtension, ParseRes};
|
||||||
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -21,7 +22,7 @@ impl CrsnExtension for ArithOps {
|
|||||||
"arith"
|
"arith"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
fn parse_op<'a>(&self, pos: SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
parse::parse(keyword, args)
|
parse::parse(pos, keyword, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-16
@@ -5,8 +5,9 @@ use crsn::asm::parse::arg_parser::TokenParser;
|
|||||||
use crsn::module::ParseRes;
|
use crsn::module::ParseRes;
|
||||||
|
|
||||||
use crate::defs::ArithOp;
|
use crate::defs::ArithOp;
|
||||||
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse<'a>(pos: SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
Ok(ParseRes::ext(match keyword {
|
Ok(ParseRes::ext(match keyword {
|
||||||
"cmp" => {
|
"cmp" => {
|
||||||
ArithOp::Compare {
|
ArithOp::Compare {
|
||||||
@@ -56,7 +57,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Add requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +80,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Sub requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +103,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Mul requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +130,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into()));
|
return Err(CrsnError::Parse("DivR requires 3 or 4 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +156,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Div requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +180,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Mod requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +203,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("And requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,7 +226,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Or requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,7 +249,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Xor requires 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +270,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into()));
|
return Err(CrsnError::Parse("Cpl requires 1 or 2 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,7 +301,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Rol requires 1, 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,7 +332,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Ror requires 1, 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,7 +363,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Lsl requires 1, 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +394,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Lsr requires 1, 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,7 +425,7 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into()));
|
return Err(CrsnError::Parse("Asr requires 1, 2 or 3 arguments".into(), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crsn::asm::error::CrsnError;
|
|||||||
use crsn::asm::instr::op::OpKind;
|
use crsn::asm::instr::op::OpKind;
|
||||||
use crsn::asm::parse::arg_parser::TokenParser;
|
use crsn::asm::parse::arg_parser::TokenParser;
|
||||||
use crsn::module::{CrsnExtension, ParseRes};
|
use crsn::module::{CrsnExtension, ParseRes};
|
||||||
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -24,7 +25,7 @@ impl CrsnExtension for ScreenOps {
|
|||||||
"screen"
|
"screen"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
fn parse_op<'a>(&self, pos: SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
parse::parse(keyword, args)
|
parse::parse(pos, keyword, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ use crsn::asm::parse::arg_parser::TokenParser;
|
|||||||
use crsn::module::ParseRes;
|
use crsn::module::ParseRes;
|
||||||
|
|
||||||
use crate::defs::ScreenOp;
|
use crate::defs::ScreenOp;
|
||||||
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse<'a>(pos: SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
Ok(ParseRes::ext(match keyword {
|
Ok(ParseRes::ext(match keyword {
|
||||||
"sc-init" => {
|
"sc-init" => {
|
||||||
ScreenOp::ScreenInit {
|
ScreenOp::ScreenInit {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crsn::asm::parse::arg_parser::TokenParser;
|
|||||||
use crsn::module::{CrsnExtension, ParseRes};
|
use crsn::module::{CrsnExtension, ParseRes};
|
||||||
use crsn::runtime::fault::Fault;
|
use crsn::runtime::fault::Fault;
|
||||||
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
use crsn::runtime::run_thread::{RunState, ThreadInfo};
|
||||||
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
mod defs;
|
mod defs;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -24,8 +25,8 @@ impl CrsnExtension for StackOps {
|
|||||||
"stacks"
|
"stacks"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
fn parse_op<'a>(&self, pos: SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
parse::parse(keyword, args)
|
parse::parse(pos, keyword, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
fn drop_obj(&self, _ti: &ThreadInfo, state: &mut RunState, handle: Value) -> Result<Option<()>, Fault> {
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ use crsn::asm::parse::arg_parser::TokenParser;
|
|||||||
use crsn::module::ParseRes;
|
use crsn::module::ParseRes;
|
||||||
|
|
||||||
use crate::defs::StackOp;
|
use crate::defs::StackOp;
|
||||||
|
use crsn::sexp::SourcePosition;
|
||||||
|
|
||||||
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
pub(crate) fn parse<'a>(pos: SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||||
Ok(ParseRes::ext(match keyword {
|
Ok(ParseRes::ext(match keyword {
|
||||||
"stack" => {
|
"stack" => {
|
||||||
StackOp::NewStack {
|
StackOp::NewStack {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub struct Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Position in the input string
|
/// Position in the input string
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, Default)]
|
||||||
pub struct SourcePosition {
|
pub struct SourcePosition {
|
||||||
/// The line number on which the error occurred.
|
/// The line number on which the error occurred.
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
@@ -76,10 +76,10 @@ pub(crate) fn err<T>(message: &'static str, s: &str, pos: &usize) -> ERes<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Build a span
|
/// Build a span
|
||||||
pub(crate) fn spos(s: &str, pos: &usize) -> Option<Box<SourcePosition>> {
|
pub(crate) fn spos(s: &str, pos: &usize) -> SourcePosition {
|
||||||
if *pos >= s.len() {
|
if *pos >= s.len() {
|
||||||
None
|
Default::default()
|
||||||
} else {
|
} else {
|
||||||
Some(Box::new(get_line_and_column(s, *pos)))
|
get_line_and_column(s, *pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
//! Use `parse` to get an s-expression from its string representation, and the
|
//! Use `parse` to get an s-expression from its string representation, and the
|
||||||
//! `Display` trait to serialize it, potentially by doing `sexp.to_string()`.
|
//! `Display` trait to serialize it, potentially by doing `sexp.to_string()`.
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -38,9 +37,33 @@ pub enum Atom {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Sexp {
|
pub enum Sexp {
|
||||||
/// Atom
|
/// Atom
|
||||||
Atom(Atom, Option<Box<SourcePosition>>),
|
Atom(Atom, SourcePosition),
|
||||||
/// List of expressions
|
/// List of expressions
|
||||||
List(Vec<Sexp>, Option<Box<SourcePosition>>),
|
List(Vec<Sexp>, SourcePosition),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sexp {
|
||||||
|
pub fn pos(&self) -> &SourcePosition {
|
||||||
|
match self {
|
||||||
|
Sexp::List(_, pos) | Sexp::Atom(_, pos) => pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check fi thsi Sexp is an atom
|
||||||
|
pub fn is_atom(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Sexp::Atom(_, _) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check fi thsi Sexp is a list
|
||||||
|
pub fn is_list(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Sexp::List(_, _) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Sexp {
|
impl PartialEq for Sexp {
|
||||||
@@ -207,22 +230,22 @@ fn parse_sexp(s: &str, pos: &mut usize) -> ERes<Sexp> {
|
|||||||
|
|
||||||
/// Constructs an atomic s-expression from a string.
|
/// Constructs an atomic s-expression from a string.
|
||||||
pub fn atom_s(s: &str) -> Sexp {
|
pub fn atom_s(s: &str) -> Sexp {
|
||||||
Sexp::Atom(Atom::S(s.to_owned()), None)
|
Sexp::Atom(Atom::S(s.to_owned()), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an atomic s-expression from an int.
|
/// Constructs an atomic s-expression from an int.
|
||||||
pub fn atom_i(i: i64) -> Sexp {
|
pub fn atom_i(i: i64) -> Sexp {
|
||||||
Sexp::Atom(Atom::I(i), None)
|
Sexp::Atom(Atom::I(i), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an atomic s-expression from a float.
|
/// Constructs an atomic s-expression from a float.
|
||||||
pub fn atom_f(f: f64) -> Sexp {
|
pub fn atom_f(f: f64) -> Sexp {
|
||||||
Sexp::Atom(Atom::F(f), None)
|
Sexp::Atom(Atom::F(f), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a list s-expression given a slice of s-expressions.
|
/// Constructs a list s-expression given a slice of s-expressions.
|
||||||
pub fn list(xs: &[Sexp]) -> Sexp {
|
pub fn list(xs: &[Sexp]) -> Sexp {
|
||||||
Sexp::List(xs.to_owned(), None)
|
Sexp::List(xs.to_owned(), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an s-expression out of a `&str`.
|
/// Reads an s-expression out of a `&str`.
|
||||||
|
|||||||
Reference in New Issue
Block a user