Skip to content

Commit

Permalink
add functions
Browse files Browse the repository at this point in the history
  • Loading branch information
iamgabrieloliveira committed Dec 29, 2024
1 parent 8879baa commit 6443973
Show file tree
Hide file tree
Showing 6 changed files with 439 additions and 98 deletions.
21 changes: 17 additions & 4 deletions example.lox
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
print "Starting loop";
fun hello() {
print "hello";
}

hello();

for (var i = 0; i < 10; i = i + 1) {
print i;
print hello;

fun sum(a, b) {
print a + b;
}

print "End of loop";
sum(1, 10);

fun say_hello(first_name, last_name) {
print "Hello, " + first_name + " " + last_name;
}

say_hello("Gabriel", "Oliveira");


73 changes: 71 additions & 2 deletions src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// program -> declaration* EOF ;
// block -> "{" declaration "}"
// declaration → variable_declaration | statement;
// declaration → fn_declaration | variable_declaration | statement;
// fn_declaration -> "fn" IDENTIFIER "(" parameters? ")" block ;
// parameters -> IDENTIFIER ( "," IDENTIFIER )* ;
// variable_declaration -> "var" IDENTIFIER ( "=" expression )? ";" ;
// statement -> expr_statement | if_statement | print_statement | while_statement | block;
// if_statement = "if" "(" condition ")" statement ( "else" statement )?
Expand All @@ -21,10 +23,11 @@

use std::fmt;

use crate::Token;
use crate::{environment::Environment, interpreter::execute_block, Token};

#[derive(Clone, Debug, PartialEq)]
pub enum Statement<'a> {
Break,
Expression(Expression<'a>),
If {
condition: Expression<'a>,
Expand All @@ -35,6 +38,7 @@ pub enum Statement<'a> {
condition: Expression<'a>,
body: Box<Statement<'a>>,
},
Function(FunctionStatement<'a>),
Block(Vec<Statement<'a>>),
Print(Expression<'a>),
Var {
Expand All @@ -43,6 +47,13 @@ pub enum Statement<'a> {
},
}

#[derive(Clone, Debug, PartialEq)]
pub struct FunctionStatement<'a> {
pub name: Token<'a>,
pub params: Vec<Token<'a>>,
pub body: Vec<Statement<'a>>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Expression<'a> {
Literal(Literal),
Expand All @@ -63,6 +74,11 @@ pub enum Expression<'a> {
},
Grouping(Box<Expression<'a>>),
Variable(Token<'a>),
Call {
callee: Box<Expression<'a>>,
paren: Token<'a>,
arguments: Vec<Expression<'a>>,
},
}

#[derive(Clone, Debug, PartialEq)]
Expand All @@ -74,6 +90,59 @@ pub enum Literal {
Nil,
}

pub type CallableReturn<'a> = (Environment<'a>, crate::environment::Value<'a>);

pub trait Callable<'a>: std::fmt::Debug + std::fmt::Display {
fn arity(&self) -> usize;
fn call(
&self,
env: Environment<'a>,
args: Vec<crate::environment::Value<'a>>,
) -> CallableReturn<'a>;
}

impl<'a> PartialEq for dyn Callable<'a> {
fn eq(&self, other: &Self) -> bool {
todo!()
}
}

#[derive(Debug)]
pub struct Function<'a> {
pub declaration: FunctionStatement<'a>,
}

impl<'a> Callable<'a> for Function<'a> {
fn arity(&self) -> usize {
self.declaration.params.len()
}

fn call(
&self,
mut env: Environment<'a>,
args: Vec<crate::environment::Value<'a>>,
) -> CallableReturn<'a> {
for (i, arg) in args.iter().enumerate() {
match self.declaration.params.get(i) {
Some(param) => {
env.define(param.lexeme, arg.clone());
}
None => unreachable!(),
};
}

let env = execute_block(self.declaration.body.clone(), env).unwrap();

(env, crate::environment::Value::Literal(Literal::Nil))
}
}

impl<'a> std::fmt::Display for Function<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{} fn>", self.declaration.name.lexeme)
}
}

impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand Down
26 changes: 18 additions & 8 deletions src/environment.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
use crate::ast::Literal;
use std::collections::HashMap;
use crate::ast::{Callable, Literal};
use std::{collections::HashMap, rc::Rc};

type Value = Option<Literal>;
#[derive(Debug, Clone)]
pub enum Value<'a> {
Literal(Literal),
Callable(Rc<dyn Callable<'a> + 'a>),
}

impl<'a> PartialEq for Value<'a> {
fn eq(&self, _other: &Self) -> bool {
todo!()
}
}

#[derive(Debug)]
pub struct Environment<'a> {
values: HashMap<&'a str, Value>,
values: HashMap<&'a str, Value<'a>>,
pub parent: Box<Option<Environment<'a>>>,
}

Expand All @@ -29,11 +39,11 @@ impl<'a> Environment<'a> {
self.parent.unwrap()
}

pub fn define(&mut self, name: &'a str, value: Option<Literal>) -> Option<Value> {
pub fn define(&mut self, name: &'a str, value: Value<'a>) -> Option<Value<'a>> {
self.values.insert(name, value)
}

pub fn define_deep(&mut self, name: &'a str, value: Option<Literal>) -> Option<Value> {
pub fn define_deep(&mut self, name: &'a str, value: Value<'a>) -> Option<Value<'a>> {
match self.define(name, value.clone()) {
Some(v) => Some(v),
None => match *self.parent {
Expand All @@ -43,11 +53,11 @@ impl<'a> Environment<'a> {
}
}

pub fn get(&self, name: &'a str) -> Option<&Value> {
pub fn get(&self, name: &'a str) -> Option<&Value<'a>> {
self.values.get(&name)
}

pub fn get_deep(&self, name: &'a str) -> Option<&Value> {
pub fn get_deep(&self, name: &'a str) -> Option<&Value<'a>> {
let mut variable = self.get(name);

if variable.is_none() {
Expand Down
Loading

0 comments on commit 6443973

Please sign in to comment.