From 623fa71355288861126f83352f46edc8b5b713cb Mon Sep 17 00:00:00 2001 From: Daniel M Date: Fri, 24 Dec 2021 02:25:27 +0100 Subject: [PATCH] Add simple and very rough interpreter - Implemented an interpreter that - Only works with int64 values - Executes maths expressions - Declares and assigns variables in global table - Can use variables in expressions - Debug prints expression only statements - Can NOT use, or declare functions --- plang2/src/main.rs | 14 ++++-- plang2_lib/src/interpreter.rs | 93 +++++++++++++++++++++++++++++++++++ plang2_lib/src/lib.rs | 2 + 3 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 plang2_lib/src/interpreter.rs diff --git a/plang2/src/main.rs b/plang2/src/main.rs index 3e10da8..a0d270f 100644 --- a/plang2/src/main.rs +++ b/plang2/src/main.rs @@ -4,9 +4,9 @@ use plang2_lib::*; fn main() { let code = r#" - a = 54 * 3; - b = 5; - print("{}", a + b); + let a = 5 * 3; + let b = 5; + (a + b * 3) / 5; "#; let mut lexer = Lexer::new(code); @@ -16,8 +16,12 @@ fn main() { println!("Tokens: \n{}\n", tokens); let mut parser = Parser::new(tokens); - let expr = parser.parse().unwrap(); + let prog = parser.parse().unwrap(); - println!("{:#?}", expr); + println!("{:#?}\n\n", prog); + + let mut interpreter = Interpreter::new(prog); + + interpreter.run(); } diff --git a/plang2_lib/src/interpreter.rs b/plang2_lib/src/interpreter.rs new file mode 100644 index 0000000..c4a0870 --- /dev/null +++ b/plang2_lib/src/interpreter.rs @@ -0,0 +1,93 @@ +use std::collections::HashMap; + +use crate::{ast::{Statement, Expr}, token::Literal}; + +pub struct Interpreter { + prog: Vec, + + // TODO: Those varibales are global only, so this will have to change with functions. Also Literal is reused as variable type + variables: HashMap, + + // Print expression statements to stdout + debug: bool, +} + +impl Interpreter { + pub fn new(prog: Vec) -> Self { + let variables = Default::default(); + Self { prog, variables, debug: true } + } + + pub fn run(&mut self) { + + for idx in 0..self.prog.len() { + self.execute_stmt(idx); + } + + } + + pub fn execute_stmt(&mut self, idx: usize) { + + // TODO: The clone here is not optimal + match self.prog[idx].clone() { + Statement::Expr(expr) => { + let expr_result = self.execute_expr(expr.clone()); + if self.debug { + println!("{:?}", expr_result); + } + } + Statement::LetBinding(var_name, expr) => { + let rhs = self.execute_expr(expr); + self.variables.insert(var_name, rhs); + } + Statement::Assignment(var_name, expr) => { + let rhs = self.execute_expr(expr); + *self.variables.get_mut(&var_name).expect("Assigning variable before declaration") = rhs; + }, + } + } + + fn execute_expr(&mut self, expr: Expr) -> Literal { + match expr { + Expr::Literal(lit) => lit, + Expr::Variable(name) => self.variables.get(&name).expect("Using variable before declaration").clone(), + Expr::FnCall(_) => todo!(), + Expr::BinOp(bot, lhs, rhs) => { + + let lhs = match self.execute_expr(*lhs) { + Literal::Int64(val) => val, + _ => panic!("Binary operators for non i64 not yet implemented") + }; + let rhs = match self.execute_expr(*rhs) { + Literal::Int64(val) => val, + _ => panic!("Binary operators for non i64 not yet implemented") + }; + + let res = match bot { + crate::ast::BinOpType::Add => lhs + rhs, + crate::ast::BinOpType::Sub => lhs - rhs, + crate::ast::BinOpType::Mul => lhs * rhs, + crate::ast::BinOpType::Div => lhs / rhs, + crate::ast::BinOpType::Mod => lhs % rhs, + }; + + Literal::Int64(res) + } + Expr::UnOp(uot, expr) => { + match uot { + crate::ast::UnOpType::Neg => { + let mut res = self.execute_expr(*expr); + match &mut res { + Literal::Boolean(_) => panic!("Can't negate bool"), + Literal::Int64(val) => *val *= -1, + Literal::String(_) => panic!("Can't negate string"), + }; + + res + } + } + } + } + } + +} diff --git a/plang2_lib/src/lib.rs b/plang2_lib/src/lib.rs index c974b80..fc3a712 100644 --- a/plang2_lib/src/lib.rs +++ b/plang2_lib/src/lib.rs @@ -2,6 +2,8 @@ pub mod token; pub mod lexer; pub mod ast; pub mod parser; +pub mod interpreter; pub use lexer::Lexer; pub use parser::Parser; +pub use interpreter::Interpreter;