Experiment with monadic bind.
This commit is contained in:
parent
0e0bed3c9d
commit
1f530f3b24
|
@ -1425,6 +1425,7 @@ impl Default for Bls12_381Point {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
|
||||
pub enum AssignmentKind {
|
||||
Let,
|
||||
Bind,
|
||||
Expect,
|
||||
}
|
||||
|
||||
|
@ -1440,6 +1441,7 @@ impl AssignmentKind {
|
|||
pub fn location_offset(&self) -> usize {
|
||||
match self {
|
||||
AssignmentKind::Let => 3,
|
||||
AssignmentKind::Bind => 3,
|
||||
AssignmentKind::Expect => 6,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -684,9 +684,10 @@ impl<'comments> Formatter<'comments> {
|
|||
kind: AssignmentKind,
|
||||
annotation: &'a Option<Annotation>,
|
||||
) -> Document<'a> {
|
||||
let keyword = match kind {
|
||||
AssignmentKind::Let => "let",
|
||||
AssignmentKind::Expect => "expect",
|
||||
let (keyword, equal) = match kind {
|
||||
AssignmentKind::Let => ("let", "="),
|
||||
AssignmentKind::Bind => ("let", "<-"),
|
||||
AssignmentKind::Expect => ("expect", "="),
|
||||
};
|
||||
|
||||
match pattern {
|
||||
|
@ -708,7 +709,8 @@ impl<'comments> Formatter<'comments> {
|
|||
.to_doc()
|
||||
.append(" ")
|
||||
.append(pattern.append(annotation).group())
|
||||
.append(" =")
|
||||
.append(" ")
|
||||
.append(equal)
|
||||
.append(self.case_clause_value(value))
|
||||
}
|
||||
}
|
||||
|
@ -1842,11 +1844,7 @@ impl<'a> Documentable<'a> for &'a ArgName {
|
|||
}
|
||||
|
||||
fn pub_(public: bool) -> Document<'static> {
|
||||
if public {
|
||||
"pub ".to_doc()
|
||||
} else {
|
||||
nil()
|
||||
}
|
||||
if public { "pub ".to_doc() } else { nil() }
|
||||
}
|
||||
|
||||
impl<'a> Documentable<'a> for &'a UnqualifiedImport {
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
expr::UntypedExpr,
|
||||
parser::{annotation, error::ParseError, pattern, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn let_(
|
||||
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
|
@ -12,9 +11,9 @@ pub fn let_(
|
|||
just(Token::Let)
|
||||
.ignore_then(pattern())
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.then_ignore(just(Token::Equal))
|
||||
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
||||
.then(r.clone())
|
||||
.validate(move |((pattern, annotation), value), span, emit| {
|
||||
.validate(move |(((pattern, annotation), kind), value), span, emit| {
|
||||
if matches!(value, UntypedExpr::Assignment { .. }) {
|
||||
emit(ParseError::invalid_assignment_right_hand_side(span))
|
||||
}
|
||||
|
@ -23,7 +22,11 @@ pub fn let_(
|
|||
location: span,
|
||||
value: Box::new(value),
|
||||
pattern,
|
||||
kind: ast::AssignmentKind::Let,
|
||||
kind: if kind == Token::LArrow {
|
||||
ast::AssignmentKind::Bind
|
||||
} else {
|
||||
ast::AssignmentKind::Let
|
||||
},
|
||||
annotation,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -163,6 +163,8 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
|||
just("!=").to(Token::NotEqual),
|
||||
just('!').to(Token::Bang),
|
||||
just('?').to(Token::Question),
|
||||
just("<-").to(Token::LArrow),
|
||||
just("->").to(Token::RArrow),
|
||||
choice((
|
||||
just("<=").to(Token::LessEqual),
|
||||
just('<').to(Token::Less),
|
||||
|
@ -170,7 +172,6 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
|||
just('>').to(Token::Greater),
|
||||
)),
|
||||
just('+').to(Token::Plus),
|
||||
just("->").to(Token::RArrow),
|
||||
just('-').to(Token::Minus),
|
||||
just('*').to(Token::Star),
|
||||
just('/').to(Token::Slash),
|
||||
|
|
|
@ -62,6 +62,7 @@ pub enum Token {
|
|||
Pipe, // '|>'
|
||||
Dot, // '.'
|
||||
RArrow, // '->'
|
||||
LArrow, // '<-'
|
||||
DotDot, // '..'
|
||||
EndOfFile,
|
||||
// Docs/Extra
|
||||
|
@ -152,6 +153,7 @@ impl fmt::Display for Token {
|
|||
Token::Pipe => "|>",
|
||||
Token::Dot => ".",
|
||||
Token::RArrow => "->",
|
||||
Token::LArrow => "<-",
|
||||
Token::DotDot => "..",
|
||||
Token::EndOfFile => "EOF",
|
||||
Token::Comment => "//",
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
|||
tipo::{fields::FieldMap, PatternConstructor, TypeVar},
|
||||
};
|
||||
use std::{cmp::Ordering, collections::HashMap, ops::Deref, rc::Rc};
|
||||
use vec1::Vec1;
|
||||
use vec1::{vec1, Vec1};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ExprTyper<'a, 'b> {
|
||||
|
@ -978,6 +978,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
// If `expect` is explicitly used, we still check exhaustiveness but instead of returning an
|
||||
// error we emit a warning which explains that using `expect` is unnecessary.
|
||||
match kind {
|
||||
AssignmentKind::Bind => {
|
||||
unreachable!("monadic-bind should have been desugared earlier.")
|
||||
}
|
||||
|
||||
AssignmentKind::Let => {
|
||||
self.environment
|
||||
.check_exhaustiveness(&[&pattern], location, true)?
|
||||
|
@ -1708,15 +1712,26 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
}
|
||||
|
||||
fn infer_seq(&mut self, location: Span, untyped: Vec<UntypedExpr>) -> Result<TypedExpr, Error> {
|
||||
let sequence = self.in_new_scope(|scope| {
|
||||
let mut breakpoint = None;
|
||||
|
||||
let mut sequence = self.in_new_scope(|scope| {
|
||||
let count = untyped.len();
|
||||
|
||||
let mut expressions = Vec::with_capacity(count);
|
||||
|
||||
for (i, expression) in untyped.into_iter().enumerate() {
|
||||
let no_assignment = assert_no_assignment(&expression);
|
||||
for (i, expression) in untyped.iter().enumerate() {
|
||||
let no_assignment = assert_no_assignment(expression);
|
||||
|
||||
let typed_expression = scope.infer(expression)?;
|
||||
let typed_expression = match expression {
|
||||
UntypedExpr::Assignment {
|
||||
kind: AssignmentKind::Bind,
|
||||
..
|
||||
} => {
|
||||
breakpoint = Some((i, expression.clone()));
|
||||
return Ok(expressions);
|
||||
}
|
||||
_ => scope.infer(expression.to_owned())?,
|
||||
};
|
||||
|
||||
expressions.push(match i.cmp(&(count - 1)) {
|
||||
// When the expression is the last in a sequence, we enforce it is NOT
|
||||
|
@ -1738,6 +1753,74 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok(expressions)
|
||||
})?;
|
||||
|
||||
if let Some((
|
||||
i,
|
||||
UntypedExpr::Assignment {
|
||||
location,
|
||||
value,
|
||||
pattern,
|
||||
..
|
||||
},
|
||||
)) = breakpoint
|
||||
{
|
||||
let then = UntypedExpr::Sequence {
|
||||
location,
|
||||
expressions: untyped.into_iter().skip(i + 1).collect::<Vec<_>>(),
|
||||
};
|
||||
|
||||
// TODO: This must be constructed based on the inferred type of *value*.
|
||||
//
|
||||
// let tipo = self.infer(untyped_value.clone())?.tipo();
|
||||
//
|
||||
// The following is the `and_then` for Option. The one for Fuzzer is a bit
|
||||
// different.
|
||||
let desugar = UntypedExpr::When {
|
||||
location,
|
||||
subject: value.clone(),
|
||||
clauses: vec![
|
||||
UntypedClause {
|
||||
location,
|
||||
guard: None,
|
||||
patterns: vec1![Pattern::Constructor {
|
||||
location,
|
||||
is_record: false,
|
||||
with_spread: false,
|
||||
name: "None".to_string(),
|
||||
module: None,
|
||||
constructor: (),
|
||||
tipo: (),
|
||||
arguments: vec![],
|
||||
}],
|
||||
then: UntypedExpr::Var {
|
||||
location,
|
||||
name: "None".to_string(),
|
||||
},
|
||||
},
|
||||
UntypedClause {
|
||||
location,
|
||||
guard: None,
|
||||
patterns: vec1![Pattern::Constructor {
|
||||
location,
|
||||
is_record: false,
|
||||
with_spread: false,
|
||||
name: "Some".to_string(),
|
||||
module: None,
|
||||
constructor: (),
|
||||
tipo: (),
|
||||
arguments: vec![CallArg {
|
||||
location,
|
||||
label: None,
|
||||
value: pattern.clone(),
|
||||
}],
|
||||
}],
|
||||
then,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
sequence.push(self.infer(desugar)?);
|
||||
};
|
||||
|
||||
let unused = self
|
||||
.environment
|
||||
.warnings
|
||||
|
|
Loading…
Reference in New Issue