Skip to content

Commit a443218

Browse files
committed
serde parse
1 parent 8216980 commit a443218

File tree

5 files changed

+102
-28
lines changed

5 files changed

+102
-28
lines changed

CHANGELOG.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Support of reading SVD from YAML or JSON files instead of XML
13+
1014
### Changed
1115

1216
- Use `svd-parser` v0.13.1
1317
- Replace suffix in fields' name before converting to snake case when generating methods #563
18+
- MIPS API now re-exports `mips_rt::interrupt` when the `rt` feature is enabled
1419

1520
### Fixed
1621

1722
- Fix ValidateLevel usage in lib.rs
1823
- Parenthesizing `#offset_calc` to avoid clippy's warning of operator precedence
1924

20-
### Changed
21-
22-
- MIPS API now re-exports `mips_rt::interrupt` when the `rt` feature is enabled
23-
2425
## [v0.20.0] - 2021-12-07
2526

2627
### Fixed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,17 @@ quote = "1.0"
4545
proc-macro2 = "1.0"
4646
anyhow = "1.0"
4747
thiserror = "1.0"
48+
serde_json = "1.0.75"
49+
serde_yaml = "0.8.23"
4850

4951
[dependencies.svd-parser]
5052
features = ["derive-from"]
5153
version = "0.13.1"
5254

55+
[dependencies.svd-rs]
56+
features = ["serde"]
57+
version = "0.13.0"
58+
5359
[dependencies.syn]
5460
version = "1.0"
5561
features = ["full","extra-traits"]

src/lib.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,8 @@
502502
use quote::quote;
503503
use svd_parser::svd;
504504

505-
mod generate;
506-
mod util;
505+
pub mod generate;
506+
pub mod util;
507507

508508
pub use crate::util::{Config, Target};
509509

@@ -519,7 +519,8 @@ pub struct DeviceSpecific {
519519
pub build_rs: String,
520520
}
521521

522-
use anyhow::Result;
522+
use anyhow::{Context, Result};
523+
523524
#[derive(Debug, thiserror::Error)]
524525
pub enum SvdError {
525526
#[error("Cannot format crate")]
@@ -529,10 +530,10 @@ pub enum SvdError {
529530
}
530531

531532
/// Generates rust code for the specified svd content.
532-
pub fn generate(xml: &str, config: &Config) -> Result<Generation> {
533+
pub fn generate(input: &str, config: &Config) -> Result<Generation> {
533534
use std::fmt::Write;
534535

535-
let device = svd_parser::parse(xml)?;
536+
let device = load_from(input, config)?;
536537
let mut device_x = String::new();
537538
let items =
538539
generate::device::render(&device, config, &mut device_x).or(Err(SvdError::Render))?;
@@ -562,6 +563,30 @@ pub fn generate(xml: &str, config: &Config) -> Result<Generation> {
562563
})
563564
}
564565

566+
/// Load a [Device] from a string slice with given [config](crate::util::Config).
567+
pub fn load_from(input: &str, config: &crate::util::Config) -> Result<svd::Device> {
568+
use self::util::SourceType;
569+
use svd_parser::ValidateLevel;
570+
571+
Ok(match config.source_type {
572+
SourceType::Xml => {
573+
let mut parser_config = svd_parser::Config::default();
574+
parser_config.validate_level = if config.strict {
575+
ValidateLevel::Strict
576+
} else {
577+
ValidateLevel::Weak
578+
};
579+
580+
svd_parser::parse_with_config(input, &parser_config)
581+
.with_context(|| "Error parsing SVD XML file".to_string())?
582+
}
583+
SourceType::Yaml => serde_yaml::from_str(input)
584+
.with_context(|| "Error parsing SVD YAML file".to_string())?,
585+
SourceType::Json => serde_json::from_str(input)
586+
.with_context(|| "Error parsing SVD JSON file".to_string())?,
587+
})
588+
}
589+
565590
/// Assigns a handler to an interrupt
566591
///
567592
/// **NOTE** The `interrupt!` macro on Cortex-M and MSP430 device crates is closer in syntax to the

src/main.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
#![recursion_limit = "128"]
22

33
use log::{error, info};
4-
use std::path::PathBuf;
5-
use svd_parser::svd;
6-
7-
mod generate;
8-
mod util;
4+
use std::path::{Path, PathBuf};
95

106
use std::fs::File;
117
use std::io::Write;
@@ -14,7 +10,10 @@ use std::process;
1410
use anyhow::{Context, Result};
1511
use clap::{App, Arg};
1612

17-
use crate::util::{build_rs, Config, Target};
13+
use svd2rust::{
14+
generate, load_from,
15+
util::{build_rs, Config, SourceType, Target},
16+
};
1817

1918
fn run() -> Result<()> {
2019
use clap_conf::prelude::*;
@@ -84,6 +83,11 @@ fn run() -> Result<()> {
8483
.short("s")
8584
.help("Make advanced checks due to parsing SVD"),
8685
)
86+
.arg(
87+
Arg::with_name("source_type")
88+
.long("source_type")
89+
.help("Specify file/stream format"),
90+
)
8791
.arg(
8892
Arg::with_name("log_level")
8993
.long("log")
@@ -101,19 +105,19 @@ fn run() -> Result<()> {
101105
))
102106
.get_matches();
103107

104-
let xml = &mut String::new();
108+
let input = &mut String::new();
105109
match matches.value_of("input") {
106110
Some(file) => {
107111
File::open(file)
108112
.context("Cannot open the SVD file")?
109-
.read_to_string(xml)
113+
.read_to_string(input)
110114
.context("Cannot read the SVD file")?;
111115
}
112116
None => {
113117
let stdin = std::io::stdin();
114118
stdin
115119
.lock()
116-
.read_to_string(xml)
120+
.read_to_string(input)
117121
.context("Cannot read from stdin")?;
118122
}
119123
}
@@ -146,6 +150,18 @@ fn run() -> Result<()> {
146150
cfg.bool_flag("ignore_groups", Filter::Arg) || cfg.bool_flag("ignore_groups", Filter::Conf);
147151
let strict = cfg.bool_flag("strict", Filter::Arg) || cfg.bool_flag("strict", Filter::Conf);
148152

153+
let mut source_type = cfg
154+
.grab()
155+
.arg("source_type")
156+
.conf("source_type")
157+
.done()
158+
.and_then(|s| SourceType::from_extension(&s))
159+
.unwrap_or_default();
160+
161+
if let Some(file) = matches.value_of("input") {
162+
source_type = SourceType::from_path(Path::new(file))
163+
}
164+
149165
let config = Config {
150166
target,
151167
nightly,
@@ -155,18 +171,11 @@ fn run() -> Result<()> {
155171
ignore_groups,
156172
strict,
157173
output_dir: path.clone(),
158-
};
159-
160-
let mut parser_config = svd_parser::Config::default();
161-
parser_config.validate_level = if strict {
162-
svd::ValidateLevel::Strict
163-
} else {
164-
svd::ValidateLevel::Weak
174+
source_type,
165175
};
166176

167177
info!("Parsing device from SVD file");
168-
let device = svd_parser::parse_with_config(xml, &parser_config)
169-
.with_context(|| "Error parsing SVD file".to_string())?;
178+
let device = load_from(input, &config)?;
170179

171180
let mut device_x = String::new();
172181
info!("Rendering device");

src/util.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::svd::{
66
use inflections::Inflect;
77
use proc_macro2::{Ident, Literal, Span, TokenStream};
88
use quote::{quote, ToTokens};
9-
use std::path::PathBuf;
9+
use std::path::{Path, PathBuf};
1010

1111
use anyhow::{anyhow, bail, Context, Result};
1212

@@ -26,6 +26,7 @@ pub struct Config {
2626
pub ignore_groups: bool,
2727
pub strict: bool,
2828
pub output_dir: PathBuf,
29+
pub source_type: SourceType,
2930
}
3031

3132
impl Default for Config {
@@ -39,6 +40,7 @@ impl Default for Config {
3940
ignore_groups: false,
4041
strict: false,
4142
output_dir: PathBuf::from("."),
43+
source_type: SourceType::default(),
4244
}
4345
}
4446
}
@@ -75,6 +77,37 @@ impl Default for Target {
7577
}
7678
}
7779

80+
#[derive(Clone, Copy, PartialEq, Debug)]
81+
pub enum SourceType {
82+
Xml,
83+
Yaml,
84+
Json,
85+
}
86+
87+
impl Default for SourceType {
88+
fn default() -> Self {
89+
Self::Xml
90+
}
91+
}
92+
93+
impl SourceType {
94+
/// Make a new [`Source`] from a given extension.
95+
pub fn from_extension(s: &str) -> Option<Self> {
96+
match s {
97+
"yml" | "yaml" => Some(Self::Yaml),
98+
"json" => Some(Self::Json),
99+
"svd" | "xml" => Some(Self::Xml),
100+
_ => None,
101+
}
102+
}
103+
pub fn from_path(path: &Path) -> Self {
104+
path.extension()
105+
.and_then(|e| e.to_str())
106+
.and_then(Self::from_extension)
107+
.unwrap_or_default()
108+
}
109+
}
110+
78111
pub trait ToSanitizedPascalCase {
79112
fn to_sanitized_pascal_case(&self) -> Cow<str>;
80113
}

0 commit comments

Comments
 (0)