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