From 6ff32bd4a477b58266bbf703478730bfcb38e11d Mon Sep 17 00:00:00 2001 From: Thelie Date: Sat, 19 Feb 2022 11:37:31 +0100 Subject: [PATCH] Initial commit --- .gitignore | 14 ++++++++++++ Cargo.toml | 19 ++++++++++++++++ TODO | 34 +++++++++++++++++++++++++++++ build.rs | 5 +++++ src/callobj.rs | 47 ++++++++++++++++++++++++++++++++++++++++ src/fun_parser.lalrpop | 22 +++++++++++++++++++ src/lib.rs | 49 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 190 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 TODO create mode 100644 build.rs create mode 100644 src/callobj.rs create mode 100644 src/fun_parser.lalrpop create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2dde6f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Rust +/target +Cargo.lock + +# Version control and locks. +*.orig +*.swp +*~ +.#* +\#*\# +ChangeLog +[0-9]*.patch +[0-9]*.txt +/vc-dwim-log-* \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ddc7d0a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "sing" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +build = "build.rs" + +[lib] +proc-macro = true + +[build-dependencies] +lalrpop = "0.19" + +[dependencies] +syn = "1" +regex = "1" +lalrpop-util = "0.19" +lalrpop = "0.19" \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..fa82024 --- /dev/null +++ b/TODO @@ -0,0 +1,34 @@ +# Sing + +Std +I/o +Negotiator +Generator + +## What is sing meant to be? + +- Provide stdio interface to traits +- not like serde because it's for traits instead of objects +- not like clap since it works at run time, not before +- similar ease of use as both of the above though + +## How to get there + +- Using lalrpop (in a feature flag) +- Maybe utilize serde +- Look at how clap handles states between macro calls + - They operate on a singleton lol + - This would need to store All traits and their functions + - It should also own (locked) Stdin, Stdout and Stderr (or any one Read and two Write objects) + - This bad boi would also implement the main loop for the cli application. + +## Links oder so lül + +https://serde.rs/impl-serializer.html +https://docs.serde.rs/serde/trait.Serializer.html +https://docs.rs/proc-macro2/1.0.36/proc_macro2/ +https://docs.rs/syn/1.0.86/syn/ +https://github.com/clap-rs/clap/blob/master/src/derive.rs +https://github.com/clap-rs/clap +https://github.com/clap-rs/clap/blob/v3.0.14/examples/tutorial_builder/README.md +https://www.morling.dev/blog/whats-in-a-good-error-message/ \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..23c7d3f --- /dev/null +++ b/build.rs @@ -0,0 +1,5 @@ +extern crate lalrpop; + +fn main() { + lalrpop::process_root().unwrap(); +} diff --git a/src/callobj.rs b/src/callobj.rs new file mode 100644 index 0000000..93c6290 --- /dev/null +++ b/src/callobj.rs @@ -0,0 +1,47 @@ +use std::fmt; + +pub struct CallObj { + trait_string: Option, + fun_string: String, + index: usize, + data: Vec, +} + +impl CallObj { + pub fn new((trait_string, fun_string, index): (Option, String, usize), data: Vec) -> Self { + Self{ + trait_string, + fun_string, + index, + data, + } + } +} + +impl fmt::Display for CallObj { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut repr = String::new(); + + match &self.trait_string { + Some(tstr) => { + repr.push_str(tstr); + repr.push('>'); + }, + None => {} + } + + repr.push_str(&self.fun_string); + + if self.index != usize::MAX { + repr.push('>'); + repr.push_str(&self.index.to_string()); + } + + for element in &self.data { + repr.push(' '); + repr.push_str(element); + } + + write!(f, "{}", repr) + } +} diff --git a/src/fun_parser.lalrpop b/src/fun_parser.lalrpop new file mode 100644 index 0000000..0ca72ab --- /dev/null +++ b/src/fun_parser.lalrpop @@ -0,0 +1,22 @@ +use std::str::FromStr; + +use crate::callobj::CallObj; + +grammar; + +pub Call: CallObj = { + => CallObj::new(<>), +}; + +Descriptor: (Option, String, usize) = { + ">")?> ">" => (t, f, i), + ">")?> => (t, f, usize::MAX), +} + +Identifier: String = r"[A-Z][a-zA-Z]*" => <>.to_string(); + +Index: usize = r"[1-9][0-9]*" => usize::from_str(<>).unwrap(); + +Data: Vec = Value+; + +Value: String = r" [0-9a-zA-Z]*" => (<>[1..<>.chars().count()]).to_string(); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..efae85a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,49 @@ + +use proc_macro::TokenStream; +#[macro_use] extern crate lalrpop_util; +extern crate lalrpop; + +mod callobj; + +lalrpop_mod!(fun_parser); + +#[proc_macro_derive(HelloMacro)] +pub fn hello_macro_derive(input: TokenStream) -> TokenStream { + let _friend = lalrpop::process_root(); + println!("Hello world!"); + fun_parser::CallParser::new(); + input +} + +#[cfg(test)] +mod tests { + use crate::fun_parser; + + + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } + + #[test] + fn parser_parses() { + let test_str = "Trait>Fun>1 arg1 arg2 arg3"; + assert!(fun_parser::CallParser::new() + .parse(test_str) + .is_ok()); + } + + #[test] + fn parser_parses_correctly() { + let test_str: &str = "Trait>Fun>1 arg1 arg2 arg3"; + println!("[{}]", + fun_parser::CallParser::new() + .parse(test_str).unwrap() + ); + assert!(format!( "{}", + fun_parser::CallParser::new() + .parse(test_str).unwrap() + ) == test_str); + } +}