allow invalid -> nop parse, clean up
- new functions `*_with_invalid` and `set_code_invalid` create a program with invalid operations translated to Nop and the parse errors collected. - `step` function refactored to be consistant about advancing the instrution pointer with errors. optional ignore erros and advance anyway. Signed-off-by: Rachel <508861+Ryex@users.noreply.github.com>
This commit is contained in:
@@ -9,19 +9,19 @@ use std::{
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
trait PrimitiveRepr {}
|
||||
impl PrimitiveRepr for u8 {}
|
||||
impl PrimitiveRepr for u16 {}
|
||||
impl PrimitiveRepr for u32 {}
|
||||
impl PrimitiveRepr for u64 {}
|
||||
impl PrimitiveRepr for u128 {}
|
||||
impl PrimitiveRepr for usize {}
|
||||
impl PrimitiveRepr for i8 {}
|
||||
impl PrimitiveRepr for i16 {}
|
||||
impl PrimitiveRepr for i32 {}
|
||||
impl PrimitiveRepr for i64 {}
|
||||
impl PrimitiveRepr for i128 {}
|
||||
impl PrimitiveRepr for isize {}
|
||||
// trait PrimitiveRepr {}
|
||||
// impl PrimitiveRepr for u8 {}
|
||||
// impl PrimitiveRepr for u16 {}
|
||||
// impl PrimitiveRepr for u32 {}
|
||||
// impl PrimitiveRepr for u64 {}
|
||||
// impl PrimitiveRepr for u128 {}
|
||||
// impl PrimitiveRepr for usize {}
|
||||
// impl PrimitiveRepr for i8 {}
|
||||
// impl PrimitiveRepr for i16 {}
|
||||
// impl PrimitiveRepr for i32 {}
|
||||
// impl PrimitiveRepr for i64 {}
|
||||
// impl PrimitiveRepr for i128 {}
|
||||
// impl PrimitiveRepr for isize {}
|
||||
|
||||
struct EnumVariant<P>
|
||||
where
|
||||
@@ -328,7 +328,7 @@ fn write_constants() {
|
||||
|
||||
writeln!(
|
||||
&mut writer,
|
||||
"pub(crate) const CONSTANTS_LOOKUP: phf::Map<&'static str, f64> = {};",
|
||||
"#[allow(clippy::approx_constant)] pub(crate) const CONSTANTS_LOOKUP: phf::Map<&'static str, f64> = {};",
|
||||
constants_lookup_map_builder.build()
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
nan f64::NAN A constant representing 'not a number'. This constants technically provides a 'quiet' NaN, a signal NaN from some instructions will result in an exception and halt execution
|
||||
pinf f64::INFINITY A constant representing a positive infinite value
|
||||
ninf f64::NEG_INFINITY A constant representing a negative infinite value
|
||||
pi 3.14159265358979f64 \nA constant representing the ratio of the circumference of a circle to its diameter, provided in double percision
|
||||
pi 3.141592653589793f64 \nA constant representing the ratio of the circumference of a circle to its diameter, provided in double percision
|
||||
deg2rad 0.0174532923847437f64 \nDegrees to radians conversion constant
|
||||
rad2deg 57.2957801818848f64 \nRadians to degrees conversion constant
|
||||
epsilon f64::EPSILON A constant representing the smallest value representable in double precision
|
||||
|
||||
@@ -88,7 +88,7 @@ pub mod generated {
|
||||
pub use generated::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct ParseError {
|
||||
pub line: usize,
|
||||
pub start: usize,
|
||||
@@ -147,6 +147,14 @@ pub fn parse(code: &str) -> Result<Vec<Line>, ParseError> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Like `parse` but can return Code::Invalid for some lines
|
||||
pub fn parse_with_invlaid(code: &str) -> Vec<Line> {
|
||||
code.lines()
|
||||
.enumerate()
|
||||
.map(|(n, l)| Line::from_str_with_invalid(n, l))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Line {
|
||||
pub code: Option<Code>,
|
||||
@@ -168,15 +176,47 @@ impl FromStr for Line {
|
||||
}
|
||||
})
|
||||
.transpose()?;
|
||||
let comment = parts.next().map(|s| s.parse()).transpose()?;
|
||||
let comment = parts
|
||||
.next()
|
||||
.map(|s| s.parse())
|
||||
.transpose()
|
||||
.expect("infallible");
|
||||
Ok(Line { code, comment })
|
||||
}
|
||||
}
|
||||
|
||||
impl Line {
|
||||
fn from_str_with_invalid(line: usize, s: &str) -> Self {
|
||||
let mut parts = s.splitn(2, '#');
|
||||
let code_part = parts
|
||||
.next()
|
||||
.and_then(|s| {
|
||||
let s = s.trim_end();
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(s.parse::<Code>().map_err(|e| e.offset_line(line)))
|
||||
}
|
||||
})
|
||||
.transpose();
|
||||
let code = match code_part {
|
||||
Ok(c) => c,
|
||||
Err(e) => Some(Code::Invalid(e)),
|
||||
};
|
||||
let comment = parts
|
||||
.next()
|
||||
.map(|s| s.parse())
|
||||
.transpose()
|
||||
.expect("infallible");
|
||||
Line { code, comment }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Code {
|
||||
Instruction(Instruction),
|
||||
Label(Label),
|
||||
Invalid(ParseError),
|
||||
}
|
||||
|
||||
impl FromStr for Code {
|
||||
@@ -201,7 +241,7 @@ pub struct Comment {
|
||||
}
|
||||
|
||||
impl FromStr for Comment {
|
||||
type Err = ParseError;
|
||||
type Err = std::convert::Infallible;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Comment {
|
||||
comment: s.to_owned(),
|
||||
@@ -279,16 +319,22 @@ pub enum Device {
|
||||
Indirect { indirection: u32, target: u32 },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RegisterSpec {
|
||||
pub indirection: u32,
|
||||
pub target: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DeviceSpec {
|
||||
pub device: Device,
|
||||
pub connection: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Operand {
|
||||
RegisterSpec {
|
||||
indirection: u32,
|
||||
target: u32,
|
||||
},
|
||||
DeviceSpec {
|
||||
device: Device,
|
||||
connection: Option<u32>,
|
||||
},
|
||||
RegisterSpec(RegisterSpec),
|
||||
DeviceSpec(DeviceSpec),
|
||||
Number(Number),
|
||||
LogicType(LogicType),
|
||||
SlotLogicType(SlotLogicType),
|
||||
@@ -298,12 +344,17 @@ pub enum Operand {
|
||||
}
|
||||
|
||||
impl Operand {
|
||||
pub fn get_value(&self, ic: &interpreter::IC) -> Result<f64, interpreter::ICError> {
|
||||
pub fn as_value(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<f64, interpreter::ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} => ic.get_register(indirection, target),
|
||||
}) => ic.get_register(indirection, target),
|
||||
Operand::Number(num) => Ok(num.value()),
|
||||
Operand::LogicType(lt) => lt
|
||||
.get_str("value")
|
||||
@@ -321,17 +372,85 @@ impl Operand {
|
||||
.get_str("value")
|
||||
.map(|val| val.parse::<u8>().unwrap() as f64)
|
||||
.ok_or(interpreter::ICError::TypeValueNotKnown),
|
||||
Operand::Identifier(ident) => ic.get_ident_value(&ident.name),
|
||||
Operand::DeviceSpec { .. } => Err(interpreter::ICError::DeviceNotValue),
|
||||
Operand::Identifier(id) => {
|
||||
Err(interpreter::ICError::UnknownIdentifier(id.name.to_string()))
|
||||
}
|
||||
Operand::DeviceSpec { .. } => Err(interpreter::ICError::IncorrectOperandType {
|
||||
inst,
|
||||
index,
|
||||
desired: "Value".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_i64(
|
||||
pub fn as_register(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<RegisterSpec, interpreter::ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::RegisterSpec(reg) => Ok(reg),
|
||||
Operand::Identifier(id) => {
|
||||
Err(interpreter::ICError::UnknownIdentifier(id.name.to_string()))
|
||||
}
|
||||
_ => Err(interpreter::ICError::IncorrectOperandType {
|
||||
inst,
|
||||
index,
|
||||
desired: "Register".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_device(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<(Option<u16>, Option<u32>), interpreter::ICError> {
|
||||
match self.translate_alias(ic) {
|
||||
Operand::DeviceSpec(DeviceSpec { device, connection }) => match device {
|
||||
Device::Db => Ok((Some(ic.device), connection)),
|
||||
Device::Numbered(p) => {
|
||||
let dp = ic
|
||||
.pins
|
||||
.get(p as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(p as f64))
|
||||
.copied()?;
|
||||
Ok((dp, connection))
|
||||
}
|
||||
Device::Indirect {
|
||||
indirection,
|
||||
target,
|
||||
} => {
|
||||
let val = ic.get_register(indirection, target)?;
|
||||
let dp = ic
|
||||
.pins
|
||||
.get(val as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(val))
|
||||
.copied()?;
|
||||
Ok((dp, connection))
|
||||
}
|
||||
},
|
||||
Operand::Identifier(id) => {
|
||||
Err(interpreter::ICError::UnknownIdentifier(id.name.to_string()))
|
||||
}
|
||||
_ => Err(interpreter::ICError::IncorrectOperandType {
|
||||
inst,
|
||||
index,
|
||||
desired: "Value".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value_i64(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
signed: bool,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<i64, interpreter::ICError> {
|
||||
let val = self.get_value(ic)?;
|
||||
let val = self.as_value(ic, inst, index)?;
|
||||
if val < -9.223_372_036_854_776E18 {
|
||||
Err(interpreter::ICError::ShiftUnderflowI64)
|
||||
} else if val <= 9.223_372_036_854_776E18 {
|
||||
@@ -341,8 +460,13 @@ impl Operand {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_i32(&self, ic: &interpreter::IC) -> Result<i32, interpreter::ICError> {
|
||||
let val = self.get_value(ic)?;
|
||||
pub fn as_value_i32(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
inst: InstructionOp,
|
||||
index: u32,
|
||||
) -> Result<i32, interpreter::ICError> {
|
||||
let val = self.as_value(ic, inst, index)?;
|
||||
if val < -2147483648.0 {
|
||||
Err(interpreter::ICError::ShiftUnderflowI32)
|
||||
} else if val <= 2147483647.0 {
|
||||
@@ -359,47 +483,15 @@ impl Operand {
|
||||
alias.clone()
|
||||
} else if let Some(define) = ic.defines.get(&id.name) {
|
||||
Operand::Number(Number::Float(*define))
|
||||
} else if let Some(label) = ic.program.labels.get(&id.name) {
|
||||
Operand::Number(Number::Float(*label as f64))
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_device_id(
|
||||
&self,
|
||||
ic: &interpreter::IC,
|
||||
) -> Result<(Option<u16>, Option<u32>), interpreter::ICError> {
|
||||
match &self {
|
||||
Operand::DeviceSpec { device, connection } => match device {
|
||||
Device::Db => Ok((Some(ic.device), *connection)),
|
||||
Device::Numbered(p) => {
|
||||
let dp = ic
|
||||
.pins
|
||||
.get(*p as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(*p as f64))
|
||||
.copied()?;
|
||||
Ok((dp, *connection))
|
||||
}
|
||||
Device::Indirect {
|
||||
indirection,
|
||||
target,
|
||||
} => {
|
||||
let val = ic.get_register(*indirection, *target)?;
|
||||
let dp = ic
|
||||
.pins
|
||||
.get(val as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(val))
|
||||
.copied()?;
|
||||
Ok((dp, *connection))
|
||||
}
|
||||
},
|
||||
Operand::Identifier(id) => ic.get_ident_device_id(&id.name),
|
||||
_ => Err(interpreter::ICError::ValueNotDevice),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Operand {
|
||||
@@ -408,14 +500,14 @@ impl FromStr for Operand {
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let chars = s.chars().collect::<Vec<_>>();
|
||||
match &chars[..] {
|
||||
['s', 'p'] => Ok(Operand::RegisterSpec {
|
||||
['s', 'p'] => Ok(Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 16,
|
||||
}),
|
||||
['r', 'a'] => Ok(Operand::RegisterSpec {
|
||||
})),
|
||||
['r', 'a'] => Ok(Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 17,
|
||||
}),
|
||||
})),
|
||||
['r', rest @ ..] => {
|
||||
let mut rest_iter = rest.iter();
|
||||
let indirection = rest_iter.take_while_ref(|c| *c == &'r').count();
|
||||
@@ -426,10 +518,10 @@ impl FromStr for Operand {
|
||||
let target = target_str.parse::<u32>().ok();
|
||||
if let Some(target) = target {
|
||||
if rest_iter.next().is_none() {
|
||||
return Ok(Operand::RegisterSpec {
|
||||
return Ok(Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: indirection as u32,
|
||||
target,
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
return Err(ParseError {
|
||||
line: 0,
|
||||
@@ -443,16 +535,16 @@ impl FromStr for Operand {
|
||||
Ok(Operand::Identifier(s.parse::<Identifier>()?))
|
||||
}
|
||||
['d', rest @ ..] => match rest {
|
||||
['b'] => Ok(Operand::DeviceSpec {
|
||||
['b'] => Ok(Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Db,
|
||||
connection: None,
|
||||
}),
|
||||
})),
|
||||
['b', ':', chan @ ..] => {
|
||||
if chan.iter().all(|c| c.is_ascii_digit()) {
|
||||
Ok(Operand::DeviceSpec {
|
||||
Ok(Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Db,
|
||||
connection: Some(String::from_iter(chan).parse().unwrap()),
|
||||
})
|
||||
}))
|
||||
} else {
|
||||
Err(ParseError {
|
||||
line: 0,
|
||||
@@ -501,13 +593,13 @@ impl FromStr for Operand {
|
||||
}
|
||||
}?;
|
||||
if rest_iter.next().is_none() {
|
||||
Ok(Operand::DeviceSpec {
|
||||
Ok(Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Indirect {
|
||||
indirection: indirection as u32,
|
||||
target,
|
||||
},
|
||||
connection,
|
||||
})
|
||||
}))
|
||||
} else {
|
||||
Err(ParseError {
|
||||
line: 0,
|
||||
@@ -552,10 +644,10 @@ impl FromStr for Operand {
|
||||
}?;
|
||||
if let Some(target) = target {
|
||||
if rest_iter.next().is_none() {
|
||||
Ok(Operand::DeviceSpec {
|
||||
Ok(Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Numbered(target),
|
||||
connection,
|
||||
})
|
||||
}))
|
||||
} else {
|
||||
Err(ParseError {
|
||||
line: 0,
|
||||
@@ -675,12 +767,6 @@ impl FromStr for Operand {
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(PartialEq, Debug)]
|
||||
// pub struct LogicType {
|
||||
// pub name: String,
|
||||
// pub value: f64,
|
||||
// }
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct Label {
|
||||
pub id: Identifier,
|
||||
@@ -712,7 +798,6 @@ impl FromStr for Label {
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Identifier {
|
||||
// #[rust_sitter::leaf(pattern = r"[a-zA-Z_.][\w\d.]*", transform = |id| id.to_string())]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
@@ -803,10 +888,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::S,
|
||||
operands: vec![
|
||||
Operand::DeviceSpec {
|
||||
Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Numbered(0),
|
||||
connection: None,
|
||||
},
|
||||
}),
|
||||
Operand::LogicType(LogicType::Setting),
|
||||
Operand::Number(Number::Float(0.0)),
|
||||
],
|
||||
@@ -824,10 +909,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 0,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Hexadecimal(4095.0)),
|
||||
],
|
||||
},),),
|
||||
@@ -898,10 +983,10 @@ mod tests {
|
||||
Operand::Identifier(Identifier {
|
||||
name: "a_var".to_owned(),
|
||||
},),
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 0,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},),),
|
||||
comment: None,
|
||||
@@ -913,10 +998,10 @@ mod tests {
|
||||
Operand::Identifier(Identifier {
|
||||
name: "a_device".to_owned(),
|
||||
},),
|
||||
Operand::DeviceSpec {
|
||||
Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Numbered(0),
|
||||
connection: None,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},),),
|
||||
comment: None,
|
||||
@@ -925,10 +1010,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::S,
|
||||
operands: vec![
|
||||
Operand::DeviceSpec {
|
||||
Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Numbered(0),
|
||||
connection: None,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Float(12.0)),
|
||||
Operand::Number(Number::Float(0.0)),
|
||||
],
|
||||
@@ -939,10 +1024,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 2,
|
||||
},
|
||||
}),
|
||||
Operand::Identifier(Identifier {
|
||||
name: "LogicType.Temperature".to_owned()
|
||||
}),
|
||||
@@ -954,10 +1039,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 3,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Constant(f64::INFINITY)),
|
||||
],
|
||||
},),),
|
||||
@@ -979,17 +1064,17 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::L,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 1,
|
||||
},
|
||||
Operand::DeviceSpec {
|
||||
}),
|
||||
Operand::DeviceSpec(DeviceSpec {
|
||||
device: Device::Indirect {
|
||||
indirection: 0,
|
||||
target: 15,
|
||||
},
|
||||
connection: None,
|
||||
},
|
||||
}),
|
||||
Operand::LogicType(LogicType::RatioWater),
|
||||
],
|
||||
},),),
|
||||
@@ -999,10 +1084,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 0,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::String("AccessCardBlack".to_owned()),),
|
||||
],
|
||||
},),),
|
||||
@@ -1012,10 +1097,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 1,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Float(-2045627372.0)),
|
||||
],
|
||||
},),),
|
||||
@@ -1025,10 +1110,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 1,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Hexadecimal(255.0)),
|
||||
],
|
||||
},),),
|
||||
@@ -1038,10 +1123,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 0,
|
||||
target: 1,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Binary(8.0)),
|
||||
],
|
||||
},),),
|
||||
@@ -1051,10 +1136,10 @@ mod tests {
|
||||
code: Some(Code::Instruction(Instruction {
|
||||
instruction: InstructionOp::Move,
|
||||
operands: vec![
|
||||
Operand::RegisterSpec {
|
||||
Operand::RegisterSpec(RegisterSpec {
|
||||
indirection: 1,
|
||||
target: 1,
|
||||
},
|
||||
}),
|
||||
Operand::Number(Number::Float(0.0)),
|
||||
],
|
||||
},),),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -515,6 +515,7 @@ impl VM {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, VMError> {
|
||||
let device = self
|
||||
.devices
|
||||
@@ -534,7 +535,27 @@ impl VM {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn step_ic(&self, id: u16) -> Result<bool, VMError> {
|
||||
/// Set program code and translate invalid lines to Nop, collecting errors
|
||||
pub fn set_code_invalid(&self, id: u16, code: &str) -> Result<bool, VMError> {
|
||||
let device = self
|
||||
.devices
|
||||
.get(&id)
|
||||
.ok_or(VMError::UnknownId(id))?
|
||||
.borrow();
|
||||
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
|
||||
let mut ic = self
|
||||
.ics
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.borrow_mut();
|
||||
let new_prog = interpreter::Program::from_code_with_invalid(code);
|
||||
ic.program = new_prog;
|
||||
ic.ip = 0;
|
||||
ic.code = code.to_string();
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn step_ic(&self, id: u16, advance_ip_on_err: bool) -> Result<bool, VMError> {
|
||||
let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone();
|
||||
let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?;
|
||||
let ic = self
|
||||
@@ -543,7 +564,7 @@ impl VM {
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.clone();
|
||||
ic.borrow_mut().ic = 0;
|
||||
let result = ic.borrow_mut().step(self)?;
|
||||
let result = ic.borrow_mut().step(self, advance_ip_on_err)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -558,7 +579,7 @@ impl VM {
|
||||
.clone();
|
||||
ic.borrow_mut().ic = 0;
|
||||
for _i in 0..128 {
|
||||
if let Err(err) = ic.borrow_mut().step(self) {
|
||||
if let Err(err) = ic.borrow_mut().step(self, ignore_errors) {
|
||||
if !ignore_errors {
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
@@ -235,9 +235,9 @@ impl DeviceRef {
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "step")]
|
||||
pub fn step_ic(&self) -> Result<bool, JsError> {
|
||||
pub fn step_ic(&self, advance_ip_on_err: bool) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().step_ic(id)?)
|
||||
Ok(self.vm.borrow().step_ic(id, advance_ip_on_err)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "run")]
|
||||
@@ -253,11 +253,19 @@ impl DeviceRef {
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setCode")]
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&self, code: &str) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().set_code(id, code)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setCodeInvalid")]
|
||||
/// Set program code and translate invalid lines to Nop, collecting errors
|
||||
pub fn set_code_invlaid(&self, code: &str) -> Result<bool, JsError> {
|
||||
let id = self.device.borrow().id;
|
||||
Ok(self.vm.borrow().set_code_invalid(id, code)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setRegister")]
|
||||
pub fn ic_set_register(&self, index: u32, val: f64) -> Result<f64, JsError> {
|
||||
let ic_id = *self
|
||||
@@ -319,13 +327,20 @@ impl VM {
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setCode")]
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().set_code(id, code)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "setCodeInvalid")]
|
||||
/// Set program code and translate invalid lines to Nop, collecting errors
|
||||
pub fn set_code_invalid(&self, id: u16, code: &str) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().set_code_invalid(id, code)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "stepIC")]
|
||||
pub fn step_ic(&self, id: u16) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().step_ic(id)?)
|
||||
pub fn step_ic(&self, id: u16, advance_ip_on_err: bool) -> Result<bool, JsError> {
|
||||
Ok(self.vm.borrow().step_ic(id, advance_ip_on_err)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "runIC")]
|
||||
|
||||
Reference in New Issue
Block a user