spatialos_codegen/ast/
root.rs

1use crate::ast::SchemaFile;
2use crate::{ast::ASTNode, resolver::resolve_types};
3use std::convert::TryFrom;
4use std::ffi::OsStr;
5use std::path::Path;
6use std::path::PathBuf;
7use walkdir::WalkDir;
8
9#[derive(Debug, Eq, PartialEq, Default)]
10pub struct ASTBuilder {
11    directories: Vec<PathBuf>,
12}
13
14#[allow(dead_code)]
15impl ASTBuilder {
16    pub fn build(self) -> AST {
17        self.directories
18            .into_iter()
19            .map(|d| {
20                WalkDir::new(&d)
21                    .follow_links(true)
22                    .into_iter()
23                    .filter_map(|e| e.ok())
24                    .map(|e| {
25                        e.path()
26                            .to_str()
27                            .map(|s| s.to_string())
28                            .ok_or("Can't tranform into &str")
29                    })
30                    .filter_map(Result::ok)
31                    .map(PathBuf::from)
32                    .filter(|p| p.extension() == Some(OsStr::new("schema")))
33                    .map(|p| (SchemaFile::try_from(p.clone()), p))
34                    .map(|(schemas, buf)| match schemas {
35                        Ok(data) => Ok(data),
36                        Err(e) => {
37                            eprintln!("{}: {:?}", e, buf);
38                            Err(())
39                        }
40                    })
41                    .filter_map(Result::ok)
42                    .collect::<Vec<_>>()
43            })
44            .flatten()
45            .fold(AST::default(), |acc, val| {
46                acc.merge_schema(&val, &val.package_name)
47            })
48    }
49
50    pub fn with_directory<P: AsRef<Path>>(mut self, path: P) -> Self {
51        let path = path.as_ref().to_path_buf();
52        self.directories.push(path);
53        self
54    }
55}
56
57#[derive(Debug, Eq, PartialEq, Default)]
58pub struct AST {
59    pub inner: Vec<ASTNode>,
60}
61
62impl AST {
63    pub fn generate<P: AsRef<Path> + Clone, S: AsRef<str>>(self, path: P, module: S) -> Result<(), std::io::Error> {
64        let new_ast = resolve_types(self, module);
65        let path_clone = path.clone();
66        if path_clone.as_ref().exists() {
67            std::fs::remove_dir_all(path)?;
68        }
69        for node in &new_ast.inner {
70            node.generate_node(path_clone.clone())?;
71        }
72        ASTNode::generate_mod_rs(&new_ast.inner, path_clone)
73    }
74
75    fn merge_schema<T: AsRef<str>>(self, schema: &SchemaFile, path: &[T]) -> Self {
76        if !path.is_empty() {
77            let is_path_present = self
78                .inner
79                .iter()
80                .map(|n| match n {
81                    ASTNode::SchemaNode(_) => panic!("SchemaFile shouldn't be at the root of AST"),
82                    ASTNode::PackageNode(pn) => pn.name == *path[0].as_ref(),
83                })
84                .fold(false, |acc, val| acc | val);
85            if is_path_present {
86                AST {
87                    inner: self
88                        .inner
89                        .into_iter()
90                        .map(|n| n.merge_schema(schema, path))
91                        .collect::<Vec<ASTNode>>(),
92                }
93            } else {
94                let mut inner = self.inner;
95                inner.push(ASTNode::package_schema(schema, path));
96                AST { inner }
97            }
98        } else {
99            panic!("SchemaFile does not have a package name");
100        }
101    }
102}