if then else

This commit is contained in:
me 2025-12-20 15:34:30 +02:00
parent 621c674109
commit e29b8e1620
6 changed files with 184 additions and 52 deletions

View file

@ -17,21 +17,21 @@ let setup = fn() {
return { return {
.player: { .position: { .x: 10, .y: 20 }, }, .player: { .position: { .x: 10, .y: 20 }, },
}; };
}; }
let update = fn(state, events) { let update = fn(state, events) {
let new = 100; let new = 100;
state.player.position.x = new; state.player.position.x = new;
return state; return state;
}; }
let draw = fn(frame, state) { let draw = fn(frame, state) {
frame.clear(0,0,0); frame.clear(0,0,0);
}; }
let migrate = fn(state) { let migrate = fn(state) {
return { .player: { .pos: state.player.position } }; return { .player: { .pos: state.player.position } };
}; }
``` ```
- dynamic software updating could occur every frame - dynamic software updating could occur every frame

View file

@ -77,18 +77,11 @@ fn parse_definition(tokens: &mut Tokens) -> ParseResult<ast::Definition> {
}; };
if let Some(name) = parse_identifier_name(tokens)? { if let Some(name) = parse_identifier_name(tokens)? {
if let Some(expr) = parse_set(tokens)? { if let Some(expr) = parse_set(tokens)? {
if let Some(_) = tokens.next_if(&Token::Semicolon) {
Ok(Some(ast::Definition { Ok(Some(ast::Definition {
mutable, mutable,
name, name,
expr, expr,
})) }))
} else {
Err(Error::UnexpectedToken {
expected: Token::Semicolon,
got: tokens.next(),
})
}
} else { } else {
Err(Error::UnexpectedToken { Err(Error::UnexpectedToken {
expected: Token::Equals, expected: Token::Equals,
@ -180,6 +173,45 @@ fn parse_simple_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
parse_record, parse_record,
parse_vector, parse_vector,
|t| t.between(&Token::OpenParen, &Token::CloseParen, parse_expr), |t| t.between(&Token::OpenParen, &Token::CloseParen, parse_expr),
|t| {
if let Some(_) = t.next_if(&Token::If) {
if let Some(condition) = parse_expr(t)? {
if let Some(then) = t
.between(&Token::OpenCurly, &Token::CloseCurly, parse_block)?
.map(ast::Expr::Block)
{
if let Some(r#else) = if let Some(_) = t.next_if(&Token::Else) {
Ok(
t.between(&Token::OpenCurly, &Token::CloseCurly, parse_block)?
.map(ast::Expr::Block),
)
} else {
Ok(Some(ast::UNIT))
}? {
Ok(Some(ast::Expr::If {
condition: Box::new(condition),
then: Box::new(then),
r#else: Box::new(r#else),
}))
} else {
Err(Error::UnexpectedTokenForParser(
"if then block".into(),
t.next(),
))
}
} else {
Err(Error::UnexpectedTokenForParser(
"if condition".into(),
t.next(),
))
}
} else {
Err(Error::UnexpectedTokenForParser("if".into(), t.next()))
}
} else {
Ok(None)
}
},
]) ])
} }
@ -211,38 +243,29 @@ fn parse_fn(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
} }
fn parse_block(tokens: &mut Tokens) -> ParseResult<Vec<ast::Statement>> { fn parse_block(tokens: &mut Tokens) -> ParseResult<Vec<ast::Statement>> {
tokens.many(parse_statement) if let Some(mut stmts) = tokens.many_sep_by(&Token::Semicolon, parse_statement)? {
} println!("{stmts:#?} {} {:#?}", stmts.len(), tokens.peek());
if stmts.len() > 0 && tokens.next_if(&Token::Semicolon).is_some() {
fn parse_statement(tokens: &mut Tokens) -> ParseResult<ast::Statement> { stmts.push(ast::Statement::Expr(ast::UNIT));
tokens.one_of(vec![ println!("stmts: {stmts:#?}");
|tokens| { Ok(Some(stmts))
if let Some(expr) = parse_expr(tokens)?.map(ast::Statement::Expr) {
if let Some(_) = tokens.next_if(&Token::Semicolon) {
Ok(Some(expr))
} else { } else {
println!("parse statement expr"); println!("stmts or not: {stmts:#?} {tokens:#?}");
Err(Error::UnexpectedToken { Ok(Some(stmts))
expected: Token::Semicolon,
got: tokens.next(),
})
} }
} else { } else {
Ok(None) Ok(None)
} }
}, }
fn parse_statement(tokens: &mut Tokens) -> ParseResult<ast::Statement> {
tokens.one_of(vec![
|tokens| Ok(parse_expr(tokens)?.map(ast::Statement::Expr)),
|tokens| Ok(parse_definition(tokens)?.map(ast::Statement::Let)), |tokens| Ok(parse_definition(tokens)?.map(ast::Statement::Let)),
|tokens| { |tokens| {
if let Some(_) = tokens.next_if(&Token::Return) { if let Some(_) = tokens.next_if(&Token::Return) {
let expr = parse_expr(tokens)?; let expr = parse_expr(tokens)?;
if let Some(_) = tokens.next_if(&Token::Semicolon) {
Ok(Some(ast::Statement::Return(expr))) Ok(Some(ast::Statement::Return(expr)))
} else {
Err(Error::UnexpectedToken {
expected: (Token::Return),
got: tokens.next(),
})
}
} else { } else {
Ok(None) Ok(None)
} }
@ -411,6 +434,18 @@ mod tests {
insta::assert_debug_snapshot!(result); insta::assert_debug_snapshot!(result);
} }
#[test] #[test]
fn if_then_else() {
let program = "if 1 == 1 { \"Hello\" } else { \"World\" }".to_string();
let result = parse(&mut scan(program), parse_expr);
insta::assert_debug_snapshot!(result);
}
#[test]
fn if_then() {
let program = "if !(3 < 2) { \"Hello\" }".to_string();
let result = parse(&mut scan(program), parse_expr);
insta::assert_debug_snapshot!(result);
}
#[test]
fn vector_empty() { fn vector_empty() {
let program = "[]".to_string(); let program = "[]".to_string();
let result = parse(&mut scan(program), parse_expr); let result = parse(&mut scan(program), parse_expr);
@ -454,13 +489,13 @@ mod tests {
} }
#[test] #[test]
fn let_number() { fn let_number() {
let program = "let x = 108;".to_string(); let program = "let x = 108".to_string();
let result = parse(&mut scan(program), parse_definition); let result = parse(&mut scan(program), parse_definition);
insta::assert_debug_snapshot!(result); insta::assert_debug_snapshot!(result);
} }
#[test] #[test]
fn let_mut_number() { fn let_mut_number() {
let program = "let mut x = 108;".to_string(); let program = "let mut x = 108".to_string();
let result = parse(&mut scan(program), parse_definition); let result = parse(&mut scan(program), parse_definition);
insta::assert_debug_snapshot!(result); insta::assert_debug_snapshot!(result);
} }
@ -471,21 +506,21 @@ let setup = fn() {
return { return {
.player: { .position: { .x: 10, .y: 20 }, }, .player: { .position: { .x: 10, .y: 20 }, },
}; };
}; }
let update = fn(state, events) { let update = fn(state, events) {
let new = 100; let new = 100;
state.player.position.x = new; state.player.position.x = new;
return state; return state;
}; }
let draw = fn(frame, state) { let draw = fn(frame, state) {
frame.clear(0,0,0); frame.clear(0,0,0);
}; }
let migrate = fn(state) { let migrate = fn(state) {
return { .player: { .pos: state.player.position } }; return { .player: { .pos: state.player.position } };
}; }
" "
.to_string(); .to_string();
let result = parse(&mut scan(program), parse_definitions); let result = parse(&mut scan(program), parse_definitions);

View file

@ -30,9 +30,9 @@ impl Scanner {
self.cursor.column += 1; self.cursor.column += 1;
} }
} }
//if let Some(chr) = ch { // if let Some(chr) = ch {
// println!("'{}' {}", chr, self.cursor); // println!("'{}' {}", chr, self.cursor);
//} // }
ch ch
} }
pub fn cursor(&self) -> Pos { pub fn cursor(&self) -> Pos {
@ -303,6 +303,8 @@ pub fn scan(source: String) -> Tokens {
"fn" => Token::Fn, "fn" => Token::Fn,
"let" => Token::Let, "let" => Token::Let,
"mut" => Token::Mut, "mut" => Token::Mut,
"if" => Token::If,
"else" => Token::Else,
"return" => Token::Return, "return" => Token::Return,
"true" => Token::True, "true" => Token::True,
"false" => Token::False, "false" => Token::False,

View file

@ -0,0 +1,43 @@
---
source: src/parser/parser.rs
expression: result
---
Ok(
If {
condition: Not(
Op {
lhs: Value(
Int(
3,
),
),
op: Compare(
Lt,
),
rhs: Value(
Int(
2,
),
),
},
),
then: Block(
[
Expr(
Value(
String(
"Hello",
),
),
),
],
),
else: Value(
Record(
Record(
{},
),
),
),
},
)

View file

@ -0,0 +1,45 @@
---
source: src/parser/parser.rs
expression: result
---
Ok(
If {
condition: Op {
lhs: Value(
Int(
1,
),
),
op: Compare(
Eq,
),
rhs: Value(
Int(
1,
),
),
},
then: Block(
[
Expr(
Value(
String(
"Hello",
),
),
),
],
),
else: Block(
[
Expr(
Value(
String(
"World",
),
),
),
],
),
},
)

View file

@ -21,6 +21,8 @@ pub enum Token {
Let, Let,
Fn, Fn,
Mut, Mut,
If,
Else,
Return, Return,
OpenParen, OpenParen,
CloseParen, CloseParen,
@ -77,10 +79,13 @@ impl Tokens {
self.0.last() self.0.last()
} }
pub fn next(&mut self) -> Option<LocatedToken> { pub fn next(&mut self) -> Option<LocatedToken> {
self.0.pop() let t = self.0.pop();
// println!("'{:?}'", t);
t
} }
pub fn next_if(&mut self, token: &Token) -> Option<LocatedToken> { pub fn next_if(&mut self, token: &Token) -> Option<LocatedToken> {
self.0.pop_if(|t| match (t.token.clone(), token) { let t = self.0.pop_if(|t| match (t.token.clone(), token) {
(a, b) if a == *b => true, (a, b) if a == *b => true,
(Token::Identifier(_), Token::Identifier(_)) => true, (Token::Identifier(_), Token::Identifier(_)) => true,
(Token::Number(_), Token::Number(_)) => true, (Token::Number(_), Token::Number(_)) => true,
@ -88,7 +93,9 @@ impl Tokens {
(Token::Label(_), Token::Label(_)) => true, (Token::Label(_), Token::Label(_)) => true,
(Token::Op(_), Token::Op(_)) => true, (Token::Op(_), Token::Op(_)) => true,
_ => false, _ => false,
}) });
// println!("'{:?}'", t);
t
} }
pub fn between<T>(&mut self, start: &Token, end: &Token, parser: Parser<T>) -> ParseResult<T> { pub fn between<T>(&mut self, start: &Token, end: &Token, parser: Parser<T>) -> ParseResult<T> {
if let Some(_start) = self.next_if(start) { if let Some(_start) = self.next_if(start) {