asn1_compiler/
compiler.rs

1#![allow(dead_code)]
2//! Structs related to ASN.1 Compiler
3
4use std::collections::HashMap;
5use std::fs::File;
6use std::io;
7use std::io::Write;
8use std::path::Path;
9use std::process::{Command, Stdio};
10
11use topological_sort::TopologicalSort;
12
13use crate::error::Error;
14use anyhow::Result;
15
16use crate::parser::asn::structs::module::Asn1Module;
17
18use crate::generator::{Codec, Derive, Generator, Visibility};
19use crate::resolver::Resolver;
20use crate::tokenizer::Token;
21
22/// ASN.1 Compiler Struct.
23///
24/// An application should create a Compiler Structure and will call Public API functions on the
25/// compiler.
26#[derive(Debug)]
27pub struct Asn1Compiler {
28    // Modules belonging to this 'invocation' of compiler. Modules are maintined inside a `RefCell`
29    // because we need Interior Mutability with the modules (for example to 'resolve' definitions
30    // within the modules.
31    modules: HashMap<String, Asn1Module>,
32
33    // Holds the 'Resolver' that is used for 'resolv'ing definitions.
34    resolver: Resolver,
35
36    // Holds the 'Generator' that is used for 'generate'ing the code for the 'resolved types'.
37    generator: Generator,
38
39    // Holds the file name for the output module.
40    output_filename: String,
41}
42
43impl Default for Asn1Compiler {
44    fn default() -> Self {
45        Asn1Compiler::new("default.rs", &Visibility::Public, vec![Codec::Aper], vec![])
46    }
47}
48
49impl Asn1Compiler {
50    /// Create a new Instance of the Compiler structure.
51    pub fn new(
52        output: &str,
53        visibility: &Visibility,
54        codecs: Vec<Codec>,
55        derives: Vec<Derive>,
56    ) -> Self {
57        Asn1Compiler {
58            modules: HashMap::new(),
59            resolver: Resolver::new(),
60            generator: Generator::new(visibility, codecs, derives), // FIXME: Hard coded
61            output_filename: output.to_string(),
62        }
63    }
64
65    /// Add a module to the list of known modules.
66    ///
67    /// If the module alredy exists, returns `false` else returns `true`.
68    pub fn add_module(&mut self, module: Asn1Module) -> bool {
69        log::debug!("Adding module: {}", module.get_module_name());
70        self.modules
71            .insert(module.get_module_name(), module)
72            .is_some()
73    }
74
75    /// Resolve Modules order and definitions within those modules.
76    ///
77    /// First Makes sure that all the modules that have IMPORTs are indeed added to us. Then
78    /// definitions in each of the modules are 'resolved'. Calls the `Resolver` functions to do
79    /// that. Modules are Topologically Sorted before they are resolved and definitions within
80    /// modules are topologically sorted as well. This makes Error handling for undefined
81    /// definitions much easier.
82    // FIXME: Support the case where module is imported by a name different from it's actual name.
83    pub fn resolve_modules(&mut self) -> Result<()> {
84        log::info!("Resolving imports from all modules.");
85        self.resolve_imports()?;
86
87        log::info!("Resolving definitions from all modules.");
88        self.resolve_definitions()
89    }
90
91    /// Generate the code
92    pub fn generate(&mut self) -> Result<()> {
93        log::info!("Generating code, writing to file: {}", self.output_filename);
94
95        let input_text = self.generator.generate(&self.resolver)?;
96        let output_text = self.rustfmt_generated_code(&input_text)?;
97
98        let mut output_file = File::create(&self.output_filename).map_err(|e| {
99            let errorstr = format!("Error {} Creating File: {}", e, self.output_filename);
100            Error::CodeGenerationError(errorstr)
101        })?;
102
103        output_file
104            .write_all(output_text.as_bytes())
105            .map_err(|e| Error::CodeGenerationError(e.to_string()))?;
106
107        eprintln!("\n\nWrote generated code to '{}'.", self.output_filename);
108
109        Ok(())
110    }
111
112    /// Compilation Driver for a String as module(s).
113    pub fn compile_string(&mut self, modules_string: &str, parse_only: bool) -> Result<()> {
114        let mut tokens = crate::tokenizer::tokenize_string(modules_string)?;
115        self.parse_tokens_into_modules(&mut tokens)?;
116        if !parse_only {
117            self.resolve_modules()?;
118            self.generate()
119        } else {
120            Ok(())
121        }
122    }
123
124    /// The Actual compilation driver
125    pub fn compile_files<T: AsRef<Path> + std::fmt::Debug>(&mut self, files: &[T]) -> Result<()> {
126        for file in files {
127            log::info!("Processing file: {:?}", file);
128            let file = File::open(file).map_err(|e| io_error!("{:#?}", e))?;
129            let mut tokens = crate::tokenizer::tokenize(file)?;
130            self.parse_tokens_into_modules(&mut tokens)?;
131        }
132        self.resolve_modules()?;
133
134        self.generate()
135    }
136
137    fn parse_tokens_into_modules(&mut self, tokens: &mut Vec<Token>) -> Result<()> {
138        log::debug!("Parsing {} tokens.", tokens.len());
139        let mut modules = crate::parser::parse(tokens)?;
140        loop {
141            let module = modules.pop();
142            if module.is_none() {
143                break;
144            }
145            let module = module.unwrap();
146            log::debug!("Adding module : {}", module.get_module_name());
147            self.add_module(module);
148        }
149        Ok(())
150    }
151
152    fn rustfmt_generated_code(&self, code: &str) -> Result<String> {
153        log::debug!("Runing `rustfmt` on the generated code.");
154        let rustfmt_binary = "rustfmt"; // TODO: Get from `env` , 'custom path' etc.
155        let mut cmd = Command::new(rustfmt_binary);
156
157        cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
158
159        let mut child = cmd.spawn().map_err(|e| resolve_error!("{:#?}", e))?;
160        let mut child_stdin = child.stdin.take().unwrap();
161        let mut child_stdout = child.stdout.take().unwrap();
162
163        let code = code.to_owned();
164        let stdin_handle =
165            ::std::thread::spawn(move || match child_stdin.write_all(code.as_bytes()) {
166                Ok(_) => code,
167                Err(_) => "write error in rustfmt".to_owned(),
168            });
169
170        let mut output = vec![];
171        io::copy(&mut child_stdout, &mut output).map_err(|e| resolve_error!("{:#?}", e))?;
172
173        let status = child.wait().map_err(|e| resolve_error!("{:#?}", e))?;
174
175        match String::from_utf8(output) {
176            Ok(formatted_output) => match status.code() {
177                Some(0) => Ok(formatted_output),
178                _ => Err(resolve_error!("`rustfmt` failed to write some bindings.").into()),
179            },
180            _ => Ok(stdin_handle.join().unwrap()),
181        }
182    }
183
184    fn resolve_imports(&self) -> Result<()> {
185        log::debug!("Resolving imports.");
186        for (_, module) in self.modules.iter() {
187            for (import, module_name) in module.get_imported_defs() {
188                let target = self.modules.get(module_name.name_as_str());
189                if target.is_none() {
190                    return Err(resolve_error!(
191                        "Module '{}', corresponding to definition '{}' not found!",
192                        module_name.name_as_str(),
193                        import
194                    )
195                    .into());
196                }
197            }
198        }
199
200        log::debug!("All IMPORTS in All Modules Resolved!");
201        Ok(())
202    }
203
204    fn sorted_modules(&self) -> Vec<String> {
205        log::trace!("Topologically sorting modules.");
206        let mut ts = TopologicalSort::<String>::new();
207
208        for module in self.modules.values() {
209            let imports = module.get_imported_defs();
210            for (_, m) in imports {
211                ts.add_dependency(m.name(), module.get_module_name())
212            }
213            ts.insert(module.get_module_name());
214        }
215
216        let mut out_vec = vec![];
217        loop {
218            let popped = ts.pop_all();
219            if popped.is_empty() {
220                break;
221            } else {
222                out_vec.extend(popped);
223            }
224        }
225        out_vec
226    }
227
228    fn resolve_definitions(&mut self) -> Result<()> {
229        let module_names = self.sorted_modules();
230        for name in module_names {
231            let module = self.modules.get_mut(&name).unwrap();
232
233            //let module_definitions = module.definitions_sorted();
234            self.resolver.resolve_definitions(module)?;
235        }
236        log::trace!(
237            "Resolved Definitions: {:#?}",
238            self.resolver.resolved_defs.keys()
239        );
240        log::trace!(
241            "Parameterized Types: {:#?}",
242            self.resolver.parameterized_defs.keys()
243        );
244        log::trace!("Object Classes: {:#?}", self.resolver.classes.keys());
245
246        Ok(())
247    }
248}