use crate::internal::as2::ast::{ClassMember, ClassMemberAttribute, Statement, StatementKind};
use crate::internal::as2::lexer::tokens::{Keyword, TokenKind};
use crate::internal::as2::parser::statement::{declaration, dot_separated_identifiers, function};
use crate::internal::as2::parser::{Tokens, skip_newlines};
use crate::internal::span::{Span, Spanned};
use std::collections::HashMap;
use winnow::combinator::{fail, opt, peek, separated};
use winnow::error::{ParserError, StrContext};
use winnow::token::any;
use winnow::{ModalResult, Parser};
pub(crate) fn class<'i>(i: &mut Tokens<'i>) -> ModalResult<Statement<'i>> {
let name = dot_separated_identifiers.parse_next(i)?;
let extends = opt((
TokenKind::Keyword(Keyword::Extends),
dot_separated_identifiers,
)
.map(|(_, id)| id))
.parse_next(i)?;
let implements: Option<Vec<Spanned<String>>> = opt((
TokenKind::Keyword(Keyword::Implements),
separated(1.., dot_separated_identifiers, TokenKind::Comma),
)
.map(|(_, id)| id))
.parse_next(i)?;
TokenKind::OpenBrace.parse_next(i)?;
skip_newlines.parse_next(i)?;
let mut members = vec![];
let mut attributes = HashMap::new();
loop {
let next = peek(any).parse_next(i)?;
match next.kind {
TokenKind::CloseBrace => break,
TokenKind::Semicolon | TokenKind::Newline => {
any.parse_next(i)?;
}
TokenKind::Keyword(Keyword::Function) => {
members.push((
function
.map(|f| Spanned::new(f.span, ClassMember::Function(f.value)))
.parse_next(i)?,
std::mem::take(&mut attributes),
));
}
TokenKind::Keyword(Keyword::Var) => {
let start = TokenKind::Keyword(Keyword::Var).parse_next(i)?.span;
let declaration = declaration.parse_next(i)?;
members.push((
Spanned::new(
Span::encompassing(start, declaration.span),
ClassMember::Variable(declaration.value),
),
std::mem::take(&mut attributes),
));
}
TokenKind::Keyword(Keyword::Static)
if !attributes.contains_key(&ClassMemberAttribute::Static) =>
{
let span = TokenKind::Keyword(Keyword::Static).parse_next(i)?.span;
attributes.insert(ClassMemberAttribute::Static, span);
}
TokenKind::Keyword(Keyword::Private)
if !attributes.contains_key(&ClassMemberAttribute::Public)
&& !attributes.contains_key(&ClassMemberAttribute::Private) =>
{
let span = TokenKind::Keyword(Keyword::Private).parse_next(i)?.span;
attributes.insert(ClassMemberAttribute::Private, span);
}
TokenKind::Keyword(Keyword::Public)
if !attributes.contains_key(&ClassMemberAttribute::Public)
&& !attributes.contains_key(&ClassMemberAttribute::Private) =>
{
let span = TokenKind::Keyword(Keyword::Public).parse_next(i)?.span;
attributes.insert(ClassMemberAttribute::Public, span);
}
_ => {
fail.context(StrContext::Expected(
TokenKind::Keyword(Keyword::Function).expected(),
))
.parse_next(i)?;
unreachable!()
}
}
skip_newlines.parse_next(i)?;
}
if !attributes.is_empty() {
return Err(ParserError::from_input(i));
}
let end = TokenKind::CloseBrace.parse_next(i)?.span;
Ok(Statement::new(
Span::encompassing(name.span, end),
StatementKind::Class {
name,
extends,
implements: implements.unwrap_or_default(),
members,
},
))
}