gettin somewhere

main
Jordan Orelli 11 months ago
parent 56bfdcc9fc
commit 7004de4e82

@ -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<S: Into<String>>(msg: S) -> Self {
Self::ValueTypeError(msg.into())
}
}
impl Error {
pub fn last_error() -> Self {
unsafe { Error::WindowsError(GetLastError().to_hresult().message().to_string()) }

@ -426,7 +426,7 @@ impl<'text> Lexer<'text> {
pub fn peek_at(&mut self, idx: usize) -> Result<Option<&Token>, LexError> {
self.fill_lookahead(idx + 1)?;
Ok(None)
Ok(self.lookahead.get(idx))
}
pub fn peek(&mut self) -> Result<Option<&Token>, 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") ]
}
}

@ -10,6 +10,7 @@ mod parse;
mod parse2;
mod prompt;
mod shell;
mod syntax;
use crate::log::*;
use prompt::Prompt;

@ -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<Weak<Node>>,
/// 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<Vec<Rc<Node>>>,
pub children: RefCell<Vec<Rc<Node>>>,
}
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<Node>,
root: Rc<Node>,
idx: usize,
}
impl Iterator for ChildIter {
type Item = Cursor;
fn next(&mut self) -> Option<Self::Item> {
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<Node>,
root: Rc<Node>,
}
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<Node> {
pub fn up_to_root(&mut self) {
self.target = Rc::clone(&self.root);
}
pub fn into_root(self) -> Rc<Node> {
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<Rc<Node>, ParseError> {
pub fn parse(mut self) -> Result<Cursor, ParseError> {
while self.step()? {}
Ok(self.cursor.into_root())
self.cursor.up_to_root();
Ok(self.cursor)
}
fn step(&mut self) -> Result<bool, ParseError> {
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<bool, ParseError> {
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<bool, ParseError> {
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<Rc<Node>, ParseError> {
fn parse(source: &str) -> Result<Cursor, ParseError> {
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(())

@ -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<Value, ExecError>;
}
#[derive(Debug)]
enum Element {
Block(Block),
Command(Command),
Literal(Value),
}
impl Eval for Element {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> {
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<Value, ExecError> {
Ok(self.clone())
}
}
impl Value {
pub fn try_to_string(self) -> Result<String, ExecError> {
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<Command>,
}
impl Block {
pub fn new() -> Self {
Block {
commands: Vec::new(),
}
}
}
impl Eval for Block {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> {
let mut v = Value::None;
for cmd in self.commands.iter() {
v = cmd.eval(ctx)?;
}
Ok(v)
}
}
#[derive(Debug)]
struct Command {
name: Box<Element>,
args: Vec<Element>,
}
impl Eval for Command {
fn eval(&self, ctx: &mut State) -> Result<Value, ExecError> {
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::<Result<Vec<String>, 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<usize>,
}
impl TreeBuilder {
fn new() -> Self {
Self {
visited: HashSet::new(),
}
}
fn descend(&mut self, source: &mut parse2::Cursor) -> Result<Element, ParseError> {
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<Element, ParseError> {
source.up_to_root();
let mut builder = TreeBuilder::new();
builder.descend(&mut source)
}
fn x(source: &str) -> Result<Element, ParseError> {
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
*/
Loading…
Cancel
Save