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:
KtorZ
2024-04-18 17:18:57 +02:00
committed by Kasey
parent 390bccd406
commit 2cb2c7fa1f
13 changed files with 235 additions and 22 deletions

View File

@@ -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(),

View File

@@ -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;

View 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)"#);
}
}

View 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,
},
},
}

View File

@@ -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,
},
},
}