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
pub use golang_type_core;

use std::str::FromStr;

use golang_parser::{Parser, NODE_KIND_COMMENT};

pub mod alias_decl;
pub mod type_def;

pub use self::alias_decl::{AliasDecl, AliasDeclParseError};
pub use self::type_def::{TypeDef, TypeDefParseError};

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct TypeDecl {
    pub type_specs: Vec<TypeSpec>,
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub enum TypeSpec {
    AliasDecl(AliasDecl),
    TypeDef(TypeDef),
}

#[derive(thiserror::Error, Debug)]
pub enum TypeDeclParseError {
    #[error("GolangParserError {0:?}")]
    GolangParserError(#[from] golang_parser::Error),
    #[error("NodeKindUnknown {0}")]
    NodeKindUnknown(String),
    //
    #[error("AliasDeclParseError {0:?}")]
    AliasDeclParseError(#[from] AliasDeclParseError),
    #[error("TypeDefParseError {0:?}")]
    TypeDefParseError(#[from] TypeDefParseError),
}

impl FromStr for TypeDecl {
    type Err = TypeDeclParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parser = Parser::new(s)?;
        let source = parser.get_source();
        let root_node = parser.get_root_node();

        let mut type_specs = vec![];

        let mut cursor = root_node.walk();
        let mut node_source_file_named_children_iter = root_node
            .named_children(&mut cursor)
            .filter(|x| x.kind() != NODE_KIND_COMMENT);

        if let Some(node_type_declaration) = node_source_file_named_children_iter.next() {
            for node in node_type_declaration
                .named_children(&mut node_type_declaration.walk())
                .filter(|x| x.kind() != NODE_KIND_COMMENT)
            {
                match node.kind() {
                    "type_alias" => {
                        let type_spec =
                            TypeSpec::AliasDecl(AliasDecl::from_type_alias_node(node, source)?);
                        type_specs.push(type_spec);
                    }
                    "type_spec" => {
                        let type_spec =
                            TypeSpec::TypeDef(TypeDef::from_type_spec_node(node, source)?);
                        type_specs.push(type_spec);
                    }
                    _ => return Err(TypeDeclParseError::NodeKindUnknown(node.kind().to_owned())),
                }
            }
        }

        if let Some(node) = node_source_file_named_children_iter.next() {
            return Err(TypeDeclParseError::NodeKindUnknown(node.kind().to_owned()));
        }

        Ok(Self { type_specs })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_empty() {
        match "type ()".parse::<TypeDecl>() {
            Ok(type_decl) => assert_eq!(type_decl.type_specs.len(), 0),
            Err(err) => assert!(false, "{:?}", err),
        }
    }

    #[test]
    fn test_parse_only_comment() {
        match r#"
        type (
        //
        )
        "#
        .trim_start()
        .trim_end()
        .parse::<TypeDecl>()
        {
            Ok(type_decl) => assert_eq!(type_decl.type_specs.len(), 0),
            Err(err) => assert!(false, "{:?}", err),
        }
    }
}