asn1-compiler 0.1.2

ASN.1 Compiler in Rust.
#![allow(dead_code)]
//! Structs related to ASN.1 Compiler
use std::collections::HashMap;

use ::rustfmt::{config::Config, format_input, Input};
use topological_sort::TopologicalSort;

use crate::error::Error;

use crate::parser::asn::structs::module::Asn1Module;

use crate::generator::Generator;
use crate::resolver::Resolver;

/// ASN.1 Compiler Struct.
///
/// An application should create a Compiler Structure and will call Public API functions on the
/// compiler.
#[derive(Debug)]
pub struct Asn1Compiler {
    // Modules belonging to this 'invocation' of compiler. Modules are maintined inside a `RefCell`
    // because we need Interior Mutability with the modules (for example to 'resolve' definitions
    // within the modules.
    modules: HashMap<String, Asn1Module>,

    // Holds the 'Resolver' that is used for 'resolv'ing definitions.
    resolver: Resolver,

    // Holds the 'Generator' that is used for 'generate'ing the code for the 'resolved types'.
    generator: Generator,
}

impl Asn1Compiler {
    /// Create a new Instance of the Compiler structure.
    pub fn new() -> Self {
        Asn1Compiler {
            modules: HashMap::new(),
            resolver: Resolver::new(),
            generator: Generator::new("ngap"), // FIXME: Hard coded
        }
    }

    /// Add a module to the list of known modules.
    ///
    /// If the module alredy exists, returns `false` else returns `true`.
    pub fn add_module(&mut self, module: Asn1Module) -> bool {
        let old = self.modules.insert(module.get_module_name(), module);
        !old.is_none()
    }

    /// Resolve Modules order and definitions within those modules.
    ///
    /// First Makes sure that all the modules that have IMPORTs are indeed added to us. Then
    /// definitions in each of the modules are 'resolved'. Calls the `Resolver` functions to do
    /// that. Modules are Topologically Sorted before they are resolved and definitions within
    /// modules are topologically sorted as well. This makes Error handling for undefined
    /// definitions much easier.
    // FIXME: Support the case where module is imported by a name different from it's actual name.
    pub fn resolve_modules(&mut self) -> Result<(), Error> {
        self.resolve_imports()?;
        self.resolve_definitions()
    }

    /// Generate the code
    pub fn generate(&mut self) -> Result<(), Error> {
        // eprintln!("{}", &mut self.generator.generate(&self.resolver)?);

        let input_text = self.generator.generate(&self.resolver)?;
        let input = Input::Text(input_text);

        let (summary, filemap, _) =
            format_input(input, &Config::default(), Some(&mut std::io::stdout()))
                .map_err(|e| resolve_error!("{:#?}", e.1))?;

        eprintln!("Summary: {:#?}", summary);
        println!("{}", filemap[0].1);

        Ok(())
    }

    fn resolve_imports(&self) -> Result<(), Error> {
        for (_, module) in self.modules.iter() {
            for (import, module_name) in module.get_imported_defs() {
                let target = self.modules.get(module_name.name_as_str());
                if target.is_none() {
                    return Err(resolve_error!(
                        "Module '{}', corresponding to definition '{}' not found!",
                        module_name.name_as_str(),
                        import
                    ));
                }
            }
        }
        eprintln!("All IMPORTS in All Modules Resolved!");
        Ok(())
    }

    fn sorted_modules(&self) -> Vec<String> {
        let mut ts = TopologicalSort::<String>::new();

        for module in self.modules.values() {
            let imports = module.get_imported_defs();
            for (_, m) in imports {
                ts.add_dependency(m.name(), module.get_module_name())
            }
            ts.insert(module.get_module_name());
        }

        let mut out_vec = vec![];
        loop {
            let popped = ts.pop_all();
            if popped.is_empty() {
                break;
            } else {
                out_vec.extend(popped);
            }
        }
        out_vec
    }

    fn resolve_definitions(&mut self) -> Result<(), Error> {
        let module_names = self.sorted_modules();
        for name in module_names {
            let mut module = self.modules.get_mut(&name).unwrap();

            //let module_definitions = module.definitions_sorted();
            self.resolver.resolve_definitions(&mut module)?;
        }
        eprintln!(
            "Resolved Definitions: {:#?}",
            self.resolver.resolved_defs.keys()
        );
        eprintln!(
            "Parameterized Types: {:#?}",
            self.resolver.parameterized_defs.keys()
        );
        eprintln!("Object Classes: {:#?}", self.resolver.classes.keys());

        Ok(())
    }
}