Skip to main content

fastxdr/ast/
mod.rs

1mod basic_type;
2pub use basic_type::*;
3
4mod structure;
5pub use structure::*;
6
7mod union;
8pub use union::*;
9
10mod enumeration;
11pub use enumeration::*;
12
13mod node;
14use node::*;
15
16mod array;
17pub use array::*;
18
19mod typedef;
20pub use typedef::*;
21
22pub mod indexes;
23use indexes::*;
24
25pub trait CompoundType {
26    fn inner_types(&self) -> Vec<&ArrayType<BasicType>>;
27    fn contains_opaque(&self) -> bool;
28}
29
30use crate::Result;
31use pest::iterators::Pair;
32use pest::Parser;
33use pest_derive::Parser;
34use std::convert::TryFrom;
35
36#[derive(Parser)]
37#[grammar = "xdr.pest"]
38pub(crate) struct XDRParser;
39
40#[derive(Debug)]
41pub struct Ast {
42    constant_index: ConstantIndex,
43    generic_index: GenericIndex,
44    type_index: TypeIndex,
45}
46
47/// The `Ast` type provides high-level access to elements of the AST read from
48/// an XDR spec.
49impl Ast {
50    pub fn new(xdr: &str) -> Result<Self> {
51        // Tokenise the input
52        let mut root = XDRParser::parse(Rule::item, xdr)?;
53        // Parse into an AST
54        let ast = walk(root.next().ok_or("unable to tokenise input")?);
55
56        // Build some helpful indexes to answer questions about types when
57        // generating the Rust code.
58        let constant_index = ConstantIndex::new(&ast);
59        let generic_index = GenericIndex::new(&ast);
60        let type_index = TypeIndex::new(&ast);
61
62        Ok(Ast {
63            constant_index,
64            generic_index,
65            type_index,
66        })
67    }
68
69    pub fn constants(&self) -> &ConstantIndex {
70        &self.constant_index
71    }
72
73    pub fn generics(&self) -> &GenericIndex {
74        &self.generic_index
75    }
76
77    pub fn types(&self) -> &TypeIndex {
78        &self.type_index
79    }
80}
81
82// Recurse into the tokens from the PEG parser, constructing a syntax tree and
83// initialising higher-level representations of the compound types from them.
84//
85// These higher-level types will then be extracted and added to the type index
86// later.
87fn walk(ast: Pair<'_, Rule>) -> Node<'_> {
88    fn collect_values(ast: Pair<'_, Rule>) -> Vec<Node<'_>> {
89        ast.into_inner().map(walk).collect()
90    }
91
92    match ast.as_rule() {
93        Rule::item => Node::Root(collect_values(ast)),
94        Rule::typedef => Node::Typedef(Typedef::new(collect_values(ast))),
95        Rule::constant => Node::Constant(collect_values(ast)),
96        Rule::ident | Rule::ident_const | Rule::ident_value => {
97            if let Ok(t) = BasicType::try_from(ast.as_str()) {
98                Node::Type(t)
99            } else {
100                Node::Ident(ast.as_str())
101            }
102        }
103        Rule::enum_type => Node::Enum(Enum::new(collect_values(ast))),
104        Rule::enum_variant => Node::EnumVariant(collect_values(ast)),
105        Rule::array => Node::Array(collect_values(ast)),
106        Rule::array_variable => Node::ArrayVariable(ast.into_inner().as_str()),
107        Rule::array_fixed => Node::ArrayFixed(ast.into_inner().as_str()),
108        Rule::struct_type => Node::Struct(Struct::new(collect_values(ast))),
109        Rule::struct_data_field => Node::StructDataField(collect_values(ast)),
110        Rule::union_data_field => Node::UnionDataField(collect_values(ast)),
111        Rule::union => Node::Union(Union::new(collect_values(ast))),
112        Rule::union_case => Node::UnionCase(collect_values(ast)),
113        Rule::union_default => Node::UnionDefault(collect_values(ast)),
114        Rule::union_void => Node::UnionVoid,
115        Rule::option => Node::Option(collect_values(ast)),
116        Rule::basic_type => {
117            Node::Type(BasicType::try_from(ast.as_str()).expect("unrecognised type"))
118        }
119        Rule::EOI => Node::EOF,
120        e => unimplemented!("unknown token type {:?}", e),
121    }
122}