wayland_scanner_lib/
parser.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use xml::reader::{EventReader, XmlEvent};
6
7use std::io::Read;
8use std::str::{FromStr, ParseBoolError};
9use std::{error, fmt};
10
11#[derive(Debug, PartialEq)]
12pub enum ArgKind {
13    Int,
14    Uint,
15    Fixed,
16    Object,
17    NewId,
18    String,
19    Array,
20    Fd,
21}
22
23impl ArgKind {
24    fn from_str(s: &str) -> Option<ArgKind> {
25        match s {
26            "int" => Some(ArgKind::Int),
27            "uint" => Some(ArgKind::Uint),
28            "fixed" => Some(ArgKind::Fixed),
29            "string" => Some(ArgKind::String),
30            "object" => Some(ArgKind::Object),
31            "new_id" => Some(ArgKind::NewId),
32            "array" => Some(ArgKind::Array),
33            "fd" => Some(ArgKind::Fd),
34            _ => None,
35        }
36    }
37}
38
39#[derive(Debug)]
40pub enum ParseElement {
41    Protocol {
42        name: String,
43    },
44    Copyright,
45    Interface {
46        name: String,
47        version: u32,
48    },
49    Description {
50        summary: String,
51    },
52    Request {
53        name: String,
54        since: u32,
55        request_type: Option<String>,
56    },
57    Event {
58        name: String,
59        since: u32,
60    },
61    Arg {
62        name: String,
63        kind: ArgKind,
64        summary: Option<String>,
65        interface: Option<String>,
66        nullable: bool,
67        enum_type: Option<String>,
68    },
69    Enum {
70        name: String,
71        since: u32,
72        bitfield: bool,
73    },
74    EnumEntry {
75        name: String,
76        value: i64,
77        summary: Option<String>,
78        since: u32,
79    },
80}
81
82#[derive(Debug)]
83pub struct ParseNode {
84    pub element: ParseElement,
85    pub body: Option<String>,
86    pub children: Vec<ParseNode>,
87}
88
89pub struct Parser<R: Read> {
90    xml: xml::reader::EventReader<R>,
91}
92
93#[derive(Debug, Clone)]
94pub struct ParseError {
95    msg: String,
96}
97
98impl ParseError {
99    fn new(msg: String) -> Self {
100        ParseError { msg }
101    }
102}
103
104impl fmt::Display for ParseError {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        write!(f, "{}", self.msg)
107    }
108}
109
110impl error::Error for ParseError {
111    fn description(&self) -> &str {
112        &self.msg
113    }
114
115    fn cause(&self) -> Option<&dyn error::Error> {
116        None
117    }
118}
119
120impl From<ParseBoolError> for ParseError {
121    fn from(e: ParseBoolError) -> Self {
122        ParseError::new(format!("Failed to parse boolean {}", e))
123    }
124}
125
126pub type ParseResult<T> = Result<T, ParseError>;
127
128/// The default rust numeric parse routines do not handle '0x..' constants.
129/// This just maps 0x to a radix of 16.
130fn parse_int<T: FromStr + num::Num>(s: &str) -> ParseResult<T> {
131    if s.starts_with("0x") {
132        T::from_str_radix(&s[2..], 16)
133            .map_err(|_| ParseError::new(format!("Failed to parse int {}", s)))
134    } else {
135        s.parse::<T>().map_err(|_| ParseError::new(format!("Failed to parse int {}", s)))
136    }
137}
138
139trait XmlAttr
140where
141    Self: Sized,
142{
143    fn default() -> Self;
144
145    fn from_xml_attr(attr: xml::attribute::OwnedAttribute) -> ParseResult<Self>;
146}
147
148impl<T> XmlAttr for Option<T>
149where
150    T: XmlAttr,
151{
152    fn default() -> Self {
153        None
154    }
155
156    fn from_xml_attr(attr: xml::attribute::OwnedAttribute) -> ParseResult<Self> {
157        T::from_xml_attr(attr).map(|t| Some(t))
158    }
159}
160
161macro_rules! impl_xml_attr {
162    ($type:ty, $default:expr, $attr:ident => $from_attr:expr) => {
163        impl XmlAttr for $type {
164            fn default() -> Self {
165                $default
166            }
167
168            fn from_xml_attr($attr: xml::attribute::OwnedAttribute) -> ParseResult<Self> {
169                $from_attr
170            }
171        }
172    };
173}
174
175impl_xml_attr!(u32, 0, attr => parse_int::<Self>(&attr.value));
176impl_xml_attr!(i64, 0, attr => parse_int::<Self>(&attr.value));
177impl_xml_attr!(bool, false, attr => Ok(attr.value.parse::<bool>()?));
178impl_xml_attr!(String, "".to_owned(), attr => Ok(attr.value));
179impl_xml_attr!(Option<ArgKind>, None, attr => Ok(ArgKind::from_str(&attr.value)));
180
181/// Simplifies binding a set of XML attributes to an expression.
182///
183///
184/// Ex:
185///
186///   // Reads the XML attribute with the name 'attr1' and stores the value into
187///   // |var1|. If |attrs| does not contain 'attr1' then |var1| will be None.
188///   map_xml_attrs!(attrs, ("attr1" => var1: Option<String>) => {
189///         println!("Found attr1 == {}", var1)
190///   });
191///
192/// There must be a corresponding |XmlAttr| trait implementation for any type
193/// that appears in the argument list.
194macro_rules! map_xml_attrs {
195    ($attributes:expr, ($($xml_name:expr => $field_name:ident : $field_type:ty),*) => { $body:expr }) => {
196        {
197            $(
198                let mut $field_name : $field_type = XmlAttr::default();
199            )*
200            for attr in $attributes {
201                match attr.name.local_name.as_ref() {
202                    $(
203                        $xml_name => $field_name = XmlAttr::from_xml_attr(attr)?,
204                    )*
205                    _ => {
206                        return Err(ParseError::new(format!(
207                            "Unsupported attribute {}",
208                            attr.name.local_name
209                        )));
210                    }
211                }
212            }
213            $body
214        }
215    }
216}
217
218impl<R: Read> Parser<R> {
219    /// Reads the entire XML document, returning the root node of the parse
220    /// tree.
221    pub fn read_document(&mut self) -> ParseResult<ParseNode> {
222        if let Ok(XmlEvent::StartDocument { .. }) = self.xml.next() {
223            self.read_node()
224        } else {
225            Err(ParseError::new("Missing StartDocument".to_owned()))
226        }
227    }
228
229    fn read_node(&mut self) -> ParseResult<ParseNode> {
230        match self.xml.next() {
231            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
232                let element = self.element_from_xml(name.local_name.as_ref(), attributes)?;
233                self.populate_node(element, name.local_name.as_ref())
234            }
235            node => Err(ParseError::new(format!("Not Implemented {:?}", node))),
236        }
237    }
238
239    fn populate_node(&mut self, element: ParseElement, xml_name: &str) -> ParseResult<ParseNode> {
240        let mut children: Vec<ParseNode> = Vec::new();
241        let mut body: Option<String> = None;
242        loop {
243            match self.xml.next() {
244                Ok(XmlEvent::EndElement { name }) => {
245                    if name.local_name == xml_name {
246                        return Ok(ParseNode { element, children, body });
247                    }
248                    return Err(ParseError::new("Unexpected EndElement".to_owned()));
249                }
250                Ok(XmlEvent::StartElement { name, attributes, .. }) => {
251                    let element = self.element_from_xml(name.local_name.as_ref(), attributes)?;
252                    let node = self.populate_node(element, name.local_name.as_ref())?;
253                    children.push(node);
254                }
255                Ok(XmlEvent::CData(text)) | Ok(XmlEvent::Characters(text)) => {
256                    body = Some(text);
257                }
258                Ok(XmlEvent::Whitespace(_)) | Ok(XmlEvent::Comment(_)) => continue,
259                event => {
260                    return Err(ParseError::new(format!("Unhandled event {:?}", event)));
261                }
262            }
263        }
264    }
265
266    fn element_from_xml(
267        &self,
268        element_name: &str,
269        attributes: Vec<xml::attribute::OwnedAttribute>,
270    ) -> ParseResult<ParseElement> {
271        match element_name {
272            "protocol" => map_xml_attrs!(attributes,
273                                      ("name" => name: Option<String>) => {
274                Ok(ParseElement::Protocol {
275                    name: name
276                        .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
277                })
278            }),
279            "copyright" => Ok(ParseElement::Copyright),
280            "interface" => map_xml_attrs!(attributes,
281                                           ("name" => name: Option<String>,
282                                            "version" => version: u32) => {
283                Ok(ParseElement::Interface {
284                    name: name
285                        .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
286                    version,
287                })
288
289            }),
290            "request" => map_xml_attrs!(attributes,
291                                         ("name" => name: Option<String>,
292                                          "type" => request_type: Option<String>,
293                                          "since" => since: u32) => {
294
295                Ok(ParseElement::Request {
296                    name: name
297                        .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
298                    request_type,
299                    since,
300                })
301            }),
302            "event" => map_xml_attrs!(attributes,
303                                       ("name" => name: Option<String>,
304                                        "since" => since: u32) => {
305                Ok(ParseElement::Event {
306                    name: name
307                        .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
308                    since,
309                })
310            }),
311            "enum" => map_xml_attrs!(attributes,
312                                      ("name" => name: Option<String>,
313                                       "since" => since: u32,
314                                       "bitfield" => bitfield: bool) => {
315                Ok(ParseElement::Enum {
316                    name: name
317                        .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
318                    since,
319                    bitfield,
320                })
321            }),
322            "entry" => map_xml_attrs!(attributes,
323                                       ("name" => name: Option<String>,
324                                        "value" => value: Option<i64>,
325                                        "since" => since: u32,
326                                        "summary" => summary: Option<String>) => {
327                Ok(ParseElement::EnumEntry {
328                    name: name
329                        .ok_or_else(|| ParseError::new("Missing 'name' attribute".to_owned()))?,
330                    value: value
331                        .ok_or_else(|| ParseError::new("Missing 'value' attribute".to_owned()))?,
332                    since,
333                    summary,
334                })
335            }),
336            "arg" => map_xml_attrs!(attributes,
337                                     ("name" => name: Option<String>,
338                                      "type" => kind: Option<ArgKind>,
339                                      "summary" => summary: Option<String>,
340                                      "interface" => interface: Option<String>,
341                                      "allow-null" => nullable: bool,
342                                      "enum" => enum_type: Option<String>) => {
343
344                Ok(ParseElement::Arg {
345                    name: name.ok_or_else(|| {
346                        ParseError::new("Missing 'name' attributue on argument".to_owned())
347                    })?,
348                    kind: kind.ok_or_else(|| {
349                        ParseError::new("Missing 'type' attributue on argument".to_owned())
350                    })?,
351                    summary,
352                    interface,
353                    nullable,
354                    enum_type,
355                })
356            }),
357            "description" => map_xml_attrs!(attributes,
358                                             ("summary" => summary: Option<String>) => {
359                Ok(ParseElement::Description {
360                    summary: summary.ok_or_else(|| {
361                        ParseError::new("Missing 'summary' attributue on argument".to_owned())
362                    })?,
363                })
364            }),
365            tag => Err(ParseError::new(format!("Tag not implemented {}", tag))),
366        }
367    }
368}
369
370impl<R: Read> Parser<R> {
371    pub fn new(source: R) -> Parser<R> {
372        Parser { xml: EventReader::new(source) }
373    }
374}
375
376impl<'a> Parser<&'a [u8]> {
377    pub fn from_str(protocol: &str) -> Parser<&[u8]> {
378        Parser { xml: EventReader::from_str(protocol) }
379    }
380}