mirror of
https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator.git
synced 2025-02-23 09:07:07 +09:00
new: file IO & formatting & update docs with an example
This commit is contained in:
parent
a6c56ef9d6
commit
76c19d194d
6 changed files with 103 additions and 44 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -88,6 +88,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
|
@ -163,6 +164,16 @@ version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettyplease"
|
||||||
|
version = "0.2.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.93"
|
version = "1.0.93"
|
||||||
|
|
|
@ -17,6 +17,7 @@ env_logger = "0.11.6"
|
||||||
heck = "0.5"
|
heck = "0.5"
|
||||||
itertools = "0.14"
|
itertools = "0.14"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
prettyplease = "0.2"
|
||||||
proc-macro2 = "1.0.93"
|
proc-macro2 = "1.0.93"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
roxmltree = "0.20"
|
roxmltree = "0.20"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Generate register interface rust code from types in [`crate::types`].
|
//! Generate register interface rust code from types in [`crate::types`].
|
||||||
//!
|
//!
|
||||||
//! root: [`CodeGen`]
|
//! root: [`Module::generate_code`]
|
||||||
//!
|
//!
|
||||||
//! # TODO
|
//! # For developers
|
||||||
//! add docs (especially fields and registers)
|
//! Pass `--document-private-items` to see non-public items.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
@ -15,13 +15,14 @@ use crate::{
|
||||||
types::{Block, Module, ModuleBlockElements, Register},
|
types::{Block, Module, ModuleBlockElements, Register},
|
||||||
};
|
};
|
||||||
use heck::{ToSnakeCase, ToUpperCamelCase};
|
use heck::{ToSnakeCase, ToUpperCamelCase};
|
||||||
|
use itertools::Itertools;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CodeGenError {
|
pub enum CodeGenError {
|
||||||
#[error("tokenization error: {0}")]
|
#[error("tokenization(syn) error: {0}")]
|
||||||
TokenizeError(#[from] syn::Error),
|
SynError(#[from] syn::Error),
|
||||||
#[error("failed to create file: {0}")]
|
#[error("failed to create file: {0}")]
|
||||||
FilePathError(String),
|
FilePathError(String),
|
||||||
#[error("parent is required for {module}")]
|
#[error("parent is required for {module}")]
|
||||||
|
@ -121,8 +122,17 @@ mod util {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn generate_code(self) -> Result<HashMap<path::PathBuf, proc_macro2::TokenStream>, CodeGenError> {
|
pub fn generate_code(self) -> Result<HashMap<path::PathBuf, syn::File>, CodeGenError> {
|
||||||
self.generate_register_interface(None, None, HashMap::new())
|
let files = self.generate_register_interface(None, None, HashMap::new())?;
|
||||||
|
Ok(files
|
||||||
|
.into_iter()
|
||||||
|
.map(
|
||||||
|
|(path, tokens)| -> Result<(PathBuf, syn::File), syn::Error> {
|
||||||
|
let file: syn::File = syn::parse2(tokens)?;
|
||||||
|
Ok((path, file))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.process_results(|kv| HashMap::from_iter(kv))?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
27
src/io.rs
Normal file
27
src/io.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//! File IO for generated codes.
|
||||||
|
|
||||||
|
use std::{collections::HashMap, fs, io, path};
|
||||||
|
|
||||||
|
/// Write formatted codes generated with [`Module::generate_code`](crate::types::Module::generate_code).
|
||||||
|
pub fn write_to_files(
|
||||||
|
files: HashMap<path::PathBuf, syn::File>,
|
||||||
|
out_path: &path::Path,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if !out_path.is_dir() {
|
||||||
|
return Err(io::Error::from(io::ErrorKind::NotADirectory));
|
||||||
|
}
|
||||||
|
if fs::read_dir(out_path)?.next().is_some() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::AlreadyExists,
|
||||||
|
"out path is not empty",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for (file_path, code) in files {
|
||||||
|
fs::DirBuilder::new()
|
||||||
|
.recursive(true)
|
||||||
|
.create(out_path.join(&file_path).parent().unwrap())?;
|
||||||
|
|
||||||
|
fs::write(out_path.join(&file_path), prettyplease::unparse(&code))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
35
src/lib.rs
35
src/lib.rs
|
@ -1,4 +1,27 @@
|
||||||
//! Root document [`types::Module::from_xml_dom`]
|
//! Generate register interface software from register map in XML.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! Here's a typical usage:
|
||||||
|
//! ```no_run
|
||||||
|
//! use endcap_sl_software_ri_generator::types;
|
||||||
|
//!
|
||||||
|
//! let xmlfile = std::fs::read_to_string("./csr.xml")?;
|
||||||
|
//! let doc = roxmltree::Document::parse_with_options(
|
||||||
|
//! &xmlfile,
|
||||||
|
//! roxmltree::ParsingOptions {
|
||||||
|
//! allow_dtd: true,
|
||||||
|
//! nodes_limit: u32::MAX,
|
||||||
|
//! },
|
||||||
|
//! )?;
|
||||||
|
//!
|
||||||
|
//! let register_map = types::Module::from_xml_dom(doc.root_element())?;
|
||||||
|
//!
|
||||||
|
//! let files = register_map.generate_code()?;
|
||||||
|
//! endcap_sl_software_ri_generator::write_to_files(files, &std::path::PathBuf::from("out"))?;
|
||||||
|
//!
|
||||||
|
//! # Ok::<(), anyhow::Error>(())
|
||||||
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! # Overview
|
//! # Overview
|
||||||
//!
|
//!
|
||||||
|
@ -9,13 +32,15 @@
|
||||||
//!
|
//!
|
||||||
//! # modules
|
//! # modules
|
||||||
//! - [`types`]: type definitions of internal register map representation
|
//! - [`types`]: type definitions of internal register map representation
|
||||||
//! - [`type_traits`]: supplemental traits for types in [`types`]
|
|
||||||
//! - [`parser`]: supplemental parser (string to custom types)
|
|
||||||
//! - [`converter`]: DOM to internal representation
|
//! - [`converter`]: DOM to internal representation
|
||||||
//! - [`generator`]: internal representation to rust code
|
//! - [`generator`]: internal representation to rust code
|
||||||
|
//! - [`io`]: formatting and printing
|
||||||
|
|
||||||
pub mod converter;
|
pub mod converter;
|
||||||
pub mod generator;
|
pub mod generator;
|
||||||
pub mod parser;
|
pub mod io;
|
||||||
pub mod type_traits;
|
mod parser;
|
||||||
|
mod type_traits;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
pub use io::write_to_files;
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -1,15 +1,13 @@
|
||||||
use std::fs::DirBuilder;
|
use std::fs;
|
||||||
use std::io::Write;
|
|
||||||
use std::{fs, io::BufWriter};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::Result;
|
||||||
use endcap_sl_software_ri_generator::types;
|
use endcap_sl_software_ri_generator::types;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
log::debug!("logger enabled");
|
||||||
|
|
||||||
println!("Hello, world!");
|
|
||||||
let xmlfile = fs::read_to_string("./csr.xml")?;
|
let xmlfile = fs::read_to_string("./csr.xml")?;
|
||||||
let doc = roxmltree::Document::parse_with_options(
|
let doc = roxmltree::Document::parse_with_options(
|
||||||
&xmlfile,
|
&xmlfile,
|
||||||
|
@ -18,39 +16,26 @@ fn main() -> Result<()> {
|
||||||
nodes_limit: u32::MAX,
|
nodes_limit: u32::MAX,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
// println!("Parsed: {:#?}", doc);
|
log::debug!("Parsed: {:#?}", doc);
|
||||||
// println!("Root: {:?}", doc.root_element());
|
|
||||||
|
|
||||||
let register_map = types::Module::from_xml_dom(doc.root_element())?;
|
let register_map = types::Module::from_xml_dom(doc.root_element())?;
|
||||||
println!("read: {:#?}", register_map);
|
log::info!("read: {:?}", register_map);
|
||||||
|
log::debug!("read: {:#?}", register_map);
|
||||||
println!("===========================================");
|
|
||||||
|
|
||||||
let files = register_map.generate_code()?;
|
let files = register_map.generate_code()?;
|
||||||
// println!("{:#?}", files);
|
if log::log_enabled!(log::Level::Debug) {
|
||||||
for filepath in files.keys().sorted() {
|
for (path, code) in &files {
|
||||||
println!("{}", filepath.display());
|
log::debug!("path: {:?}", path);
|
||||||
|
log::debug!("{}", prettyplease::unparse(code));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !std::fs::read_dir("register_interface")
|
if log::log_enabled!(log::Level::Info) {
|
||||||
.context("register_interface not found")?
|
for filepath in files.keys().sorted() {
|
||||||
.collect_vec()
|
log::info!("{}", filepath.display());
|
||||||
.is_empty()
|
}
|
||||||
{
|
|
||||||
return Err(anyhow!("dir register_interface is not empty"));
|
|
||||||
};
|
|
||||||
for (file, code) in files {
|
|
||||||
DirBuilder::new()
|
|
||||||
.recursive(true)
|
|
||||||
.create(file.parent().context("no parent")?)?;
|
|
||||||
let file = fs::OpenOptions::new()
|
|
||||||
.create(true)
|
|
||||||
.truncate(true)
|
|
||||||
.write(true)
|
|
||||||
.open(file)
|
|
||||||
.context("opening file")?;
|
|
||||||
let mut writer = BufWriter::new(file);
|
|
||||||
write!(writer, "{}", code)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endcap_sl_software_ri_generator::write_to_files(files, &std::path::PathBuf::from("out"))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue