feat: if expressions

This commit is contained in:
rvcas 2022-10-04 13:18:38 -04:00 committed by Lucas
parent dba82d544d
commit 6ef8ba5c35
6 changed files with 153 additions and 4 deletions

View File

@ -437,6 +437,16 @@ pub enum ClauseGuard<Type, RecordTag> {
Constant(Constant<Type, RecordTag>), Constant(Constant<Type, RecordTag>),
} }
pub type TypedIfBranch = IfBranch<TypedExpr>;
pub type UntypedIfBranch = IfBranch<UntypedExpr>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IfBranch<Expr> {
pub condition: Expr,
pub body: Expr,
pub location: Span,
}
pub struct TypedRecordUpdateArg { pub struct TypedRecordUpdateArg {
pub label: String, pub label: String,
pub location: Span, pub location: Span,

View File

@ -4,8 +4,8 @@ use vec1::Vec1;
use crate::{ use crate::{
ast::{ ast::{
Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, Pattern, RecordUpdateSpread, Span, Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, IfBranch, Pattern,
TodoKind, TypedRecordUpdateArg, UntypedRecordUpdateArg, RecordUpdateSpread, Span, TodoKind, TypedRecordUpdateArg, UntypedRecordUpdateArg,
}, },
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor}, tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
}; };
@ -104,6 +104,13 @@ pub enum TypedExpr {
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>, String>>, clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>, String>>,
}, },
If {
location: Span,
branches: Vec1<IfBranch<Self>>,
final_else: Box<Self>,
tipo: Arc<Type>,
},
RecordAccess { RecordAccess {
location: Span, location: Span,
tipo: Arc<Type>, tipo: Arc<Type>,
@ -233,6 +240,12 @@ pub enum UntypedExpr {
clauses: Vec<Clause<Self, (), (), ()>>, clauses: Vec<Clause<Self, (), (), ()>>,
}, },
If {
location: Span,
branches: Vec1<IfBranch<Self>>,
final_else: Box<Self>,
},
FieldAccess { FieldAccess {
location: Span, location: Span,
label: String, label: String,
@ -338,7 +351,8 @@ impl UntypedExpr {
| Self::TupleIndex { location, .. } | Self::TupleIndex { location, .. }
| Self::FieldAccess { location, .. } | Self::FieldAccess { location, .. }
| Self::RecordUpdate { location, .. } | Self::RecordUpdate { location, .. }
| Self::Negate { location, .. } => *location, | Self::Negate { location, .. }
| Self::If { location, .. } => *location,
Self::Sequence { Self::Sequence {
location, location,
expressions, expressions,

View File

@ -25,8 +25,8 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
just("|>").to(Token::Pipe), just("|>").to(Token::Pipe),
just(',').to(Token::Comma), just(',').to(Token::Comma),
just(':').to(Token::Colon), just(':').to(Token::Colon),
just('|').to(Token::Vbar),
just("||").to(Token::VbarVbar), just("||").to(Token::VbarVbar),
just('|').to(Token::Vbar),
just("&&").to(Token::AmperAmper), just("&&").to(Token::AmperAmper),
)); ));
@ -63,6 +63,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
"const" => Token::Const, "const" => Token::Const,
"fn" => Token::Fn, "fn" => Token::Fn,
"if" => Token::If, "if" => Token::If,
"else" => Token::Else,
"is" => Token::Is, "is" => Token::Is,
"let" => Token::Let, "let" => Token::Let,
"opaque" => Token::Opaque, "opaque" => Token::Opaque,

View File

@ -443,6 +443,40 @@ pub fn expr_parser(
}, },
); );
let if_parser = just(Token::If)
.ignore_then(r.clone().then(block_parser.clone()).map_with_span(
|(condition, body), span| ast::IfBranch {
condition,
body,
location: span,
},
))
.then(
just(Token::Else)
.ignore_then(just(Token::If))
.ignore_then(r.clone().then(block_parser.clone()).map_with_span(
|(condition, body), span| ast::IfBranch {
condition,
body,
location: span,
},
))
.repeated(),
)
.then_ignore(just(Token::Else))
.then(block_parser.clone())
.map_with_span(|((first, alternative_branches), final_else), span| {
let mut branches = vec1::vec1![first];
branches.extend(alternative_branches);
expr::UntypedExpr::If {
location: span,
branches,
final_else: Box::new(final_else),
}
});
let expr_unit_parser = choice(( let expr_unit_parser = choice((
string_parser, string_parser,
int_parser, int_parser,
@ -454,6 +488,7 @@ pub fn expr_parser(
when_parser, when_parser,
let_parser, let_parser,
assert_parser, assert_parser,
if_parser,
)); ));
// Parsing a function call into the appropriate structure // Parsing a function call into the appropriate structure

View File

@ -93,6 +93,18 @@ fn module() {
fn update_name(user: User, name: String) -> User { fn update_name(user: User, name: String) -> User {
User { ..user, name: "Aiken", } User { ..user, name: "Aiken", }
} }
fn ifs() {
if True {
1 + 1
} else if a < 4 {
5
} else if a || b {
6
} else {
3
}
}
"#; "#;
let len = code.chars().count(); let len = code.chars().count();
@ -992,6 +1004,81 @@ fn module() {
},), },),
return_type: (), return_type: (),
}, },
ast::UntypedDefinition::Fn {
arguments: vec![],
body: expr::UntypedExpr::If {
location: Span::new(SrcId::empty(), 1823..2036),
branches: vec1::vec1![
ast::IfBranch {
condition: expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1826..1830),
name: "True".to_string(),
},
body: expr::UntypedExpr::BinOp {
location: Span::new(SrcId::empty(), 1853..1858),
name: ast::BinOp::AddInt,
left: Box::new(expr::UntypedExpr::Int {
location: Span::new(SrcId::empty(), 1853..1854),
value: "1".to_string(),
}),
right: Box::new(expr::UntypedExpr::Int {
location: Span::new(SrcId::empty(), 1857..1858),
value: "1".to_string(),
}),
},
location: Span::new(SrcId::empty(), 1826..1876),
},
ast::IfBranch {
condition: expr::UntypedExpr::BinOp {
location: Span::new(SrcId::empty(), 1885..1890),
name: ast::BinOp::LtInt,
left: Box::new(expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1885..1886),
name: "a".to_string(),
}),
right: Box::new(expr::UntypedExpr::Int {
location: Span::new(SrcId::empty(), 1889..1890),
value: "4".to_string(),
}),
},
body: expr::UntypedExpr::Int {
location: Span::new(SrcId::empty(), 1913..1914),
value: "5".to_string(),
},
location: Span::new(SrcId::empty(), 1885..1932),
},
ast::IfBranch {
condition: expr::UntypedExpr::BinOp {
location: Span::new(SrcId::empty(), 1941..1947),
name: ast::BinOp::Or,
left: Box::new(expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1941..1942),
name: "a".to_string(),
}),
right: Box::new(expr::UntypedExpr::Var {
location: Span::new(SrcId::empty(), 1946..1947),
name: "b".to_string(),
}),
},
body: expr::UntypedExpr::Int {
location: Span::new(SrcId::empty(), 1970..1971),
value: "6".to_string(),
},
location: Span::new(SrcId::empty(), 1941..1989),
},
],
final_else: Box::new(expr::UntypedExpr::Int {
location: Span::new(SrcId::empty(), 2017..2018),
value: "3".to_string(),
}),
},
doc: None,
location: Span::new(SrcId::empty(), 1796..2050),
name: "ifs".to_string(),
public: false,
return_annotation: None,
return_type: (),
},
] ]
}, },
); );

View File

@ -61,6 +61,7 @@ pub enum Token {
Const, Const,
Fn, Fn,
If, If,
Else,
Is, Is,
Let, Let,
Opaque, Opaque,
@ -134,6 +135,7 @@ impl fmt::Display for Token {
Token::Const => "const", Token::Const => "const",
Token::Fn => "fn", Token::Fn => "fn",
Token::If => "if", Token::If => "if",
Token::Else => "else",
Token::Use => "import", Token::Use => "import",
Token::Let => "let", Token::Let => "let",
Token::Opaque => "opaque", Token::Opaque => "opaque",