protospec_build/semantics/convert/program/
mod.rs

1use super::*;
2
3mod resolve;
4
5mod ffi;
6
7mod import;
8
9mod field;
10
11mod const_;
12
13impl Program {
14    pub fn from_ast<'a, T: ImportResolver + 'static>(
15        ast: &ast::Program,
16        resolver: &'a T,
17    ) -> AsgResult<Program> {
18        let mut cached_imports: IndexMap<String, Program> = IndexMap::new();
19
20        Program::from_ast_imports(ast, resolver, &mut cached_imports)?;
21        Program::from_ast_imported(ast, resolver, &cached_imports)
22    }
23
24    fn from_ast_imported<T: ImportResolver + 'static>(
25        ast: &ast::Program,
26        resolver: &T,
27        import_cache: &IndexMap<String, Program>,
28    ) -> AsgResult<Program> {
29        let program = Arc::new(RefCell::new(Program {
30            types: IndexMap::new(),
31            consts: IndexMap::new(),
32            transforms: IndexMap::new(),
33            functions: IndexMap::new(),
34        }));
35
36        {
37            let mut return_fields = vec![];
38            let scope = Arc::new(RefCell::new(Scope {
39                parent_scope: None,
40                program: program.clone(),
41                declared_fields: IndexMap::new(),
42                declared_inputs: IndexMap::new(),
43            }));
44
45            // import ffis
46            for declaration in ast.declarations.iter() {
47                match declaration {
48                    ast::Declaration::Ffi(ffi) => {
49                        Scope::convert_ffi_declaration(ffi, resolver, &*program)?;
50                    }
51                    _ => (),
52                }
53            }
54
55            // handle file imports
56            for declaration in ast.declarations.iter() {
57                match declaration {
58                    ast::Declaration::Import(import) => {
59                        Scope::convert_import_declaration(import, resolver, &*program, import_cache)?;
60                    }
61                    _ => (),
62                }
63            }
64
65            // consts and enums
66            for declaration in ast.declarations.iter() {
67                match declaration {
68                    ast::Declaration::Type(type_) if matches!(type_.value.type_.raw_type, ast::RawType::Enum(_) | ast::RawType::Bitfield(_)) => {
69                        let field = Scope::convert_type_declaration(type_, &*program)?;
70                        let scope = Scope::convert_ast_field_arguments(&scope, &field, Some(&type_.arguments[..]))?;
71                        Scope::convert_ast_field(&scope, &type_.value, &field)?;
72                    }
73                    ast::Declaration::Const(const_) => {
74                        Scope::convert_const_declaration(const_, &*program, &scope)?;
75                    }
76                    _ => (),
77                }
78            }
79
80            // remaining fields
81            for declaration in ast.declarations.iter() {
82                match declaration {
83                    ast::Declaration::Type(type_) if !matches!(type_.value.type_.raw_type, ast::RawType::Enum(_) | ast::RawType::Bitfield(_)) => {
84                        let field = Scope::convert_type_declaration(type_, &*program)?;
85                        return_fields.push((type_, field));
86                    }
87                    _ => (),
88                }
89            }
90
91            // convert arguments
92            let mut sub_scopes = vec![];
93            for (type_, field) in &return_fields {
94                sub_scopes.push(Scope::convert_ast_field_arguments(&scope, &field, Some(&type_.arguments[..]))?);
95            }
96
97            // convert rest
98            for ((type_, field), sub_scope) in return_fields.into_iter().zip(sub_scopes.iter()) {
99                Scope::convert_ast_field(sub_scope, &type_.value, &field)?;
100            }
101        }
102
103        let program = Arc::try_unwrap(program)
104            .ok()
105            .expect("leaked program arc")
106            .into_inner();
107
108        program.scan_cycles();
109        Ok(program)
110    }
111}