use crate::SyntaxKind::{
ANNOTATION_ARG, ANNOTATION_ARGS, ANNOTATION_LINE, AT_L_BRACKET, COLON_COLON, COMMA, EQ, FLOAT,
FLOAT_LIT, IDENT, INTEGER, INTEGER_LIT, L_BRACKET, L_PAREN, NEWLINE, QUOTE, R_BRACKET, R_PAREN,
STRING_ESCAPE, STRING_LIT, STRING_TEXT,
};
use super::Parser;
pub(crate) fn annotation_line(p: &mut Parser<'_, '_>) {
p.start_node(ANNOTATION_LINE);
p.expect(AT_L_BRACKET);
p.expect(IDENT);
if p.at(L_PAREN) {
annotation_args(p);
}
p.expect(R_BRACKET);
let mut trailing = false;
while !p.at_eof() && p.nth_raw(0) != NEWLINE {
if !matches!(p.nth_raw(0), crate::SyntaxKind::WHITESPACE) {
trailing = true;
}
p.bump();
}
if trailing {
p.error("unexpected text after `]` on an annotation line".into());
}
if p.at(NEWLINE) {
p.bump();
}
p.finish_node();
}
fn annotation_args(p: &mut Parser<'_, '_>) {
p.start_node(ANNOTATION_ARGS);
p.expect(L_PAREN);
if p.enter_depth() {
p.skip_ws_and_newlines();
while p.peek_skip_nl() != R_PAREN && !p.at_eof() {
let before = p.pos();
annotation_arg(p);
if p.pos() == before {
p.error_recover("unexpected token in annotation arguments");
p.skip_ws_and_newlines();
continue;
}
p.skip_ws_and_newlines();
if !p.eat(COMMA) {
break;
}
p.skip_ws_and_newlines();
}
p.exit_depth();
}
p.expect(R_PAREN);
p.finish_node();
}
fn annotation_arg(p: &mut Parser<'_, '_>) {
match p.current() {
IDENT if p.nth(1) == COLON_COLON => {
p.start_node(ANNOTATION_ARG);
super::expr::path(p);
p.finish_node();
}
IDENT => {
p.start_node(ANNOTATION_ARG);
p.expect(IDENT);
if p.at(L_PAREN) {
annotation_args(p);
} else if p.at(EQ) {
p.expect(EQ);
if p.at(QUOTE) {
annotation_string_value(p);
} else if p.at(INTEGER) {
annotation_integer_value(p);
} else if p.at(IDENT) {
p.eat(IDENT);
}
}
p.finish_node();
}
INTEGER => {
p.start_node(ANNOTATION_ARG);
p.start_node(INTEGER_LIT);
p.expect(INTEGER);
p.finish_node();
p.finish_node();
}
FLOAT => {
p.start_node(ANNOTATION_ARG);
p.start_node(FLOAT_LIT);
p.expect(FLOAT);
p.finish_node();
p.finish_node();
}
QUOTE => {
p.start_node(ANNOTATION_ARG);
super::expr::string_lit(p);
p.finish_node();
}
_ => {}
}
}
fn annotation_string_value(p: &mut Parser<'_, '_>) {
p.start_node(STRING_LIT);
p.expect(QUOTE);
while matches!(
p.current(),
STRING_TEXT | STRING_ESCAPE | L_BRACKET | R_BRACKET
) {
p.bump();
}
p.expect(QUOTE);
p.finish_node();
}
fn annotation_integer_value(p: &mut Parser<'_, '_>) {
p.start_node(INTEGER_LIT);
p.expect(INTEGER);
p.finish_node();
}