use crate::parser::{self, ArgKind};
#[derive(Debug)]
pub struct Protocol {
pub name: String,
pub copyright: Option<String>,
pub description: Option<Description>,
pub interfaces: Vec<Interface>,
}
#[derive(Debug)]
pub struct Description {
pub summary: String,
pub description: String,
}
#[derive(Debug)]
pub struct Interface {
pub name: String,
pub version: u32,
pub description: Option<Description>,
pub requests: Vec<Message>,
pub events: Vec<Message>,
pub enums: Vec<Enum>,
}
#[derive(Debug)]
pub struct Message {
pub name: String,
pub since: u32,
pub request_type: Option<String>,
pub description: Option<Description>,
pub args: Vec<Arg>,
}
#[derive(Debug)]
pub struct Arg {
pub name: String,
pub kind: ArgKind,
pub summary: Option<String>,
pub interface: Option<String>,
pub nullable: bool,
pub enum_type: Option<String>,
pub description: Option<Description>,
}
#[derive(Debug)]
pub struct Enum {
pub name: String,
pub since: u32,
pub bitfield: bool,
pub description: Option<Description>,
pub entries: Vec<EnumEntry>,
}
#[derive(Debug)]
pub struct EnumEntry {
pub name: String,
pub value: i64,
pub summary: Option<String>,
pub since: u32,
pub description: Option<Description>,
}
pub type AstError = String;
pub type AstResult<T> = Result<T, AstError>;
fn build_protocol(node: parser::ParseNode) -> AstResult<Protocol> {
if let parser::ParseElement::Protocol { name } = node.element {
let mut copyright: Option<String> = None;
let mut description: Option<Description> = None;
let mut interfaces: Vec<Interface> = Vec::new();
for child in node.children {
match &child.element {
parser::ParseElement::Copyright => copyright = Some(build_copyright(child)?),
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
parser::ParseElement::Interface { .. } => interfaces.push(build_interface(child)?),
_ => return Err("Unsupported".to_owned()),
}
}
Ok(Protocol { name: name, copyright, description, interfaces })
} else {
Err("Unexpected Element; expected Protocol".to_owned())
}
}
fn build_copyright(node: parser::ParseNode) -> AstResult<String> {
if let Some(copyright) = node.body {
Ok(copyright)
} else {
Err(format!("Unexpected node {:?}", node))
}
}
fn build_description(node: parser::ParseNode) -> AstResult<Description> {
if let parser::ParseElement::Description { summary } = node.element {
Ok(Description { summary, description: node.body.unwrap_or_else(|| "".to_owned()) })
} else {
Err("Invalid node".to_owned())
}
}
fn build_interface(node: parser::ParseNode) -> AstResult<Interface> {
if let parser::ParseElement::Interface { name, version } = node.element {
let mut description: Option<Description> = None;
let mut requests: Vec<Message> = Vec::new();
let mut events: Vec<Message> = Vec::new();
let mut enums: Vec<Enum> = Vec::new();
for child in node.children {
match &child.element {
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
parser::ParseElement::Request { .. } => requests.push(build_request(child)?),
parser::ParseElement::Event { .. } => events.push(build_event(child)?),
parser::ParseElement::Enum { .. } => enums.push(build_enum(child)?),
_ => return Err("Unsupported".to_owned()),
}
}
Ok(Interface { name, version, description, requests, events, enums })
} else {
Err("Invalid node".to_owned())
}
}
fn build_request(node: parser::ParseNode) -> AstResult<Message> {
if let parser::ParseElement::Request { name, since, request_type } = node.element {
let mut description: Option<Description> = None;
let mut args: Vec<Arg> = Vec::new();
for child in node.children {
match &child.element {
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
parser::ParseElement::Arg { .. } => args.append(&mut build_arg(child)?),
_ => return Err("Unsupported".to_owned()),
}
}
Ok(Message { name, since, request_type, description, args })
} else {
Err("Invalid node".to_owned())
}
}
fn build_event(node: parser::ParseNode) -> AstResult<Message> {
if let parser::ParseElement::Event { name, since } = node.element {
let mut description: Option<Description> = None;
let mut args: Vec<Arg> = Vec::new();
for child in node.children {
match &child.element {
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
parser::ParseElement::Arg { .. } => args.append(&mut build_arg(child)?),
_ => return Err("Unsupported".to_owned()),
}
}
Ok(Message { name, since, description, args, request_type: None })
} else {
Err("Invalid node".to_owned())
}
}
fn build_arg(node: parser::ParseNode) -> AstResult<Vec<Arg>> {
if let parser::ParseElement::Arg { name, kind, summary, interface, nullable, enum_type } =
node.element
{
let mut description: Option<Description> = None;
for child in node.children {
match &child.element {
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
_ => return Err("Unsupported".to_owned()),
}
}
let arg = Arg { name, kind, summary, interface, nullable, enum_type, description };
if arg.kind == ArgKind::NewId && arg.interface.is_none() {
Ok(vec![
Arg {
name: format!("{}_interface_name", arg.name),
kind: ArgKind::String,
summary: None,
interface: None,
nullable: false,
enum_type: None,
description: None,
},
Arg {
name: format!("{}_interface_version", arg.name),
kind: ArgKind::Uint,
summary: None,
interface: None,
nullable: false,
enum_type: None,
description: None,
},
arg,
])
} else {
Ok(vec![arg])
}
} else {
Err("Invalid node".to_owned())
}
}
fn build_enum(node: parser::ParseNode) -> AstResult<Enum> {
if let parser::ParseElement::Enum { name, since, bitfield } = node.element {
let mut description: Option<Description> = None;
let mut entries: Vec<EnumEntry> = Vec::new();
for child in node.children {
match &child.element {
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
parser::ParseElement::EnumEntry { .. } => entries.push(build_enum_entry(child)?),
_ => return Err("Unsupported".to_owned()),
}
}
Ok(Enum { name, since, bitfield, description, entries })
} else {
Err("Invalid node".to_owned())
}
}
fn build_enum_entry(node: parser::ParseNode) -> AstResult<EnumEntry> {
if let parser::ParseElement::EnumEntry { name, value, summary, since } = node.element {
let mut description: Option<Description> = None;
for child in node.children {
match &child.element {
parser::ParseElement::Description { .. } => {
description = Some(build_description(child)?)
}
_ => return Err("Unsupported".to_owned()),
}
}
Ok(EnumEntry { name, value, summary, since, description })
} else {
Err("Invalid node".to_owned())
}
}
impl Protocol {
pub fn from_parse_tree(parse_tree: parser::ParseNode) -> AstResult<Protocol> {
build_protocol(parse_tree)
}
}