Add dedicated 'Pair' typed and untyped expression
Before this commit, we would parse 'Pair' as a user-defined data-types, and thus piggybacking on that whole record system. While perhaps handy for some things, it's also semantically wrong and induces a lot more complexity in codegen which now needs to systematically distinguish every data-type access between pairs, and others. So it's better to have it as a separate expression, and handle it similar to tuples (since it's fundamentally a 2-tuple with a special serialization).
This commit is contained in:
@@ -1,20 +1,11 @@
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use super::anonymous_function::parser as anonymous_function;
|
||||
use super::assignment;
|
||||
use super::block::parser as block;
|
||||
use super::bytearray::parser as bytearray;
|
||||
use super::if_else::parser as if_else;
|
||||
use super::int::parser as int;
|
||||
use super::list::parser as list;
|
||||
use super::record::parser as record;
|
||||
use super::record_update::parser as record_update;
|
||||
use super::string::parser as string;
|
||||
use super::tuple::parser as tuple;
|
||||
use super::var::parser as var;
|
||||
use super::when::parser as when;
|
||||
use super::{and_or_chain, anonymous_binop::parser as anonymous_binop};
|
||||
|
||||
use super::{
|
||||
and_or_chain, anonymous_binop::parser as anonymous_binop,
|
||||
anonymous_function::parser as anonymous_function, assignment, block::parser as block,
|
||||
bytearray::parser as bytearray, if_else::parser as if_else, int::parser as int,
|
||||
list::parser as list, pair::parser as pair, record::parser as record,
|
||||
record_update::parser as record_update, string::parser as string, tuple::parser as tuple,
|
||||
var::parser as var, when::parser as when,
|
||||
};
|
||||
use crate::{
|
||||
expr::UntypedExpr,
|
||||
parser::{
|
||||
@@ -23,6 +14,7 @@ use crate::{
|
||||
token::Token,
|
||||
},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser<'a>(
|
||||
sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
@@ -58,6 +50,7 @@ pub fn chain_start<'a>(
|
||||
choice((
|
||||
string(),
|
||||
int(),
|
||||
pair(expression.clone()),
|
||||
record_update(expression.clone()),
|
||||
record(expression.clone()),
|
||||
field_access::constructor(),
|
||||
|
||||
@@ -12,6 +12,7 @@ mod fail_todo_trace;
|
||||
mod if_else;
|
||||
mod int;
|
||||
mod list;
|
||||
mod pair;
|
||||
mod record;
|
||||
mod record_update;
|
||||
mod sequence;
|
||||
@@ -31,6 +32,7 @@ pub use fail_todo_trace::parser as fail_todo_trace;
|
||||
pub use if_else::parser as if_else;
|
||||
pub use int::parser as int;
|
||||
pub use list::parser as list;
|
||||
pub use pair::parser as pair;
|
||||
pub use record::parser as record;
|
||||
pub use record_update::parser as record_update;
|
||||
pub use sequence::parser as sequence;
|
||||
|
||||
53
crates/aiken-lang/src/parser/expr/pair.rs
Normal file
53
crates/aiken-lang/src/parser/expr/pair.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::{
|
||||
builtins::{PAIR, PRELUDE},
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser(
|
||||
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||
select! {Token::Name { name } if &name == PRELUDE => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then_ignore(select! {Token::UpName { name } if &name == PAIR => name})
|
||||
.ignore_then(
|
||||
r.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.exactly(2)
|
||||
.allow_trailing()
|
||||
.delimited_by(
|
||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||
just(Token::RightParen),
|
||||
)
|
||||
.map_with_span(|elems, location| UntypedExpr::Pair {
|
||||
location,
|
||||
fst: elems
|
||||
.first()
|
||||
.expect("Pair should have exactly 2 elements")
|
||||
.to_owned()
|
||||
.into(),
|
||||
snd: elems
|
||||
.last()
|
||||
.expect("Pair should have exactly 2 elements")
|
||||
.to_owned()
|
||||
.into(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
||||
#[test]
|
||||
fn basic_pair() {
|
||||
assert_expr!(r#"Pair(1, 2)"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pair_from_prelude() {
|
||||
assert_expr!(r#"aiken.Pair(1, 2)"#);
|
||||
}
|
||||
}
|
||||
21
crates/aiken-lang/src/parser/expr/snapshots/basic_pair.snap
Normal file
21
crates/aiken-lang/src/parser/expr/snapshots/basic_pair.snap
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: crates/aiken-lang/src/parser/expr/pair.rs
|
||||
description: "Code:\n\nPair(1, 2)"
|
||||
---
|
||||
Pair {
|
||||
location: 4..10,
|
||||
fst: UInt {
|
||||
location: 5..6,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
snd: UInt {
|
||||
location: 8..9,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: crates/aiken-lang/src/parser/expr/pair.rs
|
||||
description: "Code:\n\naiken.Pair(1, 2)"
|
||||
---
|
||||
Pair {
|
||||
location: 10..16,
|
||||
fst: UInt {
|
||||
location: 11..12,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
snd: UInt {
|
||||
location: 14..15,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user