start lexin

parse-tree
Jordan Orelli 1 year ago
parent 0a0dfc2ee9
commit d79a28b3b0

@ -10,6 +10,7 @@ fn next_pair<I: Iterator<Item=TokenTree>>(tokens: &mut I) -> Option<(TokenTree,
}
}
#[allow(dead_code)]
struct Escape {
sequence: String,
name: String,

@ -1,5 +1,66 @@
mod tail;
mod command;
mod tail;
mod which;
mod printenv;
mod echo;
pub use tail::Tail;
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 {
fn name() -> String;
fn create() -> Self;
fn exec(&mut self, args: Vec<&str>) -> anyhow::Result<bool>;
fn exec(&mut self, args: Vec<&str>) -> 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)
}
}
}

@ -5,6 +5,7 @@ mod key;
mod line;
mod log;
mod output;
mod parse;
mod prompt;
mod shell;
@ -60,6 +61,7 @@ fn main() -> Result<()> {
shell.output.newline()?;
let s = shell.line.pop();
let parts: Vec<&str> = s.split_whitespace().collect();
if parts.len() > 0 {
let cmd = parts[0].to_string();
let args = if parts.len() > 1 {

@ -102,21 +102,13 @@ impl Writer {
pub fn stdout() -> Result<Self> {
unsafe {
let handle = Console::GetStdHandle(Console::STD_OUTPUT_HANDLE)
.context("unable to get stdin handle")?;
.context("unable to get stdout handle")?;
let mut stdout = Self{output: handle};
stdout.reset()?;
Ok(stdout)
}
}
// pub fn new() -> Result<Self> {
// let mut v = Self {
// output: stdout_handle()?,
// };
// v.reset()?;
// Ok(v)
// }
pub fn close(&mut self) -> Result<()> {
unsafe {
CloseHandle(self.output);
@ -128,15 +120,6 @@ impl Writer {
unsafe {
Console::SetConsoleOutputCP(65001);
}
// let mut mode = Console::CONSOLE_MODE(0);
// unsafe {
// if Console::GetConsoleMode(self.output, &mut mode).as_bool() {
// // debug!("Stdout details:");
// // log_output_mode(mode);
// } else {
// return Err(Error::last_error().into());
// }
// }
Ok(())
}
@ -164,10 +147,10 @@ impl Writer {
Ok(())
}
pub fn hide_cursor(&mut self) -> Result<()> {
self.write(b"\x1b[?25l")?;
Ok(())
}
// pub fn hide_cursor(&mut self) -> Result<()> {
// self.write(b"\x1b[?25l")?;
// Ok(())
// }
}
impl Write for Writer {

@ -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(())
}
}

@ -1,11 +1,14 @@
use crate::{input, line::Line, log::*, output, ext::{Command, Tail}};
use std::{
fs::File,
io::{Read, Seek, SeekFrom, Write},
path::{Path, PathBuf},
use crate::{
ext::{Command, Echo, Printenv, Tail, Which},
input,
line::Line,
log::*,
output,
// parse::parse,
};
use std::path::{Path, PathBuf};
use anyhow::Result;
use dirs;
@ -108,48 +111,10 @@ impl Shell {
}
return Ok(true);
}
"printenv" => {
if args.len() > 0 {
let name = args[0];
match std::env::var(name) {
Ok(val) => {
println!("{}", val);
return Ok(true);
}
Err(e) => {
println!("ERROR {}", e);
return Ok(false);
}
}
} else {
println!("which variable you fucking dork");
return Ok(false);
}
}
"which" => {
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]);
return Ok(false);
} else {
println!("what do you want to look for?");
return Ok(false);
}
}
"printenv" => Printenv::create().exec(args),
"which" => Which::create().exec(args),
"tail" => Tail::create().exec(args),
"echo" => {
println!("{}", args.join(" "));
return Ok(true);
}
"echo" => Echo::create().exec(args),
_ => {
let mut proc = std::process::Command::new(cmd);
if args.len() > 0 {
@ -171,4 +136,10 @@ impl Shell {
}
}
}
// pub fn parse(&mut self) -> (String, Vec<&str>) {
// let buf = self.line.show();
// let tree = parse(buf);
// (String::new(), vec!())
// }
}

Loading…
Cancel
Save