Skip to content

Commit

Permalink
⚙️ started implementing functions
Browse files Browse the repository at this point in the history
  • Loading branch information
aym-n committed Jan 5, 2024
1 parent 48ee225 commit 536038d
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 30 deletions.
1 change: 1 addition & 0 deletions generate_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub fn generate_ast(output_dir: &String) -> io::Result<()> {
&vec![
"Assign : Token name, Box<Expr> value".to_string(),
"Binary : Box<Expr> left, Token operator, Box<Expr> right".to_string(),
"Call : Box<Expr> callee, Token paren, Vec<Expr> arguments".to_string(),
"Grouping : Box<Expr> expression".to_string(),
"Literal : Option<Object> value".to_string(),
"Logical : Box<Expr> left, Token operator, Box<Expr> right".to_string(),
Expand Down
34 changes: 34 additions & 0 deletions src/callable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

use crate::interpreter::Interpreter;
use crate::tokens::Object;
use crate::errors::Error;
use std::rc::Rc;
use core::fmt::Debug;

#[derive(Clone)]
pub struct Callable{
pub func: Rc<dyn CallableTrait>,
}

impl Debug for Callable{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<func>")
}
}

impl PartialEq for Callable{
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.func, &other.func)
}
}


pub trait CallableTrait {
fn call(&self, interpreter: &Interpreter, arguments: &Vec<Object>) -> Result<Object, Error>;
}

impl CallableTrait for Callable {
fn call(&self, interpreter: &Interpreter, arguments: &Vec<Object>) -> Result<Object, Error> {
self.func.call(interpreter, arguments)
}
}
15 changes: 15 additions & 0 deletions src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::errors::*;
pub enum Expr {
Assign(AssignExpr),
Binary(BinaryExpr),
Call(CallExpr),
Grouping(GroupingExpr),
Literal(LiteralExpr),
Logical(LogicalExpr),
Expand All @@ -16,6 +17,7 @@ impl Expr {
match self {
Expr::Assign(v) => v.accept(expr_visitor),
Expr::Binary(v) => v.accept(expr_visitor),
Expr::Call(v) => v.accept(expr_visitor),
Expr::Grouping(v) => v.accept(expr_visitor),
Expr::Literal(v) => v.accept(expr_visitor),
Expr::Logical(v) => v.accept(expr_visitor),
Expand All @@ -36,6 +38,12 @@ pub struct BinaryExpr {
pub right: Box<Expr>,
}

pub struct CallExpr {
pub callee: Box<Expr>,
pub paren: Token,
pub arguments: Vec<Expr>,
}

pub struct GroupingExpr {
pub expression: Box<Expr>,
}
Expand All @@ -62,6 +70,7 @@ pub struct VariableExpr {
pub trait ExprVisitor<T> {
fn visit_assign_expr(&self, expr: &AssignExpr) -> Result<T , Error>;
fn visit_binary_expr(&self, expr: &BinaryExpr) -> Result<T , Error>;
fn visit_call_expr(&self, expr: &CallExpr) -> Result<T , Error>;
fn visit_grouping_expr(&self, expr: &GroupingExpr) -> Result<T , Error>;
fn visit_literal_expr(&self, expr: &LiteralExpr) -> Result<T , Error>;
fn visit_logical_expr(&self, expr: &LogicalExpr) -> Result<T , Error>;
Expand All @@ -81,6 +90,12 @@ impl BinaryExpr {
}
}

impl CallExpr {
pub fn accept<T>(&self, visitor: &dyn ExprVisitor<T>) -> Result<T , Error> {
visitor.visit_call_expr(self)
}
}

impl GroupingExpr {
pub fn accept<T>(&self, visitor: &dyn ExprVisitor<T>) -> Result<T , Error> {
visitor.visit_grouping_expr(self)
Expand Down
25 changes: 25 additions & 0 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,31 @@ impl ExprVisitor<Object> for Interpreter {
}
}

fn visit_call_expr(&self, expr: &CallExpr) -> Result<Object, Error> {

let callee = self.evaluate(&expr.callee)?;

let mut arguments = Vec::new();

for argument in &expr.arguments {
arguments.push(self.evaluate(argument)?);
}


if let Object::Function(function) = callee {

let _ = function.func.call(self, &arguments);

} else {
return Err(Error::new(
expr.paren.line,
format!("Can only call functions and classes"),
));
}

Ok(Object::Nil)
}

fn visit_variable_expr(&self, expr: &VariableExpr) -> Result<Object, Error> {
self.environment.borrow().borrow().get(&expr.name)
}
Expand Down
29 changes: 0 additions & 29 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,6 @@ impl Lexer {
}
}

pub fn scan_tokens(&mut self) -> Vec<Token> {
let mut tokens: Vec<Token> = Vec::new();

while !self.is_at_end() {
self.start = self.current;
let token = self.next();
if let Some(token) = token {
tokens.push(token);
}
}

tokens.push(Token::new(TokenKind::EOF, "".to_string(), None, self.line));

tokens
}

pub fn current_char(&self) -> char {
self.input.chars().nth(self.current).unwrap_or('\0')
}
Expand Down Expand Up @@ -121,19 +105,6 @@ impl Lexer {
fn is_at_end(&self) -> bool {
self.current >= self.input.len()
}

fn match_char(&mut self, expected: char) -> bool {
if self.is_at_end() {
self.current += 1;
return false;
}

if self.current_char() != expected {
return false;
}

true
}
}

impl Iterator for Lexer {
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ mod stmt;

mod enviroment;

mod callable;

fn eval(source: &str) -> Result<(), Error> {
let lexer = Lexer::new(source.to_string());
let mut tokens: Vec<Token> = lexer.collect();
Expand Down
42 changes: 41 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,47 @@ impl Parser {
}));
}

Ok(self.primary()?)
Ok(self.call()?)
}

fn finish_call(&mut self, callee : Expr) -> Result<Expr, Error> {
let mut arguments: Vec<Expr> = Vec::new();

if !self.check(TokenKind::RightParen) {
loop {
if arguments.len() >= 255 {
return Err(Error::new(
self.peek().line,
"Can't have more than 255 arguments.".to_string(),
));
}
arguments.push(self.expression()?);
if !self.match_token(vec![TokenKind::Comma]) {
break;
}
}
}

let paren = self.consume(TokenKind::RightParen, "Expect ')' after arguments.")?;

Ok(Expr::Call(CallExpr {
callee: Box::new(callee),
paren,
arguments,
}))
}

fn call(&mut self) -> Result<Expr, Error> {
let mut expr = self.primary()?;

loop {
if self.match_token(vec![TokenKind::LeftParen]) {
expr = self.finish_call(expr)?;
} else {
break;
}
}
Ok(expr)
}

fn primary(&mut self) -> Result<Expr, Error> {
Expand Down
3 changes: 3 additions & 0 deletions src/tokens.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt;
use crate::callable::Callable;

#[derive(Debug, Default, PartialEq, Clone)]
pub enum TokenKind {
Expand Down Expand Up @@ -62,6 +63,7 @@ pub enum Object {
Num(f64),
Str(String),
Bool(bool),
Function(Callable),
Nil,
ArithmeticError,
}
Expand All @@ -74,6 +76,7 @@ impl fmt::Display for Object {
Object::Nil => write!(f, "nil"),
Object::Bool(x) => write!(f, "{x}"),
Object::ArithmeticError => write!(f, "Arithmetic Error"),
Object::Function(_) => write!(f, "<func>"),
}
}
}
Expand Down

0 comments on commit 536038d

Please sign in to comment.