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
This commit is contained in:
Daniel M 2021-12-24 02:25:27 +01:00
parent 6bd58a4ecb
commit 623fa71355
3 changed files with 104 additions and 5 deletions

View File

@ -4,9 +4,9 @@ use plang2_lib::*;
fn main() { fn main() {
let code = r#" let code = r#"
a = 54 * 3; let a = 5 * 3;
b = 5; let b = 5;
print("{}", a + b); (a + b * 3) / 5;
"#; "#;
let mut lexer = Lexer::new(code); let mut lexer = Lexer::new(code);
@ -16,8 +16,12 @@ fn main() {
println!("Tokens: \n{}\n", tokens); println!("Tokens: \n{}\n", tokens);
let mut parser = Parser::new(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();
} }

View File

@ -0,0 +1,93 @@
use std::collections::HashMap;
use crate::{ast::{Statement, Expr}, token::Literal};
pub struct Interpreter {
prog: Vec<Statement>,
// TODO: Those varibales are global only, so this will have to change with functions. Also Literal is reused as variable type
variables: HashMap<String, Literal>,
// Print expression statements to stdout
debug: bool,
}
impl Interpreter {
pub fn new(prog: Vec<Statement>) -> 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
}
}
}
}
}
}

View File

@ -2,6 +2,8 @@ pub mod token;
pub mod lexer; pub mod lexer;
pub mod ast; pub mod ast;
pub mod parser; pub mod parser;
pub mod interpreter;
pub use lexer::Lexer; pub use lexer::Lexer;
pub use parser::Parser; pub use parser::Parser;
pub use interpreter::Interpreter;