evaluator

This commit is contained in:
Yann Ahlgrim
2026-07-11 20:25:22 +02:00
parent 30bcf7c6b2
commit 5869d8acc2
5 changed files with 189 additions and 3 deletions
+57
View File
@@ -3,6 +3,7 @@ use crate::token::Token;
pub trait NodeTrait { pub trait NodeTrait {
fn token_literal(&self) -> String; fn token_literal(&self) -> String;
fn string(&self) -> String; fn string(&self) -> String;
fn as_any(&self) -> &dyn std::any::Any;
} }
#[allow(dead_code)] #[allow(dead_code)]
@@ -47,6 +48,10 @@ impl NodeTrait for Expression {
Expression::CallExpression(i) => i.string(), Expression::CallExpression(i) => i.string(),
} }
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct Program { pub struct Program {
@@ -69,6 +74,10 @@ impl NodeTrait for Program {
} }
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct LetStatement { pub struct LetStatement {
@@ -102,6 +111,10 @@ impl NodeTrait for LetStatement {
out.push_str(";"); out.push_str(";");
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
impl StatementTrait for LetStatement { impl StatementTrait for LetStatement {
@@ -121,6 +134,10 @@ impl NodeTrait for ReturnStatement {
out.push_str(";"); out.push_str(";");
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
impl StatementTrait for ReturnStatement { impl StatementTrait for ReturnStatement {
@@ -135,6 +152,10 @@ impl NodeTrait for ExpressionStatement {
fn string(&self) -> String { fn string(&self) -> String {
self.expression.string() self.expression.string()
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
impl StatementTrait for ExpressionStatement { impl StatementTrait for ExpressionStatement {
@@ -155,6 +176,10 @@ impl NodeTrait for Identifier {
fn string(&self) -> String { fn string(&self) -> String {
self.value.clone() self.value.clone()
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
#[derive(Debug)] #[derive(Debug)]
@@ -171,6 +196,10 @@ impl NodeTrait for IntegerLiteral {
fn string(&self) -> String { fn string(&self) -> String {
self.value.to_string() self.value.to_string()
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct PrefixExpression { pub struct PrefixExpression {
@@ -190,6 +219,10 @@ impl NodeTrait for PrefixExpression {
out.push_str(&self.right.string()); out.push_str(&self.right.string());
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct InfixExpression { pub struct InfixExpression {
@@ -215,6 +248,10 @@ impl NodeTrait for InfixExpression {
out.push_str(")"); out.push_str(")");
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct Boolean { pub struct Boolean {
@@ -230,6 +267,10 @@ impl NodeTrait for Boolean {
fn string(&self) -> String { fn string(&self) -> String {
self.value.to_string() self.value.to_string()
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct IfExpression { pub struct IfExpression {
@@ -256,6 +297,10 @@ impl NodeTrait for IfExpression {
} }
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct BlockStatement { pub struct BlockStatement {
@@ -275,6 +320,10 @@ impl NodeTrait for BlockStatement {
} }
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct FunctionLiteral { pub struct FunctionLiteral {
@@ -298,6 +347,10 @@ impl NodeTrait for FunctionLiteral {
out.push_str(&self.body.string()); out.push_str(&self.body.string());
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
pub struct CallExpression { pub struct CallExpression {
@@ -320,4 +373,8 @@ impl NodeTrait for CallExpression {
out.push_str(")"); out.push_str(")");
out out
} }
fn as_any(&self) -> &dyn std::any::Any {
self
}
} }
+75
View File
@@ -0,0 +1,75 @@
use crate::ast::Program;
use crate::ast::{self};
use crate::object::{self, Null, Object};
const NULL: Null = Null;
const BOOL_TRUE: object::Boolean = object::Boolean { value: true };
const BOOL_FALSE: object::Boolean = object::Boolean { value: false };
fn eval(node: Box<dyn ast::NodeTrait>) -> Option<Box<dyn object::Object>> {
let node = node.as_ref();
if let Some(stmt) = node.as_any().downcast_ref::<ast::ExpressionStatement>() {
return eval_expression(&stmt.expression);
}
if let Some(stmt) = node.as_any().downcast_ref::<ast::LetStatement>() {
return None;
}
if let Some(stmt) = node.as_any().downcast_ref::<ast::ReturnStatement>() {
return eval_expression(&stmt.return_value);
}
if let Some(expr) = node.as_any().downcast_ref::<ast::Expression>() {
return eval_expression(expr);
}
if let Some(expr) = node.as_any().downcast_ref::<ast::PrefixExpression>() {
let right = &eval(expr.right);
return eval_prefix_expression(expr.operator, right);
}
None
}
pub fn eval_program(program: Program) -> Option<Box<dyn object::Object>> {
let mut res: Option<Box<dyn object::Object>> = None;
for stmt in program.statements {
res = eval(stmt)
}
res
}
fn eval_expression(expression: &ast::Expression) -> Option<Box<dyn object::Object>> {
match expression {
ast::Expression::IntegerLiteral(int) => {
Some(Box::new(object::Integer { value: int.value }))
}
ast::Expression::Boolean(b) => Some(Box::new(native_bool_to_bool_object(b.value))),
_ => None,
}
}
fn eval_prefix_expression(
operator: String,
right: &Option<Box<dyn object::Object>>,
) -> Option<Box<dyn object::Object>> {
match operator.as_str() {
"!" => eval_bang_operator_expression(right),
_ => Some(Box::new(NULL)),
}
}
fn eval_bang_operator_expression(
right: &Option<Box<dyn object::Object>>,
) -> Option<Box<dyn object::Object>> {
let bool_true = Box::new(BOOL_TRUE);
let bool_false = Box::new(BOOL_FALSE);
let null = Box::new(NULL);
match right..unwrap() {
bool_true => Some(bool_false),
bool_false => Some(bool_true),
null => Some(bool_true),
_ => Some(bool_false),
}
}
fn native_bool_to_bool_object(input: bool) -> object::Boolean {
if input { BOOL_TRUE } else { BOOL_FALSE }
}
+2
View File
@@ -1,5 +1,7 @@
mod ast; mod ast;
mod evaluator;
mod lexer; mod lexer;
mod object;
mod parser; mod parser;
mod repl; mod repl;
mod token; mod token;
+50
View File
@@ -0,0 +1,50 @@
pub enum ObjectType {
INTEGER,
BOOLEAN,
NULL,
}
pub trait Object {
fn object_type(&self) -> ObjectType;
fn inspect(&self) -> String;
}
pub struct Integer {
pub value: i64,
}
impl Object for Integer {
fn object_type(&self) -> ObjectType {
ObjectType::INTEGER
}
fn inspect(&self) -> String {
self.value.to_string()
}
}
pub struct Boolean {
pub value: bool,
}
impl Object for Boolean {
fn object_type(&self) -> ObjectType {
ObjectType::BOOLEAN
}
fn inspect(&self) -> String {
self.value.to_string()
}
}
pub struct Null;
impl Object for Null {
fn object_type(&self) -> ObjectType {
ObjectType::NULL
}
fn inspect(&self) -> String {
"null".to_string()
}
}
+5 -3
View File
@@ -1,4 +1,4 @@
use crate::ast::NodeTrait; use crate::evaluator;
use crate::lexer::new; use crate::lexer::new;
use crate::parser::Parser; use crate::parser::Parser;
use crate::parser::new_parser; use crate::parser::new_parser;
@@ -20,11 +20,13 @@ pub fn start_repl() {
let lexer = new(input.to_string()); let lexer = new(input.to_string());
let mut parser: Parser = new_parser(lexer); let mut parser: Parser = new_parser(lexer);
let program = parser.parse_program(); let program = parser.parse_program();
let evaluated = evaluator::eval_program(program);
for err in parser.errors() { for err in parser.errors() {
eprintln!("ERROR: {}", err); eprintln!("ERROR: {}", err);
} }
if !evaluated.is_none() {
println!("{}", program.string()); println!("{}", evaluated.unwrap().inspect());
}
} }
} }