start lexin
parent
0a0dfc2ee9
commit
d79a28b3b0
@ -1,5 +1,66 @@
|
|||||||
mod tail;
|
|
||||||
mod command;
|
mod command;
|
||||||
|
mod tail;
|
||||||
|
mod which;
|
||||||
|
mod printenv;
|
||||||
|
mod echo;
|
||||||
|
|
||||||
pub use tail::Tail;
|
|
||||||
pub use command::Command;
|
pub use command::Command;
|
||||||
|
pub use echo::Echo;
|
||||||
|
pub use tail::Tail;
|
||||||
|
pub use which::Which;
|
||||||
|
pub use printenv::Printenv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Posix Shell builtins:
|
||||||
|
|
||||||
|
alias bg cd command false fc fg getopts hash jobs kill
|
||||||
|
newgrp pwd read true type ulimit umask unalias wait
|
||||||
|
|
||||||
|
Bourne Shell builtins:
|
||||||
|
|
||||||
|
: - do nothing except expand arguments and perform redirections
|
||||||
|
. - read and execute a file in the current shell context
|
||||||
|
break - exit from a loop
|
||||||
|
cd - change the current working directory to directory
|
||||||
|
continue - resume the next iteration of a loop
|
||||||
|
eval - evaluate the arguments as a single command
|
||||||
|
exec - replace the shell without creating a new process
|
||||||
|
exit - exits the process with a status
|
||||||
|
export - exports environment variables
|
||||||
|
getopts - used by shell scripts to parse arguments
|
||||||
|
hash - displays the hash table used by the shell to map command names to files
|
||||||
|
pwd - prints the absolute path of the current directory
|
||||||
|
readonly - mark each name as readonly so that they cannot be reassigned
|
||||||
|
return - causes a shell function to stop execution and return a value
|
||||||
|
shift - shifts the position parameters to the left by n
|
||||||
|
test - evaluate a conditional expression and return a status of 0 or 1
|
||||||
|
times - print out the user and system times used by the shell and its children. sorry, what the fuck is this
|
||||||
|
trap - execute commands when a given signal is received
|
||||||
|
umask - set the shell process's file creation mask
|
||||||
|
unset - clears variable or function names
|
||||||
|
|
||||||
|
Bash Builtins:
|
||||||
|
|
||||||
|
alias - creates an alias for a command
|
||||||
|
bind - adds key bindings
|
||||||
|
builtin - access a builtin function even if it has been masked by another function
|
||||||
|
caller - tells you what line number you're executing?
|
||||||
|
command - runs a command with a given name, ignoring shell functions
|
||||||
|
declare - declare variables and give them attributes
|
||||||
|
echo - echos the outputs
|
||||||
|
enable - enable and disable builtin shell commands
|
||||||
|
help - display help text about builtin commands
|
||||||
|
let - perform arithmetic on shell variables
|
||||||
|
local - create local variables
|
||||||
|
logout - exits a login shell with a status
|
||||||
|
mapfile - read lines from stdin or a file into an array
|
||||||
|
printf - formats arguments using a format string
|
||||||
|
read - reads one line from stdin or from a file
|
||||||
|
readarray - read lines from stdin into an array or something
|
||||||
|
source - executes the script in the current shell
|
||||||
|
type - tells you if a thing is an alias, function, builtin, or file command
|
||||||
|
typeset - synonym for declare, included for korn shell compatibility
|
||||||
|
ulimit - provides control over the resources available to the processes started by the shell
|
||||||
|
unalias - clears an alias
|
||||||
|
|
||||||
|
*/
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
pub trait Command {
|
pub trait Command {
|
||||||
fn name() -> String;
|
fn name() -> String;
|
||||||
|
|
||||||
fn create() -> Self;
|
fn create() -> Self;
|
||||||
|
fn exec(&mut self, args: Vec<&str>) -> Result<bool>;
|
||||||
fn exec(&mut self, args: Vec<&str>) -> anyhow::Result<bool>;
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
use crate::ext::Command;
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub struct Echo {}
|
||||||
|
|
||||||
|
impl Command for Echo {
|
||||||
|
fn name() -> String {
|
||||||
|
String::from("echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec(&mut self, args: Vec<&str>) -> Result<bool> {
|
||||||
|
println!("{}", args.join(" "));
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
use crate::ext::Command;
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub struct Printenv {}
|
||||||
|
|
||||||
|
impl Command for Printenv {
|
||||||
|
fn name() -> String {
|
||||||
|
String::from("printenv")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec(&mut self, args: Vec<&str>) -> Result<bool> {
|
||||||
|
if args.len() > 0 {
|
||||||
|
let name = args[0];
|
||||||
|
match std::env::var(name) {
|
||||||
|
Ok(val) => {
|
||||||
|
println!("{}", val);
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("ERROR {}", e);
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("which variable you fucking dork");
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
use crate::ext::Command;
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub struct Which {}
|
||||||
|
|
||||||
|
impl Command for Which {
|
||||||
|
fn name() -> String {
|
||||||
|
String::from("which")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec(&mut self, args: Vec<&str>) -> Result<bool> {
|
||||||
|
if args.len() > 0 {
|
||||||
|
let path = std::env::var("path").unwrap();
|
||||||
|
let dirs: Vec<&str> = path.split(";").collect();
|
||||||
|
for d in dirs {
|
||||||
|
let dir = std::path::Path::new(d);
|
||||||
|
let fname = dir.join(args[0]).with_extension("exe");
|
||||||
|
if fname.exists() && fname.is_file() {
|
||||||
|
println!("{}", fname.to_str().unwrap());
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("not found: {}", args[0]);
|
||||||
|
Ok(false)
|
||||||
|
} else {
|
||||||
|
println!("what do you want to look for?");
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Token {
|
||||||
|
Ident(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn lex<S: AsRef<str>>(text: S) -> Result<Vec<Token>, Error> {
|
||||||
|
Lexer::new(text.as_ref()).lex()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Lexer<'text> {
|
||||||
|
chars: std::str::Chars<'text>,
|
||||||
|
peeked: Option<char>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'text> Lexer<'text> {
|
||||||
|
fn new(text: &'text str) -> Self {
|
||||||
|
Self {
|
||||||
|
chars: text.chars(),
|
||||||
|
peeked: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lex(&mut self) -> Result<Vec<Token>, Error> {
|
||||||
|
let mut tokens = vec![];
|
||||||
|
while self.peek().is_some() {
|
||||||
|
self.skip_whitespace();
|
||||||
|
match self.peek() {
|
||||||
|
None => { return Ok(tokens) },
|
||||||
|
Some(_) => {
|
||||||
|
tokens.push(self.ident());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(tokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_whitespace(&mut self) {
|
||||||
|
loop {
|
||||||
|
match self.peek() {
|
||||||
|
None => break,
|
||||||
|
Some(c) => {
|
||||||
|
if c.is_whitespace() {
|
||||||
|
self.skip()
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&mut self) -> Option<char> {
|
||||||
|
match self.peeked {
|
||||||
|
Some(c) => Some(c),
|
||||||
|
None => match self.chars.next() {
|
||||||
|
Some(c) => {
|
||||||
|
self.peeked = Some(c);
|
||||||
|
Some(c)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip(&mut self) {
|
||||||
|
if self.peeked.is_some() {
|
||||||
|
self.peeked = None;
|
||||||
|
} else {
|
||||||
|
self.chars.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ident(&mut self) -> Token {
|
||||||
|
let mut kept: Vec<char> = vec!();
|
||||||
|
loop {
|
||||||
|
match self.peek() {
|
||||||
|
None => break,
|
||||||
|
Some(c) => {
|
||||||
|
if c.is_whitespace() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kept.push(c);
|
||||||
|
self.skip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Token::Ident(kept.iter().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn parse(line: String) -> Result<Tree, Error> {
|
||||||
|
// Ok(Tree::new())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub struct Tree {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl Tree {
|
||||||
|
// pub fn new() -> Self { Self { } }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lex_empty() -> Result<(), Error> {
|
||||||
|
let tokens = lex("")?;
|
||||||
|
assert_eq!(tokens.len(), 0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lex_ident() -> Result<(), Error> {
|
||||||
|
let tokens = lex("one")?;
|
||||||
|
assert_eq!(tokens.len(), 1);
|
||||||
|
assert_eq!(tokens[0], Token::Ident(String::from("one")));
|
||||||
|
|
||||||
|
let tokens = lex("one two")?;
|
||||||
|
assert_eq!(tokens.len(), 2);
|
||||||
|
assert_eq!(tokens[0], Token::Ident(String::from("one")));
|
||||||
|
assert_eq!(tokens[1], Token::Ident(String::from("two")));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue