diff --git a/crates/oyster_builtin_proc/src/lib.rs b/crates/oyster_builtin_proc/src/lib.rs index cb0de7d..1fb75f2 100644 --- a/crates/oyster_builtin_proc/src/lib.rs +++ b/crates/oyster_builtin_proc/src/lib.rs @@ -1,4 +1,6 @@ +//! Contains the proc macro used to define builtins. #![deny(unreachable_pub)] +#![warn(missing_docs)] use darling::FromMeta; use proc_macro::TokenStream; @@ -16,6 +18,20 @@ struct AttrArgs { nofork: bool, } +/// Define a built in with the given description and name. +/// +/// ```rust +/// use oyster_builtin_proc::builtin; +/// +/// #[builtin( +/// name = "greet", // optionally override name +/// description = "greets the user", +/// nofork = true, // optionally don't fork, required for cd and similar +/// )] +/// fn hello(_shell: &mut Shell, _args: &[Cow]) { +/// println!("Hello world!"); +/// } +/// ``` #[proc_macro_attribute] pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream { let attrs = parse_macro_input!(attr as AttributeArgs); @@ -49,7 +65,7 @@ pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream { }; TokenStream::from(quote! { - #[allow(non_upper_case_globals)] + #[allow(non_upper_case_globals, missing_docs)] #vis static #ident: #builtin = { #fn_token #ident(#inputs) #block diff --git a/crates/oyster_lineedit/src/lib.rs b/crates/oyster_lineedit/src/lib.rs index 854c159..f403a07 100644 --- a/crates/oyster_lineedit/src/lib.rs +++ b/crates/oyster_lineedit/src/lib.rs @@ -1,7 +1,10 @@ +//! Readline implementation used in oyster. #![deny(unreachable_pub)] +#![warn(missing_docs)] use std::io::{self, Write}; +/// Read a line from stdin and return it. pub fn readline(prompt: &str) -> Result { print!("{}", prompt); io::stdout().flush()?; diff --git a/crates/oyster_parser/src/ast.rs b/crates/oyster_parser/src/ast.rs index 9dcc0ef..420db8c 100644 --- a/crates/oyster_parser/src/ast.rs +++ b/crates/oyster_parser/src/ast.rs @@ -1,32 +1,46 @@ +//! Defines the abstract syntax tree of a valid program. use crate::{NodeKind, ParseError, ParseEvent, Parser}; -/// Abtract, lossy representation of the syntax. +/// Abtract, lossy representation of the syntax of an entire program. #[derive(Debug)] pub struct Code<'a>(pub Vec>); +/// A statement in a program. #[derive(Debug)] pub enum Statement<'a> { + /// See [Pipeline]. Pipeline(Pipeline<'a>), } +/// A pipeline consisting of multiple commands. #[derive(Debug)] pub struct Pipeline<'a>(pub Vec>); +/// Redirects between commands in a [Pipeline]. #[derive(Debug, Clone, Copy)] pub enum Redirect { + /// No redirect. None, + /// Stdout is getting redirected. Stdout, } +/// A command within a [Pipeline]. #[derive(Debug)] pub struct Command<'a>(pub Vec>, pub Redirect); +/// A word within a [Command]. #[derive(Debug)] pub struct Word<'a>(pub Vec>); +/// Part of a [Word]. +/// This can be anything from different parts of a quoted string, to escaped symbols, or even +/// subcommands. #[derive(Debug)] pub enum WordPart<'a> { + /// Plain text. Text(&'a str), + /// A command substitution that needs to be run first. CommandSubstitution(Code<'a>), } diff --git a/crates/oyster_parser/src/cst.rs b/crates/oyster_parser/src/cst.rs index 1a4cb96..66067f2 100644 --- a/crates/oyster_parser/src/cst.rs +++ b/crates/oyster_parser/src/cst.rs @@ -1,18 +1,30 @@ use crate::{NodeKind, ParseError, ParseEvent, Parser}; /// A concrete, loss-less representation of the parsed program. +/// Only leafs contain actual code. #[derive(Debug)] pub enum ParseTree { + /// A sub-tree in the program. + /// These do not contain data. Tree { + /// What kind of node are we dealing with. kind: NodeKind, + /// The children of this tree. children: Vec, }, + /// A leaf node. + /// This contains all the code snippets. Leaf { + /// What kind of node we are dealing with. kind: NodeKind, + /// The length of the code referred to by this node. len: usize, }, + /// A parse error occured. Error { + /// Which error occured. kind: ParseError, + /// How much code to skip until recovery? len: usize, }, } diff --git a/crates/oyster_parser/src/lexer.rs b/crates/oyster_parser/src/lexer.rs index 36f8154..e9a299b 100644 --- a/crates/oyster_parser/src/lexer.rs +++ b/crates/oyster_parser/src/lexer.rs @@ -34,7 +34,10 @@ pub enum TokenKind { /// The parser is responsible for getting that information, if required. #[derive(Debug)] pub struct Token { + /// The [TokenKind] of the token. pub kind: TokenKind, + /// How long the token is. + /// To actually get the code, you need to keep count yourself. pub len: usize, } diff --git a/crates/oyster_parser/src/lib.rs b/crates/oyster_parser/src/lib.rs index 1d8a525..5af41c7 100644 --- a/crates/oyster_parser/src/lib.rs +++ b/crates/oyster_parser/src/lib.rs @@ -1,4 +1,5 @@ #![deny(unreachable_pub)] +#![warn(missing_docs)] //! Parser for the oyster shell, the grammar is outlined below, `extras` are allowed everywhere, //! *except* inside `word`. diff --git a/crates/oyster_parser/src/parser.rs b/crates/oyster_parser/src/parser.rs index 1abeaef..d9b51dc 100644 --- a/crates/oyster_parser/src/parser.rs +++ b/crates/oyster_parser/src/parser.rs @@ -4,6 +4,7 @@ use crate::{lexer::Lexer, Token, TokenKind}; /// Errors that might occur during parsing. #[derive(Debug, Error)] +#[allow(missing_docs)] pub enum ParseError { #[error("unexpected pipe")] UnexpectedPipe, @@ -16,8 +17,12 @@ pub enum ParseError { } /// Type of the node. +/// For specific information refer to [TokenKind]. #[derive(Debug)] +#[allow(missing_docs)] pub enum NodeKind { + // TokenKinds + Whitespace, Newlines, Semicolon, @@ -29,6 +34,8 @@ pub enum NodeKind { EscapedChar, Comment, + // Nodes in the tree, that appear in the cst. + Program, CommandSubstitution, Pipeline, @@ -36,6 +43,8 @@ pub enum NodeKind { Word, DQuotedString, + // Nodes in the tree, that don't appear in the cst. + /// Read a pipe but didn't start word yet. PipelineCont, } @@ -43,9 +52,14 @@ pub enum NodeKind { /// Events required to build a syntax tree. #[derive(Debug)] pub enum ParseEvent { + /// An error occured. Error(ParseError, usize), + /// Start a new tree node. + /// From now on, all nodes are child notes. StartNode(NodeKind), + /// End the most recently started tree node. EndNode, + /// A new leaf note. NewLeaf(NodeKind, usize), } diff --git a/crates/oyster_runtime/src/builtins/math.rs b/crates/oyster_runtime/src/builtins/math.rs index e33f0c9..c5b3a12 100644 --- a/crates/oyster_runtime/src/builtins/math.rs +++ b/crates/oyster_runtime/src/builtins/math.rs @@ -1,3 +1,4 @@ +//! Standard math builtins. use std::{ borrow::Cow, ffi::OsStr, diff --git a/crates/oyster_runtime/src/builtins/mod.rs b/crates/oyster_runtime/src/builtins/mod.rs index 795c9be..51a6590 100644 --- a/crates/oyster_runtime/src/builtins/mod.rs +++ b/crates/oyster_runtime/src/builtins/mod.rs @@ -1,3 +1,4 @@ +//! Definition of all the builtin builtins, and the general framework managing builtins. pub mod math; use std::{borrow::Cow, collections::HashMap, ffi::OsStr}; @@ -6,11 +7,18 @@ use oyster_builtin_proc::builtin; use crate::Shell; +/// Definition of a builtin. +/// See [oyster_builtin_proc::builtin] for an easier way to generate them. #[derive(Clone, Copy)] pub struct Builtin { + /// Name of the builtin. pub name: &'static str, + /// Description of the builtin, used in `help`. pub description: &'static str, + /// Whether the builtin should fork when executed. + /// Should be false for most builtins. pub nofork: bool, + /// The actual function to call when the builtin runs. pub fun: fn(shell: &mut Shell, args: &[Cow]), } diff --git a/crates/oyster_runtime/src/lib.rs b/crates/oyster_runtime/src/lib.rs index da4ba41..88c82c8 100644 --- a/crates/oyster_runtime/src/lib.rs +++ b/crates/oyster_runtime/src/lib.rs @@ -1,4 +1,7 @@ +//! The runtime of the shell. +//! This contains all the code related to actually running the program. #![deny(unreachable_pub)] +#![warn(missing_docs)] //! The runtime for executing oyster programs. //! Panics when an invalid ast gets passed. @@ -33,14 +36,19 @@ use thiserror::Error; pub struct Status(pub i32); impl Status { + /// The command succeeded. pub const SUCCESS: Status = Status(0); + /// The command failed to execute (most likely permissions). pub const COULD_NOT_EXEC: Status = Status(126); + /// The command could not be found. pub const COMMAND_NOT_FOUND: Status = Status(127); + /// The base whch signals get added onto, i.e. SIGINT (2) results in 130. pub const SIG_BASE: Status = Status(128); } /// Errors that occur during runtime. #[derive(Debug, Error)] +#[allow(missing_docs)] pub enum RuntimeError { #[error("failed to create pipe: {0}")] PipeCreationFailed(#[source] nix::Error), @@ -67,6 +75,7 @@ pub enum RuntimeError { IOError(#[source] io::Error), } +/// The main "app struct", containing all the data related to the current shell instance. pub struct Shell { is_running: bool, builtins: BuiltinMap,