yolol_runner/
lib.rs

1mod ast;
2mod parser;
3use std::fs::read_to_string;
4
5use ast::Tree;
6use parser::yolol_parser;
7use yolol_devices::devices::chip::CodeRunner;
8use yolol_devices::field::Field;
9use yolol_devices::value::ValueTrait;
10use yolol_devices::value::YololInt;
11use yolol_devices::value::YololValue;
12
13#[derive(Debug, Default)]
14pub struct YololRunner {
15    lines: Vec<String>,
16    globals: Vec<Field>,
17    locals: Vec<Field>,
18    pc: usize,
19    path: String,
20}
21
22impl YololRunner {
23    /// Get a reference to the yolol runner's globals.
24    pub fn globals(&self) -> &[Field] {
25        self.globals.as_slice()
26    }
27
28    /// Get a reference to the yolol runner's locals.
29    pub fn locals(&self) -> &[Field] {
30        self.locals.as_slice()
31    }
32
33    fn get_local(&mut self, k: String) -> &mut Field {
34        if self
35            .locals
36            .iter()
37            .any(|f| f.name().to_lowercase() == k.to_lowercase())
38        {
39            for f in &mut self.locals {
40                if f.name() == k {
41                    return f;
42                }
43            }
44            unreachable!();
45        } else {
46            let mut field = Field::default();
47            field.set_name(k.clone());
48            self.locals.push(field);
49            self.get_local(k)
50        }
51    }
52
53    fn get_global(&mut self, k: String) -> &mut Field {
54        if self
55            .globals
56            .iter()
57            .any(|f| f.name().to_lowercase() == k.to_lowercase())
58        {
59            for f in &mut self.globals {
60                if f.name() == k {
61                    return f;
62                }
63            }
64            unreachable!();
65        } else {
66            let mut field = Field::default();
67            field.set_name(k.clone());
68            self.globals.push(field);
69            self.get_global(k)
70        }
71    }
72
73    fn process(&mut self, token: &Tree) -> Option<()> {
74        match token {
75            Tree::Error => None,
76            Tree::Comment(_) => Some(()),
77            Tree::Assign(r, l) => self.process_assing(r, l),
78            Tree::IfThen(p, s) => {
79                let v = &self.process_expr(p)?;
80                if v.into() {
81                    for stmt in s {
82                        self.process(stmt)?;
83                    }
84                }
85                Some(())
86            }
87            Tree::Goto(t) => {
88                if let YololValue::Int(v) = &self.process_expr(t)? {
89                    let pc: i64 = v.into();
90                    self.pc = (pc - 2).clamp(0, 20) as usize;
91                }
92                None
93            }
94            Tree::Empty => Some(()),
95            t => self.process_expr(t).map(|_| ()),
96        }
97    }
98
99    fn process_assing(&mut self, r: &Tree, l: &Tree) -> Option<()> {
100        let value = self.process_expr(l)?;
101
102        let field = match r {
103            Tree::LocalVariable(v) => self.get_local(v.clone()),
104            Tree::GlobalVariable(v) => self.get_global(v.clone()),
105            t => unreachable!("process_assing : {:?}", t),
106        };
107        **field = value;
108        Some(())
109    }
110    fn process_expr(&mut self, token: &Tree) -> Option<YololValue> {
111        match token {
112            Tree::LocalVariable(v) => Some((**self.get_local(v.clone())).clone()),
113            Tree::GlobalVariable(v) => Some((**self.get_global(v.clone())).clone()),
114            Tree::Numerical(v) => Some(YololInt::new_raw(*v).into()),
115            Tree::String(v) => Some(v.as_str().into()),
116            Tree::Or(r, l) => Some(self.process_expr(r)?.or(&self.process_expr(l)?)),
117            Tree::And(r, l) => Some(self.process_expr(r)?.and(&self.process_expr(l)?)),
118            Tree::Eq(r, l) => Some((self.process_expr(r)? == self.process_expr(l)?).into()),
119            Tree::Ne(r, l) => Some((self.process_expr(r)? != self.process_expr(l)?).into()),
120            Tree::Gt(r, l) => Some((self.process_expr(r)? > self.process_expr(l)?).into()),
121            Tree::Lt(r, l) => Some((self.process_expr(r)? < self.process_expr(l)?).into()),
122            Tree::Gte(r, l) => Some((self.process_expr(r)? >= self.process_expr(l)?).into()),
123            Tree::Lte(r, l) => Some((self.process_expr(r)? <= self.process_expr(l)?).into()),
124            Tree::Add(r, l) => Some(&self.process_expr(r)? + &self.process_expr(l)?),
125            Tree::Sub(r, l) => &self.process_expr(r)? - &self.process_expr(l)?,
126            Tree::Mul(r, l) => &self.process_expr(r)? * &self.process_expr(l)?,
127            Tree::Div(r, l) => &self.process_expr(r)? / &self.process_expr(l)?,
128            Tree::Mod(r, l) => &self.process_expr(r)? % &self.process_expr(l)?,
129            Tree::Neg(l) => &YololValue::default() - &self.process_expr(l)?,
130            Tree::Fac(r) => Some(self.process_expr(r)?.fac()?),
131            Tree::Abs(r) => Some(self.process_expr(r)?.abs()?),
132            Tree::Sqrt(r) => Some(self.process_expr(r)?.sqrt()?),
133            Tree::Sin(r) => Some(self.process_expr(r)?.sin()?),
134            Tree::Asin(r) => Some(self.process_expr(r)?.asin()?),
135            Tree::Cos(r) => Some(self.process_expr(r)?.cos()?),
136            Tree::Acos(r) => Some(self.process_expr(r)?.acos()?),
137            Tree::Tan(r) => Some(self.process_expr(r)?.tan()?),
138            Tree::Atan(r) => Some(self.process_expr(r)?.atan()?),
139            Tree::Not(r) => Some((self.process_expr(r)? == false.into()).into()),
140            Tree::Exp(r, l) => Some(self.process_expr(r)?.pow(&self.process_expr(l)?)?),
141
142            Tree::AssignAdd(r, l) => {
143                let v = self.process_expr(l)?;
144                let field = match &**r {
145                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
146                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
147                    _ => unreachable!(),
148                };
149                **field = &**field + &v;
150                Some(YololValue::default())
151            }
152
153            Tree::AssignSub(r, l) => {
154                let v = self.process_expr(l)?;
155                let field = match &**r {
156                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
157                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
158                    _ => unreachable!(),
159                };
160                **field = (&**field - &v)?;
161                Some(YololValue::default())
162            }
163
164            Tree::AssignMul(r, l) => {
165                let v = self.process_expr(l)?;
166                let field = match &**r {
167                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
168                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
169                    _ => unreachable!(),
170                };
171                **field = (&**field * &v)?;
172                Some(YololValue::default())
173            }
174
175            Tree::AssignDiv(r, l) => {
176                let v = self.process_expr(l)?;
177                let field = match &**r {
178                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
179                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
180                    _ => unreachable!(),
181                };
182                **field = (&**field / &v)?;
183                Some(YololValue::default())
184            }
185
186            Tree::AssignMod(r, l) => {
187                let v = self.process_expr(l)?;
188                let field = match &**r {
189                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
190                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
191                    _ => unreachable!(),
192                };
193                **field = (&**field % &v)?;
194                Some(YololValue::default())
195            }
196
197            Tree::AssignExp(r, l) => {
198                let v = self.process_expr(l)?;
199                let field = match &**r {
200                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
201                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
202                    _ => unreachable!(),
203                };
204                let v = field.pow(&v);
205                **field = v?;
206                Some(YololValue::default())
207            }
208
209            Tree::PostInc(r) => {
210                let field = match &**r {
211                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
212                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
213                    _ => unreachable!(),
214                };
215                Some(field.post_inc())
216            }
217            Tree::PostDec(r) => {
218                let field = match &**r {
219                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
220                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
221                    _ => unreachable!(),
222                };
223                Some(field.post_dec()?)
224            }
225            Tree::PreDec(r) => {
226                let field = match &**r {
227                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
228                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
229                    _ => unreachable!(),
230                };
231                Some(field.pre_dec()?)
232            }
233            Tree::PreInc(r) => {
234                let field = match &**r {
235                    Tree::LocalVariable(v) => self.get_local(v.to_string()),
236                    Tree::GlobalVariable(v) => self.get_global(v.to_string()),
237                    _ => unreachable!(),
238                };
239                Some(field.pre_inc())
240            }
241            t => unreachable!("process_expr : {:?}", t),
242        }
243    }
244}
245
246impl CodeRunner for YololRunner {
247    fn parse(&mut self, path: &str) -> Option<()> {
248        self.path = path.to_string();
249        if let Ok(file) = read_to_string(path) {
250            self.lines = file
251                .replace("\r\n", "\n")
252                .split('\n')
253                .map(|s| s.to_string())
254                .collect(); //yolol_parser::root(&file).unwrap();
255            return Some(());
256        }
257        None
258    }
259
260    fn step(&mut self) {
261        if self.lines.len() <= self.pc {
262            self.pc = 0;
263        }
264        let stmts = yolol_parser::line(&self.lines[self.pc]);
265        if let Ok(stmts) = stmts {
266            for stmt in stmts {
267                if self.process(&stmt).is_none() {
268                    break;
269                }
270            }
271        } else if let Err(err) = stmts {
272            println!("error {} line {}\n{}", self.path, self.pc + 1, err);
273        }
274        self.pc += 1;
275    }
276
277    fn update_globals(&mut self, globals: Vec<Field>) {
278        self.globals = globals;
279    }
280
281    fn get_global(&self) -> Vec<Field> {
282        self.globals.clone()
283    }
284}