arity_parser/parser/
core.rs1use crate::parser::bracket_balancer::rebalance_brackets;
2use crate::parser::context::StatementTracker;
3use crate::parser::events::Event;
4use crate::parser::expr::parse_expr;
5use crate::parser::lexer::{TokKind, lex_with_md};
6use crate::parser::tree_builder::build_tree;
7use crate::syntax::SyntaxNode;
8
9pub use crate::parser::diagnostics::ParseDiagnostic;
10
11#[derive(Debug, Clone)]
12pub struct ParseOutput {
13 pub cst: SyntaxNode,
14 pub diagnostics: Vec<ParseDiagnostic>,
15}
16
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
21#[non_exhaustive]
22pub struct ParseOptions {
23 pub roxygen_markdown_default: bool,
35}
36
37impl ParseOptions {
38 #[must_use]
45 pub fn with_roxygen_markdown_default(mut self, on: bool) -> Self {
46 self.roxygen_markdown_default = on;
47 self
48 }
49}
50
51pub fn parse(text: &str) -> ParseOutput {
52 parse_with_options(text, &ParseOptions::default())
53}
54
55pub fn parse_with_options(text: &str, options: &ParseOptions) -> ParseOutput {
58 let md_default = options.roxygen_markdown_default;
59 let tokens = rebalance_brackets(lex_with_md(text, md_default));
60 let mut diagnostics = Vec::new();
61 let mut root_events = Vec::new();
62
63 let mut i = 0usize;
64 let mut statements = StatementTracker::default();
65 while i < tokens.len() {
66 if matches!(
67 tokens[i].kind,
68 TokKind::Whitespace | TokKind::Newline | TokKind::Semicolon
69 ) {
70 root_events.push(Event::Tok(i));
71 i += 1;
72 continue;
73 }
74
75 if tokens[i].kind == TokKind::RoxygenMarker {
76 i = crate::parser::roxygen::emit_roxygen_block(
77 &tokens,
78 i,
79 &mut root_events,
80 md_default,
81 );
82 continue;
83 }
84
85 let before = diagnostics.len();
86 if let Some(expr) = parse_expr(&tokens, i, 0, &mut diagnostics, md_default) {
87 if !tokens[expr.start].kind.is_comment_like() {
91 let recovered = diagnostics.len() > before;
92 statements.record(&tokens, expr.start, expr.end, recovered, &mut diagnostics);
93 }
94 root_events.extend(expr.events);
95 i = expr.end;
96 } else {
97 crate::parser::diagnostics::push_token_diagnostic(
102 &mut diagnostics,
103 &format!("unexpected '{}'", tokens[i].text),
104 &tokens[i],
105 );
106 root_events.push(Event::Tok(i));
107 i += 1;
108 statements.record_recovery(i);
109 }
110 }
111
112 let cst = build_tree(&tokens, &root_events);
113 ParseOutput { cst, diagnostics }
114}
115
116pub fn reconstruct(text: &str) -> String {
117 parse(text)
118 .cst
119 .descendants_with_tokens()
120 .filter_map(|el| el.into_token())
121 .map(|tok| tok.text().to_string())
122 .collect::<String>()
123}