From 5c59b816ead882e95ab96f152b64eca14ed5a497 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 4 Apr 2024 10:37:09 +0200 Subject: [PATCH] Add parser for 'Pair' pattern And a few more tests along the way for others. Note that it is important here that we try to parse for a 'Pair' BEFORE we try to parse for a constructor pattern. Because the latter would swallow any Pair pattern. --- crates/aiken-lang/src/parser/pattern/mod.rs | 86 ++++++++++++++++--- crates/aiken-lang/src/parser/pattern/pair.rs | 25 ++++++ .../snapshots/pattern_constructor_labels.snap | 35 ++++++++ .../pattern_constructor_no_labels.snap | 31 +++++++ .../pattern_constructor_pair_interleaved.snap | 44 ++++++++++ .../snapshots/pattern_constructor_spread.snap | 25 ++++++ .../snapshots/pattern_discard_named.snap | 8 ++ .../snapshots/pattern_discard_unnamed.snap | 8 ++ .../snapshots/pattern_list_spread.snap | 19 ++++ .../snapshots/pattern_pair_discards.snap | 15 ++++ .../pattern_pair_explicit_depth_1.snap | 24 ++++++ .../pattern_pair_explicit_depth_2.snap | 60 +++++++++++++ .../parser/pattern/snapshots/pattern_var.snap | 8 ++ 13 files changed, 376 insertions(+), 12 deletions(-) create mode 100644 crates/aiken-lang/src/parser/pattern/pair.rs create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_labels.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_no_labels.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_pair_interleaved.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_spread.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_named.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_unnamed.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_list_spread.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_discards.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_1.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_2.snap create mode 100644 crates/aiken-lang/src/parser/pattern/snapshots/pattern_var.snap diff --git a/crates/aiken-lang/src/parser/pattern/mod.rs b/crates/aiken-lang/src/parser/pattern/mod.rs index 02722fb4..21989a73 100644 --- a/crates/aiken-lang/src/parser/pattern/mod.rs +++ b/crates/aiken-lang/src/parser/pattern/mod.rs @@ -4,30 +4,32 @@ mod constructor; mod discard; mod int; mod list; +mod pair; mod tuple; mod var; -pub use constructor::parser as constructor; -pub use discard::parser as discard; -pub use int::parser as int; -pub use list::parser as list; -pub use tuple::parser as tuple; -pub use var::parser as var; - use crate::{ ast::UntypedPattern, parser::{error::ParseError, token::Token}, }; +pub use constructor::parser as constructor; +pub use discard::parser as discard; +pub use int::parser as int; +pub use list::parser as list; +pub use pair::parser as pair; +pub use tuple::parser as tuple; +pub use var::parser as var; pub fn parser() -> impl Parser { - recursive(|expression| { + recursive(|pattern| { choice(( - var(expression.clone()), - constructor(expression.clone()), + var(pattern.clone()), + pair(pattern.clone()), + constructor(pattern.clone()), discard(), int(), - tuple(expression.clone()), - list(expression), + tuple(pattern.clone()), + list(pattern), )) .then( just(Token::As) @@ -47,3 +49,63 @@ pub fn parser() -> impl Parser { }) }) } + +#[cfg(test)] +mod tests { + use crate::assert_pattern; + + #[test] + fn pattern_var() { + assert_pattern!("foo"); + } + + #[test] + fn pattern_discard_unnamed() { + assert_pattern!("_"); + } + + #[test] + fn pattern_discard_named() { + assert_pattern!("_foo"); + } + + #[test] + fn pattern_pair_discards() { + assert_pattern!("Pair(_, _)"); + } + + #[test] + fn pattern_pair_explicit_depth_1() { + assert_pattern!("Pair(14, True)"); + } + + #[test] + fn pattern_pair_explicit_depth_2() { + assert_pattern!("Pair([1,2,3], Pair((14, 42), _))"); + } + + #[test] + fn pattern_constructor_no_labels() { + assert_pattern!("Foo(a, b)"); + } + + #[test] + fn pattern_constructor_labels() { + assert_pattern!("Foo { a, b }"); + } + + #[test] + fn pattern_constructor_spread() { + assert_pattern!("Foo { a, .. }"); + } + + #[test] + fn pattern_constructor_pair_interleaved() { + assert_pattern!("Foo(a, Pair(1, 2))"); + } + + #[test] + fn pattern_list_spread() { + assert_pattern!("[head, ..]"); + } +} diff --git a/crates/aiken-lang/src/parser/pattern/pair.rs b/crates/aiken-lang/src/parser/pattern/pair.rs new file mode 100644 index 00000000..58be7614 --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/pair.rs @@ -0,0 +1,25 @@ +use crate::{ + ast::UntypedPattern, + builtins::PAIR, + parser::{error::ParseError, token::Token}, +}; +use chumsky::prelude::*; + +pub fn parser( + pattern: Recursive<'_, Token, UntypedPattern, ParseError>, +) -> impl Parser + '_ { + select! {Token::UpName { name } if name == PAIR => name} + .ignore_then(choice(( + just(Token::LeftParen), + just(Token::NewLineLeftParen), + ))) + .then(pattern.clone()) + .then_ignore(just(Token::Comma)) + .then(pattern.clone()) + .then_ignore(just(Token::RightParen)) + .map_with_span(|((_name, fst), snd), location| UntypedPattern::Pair { + fst: Box::new(fst), + snd: Box::new(snd), + location, + }) +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_labels.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_labels.snap new file mode 100644 index 00000000..ed12efb8 --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_labels.snap @@ -0,0 +1,35 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nFoo { a, b }" +--- +Constructor { + is_record: true, + location: 0..12, + name: "Foo", + arguments: [ + CallArg { + label: Some( + "a", + ), + location: 6..7, + value: Var { + location: 6..7, + name: "a", + }, + }, + CallArg { + label: Some( + "b", + ), + location: 9..10, + value: Var { + location: 9..10, + name: "b", + }, + }, + ], + module: None, + constructor: (), + with_spread: false, + tipo: (), +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_no_labels.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_no_labels.snap new file mode 100644 index 00000000..0d04a988 --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_no_labels.snap @@ -0,0 +1,31 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nFoo(a, b)" +--- +Constructor { + is_record: false, + location: 0..9, + name: "Foo", + arguments: [ + CallArg { + label: None, + location: 4..5, + value: Var { + location: 4..5, + name: "a", + }, + }, + CallArg { + label: None, + location: 7..8, + value: Var { + location: 7..8, + name: "b", + }, + }, + ], + module: None, + constructor: (), + with_spread: false, + tipo: (), +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_pair_interleaved.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_pair_interleaved.snap new file mode 100644 index 00000000..78af775c --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_pair_interleaved.snap @@ -0,0 +1,44 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nFoo(a, Pair(1, 2))" +--- +Constructor { + is_record: false, + location: 0..18, + name: "Foo", + arguments: [ + CallArg { + label: None, + location: 4..5, + value: Var { + location: 4..5, + name: "a", + }, + }, + CallArg { + label: None, + location: 7..17, + value: Pair { + location: 7..17, + fst: Int { + location: 12..13, + value: "1", + base: Decimal { + numeric_underscore: false, + }, + }, + snd: Int { + location: 15..16, + value: "2", + base: Decimal { + numeric_underscore: false, + }, + }, + }, + }, + ], + module: None, + constructor: (), + with_spread: false, + tipo: (), +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_spread.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_spread.snap new file mode 100644 index 00000000..499d0e00 --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_constructor_spread.snap @@ -0,0 +1,25 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nFoo { a, .. }" +--- +Constructor { + is_record: true, + location: 0..13, + name: "Foo", + arguments: [ + CallArg { + label: Some( + "a", + ), + location: 6..7, + value: Var { + location: 6..7, + name: "a", + }, + }, + ], + module: None, + constructor: (), + with_spread: true, + tipo: (), +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_named.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_named.snap new file mode 100644 index 00000000..bc0185c9 --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_named.snap @@ -0,0 +1,8 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\n_foo" +--- +Discard { + name: "_foo", + location: 0..4, +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_unnamed.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_unnamed.snap new file mode 100644 index 00000000..47feccfd --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_discard_unnamed.snap @@ -0,0 +1,8 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\n_" +--- +Discard { + name: "_", + location: 0..1, +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_list_spread.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_list_spread.snap new file mode 100644 index 00000000..723df47e --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_list_spread.snap @@ -0,0 +1,19 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\n[head, ..]" +--- +List { + location: 0..10, + elements: [ + Var { + location: 1..5, + name: "head", + }, + ], + tail: Some( + Discard { + name: "_", + location: 9..10, + }, + ), +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_discards.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_discards.snap new file mode 100644 index 00000000..d385168d --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_discards.snap @@ -0,0 +1,15 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nPair(_, _)" +--- +Pair { + location: 0..10, + fst: Discard { + name: "_", + location: 5..6, + }, + snd: Discard { + name: "_", + location: 8..9, + }, +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_1.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_1.snap new file mode 100644 index 00000000..1b7a751a --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_1.snap @@ -0,0 +1,24 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nPair(14, True)" +--- +Pair { + location: 0..14, + fst: Int { + location: 5..7, + value: "14", + base: Decimal { + numeric_underscore: false, + }, + }, + snd: Constructor { + is_record: false, + location: 9..13, + name: "True", + arguments: [], + module: None, + constructor: (), + with_spread: false, + tipo: (), + }, +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_2.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_2.snap new file mode 100644 index 00000000..249066df --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_pair_explicit_depth_2.snap @@ -0,0 +1,60 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nPair([1,2,3], Pair((14, 42), _))" +--- +Pair { + location: 0..32, + fst: List { + location: 5..12, + elements: [ + Int { + location: 6..7, + value: "1", + base: Decimal { + numeric_underscore: false, + }, + }, + Int { + location: 8..9, + value: "2", + base: Decimal { + numeric_underscore: false, + }, + }, + Int { + location: 10..11, + value: "3", + base: Decimal { + numeric_underscore: false, + }, + }, + ], + tail: None, + }, + snd: Pair { + location: 14..31, + fst: Tuple { + location: 19..27, + elems: [ + Int { + location: 20..22, + value: "14", + base: Decimal { + numeric_underscore: false, + }, + }, + Int { + location: 24..26, + value: "42", + base: Decimal { + numeric_underscore: false, + }, + }, + ], + }, + snd: Discard { + name: "_", + location: 29..30, + }, + }, +} diff --git a/crates/aiken-lang/src/parser/pattern/snapshots/pattern_var.snap b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_var.snap new file mode 100644 index 00000000..2f3512a5 --- /dev/null +++ b/crates/aiken-lang/src/parser/pattern/snapshots/pattern_var.snap @@ -0,0 +1,8 @@ +--- +source: crates/aiken-lang/src/parser/pattern/mod.rs +description: "Code:\n\nfoo" +--- +Var { + location: 0..3, + name: "foo", +}