1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/// High-level code generation logic.
mod code;
/// Format documentation as rustdoc.
mod docstring;
/// Actual changes to the filesystem.
pub mod filesystem;
/// High-level planning for what the final generation configs will look like. All logic that touch
/// Yin concepts in the codegen module should live inside of this sub-module.
pub mod planning;
/// Finalized code generation.
mod postprocessing;
/// Format codegen.
pub mod string_format;
/// Track autogenerated files.
pub mod track_autogen;

pub use code::{code, CodeConfig, StructConfig};
use filesystem::{output_code_verbatim, OutputConfig};
pub use postprocessing::mark_autogen::{add_indent, count_indent};
pub use postprocessing::mark_fmt::add_fmt_skips;
use postprocessing::post_process_generation;

/// How many characters per line each autogenerated document should have.
const CODE_WIDTH: usize = 80;

/// Runtime options for code generation.
#[derive(Copy, Clone)]
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 to add rustfmt attributes to prevent rustfmt from acting on certain lines.
    pub add_rustfmt_attributes: 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,
    /// Whether or not we're outputting code for release.
    ///
    /// If we are, the implications are:
    ///
    ///  * No autogeneration comments, so that documentation looks good on docs.rs
    ///  * No `build.rs`, because there's no network access for builds on docs.rs anyways
    ///  * Autogenerated files will be committed instead of ignored, because they can't be built
    ///    without `build.rs` to do it
    ///  * A release branch will be created, ready for cargo publishing
    pub release: bool,
}

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

/// Perform post-processing on generated code given the options specified in `codegen_cfg`, and
/// then output it to the given destination file path.
pub fn output_code(generated_code: &str, destination: &str, codegen_cfg: &CodegenConfig) {
    output_code_verbatim(&OutputConfig {
        code: &post_process_generation(generated_code, codegen_cfg),
        file_path: destination,
        git_ignore: !codegen_cfg.release,
        cargo_track: codegen_cfg.track_autogen,
    });
}