titleformat_rs/
program.rs1use crate::environment::{value_string, Environment, Value};
2use crate::parser;
3use crate::types::Error;
4use crate::types::Expr;
5use crate::types::Expr::*;
6use std::collections::HashMap;
7
8#[derive(Debug, Default)]
9pub struct Program {
10 instr: Vec<Expr>,
11}
12
13impl Program {
14 pub fn new() -> Self {
22 Program { instr: vec![] }
23 }
24
25 pub fn parse(&mut self, instr: &str) -> Result<(), Error> {
34 self.instr = parser::parse(instr)?;
35 Ok(())
36 }
37
38 pub fn run(&mut self) -> Result<String, Error> {
48 self.run_with_meta(HashMap::new())
49 }
50
51 pub fn run_with_meta(&self, metadata: HashMap<String, Vec<String>>) -> Result<String, Error> {
64 let mut env = Environment::new(metadata);
65 let result = match self.resolve_arg_vec(&mut env, &self.instr)? {
66 ExprValue(v) => v.val.clone(),
67 _ => unreachable!(),
68 };
69 Ok(result)
70 }
71
72 fn resolve_arg_vec(&self, env: &mut Environment, args: &Vec<Expr>) -> Result<Expr, Error> {
75 let mut new_arg = value_string("", false);
76
77 for arg in args {
78 let tmp = self.eval(env, arg)?;
79 new_arg.val = new_arg.val + &tmp.val;
80 new_arg.cond = new_arg.cond || tmp.cond;
82 }
83
84 Ok(ExprValue(new_arg))
85 }
86
87 fn eval(&self, env: &mut Environment, expr: &Expr) -> Result<Value, Error> {
88 match expr {
89 ExprValue(v) => Ok(v.clone()),
90 Literal(v) => Ok(value_string(v, true)),
92 Variable(var) => Ok(env.get_variable(var)),
93 Conditional(args) => {
94 let arg = self.resolve_arg_vec(env, args)?;
95 match self.eval(env, &arg)? {
96 Value { val: v, cond: true } => Ok(value_string(&v, true)),
97 _ => Ok(value_string("", false)),
98 }
99 }
100 FuncCall(name, args) => {
101 let mut evaluated_args = Vec::new();
102 for unresolved in args {
103 let resolved = self.resolve_arg_vec(env, unresolved)?;
104 let new_arg = self.eval(env, &resolved)?;
105 evaluated_args.push(new_arg);
106 }
107 Ok(env.call(name, evaluated_args)?)
108 }
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_parse() {
119 let mut prog = Program::new();
120 prog.parse("%a%").unwrap();
121 }
122
123 #[test]
124 fn test_multi_parse() {
125 let mut prog = Program::new();
126 prog.parse("%a%").unwrap();
127 prog.parse("%b%").unwrap();
128 }
129
130 #[test]
131 fn test_run_empty() {
132 let mut prog = Program::new();
133 prog.parse("").unwrap();
134 assert_eq!(prog.run().unwrap(), String::from(""));
135 }
136
137 #[test]
138 fn test_run() {
139 let mut prog = Program::new();
140 prog.parse("%a%").unwrap();
141 let mut m = HashMap::new();
142 m.insert(String::from("a"), vec![String::from("val")]);
143 assert_eq!(prog.run_with_meta(m).unwrap(), String::from("val"));
144 }
145
146 #[test]
147 fn test_run_unknown_variable() {
148 let mut prog = Program::new();
149 prog.parse("%unknown%").unwrap();
150 assert_eq!(prog.run().unwrap(), String::from("?"));
151 }
152
153 #[test]
154 fn test_run_func() {
155 let mut prog = Program::new();
156 prog.parse("$add(2,2)").unwrap();
157 assert_eq!(prog.run().unwrap(), String::from("4"));
158 }
159
160 #[test]
161 fn test_run_func_variable() {
162 let mut prog = Program::new();
163 prog.parse("$add(%a%,2)").unwrap();
164 let mut m = HashMap::new();
165 m.insert(String::from("a"), vec![String::from("2")]);
166 assert_eq!(prog.run_with_meta(m).unwrap(), String::from("4"));
167 }
168
169 #[test]
170 fn test_run_func_func() {
171 let mut prog = Program::new();
172 prog.parse("$add($add(1,1),2)").unwrap();
173 assert_eq!(prog.run().unwrap(), String::from("4"));
174 }
175
176 #[test]
177 fn test_multi_run() {
178 let mut prog = Program::new();
179 prog.parse("$add(%a%,2)").unwrap();
180 let mut m = HashMap::new();
181 m.insert(String::from("a"), vec![String::from("2")]);
182 assert_eq!(prog.run_with_meta(m.clone()).unwrap(), String::from("4"));
183 assert_eq!(prog.run_with_meta(m).unwrap(), String::from("4"));
184 }
185
186 #[test]
187 fn test_run_conditional_variable_exists() {
188 let mut prog = Program::new();
189 prog.parse("[%a%]").unwrap();
190 let mut m = HashMap::new();
191 m.insert(String::from("a"), vec![String::from("val")]);
192 assert_eq!(prog.run_with_meta(m).unwrap(), String::from("val"));
193 }
194
195 #[test]
196 fn test_run_conditional_variable_nonexistent() {
197 let mut prog = Program::new();
198 prog.parse("[%a%]").unwrap();
199 assert_eq!(prog.run().unwrap(), String::from(""));
200 }
201
202 #[test]
203 fn test_run_conditional_function_variable_exists() {
204 let mut prog = Program::new();
205 prog.parse("[$add(%a%,2)]").unwrap();
206 let mut m = HashMap::new();
207 m.insert(String::from("a"), vec![String::from("2")]);
208 assert_eq!(prog.run_with_meta(m).unwrap(), String::from("4"));
209 }
210
211 #[test]
212 fn test_run_conditional_function_variable_nonexistent() {
213 let mut prog = Program::new();
214 prog.parse("[$add(%a%,2)]").unwrap();
215 assert_eq!(prog.run().unwrap(), String::from(""));
216 }
217
218 #[test]
219 fn test_conditional_variable_literal() {
220 let mut prog = Program::new();
221 prog.parse("[%a%b]").unwrap();
222 let mut m = HashMap::new();
223 m.insert(String::from("a"), vec![String::from("2")]);
224 assert_eq!(prog.run_with_meta(m).unwrap(), String::from("2b"));
225 }
226}