use std::collections::HashMap; use std::fmt::Write; use anyhow::Context; use dpc::ir::IR; use dpc::output::datapack::Datapack; use dpc::output::strip::StripMode; use dpc::parse::lex::{lex, Token}; use dpc::project::{OptimizationLevel, ProjectSettings, ProjectSettingsBuilder}; use dpc::{codegen_ir, CodegenIRSettings}; use itertools::Itertools; #[allow(dead_code)] pub static TEST_ENTRYPOINT: &str = "test:main"; pub fn get_control_comment( contents: &str, ) -> anyhow::Result<(CodegenIRSettings, ProjectSettings, bool)> { let default = CodegenIRSettings { debug: false, debug_functions: false, ir_passes: false, mir_passes: false, lir_passes: false, }; let mut project = ProjectSettingsBuilder::new("dpc"); // We start at full since we want all the optimizations to interact, // and if we don't want any optimizations we can just turn off passes project = project.op_level(OptimizationLevel::Full); let lexed = lex(contents).context("Failed to lex text")?; let Some(first) = lexed.first() else { return Ok((default, project.build(), false)) }; let Token::Comment(comment) = &first.0 else { return Ok((default, project.build(), false)) }; let debug = comment.contains("debug"); let debug_functions = comment.contains("debug_functions"); let ir_passes = comment.contains("ir_passes"); let mir_passes = comment.contains("mir_passes"); let lir_passes = comment.contains("lir_passes"); let strip_mode = if comment.contains("strip_unstable") { StripMode::Unstable } else { StripMode::None }; let split = comment.contains("split"); if comment.contains("o0") { project = project.op_level(OptimizationLevel::None); } if comment.contains("o1") { project = project.op_level(OptimizationLevel::Basic); } if comment.contains("o2") { project = project.op_level(OptimizationLevel::More); } if comment.contains("o3") { project = project.op_level(OptimizationLevel::Full); } let settings = CodegenIRSettings { debug, debug_functions, ir_passes, mir_passes, lir_passes, }; let project = project.strip_mode(strip_mode); Ok((settings, project.build(), split)) } pub fn generate_datapacks( ir: IR, project: ProjectSettings, mut settings: CodegenIRSettings, split: bool, ) -> anyhow::Result> { let mut out = HashMap::new(); let datapack = codegen_ir(ir.clone(), &project, settings.clone()).context("Failed to codegen input")?; out.insert("main".into(), datapack); if split { settings.mir_passes = true; settings.lir_passes = true; let datapack = codegen_ir(ir, &project, settings).context("Failed to codegen input")?; out.insert("opt".into(), datapack); } Ok(out) } pub fn create_output(packs: HashMap) -> anyhow::Result { let mut out = String::new(); let len = packs.len(); for (pack_id, pack) in packs.into_iter().sorted_by_key(|x| x.0.clone()) { if len != 1 { writeln!(&mut out, "######## {pack_id} ########")?; } for (id, func) in pack.functions.iter().sorted_by_key(|x| x.0) { writeln!(&mut out, "# === {id} === #")?; for cmd in &func.contents { writeln!(&mut out, "{cmd}")?; } out.push('\n'); } } // Remove the final newline out.pop(); Ok(out) }