yog_script_analyze/parser/
mod.rs1mod block;
6mod decl;
7mod expr;
8mod header;
9mod lambda;
10mod member;
11mod params;
12pub(crate) mod patch;
13mod pattern;
14mod postfix;
15mod primary;
16mod types;
17
18use yog_ids::script_problem;
19
20use crate::source::token::{Punct, Span, Tok, Token};
21use crate::words::{Starts, Word};
22use yog_analysis::Report;
23
24#[derive(Debug)]
26pub struct Fail;
27
28pub type PResult<T> = Result<T, Fail>;
29
30pub struct Parser<'t, 'r, 'a> {
31 toks: &'t [Token],
32 pos: usize,
33 pub(crate) report: &'r mut Report<'a>,
34 pub(crate) nanites: bool,
36 no_brace: bool,
39}
40
41impl<'t, 'r, 'a> Parser<'t, 'r, 'a> {
42 pub fn new(toks: &'t [Token], report: &'r mut Report<'a>, nanites: bool) -> Self {
44 Parser {
45 toks,
46 pos: 0,
47 report,
48 nanites,
49 no_brace: false,
50 }
51 }
52
53 pub(crate) fn consumed(&self) -> usize {
55 self.pos
56 }
57
58 pub(crate) fn tok(&self) -> &'t Tok {
59 self.nth(0)
60 }
61
62 pub(crate) fn nth(&self, n: usize) -> &'t Tok {
64 let last = self.toks.len().saturating_sub(1);
65 &self.toks[(self.pos + n).min(last)].tok
66 }
67
68 pub(crate) fn span(&self) -> Span {
69 self.span_at(0)
70 }
71
72 pub(crate) fn span_at(&self, n: usize) -> Span {
74 self.toks[(self.pos + n).min(self.toks.len() - 1)].span
75 }
76
77 pub(crate) fn prev(&self) -> Span {
79 self.pos
80 .checked_sub(1)
81 .map_or_else(|| self.span(), |i| self.toks[i].span)
82 }
83
84 pub(crate) fn bump(&mut self) -> &'t Token {
85 let t = &self.toks[self.pos.min(self.toks.len() - 1)];
86 if t.tok != Tok::Eof {
87 self.pos += 1;
88 }
89 t
90 }
91
92 pub(crate) fn at(&self, p: Punct) -> bool {
93 *self.tok() == Tok::Punct(p)
94 }
95
96 pub(crate) fn nth_is(&self, n: usize, p: Punct) -> bool {
97 *self.nth(n) == Tok::Punct(p)
98 }
99
100 pub(crate) fn eat(&mut self, p: Punct) -> bool {
101 let here = self.at(p);
102 if here {
103 self.bump();
104 }
105 here
106 }
107
108 pub(crate) fn need(&mut self, p: Punct) -> PResult<Span> {
109 if self.at(p) {
110 return Ok(self.bump().span);
111 }
112 Err(self.expected(&format!("`{}`", p.text())))
113 }
114
115 pub(crate) fn end(&mut self) -> PResult<()> {
117 self.need(Punct::Semi).map(drop)
118 }
119
120 pub(crate) fn is_word(tok: &Tok, word: &Word) -> bool {
122 match tok {
123 Tok::Keyword(w) => *w == word,
124 Tok::Ident(text) => !word.reserved && text == word.text,
125 _ => false,
126 }
127 }
128
129 pub(crate) fn at_word(&self, word: &Word) -> bool {
130 Self::is_word(self.tok(), word)
131 }
132
133 pub(crate) fn nth_word(&self, n: usize, word: &Word) -> bool {
134 Self::is_word(self.nth(n), word)
135 }
136
137 pub(crate) fn eat_word(&mut self, word: &Word) -> bool {
138 let here = self.at_word(word);
139 if here {
140 self.bump();
141 }
142 here
143 }
144
145 pub(crate) fn need_word(&mut self, word: &Word) -> PResult<Span> {
146 if self.at_word(word) {
147 return Ok(self.bump().span);
148 }
149 Err(self.expected(&format!("`{}`", word.text)))
150 }
151
152 pub(crate) fn starts(&self, word: &Word, starts: Starts) -> bool {
154 starts.map_or_else(|| self.at_word(word), |f| f(self))
155 }
156
157 pub(crate) fn expected(&mut self, what: &str) -> Fail {
159 let found = describe(self.tok());
160 self.error(
161 script_problem::EXPECTED,
162 self.span(),
163 format!("expected {what}, found {found}"),
164 )
165 }
166
167 pub(crate) fn error(
168 &mut self,
169 code: &str,
170 span: Span,
171 message: impl std::fmt::Display,
172 ) -> Fail {
173 self.report.error(code, span, message);
174 Fail
175 }
176
177 pub(crate) fn recover(&mut self) {
180 let mut depth = 0usize;
181 loop {
182 match self.tok() {
183 Tok::Eof => return,
184 Tok::Punct(Punct::Semi) if depth == 0 => {
185 self.bump();
186 return;
187 }
188 Tok::Punct(Punct::LBrace | Punct::LParen | Punct::LBracket) => depth += 1,
189 Tok::Punct(Punct::RBrace | Punct::RParen | Punct::RBracket) => {
190 if depth == 0 {
191 return;
192 }
193 depth -= 1;
194 if depth == 0 && self.at(Punct::RBrace) {
195 self.bump();
196 return;
197 }
198 }
199 _ => {}
200 }
201 self.bump();
202 }
203 }
204
205 pub(crate) fn no_brace<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
207 let was = std::mem::replace(&mut self.no_brace, true);
208 let out = f(self);
209 self.no_brace = was;
210 out
211 }
212
213 pub(crate) fn braces<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
215 let was = std::mem::replace(&mut self.no_brace, false);
216 let out = f(self);
217 self.no_brace = was;
218 out
219 }
220}
221
222fn describe(tok: &Tok) -> String {
224 match tok {
225 Tok::Ident(name) => format!("`{name}`"),
226 Tok::Keyword(w) => format!("`{}`", w.text),
227 Tok::Punct(p) => format!("`{}`", p.text()),
228 Tok::Int(_) | Tok::Float(_) | Tok::Unit(..) => "a number".into(),
229 Tok::Version(v) => format!("the version `{v}`"),
230 Tok::Str(_) | Tok::RawStr(_) | Tok::Text(_) => "a string".into(),
231 Tok::Char(_) => "a character".into(),
232 Tok::Lifetime(name) => format!("the lifetime `'{name}`"),
233 Tok::Content(kind, id) => format!("`@{kind}:{id}`"),
234 Tok::Tag(id) => format!("`#{id}`"),
235 Tok::Doc(_) => "a doc comment".into(),
236 Tok::Eof => "the end of the file".into(),
237 }
238}