From 8fee5558604691b70483b9eb4d7122c11952087e Mon Sep 17 00:00:00 2001 From: Wataru Otsubo Date: Thu, 30 Jan 2025 15:33:05 +0900 Subject: [PATCH] wip(converter): until Block converter (next: Register) --- src/converter.rs | 290 ++++++++++++++++++++++++++++++++++++++++++----- src/lib.rs | 2 + src/main.rs | 2 + src/parser.rs | 40 +++++++ src/types.rs | 4 +- 5 files changed, 310 insertions(+), 28 deletions(-) diff --git a/src/converter.rs b/src/converter.rs index 7974a4f..96fb98c 100644 --- a/src/converter.rs +++ b/src/converter.rs @@ -1,12 +1,15 @@ //! Convert DOM to register interface, complementing optional parameters. -use std::num; +use std::{num, str}; use roxmltree::{Node, TextPos}; use thiserror::Error; use crate::parser::{ParseEnumError, ParsePrefixedU32, ParsePrefixedU32Error}; -use crate::types::Module; +use crate::types::{ + BitString, Block, DataType, Field, Fifo, Memory, Module, ModuleBlockElements, MultipleParams, + Register, Value, +}; #[derive(Debug, Error, PartialEq)] pub enum DomConversionError { @@ -36,8 +39,13 @@ pub enum DomConversionError { #[source] source: ParseEnumError, }, - #[error("invalid dom structure: {0}")] - InvalidFormat(String), + #[error("invalid node {found}: {start} - {end}", start = pos.0, end = pos.1)] + InvalidNode { + pos: (TextPos, TextPos), + found: String, + }, + #[error("other dom conversion error: {0}")] + OtherError(String), } impl DomConversionError { @@ -79,48 +87,278 @@ impl DomConversionError { source: e, } } + + fn invalid_node(found: String, node: Node) -> Self { + let range = node.range(); + let doc = node.document(); + Self::InvalidNode { + pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), + found, + } + } +} + +mod util { + use roxmltree::Node; + + use crate::types::{DataType, RwSpecifier}; + + use super::DomConversionError; + + pub(crate) fn get_name(node: Node) -> Result { + match node.attribute("name") { + Some(name) => Ok(name.to_string()), + None => Err(DomConversionError::attr_not_found("name", node)), + } + } + + pub(crate) fn get_type(node: Node) -> Option> { + node.attribute("type").map(|x| { + x.parse() + .map_err(|e| DomConversionError::parse_enum_error(e, "type", node)) + }) + } + + pub(crate) fn get_modf(node: Node) -> Option> { + node.attribute("modf").map(|x| { + x.parse() + .map_err(|e| DomConversionError::parse_enum_error(e, "modf", node)) + }) + } } impl Module { - pub fn from_xml_dom(root: Node) -> Result { - assert!(root.parent().unwrap().is_root()); - assert_eq!(root.tag_name().name(), "module"); + pub fn from_xml_dom(node: Node) -> Result { + assert!(node.parent().unwrap().is_root()); + assert_eq!(node.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") { + let name = util::get_name(node)?; + let addr = match node.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)), + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "addr", node))?, + None => return Err(DomConversionError::attr_not_found("addr", node)), }; - let size = match root.attribute("size") { + let size = match node.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)), + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "size", node))?, + None => return Err(DomConversionError::attr_not_found("size", node)), }; - let amod = root + let amod = node .attribute("amod") .map(|amod| { amod.parse() - .map_err(|e| DomConversionError::parse_enum_error(e, "amod", root)) + .map_err(|e| DomConversionError::parse_enum_error(e, "amod", node)) }) .transpose()?; + let r#type = util::get_type(node).transpose()?; + + let child_bitstrings = node + .children() + .filter(|node| node.is_element()) + .filter(|node| node.tag_name().name().eq("bitstring")) + .map(|node| BitString::from_xml_dom(node)) + .collect::>()?; + let child_other = node + .children() + .filter(|node| node.is_element()) + .map(|node| ModuleBlockElements::from_xml_dom(node)) + .collect::>()?; + Ok(Self { name, addr, size, amod, - r#type: todo!(), - desc: todo!(), - elements_bitstring: todo!(), - elements_other: todo!(), + r#type, + desc: node.attribute("desc").map(str::to_string), + elements_bitstring: child_bitstrings, + elements_other: child_other, }) } } + +impl ModuleBlockElements { + pub(crate) fn from_xml_dom(node: Node) -> Result { + match node.tag_name().name() { + "block" => Ok(Self::Block(Block::from_xml_dom(node)?)), + "register" => Ok(Self::Register(Register::from_xml_dom(node)?)), + "memory" => Ok(Self::Memory(Memory::from_xml_dom(node)?)), + "fifo" => Ok(Self::Fifo(Fifo::from_xml_dom(node)?)), + s => Err(DomConversionError::invalid_node(s.to_string(), node)), + } + } +} + +impl BitString { + pub(crate) fn from_xml_dom(node: Node) -> Result { + let name = util::get_name(node)?; + let size = node + .attribute("size") + .map(|addr| { + addr.parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "size", node)) + }) + .transpose()?; + let mask = node + .attribute("mask") + .map(|addr| { + addr.parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "mask", node)) + }) + .transpose()?; + let modf = node + .attribute("modf") + .map(|addr| { + addr.parse() + .map_err(|e| DomConversionError::parse_enum_error(e, "modf", node)) + }) + .transpose()?; + + let children = node + .children() + .filter(|node| node.is_element() && node.tag_name().name().eq("field")) + .map(|node| Field::from_xml_dom(node)) + .collect::>()?; + + Ok(Self { + name, + size, + mask, + modf, + desc: node.attribute("desc").map(str::to_string), + elements_field: children, + }) + } +} + +impl Block { + pub(crate) fn from_xml_dom(node: Node) -> Result { + let name = util::get_name(node)?; + let addr = match node.attribute("addr") { + Some(addr) => addr + .parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "addr", node))?, + None => { + // derive from parent + todo!("need to confirm") + } + }; + let r#type = match util::get_type(node).transpose()? { + Some(x) => Some(x), + None => node + .ancestors() + .filter_map(util::get_type) + .next() + .transpose()?, + }; + let modf = match util::get_modf(node).transpose()? { + Some(x) => Some(x), + None => node + .ancestors() + .filter_map(util::get_modf) + .next() + .transpose()?, + }; + let multiple = MultipleParams::from_xml_dom(node)?; + let decoder = match node.attribute("decoder") { + Some(s) => s.to_string(), + None => match node + .ancestors() + .filter_map(|node| node.attribute("decoder")) + .next() + { + Some(s) => Ok(s.to_string()), + None => Err(DomConversionError::OtherError( + "decoder format is not yet fixed".to_string(), + )), + }?, + }; + let size = match node.attribute("size") { + Some(addr) => addr + .parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "size", node))?, + None => return Err(DomConversionError::attr_not_found("size", node)), + }; + let desc = node.attribute("desc").map(str::to_string); + + let children = node + .children() + .filter(|node| node.is_element()) + .map(|node| ModuleBlockElements::from_xml_dom(node)) + .collect::>()?; + + Ok(Block { + name, + addr, + r#type, + modf, + multiple, + decoder, + size, + desc, + elements: children, + }) + } +} + +impl Register { + pub(crate) fn from_xml_dom(node: Node) -> Result { + todo!("do here next") + } +} + +impl Memory { + pub(crate) fn from_xml_dom(node: Node) -> Result { + todo!() + } +} + +impl Fifo { + pub(crate) fn from_xml_dom(node: Node) -> Result { + todo!() + } +} + +impl Field { + pub(crate) fn from_xml_dom(node: Node) -> Result { + todo!() + } +} + +impl Value { + pub(crate) fn from_xml_dom(node: Node) -> Result { + todo!() + } +} + +impl MultipleParams { + pub(crate) fn from_xml_dom(node: Node) -> Result, DomConversionError> { + let multiple = match node + .attribute("multiple") + .map(|x| { + x.parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "multiple", node)) + }) + .transpose()? + { + Some(x) => x, + None => return Ok(None), + }; + + let offset = match node + .attribute("offset") + .map(|x| { + x.parse_prefixed_u32() + .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "offset", node)) + }) + .transpose()? + { + Some(x) => x, + None => return Ok(None), + }; + + Ok(Some(MultipleParams { multiple, offset })) + } +} diff --git a/src/lib.rs b/src/lib.rs index 8d84cd2..477c59e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +//! Root document [`types::Module::from_xml_dom`] + pub mod types; pub mod parser; pub mod converter; diff --git a/src/main.rs b/src/main.rs index cb34e4f..11ce1eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,8 @@ fn main() { { let root = doc.root_element(); println!("tag: {:?}", root.tag_name()); + let root_childs = root.children().filter(|node| node.is_element()); + println!("children: {:?}", root_childs); } let register_map = types::Module::from_xml_dom(doc.root_element()).unwrap(); diff --git a/src/parser.rs b/src/parser.rs index ec0ab99..aea5d71 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -109,3 +109,43 @@ mod parse_amodvalues { } } } + +mod parse_datatype { + use std::str::FromStr; + + use crate::types::DataType; + + use super::ParseEnumError; + + impl FromStr for DataType { + type Err = ParseEnumError; + + fn from_str(s: &str) -> Result { + match s { + "D32" => Ok(Self::D32), + s => Err(ParseEnumError::invalid_variant::(s.to_string())), + } + } + } +} + +mod parse_rw_specifier { + use std::str::FromStr; + + use crate::types::RwSpecifier; + + use super::ParseEnumError; + + impl FromStr for RwSpecifier { + type Err = ParseEnumError; + + fn from_str(s: &str) -> Result { + match s { + "R" => Ok(Self::R), + "W" => Ok(Self::W), + "RW" => Ok(Self::RW), + s => Err(ParseEnumError::invalid_variant::(s.to_string())), + } + } + } +} diff --git a/src/types.rs b/src/types.rs index 2825cbc..3a0fa97 100644 --- a/src/types.rs +++ b/src/types.rs @@ -34,9 +34,9 @@ pub struct Block { /// Fill this with proper calc. pub addr: u32, /// Fill this with proper calc. - pub r#type: DataType, + pub r#type: Option, /// Fill this with proper calc. - pub modf: RwSpecifier, + pub modf: Option, // TODO: should this be expanded? pub multiple: Option, // TODO