From 7988c8a2e1220ffbf806a533e83c591ec3e1f891 Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Sun, 15 Oct 2023 11:47:06 +0200 Subject: [PATCH] wip parser --- src/ast.rs | 123 +++++++++++++++++++++++++++++++++++++++++++++++ src/env.rs | 9 ++++ src/expand.rs | 44 +++++++++++++++++ src/main.rs | 19 +++++++- src/parse.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 src/ast.rs create mode 100644 src/env.rs create mode 100644 src/expand.rs create mode 100644 src/parse.rs diff --git a/src/ast.rs b/src/ast.rs new file mode 100644 index 0000000..5a20bbc --- /dev/null +++ b/src/ast.rs @@ -0,0 +1,123 @@ +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +#[derive(Debug)] +pub enum Command { + Simple { + assignments: Vec<(String, Word)>, + command_word: Word, + redirections: Vec + }, + Pipeline(Vec), + Sequence(Vec), + ShortCircuitConjection(Vec), + ShortCircuitDisjunction(Vec), + 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 +} + +#[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 // '>&' +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/env.rs b/src/env.rs new file mode 100644 index 0000000..091e68d --- /dev/null +++ b/src/env.rs @@ -0,0 +1,9 @@ +use std::collections::HashMap; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +struct Environment { + variables: HashMap +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/expand.rs b/src/expand.rs new file mode 100644 index 0000000..412fc5f --- /dev/null +++ b/src/expand.rs @@ -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 { + 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 + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/main.rs b/src/main.rs index 5533bc1..d6025bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,11 @@ use { tiny_ansi::TinyAnsi }; +mod ast; +mod env; +mod parse; +//mod expand; + //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ pub fn get_type_str(cmd: &str, item: &str) -> Option { @@ -31,7 +36,19 @@ fn main() { let mut dict = TypeDict::new(); 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_stdout_type : Option = None; diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..9a54df4 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,130 @@ +use { + crate::ast::*, + std::iter::{Peekable, FromIterator}, +}; + +pub struct WordLexer +where It: Iterator { + chars: Peekable +} + +impl From for WordLexer +where It: Iterator { + fn from(iter: It) -> Self { + WordLexer { + chars: iter.into_iter().peekable() + } + } +} + +#[derive(Debug)] +pub enum LexError { + UnexpectedEnd(char) +} + +impl WordLexer +where It: Iterator { + fn collect_until(&mut self, close: char) -> Result { + 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 Iterator for WordLexer +where It: Iterator { + type Item = Result; + + fn next(&mut self) -> Option> { + 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::>() + }; + + 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 + } + } + } +} +