mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-03 16:16:33 +00:00
Added function validation.
Fixed issue with function `modify_spu_delay1`.
`dcb_util::fmt_err{_wrapper}` not supports non-static errors.
This commit is contained in:
parent
49c8ee53cc
commit
1749b78fed
@ -6,10 +6,12 @@
|
||||
//! type.
|
||||
|
||||
// Modules
|
||||
pub mod error;
|
||||
pub mod kind;
|
||||
pub mod table;
|
||||
|
||||
// Exports
|
||||
pub use error::ValidateError;
|
||||
pub use kind::FuncKind;
|
||||
pub use table::FuncTable;
|
||||
|
||||
@ -61,12 +63,40 @@ pub struct Func {
|
||||
pub kind: FuncKind,
|
||||
}
|
||||
|
||||
// Getters
|
||||
impl Func {
|
||||
/// Checks if this function contains `pos`
|
||||
#[must_use]
|
||||
pub fn contains(&self, pos: Pos) -> bool {
|
||||
(self.start_pos..self.end_pos).contains(&pos)
|
||||
}
|
||||
|
||||
/// Validates this function
|
||||
pub fn validate(&self) -> Result<(), ValidateError<'_>> {
|
||||
// TODO: Validate name and signature?
|
||||
|
||||
// If our positions don't make a proper range, return Err
|
||||
if self.end_pos < self.start_pos {
|
||||
return Err(ValidateError::InvalidRange {
|
||||
start_pos: self.start_pos,
|
||||
end_pos: self.end_pos,
|
||||
});
|
||||
}
|
||||
|
||||
// Check all positions of labels and comments are within our range.
|
||||
for (&pos, comment) in self.inline_comments.iter().chain(&self.comments) {
|
||||
if !self.contains(pos) {
|
||||
return Err(ValidateError::CommentPosOutOfBounds { pos, comment });
|
||||
}
|
||||
}
|
||||
for (&pos, label) in &self.labels {
|
||||
if !self.contains(pos) {
|
||||
return Err(ValidateError::LabelPosOutOfBounds { pos, label });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Func {
|
||||
|
||||
38
dcb-exe/src/func/error.rs
Normal file
38
dcb-exe/src/func/error.rs
Normal file
@ -0,0 +1,38 @@
|
||||
//! Errors
|
||||
|
||||
// Imports
|
||||
use crate::Pos;
|
||||
|
||||
/// Validation error
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ValidateError<'a> {
|
||||
/// Function range is invalid
|
||||
#[error("Range {start_pos}..{end_pos} is invalid")]
|
||||
InvalidRange {
|
||||
/// Start position
|
||||
start_pos: Pos,
|
||||
|
||||
/// End position
|
||||
end_pos: Pos,
|
||||
},
|
||||
|
||||
/// Label position is outside of function
|
||||
#[error("Label {label} @ {pos} is outside of function bounds")]
|
||||
LabelPosOutOfBounds {
|
||||
/// Position
|
||||
pos: Pos,
|
||||
|
||||
/// Label
|
||||
label: &'a str,
|
||||
},
|
||||
|
||||
/// Comment position is outside of function
|
||||
#[error("Comment {comment} @ {pos} is outside of function bounds")]
|
||||
CommentPosOutOfBounds {
|
||||
/// Position
|
||||
pos: Pos,
|
||||
|
||||
/// Comment
|
||||
comment: &'a str,
|
||||
},
|
||||
}
|
||||
@ -17,16 +17,18 @@ pub use error::GetKnownError;
|
||||
// Imports
|
||||
use super::Func;
|
||||
use crate::Pos;
|
||||
use std::{collections::BTreeSet, fs::File, iter::FromIterator, ops::RangeBounds};
|
||||
use std::{collections::BTreeSet, iter::FromIterator, ops::RangeBounds};
|
||||
|
||||
/// Function table
|
||||
///
|
||||
/// Stores all functions sorted by their address.
|
||||
/// Also guarantees all functions are unique and non-overlapping.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(serde::Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct FuncTable(BTreeSet<Func>);
|
||||
|
||||
// Constructors
|
||||
impl FuncTable {
|
||||
/// Creates an empty function table
|
||||
#[must_use]
|
||||
@ -35,16 +37,6 @@ impl FuncTable {
|
||||
}
|
||||
}
|
||||
|
||||
// Constructors
|
||||
impl FuncTable {
|
||||
/// Returns all known functions
|
||||
pub fn get_known() -> Result<Self, GetKnownError> {
|
||||
let file = File::open("resources/game_funcs.yaml").map_err(GetKnownError::File)?;
|
||||
|
||||
serde_yaml::from_reader(file).map_err(GetKnownError::Parse)
|
||||
}
|
||||
}
|
||||
|
||||
// Getters
|
||||
impl FuncTable {
|
||||
/// Retrieves the function containing `pos`
|
||||
@ -70,21 +62,30 @@ impl FuncTable {
|
||||
// Note: `BTreeSet` already discards duplicates on it's own.
|
||||
impl Extend<Func> for FuncTable {
|
||||
fn extend<T: IntoIterator<Item = Func>>(&mut self, funcs: T) {
|
||||
self.0.extend(funcs);
|
||||
for func in funcs {
|
||||
self.extend_one(func);
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_one(&mut self, func: Func) {
|
||||
self.0.extend_one(func);
|
||||
}
|
||||
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.0.extend_reserve(additional);
|
||||
// Validate the function before inserting it.
|
||||
match func.validate() {
|
||||
Ok(()) => self.0.extend_one(func),
|
||||
// If it fails validation, discard it and warn
|
||||
Err(err) => log::warn!(
|
||||
"Function {} failed validation, ignoring:\n{}",
|
||||
func.name,
|
||||
dcb_util::fmt_err_wrapper(&err)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Func> for FuncTable {
|
||||
fn from_iter<T: IntoIterator<Item = Func>>(iter: T) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
let mut table = Self::new();
|
||||
table.extend(iter);
|
||||
table
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -125,7 +125,7 @@ pub const fn saturating_signed_offset(a: u64, b: i64) -> u64 {
|
||||
}
|
||||
|
||||
/// Prints an error
|
||||
pub fn fmt_err(err: &(dyn std::error::Error + 'static), f: &mut fmt::Formatter) -> fmt::Result {
|
||||
pub fn fmt_err(err: &(dyn std::error::Error + '_), f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "{err}")?;
|
||||
|
||||
match err.source() {
|
||||
@ -139,7 +139,7 @@ pub fn fmt_err(err: &(dyn std::error::Error + 'static), f: &mut fmt::Formatter)
|
||||
}
|
||||
|
||||
/// Returns a wrapper that prints an error
|
||||
pub fn fmt_err_wrapper<'a>(err: &'a (dyn std::error::Error + 'static)) -> impl fmt::Display + 'a {
|
||||
pub fn fmt_err_wrapper<'a>(err: &'a (dyn std::error::Error + 'a)) -> impl fmt::Display + 'a {
|
||||
DisplayWrapper::new(move |f| self::fmt_err(err, f))
|
||||
}
|
||||
|
||||
|
||||
@ -239,8 +239,8 @@
|
||||
Sets `SPU_DELAY` to `(SPU_DELAY & 0xf0fffff) | 0x2000ffff`
|
||||
and returns the new value
|
||||
inline_comments:
|
||||
0x8004b45c: "$v0 = *SPU_DELAY"
|
||||
0x8004b474: "*SPU_DELAY = $v0"
|
||||
0x8004b434: "$v0 = *SPU_DELAY"
|
||||
0x8004b44c: "*SPU_DELAY = $v0"
|
||||
start_pos: 0x8004b428
|
||||
end_pos: 0x8004b450
|
||||
kind: Known
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user