wip parser
This commit is contained in:
parent
73817529d6
commit
7988c8a2e1
5 changed files with 324 additions and 1 deletions
123
src/ast.rs
Normal file
123
src/ast.rs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Command {
|
||||||
|
Simple {
|
||||||
|
assignments: Vec<(String, Word)>,
|
||||||
|
command_word: Word,
|
||||||
|
redirections: Vec<Redirection>
|
||||||
|
},
|
||||||
|
Pipeline(Vec<Command>),
|
||||||
|
Sequence(Vec<Command>),
|
||||||
|
ShortCircuitConjection(Vec<Command>),
|
||||||
|
ShortCircuitDisjunction(Vec<Command>),
|
||||||
|
Negation(Command),
|
||||||
|
While {
|
||||||
|
condition: Command,
|
||||||
|
loop_body: Command
|
||||||
|
},
|
||||||
|
For {
|
||||||
|
varname: String,
|
||||||
|
sequence: Word,
|
||||||
|
loop_body: Command
|
||||||
|
}
|
||||||
|
If {
|
||||||
|
condition: Command,
|
||||||
|
then_branch: Command,
|
||||||
|
else_branch: Command
|
||||||
|
},
|
||||||
|
Case {
|
||||||
|
expr: Word,
|
||||||
|
cases: Vec<(Word, Command)>
|
||||||
|
},
|
||||||
|
Function {
|
||||||
|
name: String,
|
||||||
|
body: Command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are all luminous beings.
|
||||||
|
* Why then, do we not appear before each
|
||||||
|
* other radiant in our illumination ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bewteen the idea
|
||||||
|
* And the reality
|
||||||
|
* Between the motion
|
||||||
|
* And the act
|
||||||
|
* Falls the Shadow
|
||||||
|
* (T.S. Eliot)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Word {
|
||||||
|
pub segments: Vec<WordSegment>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WordSegment {
|
||||||
|
FieldSeparator,
|
||||||
|
Tilde(String),
|
||||||
|
Literal(String),
|
||||||
|
Parameter(String, ParameterFormat),
|
||||||
|
Subshell(Command),
|
||||||
|
DoubleQuote(Word),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParameterFormat {
|
||||||
|
Normal,
|
||||||
|
Length,
|
||||||
|
Default(Word),
|
||||||
|
Assign(Word),
|
||||||
|
Error(Word),
|
||||||
|
Alt(Word),
|
||||||
|
Sub(ParamSubSide, ParamSubMode, Word),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParamSubMode {
|
||||||
|
Shortest, Longest
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParamSubSide {
|
||||||
|
Prefix, Suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Redirection {
|
||||||
|
redirection_type: RedirectionType,
|
||||||
|
fd: u64,
|
||||||
|
target: Word
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RedirectionType {
|
||||||
|
File(FileRedirectionType),
|
||||||
|
Dup(DupRedirectionType),
|
||||||
|
Heredoc // '<<'
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FileRedirectionType {
|
||||||
|
In, // '<'
|
||||||
|
InOut, // '<>'
|
||||||
|
Out, // '>'
|
||||||
|
OutReplace, // '>|'
|
||||||
|
OutAppend, // '>|'
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DupRedirectionType {
|
||||||
|
In, // '<&'
|
||||||
|
Out // '>&'
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
9
src/env.rs
Normal file
9
src/env.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
||||||
|
|
||||||
|
struct Environment {
|
||||||
|
variables: HashMap<String, String>
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
44
src/expand.rs
Normal file
44
src/expand.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use crate::ast::*;
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
||||||
|
|
||||||
|
impl Word {
|
||||||
|
pub fn (&mut self, env: &Environment) {
|
||||||
|
for x in self.0.iter_mut() {
|
||||||
|
x.expand_tilde();
|
||||||
|
match x {
|
||||||
|
Word::Tilde => Word::Literal( env.get_home() ),
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand(&self) -> Vec<String> {
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
|
||||||
|
for seg in self.segments.iter() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
fields
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split_field(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WordSegment {
|
||||||
|
pub fn split_field(&self) -> Word {
|
||||||
|
|
||||||
|
match self {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand(&self) -> Word {
|
||||||
|
match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
19
src/main.rs
19
src/main.rs
|
@ -4,6 +4,11 @@ use {
|
||||||
tiny_ansi::TinyAnsi
|
tiny_ansi::TinyAnsi
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod ast;
|
||||||
|
mod env;
|
||||||
|
mod parse;
|
||||||
|
//mod expand;
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
|
||||||
|
|
||||||
pub fn get_type_str(cmd: &str, item: &str) -> Option<String> {
|
pub fn get_type_str(cmd: &str, item: &str) -> Option<String> {
|
||||||
|
@ -31,7 +36,19 @@ fn main() {
|
||||||
let mut dict = TypeDict::new();
|
let mut dict = TypeDict::new();
|
||||||
|
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
for pipeline in std::io::BufReader::new(stdin).lines() {
|
for line in std::io::BufReader::new(stdin).lines() {
|
||||||
|
if let Ok(line) = line {
|
||||||
|
let mut lex = parse::WordLexer::from( line.chars() );
|
||||||
|
for word in lex {
|
||||||
|
eprintln!("word-segment: {:?}", word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
let stdin = std::io::stdin();
|
||||||
|
for pipeline in std::io::BufReader::new(stdin).lines() {
|
||||||
let mut last_cmd = String::new();
|
let mut last_cmd = String::new();
|
||||||
let mut last_stdout_type : Option<TypeTerm> = None;
|
let mut last_stdout_type : Option<TypeTerm> = None;
|
||||||
|
|
||||||
|
|
130
src/parse.rs
Normal file
130
src/parse.rs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
use {
|
||||||
|
crate::ast::*,
|
||||||
|
std::iter::{Peekable, FromIterator},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WordLexer<It>
|
||||||
|
where It: Iterator<Item = char> {
|
||||||
|
chars: Peekable<It>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<It> From<It> for WordLexer<It>
|
||||||
|
where It: Iterator<Item = char> {
|
||||||
|
fn from(iter: It) -> Self {
|
||||||
|
WordLexer {
|
||||||
|
chars: iter.into_iter().peekable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LexError {
|
||||||
|
UnexpectedEnd(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<It> WordLexer<It>
|
||||||
|
where It: Iterator<Item = char> {
|
||||||
|
fn collect_until(&mut self, close: char) -> Result<String, LexError> {
|
||||||
|
let mut val = String::new();
|
||||||
|
while let Some(c) = self.chars.peek().cloned() {
|
||||||
|
if c == close {
|
||||||
|
return Ok(val)
|
||||||
|
} else {
|
||||||
|
self.chars.next();
|
||||||
|
val.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if close.is_whitespace() {
|
||||||
|
Ok(val)
|
||||||
|
} else {
|
||||||
|
Err(LexError::UnexpectedEnd(close))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<It> Iterator for WordLexer<It>
|
||||||
|
where It: Iterator<Item = char> {
|
||||||
|
type Item = Result<WordSegment, LexError>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Result<WordSegment, LexError>> {
|
||||||
|
match self.chars.peek().cloned() {
|
||||||
|
Some('~') => {
|
||||||
|
self.chars.next();
|
||||||
|
match self.collect_until(' ') {
|
||||||
|
Ok(s) => Some(Ok(WordSegment::Tilde(s))),
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some('"') => {
|
||||||
|
self.chars.next();
|
||||||
|
match self.collect_until('"') {
|
||||||
|
Ok(s) => {
|
||||||
|
self.chars.next();
|
||||||
|
|
||||||
|
let word = Word {
|
||||||
|
segments: WordLexer { chars: s.chars().peekable() }
|
||||||
|
.scan((), |_, x| x.ok())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(Ok(WordSegment::DoubleQuote(word)))
|
||||||
|
},
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some('\'') => {
|
||||||
|
self.chars.next();
|
||||||
|
match self.collect_until('\'') {
|
||||||
|
Ok(s) => {
|
||||||
|
self.chars.next();
|
||||||
|
Some(Ok(WordSegment::Literal(s)))
|
||||||
|
},
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some('$') => {
|
||||||
|
self.chars.next();
|
||||||
|
match self.chars.peek() {
|
||||||
|
Some('{') => {
|
||||||
|
self.chars.next();
|
||||||
|
match self.collect_until('}') {
|
||||||
|
Ok(s) => {
|
||||||
|
self.chars.next();
|
||||||
|
Some(Ok(WordSegment::Variable(s)))
|
||||||
|
}
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
match self.collect_until(' ') {
|
||||||
|
Ok(s) => {
|
||||||
|
Some(Ok(WordSegment::Variable(s)))
|
||||||
|
}
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(c) => {
|
||||||
|
while let Some(c) = self.chars.peek() {
|
||||||
|
if c.is_whitespace() {
|
||||||
|
self.chars.next();
|
||||||
|
} else {
|
||||||
|
return match self.collect_until(' ') {
|
||||||
|
Ok(s) => {
|
||||||
|
Some(Ok(WordSegment::Literal(s)))
|
||||||
|
}
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue