feat: expect boolean sugar

This commit is contained in:
rvcas
2023-07-15 20:50:02 -04:00
parent d009358266
commit 1b8e94fe32
9 changed files with 198 additions and 31 deletions

View File

@@ -9,25 +9,7 @@ use crate::{
pub fn let_(
r: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
assignment(r, ast::AssignmentKind::Let)
}
pub fn expect(
r: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
assignment(r, ast::AssignmentKind::Expect)
}
fn assignment(
r: Recursive<'_, Token, UntypedExpr, ParseError>,
kind: ast::AssignmentKind,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
let keyword = match kind {
ast::AssignmentKind::Let => Token::Let,
ast::AssignmentKind::Expect => Token::Expect,
};
just(keyword)
just(Token::Let)
.ignore_then(pattern())
.then(just(Token::Colon).ignore_then(annotation()).or_not())
.then_ignore(just(Token::Equal))
@@ -37,12 +19,50 @@ fn assignment(
location: span,
value: Box::new(value),
pattern,
kind,
kind: ast::AssignmentKind::Let,
annotation,
},
)
}
pub fn expect(
r: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
just(Token::Expect)
.ignore_then(
pattern()
.then(just(Token::Colon).ignore_then(annotation()).or_not())
.then_ignore(just(Token::Equal))
.or_not(),
)
.then(r.clone())
.map_with_span(move |(opt_pattern, value), span| {
let (pattern, annotation) = opt_pattern.unwrap_or_else(|| {
(
ast::UntypedPattern::Constructor {
is_record: false,
location: span,
name: "True".to_string(),
arguments: vec![],
module: None,
constructor: (),
with_spread: false,
tipo: (),
},
None,
)
});
UntypedExpr::Assignment {
location: span,
value: Box::new(value),
pattern,
kind: ast::AssignmentKind::Expect,
annotation,
}
})
}
#[cfg(test)]
mod tests {
use crate::assert_expr;
@@ -56,4 +76,9 @@ mod tests {
fn expect() {
assert_expr!("expect Some(x) = something.field");
}
#[test]
fn expect_bool_sugar() {
assert_expr!("expect something.field == wow");
}
}

View File

@@ -0,0 +1,35 @@
---
source: crates/aiken-lang/src/parser/expr/assignment.rs
description: "Code:\n\nexpect something.field == wow"
---
Assignment {
location: 0..29,
value: BinOp {
location: 7..29,
name: Eq,
left: FieldAccess {
location: 7..22,
label: "field",
container: Var {
location: 7..16,
name: "something",
},
},
right: Var {
location: 26..29,
name: "wow",
},
},
pattern: Constructor {
is_record: false,
location: 0..29,
name: "True",
arguments: [],
module: None,
constructor: (),
with_spread: false,
tipo: (),
},
kind: Expect,
annotation: None,
}

View File

@@ -83,3 +83,18 @@ pub(crate) fn args(
.unwrap_or_else(|| (vec![], false, false))
})
}
#[cfg(test)]
mod tests {
use crate::assert_pattern;
#[test]
fn constructor_basic() {
assert_pattern!("True");
}
#[test]
fn constructor_module_select() {
assert_pattern!("module.Foo");
}
}

View File

@@ -0,0 +1,14 @@
---
source: crates/aiken-lang/src/parser/pattern/constructor.rs
description: "Code:\n\nTrue"
---
Constructor {
is_record: false,
location: 0..4,
name: "True",
arguments: [],
module: None,
constructor: (),
with_spread: false,
tipo: (),
}

View File

@@ -0,0 +1,16 @@
---
source: crates/aiken-lang/src/parser/pattern/constructor.rs
description: "Code:\n\nmodule.Foo"
---
Constructor {
is_record: false,
location: 0..10,
name: "Foo",
arguments: [],
module: Some(
"module",
),
constructor: (),
with_spread: false,
tipo: (),
}

View File

@@ -61,6 +61,27 @@ macro_rules! assert_annotation {
};
}
#[macro_export]
macro_rules! assert_pattern {
($code:expr) => {
use chumsky::Parser;
let $crate::parser::lexer::LexInfo { tokens, .. } = $crate::parser::lexer::run(indoc::indoc! { $code }).unwrap();
let stream = chumsky::Stream::from_iter($crate::ast::Span::create(tokens.len(), 1), tokens.into_iter());
let result = $crate::parser::pattern().parse(stream).unwrap();
insta::with_settings!({
description => concat!("Code:\n\n", indoc::indoc! { $code }),
prepend_module_to_snapshot => false,
omit_expression => true
}, {
insta::assert_debug_snapshot!(result);
});
};
}
#[macro_export]
macro_rules! assert_module {
($code:expr) => {