use super::*;
impl<'a> Parser<'a> {
pub(super) fn parse_object_body(&mut self, in_for: bool) -> Result<ObjectBody> {
self.expect(&TokenKind::LBrace, "{")?;
let params = self.parse_body_params()?;
let mut entries = Vec::new();
let mut prev_end: Option<usize> = None;
while !matches!(self.peek(), TokenKind::RBrace) {
if self.at_eof() {
return Err(self.error_at(self.prev_end, "Missing `}` delimiter."));
}
let start = self.peek_tok().offset;
if prev_end == Some(start) {
return Err(self.error_at(
start,
"Object members must be separated by whitespace, newline, or semicolon.\n\
Object entries must be separated by newline or semicolon.",
));
}
self.parse_object_member(in_for, &mut entries)?;
prev_end = Some(self.prev_end);
}
self.advance(); Ok(ObjectBody { params, entries })
}
pub(super) fn parse_body_params(&mut self) -> Result<Vec<String>> {
let is_param_start = |kind: &TokenKind| matches!(kind, TokenKind::Ident(_));
if !is_param_start(self.peek()) {
return Ok(Vec::new());
}
let saved = (self.pos, self.prev_end, self.prev_line);
let parsed = (|| -> Result<Option<Vec<String>>> {
let params = self.parse_parameters(&TokenKind::Arrow)?;
if matches!(self.peek(), TokenKind::Arrow) {
self.advance();
Ok(Some(params))
} else {
Ok(None)
}
})();
match parsed {
Ok(Some(params)) => Ok(params),
_ => {
(self.pos, self.prev_end, self.prev_line) = saved;
Ok(Vec::new())
}
}
}
pub(super) fn parse_object_member(
&mut self,
in_for: bool,
entries: &mut Vec<Entry>,
) -> Result<()> {
match self.peek() {
TokenKind::Ident(_)
if matches!(
self.peek_nth(1),
TokenKind::LBrace | TokenKind::Colon | TokenKind::Equals
) =>
{
let entry = self.parse_object_property(MemberHeader::default(), in_for)?;
entries.push(entry);
}
TokenKind::KwFunction => {
let entry = self.parse_object_method(MemberHeader::default(), in_for)?;
entries.extend(entry);
}
TokenKind::LPred => {
self.advance();
let pred = self.parse_expr()?;
self.expect(&TokenKind::RBracket, "]]")?;
let first_end = self.prev_end;
if !matches!(self.peek(), TokenKind::RBracket)
|| self.peek_tok().offset != first_end
{
return Err(self.unexpected_token("]]"));
}
self.advance();
let value = self.parse_entry_value(&pred)?;
entries.push(Entry::Predicate(pred, value));
}
TokenKind::LBracket => {
self.advance();
let key = self.parse_expr()?;
self.expect(&TokenKind::RBracket, "]")?;
let value = self.parse_entry_value(&key)?;
entries.push(Entry::DynProperty(key, value));
}
TokenKind::DotDotDot | TokenKind::QuestionDotDotDot => {
let nullable = matches!(self.peek(), TokenKind::QuestionDotDotDot);
self.advance();
let expr = self.parse_expr()?;
entries.push(Entry::Spread(if nullable {
Expr::Binop(
BinOp::NullCoalesce,
Box::new(expr),
Box::new(Expr::ObjectBody(Vec::new().into())),
)
} else {
expr
}));
}
TokenKind::KwWhen => {
self.advance();
self.expect(&TokenKind::LParen, "(")?;
let condition = self.parse_expr()?;
self.expect(&TokenKind::RParen, ")")?;
let body = self.parse_generator_body(in_for)?;
let else_body = if matches!(self.peek(), TokenKind::KwElse) {
self.advance();
Some(self.parse_generator_body(in_for)?.into())
} else {
None
};
entries.push(Entry::WhenGenerator(WhenGenerator {
condition,
body: body.into(),
else_body,
}));
}
TokenKind::KwFor => {
self.advance();
self.expect(&TokenKind::LParen, "(")?;
let first = self.parse_typed_parameter()?;
let (key_var, val_var) = if matches!(self.peek(), TokenKind::Comma) {
self.advance();
let second_offset = self.peek_tok().offset;
let second = self.parse_typed_parameter()?;
if first.0 == second.0 && first.0 != "_" {
return Err(self.error_at(
second_offset,
format!("Duplicate definition of member `{}`.", second.0),
));
}
(Some(first), second)
} else {
(None, first)
};
self.expect(&TokenKind::KwIn, "in")?;
let collection = self.parse_expr()?;
self.expect(&TokenKind::RParen, ")")?;
let mut body = self.parse_generator_body(true)?;
let checks: Vec<Expr> = key_var
.iter()
.chain([&val_var])
.filter_map(|(name, ty)| {
let ty = ty.clone()?;
Some(Expr::Let(
"_".to_string(),
Box::new(Expr::As(Box::new(Expr::Ident(name.clone())), ty)),
Box::new(Expr::Bool(true)),
))
})
.collect();
if let Some(condition) = checks
.into_iter()
.reduce(|a, b| Expr::Binop(BinOp::And, Box::new(a), Box::new(b)))
{
body = vec![Entry::WhenGenerator(WhenGenerator {
condition,
body: body.into(),
else_body: None,
})];
}
let key_var = key_var.map(|(name, _)| name);
let val_var = val_var.0;
entries.push(Entry::ForGenerator(ForGenerator {
key_var,
val_var,
collection,
body: body.into(),
}));
}
TokenKind::KwTypeAlias => {
entries.push(self.parse_type_alias(MemberHeader::default())?);
}
TokenKind::KwClass => {
entries.push(self.parse_class(MemberHeader::default())?);
}
kind if matches!(kind, TokenKind::At) || token_modifier(kind).is_some() => {
let header = self.parse_member_header()?;
if matches!(self.peek(), TokenKind::KwFunction) {
let entry = self.parse_object_method(header, in_for)?;
entries.extend(entry);
} else if matches!(self.peek(), TokenKind::KwTypeAlias) {
entries.push(self.parse_type_alias(header)?);
} else if matches!(self.peek(), TokenKind::KwClass) {
entries.push(self.parse_class(header)?);
} else {
let entry = self.parse_object_property(header, in_for)?;
entries.push(entry);
}
}
_ => {
let expr = self.parse_expr()?;
entries.push(Entry::Elem(expr));
}
}
Ok(())
}
pub(super) fn parse_generator_body(&mut self, in_for: bool) -> Result<Vec<Entry>> {
let body = self.parse_object_body(in_for)?;
Ok(body.entries)
}
pub(super) fn parse_entry_value(&mut self, key: &Expr) -> Result<Expr> {
if matches!(self.peek(), TokenKind::Equals) {
self.advance();
return self.parse_expr();
}
match self.parse_body_list()? {
BodyList::Plain(entries) => Ok(Expr::ObjectBody(entries.into())),
BodyList::Amended(f) => Ok(f(Expr::Index(
Box::new(Expr::Ident("super".into())),
Box::new(key.clone()),
))),
}
}
pub(super) fn for_generator_error(&self, what: &str) -> Error {
self.parse_error(format!(
"A for-generator cannot generate object {what} (only entries and elements)."
))
}
pub(super) fn parse_object_property(
&mut self,
header: MemberHeader,
in_for: bool,
) -> Result<Entry> {
if in_for {
return Err(self.for_generator_error("properties"));
}
self.check_modifiers(&header, MemberKind::ObjectMember)?;
let local = header.has(Modifier::Local);
let name = self.expect_ident()?;
let type_ann = if matches!(self.peek(), TokenKind::Colon) {
self.advance();
let type_offset = self.peek_tok().offset;
let ty = self.parse_type()?;
if !local {
return Err(self.error_at(
type_offset,
"A non-local object property cannot have a type annotation.",
));
}
Some(ty)
} else {
None
};
let (mut value, body) = if type_ann.is_some() || matches!(self.peek(), TokenKind::Equals) {
self.expect(&TokenKind::Equals, "=")?;
(Some(self.parse_expr()?), None)
} else {
if local && matches!(self.peek(), TokenKind::LBrace) {
return Err(self.local_amend_error());
}
self.parse_property_bodies(&name)?
};
if let (Some(value), Some(ty)) = (&mut value, &type_ann)
&& infers_new(ty)
{
infer_method_return_new(value, ty);
}
Ok(Entry::Property(std::sync::Arc::new(Property {
modifiers: header.modifiers(),
annotations: header.annotations,
name: name.into(),
type_ann,
value,
body: body.map(Into::into),
is_method: false,
})))
}
pub(super) fn parse_object_method(
&mut self,
header: MemberHeader,
in_for: bool,
) -> Result<Option<Entry>> {
if in_for {
return Err(self.for_generator_error("methods"));
}
if !header.has(Modifier::Local) {
return Err(self.parse_error(
"Method needs a `local` modifier because it is defined in an object, not a class.",
));
}
self.parse_method(header, MemberKind::ObjectMember)
}
}
pub(super) struct ObjectBody {
pub(super) params: Vec<String>,
pub(super) entries: Vec<Entry>,
}
pub(super) fn amend_expr(parent: Expr, body: ObjectBody) -> Expr {
let entries = Expr::ObjectBody(body.entries.into());
if body.params.is_empty() {
return Expr::Binop(BinOp::Add, Box::new(parent), Box::new(entries));
}
let args = body.params.iter().cloned().map(Expr::Ident).collect();
let call = Expr::Call(
Box::new(Expr::Field(Box::new(parent), "apply".to_string())),
args,
);
Expr::Lambda(
body.params.into(),
std::sync::Arc::new(Expr::Binop(BinOp::Add, Box::new(call), Box::new(entries))),
)
}