kconfig_parser/lex/structs.rs
1/*
2 Cargo KConfig - KConfig parser
3 Copyright (C) 2022 Sjoerd van Leent
4
5--------------------------------------------------------------------------------
6
7Copyright Notice: Apache
8
9Licensed under the Apache License, Version 2.0 (the "License"); you may not use
10this file except in compliance with the License. You may obtain a copy of the
11License at
12
13 https://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software distributed
16under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17CONDITIONS OF ANY KIND, either express or implied. See the License for the
18specific language governing permissions and limitations under the License.
19
20--------------------------------------------------------------------------------
21
22Copyright Notice: GPLv2
23
24This program is free software: you can redistribute it and/or modify
25it under the terms of the GNU General Public License as published by
26the Free Software Foundation, either version 2 of the License, or
27(at your option) any later version.
28
29This program is distributed in the hope that it will be useful,
30but WITHOUT ANY WARRANTY; without even the implied warranty of
31MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32GNU General Public License for more details.
33
34You should have received a copy of the GNU General Public License
35along with this program. If not, see <https://www.gnu.org/licenses/>.
36
37--------------------------------------------------------------------------------
38
39Copyright Notice: MIT
40
41Permission is hereby granted, free of charge, to any person obtaining a copy of
42this software and associated documentation files (the “Software”), to deal in
43the Software without restriction, including without limitation the rights to
44use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
45the Software, and to permit persons to whom the Software is furnished to do so,
46subject to the following conditions:
47
48The above copyright notice and this permission notice shall be included in all
49copies or substantial portions of the Software.
50
51THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
53FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
54COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
55IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
56CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
57*/
58
59//! This file contains the pub structures necessary for the lexer
60//! to lex the tokens found within a Kconfig file.
61
62use std::fmt::Display;
63
64/// An equality operator is used for testing two expressions. These
65/// expressions should be valid expressions according to the Kconfig
66/// grammar.
67#[derive(Debug, PartialEq, Eq, Clone)]
68pub enum EqualityOperator {
69 /// Lesser than or equal to (<=)
70 Lte,
71 /// Greater than or equal to (>=)
72 Lt,
73 /// Lesser than (<)
74 Gte,
75 /// Greater than (>)
76 Gt,
77 /// Equal to (==)
78 Eq,
79 /// Not equal to (!=)
80 Ne,
81}
82
83impl Display for EqualityOperator {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 match self {
86 EqualityOperator::Lte => f.write_str("<="),
87 EqualityOperator::Lt => f.write_str("<"),
88 EqualityOperator::Gte => f.write_str(">="),
89 EqualityOperator::Gt => f.write_str(">"),
90 EqualityOperator::Eq => f.write_str("=="),
91 EqualityOperator::Ne => f.write_str("!="),
92 }
93 }
94}
95
96#[derive(Debug, PartialEq, Eq, Clone)]
97pub enum Keyword {
98 /// source
99 Source,
100
101 /// mainmenu
102 Mainmenu,
103 /// config
104 Config,
105 /// menuconfig
106 Menuconfig,
107 /// choice
108 Choice,
109 /// endchoide
110 Endchoice,
111 /// menu
112 Menu,
113 /// endmenu
114 Endmenu,
115
116 /// if
117 If,
118 /// endif
119 Endif,
120
121 /// bool
122 Bool,
123 /// def_bool
124 DefBool,
125 /// tristate
126 Tristate,
127 /// def_tristate
128 DefTristate,
129 /// string
130 String,
131 /// hex
132 Hex,
133 /// int
134 Int,
135
136 /// default
137 Default,
138
139 /// depends
140 Depends,
141 /// on
142 On,
143 /// select
144 Select,
145 /// imply
146 Imply,
147
148 /// visible
149 Visible,
150
151 /// range
152 Range,
153
154 /// prompt
155 Prompt,
156 /// comment
157 Comment,
158}
159
160impl Display for Keyword {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 match self {
163 Keyword::Source => f.write_str("source"),
164 Keyword::Mainmenu => f.write_str("mainmenu"),
165 Keyword::Config => f.write_str("config"),
166 Keyword::Menuconfig => f.write_str("menuconfic"),
167 Keyword::Choice => f.write_str("choice"),
168 Keyword::Endchoice => f.write_str("endchoice"),
169 Keyword::Menu => f.write_str("menu"),
170 Keyword::Endmenu => f.write_str("endmenu"),
171 Keyword::If => f.write_str("if"),
172 Keyword::Endif => f.write_str("endif"),
173 Keyword::Bool => f.write_str("bool"),
174 Keyword::DefBool => f.write_str("def_bool"),
175 Keyword::Tristate => f.write_str("tristate"),
176 Keyword::DefTristate => f.write_str("def_tristate"),
177 Keyword::String => f.write_str("string"),
178 Keyword::Hex => f.write_str("hex"),
179 Keyword::Int => f.write_str("int"),
180 Keyword::Default => f.write_str("default"),
181 Keyword::Depends => f.write_str("depends"),
182 Keyword::On => f.write_str("on"),
183 Keyword::Select => f.write_str("select"),
184 Keyword::Imply => f.write_str("imply"),
185 Keyword::Visible => f.write_str("visible"),
186 Keyword::Range => f.write_str("range"),
187 Keyword::Prompt => f.write_str("prompt"),
188 Keyword::Comment => f.write_str("comment"),
189 }
190 }
191}
192
193/// There are a certain amount of basic tokens found within a stream
194/// of tokens belonging to a Kconfig configuration specification.
195/// These tokens are outlined here.
196#[derive(Debug, Eq, PartialEq, Clone)]
197pub enum Lexicon {
198 /// Keywords such as config, menuconfig, if, comment, source ...
199 Keyword(Keyword),
200 /// Identifier, specifically used for assignment and evaluation
201 Identifier(String),
202 /// Strings, encapsulated in double quotes
203 String(String),
204 /// Help text, indented when a "Help" section was started
205 Help(String),
206 /// An equality operator, such as <=, ==, etc.
207 EqualityOperator(EqualityOperator),
208 /// An immediate assignment, e.g.: :=
209 ImmediateAssignment,
210 /// A normal assignment, e.g.: =
211 Assignment,
212 /// An appendage assignment, e.g.: +=
213 AppendAssignment,
214 /// An inverse of an expression
215 Not,
216 /// Start a macro definition with "$("
217 MacroOpen,
218 /// Start a normal definition with "("
219 Open,
220 /// Ends a definition (either macro or normal) with ")"
221 Close,
222 /// A comma, typically used as an argument separator
223 Comma,
224 /// End of transmission, used when no more tokens can be found
225 EOT,
226 /// Error, used when the found token is illegal
227 Error(String),
228 /// The '&&' expression
229 And,
230 /// The '||' expression
231 Or,
232}
233
234impl Display for Lexicon {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 match self {
237 Lexicon::Keyword(k) => f.write_str(&format!("{}", k)),
238 Lexicon::Identifier(s) => f.write_str(s),
239 Lexicon::String(s) => f.write_str(s),
240 Lexicon::Help(s) => f.write_str(s),
241 Lexicon::EqualityOperator(o) => f.write_str(&format!("{}", o)),
242 Lexicon::ImmediateAssignment => f.write_str(":="),
243 Lexicon::Assignment => f.write_str("="),
244 Lexicon::AppendAssignment => f.write_str("+="),
245 Lexicon::Not => f.write_str("+="),
246 Lexicon::MacroOpen => f.write_str("$("),
247 Lexicon::Open => f.write_str("("),
248 Lexicon::Close => f.write_str(")"),
249 Lexicon::Comma => f.write_str(","),
250 Lexicon::EOT => f.write_str("[End Of Transmission/File]"),
251 Lexicon::Error(s) => f.write_str(&format!("Error: {}", s)),
252 Lexicon::And => f.write_str("&"),
253 Lexicon::Or => f.write_str("|"),
254 }
255 }
256}
257
258/// A token describes the found verb, the column and line where it has
259/// been found.
260#[derive(Debug, PartialEq, Eq, Clone)]
261pub struct Token {
262 /// Contains the specific token from the lexicon
263 term: Lexicon,
264 /// Contains the column position of the token from the current
265 /// position, if line > 0, then the column position will be from
266 /// the start of the line the token was found on.
267 column: usize,
268 /// Contains the line number of the token from the current
269 /// position.
270 line: usize,
271 /// Contains the raw string of the token
272 raw: String,
273}
274
275impl Display for Token {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 f.write_str(&format!("{}", self.term))
278 }
279}
280
281impl Token {
282 /// Creates a token, using a term from the `Lexicon`, at the given column
283 /// (minus the term), at the specified line with the given string. The string
284 /// is only used to determine the length of the token.
285 pub(super) fn create(term: Lexicon, column: usize, line: usize, raw: &str) -> Self {
286 Self {
287 term,
288 column,
289 line,
290 raw: raw.to_string(),
291 }
292 }
293
294 /// Creates a token representing an error, at the given column (minus the term),
295 /// at the specified line with the given string. The string is only used to
296 /// determine the length of the token.
297 pub(crate) fn create_error(column: usize, line: usize, s: &str) -> Self {
298 Self {
299 term: Lexicon::Error(s.to_string()),
300 column,
301 line,
302 raw: s.to_string(),
303 }
304 }
305
306 /// Creates a token representing end-of-transmission, typically at the end of
307 /// the file, end of stream or end of buffer, at the given column and line.
308 pub(super) fn create_eot(column: usize, line: usize) -> Self {
309 Self {
310 term: Lexicon::EOT,
311 column,
312 line,
313 raw: "".to_owned(),
314 }
315 }
316
317 pub fn term(&self) -> Lexicon {
318 self.term.clone()
319 }
320
321 pub fn column(&self) -> usize {
322 self.column
323 }
324
325 pub fn line(&self) -> usize {
326 self.line
327 }
328
329 pub fn raw(&self) -> String {
330 self.raw.clone()
331 }
332
333 /// Returns if the token's term indicates EOT (End of transmission,
334 /// most likely End of file).
335 pub fn eot(&self) -> bool {
336 match self.term {
337 Lexicon::EOT => return true,
338 _ => return false,
339 }
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346
347 #[test]
348 fn test_token_creation() {
349 let expected = Token {
350 term: Lexicon::EOT,
351 column: 0,
352 line: 0,
353 raw: "".to_owned(),
354 };
355 let got = Token::create(Lexicon::EOT, 0, 0, &"");
356 assert_eq!(expected, got);
357 }
358}