1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use nom::branch::alt;
use nom::combinator::{map, opt};
use nom::multi::many0;
use nom::sequence::delimited;
use nom::IResult;

use crate::basic::Separator;
use crate::definition::{
    Const, ConstRef, Enum, EnumRef, Exception, ExceptionRef, Service, ServiceRef, Struct,
    StructRef, Typedef, TypedefRef, Union, UnionRef,
};
use crate::header::{CppInclude, CppIncludeRef, Include, IncludeRef, Namespace, NamespaceRef};
use crate::Parser;

#[derive(PartialEq, Debug, Clone, Default)]
pub struct DocumentRef<'a> {
    pub includes: Vec<IncludeRef<'a>>,
    pub cpp_includes: Vec<CppIncludeRef<'a>>,
    pub namespaces: Vec<NamespaceRef<'a>>,
    pub typedefs: Vec<TypedefRef<'a>>,
    pub consts: Vec<ConstRef<'a>>,
    pub enums: Vec<EnumRef<'a>>,
    pub structs: Vec<StructRef<'a>>,
    pub unions: Vec<UnionRef<'a>>,
    pub exceptions: Vec<ExceptionRef<'a>>,
    pub services: Vec<ServiceRef<'a>>,
}

impl<'a> Parser<'a> for DocumentRef<'a> {
    fn parse(input: &'a str) -> IResult<&'a str, Self> {
        let mut target = Self::default();
        let includes = &mut target.includes;
        let cpp_includes = &mut target.cpp_includes;
        let namespaces = &mut target.namespaces;
        let typedefs = &mut target.typedefs;
        let consts = &mut target.consts;
        let enums = &mut target.enums;
        let structs = &mut target.structs;
        let unions = &mut target.unions;
        let exceptions = &mut target.exceptions;
        let services = &mut target.services;

        let (remains, _) = many0(delimited(
            opt(Separator::parse),
            alt((
                map(IncludeRef::parse, |i| includes.push(i)),
                map(CppIncludeRef::parse, |i| cpp_includes.push(i)),
                map(NamespaceRef::parse, |i| namespaces.push(i)),
                map(TypedefRef::parse, |i| typedefs.push(i)),
                map(ConstRef::parse, |i| consts.push(i)),
                map(EnumRef::parse, |i| enums.push(i)),
                map(StructRef::parse, |i| structs.push(i)),
                map(UnionRef::parse, |i| unions.push(i)),
                map(ExceptionRef::parse, |i| exceptions.push(i)),
                map(ServiceRef::parse, |i| services.push(i)),
            )),
            opt(Separator::parse),
        ))(input)?;
        Ok((remains, target))
    }
}

#[derive(PartialEq, Debug, Clone, Default)]
pub struct Document {
    pub includes: Vec<Include>,
    pub cpp_includes: Vec<CppInclude>,
    pub namespaces: Vec<Namespace>,
    pub typedefs: Vec<Typedef>,
    pub consts: Vec<Const>,
    pub enums: Vec<Enum>,
    pub structs: Vec<Struct>,
    pub unions: Vec<Union>,
    pub exceptions: Vec<Exception>,
    pub services: Vec<Service>,
}

impl<'a> From<DocumentRef<'a>> for Document {
    fn from(r: DocumentRef<'a>) -> Self {
        Self {
            includes: r.includes.into_iter().map(Into::into).collect(),
            cpp_includes: r.cpp_includes.into_iter().map(Into::into).collect(),
            namespaces: r.namespaces.into_iter().map(Into::into).collect(),
            typedefs: r.typedefs.into_iter().map(Into::into).collect(),
            consts: r.consts.into_iter().map(Into::into).collect(),
            enums: r.enums.into_iter().map(Into::into).collect(),
            structs: r.structs.into_iter().map(Into::into).collect(),
            unions: r.unions.into_iter().map(Into::into).collect(),
            exceptions: r.exceptions.into_iter().map(Into::into).collect(),
            services: r.services.into_iter().map(Into::into).collect(),
        }
    }
}

impl<'a> Parser<'a> for Document {
    fn parse(input: &'a str) -> IResult<&'a str, Self> {
        DocumentRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
    }
}

#[cfg(test)]
mod tests {
    use crate::basic::LiteralRef;

    use super::*;

    #[test]
    fn test_document() {
        let expected = DocumentRef {
            includes: vec![IncludeRef::from(LiteralRef::from("another.thrift"))],
            ..Default::default()
        };
        assert_eq!(
            DocumentRef::parse("include 'another.thrift'").unwrap().1,
            expected
        );
    }
}