<commit_before>use crate::language::Language;
use crate::ql;
use std::collections::{BTreeSet, HashMap};
use std::fs::File;
use std::io::LineWriter;

type SupertypeMap = HashMap<String, BTreeSet<String>>;

/// Writes the QL AST library for the given library.
///
/// # Arguments
///
/// `language` - the language for which we're generating a library
/// `classes` - the list of classes to write.
pub fn write(language: &Language, classes: &[ql::Class]) -> std::io::Result<()> {
    println!(
        "Writing QL library for {} to '{}'",
        &language.name,
        match language.ql_library_path.to_str() {
            None => "<undisplayable>",
            Some(p) => p,
        }
    );
    let file = File::create(&language.ql_library_path)?;
    let mut file = LineWriter::new(file);
    ql::write(&language.name, &mut file, &classes)
}

/// Creates a map from QL class names to their supertypes.
fn create_supertype_map(nodes: &[node_types::Entry]) -> SupertypeMap {
    let mut map = SupertypeMap::new();
    for node in nodes {
        match &node {
            node_types::Entry::Union {
                type_name,
                members: n_members,
            } => {
                let supertype_class_name = dbscheme_name_to_class_name(&node_types::escape_name(
                    &node_types::node_type_name(&type_name.kind, type_name.named),
                ));
                for n_member in n_members {
                    let subtype_class_name = dbscheme_name_to_class_name(&node_types::escape_name(
                        &node_types::node_type_name(&n_member.kind, n_member.named),
                    ));
                    match map.get_mut(&subtype_class_name) {
                        Some(set) => {
                            set.insert(supertype_class_name.clone());
                        }
                        None => {
                            let mut set: BTreeSet<String> = BTreeSet::new();
                            set.insert(supertype_class_name.clone());
                            map.insert(subtype_class_name.clone(), set);
                        }
                    }
                }
            }
            node_types::Entry::Table { type_name, fields } => {
                let node_name = node_types::node_type_name(&type_name.kind, type_name.named);
                for field in fields {
                    if field.types.len() != 1 {
                        // This field can have one of several types. Since we create an ad-hoc
                        // QL union type to represent them, the class wrapping that union type
                        // will be a supertype of all its members.
                        let field_union_name = format!(
                            "{}_{}_type",
                            &node_name,
                            match &field.name {
                                Some(name) => &name,
                                None => "child",
                            }
                        );
                        let field_union_name = node_types::escape_name(&field_union_name);
                        let supertype_name = dbscheme_name_to_class_name(&field_union_name);
                        for field_type in &field.types {
                            let member_name =
                                node_types::node_type_name(&field_type.kind, field_type.named);
                            let member_class_name =
                                dbscheme_name_to_class_name(&node_types::escape_name(&member_name));
                            match map.get_mut(&member_class_name) {
                                Some(set) => {
                                    set.insert(supertype_name.clone());
                                }
                                None => {
                                    let mut set: BTreeSet<String> = BTreeSet::new();
                                    set.insert(supertype_name.clone());
                                    map.insert(member_class_name.clone(), set);
                                }
                            }
                        }<commit_msg>Simplify hashmap insertion<commit_after>use crate::language::Language;
use crate::ql;
use std::collections::{BTreeSet, HashMap};
use std::fs::File;
use std::io::LineWriter;

type SupertypeMap = HashMap<String, BTreeSet<String>>;

/// Writes the QL AST library for the given library.
///
/// # Arguments
///
/// `language` - the language for which we're generating a library
/// `classes` - the list of classes to write.
pub fn write(language: &Language, classes: &[ql::Class]) -> std::io::Result<()> {
    println!(
        "Writing QL library for {} to '{}'",
        &language.name,
        match language.ql_library_path.to_str() {
            None => "<undisplayable>",
            Some(p) => p,
        }
    );
    let file = File::create(&language.ql_library_path)?;
    let mut file = LineWriter::new(file);
    ql::write(&language.name, &mut file, &classes)
}

/// Creates a map from QL class names to their supertypes.
fn create_supertype_map(nodes: &[node_types::Entry]) -> SupertypeMap {
    let mut map = SupertypeMap::new();
    for node in nodes {
        match &node {
            node_types::Entry::Union {
                type_name,
                members: n_members,
            } => {
                let supertype_class_name = dbscheme_name_to_class_name(&node_types::escape_name(
                    &node_types::node_type_name(&type_name.kind, type_name.named),
                ));
                for n_member in n_members {
                    let subtype_class_name = dbscheme_name_to_class_name(&node_types::escape_name(
                        &node_types::node_type_name(&n_member.kind, n_member.named),
                    ));
                    map.entry(subtype_class_name)
                        .or_insert_with(|| BTreeSet::new())
                        .insert(supertype_class_name.clone());
                }
            }
            node_types::Entry::Table { type_name, fields } => {
                let node_name = node_types::node_type_name(&type_name.kind, type_name.named);
                for field in fields {
                    if field.types.len() != 1 {
                        // This field can have one of several types. Since we create an ad-hoc
                        // QL union type to represent them, the class wrapping that union type
                        // will be a supertype of all its members.
                        let field_union_name = format!(
                            "{}_{}_type",
                            &node_name,
                            match &field.name {
                                Some(name) => &name,
                                None => "child",
                            }
                        );
                        let field_union_name = node_types::escape_name(&field_union_name);
                        let supertype_name = dbscheme_name_to_class_name(&field_union_name);
                        for field_type in &field.types {
                            let member_name =
                                node_types::node_type_name(&field_type.kind, field_type.named);
                            let member_class_name =
                                dbscheme_name_to_class_name(&node_types::escape_name(&member_name));
                            map.entry(member_class_name)
                                .or_insert_with(|| BTreeSet::new())
                                .insert(supertype_name.clone());
                        }
{'fraction_non_alphanumeric': 0.10307651853799632, 'fraction_numerical': 0.00026295030239284776, 'mean_word_length': 1.380907668231612, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4084788', 'n_tokens_mistral': 2006, 'n_tokens_neox': 1906, 'n_words': 414}