1use std::{
2 collections::{HashMap, VecDeque},
3 sync::Arc,
4};
5
6use smallvec::SmallVec;
7
8use shuck_ast::{
9 AnonymousFunctionCommand, Assignment, Comment, CompoundCommand, DeclOperand, FunctionDef, Name,
10 Position, Redirect, Span, TokenKind, Word,
11};
12
13use super::{
14 Keyword, LexedToken, Lexer, ShellDialect, ShellProfile, SyntaxFacts, ZshOptionTimeline,
15};
16
17#[cfg(feature = "benchmarking")]
18#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
19#[doc(hidden)]
20pub struct ParserBenchmarkCounters {
21 pub lexer_current_position_calls: u64,
23 pub parser_set_current_spanned_calls: u64,
25 pub parser_advance_raw_calls: u64,
27}
28
29#[derive(Debug, Clone)]
30pub(super) struct SimpleCommand {
31 pub(super) name: Word,
32 pub(super) args: SmallVec<[Word; 2]>,
33 pub(super) redirects: SmallVec<[Redirect; 1]>,
34 pub(super) assignments: SmallVec<[Assignment; 1]>,
35 pub(super) span: Span,
36}
37
38#[derive(Debug, Clone)]
39pub(super) struct BreakCommand {
40 pub(super) depth: Option<Word>,
41 pub(super) extra_args: SmallVec<[Word; 2]>,
42 pub(super) redirects: SmallVec<[Redirect; 1]>,
43 pub(super) assignments: SmallVec<[Assignment; 1]>,
44 pub(super) span: Span,
45}
46
47#[derive(Debug, Clone)]
48pub(super) struct ContinueCommand {
49 pub(super) depth: Option<Word>,
50 pub(super) extra_args: SmallVec<[Word; 2]>,
51 pub(super) redirects: SmallVec<[Redirect; 1]>,
52 pub(super) assignments: SmallVec<[Assignment; 1]>,
53 pub(super) span: Span,
54}
55
56#[derive(Debug, Clone)]
57pub(super) struct ReturnCommand {
58 pub(super) code: Option<Word>,
59 pub(super) extra_args: SmallVec<[Word; 2]>,
60 pub(super) redirects: SmallVec<[Redirect; 1]>,
61 pub(super) assignments: SmallVec<[Assignment; 1]>,
62 pub(super) span: Span,
63}
64
65#[derive(Debug, Clone)]
66pub(super) struct ExitCommand {
67 pub(super) code: Option<Word>,
68 pub(super) extra_args: SmallVec<[Word; 2]>,
69 pub(super) redirects: SmallVec<[Redirect; 1]>,
70 pub(super) assignments: SmallVec<[Assignment; 1]>,
71 pub(super) span: Span,
72}
73
74#[derive(Debug, Clone)]
75pub(super) enum BuiltinCommand {
76 Break(BreakCommand),
77 Continue(ContinueCommand),
78 Return(ReturnCommand),
79 Exit(ExitCommand),
80}
81
82#[derive(Debug, Clone)]
83pub(super) struct DeclClause {
84 pub(super) variant: Name,
85 pub(super) variant_span: Span,
86 pub(super) operands: SmallVec<[DeclOperand; 2]>,
87 pub(super) redirects: SmallVec<[Redirect; 1]>,
88 pub(super) assignments: SmallVec<[Assignment; 1]>,
89 pub(super) span: Span,
90}
91
92#[derive(Debug, Clone)]
93pub(super) enum Command {
94 Simple(SimpleCommand),
95 Builtin(BuiltinCommand),
96 Decl(Box<DeclClause>),
97 Compound(Box<CompoundCommand>, SmallVec<[Redirect; 1]>),
98 Function(FunctionDef),
99 AnonymousFunction(AnonymousFunctionCommand, SmallVec<[Redirect; 1]>),
100}
101
102#[derive(Clone)]
109pub struct Parser<'a> {
110 pub(super) input: &'a str,
111 pub(super) lexer: Lexer<'a>,
112 pub(super) synthetic_tokens: VecDeque<SyntheticToken>,
113 pub(super) alias_replays: Vec<AliasReplay>,
114 pub(super) current_token: Option<LexedToken<'a>>,
115 pub(super) current_word_cache: Option<Word>,
116 pub(super) current_token_kind: Option<TokenKind>,
117 pub(super) current_keyword: Option<Keyword>,
118 pub(super) current_span: Span,
120 pub(super) peeked_token: Option<LexedToken<'a>>,
122 pub(super) max_depth: usize,
124 pub(super) current_depth: usize,
126 pub(super) fuel: usize,
128 pub(super) max_fuel: usize,
130 pub(super) source_text_pattern_depth: usize,
132 pub(super) comments: Vec<Comment>,
134 pub(super) aliases: HashMap<String, AliasDefinition>,
136 pub(super) expand_aliases: bool,
138 pub(super) expand_next_word: bool,
141 pub(super) brace_group_depth: usize,
143 pub(super) brace_body_stack: Vec<BraceBodyContext>,
146 pub(super) syntax_facts: SyntaxFacts,
147 pub(super) shell_profile: ShellProfile,
148 pub(super) zsh_timeline: Option<Arc<ZshOptionTimeline>>,
149 pub(super) dialect: ShellDialect,
150 pub(super) brace_scan_chars: std::cell::RefCell<Vec<(char, Position)>>,
152 #[cfg(feature = "benchmarking")]
153 pub(super) benchmark_counters: Option<ParserBenchmarkCounters>,
154}
155
156#[derive(Clone)]
157pub(super) struct ParserCheckpoint<'a> {
158 pub(super) lexer: Lexer<'a>,
159 pub(super) synthetic_tokens: VecDeque<SyntheticToken>,
160 pub(super) alias_replays: Vec<AliasReplay>,
161 pub(super) current_token: Option<LexedToken<'a>>,
162 pub(super) current_token_kind: Option<TokenKind>,
163 pub(super) current_keyword: Option<Keyword>,
164 pub(super) current_span: Span,
165 pub(super) peeked_token: Option<LexedToken<'a>>,
166 pub(super) current_depth: usize,
167 pub(super) source_text_pattern_depth: usize,
168 pub(super) fuel: usize,
169 pub(super) comments_len: usize,
173 pub(super) expand_next_word: bool,
174 pub(super) brace_group_depth: usize,
175 pub(super) brace_body_stack_len: usize,
176 pub(super) syntax_facts_zsh_brace_if_spans_len: usize,
177 pub(super) syntax_facts_zsh_always_spans_len: usize,
178 pub(super) syntax_facts_zsh_case_group_parts_len: usize,
179 #[cfg(feature = "benchmarking")]
180 pub(super) benchmark_counters: Option<ParserBenchmarkCounters>,
181}
182
183#[derive(Debug, Clone)]
184pub(super) struct AliasDefinition {
185 pub(super) tokens: Arc<[LexedToken<'static>]>,
186 pub(super) expands_next_word: bool,
187}
188
189#[derive(Debug, Clone)]
190pub(super) struct AliasReplay {
191 pub(super) tokens: Arc<[LexedToken<'static>]>,
192 pub(super) next_index: usize,
193 pub(super) base: Position,
194}
195
196impl AliasReplay {
197 pub(super) fn new(alias: &AliasDefinition, base: Position) -> Self {
198 Self {
199 tokens: Arc::clone(&alias.tokens),
200 next_index: 0,
201 base,
202 }
203 }
204
205 pub(super) fn next_token<'b>(&mut self) -> Option<LexedToken<'b>> {
206 let token = self.tokens.get(self.next_index)?.clone();
207 self.next_index += 1;
208 Some(token.into_owned().rebased(self.base).with_synthetic_flag())
209 }
210}
211
212#[derive(Debug, Clone, Copy)]
213pub(super) struct SyntheticToken {
214 pub(super) kind: TokenKind,
215 pub(super) span: Span,
216}
217
218impl SyntheticToken {
219 pub(super) const fn punctuation(kind: TokenKind, span: Span) -> Self {
220 Self { kind, span }
221 }
222
223 pub(super) fn materialize<'b>(self) -> LexedToken<'b> {
224 LexedToken::punctuation(self.kind).with_span(self.span)
225 }
226}
227
228#[derive(Debug, Clone, Copy)]
229pub(super) enum FlowControlBuiltinKind {
230 Break,
231 Continue,
232 Return,
233 Exit,
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
237pub(super) enum BraceBodyContext {
238 Ordinary,
239 Function,
240 IfClause,
241}