Skip to content

Commit

Permalink
Conditions and use blocks for functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Quaqqer committed Jan 5, 2024
1 parent 57522b2 commit 476ff58
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 25 deletions.
7 changes: 5 additions & 2 deletions crates/saft-ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ pub enum Expr {
Vec(Vec<Spanned<Expr>>),

Grouping(Box<Spanned<Expr>>),
Block(Block),
Block(Spanned<Block>),

If(Box<Spanned<Expr>>, Spanned<Block>, Option<Box<Spanned<Expr>>>),

Neg(Box<Spanned<Expr>>),
Not(Box<Spanned<Expr>>),
Expand Down Expand Up @@ -94,6 +96,7 @@ impl Expr {
IDiv(..) => "integer division",
Not(..) => "not",
Block(..) => "block",
If(..) => "if expression",
}
}
}
Expand All @@ -116,6 +119,6 @@ pub enum Item {
Fn {
ident: Spanned<Ident>,
params: Vec<Spanned<Ident>>,
body: Vec<Spanned<Statement>>,
body: Spanned<Block>,
},
}
45 changes: 37 additions & 8 deletions crates/saft-eval/src/interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::natives::add_natives;
use crate::value::{Cast, Function, NativeFuncData, Num, SaftFunction, Value};
use crate::value::{Cast, Function, NativeFuncData, Num, SaftFunction, Value, ValueType};
use codespan_reporting::diagnostic::{Diagnostic, Label};
use saft_ast::{Block, Expr, Ident, Item, Module, Statement};
use saft_common::span::{Span, Spanned};
Expand Down Expand Up @@ -143,7 +143,7 @@ impl Interpreter {
}) => {
let fun = Value::Function(Function::SaftFunction(SaftFunction {
params: params.clone(),
body: Rc::new(body.clone()),
body: body.clone(),
}));
self.env.declare(ident, fun);
Ok(())
Expand Down Expand Up @@ -331,11 +331,7 @@ impl Interpreter {
interpreter.env.declare(arg_name, arg.v.clone());
}

for statement in body.iter() {
interpreter.exec_statement(statement)?;
}

Ok(Value::Nil)
interpreter.eval_block(&body.v)
}) {
Ok(v) => v,
Err(ControlFlow::Return(v)) => v,
Expand Down Expand Up @@ -586,7 +582,10 @@ impl Interpreter {
.ok_or::<Exception>(cast_error!(v, "numeric"))?),
))
}
Expr::Block(Block { stmts, tail }) => self.scoped(|interpreter| {
Expr::Block(Spanned {
v: Block { stmts, tail },
..
}) => self.scoped(|interpreter| {
for stmt in stmts {
interpreter.exec_statement(stmt)?;
}
Expand All @@ -596,8 +595,38 @@ impl Interpreter {
None => Ok(Value::Nil),
}
})?,
Expr::If(box condition, body, else_) => {
let condition = self.eval_expr(condition)?;
let enter = match Cast::<bool>::cast(condition.clone()) {
Some(b) => b,
None => return Err(cast_error!(condition, ValueType::Bool.name())),
};

if enter {
self.eval_block(&body.v)?
} else if let Some(box expr) = else_ {
self.eval_expr(expr)?.v
} else {
Value::Nil
}
}
}))
}

fn eval_block(&mut self, block: impl Borrow<Block>) -> Result<Value, ControlFlow> {
let Block { stmts, tail } = block.borrow();

self.scoped(|interpreter| {
for stmt in stmts {
interpreter.exec_statement(stmt)?;
}

match tail {
Some(box expr) => Ok::<_, ControlFlow>(interpreter.eval_expr(expr)?.v),
None => Ok(Value::Nil),
}
})
}
}

impl Default for Interpreter {
Expand Down
16 changes: 13 additions & 3 deletions crates/saft-eval/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::interpreter::{ControlFlow, Interpreter};
use std::{borrow::Borrow, rc::Rc};
use std::borrow::Borrow;

use saft_ast::Statement;
use saft_ast::Block;
use saft_common::span::{Span, Spanned};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -239,7 +239,7 @@ pub enum Function {
#[derive(Debug, Clone)]
pub struct SaftFunction {
pub params: Vec<Spanned<String>>,
pub body: Rc<Vec<Spanned<Statement>>>,
pub body: Spanned<Block>,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -391,6 +391,16 @@ impl CastFrom<Value> for f64 {
}
}

impl<T, U: CastFrom<T>> CastFrom<Spanned<T>> for U {
fn ty_name() -> String {
U::ty_name()
}

fn cast_from(value: Spanned<T>) -> Option<Self> {
value.v.cast()
}
}

impl CastFrom<Value> for bool {
fn ty_name() -> String {
"bool".into()
Expand Down
2 changes: 2 additions & 0 deletions crates/saft-lexer/src/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ impl<'a> Lexer<'a> {
"or" => mktoken!(cur, T::Or),
"true" => mktoken!(cur, T::True),
"false" => mktoken!(cur, T::False),
"if" => mktoken!(cur, T::If),
"else" => mktoken!(cur, T::Else),
s => mktoken!(cur, T::Identifier(s.into())),
}
}
Expand Down
4 changes: 4 additions & 0 deletions crates/saft-lexer/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub enum Token {
Or,
True,
False,
If,
Else,
}

impl Token {
Expand Down Expand Up @@ -85,6 +87,8 @@ impl Token {
Bang => "'!'".into(),
True => "'true'".into(),
False => "'false'".into(),
If => "'if'".into(),
Else => "'else'".into(),
}
}
}
54 changes: 42 additions & 12 deletions crates/saft-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ impl<'a> Parser<'a> {
Ok(stmts)
}

pub fn parse_block(&mut self, start: Option<Span>) -> Result<Spanned<Expr>, Error> {
fn parse_block(&mut self, start: Option<Span>) -> Result<Spanned<Block>, Error> {
let start = match start {
Some(s) => s,
None => self.eat(Token::LBrace)?,
Expand All @@ -206,10 +206,10 @@ impl<'a> Parser<'a> {
if let Some(end) = self.try_eat(Token::RBrace) {
let s = start.join(end);

return Ok(s.spanned(Expr::Block(Block {
return Ok(s.spanned(Block {
stmts,
tail: Some(Box::new(e.clone())),
})));
}));
}
}
Statement::Item(_) => {}
Expand All @@ -225,7 +225,37 @@ impl<'a> Parser<'a> {

let s = start.join(end);

Ok(s.spanned(Expr::Block(Block { stmts, tail: None })))
Ok(s.spanned(Block { stmts, tail: None }))
}

fn parse_if(&mut self, start: Option<Span>) -> Result<Spanned<Expr>, Error> {
let start = match start {
Some(s) => s,
None => self.eat(Token::If)?,
};

let condition = self.parse_expr()?;

let block = self.parse_block(None)?;

let else_ = if self.try_eat(Token::Else).is_some() {
let peek = self.peek();
match peek.v {
Token::If => Some(self.parse_if(None)?),
Token::LBrace => {
let block = self.parse_block(None)?;
Some(block.s.clone().spanned(Expr::Block(block)))
}
_ => unexpected!(peek, "'if' or a block"),
}
} else {
None
}
.map(Box::new);

Ok(start
.join(block.s.clone())
.spanned(Expr::If(Box::new(condition), block, else_)))
}

pub fn parse_statement(&mut self) -> Result<Spanned<ast::Statement>, Error> {
Expand Down Expand Up @@ -259,7 +289,8 @@ impl<'a> Parser<'a> {
| Token::True
| Token::False
| Token::Bang
| Token::LBrace => {
| Token::LBrace
| Token::If => {
let expr = self.parse_expr()?;
Ok(expr.s.clone().spanned(Statement::Expr(expr)))
}
Expand Down Expand Up @@ -324,8 +355,10 @@ impl<'a> Parser<'a> {
Ok(s.spanned(Expr::Vec(exprs)))
}
T::LBrace => {
self.parse_block(Some(start))
let block = self.parse_block(Some(start))?;
Ok(block.s.clone().spanned(Expr::Block(block)))
}
T::If => self.parse_if(Some(start)),
T::True => Ok(st.s.spanned(Expr::Bool(true))),
T::False => Ok(st.s.spanned(Expr::Bool(false))),

Expand Down Expand Up @@ -450,19 +483,16 @@ impl<'a> Parser<'a> {

self.eat(Token::RParen)?;

self.eat(Token::LBrace)?;

let body = self.parse_statements(Token::RBrace)?;

let end = self.eat(Token::RBrace)?;
let body = self.parse_block(None)?;
let s = start.join(&body.s);

Ok(Spanned::new(
Statement::Item(Item::Fn {
ident,
params,
body,
}),
start.join(end),
s,
))
}
}
Expand Down

0 comments on commit 476ff58

Please sign in to comment.