Skip to content

Commit

Permalink
serde parse
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Dec 10, 2021
1 parent 7358e78 commit 995708b
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- Add support of reading SVD from YAML or JSON files instead of XML
- Fix ValidateLevel usage in lib.rs
- Use `svd-parser` v0.12.1

## [v0.20.0] - 2021-12-07

### Fixed
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,17 @@ quote = "1.0"
proc-macro2 = "1.0"
anyhow = "1.0"
thiserror = "1.0"
serde_yaml = "0.8.21"
serde_json = "1.0.72"

[dependencies.svd-parser]
features = ["derive-from"]
version = "0.12"

[dependencies.svd-rs]
features = ["serde"]
version = "0.12.1"

[dependencies.syn]
version = "1.0"
features = ["full","extra-traits"]
6 changes: 3 additions & 3 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,8 @@ pub fn fields(
config: &Config,
) -> Result<()> {
let span = Span::call_site();
let can_read = [Access::ReadOnly, Access::ReadWriteOnce, Access::ReadWrite].contains(&access);
let can_write = access != Access::ReadOnly;
let can_read = access.can_read();
let can_write = access.can_write();

// TODO enumeratedValues
let inline = quote! { #[inline(always)] };
Expand Down Expand Up @@ -1263,7 +1263,7 @@ fn lookup_in_peripherals<'p>(
all_peripherals: &'p [Peripheral],
) -> Result<(&'p EnumeratedValues, Option<Base<'p>>)> {
if let Some(peripheral) = all_peripherals.iter().find(|p| p.name == base_peripheral) {
let all_registers = peripheral.reg_iter().collect::<Vec<_>>();
let all_registers = peripheral.all_registers().collect::<Vec<_>>();
lookup_in_peripheral(
Some(base_peripheral),
base_register,
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,10 @@ pub enum SvdError {
}

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

let device = svd_parser::parse(xml)?;
let device = crate::util::load_from(input, config)?;
let mut device_x = String::new();
let items =
generate::device::render(&device, config, &mut device_x).or(Err(SvdError::Render))?;
Expand Down
38 changes: 24 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![recursion_limit = "128"]

use log::{error, info};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use svd_parser::svd;

mod generate;
Expand All @@ -14,7 +14,7 @@ use std::process;
use anyhow::{Context, Result};
use clap::{App, Arg};

use crate::util::{build_rs, Config, Target};
use crate::util::{build_rs, load_from, Config, Source, Target};

fn run() -> Result<()> {
use clap_conf::prelude::*;
Expand Down Expand Up @@ -84,6 +84,11 @@ fn run() -> Result<()> {
.short("s")
.help("Make advanced checks due to parsing SVD"),
)
.arg(
Arg::with_name("source_type")
.long("source_type")
.help("Specify file/stream format"),
)
.arg(
Arg::with_name("log_level")
.long("log")
Expand All @@ -101,19 +106,19 @@ fn run() -> Result<()> {
))
.get_matches();

let xml = &mut String::new();
let input = &mut String::new();
match matches.value_of("input") {
Some(file) => {
File::open(file)
.context("Cannot open the SVD file")?
.read_to_string(xml)
.read_to_string(input)
.context("Cannot read the SVD file")?;
}
None => {
let stdin = std::io::stdin();
stdin
.lock()
.read_to_string(xml)
.read_to_string(input)
.context("Cannot read from stdin")?;
}
}
Expand Down Expand Up @@ -146,6 +151,18 @@ fn run() -> Result<()> {
cfg.bool_flag("ignore_groups", Filter::Arg) || cfg.bool_flag("ignore_groups", Filter::Conf);
let strict = cfg.bool_flag("strict", Filter::Arg) || cfg.bool_flag("strict", Filter::Conf);

let mut source_type = cfg
.grab()
.arg("source_type")
.conf("source_type")
.done()
.and_then(|s| Source::from_str(&s))
.unwrap_or_default();

if let Some(file) = matches.value_of("input") {
source_type = Source::from_path(Path::new(file))
}

let config = Config {
target,
nightly,
Expand All @@ -155,18 +172,11 @@ fn run() -> Result<()> {
ignore_groups,
strict,
output_dir: path.clone(),
};

let mut parser_config = svd_parser::Config::default();
parser_config.validate_level = if strict {
svd::ValidateLevel::Strict
} else {
svd::ValidateLevel::Weak
source_type,
};

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

let mut device_x = String::new();
info!("Rendering device");
Expand Down
56 changes: 54 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::borrow::Cow;

use crate::svd::{Access, Cluster, Register, RegisterCluster, RegisterInfo};
use crate::svd::{Access, Cluster, Device, Register, RegisterCluster, RegisterInfo, ValidateLevel};
use inflections::Inflect;
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::{quote, ToTokens};
use std::path::PathBuf;
use std::path::{Path, PathBuf};

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

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

pub(crate) fn load_from(input: &str, config: &crate::util::Config) -> Result<Device> {
Ok(match config.source_type {
Source::Xml => {
let mut parser_config = svd_parser::Config::default();
parser_config.validate_level = if config.strict {
ValidateLevel::Strict
} else {
ValidateLevel::Weak
};

svd_parser::parse_with_config(input, &parser_config)
.with_context(|| "Error parsing SVD XML file".to_string())?
}
Source::Yaml => serde_yaml::from_str(input)
.with_context(|| "Error parsing SVD YAML file".to_string())?,
Source::Json => serde_json::from_str(input)
.with_context(|| "Error parsing SVD JSON file".to_string())?,
})
}

#[derive(Clone, PartialEq, Debug)]
pub struct Config {
pub target: Target,
Expand All @@ -24,6 +44,7 @@ pub struct Config {
pub ignore_groups: bool,
pub strict: bool,
pub output_dir: PathBuf,
pub source_type: Source,
}

impl Default for Config {
Expand All @@ -37,6 +58,7 @@ impl Default for Config {
ignore_groups: false,
strict: false,
output_dir: PathBuf::from("."),
source_type: Source::default(),
}
}
}
Expand Down Expand Up @@ -73,6 +95,36 @@ impl Default for Target {
}
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Source {
Xml,
Yaml,
Json,
}

impl Default for Source {
fn default() -> Self {
Self::Xml
}
}

impl Source {
pub fn from_str(s: &str) -> Option<Self> {
match s {
"yml" | "yaml" => Some(Self::Yaml),
"json" => Some(Self::Json),
"xml" => Some(Self::Xml),
_ => None,
}
}
pub fn from_path(path: &Path) -> Self {
path.extension()
.and_then(|e| e.to_str())
.and_then(Self::from_str)
.unwrap_or_default()
}
}

pub trait ToSanitizedPascalCase {
fn to_sanitized_pascal_case(&self) -> Cow<str>;
}
Expand Down

0 comments on commit 995708b

Please sign in to comment.