From 7004de4e82013feaaf006fd3f090b754e08b0c44 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Tue, 30 Jan 2024 23:35:39 -0600 Subject: [PATCH] gettin somewhere --- src/error.rs | 18 +++++ src/lex.rs | 3 +- src/main.rs | 1 + src/parse2.rs | 85 +++++++++++++++++---- src/syntax.rs | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 293 insertions(+), 16 deletions(-) create mode 100644 src/syntax.rs diff --git a/src/error.rs b/src/error.rs index 74346d3..ae5ac73 100644 --- a/src/error.rs +++ b/src/error.rs @@ -63,6 +63,24 @@ pub enum ParseError { PushOntoTerminal, } +#[derive(Debug, Error)] +pub enum ExecError { + #[error("failed waiting on child process")] + ProcessWaitError(#[source] io::Error), + + #[error("failed to spawn child process")] + ProcessSpawnError(#[source] io::Error), + + #[error("value type error: {0}")] + ValueTypeError(String), +} + +impl ExecError { + pub fn type_error>(msg: S) -> Self { + Self::ValueTypeError(msg.into()) + } +} + impl Error { pub fn last_error() -> Self { unsafe { Error::WindowsError(GetLastError().to_hresult().message().to_string()) } diff --git a/src/lex.rs b/src/lex.rs index 1ec4f33..89f9389 100644 --- a/src/lex.rs +++ b/src/lex.rs @@ -426,7 +426,7 @@ impl<'text> Lexer<'text> { pub fn peek_at(&mut self, idx: usize) -> Result, LexError> { self.fill_lookahead(idx + 1)?; - Ok(None) + Ok(self.lookahead.get(idx)) } pub fn peek(&mut self) -> Result, LexError> { @@ -542,6 +542,7 @@ mod tests { glob_3 "x*" [ glob("x*") ] glob_4 "*x" [ glob("*x") ] glob_5 "*.py" [ glob("*.py") ] + mixed_1 "ls *.py" [ word("ls") glob("*.py") ] } } diff --git a/src/main.rs b/src/main.rs index 3c74a7a..099ad01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod parse; mod parse2; mod prompt; mod shell; +mod syntax; use crate::log::*; use prompt::Prompt; diff --git a/src/parse2.rs b/src/parse2.rs index e520113..950be60 100644 --- a/src/parse2.rs +++ b/src/parse2.rs @@ -4,9 +4,10 @@ use std::{ cell::RefCell, collections::VecDeque, rc::{Rc, Weak}, + sync::atomic::AtomicUsize, }; -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub enum Value { /// The start symbol of our parse tree. Each parse tree is rooted in a node whose value is the /// start symbol. This is the only node in the tree that should utilize the start symbol. @@ -24,23 +25,27 @@ impl Value { } /// A node in a parse tree. +#[derive(Debug)] pub struct Node { + pub id: usize, + /// A node may or may not have a parent node. If a node does not have a parent node, that node /// is the root node of a tree. parent: Option>, /// The value of the element at this node - value: Value, + pub value: Value, /// A node may or may not have children. Since an empty vector is a valid vector, a node /// without children is represented as having an empty children vector. A node having an empty /// list of children is a leaf node in a tree. - children: RefCell>>, + pub children: RefCell>>, } impl Node { fn new() -> Cursor { let root = Node { + id: next_id(), parent: None, value: Value::Start, children: RefCell::new(Vec::new()), @@ -54,17 +59,45 @@ impl Node { } } -/// Cursor values expose access to a parse tree. -struct Cursor { +pub struct ChildIter { target: Rc, root: Rc, + idx: usize, +} + +impl Iterator for ChildIter { + type Item = Cursor; + + fn next(&mut self) -> Option { + println!("next"); + let children = self.target.children.borrow(); + let v = children.get(self.idx)?; + println!("next has: {v:?}"); + self.idx += 1; + Some(Cursor { + target: Rc::clone(v), + root: Rc::clone(&self.root), + }) + } +} + +const LAST_ID: AtomicUsize = AtomicUsize::new(0); +fn next_id() -> usize { + LAST_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed) +} + +/// Cursor values expose access to a parse tree. +#[derive(Debug)] +pub struct Cursor { + pub target: Rc, + root: Rc, } impl Cursor { /// Climbs one level up a parse tree. The cursor is re-pointed from its current target node to /// the parent of its current target node. This method fails if the cursor is already at the /// root node of the parse tree. - fn up(&mut self) -> Result<(), ParseError> { + pub fn up(&mut self) -> Result<(), ParseError> { match &self.target.parent { None => Err(ParseError::AtRootAlready), Some(parent) => match parent.upgrade() { @@ -84,6 +117,7 @@ impl Cursor { return Err(ParseError::PushOntoTerminal); } let node = Node { + id: next_id(), parent: Some(Rc::downgrade(&self.target)), value: v, children: RefCell::new(Vec::new()), @@ -97,20 +131,32 @@ impl Cursor { Ok(()) } - fn is_root(&self) -> bool { + pub fn is_root(&self) -> bool { self.target.parent.is_none() } - fn into_root(self) -> Rc { + pub fn up_to_root(&mut self) { + self.target = Rc::clone(&self.root); + } + + pub fn into_root(self) -> Rc { Rc::clone(&self.root) } - fn value(&self) -> &Value { + pub fn value(&self) -> &Value { &self.target.value } + + pub fn iter_children(&self) -> ChildIter { + ChildIter { + target: Rc::clone(&self.target), + root: Rc::clone(&self.root), + idx: 0, + } + } } -struct Parser<'text> { +pub struct Parser<'text> { source: Lexer<'text>, cursor: Cursor, } @@ -123,12 +169,14 @@ impl<'text> Parser<'text> { } } - pub fn parse(mut self) -> Result, ParseError> { + pub fn parse(mut self) -> Result { while self.step()? {} - Ok(self.cursor.into_root()) + self.cursor.up_to_root(); + Ok(self.cursor) } fn step(&mut self) -> Result { + println!("parser step..."); match self.cursor.value() { Value::Start => self.step_start(), Value::Statement => self.step_statement(), @@ -138,24 +186,30 @@ impl<'text> Parser<'text> { fn step_start(&mut self) -> Result { assert!(matches!(self.cursor.value(), Value::Start)); + println!("step start node"); match self.source.peek()? { Some(Token::Word(_)) => { self.cursor.push(Value::Statement)?; let token = self.source.next().unwrap()?; self.cursor.push(Value::Terminal(token))?; self.cursor.up()?; + println!("start node returns true..."); Ok(true) } Some(Token::Glob(_)) => { let token = self.source.next().unwrap()?; Err(ParseError::UnexpectedToken(token)) } - None => Ok(false), + None => { + println!("start node has ... nothin peeked in source"); + Ok(false) + } } } fn step_statement(&mut self) -> Result { assert!(matches!(self.cursor.value(), Value::Statement)); + println!("step statement node"); match self.source.peek()? { Some(Token::Word(_) | Token::Glob(_)) => { let token = self.source.next().unwrap()?; @@ -168,7 +222,7 @@ impl<'text> Parser<'text> { } } -fn parse(source: &str) -> Result, ParseError> { +fn parse(source: &str) -> Result { let tokens = Lexer::new(source); let parser = Parser::new(tokens); parser.parse() @@ -209,7 +263,8 @@ mod test { #[test] fn test_parse() -> Result<(), ParseError> { - parse("ls")?; + let x = parse("ls one two three")?; + println!("Parse tree: {x:?}"); // parse("*")?; // parse("x* ls")?; Ok(()) diff --git a/src/syntax.rs b/src/syntax.rs new file mode 100644 index 0000000..47f3c24 --- /dev/null +++ b/src/syntax.rs @@ -0,0 +1,202 @@ +use crate::{ + error::{ExecError, ParseError}, + lex::{Lexer, Token}, + parse2, +}; +use std::{collections::HashSet, process}; + +struct State {} + +impl State { + pub fn new() -> Self { + Self {} + } +} + +trait Eval { + fn eval(&self, ctx: &mut State) -> Result; +} + +#[derive(Debug)] +enum Element { + Block(Block), + Command(Command), + Literal(Value), +} + +impl Eval for Element { + fn eval(&self, ctx: &mut State) -> Result { + use Element::*; + match self { + Block(block) => block.eval(ctx), + Command(cmd) => cmd.eval(ctx), + Literal(v) => v.eval(ctx), + } + } +} + +#[derive(Debug, Clone)] +enum Value { + None, + Text(String), + ExitStatus(process::ExitStatus), +} + +impl Eval for Value { + fn eval(&self, ctx: &mut State) -> Result { + Ok(self.clone()) + } +} + +impl Value { + pub fn try_to_string(self) -> Result { + match self { + Value::None => Err(ExecError::type_error("expected text value, saw None value")), + Value::Text(v) => Ok(v), + Value::ExitStatus(_) => Err(ExecError::type_error( + "expected text value, saw ExitStatus value", + )), + } + } +} + +#[derive(Debug)] +struct Block { + commands: Vec, +} + +impl Block { + pub fn new() -> Self { + Block { + commands: Vec::new(), + } + } +} + +impl Eval for Block { + fn eval(&self, ctx: &mut State) -> Result { + let mut v = Value::None; + for cmd in self.commands.iter() { + v = cmd.eval(ctx)?; + } + Ok(v) + } +} + +#[derive(Debug)] +struct Command { + name: Box, + args: Vec, +} + +impl Eval for Command { + fn eval(&self, ctx: &mut State) -> Result { + let name = self.name.eval(ctx)?.try_to_string()?; + let mut proc = process::Command::new(name); + + if self.args.len() > 0 { + let args = self + .args + .iter() + .map(|elem| elem.eval(ctx)?.try_to_string()) + .collect::, ExecError>>()?; + proc.args(args); + } + let mut child = proc.spawn().map_err(|e| ExecError::ProcessSpawnError(e))?; + let status = child.wait().map_err(|e| ExecError::ProcessWaitError(e))?; + return Ok(Value::ExitStatus(status)); + } +} + +// ????? waht am i doing now +struct TreeBuilder { + visited: HashSet, +} + +impl TreeBuilder { + fn new() -> Self { + Self { + visited: HashSet::new(), + } + } + + fn descend(&mut self, source: &mut parse2::Cursor) -> Result { + let e = match source.value() { + parse2::Value::Start => { + println!("start node"); + let mut root = Block::new(); + let children = source.iter_children(); + for mut child in children { + println!("child"); + let e = self.descend(&mut child)?; + match e { + Element::Command(cmd) => root.commands.push(cmd), + _ => panic!(), + } + } + Element::Block(root) + } + parse2::Value::Statement => { + println!("statement node"); + let mut children = source.iter_children(); + let mut first = children.next().unwrap(); + let name = self.descend(&mut first)?; + let mut cmd = Command { + name: Box::new(name), + args: Vec::new(), + }; + for mut child in children { + let e = self.descend(&mut child)?; + cmd.args.push(e); + } + Element::Command(cmd) + } + parse2::Value::Terminal(Token::Word(word)) => { + println!("terminal word node"); + Element::Literal(Value::Text(word.to_string())) + } + parse2::Value::Terminal(Token::Glob(_)) => { + todo!() + } + }; + println!("visited: {:?}", source.target.id); + self.visited.insert(source.target.id); + Ok(e) + } +} + +fn build(mut source: parse2::Cursor) -> Result { + source.up_to_root(); + let mut builder = TreeBuilder::new(); + builder.descend(&mut source) +} + +fn x(source: &str) -> Result { + let tokens = Lexer::new(source); + let parser = parse2::Parser::new(tokens); + let mut parse_tree = parser.parse()?; + println!("parse tree: {parse_tree:?}"); + let mut builder = TreeBuilder::new(); + builder.descend(&mut parse_tree) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::lex::lex; + + #[test] + fn hi() -> Result<(), ParseError> { + let e = x("ls one two three ; ls four")?; + print!("{:?}", e); + Ok(()) + } +} + +/* + +> ls + command + name: ls + +*/