diff --git a/.kdev4/fddl.kdev4 b/.kdev4/fddl.kdev4 deleted file mode 100644 index 77a959d..0000000 --- a/.kdev4/fddl.kdev4 +++ /dev/null @@ -1,5 +0,0 @@ -[Buildset] -BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x08\x00f\x00d\x00d\x00l) - -[Project] -VersionControlSupport=kdevgit diff --git a/src/interpreter/evaluator.rs b/src/interpreter/evaluator.rs new file mode 100644 index 0000000..b2a9941 --- /dev/null +++ b/src/interpreter/evaluator.rs @@ -0,0 +1,195 @@ +use crate::parser::ast::{Expression, Statement, Literal, Operator}; + +#[derive(Debug, Clone, PartialEq)] +pub enum FddlValue { + Number(f64), + Boolean(bool), + String(String), + Nil, +} + +impl std::fmt::Display for FddlValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FddlValue::Number(n) => write!(f, "{}", n), + FddlValue::Boolean(b) => write!(f, "{}", b), + FddlValue::String(s) => write!(f, "{}", s), + FddlValue::Nil => write!(f, "nil"), + } + } +} + +#[derive(Debug)] +pub enum RuntimeError { + TypeMismatch(String), + UndefinedVariable(String), +} + +pub struct Evaluator; + +impl Evaluator { + pub fn new() -> Self { + Evaluator + } + + pub fn evaluate_program(&mut self, statements: Vec) -> Result<(), RuntimeError> { + for statement in statements { + self.evaluate_statement(&statement)?; + } + Ok(()) + } + + fn evaluate_statement(&mut self, statement: &Statement) -> Result<(), RuntimeError> { + match statement { + Statement::PrintStatement(expr) => { + let value = self.evaluate_expression(expr)?; + println!("{}", value); + } + + Statement::ExpressionStatement(expr) => { + self.evaluate_expression(expr)?; + } + + _ => { + println!("Interpreter: Skipping unimplemented statement: {:?}", statement); + } + } + Ok(()) + } + + fn evaluate_expression(&mut self, expression: &Expression) -> Result { + match expression { + Expression::Literal(literal) => { + match literal { + Literal::Number(n) => Ok(FddlValue::Number(*n)), + Literal::Boolean(b) => Ok(FddlValue::Boolean(*b)), + Literal::String(s) => Ok(FddlValue::String(s.clone())), + Literal::Nil => Ok(FddlValue::Nil), + } + } + + Expression::Unary(op, right_expr) => { + let right_val = self.evaluate_expression(right_expr)?; + match op { + Operator::Minus => { + if let FddlValue::Number(n) = right_val { + Ok(FddlValue::Number(-n)) + } else { + Err(RuntimeError::TypeMismatch( + "Operand for unary '-' must be a number.".to_string(), + )) + } + } + Operator::Not => { + if let FddlValue::Boolean(b) = right_val { + Ok(FddlValue::Boolean(!b)) + } else { + Err(RuntimeError::TypeMismatch( + "Operand for 'not' must be a boolean.".to_string(), + )) + } + } + Operator::Some => { + Ok(right_val) + } + Operator::Almost => { + if let FddlValue::Number(n) = right_val { + Ok(FddlValue::Number(n.round())) + } else { + Err(RuntimeError::TypeMismatch( + "Operand for unary '~' (Almost) must be a number for this example.".to_string(), + )) + } + } + _ => Err(RuntimeError::TypeMismatch(format!( + "Unsupported unary operator {:?}.", + op + ))), + } + } + + Expression::Binary(left_expr, op, right_expr) => { // Add this new arm + let left_val = self.evaluate_expression(left_expr)?; + let right_val = self.evaluate_expression(right_expr)?; + + // Now, perform the operation based on 'op' and the types of left_val and right_val + match op { + Operator::Plus => { + // Example for addition (assuming numbers for now) + if let (FddlValue::Number(l), FddlValue::Number(r)) = (&left_val, &right_val) { + Ok(FddlValue::Number(l + r)) + } else { + // Later, you might allow string concatenation here + Err(RuntimeError::TypeMismatch( + format!("Operands for '+' must be numbers. Got {:?} and {:?}", left_val, right_val) + )) + } + } + Operator::Minus => { // Binary Minus + if let (FddlValue::Number(l), FddlValue::Number(r)) = (&left_val, &right_val) { + Ok(FddlValue::Number(l - r)) + } else { + Err(RuntimeError::TypeMismatch( + format!("Operands for '-' must be numbers. Got {:?} and {:?}", left_val, right_val) + )) + } + } + Operator::Multiply => { + if let (FddlValue::Number(l), FddlValue::Number(r)) = (&left_val, &right_val) { + Ok(FddlValue::Number(l * r)) + } else { + Err(RuntimeError::TypeMismatch( + format!("Operands for '*' must be numbers. Got {:?} and {:?}", left_val, right_val) + )) + } + } + Operator::Divide => { + if let (FddlValue::Number(l), FddlValue::Number(r)) = (&left_val, &right_val) { + if *r == 0.0 { + Err(RuntimeError::TypeMismatch("Division by zero.".to_string())) // Or a specific DivisionByZero error + } else { + Ok(FddlValue::Number(l / r)) + } + } else { + Err(RuntimeError::TypeMismatch( + format!("Operands for '/' must be numbers. Got {:?} and {:?}", left_val, right_val) + )) + } + } + Operator::Modulus => { // Assuming you have Operator::Modulus from earlier + if let (FddlValue::Number(l), FddlValue::Number(r)) = (&left_val, &right_val) { + if *r == 0.0 { + Err(RuntimeError::TypeMismatch("Modulus by zero.".to_string())) + } else { + Ok(FddlValue::Number(l % r)) + } + } else { + Err(RuntimeError::TypeMismatch( + format!("Operands for '%' must be numbers. Got {:?} and {:?}", left_val, right_val) + )) + } + } + // TODO: Add cases for Operator::Greater, Less, EqualEqual, NotEqual, And, Or etc. + // These will typically operate on numbers or booleans and produce FddlValue::Boolean. + _ => Err(RuntimeError::TypeMismatch(format!( + "Unsupported binary operator {:?}.", + op + ))), + } + } + + Expression::Grouping(inner_expr) => { + self.evaluate_expression(inner_expr) + } + + _ => { + println!("Interpreter: Unimplemented expression: {:?}", expression); + Err(RuntimeError::TypeMismatch(format!( + "Unimplemented expression type: {:?}", + expression + ))) + } + } + } + +} \ No newline at end of file diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs new file mode 100644 index 0000000..901b758 --- /dev/null +++ b/src/interpreter/mod.rs @@ -0,0 +1 @@ +pub mod evaluator; \ No newline at end of file diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index e5f92d4..6340169 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -269,6 +269,7 @@ impl Lexer { "else" => Token::Else, "true" => Token::True, "false" => Token::False, + "nil" => Token::Nil, "let" => Token::Let, "const" => Token::Const, "func" => Token::Func, diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 18ff0d2..ff2ec97 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -35,6 +35,7 @@ pub enum Token { Else, True, False, + Nil, Let, Const, Func, diff --git a/src/lib.rs b/src/lib.rs index 50e73f0..7f2ef03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod lexer; pub mod parser; -pub mod compiler; \ No newline at end of file +pub mod compiler; +pub mod interpreter; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 601eaa5..d9e7bde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,9 +6,9 @@ use std::env; use std::fs; use std::io::{self, Write}; -// use lexer::Lexer; use fddl::lexer::Lexer; use fddl::parser::Parser; +use fddl::interpreter::evaluator::Evaluator; fn main() { let args: Vec = env::args().collect(); @@ -23,7 +23,8 @@ fn main() { // basic REPL fn run_repl() { - println!("fddl repl"); + println!("FDDL REPL"); + println!("---------"); loop { print!("fddl % "); io::stdout().flush().unwrap(); @@ -45,45 +46,40 @@ fn run_file(path: &str) { run(source); } -// runs source code fn run(source: String) { - println!("Source: {}", source.trim()); // prints source for debugging + println!("Source: {}", source.trim()); let mut lexer = Lexer::new(source); let tokens = lexer.scan_tokens(); - // old code begins - // println!("Tokens:"); - // for token in &tokens { // Iterate by reference if you use tokens later - // println!("{:?}", token); - // } - // println!("---"); - // old code ends - delete if not needed + println!("Tokens: {:?}", tokens); - let mut parser = Parser::new(tokens); // Create a new parser instance - let ast_statements = parser.parse_program(); // NEW! - - println!("Parsed Statements (AST):"); - - for stmt in ast_statements { - println!("{:?}", stmt); - } + let mut parser = Parser::new(tokens); - loop { + let program_ast = parser.parse_program(); - if parser.is_at_end() { - break; + if !program_ast.is_empty() { + println!("Parsed Statements (AST):"); + for stmt in &program_ast { + println!("{:?}", stmt); } - - match parser.parse_statement() { - Some(statement) => { - println!("{:?}", statement); - } - None => { - println!("Parser returned None, might be an error or unhandled EOF by parse_statement."); - break; - } - } - + } else { + println!("No AST generated or parsing failed."); } + + + if !program_ast.is_empty() { + println!("Output:"); + let mut evaluator = Evaluator::new(); + match evaluator.evaluate_program(program_ast) { + Ok(()) => { /* Program executed successfully */ } + Err(e) => { + eprintln!("Runtime Error: {:?}", e); + } + } + } else { + println!("Skipping execution."); + } + + println!("---"); } \ No newline at end of file diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 1319f5a..cc6df3c 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -67,4 +67,8 @@ pub enum Statement { body: Vec, }, ReturnStatement(Option), + Assignment { + target_name: String, + value: Expression, + }, } \ No newline at end of file diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 37057c2..9ba374a 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -17,57 +17,46 @@ impl Parser { } } - /* fn parse_for_statement(&mut self) -> Option { - if !self.match_token(Token::LeftParen) { - eprintln!("Error: Expected '(' after 'for'."); - return None; - } + // fn parse_expression_statement(&mut self) -> Option { + // let expr = self.parse_expression()?; + // if self.match_token(Token::Semicolon) { + // Some(Statement::ExpressionStatement(expr)) + // } else { + // eprintln!("Error: Expected ';' after expression statement."); + // None + // } + // } - let initializer = if self.match_token(Token::Semicolon) { - None - } else if self.match_token(Token::Let) { - Some(Box::new(self.parse_variable_declaration()?)) - } else { - let expr_stmt = self.parse_expression_statement()?; - Some(Box::new(expr_stmt)) - }; - let condition = if self.check(&Token::Semicolon) { - eprintln!("Error: For loop condition is required (for now)."); - return None; - } else { - self.parse_expression()? - }; + fn parse_assignment_or_expression_statement(&mut self) -> Option { + let expr = self.parse_expression()?; - if !self.match_token(Token::Semicolon) { - eprintln!("Error: Expected ';' after for loop condition."); - return None; - } + self.skip_comments(); // Skip comments before semicolon - let increment = if self.check(&Token::RightParen) { - None - } else { - Some(self.parse_expression()?) - }; + if self.check(&Token::Equal) { + self.advance(); - if !self.match_token(Token::RightParen) { - eprintln!("Error: Expected ')' after for loop clauses."); - return None; - } + match expr { + Expression::Variable(target_name) => { + self.skip_comments(); + let value_expr = self.parse_expression()?; - let body = Box::new(self.parse_statement()?); - - eprintln!("Warning: For statement AST structure might need review."); - None - - } */ - - fn parse_expression_statement(&mut self) -> Option { - let expr = self.parse_expression()?; - if self.match_token(Token::Semicolon) { + self.skip_comments(); + if !self.match_token(Token::Semicolon) { + eprintln!("Error: Expected ';' after assignment."); + return None; + } + Some(Statement::Assignment { target_name, value: value_expr }) + } + _ => { + eprintln!("Error: Invalid assignment target. Must be an identifier."); + return None; + } + } + } else if self.match_token(Token::Semicolon) { Some(Statement::ExpressionStatement(expr)) } else { - eprintln!("Error: Expected ';' after expression statement."); - None + eprintln!("Error: Expected '=' for assignment or ';' after expression."); + return None; } } @@ -102,6 +91,10 @@ impl Parser { self.advance(); Some(Expression::Literal(Literal::Boolean(false))) } + Token::Nil => { + self.advance(); + Some(Expression::Literal(Literal::Nil)) + } Token::Identifier(name) => { self.advance(); Some(Expression::Variable(name)) @@ -312,7 +305,9 @@ impl Parser { self.skip_comments(); if self.is_at_end() { return None; } - if self.check(&Token::For) { + if self.check(&Token::Return) { + self.parse_return_statement() + } else if self.check(&Token::For) { self.parse_for_statement() } else if self.check(&Token::Func) { self.parse_function_declaration() @@ -327,7 +322,7 @@ impl Parser { } else if self.check(&Token::While) { self.parse_while_statement() } else { - self.parse_expression_statement() + self.parse_assignment_or_expression_statement() } } @@ -733,6 +728,41 @@ impl Parser { if self.current >= self.tokens.len() { return true; } matches!(self.tokens[self.current], Token::EOF) } + + //5-28/25 + fn parse_return_statement(&mut self) -> Option { + if !self.match_token(Token::Return) { + eprintln!("Internal parser error: Expected 'return' token."); + return None; + } + + self.skip_comments(); // Skip comments before the expression + + if self.check(&Token::Semicolon) { + self.advance(); + return Some(Statement::ReturnStatement(None)); + } + + if self.is_at_end() { + eprintln!("Error: Expected expression or ';' after 'return'."); + return None; + } + + match self.parse_expression() { + Some(expr) => { + self.skip_comments(); // Skip comments after the expression + if !self.match_token(Token::Semicolon) { + eprintln!("Error: Expected ';' after return expression."); + return None; + } + Some(Statement::ReturnStatement(Some(expr))) + } + None => { + eprintln!("Error: Invalid expression after 'return'."); + None + } + } + } }