Skip to content

Commit

Permalink
Type built-in (#350)
Browse files Browse the repository at this point in the history
  • Loading branch information
magicant authored Mar 7, 2024
2 parents 4f44149 + 72e1f07 commit 5d57650
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 3 deletions.
5 changes: 5 additions & 0 deletions yash-builtin/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@
//!
//! The `-p` option depends on [`System::confstr_path`] to obtain the standard
//! search path. See [`RealSystem::confstr_path`] for the supported platforms.
//!
//! The [`type`] built-in is equivalent to the `command` built-in with the `-V`
//! option.
//!
//! [`type`]: crate::type
use crate::common::report_error;
use enumset::EnumSet;
Expand Down
17 changes: 14 additions & 3 deletions yash-builtin/src/command/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use super::Invoke;
use super::Search;
use crate::common::syntax::parse_arguments;
use crate::common::syntax::Mode;
use crate::common::syntax::OptionOccurrence;
use crate::common::syntax::OptionSpec;
use crate::common::syntax::ParseError;
use thiserror::Error;
Expand Down Expand Up @@ -55,9 +56,13 @@ const OPTION_SPECS: &[OptionSpec] = &[
OptionSpec::new().short('V').long("verbose-identify"),
];

pub fn parse(env: &Env, args: Vec<Field>) -> Result<Command, Error> {
let (options, operands) = parse_arguments(OPTION_SPECS, Mode::with_env(env), args)?;

/// Interprets the parsed command line arguments
///
/// This function converts the result of [`parse_arguments`] into a `Command`.
pub fn interpret(
options: Vec<OptionOccurrence<'_>>,
operands: Vec<Field>,
) -> Result<Command, Error> {
// Interpret options
let mut standard_path = false;
let mut verbose_identify = None;
Expand Down Expand Up @@ -89,6 +94,12 @@ pub fn parse(env: &Env, args: Vec<Field>) -> Result<Command, Error> {
}
}

/// Parses command line arguments of the `command` built-in
pub fn parse(env: &Env, args: Vec<Field>) -> Result<Command, Error> {
let (options, operands) = parse_arguments(OPTION_SPECS, Mode::with_env(env), args)?;
interpret(options, operands)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
10 changes: 10 additions & 0 deletions yash-builtin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub mod shift;
#[cfg(feature = "yash-semantics")]
pub mod source;
pub mod trap;
#[cfg(feature = "yash-semantics")]
pub mod r#type;
pub mod typeset;
pub mod unalias;
pub mod unset;
Expand Down Expand Up @@ -270,6 +272,14 @@ pub const BUILTINS: &[(&str, Builtin)] = &[
execute: |env, args| Box::pin(trap::main(env, args)),
},
),
#[cfg(feature = "yash-semantics")]
(
"type",
Builtin {
r#type: Mandatory,
execute: |env, args| Box::pin(r#type::main(env, args)),
},
),
(
"typeset",
Builtin {
Expand Down
104 changes: 104 additions & 0 deletions yash-builtin/src/type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// This file is part of yash, an extended POSIX shell.
// Copyright (C) 2024 WATANABE Yuki
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Type built-in
//!
//! The **`type`** built-in identifies the type of commands.
//!
//! # Synopsis
//!
//! ```sh
//! type [name…]
//! ```
//!
//! # Description
//!
//! The `type` built-in prints the description of the specified command names.
//!
//! # Options
//!
//! (TODO: Non-standard options are not supported yet.)
//!
//! # Operands
//!
//! The ***name*** operands specify the command names to identify.
//!
//! # Standard output
//!
//! The command descriptions are printed to the standard output.
//!
//! # Errors
//!
//! It is an error if the *name* is not found.
//!
//! # Exit status
//!
//! The exit status is zero if all the *name*s are found, and non-zero
//! otherwise.
//!
//! # Portability
//!
//! POSIX requires that the *name* operand be specified, but many
//! implementations allow it to be omitted, in which case the built-in does
//! nothing.
//!
//! The format of the output is unspecified by POSIX. In this implementation,
//! the `type` built-in is equivalent to the [`command`] built-in with the `-V`
//! option.
//!
//! [`command`]: crate::command
use crate::command::syntax::interpret;
use crate::command::Command;
use crate::common::report_error;
use crate::common::syntax::parse_arguments;
use crate::common::syntax::Mode;
use crate::common::syntax::OptionOccurrence;
use crate::common::syntax::OptionSpec;
use yash_env::semantics::Field;
use yash_env::Env;
use yash_syntax::source::Location;

const OPTION_SPECS: &[OptionSpec] = &[
// TODO: Non-standard options
];

fn parse(env: &mut Env, args: Vec<Field>) -> Result<Command, crate::command::syntax::Error> {
let (mut options, operands) = parse_arguments(OPTION_SPECS, Mode::with_env(env), args)?;

// `type` is equivalent to `command -V`, so add the `-V` option and delegate
// to the `command` built-in.
let spec = OptionSpec::new().short('V').long("verbose-identify");
let location = env.stack.current_builtin().map_or_else(
|| Location::dummy(""),
|builtin| builtin.name.origin.clone(),
);
options.push(OptionOccurrence {
spec: &spec,
location,
argument: None,
});

interpret(options, operands)
}

/// Entry point of the `type` built-in
pub async fn main(env: &mut Env, args: Vec<Field>) -> crate::Result {
match parse(env, args) {
Ok(command) => command.execute(env).await,
Err(error) => report_error(env, &error).await,
}
}

0 comments on commit 5d57650

Please sign in to comment.