Skip to content

Commit

Permalink
if statement parsing, and partial interpretation support.
Browse files Browse the repository at this point in the history
  • Loading branch information
nulluser0 committed Jun 2, 2024
1 parent 6f353bb commit cace1d4
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 4 deletions.
36 changes: 35 additions & 1 deletion src/backend/eval/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
interpreter::evaluate,
values::{FloatVal, IntegerVal, NullVal, ObjectVal, ToFloat, Val},
},
frontend::ast::{BinaryOp, Expr, Literal, Property},
frontend::ast::{BinaryOp, Expr, Literal, Property, Stmt},
mk_float, mk_integer, mk_null,
};

Expand All @@ -19,7 +19,41 @@ pub fn evaluate_expr(expr: Expr, env: &mut Environment) -> Val {
Expr::FunctionCall(args, caller) => evaluate_call_expr(args, *caller, env),
Expr::AssignmentExpr(assignee, expr) => evaluate_assignment(*assignee, *expr, env),
Expr::Member(_, _, _) => todo!("{:?}", expr),
Expr::IfExpr(condition, then, else_stmt) => {
evaluate_if_expr(*condition, then, else_stmt, env)
}
}
}

pub fn evaluate_if_expr(
condition: Expr,
then: Vec<Stmt>,
else_stmt: Option<Vec<Stmt>>,
env: &mut Environment,
) -> Val {
// Evaluate the condition. If it is true, then complete then, else do the else_stmt (or ignore if statement.)
let condition_value = evaluate_expr(condition, env);

// Check if the condition evaluates to true
if let Val::Bool(condition_bool) = condition_value {
if condition_bool.value {
// Evaluate the consequent block if the condition is true
for stmt in then {
evaluate(stmt, env);
}
} else if let Some(alt) = else_stmt {
// Evaluate the alternative block if the condition is false and an alternative is provided
for stmt in alt {
evaluate(stmt, env);
}
}
} else {
// 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!()
}

pub fn evaluate_assignment(assignee: Expr, expr: Expr, env: &mut Environment) -> Val {
Expand Down
1 change: 0 additions & 1 deletion src/backend/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub fn evaluate(stmt: Stmt, env: &mut Environment) -> Val {
evaluate_declare_var(name, is_mutable, expr, env)
}
Stmt::ReturnStmt(_) => unimplemented!(),
Stmt::IfStmt(_, _, _) => unimplemented!(),
Stmt::FunctionDeclaration(parameters, name, body, is_async) => {
evaluate_declare_fn(parameters, name, body, is_async, env)
} // Handle other statement types...
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub enum Expr {
UnaryOp(UnaryOp, Box<Expr>),
FunctionCall(Vec<Expr>, Box<Expr>), // Args, Caller
Member(Box<Expr>, Box<Expr>, bool), // Object, Property, Computed?
IfExpr(Box<Expr>, Vec<Stmt>, Option<Vec<Stmt>>), // Condition, Then, Optional Else
}

impl std::fmt::Display for Expr {
Expand All @@ -44,7 +45,6 @@ pub enum Stmt {
DeclareStmt(String, bool, Option<Expr>), // Name, is_mutable, expr
ReturnStmt(Option<Expr>),
FunctionDeclaration(Vec<String>, String, Vec<Stmt>, bool), // Parameters, Name, Body, Is async?
IfStmt(Expr, Vec<Stmt>, Option<Vec<Stmt>>), // Condition, Then, Else
}

#[derive(Debug, PartialEq, Clone)]
Expand Down
40 changes: 39 additions & 1 deletion src/frontend/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl Parser {
fn parse_primary_expr(&mut self) -> Expr {
let tk = self.eat();
match tk {
// Token::Keyword(_) => todo!(),
Token::Keyword(Keyword::If) => self.parse_if_expr() as Expr,
Token::Identifier(name) => Expr::Identifier(name.to_string()) as Expr,
Token::IntegerLiteral(integer) => Expr::Literal(Literal::Integer(integer)) as Expr,
Token::FloatLiteral(float) => Expr::Literal(Literal::Float(float)) as Expr,
Expand All @@ -352,6 +352,44 @@ impl Parser {
}
}

fn parse_if_expr(&mut self) -> Expr {
let condition = self.parse_expr();
self.expect(
Token::Symbol(Symbol::LeftBrace),
"Expected left brace before `if` expression.",
);
let mut consequent: Vec<Stmt> = Vec::new();
while self.not_eof() && *self.at() != Token::Symbol(Symbol::RightBrace) {
consequent.push(self.parse_stmt());
}
self.expect(
Token::Symbol(Symbol::RightBrace),
"Expected right brace after `if` expression.",
);
let mut alternative: Option<Vec<Stmt>> = None;
if *self.at() == Token::Keyword(Keyword::Else) {
self.eat(); // Advance from else
if *self.at() == Token::Keyword(Keyword::If) {
alternative = Some(vec![Stmt::ExprStmt(self.parse_if_expr())])
} else {
self.expect(
Token::Symbol(Symbol::LeftBrace),
"Expected left brace before `else` expression.",
);
let mut else_block: Vec<Stmt> = Vec::new();
while self.not_eof() && *self.at() != Token::Symbol(Symbol::RightBrace) {
else_block.push(self.parse_stmt());
}
self.expect(
Token::Symbol(Symbol::RightBrace),
"Expected right brace after `else` expression.",
);
alternative = Some(else_block);
}
}
Expr::IfExpr(Box::new(condition), consequent, alternative)
}

pub fn produce_ast(&mut self, source_code: String) -> Result<Program, String> {
self.tokens = tokenize(source_code);
let mut program = Program::new(Vec::new());
Expand Down

0 comments on commit cace1d4

Please sign in to comment.