evaluator
This commit is contained in:
@@ -3,6 +3,7 @@ use crate::token::Token;
|
||||
pub trait NodeTrait {
|
||||
fn token_literal(&self) -> String;
|
||||
fn string(&self) -> String;
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -47,6 +48,10 @@ impl NodeTrait for Expression {
|
||||
Expression::CallExpression(i) => i.string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Program {
|
||||
@@ -69,6 +74,10 @@ impl NodeTrait for Program {
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LetStatement {
|
||||
@@ -102,6 +111,10 @@ impl NodeTrait for LetStatement {
|
||||
out.push_str(";");
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl StatementTrait for LetStatement {
|
||||
@@ -121,6 +134,10 @@ impl NodeTrait for ReturnStatement {
|
||||
out.push_str(";");
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl StatementTrait for ReturnStatement {
|
||||
@@ -135,6 +152,10 @@ impl NodeTrait for ExpressionStatement {
|
||||
fn string(&self) -> String {
|
||||
self.expression.string()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl StatementTrait for ExpressionStatement {
|
||||
@@ -155,6 +176,10 @@ impl NodeTrait for Identifier {
|
||||
fn string(&self) -> String {
|
||||
self.value.clone()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -171,6 +196,10 @@ impl NodeTrait for IntegerLiteral {
|
||||
fn string(&self) -> String {
|
||||
self.value.to_string()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrefixExpression {
|
||||
@@ -190,6 +219,10 @@ impl NodeTrait for PrefixExpression {
|
||||
out.push_str(&self.right.string());
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InfixExpression {
|
||||
@@ -215,6 +248,10 @@ impl NodeTrait for InfixExpression {
|
||||
out.push_str(")");
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Boolean {
|
||||
@@ -230,6 +267,10 @@ impl NodeTrait for Boolean {
|
||||
fn string(&self) -> String {
|
||||
self.value.to_string()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IfExpression {
|
||||
@@ -256,6 +297,10 @@ impl NodeTrait for IfExpression {
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlockStatement {
|
||||
@@ -275,6 +320,10 @@ impl NodeTrait for BlockStatement {
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionLiteral {
|
||||
@@ -298,6 +347,10 @@ impl NodeTrait for FunctionLiteral {
|
||||
out.push_str(&self.body.string());
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallExpression {
|
||||
@@ -320,4 +373,8 @@ impl NodeTrait for CallExpression {
|
||||
out.push_str(")");
|
||||
out
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
mod ast;
|
||||
mod evaluator;
|
||||
mod lexer;
|
||||
mod object;
|
||||
mod parser;
|
||||
mod repl;
|
||||
mod token;
|
||||
|
||||
@@ -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
@@ -1,4 +1,4 @@
|
||||
use crate::ast::NodeTrait;
|
||||
use crate::evaluator;
|
||||
use crate::lexer::new;
|
||||
use crate::parser::Parser;
|
||||
use crate::parser::new_parser;
|
||||
@@ -20,11 +20,13 @@ pub fn start_repl() {
|
||||
let lexer = new(input.to_string());
|
||||
let mut parser: Parser = new_parser(lexer);
|
||||
let program = parser.parse_program();
|
||||
let evaluated = evaluator::eval_program(program);
|
||||
|
||||
for err in parser.errors() {
|
||||
eprintln!("ERROR: {}", err);
|
||||
}
|
||||
|
||||
println!("{}", program.string());
|
||||
if !evaluated.is_none() {
|
||||
println!("{}", evaluated.unwrap().inspect());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user