Skip to content

Commit c4db1d2

Browse files
authored
Merge pull request #53 from japaric/refactor
Whoop!
2 parents 82481b8 + e75fc3b commit c4db1d2

33 files changed

+3939
-687
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ name = "svd-parser"
88
repository = "https://github.com/japaric/svd"
99
version = "0.6.0"
1010

11+
[features]
12+
unproven = []
13+
1114
[dependencies]
1215
either = "1.1.0"
1316
xmltree = "0.3.2"
17+
failure = "0.1.1"

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[![crates.io](https://img.shields.io/crates/d/svd-parser.svg)](https://crates.io/crates/svd-parser)
22
[![crates.io](https://img.shields.io/crates/v/svd-parser.svg)](https://crates.io/crates/svd-parser)
3+
[![Build Status](https://travis-ci.org/japaric/svd.svg?branch=master)](https://travis-ci.org/japaric/svd)
4+
[![Documentation](https://docs.rs/svd-parser/badge.svg)](https://docs.rs/svd-parser)
35

46
# `svd-parser`
57

generate-tests.sh

100755100644
Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ elementIn() {
1010

1111
main() {
1212
local tests_dir=$(pwd)/tests
13+
local cmsis_dir=$tests_dir/cmsis_tests
1314
local blacklist=(
1415
# These SVD files have some registers with a `resetValue` bigger than the register itself
1516
Toshiba/M365
@@ -20,13 +21,13 @@ main() {
2021
SiliconLabs/SIM3L1x8_SVD
2122
)
2223

23-
rm -rf tests
24-
mkdir -p tests
24+
rm -rf tests/cmsis_tests
25+
mkdir -p tests/cmsis_tests
2526

2627
local vendor_dir
2728
for vendor_dir in $(echo cmsis-svd/data/*); do
2829
local vendor=$(basename $vendor_dir)
29-
cat >"$tests_dir/$vendor.rs" <<EOF
30+
cat >"$cmsis_dir/$vendor.rs" <<EOF
3031
#![allow(non_snake_case)]
3132
3233
extern crate svd_parser as svd;
@@ -44,16 +45,23 @@ EOF
4445

4546
device=${device//./_}
4647

47-
cat >>"$tests_dir/$vendor.rs" <<EOF
48+
cat >>"$cmsis_dir/$vendor.rs" <<EOF
4849
#[test]
4950
fn $device() {
5051
let xml = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/$device_path"));
5152
52-
svd::parse(xml);
53+
svd::parse(xml).unwrap();
5354
}
5455
EOF
55-
done
56+
done
57+
cat >>"$cmsis_dir/mod.rs" <<EOF
58+
pub mod $vendor;
59+
EOF
5660
done
61+
cat >"$tests_dir/cmsis.rs"<<EOF
62+
pub mod cmsis_tests;
63+
use cmsis_tests::*;
64+
EOF
5765
}
5866

5967
main

src/elementext.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//! SVD Element Extensions.
2+
//! This module is extends xmltree::Element objects with convenience methods
3+
4+
use xmltree::Element;
5+
6+
use failure::ResultExt;
7+
use types::{BoolParse, Parse};
8+
9+
use error::*;
10+
11+
/// Defines extensions for implementation over xmltree::Element
12+
pub trait ElementExt {
13+
fn get_child_text_opt<K>(&self, k: K) -> Result<Option<String>, SVDError>
14+
where
15+
String: PartialEq<K>;
16+
fn get_child_text<K>(&self, k: K) -> Result<String, SVDError>
17+
where
18+
String: PartialEq<K>,
19+
K: ::std::fmt::Display + Clone;
20+
21+
fn get_text(&self) -> Result<String, SVDError>;
22+
23+
fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element, SVDError>;
24+
fn get_child_u32(&self, n: &str) -> Result<u32, SVDError>;
25+
fn get_child_bool(&self, n: &str) -> Result<bool, SVDError>;
26+
27+
fn merge(&self, n: &Self) -> Self;
28+
29+
fn debug(&self);
30+
}
31+
32+
/// Implements extensions for xmltree::Element
33+
impl ElementExt for Element {
34+
fn get_child_text_opt<K>(&self, k: K) -> Result<Option<String>, SVDError>
35+
where
36+
String: PartialEq<K>,
37+
{
38+
if let Some(child) = self.get_child(k) {
39+
Ok(Some(child
40+
.get_text()
41+
.map(|s| s.to_owned())?))
42+
} else {
43+
Ok(None)
44+
}
45+
}
46+
fn get_child_text<K>(&self, k: K) -> Result<String, SVDError>
47+
where
48+
String: PartialEq<K>,
49+
K: ::std::fmt::Display + Clone,
50+
{
51+
self.get_child_text_opt(k.clone())?.ok_or(
52+
SVDErrorKind::MissingTag(self.clone(), format!("{}", k)).into(),
53+
)
54+
}
55+
56+
/// Get text contained by an XML Element
57+
fn get_text(&self) -> Result<String, SVDError> {
58+
match self.text.as_ref() {
59+
Some(s) => Ok(s.clone()),
60+
// FIXME: Doesn't look good because SVDErrorKind doesn't format by itself. We already
61+
// capture the element and this information can be used for getting the name
62+
// This would fix ParseError
63+
None => Err(SVDErrorKind::EmptyTag(
64+
self.clone(),
65+
self.name.clone(),
66+
).into()),
67+
}
68+
}
69+
70+
/// Get a named child element from an XML Element
71+
fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element, SVDError> {
72+
match self.get_child(n) {
73+
Some(s) => Ok(s),
74+
None => Err(
75+
SVDErrorKind::MissingTag(self.clone(), n.to_string()).into(),
76+
),
77+
}
78+
}
79+
80+
/// Get a u32 value from a named child element
81+
fn get_child_u32(&self, n: &str) -> Result<u32, SVDError> {
82+
let s = self.get_child_elem(n)?;
83+
u32::parse(&s)
84+
.context(SVDErrorKind::ParseError(self.clone()))
85+
.map_err(|e| e.into())
86+
}
87+
88+
/// Get a bool value from a named child element
89+
fn get_child_bool(&self, n: &str) -> Result<bool, SVDError> {
90+
let s = self.get_child_elem(n)?;
91+
BoolParse::parse(s)
92+
}
93+
94+
// Merges the children of two elements, maintaining the name and description of the first
95+
fn merge(&self, r: &Self) -> Self {
96+
let mut n = self.clone();
97+
for c in &r.children {
98+
n.children.push(c.clone());
99+
}
100+
n
101+
}
102+
103+
fn debug(&self) {
104+
println!("<{}>", self.name);
105+
for c in &self.children {
106+
println!("{}: {:?}", c.name, c.text)
107+
}
108+
println!("</{}>", self.name);
109+
}
110+
}

src/encode.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Encode traits.
2+
//! These support encoding of SVD types to XML
3+
4+
use xmltree::Element;
5+
6+
/// Encode trait allows SVD objects to be encoded into XML elements.
7+
pub trait Encode {
8+
/// Encoding error
9+
type Error;
10+
/// Encode into an XML/SVD element
11+
fn encode(&self) -> Result<Element, Self::Error>;
12+
}
13+
14+
/// EncodeChildren allows SVD objects to be encoded as a list of XML elements
15+
/// This is typically used to merge with an existing element.
16+
pub trait EncodeChildren {
17+
/// Encoding error
18+
type Error;
19+
/// Encode into XML/SVD children to merge with existing object
20+
fn encode(&self) -> Result<Vec<Element>, Self::Error>;
21+
}

src/error.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//! SVD Errors.
2+
//! This module defines error types and messages for SVD parsing and encoding
3+
4+
use failure::{Backtrace, Context, Fail};
5+
use std::fmt::{self, Display};
6+
use xmltree::{Element, ParseError};
7+
8+
#[derive(Debug)]
9+
pub struct SVDError {
10+
inner: Context<SVDErrorKind>,
11+
}
12+
13+
// TODO: Expand and make more complex output possible.
14+
// We can use the `Element` to output name (if available) and etc.
15+
#[derive(Clone, Debug, PartialEq, Eq, Fail)]
16+
pub enum SVDErrorKind {
17+
#[fail(display = "Unknown endianness `{}`", _0)]
18+
UnknownEndian(String),
19+
// TODO: Needs context
20+
// TODO: Better name
21+
#[fail(display = "Expected a <{}> tag, found none", _1)]
22+
MissingTag(Element, String),
23+
#[fail(display = "Expected content in <{}> tag, found none", _1)]
24+
EmptyTag(Element, String),
25+
#[fail(display = "ParseError")]
26+
ParseError(Element),
27+
#[fail(display = "NameMismatch")]
28+
NameMismatch(Element),
29+
#[fail(display = "unknown access variant found")]
30+
UnknownAccessType(Element),
31+
#[fail(display = "Bit range invalid, {:?}", _1)]
32+
InvalidBitRange(Element, InvalidBitRange),
33+
#[fail(display = "Unknown write constraint")]
34+
UnknownWriteConstraint(Element),
35+
#[fail(display = "Multiple wc found")]
36+
MoreThanOneWriteConstraint(Element),
37+
#[fail(display = "Unknown usage variant")]
38+
UnknownUsageVariant(Element),
39+
#[fail(display = "Expected a <{}>, found ...", _1)]
40+
NotExpectedTag(Element, String),
41+
#[fail(
42+
display = "Invalid RegisterCluster (expected register or cluster), found {}",
43+
_1
44+
)]
45+
InvalidRegisterCluster(Element, String),
46+
#[fail(display = "Invalid modifiedWriteValues variant, found {}", _1)]
47+
InvalidModifiedWriteValues(Element, String),
48+
#[fail(
49+
display = "The content of the element could not be parsed to a boolean value {}: {}",
50+
_1,
51+
_2
52+
)]
53+
InvalidBooleanValue(Element, String, ::std::str::ParseBoolError),
54+
#[fail(display = "encoding method not implemented for svd object {}", _0)]
55+
EncodeNotImplemented(String),
56+
#[fail(display = "Error parsing SVD XML")]
57+
FileParseError,
58+
// FIXME: Should not be used, only for prototyping
59+
#[fail(display = "{}", _0)]
60+
Other(String),
61+
}
62+
63+
// TODO: Consider making into an Error
64+
#[derive(Clone, Debug, PartialEq, Eq)]
65+
pub enum InvalidBitRange {
66+
Syntax,
67+
ParseError,
68+
MsbLsb,
69+
}
70+
71+
impl Fail for SVDError {
72+
fn cause(&self) -> Option<&Fail> {
73+
self.inner.cause()
74+
}
75+
76+
fn backtrace(&self) -> Option<&Backtrace> {
77+
self.inner.backtrace()
78+
}
79+
}
80+
81+
impl Display for SVDError {
82+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83+
Display::fmt(&self.inner, f)
84+
}
85+
}
86+
87+
impl SVDError {
88+
pub fn kind(&self) -> SVDErrorKind {
89+
self.inner.get_context().clone()
90+
}
91+
}
92+
93+
impl From<SVDErrorKind> for SVDError {
94+
fn from(kind: SVDErrorKind) -> SVDError {
95+
SVDError {
96+
inner: Context::new(kind),
97+
}
98+
}
99+
}
100+
101+
impl From<Context<SVDErrorKind>> for SVDError {
102+
fn from(inner: Context<SVDErrorKind>) -> SVDError {
103+
SVDError { inner }
104+
}
105+
}
106+
107+
impl From<ParseError> for SVDError {
108+
fn from(e: ParseError) -> SVDError {
109+
SVDError {
110+
inner: e.context(SVDErrorKind::FileParseError),
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)