Skip to content

Commit 2ccab6f

Browse files
committed
serde parse
1 parent 589fb81 commit 2ccab6f

File tree

6 files changed

+93
-23
lines changed

6 files changed

+93
-23
lines changed

CHANGELOG.md

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

88
## [Unreleased]
99

10+
- Add support of reading SVD from YAML or JSON files instead of XML
11+
- Fix ValidateLevel usage in lib.rs
12+
- Use `svd-parser` v0.12.1
13+
1014
## [v0.20.0] - 2021-12-07
1115

1216
### 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_yaml = "0.8.21"
49+
serde_json = "1.0.72"
4850

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

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

src/generate/register.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ pub fn fields(
297297
config: &Config,
298298
) -> Result<()> {
299299
let span = Span::call_site();
300-
let can_read = [Access::ReadOnly, Access::ReadWriteOnce, Access::ReadWrite].contains(&access);
301-
let can_write = access != Access::ReadOnly;
300+
let can_read = access.can_read();
301+
let can_write = access.can_write();
302302

303303
// TODO enumeratedValues
304304
let inline = quote! { #[inline(always)] };
@@ -1257,7 +1257,7 @@ fn lookup_in_peripherals<'p>(
12571257
all_peripherals: &'p [Peripheral],
12581258
) -> Result<(&'p EnumeratedValues, Option<Base<'p>>)> {
12591259
if let Some(peripheral) = all_peripherals.iter().find(|p| p.name == base_peripheral) {
1260-
let all_registers = peripheral.reg_iter().collect::<Vec<_>>();
1260+
let all_registers = peripheral.all_registers().collect::<Vec<_>>();
12611261
lookup_in_peripheral(
12621262
Some(base_peripheral),
12631263
base_register,

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,10 +529,10 @@ pub enum SvdError {
529529
}
530530

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

535-
let device = svd_parser::parse(xml)?;
535+
let device = crate::util::load_from(input, config)?;
536536
let mut device_x = String::new();
537537
let items =
538538
generate::device::render(&device, config, &mut device_x).or(Err(SvdError::Render))?;

src/main.rs

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

33
use log::{error, info};
4-
use std::path::PathBuf;
4+
use std::path::{Path, PathBuf};
55
use svd_parser::svd;
66

77
mod generate;
@@ -14,7 +14,7 @@ use std::process;
1414
use anyhow::{Context, Result};
1515
use clap::{App, Arg};
1616

17-
use crate::util::{build_rs, Config, Target};
17+
use crate::util::{build_rs, load_from, Config, Source, Target};
1818

1919
fn run() -> Result<()> {
2020
use clap_conf::prelude::*;
@@ -84,6 +84,11 @@ fn run() -> Result<()> {
8484
.short("s")
8585
.help("Make advanced checks due to parsing SVD"),
8686
)
87+
.arg(
88+
Arg::with_name("source_type")
89+
.long("source_type")
90+
.help("Specify file/stream format"),
91+
)
8792
.arg(
8893
Arg::with_name("log_level")
8994
.long("log")
@@ -101,19 +106,19 @@ fn run() -> Result<()> {
101106
))
102107
.get_matches();
103108

104-
let xml = &mut String::new();
109+
let input = &mut String::new();
105110
match matches.value_of("input") {
106111
Some(file) => {
107112
File::open(file)
108113
.context("Cannot open the SVD file")?
109-
.read_to_string(xml)
114+
.read_to_string(input)
110115
.context("Cannot read the SVD file")?;
111116
}
112117
None => {
113118
let stdin = std::io::stdin();
114119
stdin
115120
.lock()
116-
.read_to_string(xml)
121+
.read_to_string(input)
117122
.context("Cannot read from stdin")?;
118123
}
119124
}
@@ -146,6 +151,18 @@ fn run() -> Result<()> {
146151
cfg.bool_flag("ignore_groups", Filter::Arg) || cfg.bool_flag("ignore_groups", Filter::Conf);
147152
let strict = cfg.bool_flag("strict", Filter::Arg) || cfg.bool_flag("strict", Filter::Conf);
148153

154+
let mut source_type = cfg
155+
.grab()
156+
.arg("source_type")
157+
.conf("source_type")
158+
.done()
159+
.and_then(|s| Source::from_str(&s))
160+
.unwrap_or_default();
161+
162+
if let Some(file) = matches.value_of("input") {
163+
source_type = Source::from_path(Path::new(file))
164+
}
165+
149166
let config = Config {
150167
target,
151168
nightly,
@@ -155,18 +172,11 @@ fn run() -> Result<()> {
155172
ignore_groups,
156173
strict,
157174
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
175+
source_type,
165176
};
166177

167178
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())?;
179+
let device = load_from(input, &config)?;
170180

171181
let mut device_x = String::new();
172182
info!("Rendering device");

src/util.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use std::borrow::Cow;
22

3-
use crate::svd::{
4-
Access, Cluster, Field, Register, RegisterCluster, RegisterInfo, RegisterProperties,
5-
};
3+
use crate::svd::{Access, Cluster, Device, Field, Register, RegisterCluster, RegisterInfo, RegisterProperties,, ValidateLevel};
64
use inflections::Inflect;
75
use proc_macro2::{Ident, Literal, Span, TokenStream};
86
use quote::{quote, ToTokens};
9-
use std::path::PathBuf;
7+
use std::path::{Path, PathBuf};
108

119
use anyhow::{anyhow, bail, Context, Result};
1210

@@ -16,6 +14,26 @@ pub const BITS_PER_BYTE: u32 = 8;
1614
/// that are not valid in Rust ident
1715
const BLACKLIST_CHARS: &[char] = &['(', ')', '[', ']', '/', ' ', '-'];
1816

17+
pub(crate) fn load_from(input: &str, config: &crate::util::Config) -> Result<Device> {
18+
Ok(match config.source_type {
19+
Source::Xml => {
20+
let mut parser_config = svd_parser::Config::default();
21+
parser_config.validate_level = if config.strict {
22+
ValidateLevel::Strict
23+
} else {
24+
ValidateLevel::Weak
25+
};
26+
27+
svd_parser::parse_with_config(input, &parser_config)
28+
.with_context(|| "Error parsing SVD XML file".to_string())?
29+
}
30+
Source::Yaml => serde_yaml::from_str(input)
31+
.with_context(|| "Error parsing SVD YAML file".to_string())?,
32+
Source::Json => serde_json::from_str(input)
33+
.with_context(|| "Error parsing SVD JSON file".to_string())?,
34+
})
35+
}
36+
1937
#[derive(Clone, PartialEq, Debug)]
2038
pub struct Config {
2139
pub target: Target,
@@ -26,6 +44,7 @@ pub struct Config {
2644
pub ignore_groups: bool,
2745
pub strict: bool,
2846
pub output_dir: PathBuf,
47+
pub source_type: Source,
2948
}
3049

3150
impl Default for Config {
@@ -39,6 +58,7 @@ impl Default for Config {
3958
ignore_groups: false,
4059
strict: false,
4160
output_dir: PathBuf::from("."),
61+
source_type: Source::default(),
4262
}
4363
}
4464
}
@@ -75,6 +95,36 @@ impl Default for Target {
7595
}
7696
}
7797

98+
#[derive(Clone, Copy, PartialEq, Debug)]
99+
pub enum Source {
100+
Xml,
101+
Yaml,
102+
Json,
103+
}
104+
105+
impl Default for Source {
106+
fn default() -> Self {
107+
Self::Xml
108+
}
109+
}
110+
111+
impl Source {
112+
pub fn from_str(s: &str) -> Option<Self> {
113+
match s {
114+
"yml" | "yaml" => Some(Self::Yaml),
115+
"json" => Some(Self::Json),
116+
"xml" => Some(Self::Xml),
117+
_ => None,
118+
}
119+
}
120+
pub fn from_path(path: &Path) -> Self {
121+
path.extension()
122+
.and_then(|e| e.to_str())
123+
.and_then(Self::from_str)
124+
.unwrap_or_default()
125+
}
126+
}
127+
78128
pub trait ToSanitizedPascalCase {
79129
fn to_sanitized_pascal_case(&self) -> Cow<str>;
80130
}

0 commit comments

Comments
 (0)