cameleon_genapi/parser/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5mod boolean;
6mod category;
7mod command;
8mod converter;
9mod elem_name;
10mod elem_type;
11mod enumeration;
12mod float;
13mod float_reg;
14mod formula;
15mod group;
16mod int_converter;
17mod int_reg;
18mod int_swiss_knife;
19mod integer;
20mod masked_int_reg;
21mod node;
22mod node_base;
23mod port;
24mod register;
25mod register_base;
26mod register_description;
27mod string;
28mod string_reg;
29mod struct_reg;
30mod swiss_knife;
31mod utils;
32mod xml;
33
34use group::GroupNode;
35use struct_reg::StructRegNode;
36use thiserror::Error;
37
38use crate::{
39    builder::{CacheStoreBuilder, NodeStoreBuilder, ValueStoreBuilder},
40    store::NodeData,
41    RegisterDescription,
42};
43
44use elem_name::{
45    ADV_FEATURE_LOCK, BOOLEAN, CATEGORY, COMMAND, CONF_ROM, CONVERTER, ENUMERATION, FLOAT,
46    FLOAT_REG, GROUP, INTEGER, INT_CONVERTER, INT_KEY, INT_REG, INT_SWISS_KNIFE, MASKED_INT_REG,
47    NODE, PORT, REGISTER, SMART_FEATURE, STRING, STRING_REG, STRUCT_REG, SWISS_KNIFE, TEXT_DESC,
48};
49
50#[derive(Debug, Error)]
51pub enum ParseError {
52    #[error("encodings must be UTF8: {0}")]
53    Utf8Error(#[from] std::str::Utf8Error),
54
55    #[error("invalid XML syntax: {0}")]
56    InvalidSyntax(#[from] roxmltree::Error),
57}
58
59pub type ParseResult<T> = std::result::Result<T, ParseError>;
60
61pub fn parse(
62    xml: &impl AsRef<str>,
63    node_builder: &mut impl NodeStoreBuilder,
64    value_builder: &mut impl ValueStoreBuilder,
65    cache_builder: &mut impl CacheStoreBuilder,
66) -> ParseResult<RegisterDescription> {
67    let document = xml::Document::from_str(xml.as_ref())?;
68    let mut node = document.root_node();
69    let reg_desc = node.parse(node_builder, value_builder, cache_builder);
70    while let Some(ref mut child) = node.next() {
71        let children: Vec<NodeData> = child.parse(node_builder, value_builder, cache_builder);
72        for child in children {
73            let id = child.node_base().id();
74            node_builder.store_node(id, child);
75        }
76    }
77
78    Ok(reg_desc)
79}
80
81trait Parse {
82    fn parse(
83        node: &mut xml::Node,
84        node_builder: &mut impl NodeStoreBuilder,
85        value_builder: &mut impl ValueStoreBuilder,
86        cache_builder: &mut impl CacheStoreBuilder,
87    ) -> Self;
88}
89
90impl Parse for Vec<NodeData> {
91    #[allow(clippy::too_many_lines)]
92    fn parse(
93        node: &mut xml::Node,
94        node_builder: &mut impl NodeStoreBuilder,
95        value_builder: &mut impl ValueStoreBuilder,
96        cache_builder: &mut impl CacheStoreBuilder,
97    ) -> Self {
98        match node.tag_name() {
99            NODE => vec![NodeData::Node(Box::new(node.parse(
100                node_builder,
101                value_builder,
102                cache_builder,
103            )))],
104            CATEGORY => vec![NodeData::Category(Box::new(node.parse(
105                node_builder,
106                value_builder,
107                cache_builder,
108            )))],
109            INTEGER => vec![NodeData::Integer(Box::new(node.parse(
110                node_builder,
111                value_builder,
112                cache_builder,
113            )))],
114            INT_REG => vec![NodeData::IntReg(Box::new(node.parse(
115                node_builder,
116                value_builder,
117                cache_builder,
118            )))],
119            MASKED_INT_REG => vec![NodeData::MaskedIntReg(Box::new(node.parse(
120                node_builder,
121                value_builder,
122                cache_builder,
123            )))],
124            BOOLEAN => vec![NodeData::Boolean(Box::new(node.parse(
125                node_builder,
126                value_builder,
127                cache_builder,
128            )))],
129            COMMAND => vec![NodeData::Command(Box::new(node.parse(
130                node_builder,
131                value_builder,
132                cache_builder,
133            )))],
134            ENUMERATION => vec![NodeData::Enumeration(Box::new(node.parse(
135                node_builder,
136                value_builder,
137                cache_builder,
138            )))],
139            FLOAT => vec![NodeData::Float(Box::new(node.parse(
140                node_builder,
141                value_builder,
142                cache_builder,
143            )))],
144            FLOAT_REG => vec![NodeData::FloatReg(Box::new(node.parse(
145                node_builder,
146                value_builder,
147                cache_builder,
148            )))],
149            STRING => vec![NodeData::String(Box::new(node.parse(
150                node_builder,
151                value_builder,
152                cache_builder,
153            )))],
154            STRING_REG => vec![NodeData::StringReg(Box::new(node.parse(
155                node_builder,
156                value_builder,
157                cache_builder,
158            )))],
159            REGISTER => vec![NodeData::Register(Box::new(node.parse(
160                node_builder,
161                value_builder,
162                cache_builder,
163            )))],
164            CONVERTER => vec![NodeData::Converter(Box::new(node.parse(
165                node_builder,
166                value_builder,
167                cache_builder,
168            )))],
169            INT_CONVERTER => vec![NodeData::IntConverter(Box::new(node.parse(
170                node_builder,
171                value_builder,
172                cache_builder,
173            )))],
174            SWISS_KNIFE => vec![NodeData::SwissKnife(Box::new(node.parse(
175                node_builder,
176                value_builder,
177                cache_builder,
178            )))],
179            INT_SWISS_KNIFE => vec![NodeData::IntSwissKnife(Box::new(node.parse(
180                node_builder,
181                value_builder,
182                cache_builder,
183            )))],
184            PORT => vec![NodeData::Port(Box::new(node.parse(
185                node_builder,
186                value_builder,
187                cache_builder,
188            )))],
189            STRUCT_REG => {
190                let node: StructRegNode = node.parse(node_builder, value_builder, cache_builder);
191                node.into_masked_int_regs(cache_builder)
192                    .into_iter()
193                    .map(|node| NodeData::MaskedIntReg(node.into()))
194                    .collect()
195            }
196            GROUP => {
197                let node: GroupNode = node.parse(node_builder, value_builder, cache_builder);
198                node.nodes
199            }
200            // TODO: Implement DCAM specific ndoes.
201            CONF_ROM | TEXT_DESC | INT_KEY | ADV_FEATURE_LOCK | SMART_FEATURE => todo!(),
202            _ => unreachable!(),
203        }
204    }
205}