From 520357d9309d0aade5355788e8bae3f520e18a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vili=20Sinerv=C3=A4?= Date: Mon, 3 Feb 2025 16:35:06 +0200 Subject: [PATCH] Add initial interpreter functionality (missing vars and funcs) --- src/compiler.rs | 18 +++++ src/compiler/interpreter.rs | 74 ++++++++++++++++++ src/compiler/value.rs | 151 ++++++++++++++++++++++++++++++++++++ src/main.rs | 12 ++- 4 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/compiler/interpreter.rs create mode 100644 src/compiler/value.rs diff --git a/src/compiler.rs b/src/compiler.rs index 8be1603..e1c84c1 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,9 +1,27 @@ +use std::io; + +use interpreter::interpret; +use parser::parse; +use tokenizer::tokenize; + mod ast; +mod interpreter; mod parser; mod token; mod tokenizer; +mod value; pub fn compile(code: &str) { let tokens = tokenizer::tokenize(code); parser::parse(&tokens); } + +pub fn start_interpreter() { + let lines = io::stdin().lines(); + + for line in lines { + if let Ok(code) = line { + println!("{}", interpret(&parse(&tokenize(&code)))); + } + } +} diff --git a/src/compiler/interpreter.rs b/src/compiler/interpreter.rs new file mode 100644 index 0000000..23e9750 --- /dev/null +++ b/src/compiler/interpreter.rs @@ -0,0 +1,74 @@ +use crate::compiler::{ + ast::Expression::{self, *}, + value::Value, +}; + +#[expect(unused_variables)] +pub fn interpret(ast: &Expression) -> Value { + match ast { + EmptyLiteral(_) => Value::None(), + IntLiteral(_, val) => Value::Int(*val), + BoolLiteral(_, val) => Value::Bool(*val), + Identifier(_, _) => todo!(), // Variables are TODO + UnaryOp(_, op, expr) => match *op { + "-" => -interpret(expr), + "not" => !interpret(expr), + _ => panic!("Unrecognized unary op {}", op), + }, + BinaryOp(_, left, op, right) => match *op { + "+" => interpret(left) + interpret(right), + "*" => interpret(left) * interpret(right), + "-" => interpret(left) - interpret(right), + "/" => interpret(left) / interpret(right), + "%" => interpret(left) % interpret(right), + "==" => Value::Bool(interpret(left) == interpret(right)), + "!=" => Value::Bool(interpret(left) != interpret(right)), + "<" => Value::Bool(interpret(left) < interpret(right)), + "<=" => Value::Bool(interpret(left) <= interpret(right)), + ">" => Value::Bool(interpret(left) > interpret(right)), + ">=" => Value::Bool(interpret(left) >= interpret(right)), + "and" => interpret(left).and(&interpret(right)), + "or" => interpret(left).or(&interpret(right)), + "=" => todo!(), // Variables are TODO + _ => panic!("Unrecognized binary op {}", op), + }, + VarDeclaration(_, name, expr) => todo!(), // Variables are TODO + Conditional(_, condition_expr, then_expr, else_expr) => { + if let Value::Bool(condition) = interpret(condition_expr) { + if condition { + interpret(then_expr) + } else if let Some(expr) = else_expr { + interpret(expr) + } else { + Value::None() + } + } else { + panic!("Non-bool as if-then-else condition!"); + } + } + While(_, condition, do_expr) => { + let mut val = Value::None(); + loop { + let condition = interpret(condition); + if let Value::Bool(cond) = condition { + if cond { + val = interpret(do_expr); + } else { + break; + } + } else { + panic!("Non-boon as while-do condition!"); + } + } + val + } + FunCall(_, name, args) => todo!(), // Functions are TODO + Block(_, expressions) => { + let mut val = Value::None(); + for expression in expressions { + val = interpret(expression); + } + val + } + } +} diff --git a/src/compiler/value.rs b/src/compiler/value.rs new file mode 100644 index 0000000..f1269da --- /dev/null +++ b/src/compiler/value.rs @@ -0,0 +1,151 @@ +use std::{ + fmt, + ops::{Add, Div, Mul, Neg, Not, Rem, Sub}, +}; + +#[derive(PartialEq, PartialOrd, Debug)] +pub enum Value { + Int(i64), + Bool(bool), + None(), +} + +impl Value { + pub fn and(&self, other: &Self) -> Self { + if let Value::Bool(val1) = self { + if let Value::Bool(val2) = other { + Value::Bool(*val1 && *val2) + } else { + panic!("Can't apply and to non-bools!") + } + } else { + panic!("Can't apply and to non-bools!!") + } + } + + pub fn or(&self, other: &Self) -> Self { + if let Value::Bool(val1) = self { + if let Value::Bool(val2) = other { + Value::Bool(*val1 || *val2) + } else { + panic!("Can't apply or to non-bools!") + } + } else { + panic!("Can't apply or to non-bools!!") + } + } +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Value::Int(val) => write!(f, "{}", val), + Value::Bool(val) => write!(f, "{}", val), + Value::None() => write!(f, ""), + } + } +} + +impl Add for Value { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + if let Value::Int(val1) = self { + if let Value::Int(val2) = other { + Value::Int(val1 + val2) + } else { + panic!("Can't apply + to non-ints!") + } + } else { + panic!("Can't apply + to non-ints!") + } + } +} + +impl Mul for Value { + type Output = Self; + + fn mul(self, other: Self) -> Self::Output { + if let Value::Int(val1) = self { + if let Value::Int(val2) = other { + Value::Int(val1 * val2) + } else { + panic!("Can't apply * to non-ints!") + } + } else { + panic!("Can't apply * to non-ints!") + } + } +} + +impl Sub for Value { + type Output = Self; + + fn sub(self, other: Self) -> Self::Output { + if let Value::Int(val1) = self { + if let Value::Int(val2) = other { + Value::Int(val1 - val2) + } else { + panic!("Can't apply - to non-ints!") + } + } else { + panic!("Can't apply - to non-ints!") + } + } +} + +impl Div for Value { + type Output = Self; + + fn div(self, other: Self) -> Self::Output { + if let Value::Int(val1) = self { + if let Value::Int(val2) = other { + Value::Int(val1 / val2) + } else { + panic!("Can't apply / to non-ints!") + } + } else { + panic!("Can't apply / to non-ints!") + } + } +} + +impl Rem for Value { + type Output = Self; + + fn rem(self, other: Self) -> Self::Output { + if let Value::Int(val1) = self { + if let Value::Int(val2) = other { + Value::Int(val1 % val2) + } else { + panic!("Can't apply % to non-ints!") + } + } else { + panic!("Can't apply % to non-ints!") + } + } +} + +impl Neg for Value { + type Output = Self; + + fn neg(self) -> Self::Output { + if let Value::Int(val) = self { + Value::Int(-val) + } else { + panic!("Can't apply - to non-ints!") + } + } +} + +impl Not for Value { + type Output = Self; + + fn not(self) -> Self::Output { + if let Value::Bool(val) = self { + Value::Bool(!val) + } else { + panic!("Can't apply ! to non-bools!") + } + } +} diff --git a/src/main.rs b/src/main.rs index 723e96d..3d6985d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,16 @@ +use std::env; + mod compiler; mod server; fn main() { - server::start("::".parse().unwrap(), 3000); + let args: Vec = env::args().collect(); + + if let Some(flag) = args.get(1) { + if flag == "-i" { + compiler::start_interpreter(); + } + } else { + server::start("::".parse().unwrap(), 3000); + } }