evaluator
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ast;
|
||||||
|
mod evaluator;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
mod object;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod repl;
|
mod repl;
|
||||||
mod token;
|
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::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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user