use crate::SyntaxKind::{
COMMA, CONST_DECL, EQ, EXTERNAL_DECL, FILE_PATH, FUNCTION_PARAM_LIST, IDENT, IDENTIFIER,
INCLUDE_STMT, INTEGER, KW_CONST, KW_EXTERNAL, KW_INCLUDE, KW_LIST, KW_VAR, L_PAREN, LIST_DECL,
LIST_DEF, LIST_MEMBER, LIST_MEMBER_OFF, LIST_MEMBER_ON, NEWLINE, R_PAREN, VAR_DECL,
};
use super::Parser;
pub(crate) fn include_statement(p: &mut Parser<'_, '_>) {
p.start_node(INCLUDE_STMT);
p.bump(); p.skip_ws();
p.start_node(FILE_PATH);
if p.at_eof() || p.nth_raw(0) == NEWLINE {
p.error("expected file path".into());
}
while !p.at_eof() && p.nth_raw(0) != NEWLINE {
p.bump();
}
p.finish_node();
if p.at(NEWLINE) {
p.bump();
}
p.finish_node();
}
pub(crate) fn external_declaration(p: &mut Parser<'_, '_>) {
p.start_node(EXTERNAL_DECL);
p.bump(); p.skip_ws();
p.start_node(IDENTIFIER);
p.expect(IDENT);
p.finish_node();
p.skip_ws();
p.expect(L_PAREN);
p.skip_ws();
if p.current() == IDENT {
function_param_list(p);
}
p.skip_ws();
p.expect(R_PAREN);
p.skip_ws();
if p.at(NEWLINE) {
p.bump();
}
p.finish_node();
}
fn function_param_list(p: &mut Parser<'_, '_>) {
p.start_node(FUNCTION_PARAM_LIST);
p.start_node(IDENTIFIER);
p.bump(); p.finish_node();
loop {
p.skip_ws();
if !p.eat(COMMA) {
break;
}
p.skip_ws();
p.start_node(IDENTIFIER);
p.expect(IDENT);
p.finish_node();
}
p.finish_node();
}
pub(crate) fn var_declaration(p: &mut Parser<'_, '_>) {
p.start_node(VAR_DECL);
p.bump(); p.skip_ws();
p.start_node(IDENTIFIER);
p.expect(IDENT);
p.finish_node();
p.skip_ws();
p.expect(EQ);
p.skip_ws();
super::expression::expression(p);
if p.at(NEWLINE) {
p.bump();
}
p.finish_node();
}
pub(crate) fn const_declaration(p: &mut Parser<'_, '_>) {
p.start_node(CONST_DECL);
p.bump(); p.skip_ws();
p.start_node(IDENTIFIER);
p.expect(IDENT);
p.finish_node();
p.skip_ws();
p.expect(EQ);
p.skip_ws();
super::expression::expression(p);
if p.at(NEWLINE) {
p.bump();
}
p.finish_node();
}
pub(crate) fn list_declaration(p: &mut Parser<'_, '_>) {
p.start_node(LIST_DECL);
p.bump(); p.skip_ws();
p.start_node(IDENTIFIER);
p.expect(IDENT);
p.finish_node();
p.skip_ws();
p.expect(EQ);
p.skip_ws();
list_definition(p);
p.skip_ws();
if p.at(NEWLINE) {
p.bump();
}
p.finish_node();
}
fn list_definition(p: &mut Parser<'_, '_>) {
p.start_node(LIST_DEF);
list_member(p);
loop {
p.skip_ws();
if !p.eat(COMMA) {
break;
}
p.skip_ws();
list_member(p);
}
p.finish_node();
}
fn list_member(p: &mut Parser<'_, '_>) {
p.start_node(LIST_MEMBER);
if p.current() == L_PAREN {
p.start_node(LIST_MEMBER_ON);
p.bump(); p.skip_ws();
p.expect_ident_or_keyword();
p.skip_ws();
if p.eat(EQ) {
p.skip_ws();
p.expect(INTEGER);
}
p.skip_ws();
p.expect(R_PAREN);
p.finish_node();
} else {
p.start_node(LIST_MEMBER_OFF);
p.expect_ident_or_keyword();
p.skip_ws();
if p.eat(EQ) {
p.skip_ws();
p.expect(INTEGER);
}
p.finish_node();
}
p.finish_node();
}
pub(crate) fn at_declaration(p: &Parser<'_, '_>) -> bool {
matches!(
p.current(),
KW_INCLUDE | KW_EXTERNAL | KW_VAR | KW_CONST | KW_LIST
)
}
pub(crate) fn at_inline_declaration(p: &Parser<'_, '_>) -> bool {
matches!(p.current(), KW_VAR | KW_CONST | KW_LIST)
}
pub(crate) fn declaration(p: &mut Parser<'_, '_>) {
match p.current() {
KW_INCLUDE => include_statement(p),
KW_EXTERNAL => external_declaration(p),
KW_VAR => var_declaration(p),
KW_CONST => const_declaration(p),
KW_LIST => list_declaration(p),
_ => {
p.error("expected declaration".into());
}
}
}