yash_env/
parser.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2025 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//! Shell language parser configuration and utilities
18//!
19//! This module contains several items related to the shell language parser.
20//!
21//! - [`Config`] is a struct that holds configuration options for the parser.
22//! - [`IsKeyword`] is a wrapper for a function that checks if a string is a
23//!   reserved word.
24//! - [`IsName`] is a wrapper for a function that checks if a string is a valid
25//!   variable name.
26//!
27//! Parser implementations are not provided in this crate (`yash-env`). The
28//! standard parser implementation is provided in the `yash-syntax` crate.
29
30use crate::Env;
31use crate::input::InputObject;
32use crate::source::Source;
33use derive_more::Debug;
34use std::num::NonZeroU64;
35use std::rc::Rc;
36
37/// Configuration for the parser
38///
39/// This struct holds various configuration options for the parser, including
40/// the input function to read source code and source information.
41///
42/// Parser implementations are not provided in this crate (`yash-env`). The
43/// standard parser implementation is provided in the `yash-syntax` crate.
44/// `Config` is provided here so that other crates can use [`RunReadEvalLoop`]
45/// without depending on `yash-syntax`.
46///
47/// Since this struct is marked as `#[non_exhaustive]`, you cannot construct it
48/// directly. Instead, use the [`with_input`](Self::with_input) function to
49/// create a `Config` instance, and then modify its fields as necessary.
50///
51/// [`RunReadEvalLoop`]: crate::semantics::RunReadEvalLoop
52#[derive(Debug)]
53#[non_exhaustive]
54pub struct Config<'a> {
55    /// Input function to read source code
56    #[debug(skip)]
57    pub input: Box<dyn InputObject + 'a>,
58
59    /// Line number for the first line of the input
60    ///
61    /// The lexer counts lines starting from this number. This affects the
62    /// `start_line_number` field of the [`Code`] instance attached to the
63    /// parsed AST.
64    ///
65    /// The default value is `1`.
66    ///
67    /// [`Code`]: crate::source::Code
68    pub start_line_number: NonZeroU64,
69
70    /// Source information for the input
71    ///
72    /// If provided, this source information is saved in the `source` field of
73    /// the [`Code`] instance attached to the parsed AST.
74    ///
75    /// The default value is `None`, in which case `Source::Unknown` is used.
76    ///
77    /// [`Code`]: crate::source::Code
78    pub source: Option<Rc<Source>>,
79}
80
81impl<'a> Config<'a> {
82    /// Creates a `Config` with the given input function.
83    #[must_use]
84    pub fn with_input(input: Box<dyn InputObject + 'a>) -> Self {
85        Self {
86            input,
87            start_line_number: NonZeroU64::new(1).unwrap(),
88            source: None,
89        }
90    }
91}
92
93/// Wrapper for a function that checks if a string is a keyword
94///
95/// This struct wraps a function that takes an environment and a string, and
96/// returns `true` if the string is a shell reserved word (keyword) in the given
97/// environment. An implementation of the function should be provided and stored
98/// in the environment's [`any`](Env::any) storage. This allows modules that
99/// need to check for keywords to do so without directly depending on the parser
100/// crate (`yash-syntax`).
101#[derive(Clone, Copy, Debug)]
102pub struct IsKeyword(pub fn(&Env, &str) -> bool);
103
104/// Wrapper for a function that checks if a string is a valid variable name
105///
106/// This struct wraps a function that takes an environment and a string, and
107/// returns `true` if the string is a valid shell variable name in the given
108/// environment. An implementation of the function should be provided and stored
109/// in the environment's [`any`](Env::any) storage. This allows modules that
110/// need to check for variable names to do so without directly depending on the
111/// parser crate (`yash-syntax`).
112#[derive(Clone, Copy, Debug)]
113pub struct IsName(pub fn(&Env, &str) -> bool);