1pub mod char_tokens {
10 pub const META: char = '\u{83}';
11 pub const POUND: char = '\u{84}'; pub const STRING: char = '\u{85}'; pub const HAT: char = '\u{86}'; pub const STAR: char = '\u{87}'; pub const INPAR: char = '\u{88}'; pub const INPARMATH: char = '\u{89}'; pub const OUTPAR: char = '\u{8a}'; pub const OUTPARMATH: char = '\u{8b}'; pub const QSTRING: char = '\u{8c}'; pub const EQUALS: char = '\u{8d}'; pub const BAR: char = '\u{8e}'; pub const INBRACE: char = '\u{8f}'; pub const OUTBRACE: char = '\u{90}'; pub const INBRACK: char = '\u{91}'; pub const OUTBRACK: char = '\u{92}'; pub const TICK: char = '\u{93}'; pub const INANG: char = '\u{94}'; pub const OUTANG: char = '\u{95}'; pub const OUTANGPROC: char = '\u{96}'; pub const QUEST: char = '\u{97}'; pub const TILDE: char = '\u{98}'; pub const QTICK: char = '\u{99}'; pub const COMMA: char = '\u{9a}'; pub const DASH: char = '\u{9b}'; pub const BANG: char = '\u{9c}'; pub const LAST_NORMAL_TOK: char = BANG;
38
39 pub const SNULL: char = '\u{9d}'; pub const DNULL: char = '\u{9e}'; pub const BNULL: char = '\u{9f}'; pub const BNULLKEEP: char = '\u{a0}'; pub const NULARG: char = '\u{a1}'; pub const MARKER: char = '\u{a2}'; #[inline]
50 pub fn is_token(c: char) -> bool {
51 let b = c as u32;
52 b >= 0x84 && b <= 0xa2
53 }
54
55 pub fn untokenize(c: char) -> Option<char> {
57 match c {
58 POUND => Some('#'),
59 STRING | QSTRING => Some('$'),
60 HAT => Some('^'),
61 STAR => Some('*'),
62 INPAR | INPARMATH => Some('('),
63 OUTPAR | OUTPARMATH => Some(')'),
64 EQUALS => Some('='),
65 BAR => Some('|'),
66 INBRACE => Some('{'),
67 OUTBRACE => Some('}'),
68 INBRACK => Some('['),
69 OUTBRACK => Some(']'),
70 TICK | QTICK => Some('`'),
71 INANG => Some('<'),
72 OUTANG | OUTANGPROC => Some('>'),
73 QUEST => Some('?'),
74 TILDE => Some('~'),
75 COMMA => Some(','),
76 DASH => Some('-'),
77 BANG => Some('!'),
78 SNULL | DNULL | BNULL | BNULLKEEP | NULARG | MARKER => None,
79 _ => None,
80 }
81 }
82
83 pub const ZTOKENS: &str = "#$^*(())$=|{}[]`<>>?~`,-!'\"\\\\";
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91#[repr(u8)]
92pub enum LexTok {
93 Nulltok = 0,
94 Seper, Newlin, Semi, Dsemi, Amper, Inpar, Outpar, Dbar, Damper, Outang, Outangbang, Doutang, Doutangbang, Inang, Inoutang, Dinang, Dinangdash, Inangamp, Outangamp, Ampoutang, Outangampbang, Doutangamp, Doutangampbang, Trinang, Bar, Baramp, Inoutpar, Dinpar, Doutpar, Amperbang, Semiamp, Semibar, Doutbrack, String, Envstring, Envarray, Endinput, Lexerr, Bang, Dinbrack, Inbrace, Outbrace, Case, Coproc, Doloop, Done, Elif, Else, Zend, Esac, Fi, For, Foreach, Func, If, Nocorrect, Repeat, Select, Then, Time, Until, While, Typeset, }
162
163impl LexTok {
164 pub fn is_redirop(self) -> bool {
166 matches!(
167 self,
168 LexTok::Outang
169 | LexTok::Outangbang
170 | LexTok::Doutang
171 | LexTok::Doutangbang
172 | LexTok::Inang
173 | LexTok::Inoutang
174 | LexTok::Dinang
175 | LexTok::Dinangdash
176 | LexTok::Inangamp
177 | LexTok::Outangamp
178 | LexTok::Ampoutang
179 | LexTok::Outangampbang
180 | LexTok::Doutangamp
181 | LexTok::Doutangampbang
182 | LexTok::Trinang
183 )
184 }
185
186 pub fn as_str(self) -> Option<&'static str> {
188 match self {
189 LexTok::Nulltok => None,
190 LexTok::Seper => Some(";"),
191 LexTok::Newlin => Some("\\n"),
192 LexTok::Semi => Some(";"),
193 LexTok::Dsemi => Some(";;"),
194 LexTok::Amper => Some("&"),
195 LexTok::Inpar => Some("("),
196 LexTok::Outpar => Some(")"),
197 LexTok::Dbar => Some("||"),
198 LexTok::Damper => Some("&&"),
199 LexTok::Outang => Some(">"),
200 LexTok::Outangbang => Some(">|"),
201 LexTok::Doutang => Some(">>"),
202 LexTok::Doutangbang => Some(">>|"),
203 LexTok::Inang => Some("<"),
204 LexTok::Inoutang => Some("<>"),
205 LexTok::Dinang => Some("<<"),
206 LexTok::Dinangdash => Some("<<-"),
207 LexTok::Inangamp => Some("<&"),
208 LexTok::Outangamp => Some(">&"),
209 LexTok::Ampoutang => Some("&>"),
210 LexTok::Outangampbang => Some("&>|"),
211 LexTok::Doutangamp => Some(">>&"),
212 LexTok::Doutangampbang => Some(">>&|"),
213 LexTok::Trinang => Some("<<<"),
214 LexTok::Bar => Some("|"),
215 LexTok::Baramp => Some("|&"),
216 LexTok::Inoutpar => Some("()"),
217 LexTok::Dinpar => Some("(("),
218 LexTok::Doutpar => Some("))"),
219 LexTok::Amperbang => Some("&|"),
220 LexTok::Semiamp => Some(";&"),
221 LexTok::Semibar => Some(";|"),
222 _ => None,
223 }
224 }
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229#[repr(u8)]
230pub enum RedirType {
231 Write = 0, Writenow, App, Appnow, Errwrite, Errwritenow, Errapp, Errappnow, Readwrite, Read, Heredoc, Heredocdash, Herestr, Mergein, Mergeout, Close, Inpipe, Outpipe, }
250
251impl RedirType {
252 pub fn is_read(self) -> bool {
254 matches!(
255 self,
256 RedirType::Read
257 | RedirType::Readwrite
258 | RedirType::Heredoc
259 | RedirType::Heredocdash
260 | RedirType::Herestr
261 | RedirType::Mergein
262 | RedirType::Inpipe
263 )
264 }
265
266 pub fn is_write_file(self) -> bool {
268 matches!(
269 self,
270 RedirType::Write
271 | RedirType::Writenow
272 | RedirType::App
273 | RedirType::Appnow
274 | RedirType::Readwrite
275 )
276 }
277}
278
279#[derive(Debug, Clone, Copy, PartialEq, Eq)]
281#[repr(u8)]
282pub enum CondType {
283 Not = 0,
284 And,
285 Or,
286 Streq, Strdeq, Strneq, Strlt, Strgtr, Nt, Ot, Ef, Eq, Ne, Lt, Gt, Le, Ge, Regex, Mod, Modi, }
304
305pub const SPECCHARS: &str = "#$^*()=|{}[]`<>?~;&\n\t \\'\"";
307
308pub const PATCHARS: &str = "#^*()|[]<>?~\\";
310
311#[inline]
313pub fn is_dash(c: char) -> bool {
314 c == '-' || c == char_tokens::DASH
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq)]
319#[repr(u8)]
320pub enum LexAct1 {
321 Bkslash = 0,
322 Comment = 1,
323 Newlin = 2,
324 Semi = 3,
325 Amper = 5,
326 Bar = 6,
327 Inpar = 7,
328 Outpar = 8,
329 Inang = 13,
330 Outang = 14,
331 Other = 15,
332}
333
334#[derive(Debug, Clone, Copy, PartialEq, Eq)]
336#[repr(u8)]
337pub enum LexAct2 {
338 Break = 0,
339 Outpar = 1,
340 Bar = 2,
341 String = 3,
342 Inbrack = 4,
343 Outbrack = 5,
344 Tilde = 6,
345 Inpar = 7,
346 Inbrace = 8,
347 Outbrace = 9,
348 Outang = 10,
349 Inang = 11,
350 Equals = 12,
351 Bkslash = 13,
352 Quote = 14,
353 Dquote = 15,
354 Bquote = 16,
355 Comma = 17,
356 Dash = 18,
357 Bang = 19,
358 Other = 20,
359 Meta = 21,
360}
361
362pub static RESERVED_WORDS: &[(&str, LexTok)] = &[
364 ("!", LexTok::Bang),
365 ("[[", LexTok::Dinbrack),
366 ("{", LexTok::Inbrace),
367 ("}", LexTok::Outbrace),
368 ("case", LexTok::Case),
369 ("coproc", LexTok::Coproc),
370 ("do", LexTok::Doloop),
371 ("done", LexTok::Done),
372 ("elif", LexTok::Elif),
373 ("else", LexTok::Else),
374 ("end", LexTok::Zend),
375 ("esac", LexTok::Esac),
376 ("fi", LexTok::Fi),
377 ("for", LexTok::For),
378 ("foreach", LexTok::Foreach),
379 ("function", LexTok::Func),
380 ("if", LexTok::If),
381 ("nocorrect", LexTok::Nocorrect),
382 ("repeat", LexTok::Repeat),
383 ("select", LexTok::Select),
384 ("then", LexTok::Then),
385 ("time", LexTok::Time),
386 ("until", LexTok::Until),
387 ("while", LexTok::While),
388];
389
390pub fn lookup_reserved_word(s: &str) -> Option<LexTok> {
392 RESERVED_WORDS
393 .iter()
394 .find(|(word, _)| *word == s)
395 .map(|(_, tok)| *tok)
396}
397
398pub static TYPESET_COMMANDS: &[&str] = &[
400 "declare", "export", "float", "integer", "local", "readonly", "typeset",
401];
402
403pub fn is_typeset_command(s: &str) -> bool {
405 TYPESET_COMMANDS.contains(&s)
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411
412 #[test]
413 fn test_token_values() {
414 assert_eq!(char_tokens::SNULL as u32, 0x9d);
415 assert_eq!(char_tokens::DNULL as u32, 0x9e);
416 assert_eq!(char_tokens::BNULL as u32, 0x9f);
417 }
418
419 #[test]
420 fn test_reserved_words() {
421 assert_eq!(lookup_reserved_word("if"), Some(LexTok::If));
422 assert_eq!(lookup_reserved_word("then"), Some(LexTok::Then));
423 assert_eq!(lookup_reserved_word("notakeyword"), None);
424 }
425
426 #[test]
427 fn test_redirop() {
428 assert!(LexTok::Outang.is_redirop());
429 assert!(LexTok::Dinang.is_redirop());
430 assert!(!LexTok::If.is_redirop());
431 assert!(!LexTok::String.is_redirop());
432 }
433}