pseudocode/
lib.rs

1#[macro_use]
2extern crate pest;
3#[macro_use]
4extern crate pest_derive;
5extern crate rand;
6
7use std::cell::RefCell;
8use std::rc::Rc;
9use std::fs::File;
10use std::io::prelude::*;
11use std::fmt;
12use std::fmt::Write;
13use std::collections::HashMap;
14use pest::Parser;
15use pest::error::{Error, ErrorVariant};
16use pest::iterators::Pair;
17use rand::prelude::*;
18
19#[derive(Parser)]
20#[grammar = "grammar.pest"]
21pub struct PseudocodeParser;
22
23pub struct Program {
24    instructions: Vec<Instruction>
25}
26
27impl Program {
28    fn new(insts: Vec<Instruction>) -> Self {
29        Program{
30            instructions: insts,
31        }
32    }
33}
34
35#[derive(Clone, Debug)]
36pub enum Op {
37    NEQ,
38    EQ,
39    GT,
40    LT,
41    GTE,
42    LTE,
43    MULT,
44    DIV,
45    PLUS,
46    MINUS,
47    MOD
48}
49
50#[derive(Clone, Debug)]
51pub enum Expr {
52    ProcedureCall(String, Vec<Expr>),
53    Number(f64),
54    String(String),
55    Boolean(bool),
56    Identifier(String),
57    BinaryExpr(Box<Expr>, Op, Box<Expr>),
58    Negate(Box<Expr>),
59    Not(Box<Expr>),
60    List(Vec<Expr>),
61    Index(String, Box<Expr>)
62}
63
64#[derive(Clone, Debug)]
65pub enum Instruction {
66    ProcedureDef(String, Vec<String>, Vec<Instruction>),
67    RepeatUntilBlock(Expr, Vec<Instruction>),
68    RepeatTimes(Expr, Vec<Instruction>),
69    ForEach(String, String, Vec<Instruction>),
70    IfSelection(Expr, Vec<Instruction>),
71    IfElseSelection(Expr, Vec<Instruction>, Vec<Instruction>),
72    ReturnStmt(Expr),
73    DisplayStmt(Expr),
74    ProcedureCall(String, Vec<Expr>),
75    IdentAssignment(String, Expr),
76    IndexAssignment(String, Expr, Expr) // list ident, index expr, value expr
77}
78
79#[derive(Clone, Debug)]
80pub enum Value {
81    Number(f64),
82    String(String),
83    Boolean(bool),
84    List(Rc<RefCell<Vec<Rc<RefCell<Value>>>>>)
85}
86
87impl fmt::Display for Value {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self  {
90            Value::Number(val) => write!(f, "{}", val),
91            Value::String(val) => write!(f, "{}", val),
92            Value::Boolean(val) => write!(f, "{}", val),
93            Value::List(list) => {
94                write!(f, "[")?;
95                let numvals = list.borrow().len();
96                for (idx, val) in list.borrow().iter().enumerate() {
97                    if idx < numvals-1 {
98                        write!(f, "{}, ", *val.borrow())?;
99                    } else {
100                        write!(f, "{}", *val.borrow())?;
101                    }
102                }
103                write!(f, "]")
104            }
105        }
106    }
107}
108
109pub struct Procedure {
110    arglist: Vec<String>,
111    body: Vec<Instruction>,
112    native: Option<Box<dyn Fn(Rc<RefCell<Scope>>) -> Result<Vec<Instruction>, String>>>
113}
114
115impl Procedure {
116    fn new(arglist: Vec<String>, body: Vec<Instruction>, native: Option<Box<dyn Fn(Rc<RefCell<Scope>>) -> Result<Vec<Instruction>, String>>>) -> Self {
117        Procedure { arglist: arglist, body: body, native: native}
118    }
119}
120
121fn call_proc(scope: Rc<RefCell<Scope>>, name: String, args: Vec<Expr>, output: Rc<RefCell<String>>) -> Result<Option<Rc<RefCell<Value>>>, String> {
122    if let Some(_proc) = scope.clone().borrow().get_proc(&name) {
123        let proc = _proc.clone();
124        let func_scope = Rc::new(RefCell::new(Scope::new(scope.clone())));
125        for (idx, varname) in proc.borrow().arglist.iter().enumerate() {
126            let expr = &args[idx];
127            let evaluated = expr.eval(scope.clone(), output.clone())?;
128            func_scope.borrow_mut().variables.insert(varname.to_string(), evaluated);
129        }
130        if let Some(native_impl) = &proc.borrow().native {
131            // get instructions from native impl
132            let instructions = native_impl(func_scope.clone())?;
133            return run_instructions(instructions, func_scope, output.clone());
134        }
135        return run_instructions(proc.borrow().body.clone(), func_scope, output.clone());
136    } else {
137        return Err(format!("No procedure named {}", name));
138    }
139}
140
141pub struct Scope<'a> {
142    variables: HashMap<String, Rc<RefCell<Value>>>,
143    procedures: HashMap<String, Rc<RefCell<Procedure>>>,
144    parent: Option<Rc<RefCell<Scope<'a>>>>,
145}
146
147impl<'a> Scope<'a> {
148    fn new(parent: Rc<RefCell<Scope<'a>>>) -> Self {
149        Scope {
150            variables: HashMap::new(),
151            procedures: HashMap::new(),
152            parent: Some(parent),
153        }
154    }
155
156    fn new_base_scope() -> Self {
157        let mut s = Scope {
158            variables: HashMap::new(),
159            procedures: HashMap::new(),
160            parent: None,
161        };
162
163        // populate pre-defined functions
164        let random_func = Procedure::new(vec!["a".to_string(), "b".to_string()], vec![], Some(Box::new(|scope| {
165            let mut rng = rand::thread_rng();
166            let a = scope.borrow().resolve("a".to_string()).ok_or("a is undefined")?;
167            let b = scope.borrow().resolve("b".to_string()).ok_or("a is undefined")?;
168            let val = match (a.borrow().clone(), b.borrow().clone()) {
169                (Value::Number(a), Value::Number(b)) => {
170                    rng.gen_range(a as i64, (b as i64)+1)
171                },
172                _ => {
173                    return Err("a and b most both be integers".to_string())
174                }
175            };
176            Ok(vec![
177                Instruction::ReturnStmt(Expr::Number(val as f64)),
178            ])
179        })));
180        s.procedures.insert("RANDOM".to_string(), Rc::new(RefCell::new(random_func)));
181
182        let concat_func = Procedure::new(vec!["a".to_string(), "b".to_string()], vec![], Some(Box::new(|scope| {
183            let a = scope.borrow().resolve("a".to_string()).ok_or("a is undefined")?;
184            let b = scope.borrow().resolve("b".to_string()).ok_or("a is undefined")?;
185            let val = match (a.borrow().clone(), b.borrow().clone()) {
186                (Value::String(a), Value::String(b)) => {
187                    format!("{}{}", a, b)
188                },
189                _ => {
190                    return Err("a and b most both be strings".to_string())
191                }
192            };
193            Ok(vec![
194                Instruction::ReturnStmt(Expr::String(val)),
195            ])
196        })));
197        s.procedures.insert("CONCAT".to_string(), Rc::new(RefCell::new(concat_func)));
198
199        let length_func = Procedure::new(vec!["l".to_string()], vec![], Some(Box::new(|scope| {
200            let list_val = scope.borrow().resolve("l".to_string()).ok_or("list is undefined")?;
201            let val = match list_val.borrow().clone() {
202                Value::List(list) => list.borrow().len() as f64,
203                _ => return Err("Argument to LENGTH must be a list".to_string())
204            };
205            Ok(vec![Instruction::ReturnStmt(Expr::Number(val))])
206        })));
207        s.procedures.insert("LENGTH".to_string(), Rc::new(RefCell::new(length_func)));
208
209        let insert_func = Procedure::new(vec!["list".to_string(), "i".to_string(), "value".to_string()], vec![], Some(Box::new(|scope| {
210            let list_val = scope.borrow().resolve("list".to_string()).ok_or("list is undefined")?;
211            let list = match list_val.borrow().clone() {
212                Value::List(list) => list,
213                _ => return Err("First argument to INSERT must be a list".to_string())
214            };
215            let idx_val = scope.borrow().resolve("i".to_string()).ok_or("i is undefined")?;
216            let idx = match *idx_val.borrow() {
217                Value::Number(idx) => if idx.fract() != 0.0 {
218                                          return Err("Second argument to INSERT must be an integer".to_string())
219                                      } else if idx < 1.0 || idx > list.borrow().len() as f64 {
220                                          return Err("Second argument to INSERT must be between 1 and the length of the list".to_string())
221                                      } else {
222                                          idx as usize
223                                      },
224                _ => return Err("First argument to INDEX must be a list".to_string())
225            };
226            let value = scope.borrow().resolve("value".to_string()).ok_or("value is undefined")?;
227            list.borrow_mut().insert(idx - 1, value);
228            Ok(vec![])
229        })));
230        s.procedures.insert("INSERT".to_string(), Rc::new(RefCell::new(insert_func)));
231
232        let remove_func = Procedure::new(vec!["list".to_string(), "i".to_string()], vec![], Some(Box::new(|scope| {
233            let list_val = scope.borrow().resolve("list".to_string()).ok_or("list is undefined")?;
234            let list = match list_val.borrow().clone() {
235                Value::List(list) => list,
236                _ => return Err("First argument to REMOVE must be a list".to_string())
237            };
238            let idx_val = scope.borrow().resolve("i".to_string()).ok_or("i is undefined")?;
239            let idx = match *idx_val.borrow() {
240                Value::Number(idx) => if idx.fract() != 0.0 {
241                    return Err("Second argument to REMOVE must be an integer".to_string())
242                } else {
243                    idx as usize
244                },
245                _ => return Err("First argument to REMOVE must be a list".to_string())
246            };
247            list.borrow_mut().remove(idx);
248            Ok(vec![])
249        })));
250        s.procedures.insert("REMOVE".to_string(), Rc::new(RefCell::new(remove_func)));
251
252        let append_func = Procedure::new(vec!["list".to_string(), "value".to_string()], vec![], Some(Box::new(|scope| {
253            let list_val = scope.borrow().resolve("list".to_string()).ok_or("list is undefined")?;
254            let list = match list_val.borrow().clone() {
255                Value::List(list) => list,
256                _ => return Err("First argument to APPEND must be a list".to_string())
257            };
258            let value = scope.borrow().resolve("value".to_string()).ok_or("value is undefined")?;
259            list.borrow_mut().push(value);
260            Ok(vec![])
261        })));
262        s.procedures.insert("APPEND".to_string(), Rc::new(RefCell::new(append_func)));
263
264        return s
265    }
266
267    fn define_proc(&mut self, name: String, arglist: Vec<String>, body: Vec<Instruction>) {
268        self.procedures.insert(name,
269            Rc::new(RefCell::new(Procedure::new(arglist, body, None))));
270    }
271
272    fn defined_in_parent(&self, ident: &String) -> bool {
273        if let Some(parent_scope) = &self.parent {
274            if parent_scope.borrow().variables.contains_key(ident) {
275                return true
276            } else {
277                parent_scope.borrow().defined_in_parent(ident)
278            }
279        } else {
280            false
281        }
282    }
283
284    fn assign(&mut self, ident: String, value: Rc<RefCell<Value>>) {
285        if self.variables.contains_key(&ident) {
286            self.variables.insert(ident, value);
287        } else if self.defined_in_parent(&ident) {
288            if let Some(parent_scope) = &self.parent {
289                parent_scope.borrow_mut().assign(ident, value);
290            }
291        } else {
292            self.variables.insert(ident, value);
293        }
294    }
295
296
297    fn resolve(&self, ident: String) -> Option<Rc<RefCell<Value>>> {
298        match self.variables.get(&ident) {
299            Some(val) => Some(val.clone()),
300            None => match &self.parent {
301                Some(parent_scope) => parent_scope.borrow().resolve(ident),
302                None => None
303            }
304        }
305    }
306
307    fn get_proc(&self, ident: &String) -> Option<Rc<RefCell<Procedure>>> {
308        match self.procedures.get(ident) {
309            Some(val) => Some(val.clone()),
310            None => match &self.parent {
311                Some(parent_scope) => parent_scope.borrow().get_proc(ident),
312                None => None
313            }
314        }
315    }
316
317    fn dump(&self) {
318        println!("### DUMPING SCOPE ###");
319        for (var, val) in self.variables.iter() {
320            println!("{} => {:?}", var, val);
321        }
322    }
323}
324
325impl Expr {
326    fn eval(&self, scope: Rc<RefCell<Scope>>, output: Rc<RefCell<String>>) -> Result<Rc<RefCell<Value>>, String> {
327        match self {
328            Expr::Number(val) => Ok(Rc::new(RefCell::new(Value::Number(*val)))),
329            Expr::String(val) => Ok(Rc::new(RefCell::new(Value::String(val.clone())))),
330            Expr::Boolean(val) => Ok(Rc::new(RefCell::new(Value::Boolean(val.clone())))),
331            Expr::Identifier(ident) => match scope.borrow().resolve(ident.to_string()) {
332                Some(val) => Ok(val),
333                None => Err(format!("Variable {} is not defined", ident))
334            },
335            Expr::Negate(expr) => {
336                let val = expr.eval(scope.clone(), output.clone())?.borrow().clone();
337                match val {
338                    Value::Number(n) => Ok(Rc::new(RefCell::new(Value::Number(-n)))),
339                    _ => Err(format!("Value {} must be a number", val))
340                }
341            },
342            Expr::Not(expr) => {
343                let val = expr.eval(scope.clone(), output.clone())?.borrow().clone();
344                match val {
345                    Value::Boolean(n) => Ok(Rc::new(RefCell::new(Value::Boolean(!n)))),
346                    _ => Err(format!("Value {} must be a boolean value but was a {:?}", val, val)),
347                }
348            },
349            Expr::BinaryExpr(lhs, op, rhs) => {
350                let lhsval = lhs.eval(scope.clone(), output.clone())?;
351                let rhsval = rhs.eval(scope.clone(), output.clone())?;
352                match op {
353                    Op::PLUS => {
354                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
355                            (Value::Number(f1), Value::Number(f2)) => {
356                                Ok(Rc::new(RefCell::new(Value::Number(f1 + f2))))
357                            },
358                            (_, _) => {
359                                Err(format!("{:?} and {:?} must both be numbers", lhsval, rhsval))
360                            }
361                        }
362                    },
363                    Op::MINUS => {
364                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
365                            (Value::Number(f1), Value::Number(f2)) => {
366                                Ok(Rc::new(RefCell::new(Value::Number(f1 - f2))))
367                            },
368                            (_, _) => {
369                                Err(format!("{:?} and {:?} must both be numbers", lhsval, rhsval))
370                            }
371                        }
372                    },
373                    Op::MULT => {
374                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
375                            (Value::Number(f1), Value::Number(f2)) => {
376                                Ok(Rc::new(RefCell::new(Value::Number(f1 * f2))))
377                            },
378                            (_, _) => {
379                                Err(format!("{:?} and {:?} must both be numbers", lhsval, rhsval))
380                            }
381                        }
382                    },
383                    Op::DIV => {
384                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
385                            (Value::Number(f1), Value::Number(f2)) => {
386                                Ok(Rc::new(RefCell::new(Value::Number(f1 / f2))))
387                            },
388                            (_, _) => {
389                                Err(format!("{:?} and {:?} must both be numbers", lhsval, rhsval))
390                            }
391                        }
392                    },
393                    Op::MOD => {
394                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
395                            (Value::Number(f1), Value::Number(f2)) => {
396                                Ok(Rc::new(RefCell::new(Value::Number(f1 % f2))))
397                            },
398                            (_, _) => {
399                                Err(format!("{:?} and {:?} must both be numbers", lhsval, rhsval))
400                            }
401                        }
402                    },
403                    Op::EQ => {
404                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
405                            (Value::Number(f1), Value::Number(f2)) => {
406                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 == f2))))
407                            },
408                            (Value::String(f1), Value::String(f2)) => {
409                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 == f2))))
410                            },
411                            (Value::Boolean(f1), Value::Boolean(f2)) => {
412                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 == f2))))
413                            },
414                            (_, _) => {
415                                Err(format!("{:?} and {:?} must be same type", lhsval, rhsval))
416                            }
417                        }
418                    },
419                    Op::NEQ => {
420                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
421                            (Value::Number(f1), Value::Number(f2)) => {
422                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 != f2))))
423                            },
424                            (Value::String(f1), Value::String(f2)) => {
425                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 != f2))))
426                            },
427                            (Value::Boolean(f1), Value::Boolean(f2)) => {
428                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 != f2))))
429                            },
430                            (_, _) => {
431                                Err(format!("{:?} and {:?} must be same type", lhsval, rhsval))
432                            }
433                        }
434                    },
435                    Op::GT => {
436                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
437                            (Value::Number(f1), Value::Number(f2)) => {
438                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 > f2))))
439                            },
440                            (_, _) => {
441                                Err(format!("{:?} and {:?} must be same type", lhsval, rhsval))
442                            }
443                        }
444                    },
445                    Op::LT => {
446                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
447                            (Value::Number(f1), Value::Number(f2)) => {
448                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 < f2))))
449                            },
450                            (_, _) => {
451                                Err(format!("{:?} and {:?} must be same type", lhsval, rhsval))
452                            }
453                        }
454                    },
455                    Op::GTE => {
456                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
457                            (Value::Number(f1), Value::Number(f2)) => {
458                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 >= f2))))
459                            },
460                            (_, _) => {
461                                Err(format!("{:?} and {:?} must be same type", lhsval, rhsval))
462                            }
463                        }
464                    },
465                    Op::LTE => {
466                        match (lhsval.borrow().clone(), rhsval.borrow().clone()) {
467                            (Value::Number(f1), Value::Number(f2)) => {
468                                Ok(Rc::new(RefCell::new(Value::Boolean(f1 <= f2))))
469                            },
470                            (_, _) => {
471                                Err(format!("{:?} and {:?} must be same type", lhsval, rhsval))
472                            }
473                        }
474                    },
475                }
476            },
477            Expr::ProcedureCall(procname, arglist) =>  {
478                let value = call_proc(scope.clone(), procname.to_string(), arglist.clone(), output.clone())?;
479                if let Some(value) = value {
480                    Ok(value)
481                } else {
482                    Ok(Rc::new(RefCell::new(Value::Number(-1.0))))
483                }
484            },
485            Expr::List(list) => {
486                let mut list_val: Vec<Rc<RefCell<Value>>> = Vec::new();
487                for vexpr in list.iter() {
488                    // 'vexpr' is the Expr at the list value
489                    let val = vexpr.eval(scope.clone(), output.clone())?;
490                    list_val.push(val)
491                }
492                let l = Rc::new(RefCell::new(list_val));
493                Ok(Rc::new(RefCell::new(Value::List(l))))
494            },
495            Expr::Index(list_ident, index_expr) => {
496                let list_val = scope.borrow().resolve(list_ident.to_string())
497                                    .expect(&format!("List variable {} is not defined", list_ident)).borrow().clone();
498                if let Value::List(list) = list_val {
499                    let index_val = index_expr.eval(scope.clone(), output.clone())?;
500                    if let Value::Number(index) = *index_val.borrow() {
501                        if index.fract() != 0.0 {
502                            return Err(format!("Index {} must be an integer", *index_val.borrow()))
503                        }
504                        match list.borrow().get(index as usize-1) {
505                            Some(val) => return Ok(val.clone()),
506                            None => return Err(format!("List index {} is out of range {:?}", index, list))
507                        };
508                    } else {
509                        return Err(format!("Index {} must be an integer", *index_val.borrow()));
510                    };
511                } else {
512                    return Err(format!("Variable {} must be a list", list_ident))
513                }
514            }
515        }
516    }
517}
518
519pub fn parse_op(pair: Pair<Rule>) -> Op {
520    let op = pair.into_inner().next().unwrap();
521    match op.as_rule() {
522        Rule::neq => Op::NEQ,
523        Rule::eq => Op::EQ,
524        Rule::gt => Op::GT,
525        Rule::lt => Op::LT,
526        Rule::gte => Op::GTE,
527        Rule::lte => Op::LTE,
528        Rule::mult => Op::MULT,
529        Rule::div => Op::DIV,
530        Rule::plus => Op::PLUS,
531        Rule::minus => Op::MINUS,
532        Rule::modop => Op::MOD,
533        _ => { panic!("{:#?} is unknown", op); }
534    }
535}
536
537fn parse_value_inner(val: Pair<Rule>) -> Expr {
538    match val.as_rule() {
539        Rule::procedure_call => {
540            let mut block = val.into_inner();
541            let ident = block.next().unwrap().as_str().to_string();
542            let arg_list: Vec<Expr> = block.next().unwrap().into_inner().map(parse_expr).collect();
543            Expr::ProcedureCall(ident, arg_list)
544        },
545        Rule::number => {
546            let val: f64 = val.as_str().parse().unwrap();
547            Expr::Number(val)
548        },
549        Rule::string => {
550            // get 'inner' value
551            Expr::String(val.into_inner().next().unwrap().as_str().to_string())
552        },
553        Rule::boolean => {
554            Expr::Boolean(val.as_str() == "true")
555        },
556        Rule::identifier => {
557            Expr::Identifier(val.as_str().trim().to_string())
558        },
559        Rule::expression => {
560            parse_expr(val)
561        },
562        Rule::list => {
563            let x: Vec<Expr> = val.into_inner().map(|v| {
564                parse_expr(v)
565            }).collect();
566            Expr::List(x)
567        },
568        Rule::index => {
569            let mut block = val.into_inner();
570            let ident = block.next().unwrap().as_str().to_string();
571            let index = parse_expr(block.next().unwrap());
572            Expr::Index(ident, Box::new(index))
573        },
574        _ => {
575            panic!("UNEXPECTED VALUE parse_value_inner {:?}", val);
576        }
577    }
578}
579
580pub fn parse_value(pair: Pair<Rule>) -> Expr {
581    let mut block = pair.into_inner();
582    let val = block.next().unwrap();
583    match val.as_rule() {
584        Rule::prefix_op => {
585            let inner_val = parse_value_inner(block.next().unwrap());
586            match val.into_inner().next().unwrap().as_rule() {
587                Rule::minus => Expr::Negate(Box::new(inner_val)),
588                Rule::not => Expr::Not(Box::new(inner_val)),
589                _ => unreachable!()
590            }
591        }
592        _ => parse_value_inner(val)
593    }
594}
595
596pub fn parse_expr(pair: Pair<Rule>) -> Expr {
597    match pair.as_rule() {
598        Rule::value => parse_value(pair),
599        Rule::expression => {
600            let mut parts = pair.into_inner();
601            let mut lhs = parse_expr(parts.next().unwrap());
602            while let Some(_) = parts.peek() {
603                let op = parse_op(parts.next().unwrap());
604                let rhs = parse_expr(parts.next().unwrap());
605                lhs = Expr::BinaryExpr(Box::new(lhs), op, Box::new(rhs));
606            }
607            return lhs;
608        },
609        _ => {
610            panic!("other {:?}", pair);
611        }
612    }
613}
614
615pub fn parse_block(block: Pair<Rule>) -> Vec<Instruction> {
616    let mut instructions: Vec<Instruction> = Vec::new();
617    // block -> block_instruction -> match
618    for inst in block.into_inner() {
619        let bi = inst.into_inner().next().unwrap();
620        match bi.as_rule() {
621            Rule::selection_block => {
622                if let Some(sel_block) = parse_selection(bi) {
623                    instructions.push(sel_block);
624                }
625            },
626            Rule::assignment => {
627                let mut block = bi.into_inner();
628                let symbol = block.next().unwrap();
629                block.next(); // consume assign symbol
630                match symbol.as_rule() {
631                    Rule::identifier => {
632                        let ident = symbol.as_str().trim().to_string();
633                        let expr = block.next().unwrap();
634                        instructions.push(Instruction::IdentAssignment(ident, parse_expr(expr)));
635                    },
636                    _ => {
637                        panic!("UNEXPECTED parse_block {:?}", symbol);
638                    }
639                }
640                // .as_str().trim().to_string();
641            },
642            Rule::return_statement => {
643                let expr = parse_expr(bi.into_inner().next().unwrap());
644                instructions.push(Instruction::ReturnStmt(expr));
645            }
646            Rule::display => {
647                let expr = parse_expr(bi.into_inner().next().unwrap());
648                instructions.push(Instruction::DisplayStmt(expr));
649            }
650            _ => {
651                panic!("other {:?}", bi);
652            }
653        }
654    }
655    return instructions;
656}
657
658pub fn parse_selection(sel: Pair<Rule>) -> Option<Instruction> {
659    let inst = sel.into_inner().next().unwrap();
660    match inst.as_rule() {
661        Rule::if_expr => {
662            let mut block = inst.into_inner();
663            let cond_expr = parse_expr(block.next().unwrap());
664            let cond_inst = parse_block(block.next().unwrap());
665            Some(Instruction::IfSelection(cond_expr, cond_inst))
666        },
667        Rule::if_else_expr => {
668            let mut block = inst.into_inner();
669            let cond_expr = parse_expr(block.next().unwrap());
670            let cond_inst = parse_block(block.next().unwrap());
671            let else_inst = parse_block(block.next().unwrap());
672            Some(Instruction::IfElseSelection(cond_expr, cond_inst, else_inst))
673        },
674        _ => { None }
675    }
676}
677
678pub fn parse_prog(prog: &str) -> Result<Program, Error<Rule>> {
679    if let Err(a) = PseudocodeParser::parse(Rule::program, prog) {
680        println!("syntax error at {:?}", a.location);
681        println!("syntax error at line col: {:?}", a.line_col);
682        match a.variant {
683            ErrorVariant::ParsingError{positives, negatives: _} => {
684                println!("positive? {:?}", positives.get(0).unwrap());
685            },
686            ErrorVariant::CustomError{message: _} => {},
687        }
688    };
689
690    let parsed = PseudocodeParser::parse(Rule::program, prog)?;
691    let mut instructions: Vec<Instruction> = Vec::new();
692    for inst in parsed {
693        match inst.as_rule() {
694            Rule::selection_block => {
695                if let Some(sel_block) = parse_selection(inst) {
696                    instructions.push(sel_block);
697                }
698            },
699            Rule::iteration_block => {
700                let block = inst.into_inner().next().unwrap();
701                match block.as_rule() {
702                    Rule::repeat_until => {
703                        let mut ib = block.into_inner();
704                        let expr = parse_expr(ib.next().unwrap());
705                        let inst = parse_block(ib.next().unwrap());
706                        instructions.push(Instruction::RepeatUntilBlock(expr, inst));
707                    },
708                    Rule::repeat_times => {
709                        let mut ib = block.into_inner();
710                        let times = parse_expr(ib.next().unwrap());
711                        let inst = parse_block(ib.next().unwrap());
712                        instructions.push(Instruction::RepeatTimes(times, inst));
713                    },
714                    Rule::for_each => {
715                        let mut ib = block.into_inner();
716                        let ident = ib.next().unwrap().as_str().trim().to_string();
717                        let loopvar = ib.next().unwrap().as_str().trim().to_string(); //parse_expr(ib.next().unwrap());
718                        let inst = parse_block(ib.next().unwrap());
719                        instructions.push(Instruction::ForEach(loopvar, ident, inst));
720                    },
721                    _ => {
722                        panic!("other {:?}", block);
723                    }
724                }
725            },
726            Rule::procedure_def => {
727                let mut block = inst.into_inner();
728                let proc_name = block.next().unwrap().as_str().to_string();
729                let arg_list: Vec<String> = block.next().unwrap().into_inner().map(|pair|
730                    pair.as_str().to_string()
731                ).collect();
732                let proc_list = parse_block(block.next().unwrap());
733                instructions.push(Instruction::ProcedureDef(proc_name, arg_list, proc_list));
734            },
735            Rule::assignment => {
736                let mut block = inst.into_inner();
737                let symbol = block.next().unwrap();
738                block.next(); // consume assign symbol
739                match symbol.as_rule() {
740                    Rule::identifier => {
741                        let ident = symbol.as_str().trim().to_string();
742                        let expr = block.next().unwrap();
743                        instructions.push(Instruction::IdentAssignment(ident, parse_expr(expr)));
744                    },
745                    Rule::index => {
746                        let mut index_sym = symbol.into_inner();
747                        let list_ident = index_sym.next().unwrap().as_str().trim().to_string();
748                        let list_index = index_sym.next().unwrap();
749                        let list_value = block.next().unwrap();
750                        instructions.push(Instruction::IndexAssignment(list_ident, parse_expr(list_index), parse_expr(list_value)));
751                    },
752                    _ => {
753                        panic!("UNEXPECTED parse_block {:?}", symbol);
754                    }
755                }
756            },
757            Rule::display => {
758                let inner = inst.into_inner().next().unwrap();
759                let expr = parse_expr(inner);
760                instructions.push(Instruction::DisplayStmt(expr));
761            }
762            Rule::expression => {
763                let inner = inst.into_inner().next().unwrap().into_inner().next().unwrap();
764                match inner.as_rule() {
765                    Rule::procedure_call => {
766                        let mut call = inner.into_inner();
767                        let ident = call.next().unwrap().as_str().trim().to_string();
768                        let arg_list: Vec<Expr> = call.next().unwrap().into_inner().map(parse_expr).collect();
769                        instructions.push(Instruction::ProcedureCall(ident, arg_list));
770                    },
771                    _ => {}
772                }
773            },
774            _ => {}
775        }
776    }
777    Ok(Program::new(instructions))
778}
779
780//TODO: return value
781fn run_instructions(instructions: Vec<Instruction>, scope: Rc<RefCell<Scope>>, output: Rc<RefCell<String>>) -> Result<Option<Rc<RefCell<Value>>>, String> {
782    let mut return_value: Option<Rc<RefCell<Value>>> = None;
783    for instruction in instructions.iter() {
784        match instruction {
785            Instruction::ProcedureDef(name, arglist, block) => {
786                scope.borrow_mut().define_proc(name.to_string(), arglist.to_vec(), block.to_vec());
787            },
788            Instruction::RepeatUntilBlock(expr, block) => {
789                loop {
790                    if let Value::Boolean(doloop) = *expr.eval(scope.clone(), output.clone())?.borrow() {
791                        if !doloop {
792                            run_instructions(block.to_vec(), scope.clone(), output.clone())?;
793                        } else {
794                            break
795                        }
796                    }
797                }
798            },
799            Instruction::RepeatTimes(expr, block) => {
800                if let Value::Number(ntimes) = *expr.eval(scope.clone(), output.clone())?.borrow() {
801                    for _ in 0..(ntimes as u64) {
802                        run_instructions(block.to_vec(), scope.clone(), output.clone())?;
803                    }
804                }
805            },
806            // TODO: ForEach
807            Instruction::ForEach(list_ident, loopvar, block) => {
808                if let Value::List(list) = scope.borrow().resolve(list_ident.to_string())
809                                    .expect(&format!("List variable {} is not defined", list_ident)).borrow().clone() {
810
811                    for item in list.borrow().iter() {
812                        let loop_scope = Rc::new(RefCell::new(Scope::new(scope.clone())));
813                        loop_scope.borrow_mut().variables.insert(loopvar.to_string(), item.clone());
814                        run_instructions(block.to_vec(), loop_scope, output.clone())?;
815                    }
816                }
817
818            },
819            Instruction::IfSelection(cond, block) => {
820                if let Value::Boolean(expr) = *cond.eval(scope.clone(), output.clone())?.borrow() {
821                    // if boolean expression is true
822                    if expr {
823                        return_value = run_instructions(block.to_vec(), scope.clone(), output.clone())?;
824                    }
825                }
826            },
827            Instruction::IfElseSelection(cond, block, elseblock) => {
828                if let Value::Boolean(expr) = *cond.eval(scope.clone(), output.clone())?.borrow() {
829                    // if boolean expression is true
830                    if expr {
831                        return_value = run_instructions(block.to_vec(), scope.clone(), output.clone())?;
832                    } else {
833                        return_value = run_instructions(elseblock.to_vec(), scope.clone(), output.clone())?;
834                    }
835                }
836            },
837            Instruction::ProcedureCall(procname, arglist) => {
838                return_value = call_proc(scope.clone(), procname.to_string(), arglist.clone(), output.clone())?;
839            }
840            Instruction::DisplayStmt(expr) => {
841                let value = expr.eval(scope.clone(), output.clone())?;
842                match write!(&mut output.borrow_mut(), "{} ", *value.borrow()) {
843                    Err(e) => panic!("Could not print to output: {}", e),
844                    _ => {}
845                };
846            },
847            Instruction::IdentAssignment(ident, expr) => {
848                let value = expr.eval(scope.clone(), output.clone())?;
849                scope.borrow_mut().assign(ident.to_string(), value);
850            },
851            Instruction::IndexAssignment(list_ident, list_index, list_value) => {
852                let list_val = scope.borrow().resolve(list_ident.to_string())
853                                    .expect(&format!("List variable {} is not defined", list_ident));
854                //let mut val = list_val.borrow_mut();
855                if let Value::List(list) = list_val.borrow().clone() {
856                    let index_val = list_index.eval(scope.clone(), output.clone())?;
857                    if let Value::Number(index) = *index_val.borrow() {
858                        if index.fract() != 0.0 {
859                            return Err(format!("Index {} must be an integer", index))
860                        }
861                        if (index) < 1.0 || (index as usize) > list.borrow().len() {
862                            return Err(format!("Index {} is out of range", index))
863                        }
864                        let value = list_value.eval(scope.clone(), output.clone())?;
865                        list.borrow_mut()[index as usize - 1] = value;
866                        // assign the new list to the original identifier
867                        let l = Rc::new(RefCell::new(Value::List(list)));
868                        scope.borrow_mut().assign(list_ident.to_string(), l);
869                    };
870                };
871            },
872            Instruction::ReturnStmt(expr) => {
873                let value = expr.eval(scope.clone(), output.clone())?;
874                return_value = Some(value);
875            }
876        }
877    }
878    Ok(return_value)
879}
880
881pub fn eval(prog: &str) -> Result<String, String> {
882    let output = Rc::new(RefCell::new(String::new()));
883    match parse_prog(prog) {
884        Ok(program) => {
885            let scope = Rc::new(RefCell::new(Scope::new_base_scope()));
886            run_instructions(program.instructions, scope.clone(), output.clone())?;
887            //(*scope.borrow()).dump();
888            Ok(output.borrow().to_string())
889        },
890        Err(err) => Err(format!("Parse Error: {}", err.to_string()))
891    }
892}
893
894pub fn eval_file(filename: &str) -> Result<String, String> {
895    let mut file = File::open(filename).expect("Problem opening file");
896    let mut prog = String::new();
897    file.read_to_string(&mut prog).expect("Problem reading file");
898    eval(&prog)
899}
900
901#[cfg(test)]
902mod tests {
903    use super::*;
904    use pest::parses_to;
905
906    macro_rules! map(
907        { $($key:expr => $value:expr),+ } => {
908            {
909                let mut m = ::std::collections::HashMap::new();
910                $(
911                    m.insert($key, $value);
912                )+
913                m
914            }
915         };
916    );
917
918    #[test]
919    fn test_parse() {
920        let success = PseudocodeParser::parse(Rule::program, "abc ← 3.0").unwrap();
921        println!("{:?}", success);
922    }
923
924    #[test]
925    fn test_parse_binary_expr() {
926        let success = PseudocodeParser::parse(Rule::expression, "(3 * 2) < (4 * 10.3)").unwrap();
927        println!("{:?}", success);
928    }
929
930    #[test]
931    fn test_parse_assignment_expr() {
932        let success = PseudocodeParser::parse(Rule::expression, "a ← 1 + 2").unwrap();
933        println!("{:#?}", success);
934    }
935
936    #[test]
937    fn test_file_output() -> Result<(), String> {
938        let file_output = map!(
939            "test_programs/assignment.ap" => "a is 3 b is 10.5 string_val is hello",
940            "test_programs/expr.ap" => "1 2 3 4 5 6 7 8 9 10",
941            "test_programs/loops.ap" => "1 2 3 x is even 2 x is odd 3 x is even 4 x is odd 5",
942            "test_programs/procedure.ap" => "inside did func work? true",
943            "test_programs/negate.ap" => "-1 -3 -6 -6 false true false true",
944            "test_programs/ops.ap" => "true false true",
945            "test_programs/list.ap" => "[] [1, 2, 3] [abc, def] [[1, 2, 3], [4, 5, 6]] [2, 7, 17.5]",
946            "test_programs/list2.ap" => "[1, 2, 3] [a, 1, 2, 3] [a, 1, b, 2, 3]",
947            "test_programs/recursion.ap" => "1 720"
948        );
949        for (file, expected_output) in file_output.iter() {
950            let output = eval_file(file).unwrap().trim().to_string();
951            assert!(output.eq(expected_output))
952        }
953        Ok(())
954    }
955
956    #[test]
957    fn test_parses_to() {
958        parses_to! {
959            parser: PseudocodeParser,
960            input: "my_variable",
961            rule: Rule::identifier,
962            tokens: [identifier(0, 11)]
963        }
964
965        parses_to! {
966            parser: PseudocodeParser,
967            input: "\"hello world\"",
968            rule: Rule::string,
969            tokens: [string(0, 13, [inner(1, 12)])]
970        }
971    }
972}