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 {
.player: { .position: { .x: 10, .y: 20 }, },
};
};
}
let update = fn(state, events) {
let new = 100;
state.player.position.x = new;
return state;
};
}
let draw = fn(frame, state) {
frame.clear(0,0,0);
};
}
let migrate = fn(state) {
return { .player: { .pos: state.player.position } };
};
}
```
- 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(expr) = parse_set(tokens)? {
if let Some(_) = tokens.next_if(&Token::Semicolon) {
Ok(Some(ast::Definition {
mutable,
name,
expr,
}))
} else {
Err(Error::UnexpectedToken {
expected: Token::Semicolon,
got: tokens.next(),
})
}
} else {
Err(Error::UnexpectedToken {
expected: Token::Equals,
@ -180,6 +173,45 @@ fn parse_simple_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
parse_record,
parse_vector,
|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>> {
tokens.many(parse_statement)
}
fn parse_statement(tokens: &mut Tokens) -> ParseResult<ast::Statement> {
tokens.one_of(vec![
|tokens| {
if let Some(expr) = parse_expr(tokens)?.map(ast::Statement::Expr) {
if let Some(_) = tokens.next_if(&Token::Semicolon) {
Ok(Some(expr))
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() {
stmts.push(ast::Statement::Expr(ast::UNIT));
println!("stmts: {stmts:#?}");
Ok(Some(stmts))
} else {
println!("parse statement expr");
Err(Error::UnexpectedToken {
expected: Token::Semicolon,
got: tokens.next(),
})
println!("stmts or not: {stmts:#?} {tokens:#?}");
Ok(Some(stmts))
}
} else {
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| {
if let Some(_) = tokens.next_if(&Token::Return) {
let expr = parse_expr(tokens)?;
if let Some(_) = tokens.next_if(&Token::Semicolon) {
Ok(Some(ast::Statement::Return(expr)))
} else {
Err(Error::UnexpectedToken {
expected: (Token::Return),
got: tokens.next(),
})
}
} else {
Ok(None)
}
@ -411,6 +434,18 @@ mod tests {
insta::assert_debug_snapshot!(result);
}
#[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() {
let program = "[]".to_string();
let result = parse(&mut scan(program), parse_expr);
@ -454,13 +489,13 @@ mod tests {
}
#[test]
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);
insta::assert_debug_snapshot!(result);
}
#[test]
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);
insta::assert_debug_snapshot!(result);
}
@ -471,21 +506,21 @@ let setup = fn() {
return {
.player: { .position: { .x: 10, .y: 20 }, },
};
};
}
let update = fn(state, events) {
let new = 100;
state.player.position.x = new;
return state;
};
}
let draw = fn(frame, state) {
frame.clear(0,0,0);
};
}
let migrate = fn(state) {
return { .player: { .pos: state.player.position } };
};
}
"
.to_string();
let result = parse(&mut scan(program), parse_definitions);

View file

@ -30,9 +30,9 @@ impl Scanner {
self.cursor.column += 1;
}
}
//if let Some(chr) = ch {
// if let Some(chr) = ch {
// println!("'{}' {}", chr, self.cursor);
//}
// }
ch
}
pub fn cursor(&self) -> Pos {
@ -303,6 +303,8 @@ pub fn scan(source: String) -> Tokens {
"fn" => Token::Fn,
"let" => Token::Let,
"mut" => Token::Mut,
"if" => Token::If,
"else" => Token::Else,
"return" => Token::Return,
"true" => Token::True,
"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,
Fn,
Mut,
If,
Else,
Return,
OpenParen,
CloseParen,
@ -77,10 +79,13 @@ impl Tokens {
self.0.last()
}
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> {
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,
(Token::Identifier(_), Token::Identifier(_)) => true,
(Token::Number(_), Token::Number(_)) => true,
@ -88,7 +93,9 @@ impl Tokens {
(Token::Label(_), Token::Label(_)) => true,
(Token::Op(_), Token::Op(_)) => true,
_ => false,
})
});
// println!("'{:?}'", t);
t
}
pub fn between<T>(&mut self, start: &Token, end: &Token, parser: Parser<T>) -> ParseResult<T> {
if let Some(_start) = self.next_if(start) {