feat: if expressions
This commit is contained in:
parent
dba82d544d
commit
6ef8ba5c35
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: (),
|
||||
},
|
||||
]
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue