runscript/
script.rs

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/// A parsed runscript
10#[derive(Clone, Debug)]
11pub struct Runscript {
12    /// The name of the runscript for the location tracker
13    pub name: String,
14    /// The source of the runscript for emitting errors
15    pub source: String,
16    /// The runscripts this runscript includes.
17    pub includes: Vec<RunscriptInclude>,
18    /// The scripts this runscript declares
19    pub scripts: Scripts,
20    /// Runtime options to change the behaviour of the interpreter
21    pub options: Vec<String>,
22}
23
24/// The script and source location of an included runscript
25#[derive(Clone, Debug)]
26pub struct RunscriptInclude {
27    pub runscript: Runscript,
28    /// Where the include statement is in the runscript which is including the other
29    pub location: RunscriptLocation,
30}
31
32/// The exectable scripts defined by a [`Runscript`](struct.Runscript.html)
33#[derive(Clone, Debug)]
34pub struct Scripts {
35    /// The scripts defined under `$#name`
36    ///
37    /// These scripts are executed in their respective `ScriptPhase` if they were chosen as the target
38    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,   // b!
44    Build,       // b
45    BuildAndRun, // br (default)
46    Run,         // r
47    RunOnly,     // r!
48}
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}