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>),
}
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 label: String,
pub location: Span,

View File

@ -4,8 +4,8 @@ use vec1::Vec1;
use crate::{
ast::{
Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, Pattern, RecordUpdateSpread, Span,
TodoKind, TypedRecordUpdateArg, UntypedRecordUpdateArg,
Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, IfBranch, Pattern,
RecordUpdateSpread, Span, TodoKind, TypedRecordUpdateArg, UntypedRecordUpdateArg,
},
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
};
@ -104,6 +104,13 @@ pub enum TypedExpr {
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>, String>>,
},
If {
location: Span,
branches: Vec1<IfBranch<Self>>,
final_else: Box<Self>,
tipo: Arc<Type>,
},
RecordAccess {
location: Span,
tipo: Arc<Type>,
@ -233,6 +240,12 @@ pub enum UntypedExpr {
clauses: Vec<Clause<Self, (), (), ()>>,
},
If {
location: Span,
branches: Vec1<IfBranch<Self>>,
final_else: Box<Self>,
},
FieldAccess {
location: Span,
label: String,
@ -338,7 +351,8 @@ impl UntypedExpr {
| Self::TupleIndex { location, .. }
| Self::FieldAccess { location, .. }
| Self::RecordUpdate { location, .. }
| Self::Negate { location, .. } => *location,
| Self::Negate { location, .. }
| Self::If { location, .. } => *location,
Self::Sequence {
location,
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::Comma),
just(':').to(Token::Colon),
just('|').to(Token::Vbar),
just("||").to(Token::VbarVbar),
just('|').to(Token::Vbar),
just("&&").to(Token::AmperAmper),
));
@ -63,6 +63,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
"const" => Token::Const,
"fn" => Token::Fn,
"if" => Token::If,
"else" => Token::Else,
"is" => Token::Is,
"let" => Token::Let,
"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((
string_parser,
int_parser,
@ -454,6 +488,7 @@ pub fn expr_parser(
when_parser,
let_parser,
assert_parser,
if_parser,
));
// Parsing a function call into the appropriate structure

View File

@ -93,6 +93,18 @@ fn module() {
fn update_name(user: User, name: String) -> User {
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();
@ -992,6 +1004,81 @@ fn module() {
},),
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,
Fn,
If,
Else,
Is,
Let,
Opaque,
@ -134,6 +135,7 @@ impl fmt::Display for Token {
Token::Const => "const",
Token::Fn => "fn",
Token::If => "if",
Token::Else => "else",
Token::Use => "import",
Token::Let => "let",
Token::Opaque => "opaque",