diff --git a/Cargo.lock b/Cargo.lock index 5254592..bf3f0d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,25 @@ name = "endcap-sl-register-interface-generator" version = "0.1.0" dependencies = [ "roxmltree", + "thiserror", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", ] [[package]] @@ -14,3 +33,40 @@ name = "roxmltree" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" diff --git a/Cargo.toml b/Cargo.toml index 5c0dcfb..de63044 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ path = "src/lib.rs" [dependencies] roxmltree = "0.20" +thiserror = "2.0" diff --git a/src/converter.rs b/src/converter.rs new file mode 100644 index 0000000..144df2c --- /dev/null +++ b/src/converter.rs @@ -0,0 +1,127 @@ +use std::num; + +use roxmltree::{Node, TextPos}; +use thiserror::Error; + +use crate::types::Module; + +#[derive(Debug, Error)] +pub enum DomConversionError { + #[error("attribute {attr} not found in element: {start} - {end}", start = pos.0, end = pos.1)] + AttributeNotFound { + attr: &'static str, + pos: (TextPos, TextPos), + }, + #[error("string conversion error: {start} - {end}", start = pos.0, end = pos.1)] + ParseIntError { + attr: &'static str, + pos: (TextPos, TextPos), + #[source] + source: num::ParseIntError, + }, + #[error("string conversion error: {start} - {end}", start = pos.0, end = pos.1)] + ParsePrefixedU32Error { + attr: &'static str, + pos: (TextPos, TextPos), + #[source] + source: ParsePrefixedU32Error, + }, + #[error("invalid dom structure: {0}")] + InvalidFormat(String), +} + +impl DomConversionError { + fn attr_not_found(attr: &'static str, node: Node) -> Self { + let range = node.range(); + let doc = node.document(); + Self::AttributeNotFound { + attr, + pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), + } + } + + fn parse_int_error(e: num::ParseIntError, attr: &'static str, node: Node) -> Self { + let range = node.range(); + let doc = node.document(); + Self::ParseIntError { + attr, + pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), + source: e, + } + } + + fn parse_prefixed_u32_error(e: ParsePrefixedU32Error, attr: &'static str, node: Node) -> Self { + let range = node.range(); + let doc = node.document(); + Self::ParsePrefixedU32Error { + attr, + pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), + source: e, + } + } +} + +#[derive(Debug, Error)] +pub enum ParsePrefixedU32Error { + #[error("invalid prefix: found {found}")] + InvalidPrefix { found: char }, + #[error("parse int error")] + ParseIntError(#[from] num::ParseIntError), +} + +trait ParsePrefixedU32 { + fn parse_prefixed_u32(&self) -> Result; +} + +impl ParsePrefixedU32 for &str { + fn parse_prefixed_u32(&self) -> Result { + let radix = match self.chars().nth(1) { + Some('x') => 16, + Some(c) if c.is_numeric() => 10, + Some(c) => return Err(ParsePrefixedU32Error::InvalidPrefix { found: c }), + None => return Err(ParsePrefixedU32Error::InvalidPrefix { found: ' ' }), + }; + + match radix { + 10 => Ok(self.parse()?), + radix => Ok(u32::from_str_radix(&self[2..], radix)?), + } + } +} + +impl Module { + pub fn from_xml_dom(root: Node) -> Result { + assert!(root.parent().unwrap().is_root()); + assert_eq!(root.tag_name().name(), "module"); + + let name = root.tag_name().name(); + println!("{}", name); + + let name = match root.attribute("name") { + Some(name) => name.to_string(), + None => return Err(DomConversionError::attr_not_found("name", root)), + }; + let addr = match root.attribute("addr") { + Some(addr) => addr + .parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "addr", root))?, + None => return Err(DomConversionError::attr_not_found("addr", root)), + }; + let size = match root.attribute("size") { + Some(addr) => addr + .parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "size", root))?, + None => return Err(DomConversionError::attr_not_found("size", root)), + }; + Ok(Self { + name, + addr, + size, + amod: todo!(), + r#type: todo!(), + desc: todo!(), + elements_bitstring: todo!(), + elements_other: todo!(), + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index cd40856..63abe1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ pub mod types; +pub mod converter; diff --git a/src/main.rs b/src/main.rs index b0218f8..1f0d6e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::fs; -use endcap_sl_register_interface_generator; +use endcap_sl_register_interface_generator::types; fn main() { println!("Hello, world!"); @@ -19,4 +19,6 @@ fn main() { let root = doc.root_element(); println!("tag: {:?}", root.tag_name()); } + + let register_map = types::Module::from_xml_dom(doc.root_element()).unwrap(); }