wayland_scanner_lib/
ast.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 crate::parser::{self, ArgKind};
6
7#[derive(Debug)]
8pub struct Protocol {
9    pub name: String,
10    pub copyright: Option<String>,
11    pub description: Option<Description>,
12    pub interfaces: Vec<Interface>,
13}
14
15#[derive(Debug)]
16pub struct Description {
17    pub summary: String,
18    pub description: String,
19}
20
21#[derive(Debug)]
22pub struct Interface {
23    pub name: String,
24    pub version: u32,
25    pub description: Option<Description>,
26    pub requests: Vec<Message>,
27    pub events: Vec<Message>,
28    pub enums: Vec<Enum>,
29}
30
31#[derive(Debug)]
32pub struct Message {
33    pub name: String,
34    pub since: u32,
35    pub request_type: Option<String>,
36    pub description: Option<Description>,
37    pub args: Vec<Arg>,
38}
39
40#[derive(Debug)]
41pub struct Arg {
42    pub name: String,
43    pub kind: ArgKind,
44    pub summary: Option<String>,
45    pub interface: Option<String>,
46    pub nullable: bool,
47    pub enum_type: Option<String>,
48    pub description: Option<Description>,
49}
50
51#[derive(Debug)]
52pub struct Enum {
53    pub name: String,
54    pub since: u32,
55    pub bitfield: bool,
56    pub description: Option<Description>,
57    pub entries: Vec<EnumEntry>,
58}
59
60#[derive(Debug)]
61pub struct EnumEntry {
62    pub name: String,
63    pub value: i64,
64    pub summary: Option<String>,
65    pub since: u32,
66    pub description: Option<Description>,
67}
68
69pub type AstError = String;
70pub type AstResult<T> = Result<T, AstError>;
71
72fn build_protocol(node: parser::ParseNode) -> AstResult<Protocol> {
73    if let parser::ParseElement::Protocol { name } = node.element {
74        let mut copyright: Option<String> = None;
75        let mut description: Option<Description> = None;
76        let mut interfaces: Vec<Interface> = Vec::new();
77        for child in node.children {
78            match &child.element {
79                parser::ParseElement::Copyright => copyright = Some(build_copyright(child)?),
80                parser::ParseElement::Description { .. } => {
81                    description = Some(build_description(child)?)
82                }
83                parser::ParseElement::Interface { .. } => interfaces.push(build_interface(child)?),
84                _ => return Err("Unsupported".to_owned()),
85            }
86        }
87        Ok(Protocol { name: name, copyright, description, interfaces })
88    } else {
89        Err("Unexpected Element; expected Protocol".to_owned())
90    }
91}
92
93fn build_copyright(node: parser::ParseNode) -> AstResult<String> {
94    if let Some(copyright) = node.body {
95        Ok(copyright)
96    } else {
97        Err(format!("Unexpected node {:?}", node))
98    }
99}
100
101fn build_description(node: parser::ParseNode) -> AstResult<Description> {
102    if let parser::ParseElement::Description { summary } = node.element {
103        Ok(Description { summary, description: node.body.unwrap_or_else(|| "".to_owned()) })
104    } else {
105        Err("Invalid node".to_owned())
106    }
107}
108
109fn build_interface(node: parser::ParseNode) -> AstResult<Interface> {
110    if let parser::ParseElement::Interface { name, version } = node.element {
111        let mut description: Option<Description> = None;
112        let mut requests: Vec<Message> = Vec::new();
113        let mut events: Vec<Message> = Vec::new();
114        let mut enums: Vec<Enum> = Vec::new();
115        for child in node.children {
116            match &child.element {
117                parser::ParseElement::Description { .. } => {
118                    description = Some(build_description(child)?)
119                }
120                parser::ParseElement::Request { .. } => requests.push(build_request(child)?),
121                parser::ParseElement::Event { .. } => events.push(build_event(child)?),
122                parser::ParseElement::Enum { .. } => enums.push(build_enum(child)?),
123                _ => return Err("Unsupported".to_owned()),
124            }
125        }
126        Ok(Interface { name, version, description, requests, events, enums })
127    } else {
128        Err("Invalid node".to_owned())
129    }
130}
131
132fn build_request(node: parser::ParseNode) -> AstResult<Message> {
133    if let parser::ParseElement::Request { name, since, request_type } = node.element {
134        let mut description: Option<Description> = None;
135        let mut args: Vec<Arg> = Vec::new();
136        for child in node.children {
137            match &child.element {
138                parser::ParseElement::Description { .. } => {
139                    description = Some(build_description(child)?)
140                }
141                parser::ParseElement::Arg { .. } => args.append(&mut build_arg(child)?),
142                _ => return Err("Unsupported".to_owned()),
143            }
144        }
145        Ok(Message { name, since, request_type, description, args })
146    } else {
147        Err("Invalid node".to_owned())
148    }
149}
150
151fn build_event(node: parser::ParseNode) -> AstResult<Message> {
152    if let parser::ParseElement::Event { name, since } = node.element {
153        let mut description: Option<Description> = None;
154        let mut args: Vec<Arg> = Vec::new();
155        for child in node.children {
156            match &child.element {
157                parser::ParseElement::Description { .. } => {
158                    description = Some(build_description(child)?)
159                }
160                parser::ParseElement::Arg { .. } => args.append(&mut build_arg(child)?),
161                _ => return Err("Unsupported".to_owned()),
162            }
163        }
164        Ok(Message { name, since, description, args, request_type: None })
165    } else {
166        Err("Invalid node".to_owned())
167    }
168}
169
170fn build_arg(node: parser::ParseNode) -> AstResult<Vec<Arg>> {
171    if let parser::ParseElement::Arg { name, kind, summary, interface, nullable, enum_type } =
172        node.element
173    {
174        let mut description: Option<Description> = None;
175        for child in node.children {
176            match &child.element {
177                parser::ParseElement::Description { .. } => {
178                    description = Some(build_description(child)?)
179                }
180                _ => return Err("Unsupported".to_owned()),
181            }
182        }
183        let arg = Arg { name, kind, summary, interface, nullable, enum_type, description };
184        // wayland has a slightly different serialization of untyped new_id
185        // arguments. Instead of just sending the object id, the interface name
186        // and version are sent first. This primarily impacts the
187        // wl_registry::bind request.
188        if arg.kind == ArgKind::NewId && arg.interface.is_none() {
189            Ok(vec![
190                Arg {
191                    name: format!("{}_interface_name", arg.name),
192                    kind: ArgKind::String,
193                    summary: None,
194                    interface: None,
195                    nullable: false,
196                    enum_type: None,
197                    description: None,
198                },
199                Arg {
200                    name: format!("{}_interface_version", arg.name),
201                    kind: ArgKind::Uint,
202                    summary: None,
203                    interface: None,
204                    nullable: false,
205                    enum_type: None,
206                    description: None,
207                },
208                arg,
209            ])
210        } else {
211            Ok(vec![arg])
212        }
213    } else {
214        Err("Invalid node".to_owned())
215    }
216}
217
218fn build_enum(node: parser::ParseNode) -> AstResult<Enum> {
219    if let parser::ParseElement::Enum { name, since, bitfield } = node.element {
220        let mut description: Option<Description> = None;
221        let mut entries: Vec<EnumEntry> = Vec::new();
222        for child in node.children {
223            match &child.element {
224                parser::ParseElement::Description { .. } => {
225                    description = Some(build_description(child)?)
226                }
227                parser::ParseElement::EnumEntry { .. } => entries.push(build_enum_entry(child)?),
228                _ => return Err("Unsupported".to_owned()),
229            }
230        }
231        Ok(Enum { name, since, bitfield, description, entries })
232    } else {
233        Err("Invalid node".to_owned())
234    }
235}
236
237fn build_enum_entry(node: parser::ParseNode) -> AstResult<EnumEntry> {
238    if let parser::ParseElement::EnumEntry { name, value, summary, since } = node.element {
239        let mut description: Option<Description> = None;
240        for child in node.children {
241            match &child.element {
242                parser::ParseElement::Description { .. } => {
243                    description = Some(build_description(child)?)
244                }
245                _ => return Err("Unsupported".to_owned()),
246            }
247        }
248        Ok(EnumEntry { name, value, summary, since, description })
249    } else {
250        Err("Invalid node".to_owned())
251    }
252}
253
254impl Protocol {
255    pub fn from_parse_tree(parse_tree: parser::ParseNode) -> AstResult<Protocol> {
256        build_protocol(parse_tree)
257    }
258}