From fb89e929fe6cb712c8a33aace3bf3e963cd3ad45 Mon Sep 17 00:00:00 2001 From: eater <=@eater.me> Date: Sat, 21 Dec 2019 01:19:11 +0100 Subject: [PATCH] first commit --- .gitignore | 2 + Cargo.lock | 6 +++ Cargo.toml | 9 ++++ README.md | 32 ++++++++++++++ src/graph.rs | 28 +++++++++++++ src/main.rs | 14 +++++++ src/parser.rs | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 204 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/graph.rs create mode 100644 src/main.rs create mode 100644 src/parser.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0b33f4b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "petri" +version = "0.1.0" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..16fbe01 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "petri" +version = "0.1.0" +authors = ["eater <=@eater.me>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..52d69a4 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# Petri + +A directional shell + +# Syntax + +The syntax of petri is a bit different than normal shells because it uses ASCII art to define running graphs + +``` +#!/usr/bin/env petri + \(diff @ @) + ^ ^ + | | +\(ls /dev) -> replace_x --+-> replace_y --x-+ + | | + +-> replace_z --+ +--- +replace_x: sed 's:x:y:g' +replace_y: sed 's:y:z:g' +replace_z: sed 's:z:x:g' +``` + +This would be the equivalent of the bash file: + +``` +ls /dev | sed 's:x:y:g' > /tmp/temp_file +diff <(sed 's:z:x:g' < /tmp/temp_file) <(sed 's:y:z:g' < /tmp/temp_file) +``` + +#### Why 'petri' + +Originally I wanted to call it `dish` but I found that to generic, and since dish is from time to time preceded with petri, I choose that. \ No newline at end of file diff --git a/src/graph.rs b/src/graph.rs new file mode 100644 index 0000000..b33cf14 --- /dev/null +++ b/src/graph.rs @@ -0,0 +1,28 @@ +use std::collections::{HashMap, HashSet}; + +#[derive(Clone, Default, Debug)] +pub struct Graph { + pub nodes: HashMap, + pub node_names: HashMap, +} + +#[derive(Clone, Default, Debug)] +pub struct Node { + pub name: Option, + // Set string to command + pub command: Option, + pub edges: Vec, +} + +#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum Transport { + Err, + Out, +} + +#[derive(Clone, Default, Debug)] +pub struct Edge { + pub from: u32, + pub to: u32, + pub transports: HashSet, +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..166ed2f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,14 @@ +use crate::parser::parse; + +mod graph; +mod parser; + +fn main() { + let graph = parse(r" +# hello +hello -> bye + + ".to_string()); + + println!("result: {:?}", graph); +} diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..09356f4 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,113 @@ +use crate::graph::{Graph, Node}; +use std::collections::HashMap; +use std::fmt::Error; + +enum State { + Default, + Edge, + Node(String), + AnonymousNode, +} + +struct Consumer { + lines: Vec, + state: ConsumerState, +} + +struct ConsumerState { + line: usize, + position: usize, + absolute_position: u64, +} + +impl Consumer { + fn consume_from_line(&mut self) -> Option { + if let Some(chxr) = self.peek_on_line() { + self.push_char(); + Some(chxr) + } else { + None + } + } + + fn peek_on_line(&mut self) -> Option { + let line = &self.lines[self.state.line]; + if self.state.position + 1 >= line.len() { + None + } else { + Ok(line[self.state.position + 1]) + } + } + + fn push_char(&mut self) { + self.state.position += 1; + self.state.absolute_position += 1; + } + + fn new(content: String) -> Consumer { + Consumer { + lines: content + .lines() + .map(|x| String::from(x)) + .collect(), + state: ConsumerState { + position: 0, + line: 0, + absolute_position: 0, + }, + } + } +} + +pub struct ParserError { + message: String, + absolute_position: u64, + position: usize, + line: usize, +} + +impl ParserError { + fn from_consumer(consumer: &Consumer, error: &str) -> ParserError { + ParserError { + message: error.to_string(), + absolute_position: consumer.state.absolute_position, + position: consumer.state.position, + line: consumer.state.line + } + } +} + +pub fn parse(contents: String) -> Result { + let mut nodes: Vec; + let mut node_names: HashMap; + let mut state = State::Default; + let mut consumer = Consumer::new(contents); + + while consumer.consume_line() { + while let Some(chxr) = consumer.consume_from_line() { + match state { + State::Default => { + match chxr { + '\\' => { + if consumer.peek_on_line() == Some('(') { + consumer.consume_from_line(); + state = State::AnonymousNode; + } else { + return Err(ParserError::from_consumer(&consumer, "Found \\ without valid next character")); + } + } + + 'a'..'z' | 'A'..'Z' => { + state = State::Node(chxr.to_string()) + } + } + } + _ => {} + } + } + } + + println!("{:?}", lines); + + Ok(Graph::default()) +} \ No newline at end of file