yash_syntax/parser/lex/
keyword.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2021 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Types and functions for parsing reserved words
18
19use std::fmt;
20use std::str::FromStr;
21use thiserror::Error;
22
23/// Error value indicating that a string is not a keyword
24///
25/// This error is returned by [`Keyword::from_str`] when the input string is not
26/// a keyword.
27#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
28pub struct ParseKeywordError;
29
30impl fmt::Display for ParseKeywordError {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.write_str("not a keyword")
33    }
34}
35
36/// Token identifier for reserved words
37#[derive(Clone, Copy, Debug, Eq, PartialEq)]
38pub enum Keyword {
39    Bang,
40    /// `[[`
41    OpenBracketBracket,
42    Case,
43    Do,
44    Done,
45    Elif,
46    Else,
47    Esac,
48    Fi,
49    For,
50    Function,
51    If,
52    In,
53    Then,
54    Until,
55    While,
56    /// `{`
57    OpenBrace,
58    /// `}`
59    CloseBrace,
60}
61
62impl Keyword {
63    /// Returns the literal string representation of the keyword.
64    #[must_use]
65    pub const fn as_str(&self) -> &'static str {
66        use Keyword::*;
67        match self {
68            Bang => "!",
69            OpenBracketBracket => "[[",
70            Case => "case",
71            Do => "do",
72            Done => "done",
73            Elif => "elif",
74            Else => "else",
75            Esac => "esac",
76            Fi => "fi",
77            For => "for",
78            Function => "function",
79            If => "if",
80            In => "in",
81            Then => "then",
82            Until => "until",
83            While => "while",
84            OpenBrace => "{",
85            CloseBrace => "}",
86        }
87    }
88
89    /// Determines if this token can be a delimiter of a clause.
90    ///
91    /// This function returns `true` for `Do`, `Done`, `Elif`, `Else`, `Esac`,
92    /// `Fi`, `Then`, and `CloseBrace`, and `false` for others.
93    #[must_use]
94    pub const fn is_clause_delimiter(self) -> bool {
95        use Keyword::*;
96        match self {
97            Do | Done | Elif | Else | Esac | Fi | Then | CloseBrace => true,
98            Bang | OpenBracketBracket | Case | For | Function | If | In | Until | While
99            | OpenBrace => false,
100        }
101    }
102}
103
104impl fmt::Display for Keyword {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        f.write_str(self.as_str())
107    }
108}
109
110impl FromStr for Keyword {
111    type Err = ParseKeywordError;
112    fn from_str(s: &str) -> Result<Keyword, ParseKeywordError> {
113        use Keyword::*;
114        match s {
115            "!" => Ok(Bang),
116            "[[" => Ok(OpenBracketBracket),
117            "case" => Ok(Case),
118            "do" => Ok(Do),
119            "done" => Ok(Done),
120            "elif" => Ok(Elif),
121            "else" => Ok(Else),
122            "esac" => Ok(Esac),
123            "fi" => Ok(Fi),
124            "for" => Ok(For),
125            "function" => Ok(Function),
126            "if" => Ok(If),
127            "in" => Ok(In),
128            "then" => Ok(Then),
129            "until" => Ok(Until),
130            "while" => Ok(While),
131            "{" => Ok(OpenBrace),
132            "}" => Ok(CloseBrace),
133            _ => Err(ParseKeywordError),
134        }
135    }
136}