diff --git a/.vscode/settings.json b/.vscode/settings.json index 4aa9c42..c94e86d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "cSpell.words": ["Peekable"] + "cSpell.words": ["binop", "Peekable"] } diff --git a/src/frontend.rs b/src/frontend.rs deleted file mode 100644 index b77d9b4..0000000 --- a/src/frontend.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::process; - -use crate::parser::Parser; - -pub fn repl() { - // Read-Eval-Print Loop - use std::io::{self, Write}; - - println!("Welcome to the Riv Lang REPL! Type 'exit' to quit."); - - loop { - print!("> "); - io::stdout().flush().unwrap(); - - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - - let input = input.trim().to_string(); - - if input == "exit" { - process::exit(0); - } - - let program = Parser::new(input).produce_ast(); - - println!("{:#?}", program); - } -} diff --git a/src/ast.rs b/src/frontend/ast.rs similarity index 100% rename from src/ast.rs rename to src/frontend/ast.rs diff --git a/src/lexer.rs b/src/frontend/lexer.rs similarity index 100% rename from src/lexer.rs rename to src/frontend/lexer.rs diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs new file mode 100644 index 0000000..483656f --- /dev/null +++ b/src/frontend/mod.rs @@ -0,0 +1,3 @@ +pub mod ast; +pub mod lexer; +pub mod parser; diff --git a/src/parser.rs b/src/frontend/parser.rs similarity index 100% rename from src/parser.rs rename to src/frontend/parser.rs diff --git a/src/main.rs b/src/main.rs index df799c8..61cf11f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,39 @@ use clap::Parser; +use std::process; -mod ast; mod frontend; -mod lexer; -mod parser; +use frontend::ast; +use frontend::lexer; +use frontend::parser; + +mod runtime; +use runtime::interpreter::evaluate; + +pub fn repl() { + // Read-Eval-Print Loop + use std::io::{self, Write}; + + println!("Welcome to the Riv Lang REPL! Type 'exit' to quit."); + + loop { + print!("> "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + + let input = input.trim().to_string(); + + if input == "exit" { + process::exit(0); + } + + let program = parser::Parser::new(input).produce_ast(); + + let result = evaluate(frontend::ast::NodeType::Program(program)); + println!("{:#?}", result); + } +} #[derive(clap::Parser)] struct CLI { @@ -20,7 +50,7 @@ fn main() -> Result<(), Box> { let cli = CLI::parse(); if cli.repl { - frontend::repl(); + repl(); } else if let Some(file_path) = cli.file { let source_code = std::fs::read_to_string(file_path)?; let mut parser = parser::Parser::new(source_code); diff --git a/src/runtime/interpreter.rs b/src/runtime/interpreter.rs new file mode 100644 index 0000000..f07cd73 --- /dev/null +++ b/src/runtime/interpreter.rs @@ -0,0 +1,61 @@ +use std::process; + +use crate::frontend::ast::{BinaryExpr, NodeType, Program}; +use crate::runtime::values::ValueType; + +fn eval_program(program: Program) -> ValueType { + // Initialize with your equivalent of NullVal + let mut last_evaluated = ValueType::Null; + + // Iterate through each statement in the program body + for statement in program.body { + last_evaluated = evaluate(statement); + } + + last_evaluated +} + +fn eval_binop(binop: BinaryExpr) -> ValueType { + let lhs = evaluate(*binop.left); + let rhs = evaluate(*binop.right); + + match (&lhs, &rhs) { + (ValueType::Number(l), ValueType::Number(r)) => eval_num_binop(*l, *r, binop.operator), + _ => ValueType::Null, + } +} + +fn eval_num_binop(lhs: f64, rhs: f64, operator: String) -> ValueType { + let result: f64; + + match operator.as_str() { + "+" => result = lhs + rhs, + "-" => result = lhs - rhs, + "*" => result = lhs * rhs, + // TODO: Handle division by zero + "/" => result = lhs / rhs, + "%" => result = lhs % rhs, + _ => { + eprintln!("Unknown operator: {}", operator); + process::exit(1); + } + } + + ValueType::Number(result) +} + +pub fn evaluate(node: NodeType) -> ValueType { + match node { + NodeType::NumericLiteral(n) => ValueType::Number(n.value), + NodeType::NullLiteral(_) => ValueType::Null, + NodeType::BinaryExpr(e) => eval_binop(e), + NodeType::Program(p) => eval_program(p), + _ => { + eprintln!( + "Evaluation for node type {:#?} is not implemented yet.", + node + ); + process::exit(1); + } + } +} diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs new file mode 100644 index 0000000..27bd8a9 --- /dev/null +++ b/src/runtime/mod.rs @@ -0,0 +1,2 @@ +pub mod interpreter; +pub mod values; diff --git a/src/runtime/values.rs b/src/runtime/values.rs new file mode 100644 index 0000000..b4f5be7 --- /dev/null +++ b/src/runtime/values.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Clone, PartialEq)] +pub enum ValueType { + Null, + Number(f64), +}