zamm_yang 0.0.5

A basic, experimental code generator
/// Generate code for attribute files.
mod attribute;
/// Format documentation as rustdoc.
mod docstring;
/// Logic for ignoring autogenerated files in Git.
mod git_ignore;
/// Mark files as autogenerated.
mod mark_autogen;
/// Parsing and generation of names
mod name_transform;
/// Track autogenerated files.
pub mod track_autogen;

use crate::concepts::ImplementConfig;
use attribute::code_attribute;
use docstring::into_docstring;
use git_ignore::{git_ignore, git_rm};
use mark_autogen::add_autogeneration_comments;
pub use name_transform::NameTransform;
use path_abs::PathAbs;
use std::fs;
use std::path::Path;

/// Runtime options for code generation.
pub struct CodegenConfig {
    /// Whether or not to mark each generated line of code with the autogeneration comment
    /// specified by `zamm_yang::codegen::mark_autogen::AUTOGENERATION_MARKER`.
    pub comment_autogen: bool,
    /// Whether or not we want Cargo to track autogenerated files and rebuild when they change.
    pub track_autogen: bool,
    /// Whether or not we're outputting code for Yin itself.
    pub yin: bool,
}

impl Default for CodegenConfig {
    fn default() -> Self {
        Self {
            comment_autogen: true,
            track_autogen: false,
            yin: false,
        }
    }
}

/// Output code to filename
pub fn output_code(implement: &ImplementConfig, options: &CodegenConfig) {
    let generated_code = code_attribute(implement, options);
    let file_relative = format!(
        "src/concepts/attributes/{}.rs",
        NameTransform::from_camel_case(&implement.name).to_snake_case()
    );
    let file_pathabs = PathAbs::new(Path::new(&file_relative))
        .unwrap_or_else(|_| panic!("Could not get absolute path for {}", file_relative));
    let file_absolute = file_pathabs.as_path().to_str().unwrap();
    let file_parent = file_pathabs
        .as_path()
        .parent()
        .unwrap_or_else(|| panic!("Could not get parent directory for {}", file_absolute));
    fs::create_dir_all(file_parent).unwrap_or_else(|_| {
        panic!(
            "Could not create intermediate directories for {}",
            file_absolute
        )
    });
    git_rm(&file_absolute);
    fs::write(file_absolute, generated_code)
        .unwrap_or_else(|_| panic!("Couldn't output generated code to {}", file_absolute));
    git_ignore(&file_pathabs).unwrap_or_else(|_| panic!("Could not ignore {}", file_absolute));
    if options.track_autogen {
        // tell cargo to regenerate autogenerated files when they're edited or removed
        println!("cargo:rerun-if-changed={}", file_relative);
    } else {
        println!("Generated {}", file_relative);
    }
}