circom-lsp-program-structure 2.1.5

Support crate for circom-lsp
Documentation
use super::ast::Definition;
use super::error_code::ReportCode;
use super::error_definition::Report;
use super::file_definition::FileID;
use super::function_data::{FunctionData, FunctionInfo};
use super::template_data::{TemplateData, TemplateInfo};

pub struct Merger {
    fresh_id: usize,
    function_info: FunctionInfo,
    template_info: TemplateInfo,
}
impl Default for Merger {
    fn default() -> Self {
        Merger {
            fresh_id: 0,
            function_info: FunctionInfo::new(),
            template_info: TemplateInfo::new(),
        }
    }
}

impl Merger {
    pub fn new() -> Merger {
        Merger::default()
    }

    pub fn add_definitions(&mut self, file_id: FileID, definitions: Vec<Definition>)  -> Result<(), Vec<Report>> {
        let mut reports = vec![];
        for definition in definitions {
            let (name, meta) = match definition {
                Definition::Template { name, args, arg_location, body, meta, parallel, is_custom_gate } => {
                    if self.contains_function(&name) || self.contains_template(&name) {
                        (Option::Some(name), meta)
                    } else {
                        let new_data = TemplateData::new(
                            name.clone(),
                            file_id,
                            body,
                            args.len(),
                            args,
                            arg_location,
                            &mut self.fresh_id,
                            parallel,
                            is_custom_gate,
                        );
                        self.get_mut_template_info().insert(name.clone(), new_data);
                        (Option::None, meta)
                    }
                }
                Definition::Function { name, body, args, arg_location, meta } => {
                    if self.contains_function(&name) || self.contains_template(&name) {
                        (Option::Some(name), meta)
                    } else {
                        let new_data = FunctionData::new(
                            name.clone(),
                            file_id,
                            body,
                            args.len(),
                            args,
                            arg_location,
                            &mut self.fresh_id,
                        );
                        self.get_mut_function_info().insert(name.clone(), new_data);
                        (Option::None, meta)
                    }
                }
            };
            if let Option::Some(definition_name) = name {
                let mut report = Report::error(
                    String::from("Duplicated callable symbol"),
                    ReportCode::SameSymbolDeclaredTwice,
                );
                report.add_primary(
                    meta.file_location(),
                    file_id,
                    format!("{} is already in use", definition_name),
                );
                reports.push(report);
            }
        }
        if reports.is_empty() { Ok(()) } else { Err(reports) }
    }
    pub fn contains_function(&self, function_name: &str) -> bool {
        self.get_function_info().contains_key(function_name)
    }
    fn get_function_info(&self) -> &FunctionInfo {
        &self.function_info
    }
    fn get_mut_function_info(&mut self) -> &mut FunctionInfo {
        &mut self.function_info
    }

    pub fn contains_template(&self, template_name: &str) -> bool {
        self.get_template_info().contains_key(template_name)
    }
    fn get_template_info(&self) -> &TemplateInfo {
        &self.template_info
    }
    fn get_mut_template_info(&mut self) -> &mut TemplateInfo {
        &mut self.template_info
    }


    pub fn decompose(self) -> (usize, FunctionInfo, TemplateInfo) {
        (self.fresh_id, self.function_info, self.template_info)
    }
}