mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 23:23:50 +03:00
parsing ambiguous explicit future types. Ex: Future<u32, Future<u32>>
This commit is contained in:
parent
5903635fa3
commit
bf95c4966a
@ -41,6 +41,8 @@ pub(crate) struct ParserContext<'a> {
|
|||||||
pub(crate) disallow_struct_construction: bool,
|
pub(crate) disallow_struct_construction: bool,
|
||||||
/// The name of the program being parsed.
|
/// The name of the program being parsed.
|
||||||
pub(crate) program_name: Option<Symbol>,
|
pub(crate) program_name: Option<Symbol>,
|
||||||
|
/// Whether traversing an ambiguous Shr token.
|
||||||
|
pub in_angle: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dummy span used to appease borrow checker.
|
/// Dummy span used to appease borrow checker.
|
||||||
@ -63,6 +65,7 @@ impl<'a> ParserContext<'a> {
|
|||||||
token,
|
token,
|
||||||
tokens,
|
tokens,
|
||||||
program_name: None,
|
program_name: None,
|
||||||
|
in_angle: false,
|
||||||
};
|
};
|
||||||
p.bump();
|
p.bump();
|
||||||
p
|
p
|
||||||
@ -248,6 +251,51 @@ impl<'a> ParserContext<'a> {
|
|||||||
self.parse_list(Delimiter::Bracket, Some(Token::Comma), f)
|
self.parse_list(Delimiter::Bracket, Some(Token::Comma), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a list separated by `,` and delimited by angle brackets.
|
||||||
|
/// Since the `>>` token is ambiguous, we need to create special state checks.
|
||||||
|
pub (super) fn parse_angle_comma_list<T>(
|
||||||
|
&mut self,
|
||||||
|
sep: Option<Token>,
|
||||||
|
mut f: impl FnMut(&mut Self) -> Result<Option<T>>,
|
||||||
|
) -> Result<(Vec<T>, bool, Span)> {
|
||||||
|
let (open, close) = Delimiter::AngleBracket.open_close_pair();
|
||||||
|
let mut list = Vec::new();
|
||||||
|
let mut trailing = false;
|
||||||
|
|
||||||
|
// Parse opening delimiter.
|
||||||
|
let open_span = self.expect(&open)?;
|
||||||
|
|
||||||
|
while !self.check(&close) && !self.check(&Token::Shr){
|
||||||
|
// Parse the element. We allow inner parser recovery through the `Option`.
|
||||||
|
if let Some(elem) = f(self)? {
|
||||||
|
list.push(elem);
|
||||||
|
}
|
||||||
|
// Parse the separator, if any.
|
||||||
|
if sep.as_ref().filter(|sep| !self.eat(sep)).is_some() {
|
||||||
|
trailing = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
trailing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.token.token == Token::Shr {
|
||||||
|
return if self.in_angle {
|
||||||
|
self.in_angle = false;
|
||||||
|
let end_span = self.expect(&Token::Shr)?;
|
||||||
|
Ok((list, trailing, open_span + end_span))
|
||||||
|
} else {
|
||||||
|
self.in_angle = true;
|
||||||
|
Ok((list, trailing, open_span + self.prev_token.span))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse closing delimiter.
|
||||||
|
let span = open_span + self.expect(&close)?;
|
||||||
|
|
||||||
|
Ok((list, trailing, span))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the current token is `(`.
|
/// Returns true if the current token is `(`.
|
||||||
pub(super) fn peek_is_left_par(&self) -> bool {
|
pub(super) fn peek_is_left_par(&self) -> bool {
|
||||||
matches!(self.token.token, Token::LeftParen)
|
matches!(self.token.token, Token::LeftParen)
|
||||||
|
@ -66,7 +66,6 @@ impl ParserContext<'_> {
|
|||||||
Token::Address => Type::Address,
|
Token::Address => Type::Address,
|
||||||
Token::Bool => Type::Boolean,
|
Token::Bool => Type::Boolean,
|
||||||
Token::Field => Type::Field,
|
Token::Field => Type::Field,
|
||||||
Token::Future => Type::Future(Default::default()),
|
|
||||||
Token::Group => Type::Group,
|
Token::Group => Type::Group,
|
||||||
Token::Scalar => Type::Scalar,
|
Token::Scalar => Type::Scalar,
|
||||||
Token::Signature => Type::Signature,
|
Token::Signature => Type::Signature,
|
||||||
@ -131,6 +130,23 @@ impl ParserContext<'_> {
|
|||||||
// Note: This is the only place where `Tuple` type is constructed in the parser.
|
// Note: This is the only place where `Tuple` type is constructed in the parser.
|
||||||
_ => Ok((Type::Tuple(TupleType::new(types.into_iter().map(|t| t.0).collect())), span)),
|
_ => Ok((Type::Tuple(TupleType::new(types.into_iter().map(|t| t.0).collect())), span)),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if self.token.token == Token::Future {
|
||||||
|
// Parse the `Future` token.
|
||||||
|
let span = self.expect(&Token::Future)?;
|
||||||
|
// Parse the angle bracket list.
|
||||||
|
if self.token.token == Token::Lt {
|
||||||
|
let (types, _, full_span) = self.parse_angle_comma_list(Some(Token::Comma),|p| p.parse_type().map(Some))?;
|
||||||
|
match types.len() {
|
||||||
|
0 => return Err(ParserError::future_must_have_at_least_one_element(span).into()),
|
||||||
|
// `Future<()>` corresponds to explicitly specifying a `Future` type with no inputs.
|
||||||
|
1 if matches!(types.get(0).unwrap().0, Type::Unit) => return Ok((Type::Future(FutureType::new(vec![], None, true)), span + full_span)),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
Ok((Type::Future(FutureType::new(types.into_iter().map(|t| t.0).collect(), None, true)), span + full_span))
|
||||||
|
} else {
|
||||||
|
Ok((Type::Future(Default::default()), span))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.parse_primitive_type()
|
self.parse_primitive_type()
|
||||||
}
|
}
|
||||||
|
@ -342,4 +342,11 @@ create_messages!(
|
|||||||
msg: format!("Cannot create an external record. Records can only be created in the program that they are defined in."),
|
msg: format!("Cannot create an external record. Records can only be created in the program that they are defined in."),
|
||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@formatted
|
||||||
|
future_must_have_at_least_one_element {
|
||||||
|
args: (),
|
||||||
|
msg: "Future type must have at least one element.".to_string(),
|
||||||
|
help: Some("Write `Future<()>` to explicitly type a future with no inputs.".to_string()),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user