templito/
expr.rs

1use crate::func_man::FuncManager;
2use crate::scope::Scope;
3use crate::tdata::*;
4use crate::temp_man::TempManager;
5use crate::tparam::*;
6use err_tools::*;
7use std::ops::Deref;
8
9#[derive(Clone, Debug, PartialEq)]
10pub enum VarPart {
11    Num(usize),
12    Id(String),
13}
14impl VarPart {
15    pub fn as_str(&self) -> Option<&str> {
16        match self {
17            VarPart::Num(_) => None,
18            VarPart::Id(s) => Some(s),
19        }
20    }
21}
22
23#[derive(Clone, Debug, PartialEq)]
24pub enum Expr {
25    Lit(TData),
26    Var(Vec<VarPart>),
27    Command(String, Vec<Expr>),
28    List(Vec<Expr>),
29    Map(Vec<(String, Expr)>),
30}
31
32pub fn run_values<'a, TM: TempManager, FM: FuncManager>(
33    cname: &str,
34    args: &[TCow<'a>],
35    tm: &mut TM,
36    fm: &FM,
37) -> anyhow::Result<TCow<'a>> {
38    if let Some(in_f) = fm.get_func(&cname) {
39        return Ok(in_f(&args)?);
40    }
41    match tm.get_t(cname).map(|t| t.clone()) {
42        Ok(in_tp) => {
43            let mut v2: Vec<&dyn TParam> = Vec::new();
44            for a in args {
45                v2.push(a);
46            }
47            let (s, mut mp) = in_tp.run_exp(&v2, tm, fm)?;
48            if let Some(v) = mp.remove("return") {
49                return Ok(TCow::Owned(v));
50            }
51            Ok(TCow::Owned(TData::String(s)))
52        }
53        Err(e) => e_string(format!("Getting template {}, {}", cname, e)),
54    }
55}
56
57pub fn run_command<'a, TM: TempManager, FM: FuncManager>(
58    cname: &str,
59    args: &'a [Expr],
60    scope: &'a Scope,
61    tm: &mut TM,
62    fm: &FM,
63) -> anyhow::Result<TCow<'a>> {
64    if cname == "run" {
65        let mut tds = Vec::new();
66        for p in args {
67            tds.push(p.run(scope, tm, fm)?);
68        }
69        //Convert TParams to pointers to call the Template
70        let mut v: Vec<&dyn TParam> = Vec::new();
71        for p in &tds[1..] {
72            v.push(p);
73        }
74        if let Some(tp) = tds.get(0) {
75            if let TData::Template(t) = tp.deref() {
76                let (s, mut mp) = t.run_exp(&v, tm, fm)?;
77                if let Some(v) = mp.remove("return") {
78                    return Ok(TCow::Owned(v));
79                }
80                return Ok(TCow::Owned(TData::String(s)));
81            }
82        }
83    }
84    if cname == "first" {
85        for p in args {
86            if let Ok(res) = p.run(scope, tm, fm) {
87                if *res.deref() != TData::Null {
88                    return Ok(res);
89                }
90            }
91        }
92        return Ok(TCow::Owned(TData::Null));
93    }
94    if cname == "select" {
95        if args.len() < 3 {
96            return e_str("'select' requires at least 1 test and 2 possible values");
97        }
98        let bval = args[0].run(scope, tm, fm)?;
99        let bval = if let Some(n) = bval.as_usize() {
100            n + 1
101        } else if let Some(b) = bval.as_bool() {
102            2 - (b as usize)
103        } else {
104            return e_string(format!("As Bool failed on {}", bval.deref()));
105        };
106
107        if bval > args.len() {
108            return e_str("'select' first param must choose return a value less than the length of the rest of the args");
109        }
110
111        return args[bval].run(scope, tm, fm);
112    }
113    let mut v = Vec::new();
114    for p in args {
115        let pval = p.run(scope, tm, fm)?;
116        v.push(pval);
117    }
118    run_values(cname, &v, tm, fm)
119}
120
121impl Expr {
122    pub fn run<'a, TM: TempManager, FM: FuncManager>(
123        &'a self,
124        scope: &'a Scope,
125        tm: &mut TM,
126        fm: &FM,
127    ) -> anyhow::Result<TCow<'a>> {
128        match self {
129            Expr::Lit(v) => Ok(TCow::Borrowed(v)),
130            Expr::Var(v) => scope.get(v).e_string(format!("No Var by the name {:?}", v)),
131            Expr::Command(c, pars) => run_command(c, pars, scope, tm, fm),
132            Expr::List(v) => {
133                let mut res: Vec<TData> = Vec::new();
134                for c in v {
135                    let r = c.run(scope, tm, fm)?;
136                    res.push(r.into_owned());
137                }
138                Ok(TCow::Owned(TData::List(res)))
139            }
140            Expr::Map(m) => {
141                let mut res = std::collections::HashMap::new();
142                for (k, v) in m {
143                    let r = v.run(scope, tm, fm)?;
144                    res.insert(k.clone(), r.into_owned());
145                }
146                Ok(TCow::Owned(TData::Map(res)))
147            }
148        }
149    }
150}