gettin somewhere
parent
56bfdcc9fc
commit
7004de4e82
@ -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…
Reference in New Issue