make more use of generics, add tests

This commit is contained in:
elkowar 2021-07-02 19:44:10 +02:00
parent dedf40d57e
commit 6a4d7361f0
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
21 changed files with 627 additions and 74 deletions

157
Cargo.lock generated
View file

@ -93,6 +93,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"terminal_size",
"winapi",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
@ -133,6 +146,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "either"
version = "1.6.1"
@ -148,6 +167,25 @@ dependencies = [
"log",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "eww_config"
version = "0.1.0"
dependencies = [
"insta",
"itertools",
"lalrpop",
"lalrpop-util",
"maplit",
"regex",
"thiserror",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
@ -190,6 +228,21 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "insta"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1b21a2971cea49ca4613c0e9fe8225ecaf5de64090fddc6002284726e9244"
dependencies = [
"console",
"lazy_static",
"serde",
"serde_json",
"serde_yaml",
"similar",
"uuid",
]
[[package]]
name = "itertools"
version = "0.10.0"
@ -199,6 +252,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "lalrpop"
version = "0.19.5"
@ -243,6 +302,12 @@ version = "0.2.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "log"
version = "0.4.14"
@ -270,18 +335,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nomwut"
version = "0.1.0"
dependencies = [
"itertools",
"lalrpop",
"lalrpop-util",
"maplit",
"regex",
"thiserror",
]
[[package]]
name = "petgraph"
version = "0.5.1"
@ -377,6 +430,61 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "serde"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]]
name = "similar"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad1d488a557b235fc46dae55512ffbfc429d2482b08b4d9435ab07384ca8aec"
[[package]]
name = "siphasher"
version = "0.3.5"
@ -417,6 +525,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.25"
@ -452,6 +570,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@ -479,3 +603,12 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View file

@ -1,5 +1,5 @@
[package]
name = "nomwut"
name = "eww_config"
version = "0.1.0"
authors = ["elkowar <5300871+elkowar@users.noreply.github.com>"]
edition = "2018"
@ -17,3 +17,6 @@ maplit = "1.0"
[build-dependencies]
lalrpop = "0.19.5"
[dev-dependencies]
insta = "1.7"

View file

@ -19,6 +19,7 @@ impl FromExpr for Expr {
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum DefType {
Widget,
}
@ -36,15 +37,16 @@ impl FromExpr for DefType {
}
}
pub struct Definitional<T> {
#[derive(Debug, Eq, PartialEq)]
pub struct Definitional<C, A> {
def_type: DefType,
name: String,
attrs: HashMap<AttrName, Expr>,
children: Vec<T>,
attrs: HashMap<AttrName, A>,
children: Vec<C>,
span: Span,
}
impl<T: FromExpr> FromExpr for Definitional<T> {
impl<C: FromExpr, A: FromExpr> FromExpr for Definitional<C, A> {
fn from_expr(e: Expr) -> AstResult<Self> {
let span = e.span();
spanned!(e.span(), {
@ -52,23 +54,24 @@ impl<T: FromExpr> FromExpr for Definitional<T> {
let mut iter = itertools::put_back(list.into_iter());
let def_type = DefType::from_expr(iter.next().or_missing(ExprType::Symbol)?)?;
let name = iter.next().or_missing(ExprType::Str)?.as_str()?;
let attrs = parse_key_values(&mut iter);
let name = iter.next().or_missing(ExprType::Symbol)?.as_symbol()?;
let attrs = parse_key_values(&mut iter)?;
let children = iter.map(|x| C::from_expr(x)).collect::<AstResult<Vec<_>>>()?;
let children = iter.map(|x| T::from_expr(x)).collect::<AstResult<Vec<_>>>()?;
Definitional { span, def_type, name, attrs, children }
})
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Element<T> {
pub struct Element<C, A> {
name: String,
attrs: HashMap<AttrName, Expr>,
children: Vec<T>,
attrs: HashMap<AttrName, A>,
children: Vec<C>,
span: Span,
}
impl FromExpr for Element<Expr> {
impl<C: FromExpr, A: FromExpr> FromExpr for Element<C, A> {
fn from_expr(e: Expr) -> AstResult<Self> {
let span = e.span();
spanned!(e.span(), {
@ -76,31 +79,33 @@ impl FromExpr for Element<Expr> {
let mut iter = itertools::put_back(list.into_iter());
let name = iter.next().or_missing(ExprType::Str)?.as_symbol()?;
let attrs = parse_key_values(&mut iter);
let attrs = parse_key_values(&mut iter)?;
let children = iter.map(C::from_expr).collect::<AstResult<Vec<_>>>()?;
Element { span, name, attrs, children: iter.collect_vec() }
Element { span, name, attrs, children }
})
}
}
fn parse_key_values<I: Iterator<Item = Expr>>(iter: &mut itertools::PutBack<I>) -> HashMap<String, Expr> {
/// Parse consecutive `:keyword value` pairs from an expression iterator into a HashMap. Transforms the keys using the FromExpr trait.
fn parse_key_values<T: FromExpr, I: Iterator<Item = Expr>>(iter: &mut itertools::PutBack<I>) -> AstResult<HashMap<String, T>> {
let mut data = HashMap::new();
loop {
match iter.next() {
Some(Expr::Keyword(span, kw)) => match iter.next() {
Some(value) => {
data.insert(kw, value);
data.insert(kw, T::from_expr(value)?);
}
None => {
iter.put_back(Expr::Keyword(span, kw));
return data;
return Ok(data);
}
},
Some(expr) => {
iter.put_back(expr);
return data;
return Ok(data);
}
None => return data,
None => return Ok(data),
}
}
}
@ -109,25 +114,18 @@ fn parse_key_values<I: Iterator<Item = Expr>>(iter: &mut itertools::PutBack<I>)
mod test {
use super::*;
use insta;
#[test]
fn test() {
let parser = parser::ExprParser::new();
assert_eq!(
Element::<Expr>::from_expr(parser.parse("(box :bar 12 :baz \"hi\" foo (bar))").unwrap()).unwrap(),
Element {
span: Span(0, 33),
name: "box".to_string(),
attrs: maplit::hashmap! {
":bar".to_string() => Expr::Number(Span(10, 12), 12),
":baz".to_string() => Expr::Str(Span(18, 22), "hi".to_string()),
},
children: vec![
Expr::Symbol(Span(23, 26), "foo".to_string()),
Expr::List(Span(27, 32), vec![Expr::Symbol(Span(28, 31), "bar".to_string())]),
],
}
);
insta::with_settings!({sort_maps => true}, {
insta::assert_debug_snapshot!(
Element::<Expr, Expr>::from_expr(parser.parse("(box :bar 12 :baz \"hi\" foo (bar))").unwrap()).unwrap()
);
insta::assert_debug_snapshot!(
Definitional::<Expr, Expr>::from_expr(parser.parse("(defwidget box (child) (child2))").unwrap()).unwrap()
);
});
}
}

View file

@ -16,12 +16,18 @@ use lalrpop_util::lalrpop_mod;
lalrpop_mod!(pub parser);
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[derive(Eq, PartialEq, Clone, Copy)]
pub struct Span(pub usize, pub usize);
impl std::fmt::Display for Span {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<{}..{}>", self.0, self.1)
write!(f, "{}..{}", self.0, self.1)
}
}
impl std::fmt::Debug for Span {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
@ -118,39 +124,33 @@ fn main() {}
#[allow(unused_macros)]
macro_rules! test_p {
($e:expr) => {
let e = $e;
let p = parser::ExprParser::new();
match p.parse(e) {
Ok(res) => println!("{}\n=> {}\n", e, res),
Err(e) => eprintln!("{}", e),
}
insta::assert_debug_snapshot!(p.parse($e))
};
}
#[test]
fn test() {
// test_p!("1");
// test_p!("(12)");
// test_p!("(1 2)");
// test_p!("(1 :foo 1)");
// test_p!("(:foo 1)");
// test_p!("(:foo->: 1)");
// test_p!("(foo 1)");
// test_p!("(lol😄 1)");
test_p!("1");
test_p!("(12)");
test_p!("(1 2)");
test_p!("(1 :foo 1)");
test_p!("(:foo 1)");
test_p!("(:foo->: 1)");
test_p!("(foo 1)");
test_p!("(lol😄 1)");
// test_p!(r#"(test "hi")"#);
// test_p!(r#"(test "h\"i")"#);
// test_p!(r#"(test " hi ")"#);
test_p!(r#"(test "hi")"#);
test_p!(r#"(test "h\"i")"#);
test_p!(r#"(test " hi ")"#);
// test_p!("(+ (1 2 (* 2 5)))");
test_p!("(+ (1 2 (* 2 5)))");
// test_p!(r#"{:key value 12 "hi" (test) (1 2 3)}"#);
test_p!(r#"{:key value 12 "hi" (test) (1 2 3)}"#);
// test_p!(r#"; test"#);
// test_p!(
// r#"(f arg ; test
// arg2)"#
//);
// println!("\n\n\n\n\n\n");
test_p!(r#"; test"#);
test_p!(
r#"(f arg ; test
arg2)"#
);
}

View file

@ -0,0 +1,31 @@
---
source: src/config.rs
expression: "Definitional::<Expr,\n Expr>::from_expr(parser.parse(\"(defwidget box (child) (child2))\").unwrap()).unwrap()"
---
Definitional {
def_type: Widget,
name: "box",
attrs: {},
children: [
List(
15..22,
[
Symbol(
16..21,
"child",
),
],
),
List(
23..31,
[
Symbol(
24..30,
"child2",
),
],
),
],
span: 0..32,
}

View file

@ -0,0 +1,34 @@
---
source: src/config.rs
expression: "Element::<Expr,\n Expr>::from_expr(parser.parse(\"(box :bar 12 :baz \\\"hi\\\" foo (bar))\").unwrap()).unwrap()"
---
Element {
name: "box",
attrs: {
":baz": Str(
18..22,
"hi",
),
":bar": Number(
10..12,
12,
),
},
children: [
Symbol(
23..26,
"foo",
),
List(
27..32,
[
Symbol(
28..31,
"bar",
),
],
),
],
span: 0..33,
}

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(r#\"(test \"h\\\"i\")\"#)"
---
Ok(
List(
0..13,
[
Symbol(
1..5,
"test",
),
Str(
6..12,
"h\\\"i",
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(r#\"(test \" hi \")\"#)"
---
Ok(
List(
0..13,
[
Symbol(
1..5,
"test",
),
Str(
6..12,
" hi ",
),
],
),
)

View file

@ -0,0 +1,46 @@
---
source: src/main.rs
expression: "p.parse(\"(+ (1 2 (* 2 5)))\")"
---
Ok(
List(
0..17,
[
Symbol(
1..2,
"+",
),
List(
3..16,
[
Number(
4..5,
1,
),
Number(
6..7,
2,
),
List(
8..15,
[
Symbol(
9..10,
"*",
),
Number(
11..12,
2,
),
Number(
13..14,
5,
),
],
),
],
),
],
),
)

View file

@ -0,0 +1,60 @@
---
source: src/main.rs
expression: "p.parse(r#\"{:key value 12 \"hi\" (test) (1 2 3)}\"#)"
---
Ok(
Table(
0..35,
[
(
Keyword(
1..5,
":key",
),
Symbol(
6..11,
"value",
),
),
(
Number(
12..14,
12,
),
Str(
15..19,
"hi",
),
),
(
List(
20..26,
[
Symbol(
21..25,
"test",
),
],
),
List(
27..34,
[
Number(
28..29,
1,
),
Number(
30..31,
2,
),
Number(
32..33,
3,
),
],
),
),
],
),
)

View file

@ -0,0 +1,10 @@
---
source: src/main.rs
expression: "p.parse(r#\"; test\"#)"
---
Ok(
Comment(
0..6,
),
)

View file

@ -0,0 +1,27 @@
---
source: src/main.rs
expression: "p.parse(r#\"(f arg ; test\n arg2)\"#)"
---
Ok(
List(
0..24,
[
Symbol(
1..2,
"f",
),
Symbol(
3..6,
"arg",
),
Comment(
7..13,
),
Symbol(
19..23,
"arg2",
),
],
),
)

View file

@ -0,0 +1,16 @@
---
source: src/main.rs
expression: "p.parse(\"(12)\")"
---
Ok(
List(
0..4,
[
Number(
1..3,
12,
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(\"(1 2)\")"
---
Ok(
List(
0..5,
[
Number(
1..2,
1,
),
Number(
3..4,
2,
),
],
),
)

View file

@ -0,0 +1,24 @@
---
source: src/main.rs
expression: "p.parse(\"(1 :foo 1)\")"
---
Ok(
List(
0..10,
[
Number(
1..2,
1,
),
Keyword(
3..7,
":foo",
),
Number(
8..9,
1,
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(\"(:foo 1)\")"
---
Ok(
List(
0..8,
[
Keyword(
1..5,
":foo",
),
Number(
6..7,
1,
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(\"(:foo->: 1)\")"
---
Ok(
List(
0..11,
[
Keyword(
1..8,
":foo->:",
),
Number(
9..10,
1,
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(\"(foo 1)\")"
---
Ok(
List(
0..7,
[
Symbol(
1..4,
"foo",
),
Number(
5..6,
1,
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(\"(lol😄 1)\")"
---
Ok(
List(
0..11,
[
Symbol(
1..8,
"lol😄",
),
Number(
9..10,
1,
),
],
),
)

View file

@ -0,0 +1,20 @@
---
source: src/main.rs
expression: "p.parse(r#\"(test \"hi\")\"#)"
---
Ok(
List(
0..11,
[
Symbol(
1..5,
"test",
),
Str(
6..10,
"hi",
),
],
),
)

View file

@ -0,0 +1,11 @@
---
source: src/main.rs
expression: "p.parse(\"1\")"
---
Ok(
Number(
0..1,
1,
),
)