Skip to main content

alba_shell/
token.rs

1//! The lexer's output: operators and words. A word is a sequence of
2//! parts because quoting decides, later, what expands and what globs:
3//! `a$B'c'` is one word of three parts.
4
5/// A byte range into the command source string.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct Span {
8    pub start: usize,
9    pub end: usize,
10}
11
12#[derive(Debug, Clone, PartialEq)]
13pub struct Token {
14    pub kind: TokenKind,
15    pub span: Span,
16}
17
18#[derive(Debug, Clone, PartialEq)]
19pub enum TokenKind {
20    Word(Word),
21    AndAnd,
22    OrOr,
23    Pipe,
24    Semi,
25    /// `>`/`>>` (stderr: false) and `2>`/`2>>` (stderr: true). `1>` and
26    /// `1>>` lex as stderr: false: the digit names the fd POSIX-style.
27    RedirectOut {
28        stderr: bool,
29        append: bool,
30    },
31    RedirectIn,
32    /// `2>&1`.
33    StderrToStdout,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub struct Word {
38    pub parts: Vec<WordPart>,
39    pub span: Span,
40}
41
42#[derive(Debug, Clone, PartialEq)]
43pub enum WordPart {
44    /// Unquoted text. Glob characters and `~` live here; expansion
45    /// decides what they mean.
46    Text(String),
47    /// One character that a backslash escaped outside of quotes (`\ `,
48    /// `\*`, `\\`). It is a separate part rather than folded into `Text`
49    /// precisely so expansion can still tell it apart: an escaped
50    /// character is literal, so it must neither field-split nor act as
51    /// glob syntax, exactly like a quoted one.
52    Escaped(char),
53    SingleQuoted(String),
54    /// `"..."`: only `Text`, `Var`, and `CmdSubst` appear inside.
55    DoubleQuoted(Vec<WordPart>),
56    /// `$NAME` or `${NAME}`.
57    Var(String),
58    /// `$?`: the exit code of the last completed command. The one special
59    /// parameter in the subset; the others (`$$`, `$!`, `$#`, `$*`, `$@`,
60    /// `$1`..`$9`) are rejected by the lexer.
61    LastExit,
62    /// `$(...)`: the raw inner source, parsed recursively by the parser.
63    /// The span covers the inner source in the outer string, so nested
64    /// diagnostics point at the right place.
65    CmdSubst {
66        source: String,
67        span: Span,
68    },
69}