Skip to content

Commit

Permalink
added expr semicolon support.
Browse files Browse the repository at this point in the history
  • Loading branch information
nulluser committed Jun 9, 2024
1 parent e1f5646 commit 3bc8318
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 24 deletions.
40 changes: 16 additions & 24 deletions src/backend/eval/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub fn evaluate_expr(expr: Expr, env: &Rc<RefCell<Environment>>) -> Val {
Expr::WhileExpr(condition, then) => evaluate_while_expr(*condition, then, env),
Expr::ForeverLoopExpr(then) => evaluate_loop_expr(then, env),
Expr::Array(_) => todo!("{:?}", expr),
Expr::SpecialNull => mk_null!(),
}
}

Expand All @@ -46,10 +47,7 @@ pub fn evaluate_while_expr(
return_value,
}) = evaluate(stmt.clone(), env)
{
return match return_value {
Some(val) => *val,
None => mk_null!(),
};
return return_value.map_or(mk_null!(), |val| *val);
}
}
}
Expand All @@ -68,10 +66,7 @@ pub fn evaluate_loop_expr(then: Vec<Stmt>, env: &Rc<RefCell<Environment>>) -> Va
return_value,
}) = evaluate(stmt.clone(), env)
{
return match return_value {
Some(val) => *val,
None => mk_null!(),
};
return return_value.map_or(mk_null!(), |val| *val);
}
}
}
Expand Down Expand Up @@ -144,7 +139,6 @@ pub fn evaluate_if_expr(
// Error: If condition doesn't evaluate to a boolean value
panic!("If condition must evaluate to a boolean value.");
}
// TODO: Handle cases where expr returns a value. Also as a result:
// TODO: Handle cases where Exprs do not return a value using the semicolon.
mk_null!()
}
Expand Down Expand Up @@ -190,31 +184,29 @@ pub fn evaluate_call_expr(args: Vec<Expr>, caller: Expr, env: &Rc<RefCell<Enviro
.collect();
let function = evaluate_expr(caller, env);
match &function {
Val::NativeFunction(callable) => return (callable.call)(evaluated_args, env),
Val::NativeFunction(callable) => (callable.call)(evaluated_args, env),
Val::Function(fn_value) => {
let scope = Rc::new(RefCell::new(Environment::new_with_parent(
fn_value.declaration_env.clone(),
)));
for (i, _) in evaluated_args
.iter()
.enumerate()
.take(fn_value.parameters.len())
{
// TODO: Check the bounds here.
// Verify arity of function.
let varname = &fn_value.parameters[i];
let arg = &evaluated_args[i];
for (varname, arg) in fn_value.parameters.iter().zip(evaluated_args.iter()) {
scope.borrow_mut().declare_var(varname, arg.clone(), false);
}
let mut result: Val = mk_null!();
for stmt in &fn_value.body {
result = evaluate(stmt.clone(), &scope)
result = evaluate(stmt.clone(), &scope);
if let Val::Special(SpecialVal {
keyword: SpecialValKeyword::Return,
return_value,
}) = result
{
return return_value.map_or(mk_null!(), |val| *val);
}
}
return result;
result
}
_ => {}
};
panic!("Cannot call value that is not a function: {:?}", function);
_ => panic!("Cannot call value that is not a function: {:?}", function),
}
}

pub fn evaluate_binary_op(
Expand Down
1 change: 1 addition & 0 deletions src/frontend/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub enum Expr {
ForExpr(Box<Expr>, Vec<Stmt>), // For item in iterable, Do Stmts
WhileExpr(Box<Expr>, Vec<Stmt>), // While Condition, Do Stmts
ForeverLoopExpr(Vec<Stmt>), // Forever loop! Has vec of stmts.
SpecialNull, // Literally just returns null. Should ONLY be returned as a result of a semicolon.
}

impl std::fmt::Display for Expr {
Expand Down
24 changes: 24 additions & 0 deletions src/frontend/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use super::{
pub struct Parser {
tokens: Vec<Token>,
inside_loop: bool,
inside_function: bool,
}

impl Default for Parser {
Expand All @@ -27,6 +28,7 @@ impl Parser {
Parser {
tokens: Vec::new(),
inside_loop: false,
inside_function: false,
}
}

Expand Down Expand Up @@ -64,6 +66,7 @@ impl Parser {
}
}
Token::Keyword(Keyword::Break) => self.parse_break_declaration(),
Token::Keyword(Keyword::Return) => self.parse_return_declaration(),
// Token::Identifier(_) => todo!(),
// Token::IntegerLiteral(_) => todo!(),
// Token::StringLiteral(_) => todo!(),
Expand Down Expand Up @@ -91,6 +94,23 @@ impl Parser {
Stmt::BreakStmt(Some(expr))
}

fn parse_return_declaration(&mut self) -> Stmt {
self.eat();
if !self.inside_function {
panic!("`return` statement found outside of a function context.")
}
if *self.at() == Token::Symbol(Symbol::Semicolon) {
self.eat();
return Stmt::ReturnStmt(None);
}
let expr = self.parse_expr();
self.expect(
Token::Symbol(Symbol::Semicolon),
"return declaration is a statement. It must end with a semicolon.",
);
Stmt::ReturnStmt(Some(expr))
}

fn parse_fn_declaration(&mut self, is_async: bool) -> Stmt {
self.eat();
let name = match self.eat() {
Expand All @@ -111,10 +131,13 @@ impl Parser {
Token::Symbol(Symbol::LeftBrace),
"Expected function body following declaration.",
);
let prev_inside_function = self.inside_function;
self.inside_function = true;
let mut body: Vec<Stmt> = Vec::new();
while self.not_eof() && *self.at() != Token::Symbol(Symbol::RightBrace) {
body.push(self.parse_stmt());
}
self.inside_function = prev_inside_function;
self.expect(
Token::Symbol(Symbol::RightBrace),
"Closing brace expected inside function declaration.",
Expand Down Expand Up @@ -438,6 +461,7 @@ impl Parser {
);
Expr::Array(elements)
}
Token::Symbol(Symbol::Semicolon) => Expr::SpecialNull,
// Token::EOF => todo!(),
_ => {
println!("Unexpected token found during parsing! {:#?}", tk);
Expand Down

0 comments on commit 3bc8318

Please sign in to comment.