feat: Implement interpreter for core expressions and print statements

This commit is contained in:
Tristan 2025-05-28 13:27:33 -04:00
parent 558cbbc0d2
commit 3ce945ca0f
9 changed files with 309 additions and 85 deletions

View File

@ -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

View File

@ -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<Statement>) -> 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<FddlValue, RuntimeError> {
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
)))
}
}
}
}

1
src/interpreter/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod evaluator;

View File

@ -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,

View File

@ -35,6 +35,7 @@ pub enum Token {
Else,
True,
False,
Nil,
Let,
Const,
Func,

View File

@ -1,3 +1,4 @@
pub mod lexer;
pub mod parser;
pub mod compiler;
pub mod compiler;
pub mod interpreter;

View File

@ -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<String> = 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!("---");
}

View File

@ -67,4 +67,8 @@ pub enum Statement {
body: Vec<Statement>,
},
ReturnStatement(Option<Expression>),
Assignment {
target_name: String,
value: Expression,
},
}

View File

@ -17,57 +17,46 @@ impl Parser {
}
}
/* fn parse_for_statement(&mut self) -> Option<Statement> {
if !self.match_token(Token::LeftParen) {
eprintln!("Error: Expected '(' after 'for'.");
return None;
}
// fn parse_expression_statement(&mut self) -> Option<Statement> {
// 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<Statement> {
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<Statement> {
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<Statement> {
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
}
}
}
}