summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commandline.lalrpop66
-rw-r--r--src/error.rs42
-rw-r--r--src/main.rs106
-rw-r--r--src/path.rs319
-rw-r--r--src/path/error.rs79
-rw-r--r--src/path/parser.lalrpop92
-rw-r--r--src/path/prelude.rs5
7 files changed, 2 insertions, 707 deletions
diff --git a/src/commandline.lalrpop b/src/commandline.lalrpop
deleted file mode 100644
index d52e741..0000000
--- a/src/commandline.lalrpop
+++ /dev/null
@@ -1,66 +0,0 @@
-grammar;
-
-pub Invocation: Vec<&'input str> = {
-  <WORD*>,
-};
-
-// Several of the regexps below make use of Unicode character classes. [1] is
-// the official reference to Unicode classes, and [2] is a site that is useful
-// for browsing to get an intuitive idea of what the classes mean.
-//
-// In maintaining these regexps, it's important to understand the structure
-// of Unicode character classes. There are seven top-level categories, each
-// with a single-character name (ie. "Z" for separators). Each top-level
-// category has several subcategories which form an exhaustive partition of it;
-// the subcategories have two-character names (ie. "Zs" for space separators).
-// Every allocated codepoint is in exactly one top-level category and exactly
-// one subcategory.
-//
-// It is important that these regexps exhaustively cover the entirety of
-// Unicode, without omission; otherwise lalrpop's lexer will give InvalidToken
-// errors for unrecognized characters. Overlaps will be less catastrophic, as
-// they'll be resoved by the precedence rules, but for clarity's sake they
-// should be avoided.
-//
-// [1] http://www.unicode.org/reports/tr44/#General_Category_Values
-// [2] https://www.compart.com/en/unicode/category
-//
-match {
-  // Zs is the Unicode class for space separators. This includes the ASCII
-  // space character.
-  //
-  r"\p{Zs}+" => { },
-
-  // Zl is the Unicode class for line separators. Zp is the Unicode class for
-  // paragraph separators. Newline and carriage return are included individually
-  // here, since Unicode classifies them with the control characters rather than
-  // with the space characters.
-  //
-  r"[\p{Zl}\p{Zp}\n\r]" => NEWLINE,
-
-  // This one recognizes exactly one character, the old-school double-quote. As
-  // tempting as it is to do something clever with character classes, shells have
-  // a long history of quoting syntaxes which are subtle and quick to anger, and
-  // for this project the decision is to be radically simple instead.
-  r#"["]"# => QUOTE,
-
-  // This one matches any control character other than line feed and carriage
-  // return. The grammar doesn't reference control characters, but having a
-  // token for them makes the error messages more informative.
-  r"[\p{C}&&[^\n\r]]" => CONTROL,
-
-  // Z is the unicode class for separators, which is exhaustively partitioned
-  // into line, paragraph, and space separators. Each of those subclasses is
-  // handled above. C is the class for control characters. This regexp tests
-  // for the intersection of the negation of these character classes, along
-  // with a negated class enumerating all the explicitly-recognized characters,
-  // which means it matches any character NOT in the regexps above.
-  //
-  // Note that, counterintuitively, line feed and carriage return are classified
-  // as control characters, not as line separators. Either way, this regexp would
-  // still exclude them, but the difference might be relevant when maintaining
-  // it.
-  //
-  r#"[\P{Z}&&\P{C}&&[^"]]+"# => WORD,
-}
-
diff --git a/src/error.rs b/src/error.rs
index 1d291ed..426ebf5 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,21 +1,11 @@
 #![forbid(unsafe_code)]
 
-use crate::path::GenericPath;
-use crate::path::error::{FileNameError, DirectoryNameError, PathError};
 use crate::terminal::error::TerminalError;
 
 
-type ParseError<'a> =
-  lalrpop_util::ParseError<usize, lalrpop_util::lexer::Token<'a>, &'a str>;
-
 #[derive(Debug)]
 pub enum Error {
   IO(std::io::Error),
-  Parse(String),
-  FileName(FileNameError),
-  DirectoryName(DirectoryNameError),
-  Path(PathError),
-  PathEmpiricallyFile(GenericPath),
   Terminal(TerminalError),
 }
 
@@ -25,14 +15,6 @@ impl std::fmt::Display for Error {
   fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     match self {
       Error::IO(e) => e.fmt(f),
-      Error::Parse(e) => e.fmt(f),
-      Error::FileName(e) => e.fmt(f),
-      Error::DirectoryName(e) => e.fmt(f),
-      Error::Path(e) => e.fmt(f),
-      Error::PathEmpiricallyFile(path) =>
-        f.write_fmt(format_args!(
-            "There's a file at {}, not a directory.",
-            path)),
       Error::Terminal(e) => e.fmt(f),
     }
   }
@@ -50,30 +32,6 @@ impl From<std::io::Error> for Error {
   }
 }
 
-impl From<ParseError<'_>> for Error {
-  fn from(e: ParseError<'_>) -> Error {
-    Error::Parse(format!("{}", e))
-  }
-}
-
-impl From<FileNameError> for Error {
-  fn from(e: FileNameError) -> Error {
-    Error::FileName(e)
-  }
-}
-
-impl From<DirectoryNameError> for Error {
-  fn from(e: DirectoryNameError) -> Error {
-    Error::DirectoryName(e)
-  }
-}
-
-impl From<PathError> for Error {
-  fn from(e: PathError) -> Error {
-    Error::Path(e)
-  }
-}
-
 impl From<TerminalError> for Error {
   fn from(e: TerminalError) -> Error {
     Error::Terminal(e)
diff --git a/src/main.rs b/src/main.rs
index e94ce0c..9d8ed49 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,18 +2,10 @@
 use crate::result::Result;
 use crate::terminal::{Input, Terminal};
 
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::env;
-use std::os::unix::fs::PermissionsExt;
-use std::process::{self, Command};
+use std::process;
 use tokio::io::{self, AsyncWriteExt};
 
-#[macro_use] extern crate lalrpop_util;
-
-lalrpop_mod!(pub commandline);
 pub mod error;
-pub mod path;
 pub mod result;
 pub mod terminal;
 
@@ -67,101 +59,7 @@ async fn prompt() -> Result<()> {
 }
 
 
-async fn execute(input: &str) -> Result<()> {
-  let invocation = commandline::InvocationParser::new().parse(input)?;
-
-  match invocation.as_slice() {
-    ["environment", ..] => {
-      let environment = read_environment()?;
-      println!("{:?}", environment);
-    }
-    ["which", command_name, ..] => {
-      match find_executable_path(command_name)? {
-        Some(executable_path) => {
-          println!("{}", executable_path);
-        }
-        None => {
-          println!("Command not found: {}", command_name);
-        }
-      };
-    },
-    [command_name, ..] => {
-      match find_executable_path(command_name)? {
-        Some(executable_path) => {
-          let mut command = Command::new(executable_path.to_sys_path());
-
-          let arguments = &invocation[1..];
-          command.args(arguments);
-
-          let _status = command.status()?;
-        }
-        None => {
-          println!("Command not found: {}", command_name);
-        }
-      };
-    },
-    _ => {
-      println!("invocation '{:?}'", invocation);
-    }
-  }
-
+async fn execute(_input: &str) -> Result<()> {
   Ok(())
 }
 
-
-fn read_environment() -> Result<HashMap<String,String>> {
-  Ok(env::vars().collect())
-}
-
-
-fn get_environment(variable_name: &str) -> Result<Option<String>> {
-  Ok(env::vars()
-     .find(|(key, _)| key == variable_name)
-     .map(|(_, value)| value))
-}
-
-
-fn get_search_paths() -> Result<Vec<path::AbsoluteDirectoryPath>> {
-  let paths = get_environment("PATH")?.unwrap_or_default();
-  let paths = path::parse_path_list(&paths)?;
-
-  let mut result = Vec::new();
-  let mut seen = HashSet::new();
-  for path in paths {
-    if seen.contains(&path) {
-      continue;
-    }
-
-    seen.insert(path.clone());
-    result.push(path);
-  }
-
-  Ok(result)
-}
-
-
-fn find_executable_path(command_name: &str)
-  -> Result<Option<path::AbsoluteFilePath>>
-{
-  let file_name: path::FileName = command_name.parse()?;
-  let search_paths = get_search_paths()?;
-
-  let mut executable_path: Option<path::AbsoluteFilePath> = None;
-  for search_path in &search_paths {
-    let candidate_path = search_path.concat_file_name(&file_name);
-    match candidate_path.to_sys_path().metadata() {
-      Ok(metadata) => {
-        if metadata.is_file()
-          && metadata.permissions().mode() & 0o111 != 0
-        {
-          executable_path = Some(candidate_path);
-          break;
-        }
-      },
-      Err(_) => { },
-    }
-  }
-
-  Ok(executable_path)
-}
-
diff --git a/src/path.rs b/src/path.rs
deleted file mode 100644
index 7df10b2..0000000
--- a/src/path.rs
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- *   We implement most aspects of paths independently, not relying on
- * std::path, on the theory that path syntax is such an important part of a
- * shell that it doesn't make sense to try to integrate with non-Unix syntaxes.
- * However, we do use std::path to print individual path components, in order
- * to get the benefit of its functionality for handling non-Unicode filenames.
- */
-
-#![forbid(unsafe_code)]
-use crate::path::prelude::*;
-
-use std::str::FromStr;
-
-
-lalrpop_mod!(pub parser, "/path/parser.rs");
-pub mod error;
-pub mod prelude;
-
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub struct AbsoluteDirectoryPath {
-  directory_names: Vec<DirectoryName>,
-}
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub struct AbsoluteFilePath {
-  directory_names: Vec<DirectoryName>,
-  file_name: FileName,
-}
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub struct FileName(String);
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub struct DirectoryName(String);
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub struct GenericPath {
-  components: Vec<GenericPathComponent>,
-  starts_with_slash: bool,
-  ends_with_slash: bool,
-}
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub enum GenericPathComponent {
-  FileOrDirectoryName(String),
-  CurrentDirectory,
-  ParentDirectory,
-}
-
-
-impl std::fmt::Display for AbsoluteDirectoryPath {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    for directory_name in &self.directory_names {
-      f.write_str("/")?;
-      directory_name.fmt(f)?;
-    }
-
-    f.write_str("/")?;
-
-    Ok(())
-  }
-}
-
-
-impl std::fmt::Display for AbsoluteFilePath {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    for directory_name in &self.directory_names {
-      f.write_str("/")?;
-      directory_name.fmt(f)?;
-    }
-
-    f.write_str("/")?;
-
-    self.file_name.fmt(f)?;
-
-    Ok(())
-  }
-}
-
-
-impl std::fmt::Display for FileName {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    match self {
-      FileName(name) => {
-        let std_path = std::path::Path::new(&name);
-        f.write_fmt(format_args!("{}", std_path.display()))?;
-      },
-    }
-
-    Ok(())
-  }
-}
-
-
-impl std::fmt::Display for DirectoryName {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    match self {
-      DirectoryName(name) => {
-        let std_path = std::path::Path::new(&name);
-        f.write_fmt(format_args!("{}", std_path.display()))?;
-      },
-    }
-
-    Ok(())
-  }
-}
-
-
-impl std::fmt::Display for GenericPath {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    if self.starts_with_slash {
-      f.write_str("/")?;
-    }
-
-    let mut is_first = true;
-    for component in &self.components {
-      if !is_first {
-        f.write_str("/")?;
-      }
-
-      component.fmt(f)?;
-
-      is_first = false;
-    }
-
-    if self.ends_with_slash {
-      f.write_str("/")?;
-    }
-
-    Ok(())
-  }
-}
-
-
-impl std::fmt::Display for GenericPathComponent {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    match self {
-      GenericPathComponent::FileOrDirectoryName(name) => {
-        let std_path = std::path::Path::new(&name);
-        f.write_fmt(format_args!("{}", std_path.display()))?;
-      },
-      GenericPathComponent::CurrentDirectory => {
-        f.write_str(".")?;
-      },
-      GenericPathComponent::ParentDirectory => {
-        f.write_str("..")?;
-      },
-    }
-
-    Ok(())
-  }
-}
-
-
-impl FromStr for FileName {
-  type Err = FileNameError;
-
-  fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
-    if input.find('/').is_some() {
-      Err(FileNameError::ContainsSlash(input.to_string()))
-    } else {
-      Ok(FileName(input.to_string()))
-    }
-  }
-}
-
-
-impl FromStr for DirectoryName {
-  type Err = DirectoryNameError;
-
-  fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
-    if input.find('/').is_some() {
-      Err(DirectoryNameError::ContainsSlash(input.to_string()))
-    } else {
-      Ok(DirectoryName(input.to_string()))
-    }
-  }
-}
-
-
-impl FromStr for GenericPathComponent {
-  type Err = PathError;
-
-  fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
-    parser::PathComponentParser::new().parse(input).map_err(
-        |e| PathError::Parse(e.to_string()))
-  }
-}
-
-
-impl AbsoluteDirectoryPath {
-  pub fn to_sys_path(&self) -> std::path::PathBuf {
-    let mut result = std::path::PathBuf::new();
-    result.push(format!("{}", self));
-    result
-  }
-
-  pub fn concat_file_name(&self, file_name: &FileName) -> AbsoluteFilePath {
-    AbsoluteFilePath {
-      directory_names: self.directory_names.clone(),
-      file_name: file_name.clone(),
-    }
-  }
-}
-
-
-impl AbsoluteFilePath {
-  pub fn to_sys_path(&self) -> std::path::PathBuf {
-    let mut result = std::path::PathBuf::new();
-    result.push(format!("{}", self));
-    result
-  }
-}
-
-
-pub fn parse_path_list(path_list: &str)
-  -> Result<Vec<AbsoluteDirectoryPath>>
-{
-  match parser::PathListParser::new().parse(path_list) {
-    Ok(parsed_paths) => {
-      let mut result = Vec::new();
-      for generic_path in parsed_paths {
-        let path = absolute_directory_path(generic_path)?;
-        result.push(path);
-      }
-      Ok(result)
-    },
-   Err(original_error) => {
-      match parser::PathListAllowingEmptyPathsParser::new()
-        .parse(path_list)
-      {
-        Ok(_) => {
-          Err(PathError::PathListHasEmptyComponents(path_list.to_string()))
-        },
-        Err(_) => {
-          Err(PathError::Parse(original_error.to_string()))
-        },
-      }
-    },
-  }
-}
-
-
-pub fn absolute_directory_path(generic_path: GenericPath)
-  -> Result<AbsoluteDirectoryPath>
-{
-  if !generic_path.starts_with_slash {
-    return Err(PathError::PathLexicallyRelative(generic_path));
-  }
-
-  let mut flattened_components = Vec::new();
-  for component in &generic_path.components {
-    match component {
-      GenericPathComponent::CurrentDirectory => { },
-      GenericPathComponent::ParentDirectory => {
-        if flattened_components.len() > 0 {
-          flattened_components.pop();
-        } else {
-          return Err(PathError::PathLexicallyInvalid(generic_path));
-        }
-      },
-      GenericPathComponent::FileOrDirectoryName(name) => {
-        flattened_components.push(DirectoryName(name.to_string()));
-      },
-    }
-  }
-
-  Ok(AbsoluteDirectoryPath {
-    directory_names: flattened_components,
-  })
-}
-
-
-pub fn absolute_file_path(generic_path: GenericPath)
-  -> Result<AbsoluteFilePath>
-{
-  if !generic_path.starts_with_slash {
-    return Err(PathError::PathLexicallyRelative(generic_path));
-  }
-
-  if generic_path.ends_with_slash {
-    return Err(PathError::PathLexicallyDirectory(generic_path));
-  }
-
-  let mut iterator = generic_path.components.iter();
-
-  let file_name = match iterator.next_back() {
-    Some(GenericPathComponent::FileOrDirectoryName(name)) => {
-      FileName(name.to_string())
-    }
-    _ => {
-      return Err(PathError::PathLexicallyInvalid(generic_path));
-    }
-  };
-
-  let mut flattened_components = Vec::new();
-  for component in &generic_path.components {
-    match component {
-      GenericPathComponent::CurrentDirectory => { },
-      GenericPathComponent::ParentDirectory => {
-        if flattened_components.len() > 0 {
-          flattened_components.pop();
-        } else {
-          return Err(PathError::PathLexicallyInvalid(generic_path));
-        }
-      },
-      GenericPathComponent::FileOrDirectoryName(name) => {
-        flattened_components.push(DirectoryName(name.to_string()));
-      },
-    }
-  }
-
-  Ok(AbsoluteFilePath {
-    directory_names: flattened_components,
-    file_name: file_name,
-  })
-}
-
diff --git a/src/path/error.rs b/src/path/error.rs
deleted file mode 100644
index aee6e9f..0000000
--- a/src/path/error.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-#![forbid(unsafe_code)]
-
-use crate::path::GenericPath;
-
-pub type Result<T> = std::result::Result<T, PathError>;
-
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub enum FileNameError {
-  ContainsSlash(String),
-}
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub enum DirectoryNameError {
-  ContainsSlash(String),
-}
-
-#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)]
-pub enum PathError {
-  Parse(String),
-  PathLexicallyDirectory(GenericPath),
-  PathLexicallyRelative(GenericPath),
-  PathLexicallyInvalid(GenericPath),
-  PathListHasEmptyComponents(String),
-}
-
-
-impl std::error::Error for FileNameError { }
-
-impl std::error::Error for DirectoryNameError { }
-
-impl std::error::Error for PathError { }
-
-impl std::fmt::Display for FileNameError {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    match self {
-      FileNameError::ContainsSlash(s) =>
-        f.write_fmt(format_args!(
-            "File names cannot contain slashes, but {:?} does.", s)),
-    }
-  }
-}
-
-impl std::fmt::Display for DirectoryNameError {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    match self {
-      DirectoryNameError::ContainsSlash(s) =>
-        f.write_fmt(format_args!(
-            "File names cannot contain slashes, but {:?} does.", s)),
-    }
-  }
-}
-
-impl std::fmt::Display for PathError {
-  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-    match self {
-      PathError::Parse(s) =>
-        f.write_fmt(format_args!("Syntax error in path: {}", s)),
-      PathError::PathLexicallyDirectory(path) =>
-        f.write_fmt(format_args!(
-            "The path {} ends in a slash, but is supposed to refer to a file, \
-             not a directory.",
-            path)),
-      PathError::PathLexicallyRelative(path) =>
-        f.write_fmt(format_args!(
-            "The path {} is relative, not absolute.",
-            path)),
-      PathError::PathLexicallyInvalid(path) =>
-        f.write_fmt(format_args!(
-            "This isn't a valid path. {}",
-            path)),
-      PathError::PathListHasEmptyComponents(path_list) =>
-        f.write_fmt(format_args!(
-            "Path list has empty components: {}",
-            path_list)),
-    }
-  }
-}
-
diff --git a/src/path/parser.lalrpop b/src/path/parser.lalrpop
deleted file mode 100644
index c41b3fd..0000000
--- a/src/path/parser.lalrpop
+++ /dev/null
@@ -1,92 +0,0 @@
-grammar;
-
-use crate::path::GenericPath;
-use crate::path::GenericPathComponent;
-
-pub PathList: Vec<GenericPath> = {
-  => {
-    Vec::new()
-  },
-  <mut left:(<PathNoColons> COLON)*> <right:PathNoColons> => {
-    left.push(right);
-    left
-  },
-};
-
-pub PathListAllowingEmptyPaths: Vec<GenericPath> = {
-  => vec![GenericPath {
-    components: Vec::new(),
-    starts_with_slash: false,
-    ends_with_slash: false,
-  }],
-  PathNoColons => vec![<>],
-  <mut left:PathListAllowingEmptyPaths> COLON => {
-    left.push(GenericPath {
-      components: Vec::new(),
-      starts_with_slash: false,
-      ends_with_slash: false,
-    });
-    left
-  },
-  <mut left:PathListAllowingEmptyPaths> COLON <right:PathNoColons> => {
-    left.push(right);
-    left
-  },
-}
-
-pub PathNoColons: GenericPath = {
-  SLASH => GenericPath {
-    components: Vec::new(),
-    starts_with_slash: true,
-    ends_with_slash: true,
-  },
-  <PathNoColons2> => GenericPath {
-    components: <>,
-    starts_with_slash: false,
-    ends_with_slash: false,
-  },
-  <PathNoColons2> SLASH => GenericPath {
-    components: <>,
-    starts_with_slash: false,
-    ends_with_slash: true,
-  },
-  SLASH <PathNoColons2> => GenericPath {
-    components: <>,
-    starts_with_slash: true,
-    ends_with_slash: false,
-  },
-  SLASH <PathNoColons2> SLASH => GenericPath {
-    components: <>,
-    starts_with_slash: true,
-    ends_with_slash: true,
-  },
-}
-
-PathNoColons2: Vec<GenericPathComponent> = {
-  <PathComponent> => vec![<>],
-  <mut left:PathNoColons2> SLASH <right:PathComponent> => {
-    left.push(right);
-    left
-  }
-}
-
-pub PathComponent: GenericPathComponent = {
-  DOT => GenericPathComponent::CurrentDirectory,
-  DOT_DOT => GenericPathComponent::ParentDirectory,
-  <PATH_COMPONENT_NO_COLONS> =>
-    GenericPathComponent::FileOrDirectoryName(<>.to_string())
-}
-
-// Whitespace is not allowed.
-match {
-  r"[^:/]+" => PATH_COMPONENT_NO_COLONS,
-
-  r"/" => SLASH,
-
-  ":" => COLON,
-
-  "." => DOT,
-
-  ".." => DOT_DOT,
-}
-
diff --git a/src/path/prelude.rs b/src/path/prelude.rs
deleted file mode 100644
index f7b23dd..0000000
--- a/src/path/prelude.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![forbid(unsafe_code)]
-
-pub use crate::path::error::{
-    Result, DirectoryNameError, FileNameError, PathError};
-