test parsing styles and wiring them up with the structure elements
This commit is contained in:
parent
ad35f289c7
commit
660f892d6c
2 changed files with 63 additions and 28 deletions
30
src/lib.rs
30
src/lib.rs
|
|
@ -5,6 +5,7 @@ use crate::parse::tokens::TokenType;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Vis {
|
pub struct Vis {
|
||||||
pub structure: VisNode,
|
pub structure: VisNode,
|
||||||
pub styles: Vec<StyleNode>,
|
pub styles: Vec<StyleNode>,
|
||||||
|
|
@ -24,17 +25,28 @@ impl Vis {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_style(&self, node: &VisNode) -> Option<&StyleNode> {
|
pub fn get_styles(&self, id: &str) -> HashMap<String, String> {
|
||||||
|
// println!("get_styles {:?}", id);
|
||||||
|
let mut styles = HashMap::new();
|
||||||
|
self.get_styles2(id, &mut styles);
|
||||||
|
styles
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_styles2(&self, id: &str, styles: &mut HashMap<String, String>) {
|
||||||
|
let node = self.get_node(id);
|
||||||
|
if let Some(node) = node {
|
||||||
|
// println!("node {:?}", node);
|
||||||
let style = self.styles.iter().find(|s| s.id_ref == node.id);
|
let style = self.styles.iter().find(|s| s.id_ref == node.id);
|
||||||
if style.is_none() && node.id != "structure" {
|
if let Some(style) = style {
|
||||||
for child in &node.children {
|
style.attributes.iter().for_each(|(k, v)| {
|
||||||
if let Some(style) = self.get_style(child) {
|
if !styles.contains_key(k) {
|
||||||
return Some(style);
|
styles.insert(k.clone(), v.clone());
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
if let Some(parent) = &node.parent {
|
||||||
|
self.get_styles2(parent, styles);
|
||||||
}
|
}
|
||||||
None
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,5 +147,5 @@ pub struct StyleNode {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ContainerType {
|
pub enum ContainerType {
|
||||||
NonGroup, // needs thinking about
|
NonGroup, // needs thinking about
|
||||||
Group,
|
Group, // the idea is that group nodes don't have style, they just bequeath it to their children
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,14 @@ pub fn parse_vis(contents: &str) -> anyhow::Result<Vis> {
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
|
|
||||||
let structure = parser.structure()?;
|
let structure = parser.structure()?;
|
||||||
|
let styles = parser.styles()?;
|
||||||
|
// println!("parsed styles{:?}", styles);
|
||||||
let mut vis = Vis {
|
let mut vis = Vis {
|
||||||
structure: VisNode::new_node("structure", None::<String>, structure),
|
structure: VisNode::new_node("structure", None::<String>, structure),
|
||||||
styles: parser.styles()?,
|
styles,
|
||||||
};
|
};
|
||||||
|
|
||||||
// add bottom up references (sorry no actual refs, but clones)
|
// add bottom up references
|
||||||
vis.structure.children.iter_mut().for_each(|node| {
|
vis.structure.children.iter_mut().for_each(|node| {
|
||||||
let c = node.clone();
|
let c = node.clone();
|
||||||
node.children.iter_mut().for_each(|child| {
|
node.children.iter_mut().for_each(|child| {
|
||||||
|
|
@ -44,6 +45,7 @@ impl Parser {
|
||||||
if self.match_token(Structure) {
|
if self.match_token(Structure) {
|
||||||
self.elements()
|
self.elements()
|
||||||
} else {
|
} else {
|
||||||
|
println!("No structure found");
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,9 +61,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn element(&mut self) -> anyhow::Result<VisNode> {
|
fn element(&mut self) -> anyhow::Result<VisNode> {
|
||||||
// println!("node {:?}", self.peek());
|
|
||||||
let id = self.id()?;
|
let id = self.id()?;
|
||||||
// println!("id {}", id);
|
|
||||||
let current = self.peek().clone();
|
let current = self.peek().clone();
|
||||||
if self.match_tokens(vec![
|
if self.match_tokens(vec![
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
|
|
@ -72,7 +72,6 @@ impl Parser {
|
||||||
self.edge(id, current)
|
self.edge(id, current)
|
||||||
} else {
|
} else {
|
||||||
let title = self.title()?;
|
let title = self.title()?;
|
||||||
// println!("title {:?}", title);
|
|
||||||
let children = if self.check(&LeftBrace) {
|
let children = if self.check(&LeftBrace) {
|
||||||
self.elements()?
|
self.elements()?
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -104,7 +103,7 @@ impl Parser {
|
||||||
|
|
||||||
fn string(&mut self) -> anyhow::Result<String> {
|
fn string(&mut self) -> anyhow::Result<String> {
|
||||||
let text = self.peek().clone();
|
let text = self.peek().clone();
|
||||||
let text = text.lexeme[1..text.lexeme.len() - 1].to_owned();
|
let text = strip_surrounding(text.lexeme);
|
||||||
self.consume(Str, "Expected quoted string")?;
|
self.consume(Str, "Expected quoted string")?;
|
||||||
Ok(text)
|
Ok(text)
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +115,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn styles(&mut self) -> anyhow::Result<Vec<StyleNode>> {
|
fn styles(&mut self) -> anyhow::Result<Vec<StyleNode>> {
|
||||||
|
// println!("styles {:?}", self.peek());
|
||||||
if self.match_token(Styles) {
|
if self.match_token(Styles) {
|
||||||
self.consume(LeftBrace, "Expected '{'")?;
|
self.consume(LeftBrace, "Expected '{'")?;
|
||||||
let mut styles = vec![];
|
let mut styles = vec![];
|
||||||
|
|
@ -130,6 +130,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style(&mut self) -> anyhow::Result<StyleNode> {
|
fn style(&mut self) -> anyhow::Result<StyleNode> {
|
||||||
|
// println!("style {:?}", self.peek());
|
||||||
if self.check(&Identifier) || self.check(&Structure) {
|
if self.check(&Identifier) || self.check(&Structure) {
|
||||||
let idref = if self.check(&Structure) {
|
let idref = if self.check(&Structure) {
|
||||||
// only structure element can also be referenced
|
// only structure element can also be referenced
|
||||||
|
|
@ -137,10 +138,17 @@ impl Parser {
|
||||||
} else {
|
} else {
|
||||||
self.peek().lexeme.to_owned()
|
self.peek().lexeme.to_owned()
|
||||||
};
|
};
|
||||||
|
// println!("idref {:?}", idref);
|
||||||
self.advance();
|
self.advance();
|
||||||
let containertype = self.containertype()?;
|
let containertype = self.containertype()?;
|
||||||
|
// println!("containertype {:?}", containertype);
|
||||||
self.consume(RightParen, "Expected ')'")?;
|
self.consume(RightParen, "Expected ')'")?;
|
||||||
|
if self.peek().tokentype == Colon {
|
||||||
|
// optional
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
self.consume(LeftBrace, "Expected '{'")?;
|
self.consume(LeftBrace, "Expected '{'")?;
|
||||||
|
// println!("attributes {:?}", self.peek());
|
||||||
let attributes = self.style_elements()?;
|
let attributes = self.style_elements()?;
|
||||||
self.consume(RightBrace, "Expected '}'")?;
|
self.consume(RightBrace, "Expected '}'")?;
|
||||||
|
|
||||||
|
|
@ -155,13 +163,14 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style_elements(&mut self) -> anyhow::Result<HashMap<String, String>> {
|
fn style_elements(&mut self) -> anyhow::Result<HashMap<String, String>> {
|
||||||
|
// println!("read attributes {:?}", self.peek());
|
||||||
let mut elements = HashMap::new();
|
let mut elements = HashMap::new();
|
||||||
let mut key = self.peek().clone();
|
let mut key = self.peek().clone();
|
||||||
while key.tokentype != RightBrace {
|
while key.tokentype != RightBrace {
|
||||||
self.advance();
|
self.advance();
|
||||||
self.consume(Colon, "Expected ':'")?;
|
self.consume(Colon, "Expected ':'")?;
|
||||||
let value = self.advance().clone();
|
let value = self.advance().clone();
|
||||||
elements.insert(key.lexeme.to_owned(), value.lexeme);
|
elements.insert(key.lexeme.to_owned(), strip_surrounding(value.lexeme));
|
||||||
key = self.peek().clone();
|
key = self.peek().clone();
|
||||||
}
|
}
|
||||||
Ok(elements)
|
Ok(elements)
|
||||||
|
|
@ -241,24 +250,34 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn strip_surrounding(s: String) -> String {
|
||||||
|
s[1..s.len() - 1].to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::NodeType::Node;
|
use crate::NodeType::Node;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse() {
|
fn test_parse() {
|
||||||
let contents = r#"structure {
|
let vis_source = r#"
|
||||||
|
structure {
|
||||||
top: "top-node" {
|
top: "top-node" {
|
||||||
child: "child-node" {
|
child: "child-node" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"#;
|
}
|
||||||
let vis = crate::parse::parser::parse_vis(contents).ok();
|
styles {
|
||||||
|
top(group) {
|
||||||
|
orientation: "vertical";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let vis = crate::parse::parser::parse_vis(vis_source).ok();
|
||||||
|
|
||||||
assert!(vis.is_some(), "Parsed structure should not be None");
|
assert!(vis.is_some(), "Parsed structure should not be None");
|
||||||
|
|
||||||
if let Some(vis) = vis {
|
if let Some(vis) = vis {
|
||||||
// Validate the parsed structure by asserting its elements
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vis.structure.children.len(),
|
vis.structure.children.len(),
|
||||||
1,
|
1,
|
||||||
|
|
@ -266,15 +285,15 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
if vis.structure.children[0].node_type == Node {
|
if vis.structure.children[0].node_type == Node {
|
||||||
let node = &vis.structure.children[0];
|
let top = &vis.structure.children[0];
|
||||||
assert_eq!(node.id, "top", "The ID of the first node should be 'top'");
|
assert_eq!(top.id, "top", "The ID of the first node should be 'top'");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
node.label.as_ref().unwrap(),
|
top.label.as_ref().unwrap(),
|
||||||
&"top-node".to_owned(),
|
&"top-node".to_owned(),
|
||||||
"The title of the first node should be 'top-node'"
|
"The title of the first node should be 'top-node'"
|
||||||
);
|
);
|
||||||
assert_eq!(node.children.len(), 1);
|
assert_eq!(top.children.len(), 1);
|
||||||
let child = &node.children[0];
|
let child = &top.children[0];
|
||||||
if child.node_type == Node {
|
if child.node_type == Node {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
child.id, "child",
|
child.id, "child",
|
||||||
|
|
@ -290,6 +309,10 @@ mod tests {
|
||||||
} else {
|
} else {
|
||||||
panic!("The top-level element should be a Node");
|
panic!("The top-level element should be a Node");
|
||||||
}
|
}
|
||||||
|
assert_eq!(vis.styles.len(), 1);
|
||||||
|
let styles = vis.get_styles("top");
|
||||||
|
assert_eq!(styles.len(), 1);
|
||||||
|
assert_eq!(styles["orientation"], "vertical");
|
||||||
} else {
|
} else {
|
||||||
panic!("Parsed structure was unexpectedly None");
|
panic!("Parsed structure was unexpectedly None");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue