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