Skip to main content

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    /// `]]`
43    CloseBracketBracket,
44    Case,
45    Do,
46    Done,
47    Elif,
48    Else,
49    Esac,
50    Fi,
51    For,
52    Function,
53    If,
54    In,
55    Namespace,
56    Select,
57    Then,
58    Until,
59    While,
60    /// `{`
61    OpenBrace,
62    /// `}`
63    CloseBrace,
64}
65
66impl Keyword {
67    /// Returns the literal string representation of the keyword.
68    #[must_use]
69    pub const fn as_str(&self) -> &'static str {
70        use Keyword::*;
71        match self {
72            Bang => "!",
73            OpenBracketBracket => "[[",
74            CloseBracketBracket => "]]",
75            Case => "case",
76            Do => "do",
77            Done => "done",
78            Elif => "elif",
79            Else => "else",
80            Esac => "esac",
81            Fi => "fi",
82            For => "for",
83            Function => "function",
84            If => "if",
85            In => "in",
86            Namespace => "namespace",
87            Select => "select",
88            Then => "then",
89            Until => "until",
90            While => "while",
91            OpenBrace => "{",
92            CloseBrace => "}",
93        }
94    }
95
96    /// Determines if this token can be a delimiter of a clause.
97    ///
98    /// This function returns `true` for `Do`, `Done`, `Elif`, `Else`, `Esac`,
99    /// `Fi`, `Then`, and `CloseBrace`, and `false` for others.
100    #[must_use]
101    pub const fn is_clause_delimiter(self) -> bool {
102        use Keyword::*;
103        match self {
104            Do | Done | Elif | Else | Esac | Fi | Then | CloseBrace => true,
105            Bang | OpenBracketBracket | CloseBracketBracket | Case | For | Function | If | In
106            | Namespace | Select | Until | While | OpenBrace => false,
107        }
108    }
109}
110
111impl fmt::Display for Keyword {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        f.write_str(self.as_str())
114    }
115}
116
117impl FromStr for Keyword {
118    type Err = ParseKeywordError;
119    fn from_str(s: &str) -> Result<Keyword, ParseKeywordError> {
120        use Keyword::*;
121        match s {
122            "!" => Ok(Bang),
123            "[[" => Ok(OpenBracketBracket),
124            "]]" => Ok(CloseBracketBracket),
125            "case" => Ok(Case),
126            "do" => Ok(Do),
127            "done" => Ok(Done),
128            "elif" => Ok(Elif),
129            "else" => Ok(Else),
130            "esac" => Ok(Esac),
131            "fi" => Ok(Fi),
132            "for" => Ok(For),
133            "function" => Ok(Function),
134            "if" => Ok(If),
135            "in" => Ok(In),
136            "namespace" => Ok(Namespace),
137            "select" => Ok(Select),
138            "then" => Ok(Then),
139            "until" => Ok(Until),
140            "while" => Ok(While),
141            "{" => Ok(OpenBrace),
142            "}" => Ok(CloseBrace),
143            _ => Err(ParseKeywordError),
144        }
145    }
146}