1use std::fmt::{self, Display, Formatter};
2
3use conch_parser::ast::{AtomicTopLevelCommand, TopLevelCommand};
4use enum_map::EnumMap;
5use linked_hash_map::LinkedHashMap;
6
7use crate::parser::RunscriptLocation;
8
9#[derive(Clone, Debug)]
11pub struct Runscript {
12 pub name: String,
14 pub source: String,
16 pub includes: Vec<RunscriptInclude>,
18 pub scripts: Scripts,
20 pub options: Vec<String>,
22}
23
24#[derive(Clone, Debug)]
26pub struct RunscriptInclude {
27 pub runscript: Runscript,
28 pub location: RunscriptLocation,
30}
31
32#[derive(Clone, Debug)]
34pub struct Scripts {
35 pub targets: LinkedHashMap<String, EnumMap<ScriptPhase, Option<Script>>>,
39}
40
41#[derive(Debug, PartialEq, Hash, Eq, Clone, Copy, enum_map::Enum)]
42pub enum ScriptPhase {
43 BuildOnly, Build, BuildAndRun, Run, RunOnly, }
49
50#[derive(Clone, Debug)]
51pub struct Script {
52 pub commands: Vec<AtomicTopLevelCommand<String>>,
53 pub location: RunscriptLocation,
54}
55
56impl Runscript {
57 pub fn unwind_fileid(&self, id: &[usize]) -> Option<&Runscript> {
58 if id.is_empty() {
59 Some(&self)
60 } else {
61 let mut file_ref = self;
62 for index in id {
63 file_ref = &file_ref.includes.get(*index)?.runscript;
64 }
65 Some(file_ref)
66 }
67 }
68
69 pub fn get_target(&self, target: &str) -> Option<&EnumMap<ScriptPhase, Option<Script>>> {
70 match self.scripts.targets.get(target).as_ref() {
71 Some(map) if map.values().any(Option::is_some) => Some(map),
72 _ => {
73 for include in &self.includes {
74 match include.runscript.scripts.targets.get(target) {
75 Some(map) if map.values().any(Option::is_some) => {
76 return Some(map);
77 }
78 _ => {}
79 }
80 }
81 None
82 }
83 }
84 }
85}
86
87impl Display for ScriptPhase {
88 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
89 write!(
90 f,
91 "{}",
92 match self {
93 ScriptPhase::BuildOnly => "Build!",
94 ScriptPhase::Build => "Build",
95 ScriptPhase::BuildAndRun => "Build & Run",
96 ScriptPhase::Run => "Run",
97 ScriptPhase::RunOnly => "Run!",
98 }
99 )
100 }
101}