use enumset::enum_set; use crate::lst_parser::{ error::SyntaxError, grammar::expression::expression, syntax_kind::{SyntaxKind::*, TokenSet}, CompletedMarker, Parser, }; const TOP_LEVEL_ITEM_START: TokenSet = enum_set!(DEF_KW | MOD_KW | USE_KW); pub fn mod_body(p: &mut Parser) { loop { if top_level_item(p).is_none() { break; } } } fn mod_decl(p: &mut Parser) -> Option { let mod_start = p.start("module"); if !p.eat(MOD_KW) { mod_start.abandon(p); return None; } let mod_name = p.start("module_name"); if p.eat(IDENT) { mod_name.complete(p, MODULE_NAME); } else { mod_name.error(p, SyntaxError::Expected(vec![IDENT])); } let mod_body_marker = p.start("mod_body"); if p.eat(SEMICOLON) { mod_body_marker.abandon(p); Some(mod_start.complete(p, MODULE)) } else if p.eat(L_BRACE) { mod_body(p); if !p.eat(R_BRACE) { mod_body_marker .complete(p, MODULE_BODY) .precede(p, "unclosed_mod_body_err") .error(p, SyntaxError::UnclosedModuleBody); } else { mod_body_marker.complete(p, MODULE_BODY); } Some(mod_start.complete(p, MODULE)) } else { Some(mod_start.error(p, SyntaxError::Expected(vec![MODULE_BODY]))) } } pub fn top_level_item(p: &mut Parser) -> Option { if !TOP_LEVEL_ITEM_START.contains(p.current()) { return None; } def(p).or_else(|| mod_decl(p)).or_else(|| r#use(p)) } fn def(p: &mut Parser) -> Option { let def_start = p.start("top_level_def"); if !p.eat(DEF_KW) { def_start.abandon(p); return None; } let def_name = p.start("def_name"); if p.eat(IDENT) { def_name.complete(p, DEF_NAME); } else { def_name.error(p, SyntaxError::Expected(vec![IDENT])); } let maybe_expected_eq = p.start("maybe_expect_eq"); if !p.eat(EQ) { maybe_expected_eq.error(p, SyntaxError::Expected(vec![EQ])); } else { maybe_expected_eq.abandon(p); } let body = p.start("def_body"); if expression(p, false).is_some() { body.complete(p, DEF_BODY); } else { body.error(p, SyntaxError::Expected(vec![DEF_BODY])); } Some(if p.eat(SEMICOLON) { def_start.complete(p, DEF) } else if TOP_LEVEL_ITEM_START.contains(p.current()) || p.at(EOF) { def_start .complete(p, DEF) .precede(p, "unterminated_tl_item") .error(p, SyntaxError::UnterminatedTopLevelItem) } else { def_start .complete(p, DEF) .precede(p, "err_unexpected") .error(p, SyntaxError::Expected(vec![SEMICOLON])) }) } fn r#use(p: &mut Parser) -> Option { let use_start = p.start("use_start"); if !p.eat(USE_KW) { use_start.abandon(p); return None; } if use_pat(p).is_none() { p.start("expected_use_pat") .error(p, SyntaxError::Expected(vec![USE_PAT])); } let use_item = use_start.complete(p, USE); Some(if p.eat(SEMICOLON) { use_item } else if TOP_LEVEL_ITEM_START.contains(p.current()) || p.at(EOF) { use_item .precede(p, "unterminated_tl_item") .error(p, SyntaxError::UnterminatedTopLevelItem) } else { use_item .precede(p, "err_unexpected") .error(p, SyntaxError::Expected(vec![SEMICOLON])) }) } fn use_pat(p: &mut Parser) -> Option { let use_pat_marker = p.start("use_pat"); if !p.eat(IDENT) { return None; } loop { if p.eat(PATH_SEP) { if pat_item(p).is_none() { break Some(use_pat_marker.error(p, SyntaxError::UnfinishedPath)); } } else if p.at(SEMICOLON) && p.nth_at(1, COLON) { let broken_sep = p.start("broken_path_sep"); let wrong_semi = p.start("semi_typo"); p.eat(SEMICOLON); wrong_semi.error(p, SyntaxError::PathSepContainsSemicolon); p.eat(COLON); broken_sep.complete(p, PATH_SEP); if pat_item(p).is_none() { break Some(use_pat_marker.error(p, SyntaxError::UnfinishedPath)); } } else if p.at(COLON) && p.nth_at(1, SEMICOLON) { let broken_sep = p.start("broken_path_sep"); p.eat(COLON); let wrong_semi = p.start("semi_typo"); p.eat(SEMICOLON); wrong_semi.error(p, SyntaxError::PathSepContainsSemicolon); broken_sep.complete(p, PATH_SEP); if pat_item(p).is_none() { break Some(use_pat_marker.error(p, SyntaxError::UnfinishedPath)); } } else if p.at(SEMICOLON) && p.nth_at(1, SEMICOLON) { let broken_sep = p.start("broken_path_sep"); p.eat(SEMICOLON); p.eat(SEMICOLON); broken_sep .complete(p, PATH_SEP) .precede(p, "semi_typo_err") .error(p, SyntaxError::PathSepContainsSemicolon); if pat_item(p).is_none() { break Some(use_pat_marker.error(p, SyntaxError::UnfinishedPath)); } } else if p.eat(SEMICOLON) { break Some(use_pat_marker.complete(p, USE_PAT)); } else { break Some(use_pat_marker.error(p, SyntaxError::Expected(vec![PATH_SEP, SEMICOLON]))); } } } fn pat_item(p: &mut Parser) -> Option { let item_start = p.start("pat_item_start"); if p.eat(IDENT) { Some(item_start.complete(p, PAT_ITEM)) } else if p.eat(STAR) { Some(item_start.complete(p, PAT_GLOB)) } else if p.eat(L_BRACE) { todo!("write PAT_GROUPs") } else { None } }