mirror of
https://github.com/urinalcaketopper/fddl.git
synced 2025-06-07 05:34:47 +00:00
feat: Implement interpreter for core expressions and print statements
This commit is contained in:
parent
558cbbc0d2
commit
3ce945ca0f
@ -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
|
|
195
src/interpreter/evaluator.rs
Normal file
195
src/interpreter/evaluator.rs
Normal 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
1
src/interpreter/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod evaluator;
|
@ -269,6 +269,7 @@ impl Lexer {
|
|||||||
"else" => Token::Else,
|
"else" => Token::Else,
|
||||||
"true" => Token::True,
|
"true" => Token::True,
|
||||||
"false" => Token::False,
|
"false" => Token::False,
|
||||||
|
"nil" => Token::Nil,
|
||||||
"let" => Token::Let,
|
"let" => Token::Let,
|
||||||
"const" => Token::Const,
|
"const" => Token::Const,
|
||||||
"func" => Token::Func,
|
"func" => Token::Func,
|
||||||
|
@ -35,6 +35,7 @@ pub enum Token {
|
|||||||
Else,
|
Else,
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
|
Nil,
|
||||||
Let,
|
Let,
|
||||||
Const,
|
Const,
|
||||||
Func,
|
Func,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod compiler;
|
pub mod compiler;
|
||||||
|
pub mod interpreter;
|
62
src/main.rs
62
src/main.rs
@ -6,9 +6,9 @@ use std::env;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
// use lexer::Lexer;
|
|
||||||
use fddl::lexer::Lexer;
|
use fddl::lexer::Lexer;
|
||||||
use fddl::parser::Parser;
|
use fddl::parser::Parser;
|
||||||
|
use fddl::interpreter::evaluator::Evaluator;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
@ -23,7 +23,8 @@ fn main() {
|
|||||||
|
|
||||||
// basic REPL
|
// basic REPL
|
||||||
fn run_repl() {
|
fn run_repl() {
|
||||||
println!("fddl repl");
|
println!("FDDL REPL");
|
||||||
|
println!("---------");
|
||||||
loop {
|
loop {
|
||||||
print!("fddl % ");
|
print!("fddl % ");
|
||||||
io::stdout().flush().unwrap();
|
io::stdout().flush().unwrap();
|
||||||
@ -45,45 +46,40 @@ fn run_file(path: &str) {
|
|||||||
run(source);
|
run(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
// runs source code
|
|
||||||
fn run(source: String) {
|
fn run(source: String) {
|
||||||
println!("Source: {}", source.trim()); // prints source for debugging
|
println!("Source: {}", source.trim());
|
||||||
|
|
||||||
let mut lexer = Lexer::new(source);
|
let mut lexer = Lexer::new(source);
|
||||||
let tokens = lexer.scan_tokens();
|
let tokens = lexer.scan_tokens();
|
||||||
|
|
||||||
// old code begins
|
println!("Tokens: {:?}", tokens);
|
||||||
// println!("Tokens:");
|
|
||||||
// for token in &tokens { // Iterate by reference if you use tokens later
|
|
||||||
// println!("{:?}", token);
|
|
||||||
// }
|
|
||||||
// println!("---");
|
|
||||||
// old code ends - delete if not needed
|
|
||||||
|
|
||||||
let mut parser = Parser::new(tokens); // Create a new parser instance
|
let mut parser = Parser::new(tokens);
|
||||||
let ast_statements = parser.parse_program(); // NEW!
|
|
||||||
|
|
||||||
println!("Parsed Statements (AST):");
|
|
||||||
|
|
||||||
for stmt in ast_statements {
|
|
||||||
println!("{:?}", stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
let program_ast = parser.parse_program();
|
||||||
|
|
||||||
if parser.is_at_end() {
|
if !program_ast.is_empty() {
|
||||||
break;
|
println!("Parsed Statements (AST):");
|
||||||
|
for stmt in &program_ast {
|
||||||
|
println!("{:?}", stmt);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
match parser.parse_statement() {
|
println!("No AST generated or parsing failed.");
|
||||||
Some(statement) => {
|
|
||||||
println!("{:?}", statement);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
println!("Parser returned None, might be an error or unhandled EOF by parse_statement.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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!("---");
|
||||||
}
|
}
|
@ -67,4 +67,8 @@ pub enum Statement {
|
|||||||
body: Vec<Statement>,
|
body: Vec<Statement>,
|
||||||
},
|
},
|
||||||
ReturnStatement(Option<Expression>),
|
ReturnStatement(Option<Expression>),
|
||||||
|
Assignment {
|
||||||
|
target_name: String,
|
||||||
|
value: Expression,
|
||||||
|
},
|
||||||
}
|
}
|
@ -17,57 +17,46 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fn parse_for_statement(&mut self) -> Option<Statement> {
|
// fn parse_expression_statement(&mut self) -> Option<Statement> {
|
||||||
if !self.match_token(Token::LeftParen) {
|
// let expr = self.parse_expression()?;
|
||||||
eprintln!("Error: Expected '(' after 'for'.");
|
// if self.match_token(Token::Semicolon) {
|
||||||
return None;
|
// Some(Statement::ExpressionStatement(expr))
|
||||||
}
|
// } else {
|
||||||
|
// eprintln!("Error: Expected ';' after expression statement.");
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
let initializer = if self.match_token(Token::Semicolon) {
|
fn parse_assignment_or_expression_statement(&mut self) -> Option<Statement> {
|
||||||
None
|
let expr = self.parse_expression()?;
|
||||||
} 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()?
|
|
||||||
};
|
|
||||||
|
|
||||||
if !self.match_token(Token::Semicolon) {
|
self.skip_comments(); // Skip comments before semicolon
|
||||||
eprintln!("Error: Expected ';' after for loop condition.");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let increment = if self.check(&Token::RightParen) {
|
if self.check(&Token::Equal) {
|
||||||
None
|
self.advance();
|
||||||
} else {
|
|
||||||
Some(self.parse_expression()?)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !self.match_token(Token::RightParen) {
|
match expr {
|
||||||
eprintln!("Error: Expected ')' after for loop clauses.");
|
Expression::Variable(target_name) => {
|
||||||
return None;
|
self.skip_comments();
|
||||||
}
|
let value_expr = self.parse_expression()?;
|
||||||
|
|
||||||
let body = Box::new(self.parse_statement()?);
|
self.skip_comments();
|
||||||
|
if !self.match_token(Token::Semicolon) {
|
||||||
eprintln!("Warning: For statement AST structure might need review.");
|
eprintln!("Error: Expected ';' after assignment.");
|
||||||
None
|
return None;
|
||||||
|
}
|
||||||
} */
|
Some(Statement::Assignment { target_name, value: value_expr })
|
||||||
|
}
|
||||||
fn parse_expression_statement(&mut self) -> Option<Statement> {
|
_ => {
|
||||||
let expr = self.parse_expression()?;
|
eprintln!("Error: Invalid assignment target. Must be an identifier.");
|
||||||
if self.match_token(Token::Semicolon) {
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if self.match_token(Token::Semicolon) {
|
||||||
Some(Statement::ExpressionStatement(expr))
|
Some(Statement::ExpressionStatement(expr))
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Error: Expected ';' after expression statement.");
|
eprintln!("Error: Expected '=' for assignment or ';' after expression.");
|
||||||
None
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +91,10 @@ impl Parser {
|
|||||||
self.advance();
|
self.advance();
|
||||||
Some(Expression::Literal(Literal::Boolean(false)))
|
Some(Expression::Literal(Literal::Boolean(false)))
|
||||||
}
|
}
|
||||||
|
Token::Nil => {
|
||||||
|
self.advance();
|
||||||
|
Some(Expression::Literal(Literal::Nil))
|
||||||
|
}
|
||||||
Token::Identifier(name) => {
|
Token::Identifier(name) => {
|
||||||
self.advance();
|
self.advance();
|
||||||
Some(Expression::Variable(name))
|
Some(Expression::Variable(name))
|
||||||
@ -312,7 +305,9 @@ impl Parser {
|
|||||||
self.skip_comments();
|
self.skip_comments();
|
||||||
if self.is_at_end() { return None; }
|
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()
|
self.parse_for_statement()
|
||||||
} else if self.check(&Token::Func) {
|
} else if self.check(&Token::Func) {
|
||||||
self.parse_function_declaration()
|
self.parse_function_declaration()
|
||||||
@ -327,7 +322,7 @@ impl Parser {
|
|||||||
} else if self.check(&Token::While) {
|
} else if self.check(&Token::While) {
|
||||||
self.parse_while_statement()
|
self.parse_while_statement()
|
||||||
} else {
|
} 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; }
|
if self.current >= self.tokens.len() { return true; }
|
||||||
matches!(self.tokens[self.current], Token::EOF)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user