Skip to content

Commit

Permalink
Write Builders manually
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Feb 14, 2020
1 parent b80f8ca commit 1b5234d
Show file tree
Hide file tree
Showing 22 changed files with 1,142 additions and 344 deletions.
10 changes: 5 additions & 5 deletions src/elementext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl ElementExt for Element {
match child.get_text() {
Err(e) => match e.downcast_ref() {
// if tag is empty just ignore it
Some(SVDError::EmptyTag(_, _)) => Ok(None),
Some(ParseError::EmptyTag(_, _)) => Ok(None),
_ => return Err(e),
},
Ok(s) => Ok(Some(s.to_owned())),
Expand All @@ -53,7 +53,7 @@ impl ElementExt for Element {
K: core::fmt::Display + Clone,
{
self.get_child_text_opt(k.clone())?
.ok_or_else(|| SVDError::MissingTag(self.clone(), format!("{}", k)).into())
.ok_or_else(|| ParseError::MissingTag(self.clone(), format!("{}", k)).into())
}

/// Get text contained by an XML Element
Expand All @@ -63,22 +63,22 @@ impl ElementExt for Element {
// FIXME: Doesn't look good because SVDError doesn't format by itself. We already
// capture the element and this information can be used for getting the name
// This would fix ParseError
None => Err(SVDError::EmptyTag(self.clone(), self.name.clone()).into()),
None => Err(ParseError::EmptyTag(self.clone(), self.name.clone()).into()),
}
}

/// Get a named child element from an XML Element
fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element> {
match self.get_child(n) {
Some(s) => Ok(s),
None => Err(SVDError::MissingTag(self.clone(), n.to_string()).into()),
None => Err(ParseError::MissingTag(self.clone(), n.to_string()).into()),
}
}

/// Get a u32 value from a named child element
fn get_child_u32(&self, n: &str) -> Result<u32> {
let s = self.get_child_elem(n)?;
u32::parse(&s).context(SVDError::ParseError(self.clone()))
u32::parse(&s).context(ParseError::Other(self.clone()))
}

/// Get a bool value from a named child element
Expand Down
145 changes: 114 additions & 31 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,135 @@
//! SVD Errors.
//! This module defines error types and messages for SVD parsing and encoding
pub use anyhow::{Context, Result};
pub use anyhow::{anyhow, Context, Result};
use thiserror::Error;
use xmltree::Element;

#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum SVDError {
#[error("Unknown endianness `{0}`")]
UnknownEndian(String),
// TODO: Needs context
// TODO: Better name
#[error("Expected a <{1}> tag, found none")]
MissingTag(Element, String),
#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum ParseError {
#[error("Expected content in <{1}> tag, found none")]
EmptyTag(Element, String),
#[error("ParseError")]
ParseError(Element),
#[error("Expected a <{1}> tag, found none")]
MissingTag(Element, String),
#[error("NameMismatch")]
NameMismatch(Element),
#[error("unknown access variant '{1}' found")]
UnknownAccessType(Element, String),
#[error("Bit range invalid, {1:?}")]
InvalidBitRange(Element, InvalidBitRange),
#[error("Unknown write constraint")]
UnknownWriteConstraint(Element),
#[error("Multiple wc found")]
MoreThanOneWriteConstraint(Element),
#[error("Unknown usage variant")]
UnknownUsageVariant(Element),
#[error("Expected a <{1}>, found ...")]
NotExpectedTag(Element, String),
#[error("Invalid RegisterCluster (expected register or cluster), found {1}")]
InvalidRegisterCluster(Element, String),
#[error("Invalid modifiedWriteValues variant, found {1}")]
InvalidModifiedWriteValues(Element, String),
#[error("The content of the element could not be parsed to a boolean value {1}: {2}")]
InvalidBooleanValue(Element, String, core::str::ParseBoolError),
#[error("encoding method not implemented for svd object {0}")]
EncodeNotImplemented(String),
#[error("Error parsing SVD XML")]
FileParseError,
#[error("ParseError")]
Other(Element),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum BuildError {
#[error("`{0}` must be initialized")]
Uninitialized(String),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum AccessTypeError {
#[error("unknown access variant '{1}' found")]
Unknown(Element, String),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum BitRangeError {
#[error("Bit range invalid, {1:?}")]
Invalid(Element, InvalidBitRange),
}

// TODO: Consider making into an Error
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidBitRange {
Empty,
Syntax,
ParseError,
MsbLsb,
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum EndianError {
#[error("Unknown endianness `{0}`")]
Unknown(String),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum ModifiedWriteValuesError {
#[error("Invalid modifiedWriteValues variant, found {1}")]
Invalid(Element, String),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum DeviceError {
#[error("Device must contain at least one peripheral")]
Empty,
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum PeripheralError {
#[error("Peripheral have `registers` tag, but it is empty")]
EmptyRegisters,
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum ClusterError {
#[error("Cluster must contain at least one Register or Cluster")]
Empty,
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum RegisterError {
#[error("Register have `fields` tag, but it is empty")]
EmptyFields,
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum RegisterClusterError {
#[error("Invalid RegisterCluster (expected register or cluster), found {1}")]
Invalid(Element, String),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum UsageVariantError {
#[error("Unknown usage variant")]
Unknown(Element),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum WriteConstraintError {
#[error("Unknown write constraint")]
Unknown(Element),
#[error("Multiple wc found")]
MoreThanOne(Element),
}

#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum NameError {
#[error("Name `{0}` in tag `{1}` contains unexpected symbol")]
Invalid(String, String),
}

pub(crate) fn is_valid_name(name: &str) -> bool {
let mut chars = name.chars();
if let Some(first) = chars.next() {
if !(first.is_ascii_alphabetic() || first == '_') {
return false;
}
for c in chars {
if !(c.is_ascii_alphanumeric() || c == '_' || c == '%') {
return false;
}
}
true
} else {
false
}
}

pub(crate) fn check_name(name: &str, tag: &str) -> Result<()> {
if is_valid_name(name) {
Ok(())
} else {
Err(NameError::Invalid(name.to_string(), tag.to_string()).into())
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ pub(crate) fn new_element(name: &str, text: Option<String>) -> Element {
}
}

pub trait Build {
type Builder;
}

/// Generic test helper function
/// Takes an array of (item, xml) pairs where the item implements
/// Parse and Encode and tests object encoding and decoding
Expand Down
2 changes: 1 addition & 1 deletion src/svd/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Parse for Access {
"read-writeOnce" => Ok(Access::ReadWriteOnce),
"write-only" => Ok(Access::WriteOnly),
"writeOnce" => Ok(Access::WriteOnce),
_ => Err(SVDError::UnknownAccessType(tree.clone(), text).into()),
_ => Err(AccessTypeError::Unknown(tree.clone(), text).into()),
}
}
}
Expand Down
36 changes: 14 additions & 22 deletions src/svd/bitrange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,39 +45,31 @@ impl Parse for BitRange {
let text = range
.text
.as_ref()
.ok_or_else(|| anyhow::anyhow!("text missing"))?; // TODO: Make into a proper error, text empty or something similar
// TODO: If the `InvalidBitRange` enum was an error we could context into here somehow so that
// the output would be similar to the parse error
.ok_or_else(|| BitRangeError::Invalid(tree.clone(), InvalidBitRange::Empty))?;
if !text.starts_with('[') {
return Err(
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::Syntax).into(),
); // TODO: Maybe have a MissingOpen/MissingClosing variant
return Err(BitRangeError::Invalid(tree.clone(), InvalidBitRange::Syntax).into());
// TODO: Maybe have a MissingOpen/MissingClosing variant
}
if !text.ends_with(']') {
return Err(
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::Syntax).into(),
); // TODO: Maybe have a MissingOpen/MissingClosing variant
return Err(BitRangeError::Invalid(tree.clone(), InvalidBitRange::Syntax).into());
// TODO: Maybe have a MissingOpen/MissingClosing variant
}

let mut parts = text[1..text.len() - 1].split(':');
(
parts
.next()
.ok_or_else(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::Syntax)
})?
.ok_or_else(|| BitRangeError::Invalid(tree.clone(), InvalidBitRange::Syntax))?
.parse::<u32>()
.with_context(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::ParseError)
BitRangeError::Invalid(tree.clone(), InvalidBitRange::ParseError)
})?,
parts
.next()
.ok_or_else(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::Syntax)
})?
.ok_or_else(|| BitRangeError::Invalid(tree.clone(), InvalidBitRange::Syntax))?
.parse::<u32>()
.with_context(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::ParseError)
BitRangeError::Invalid(tree.clone(), InvalidBitRange::ParseError)
})?,
BitRangeType::BitRange,
)
Expand All @@ -86,10 +78,10 @@ impl Parse for BitRange {
(
// TODO: `u32::parse` should not hide it's errors
u32::parse(msb).with_context(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::MsbLsb)
BitRangeError::Invalid(tree.clone(), InvalidBitRange::MsbLsb)
})?,
u32::parse(lsb).with_context(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::MsbLsb)
BitRangeError::Invalid(tree.clone(), InvalidBitRange::MsbLsb)
})?,
BitRangeType::MsbLsb,
)
Expand All @@ -102,15 +94,15 @@ impl Parse for BitRange {
// TODO: capture that error comes from offset/width tag
// TODO: `u32::parse` should not hide it's errors
offset: u32::parse(offset).with_context(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::ParseError)
BitRangeError::Invalid(tree.clone(), InvalidBitRange::ParseError)
})?,
width: u32::parse(width).with_context(|| {
SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::ParseError)
BitRangeError::Invalid(tree.clone(), InvalidBitRange::ParseError)
})?,
range_type: BitRangeType::OffsetWidth,
});
} else {
return Err(SVDError::InvalidBitRange(tree.clone(), InvalidBitRange::Syntax).into());
return Err(BitRangeError::Invalid(tree.clone(), InvalidBitRange::Syntax).into());
};

Ok(Self {
Expand Down
Loading

0 comments on commit 1b5234d

Please sign in to comment.