use crate::SyntaxKind::{
COMMA, DIVERT, EQ, EQ_EQ, GT, IDENTIFIER, KNOT_BODY, KNOT_DEF, KNOT_HEADER, KNOT_PARAM_DECL,
KNOT_PARAMS, KW_FUNCTION, KW_REF, L_PAREN, NEWLINE, R_PAREN, STITCH_BODY, STITCH_DEF,
STITCH_HEADER,
};
use super::Parser;
pub(crate) fn at_knot(p: &Parser<'_, '_>) -> bool {
p.current() == EQ_EQ
}
pub(crate) fn at_stitch(p: &Parser<'_, '_>) -> bool {
p.current() == EQ && p.nth(1) != EQ && p.nth(1) != GT
}
pub(crate) fn knot_definition(p: &mut Parser<'_, '_>) {
p.start_node(KNOT_DEF);
knot_header(p);
if p.at(NEWLINE) {
p.bump();
}
knot_body(p);
p.finish_node();
}
fn knot_header(p: &mut Parser<'_, '_>) {
p.start_node(KNOT_HEADER);
p.bump(); eat_extra_equals(p);
p.skip_ws();
if p.current() == KW_FUNCTION {
p.bump();
p.skip_ws();
}
p.start_node(IDENTIFIER);
p.expect_ident_or_keyword();
p.finish_node();
p.skip_ws();
if p.current() == L_PAREN {
knot_params(p);
p.skip_ws();
}
if p.current() == EQ_EQ || p.current() == EQ {
eat_extra_equals(p);
}
p.finish_node();
}
fn knot_params(p: &mut Parser<'_, '_>) {
p.start_node(KNOT_PARAMS);
p.bump(); p.skip_ws();
if p.current() != R_PAREN {
knot_param_decl(p);
loop {
p.skip_ws();
if !p.eat(COMMA) {
break;
}
p.skip_ws();
knot_param_decl(p);
}
}
p.skip_ws();
p.expect(R_PAREN);
p.finish_node();
}
fn knot_param_decl(p: &mut Parser<'_, '_>) {
p.start_node(KNOT_PARAM_DECL);
if p.current() == DIVERT {
p.bump();
p.skip_ws();
}
if p.current() == KW_REF {
p.bump();
p.skip_ws();
}
p.start_node(IDENTIFIER);
p.expect_ident_or_keyword();
p.finish_node();
p.finish_node();
}
fn knot_body(p: &mut Parser<'_, '_>) {
p.start_node(KNOT_BODY);
loop {
p.skip_ws();
if p.at_eof() || at_knot(p) {
break;
}
if super::declaration::at_declaration(p) && !super::declaration::at_inline_declaration(p) {
break;
}
let before = p.pos();
if at_stitch(p) {
stitch_definition(p);
} else if super::declaration::at_inline_declaration(p) {
super::declaration::declaration(p);
} else {
super::story::line(p);
}
if p.pos() == before {
p.error_recover("unexpected token in knot body");
}
}
p.finish_node();
}
pub(crate) fn stitch_definition(p: &mut Parser<'_, '_>) {
p.start_node(STITCH_DEF);
stitch_header(p);
if p.at(NEWLINE) {
p.bump();
}
stitch_body(p);
p.finish_node();
}
fn stitch_header(p: &mut Parser<'_, '_>) {
p.start_node(STITCH_HEADER);
p.bump(); p.skip_ws();
p.start_node(IDENTIFIER);
p.expect_ident_or_keyword();
p.finish_node();
p.skip_ws();
if p.current() == L_PAREN {
knot_params(p);
}
p.finish_node();
}
fn stitch_body(p: &mut Parser<'_, '_>) {
p.start_node(STITCH_BODY);
loop {
p.skip_ws();
if p.at_eof() || at_knot(p) || at_stitch(p) {
break;
}
if super::declaration::at_declaration(p) && !super::declaration::at_inline_declaration(p) {
break;
}
let before = p.pos();
if super::declaration::at_inline_declaration(p) {
super::declaration::declaration(p);
} else {
super::story::line(p);
}
if p.pos() == before {
p.error_recover("unexpected token in stitch body");
}
}
p.finish_node();
}
fn eat_extra_equals(p: &mut Parser<'_, '_>) {
while p.current() == EQ_EQ || p.current() == EQ {
p.bump();
}
}