//! Corresponds to `ast::basic`. use chumsky::prelude::*; use chumsky::text::Character; use crate::ast::{Ident, Line, Space}; use crate::span::Span; pub type Error = Simple; pub type EParser = BoxedParser<'static, char, O, Error>; fn inline() -> impl Parser { filter(|c: &char| c.is_whitespace() && *c != '\n') .repeated() .to(()) } fn newline() -> impl Parser { just('\n').to(()) } fn line() -> impl Parser { let empty = newline().to(Line::Empty); let comment = just('#') .ignore_then(take_until(newline())) .map(|(s, _)| s) .collect::() .map(Line::Comment); empty.or(comment) } pub fn space() -> EParser { inline() .ignore_then(line()) .repeated() .then_ignore(inline()) .map_with_span(|lines, span| Space { lines, span }) .boxed() } pub fn ident() -> EParser { text::ident() .try_map(|name, span| { if matches!( &name as &str, "nil" | "true" | "false" | "not" | "and" | "or" | "local" | "function" | "module" ) { Err(Simple::custom(span, "identifier uses reserved name")) } else { Ok(Ident { name, span }) } }) .boxed() } pub fn local(space: EParser) -> EParser> { text::keyword("local").ignore_then(space).or_not().boxed() }