mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Simplification and comments for XML parser
This commit is contained in:
parent
ba9caf941c
commit
58992ba8ad
5 changed files with 132 additions and 75 deletions
|
@ -13,6 +13,7 @@ pub struct AttributeParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttributeParser {
|
impl AttributeParser {
|
||||||
|
// Prebuild all the regex patterns
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let capture_attribute_declaration_parameter_regex: regex::Regex = regex::Regex::new(
|
let capture_attribute_declaration_parameter_regex: regex::Regex = regex::Regex::new(
|
||||||
// Parameter: ?: (?, ... | ...) = ?
|
// Parameter: ?: (?, ... | ...) = ?
|
||||||
|
@ -85,44 +86,44 @@ impl AttributeParser {
|
||||||
Some(["{{", name, "}}"]) => {
|
Some(["{{", name, "}}"]) => {
|
||||||
let name = String::from(*name);
|
let name = String::from(*name);
|
||||||
TypeValueOrArgument::VariableArgument(VariableArgument::new(name))
|
TypeValueOrArgument::VariableArgument(VariableArgument::new(name))
|
||||||
}
|
},
|
||||||
// Integer: ?
|
// Integer: ?
|
||||||
Some([value]) if self.match_integer_regex.is_match(value) => {
|
Some([value]) if self.match_integer_regex.is_match(value) => {
|
||||||
let integer = value.parse::<i64>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
let integer = value.parse::<i64>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Integer(integer))
|
TypeValueOrArgument::TypeValue(TypeValue::Integer(integer))
|
||||||
}
|
},
|
||||||
// Decimal: ?
|
// Decimal: ?
|
||||||
Some([value]) if self.match_decimal_regex.is_match(value) => {
|
Some([value]) if self.match_decimal_regex.is_match(value) => {
|
||||||
let decimal = value.parse::<f64>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
let decimal = value.parse::<f64>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Decimal(decimal))
|
TypeValueOrArgument::TypeValue(TypeValue::Decimal(decimal))
|
||||||
}
|
},
|
||||||
// AbsolutePx: px
|
// AbsolutePx: px
|
||||||
Some([value, px]) if px.eq_ignore_ascii_case("px") => {
|
Some([value, px]) if px.eq_ignore_ascii_case("px") => {
|
||||||
let pixels = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type`{}` when parsing XML layout", value, attribute_type)[..]);
|
let pixels = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type`{}` when parsing XML layout", value, attribute_type)[..]);
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::AbsolutePx(pixels))
|
TypeValueOrArgument::TypeValue(TypeValue::AbsolutePx(pixels))
|
||||||
}
|
},
|
||||||
// Percent: ?%
|
// Percent: ?%
|
||||||
Some([value, "%"]) => {
|
Some([value, "%"]) => {
|
||||||
let percent = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
let percent = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Percent(percent))
|
TypeValueOrArgument::TypeValue(TypeValue::Percent(percent))
|
||||||
}
|
},
|
||||||
// PercentRemainder: ?@
|
// PercentRemainder: ?@
|
||||||
Some([value, "@"]) => {
|
Some([value, "@"]) => {
|
||||||
let percent_remainder = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
let percent_remainder = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::PercentRemainder(percent_remainder))
|
TypeValueOrArgument::TypeValue(TypeValue::PercentRemainder(percent_remainder))
|
||||||
}
|
},
|
||||||
// Inner: inner
|
// Inner: inner
|
||||||
Some([inner]) if inner.eq_ignore_ascii_case("inner") => {
|
Some([inner]) if inner.eq_ignore_ascii_case("inner") => {
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Inner)
|
TypeValueOrArgument::TypeValue(TypeValue::Inner)
|
||||||
}
|
},
|
||||||
// Width: width
|
// Width: width
|
||||||
Some([width]) if width.eq_ignore_ascii_case("width") => {
|
Some([width]) if width.eq_ignore_ascii_case("width") => {
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Width)
|
TypeValueOrArgument::TypeValue(TypeValue::Width)
|
||||||
}
|
},
|
||||||
// Height: height
|
// Height: height
|
||||||
Some([height]) if height.eq_ignore_ascii_case("height") => {
|
Some([height]) if height.eq_ignore_ascii_case("height") => {
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Height)
|
TypeValueOrArgument::TypeValue(TypeValue::Height)
|
||||||
}
|
},
|
||||||
// TemplateString: `? ... {{?}} ...`
|
// TemplateString: `? ... {{?}} ...`
|
||||||
Some(["`", string, "`"]) => {
|
Some(["`", string, "`"]) => {
|
||||||
let mut segments = Vec::<TemplateStringSegment>::new();
|
let mut segments = Vec::<TemplateStringSegment>::new();
|
||||||
|
@ -138,7 +139,7 @@ impl AttributeParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::TemplateString(segments))
|
TypeValueOrArgument::TypeValue(TypeValue::TemplateString(segments))
|
||||||
}
|
},
|
||||||
// Color: [?]
|
// Color: [?]
|
||||||
Some(["[", color_name, "]"]) => {
|
Some(["[", color_name, "]"]) => {
|
||||||
let color = match self.capture_color_name_in_palette_regex.captures(color_name) {
|
let color = match self.capture_color_name_in_palette_regex.captures(color_name) {
|
||||||
|
@ -154,16 +155,16 @@ impl AttributeParser {
|
||||||
};
|
};
|
||||||
|
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Color(color))
|
TypeValueOrArgument::TypeValue(TypeValue::Color(color))
|
||||||
}
|
},
|
||||||
// Bool: true/false
|
// Bool: true/false
|
||||||
Some([true_or_false]) if true_or_false.eq_ignore_ascii_case("true") || true_or_false.eq_ignore_ascii_case("false") => {
|
Some([true_or_false]) if true_or_false.eq_ignore_ascii_case("true") || true_or_false.eq_ignore_ascii_case("false") => {
|
||||||
let boolean = true_or_false.eq_ignore_ascii_case("true");
|
let boolean = true_or_false.eq_ignore_ascii_case("true");
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::Bool(boolean))
|
TypeValueOrArgument::TypeValue(TypeValue::Bool(boolean))
|
||||||
}
|
},
|
||||||
// None: none
|
// None: none
|
||||||
Some([none]) if none.eq_ignore_ascii_case("none") => {
|
Some([none]) if none.eq_ignore_ascii_case("none") => {
|
||||||
TypeValueOrArgument::TypeValue(TypeValue::None)
|
TypeValueOrArgument::TypeValue(TypeValue::None)
|
||||||
}
|
},
|
||||||
// Unrecognized type pattern
|
// Unrecognized type pattern
|
||||||
_ => panic!("Invalid attribute type `{}` when parsing XML layout", attribute_type),
|
_ => panic!("Invalid attribute type `{}` when parsing XML layout", attribute_type),
|
||||||
}
|
}
|
||||||
|
@ -216,13 +217,13 @@ impl AttributeParser {
|
||||||
TypeValueOrArgument::TypeValue(type_value) => type_value,
|
TypeValueOrArgument::TypeValue(type_value) => type_value,
|
||||||
TypeValueOrArgument::VariableArgument(variable_value) => {
|
TypeValueOrArgument::VariableArgument(variable_value) => {
|
||||||
panic!("Found the default variable value `{:?}` in the attribute declaration `{}` which only allows typed values, when parsing XML layout", variable_value, attribute_declaration);
|
panic!("Found the default variable value `{:?}` in the attribute declaration `{}` which only allows typed values, when parsing XML layout", variable_value, attribute_declaration);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
).collect::<Vec<TypeValue>>();
|
).collect::<Vec<TypeValue>>();
|
||||||
|
|
||||||
// Return the parameter
|
// Return the parameter
|
||||||
AttributeValue::VariableParameter(VariableParameter::new(name, type_sequence_options, default_type_sequence))
|
AttributeValue::VariableParameter(VariableParameter::new(name, type_sequence_options, default_type_sequence))
|
||||||
}
|
},
|
||||||
// Unrecognized type pattern
|
// Unrecognized type pattern
|
||||||
_ => panic!("Invalid attribute attribute declaration `{}` when parsing XML layout", attribute_declaration),
|
_ => panic!("Invalid attribute attribute declaration `{}` when parsing XML layout", attribute_declaration),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pub struct LayoutDomNode {
|
||||||
|
// pub namespace: String,
|
||||||
|
// pub name: String,
|
||||||
|
// pub placement:
|
||||||
|
// // pub body: Vec<LayoutDomNode>
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub struct LayoutPlacement {
|
||||||
|
// pub width: f32,
|
||||||
|
// pub height: f32,
|
||||||
|
// pub x_align:
|
||||||
|
// }
|
|
@ -24,6 +24,8 @@ impl LayoutSystem {
|
||||||
let xml_path = self.layout_xml_path(namespace, name);
|
let xml_path = self.layout_xml_path(namespace, name);
|
||||||
let window_main = self.parse_xml_file(&xml_path[..]).unwrap();
|
let window_main = self.parse_xml_file(&xml_path[..]).unwrap();
|
||||||
|
|
||||||
|
Self::print_layout_tree(&window_main);
|
||||||
|
|
||||||
// Keep track of it being loaded to prevent duplicate work
|
// Keep track of it being loaded to prevent duplicate work
|
||||||
let mut already_loaded_layouts = HashSet::new();
|
let mut already_loaded_layouts = HashSet::new();
|
||||||
already_loaded_layouts.insert(format!("{}:{}", namespace, name));
|
already_loaded_layouts.insert(format!("{}:{}", namespace, name));
|
||||||
|
@ -58,19 +60,21 @@ impl LayoutSystem {
|
||||||
// Recursively explore the newly loaded layout's tags
|
// Recursively explore the newly loaded layout's tags
|
||||||
self.explore_referenced_layouts(&new_loaded_layout, already_loaded_layouts);
|
self.explore_referenced_layouts(&new_loaded_layout, already_loaded_layouts);
|
||||||
|
|
||||||
|
// Save the loaded layout to the cache
|
||||||
self.loaded_layouts.set(&key_copy[..], new_loaded_layout);
|
self.loaded_layouts.set(&key_copy[..], new_loaded_layout);
|
||||||
}
|
},
|
||||||
// Tag has already been loaded
|
// Tag has already been loaded
|
||||||
Some(_) => {}
|
Some(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
// Text nodes don't need to be loaded
|
// Text nodes don't need to be loaded
|
||||||
LayoutAbstractNode::Text(_) => {}
|
LayoutAbstractNode::Text(_) => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the "namespace:name" format of string given a namespace and layout name
|
||||||
fn layout_name(&self, namespace: &str, name: &str) -> String {
|
fn layout_name(&self, namespace: &str, name: &str) -> String {
|
||||||
if namespace.len() > 0 {
|
if namespace.len() > 0 {
|
||||||
format!("{}:{}", namespace, name)
|
format!("{}:{}", namespace, name)
|
||||||
|
@ -80,6 +84,7 @@ impl LayoutSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the XML file path given a namespace and layout name
|
||||||
fn layout_xml_path(&self, namespace: &str, name: &str) -> String {
|
fn layout_xml_path(&self, namespace: &str, name: &str) -> String {
|
||||||
if namespace.len() > 0 {
|
if namespace.len() > 0 {
|
||||||
format!("gui/{}/{}.xml", namespace, name)
|
format!("gui/{}/{}.xml", namespace, name)
|
||||||
|
@ -89,113 +94,152 @@ impl LayoutSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get an abstract syntax tree root node representing a parsed XML layout file
|
||||||
fn parse_xml_file(&self, path: &str) -> io::Result<rctree::Node<LayoutAbstractNode>> {
|
fn parse_xml_file(&self, path: &str) -> io::Result<rctree::Node<LayoutAbstractNode>> {
|
||||||
|
// XML layout file markup source code
|
||||||
let source = fs::read_to_string(path)?;
|
let source = fs::read_to_string(path)?;
|
||||||
let parsed = xmlparser::Tokenizer::from(&source[..]);
|
// XML document parser that feeds token-by-token through the file
|
||||||
|
let parser = xmlparser::Tokenizer::from(&source[..]);
|
||||||
|
|
||||||
|
// Node stack used to collect descendant nodes while reading deeper into the tree until each reaches its closing tag
|
||||||
let mut stack: Vec<rctree::Node<LayoutAbstractNode>> = Vec::new();
|
let mut stack: Vec<rctree::Node<LayoutAbstractNode>> = Vec::new();
|
||||||
let mut current: Option<rctree::Node<LayoutAbstractNode>> = None;
|
// Opening XML tag used to collect the tag name and its various attributes
|
||||||
let mut result: Option<rctree::Node<LayoutAbstractNode>> = None;
|
let mut current_opening_tag: Option<LayoutAbstractNode> = None;
|
||||||
|
// Top-level node that is popped from the stack when the closing tag is reached at the end of the XML document
|
||||||
|
let mut final_result: Option<rctree::Node<LayoutAbstractNode>> = None;
|
||||||
|
|
||||||
let mut parsing_root_tag_with_declarations = true;
|
for token in parser {
|
||||||
|
|
||||||
for token in parsed {
|
|
||||||
match token.unwrap() {
|
match token.unwrap() {
|
||||||
|
// Beginning of an opening tag (<NAMESPACE:NAME ...)
|
||||||
xmlparser::Token::ElementStart { prefix, local, .. } => {
|
xmlparser::Token::ElementStart { prefix, local, .. } => {
|
||||||
|
// Get the supplied namespace and tag name as owned strings
|
||||||
let namespace = String::from(prefix.as_str());
|
let namespace = String::from(prefix.as_str());
|
||||||
let tag_name = String::from(local.as_str());
|
let tag_name = String::from(local.as_str());
|
||||||
|
|
||||||
let new_parsed_layout_node = LayoutAbstractNode::new_tag(namespace, tag_name);
|
// Construct an AST tag node with the namespace and tag name
|
||||||
|
let abstract_tag_node = LayoutAbstractNode::new_tag(namespace, tag_name);
|
||||||
|
|
||||||
let new_node = rctree::Node::new(new_parsed_layout_node);
|
// Store the AST node while attributes are added until the opening (or self-closing) tag ends
|
||||||
current = Some(new_node);
|
current_opening_tag = Some(abstract_tag_node);
|
||||||
}
|
},
|
||||||
|
// Any attributes within the current opening tag (... ATTRIBUTE="VALUE" ...)
|
||||||
xmlparser::Token::Attribute { prefix, local, value, .. } => {
|
xmlparser::Token::Attribute { prefix, local, value, .. } => {
|
||||||
|
// Check if the attribute has an empty prefix (thus, only a colon)
|
||||||
let colon_prefixed = prefix.start() > 0 && (prefix.start() == prefix.end());
|
let colon_prefixed = prefix.start() > 0 && (prefix.start() == prefix.end());
|
||||||
|
// Set the name to the given name, possibly with a prepended colon
|
||||||
let name = if colon_prefixed {
|
let name = if colon_prefixed {
|
||||||
let slice = local.as_str();
|
let slice = local.as_str();
|
||||||
let mut string = String::with_capacity(slice.len() + 1);
|
let mut string = String::with_capacity(slice.len() + 1);
|
||||||
string.push(':');
|
string.push(':');
|
||||||
string.push_str(slice);
|
string.push_str(slice);
|
||||||
string
|
string
|
||||||
} else { String::from(local.as_str()) };
|
} else {
|
||||||
|
String::from(local.as_str())
|
||||||
|
};
|
||||||
|
// Set the value to an ordinary string slice of the given value
|
||||||
let value = value.as_str();
|
let value = value.as_str();
|
||||||
|
|
||||||
let attribute = if parsing_root_tag_with_declarations {
|
// Attributes on the root element are parameter declarations that list the names and types of permitted variables
|
||||||
|
let attribute = if stack.is_empty() {
|
||||||
let parameter_declaration = self.attribute_parser.parse_attribute_declaration(value);
|
let parameter_declaration = self.attribute_parser.parse_attribute_declaration(value);
|
||||||
Attribute::new(name, parameter_declaration)
|
Attribute::new(name, parameter_declaration)
|
||||||
}
|
}
|
||||||
|
// Attributes on elements inside the root are arguments to the layout engine (no colon prefix) or the child layout (colon prefix)
|
||||||
else {
|
else {
|
||||||
let parameter_types = self.attribute_parser.parse_attribute_types(value);
|
let parameter_types = self.attribute_parser.parse_attribute_types(value);
|
||||||
Attribute::new(name, parameter_types)
|
Attribute::new(name, parameter_types)
|
||||||
};
|
};
|
||||||
|
|
||||||
match &mut current {
|
// Add the new attribute to the current yet-to-be-closed element
|
||||||
Some(current_node) => {
|
match &mut current_opening_tag {
|
||||||
match &mut *current_node.borrow_mut() {
|
// The opening tag is indeed a tag AST node
|
||||||
LayoutAbstractNode::Tag(tag) => {
|
Some(LayoutAbstractNode::Tag(tag)) => {
|
||||||
// Add this attribute to the current node that has not yet reached its closing angle bracket
|
tag.add_attribute(attribute);
|
||||||
tag.add_attribute(attribute);
|
},
|
||||||
}
|
// Somehow the current opening tag is actually a text node (probably impossible)
|
||||||
LayoutAbstractNode::Text(text) => {
|
Some(LayoutAbstractNode::Text(text)) => {
|
||||||
panic!("Unexpected text attribute {} attemping to be added to tag when parsing XML layout in file: {}", text, path);
|
panic!("Unexpected text attribute {} attemping to be added to tag when parsing XML layout in file: {}", text, path);
|
||||||
}
|
},
|
||||||
}
|
// Somehow there is no current opening tag to add this attribute to (probably impossible)
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
panic!("Error adding attribute to tag when parsing XML layout in file: {}", path);
|
panic!("Error adding attribute to tag when parsing XML layout in file: {}", path);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
// Either the end of the opening tag (...>) or the end of a self-closing tag (.../>) or an entire closing tag (</NAMESPACE:NAME>)
|
||||||
xmlparser::Token::ElementEnd { end, .. } => {
|
xmlparser::Token::ElementEnd { end, .. } => {
|
||||||
match end {
|
match end {
|
||||||
// After adding any attributes, the opening tag ends
|
// After adding any attributes, this element's opening tag ends (...>)
|
||||||
xmlparser::ElementEnd::Open => {
|
xmlparser::ElementEnd::Open => {
|
||||||
// After adding any attributes, we are now a layer deeper which the stack keeps track of
|
// After adding any attributes, we are now a layer deeper in the stack of yet-to-be-closed descendants
|
||||||
let node_to_push = current.take().expect(&format!("Invalid syntax when parsing XML layout in file {}", path)[..]);
|
let current_abstract_node = current_opening_tag.take().expect(&format!("Invalid syntax when parsing XML layout in file {}", path)[..]);
|
||||||
stack.push(node_to_push);
|
let tree_node_with_descendants = rctree::Node::new(current_abstract_node);
|
||||||
parsing_root_tag_with_declarations = false;
|
stack.push(tree_node_with_descendants);
|
||||||
}
|
},
|
||||||
// After adding any attributes, the self-closing tag ends
|
// After adding any attributes, this element's self-closing tag ends (.../>)
|
||||||
xmlparser::ElementEnd::Empty => {
|
xmlparser::ElementEnd::Empty => {
|
||||||
|
// Because a self-closing element does not go deeper, attach this now-complete node directly to its parent
|
||||||
let parent_node = stack.last_mut().expect(&format!("Invalid syntax when parsing XML layout in file: {}", path)[..]);
|
let parent_node = stack.last_mut().expect(&format!("Invalid syntax when parsing XML layout in file: {}", path)[..]);
|
||||||
let new_child = current.take().expect(&format!("Invalid syntax when parsing XML layout in file: {}", path)[..]);
|
let current_abstract_node = current_opening_tag.take().expect(&format!("Invalid syntax when parsing XML layout in file: {}", path)[..]);
|
||||||
parent_node.append(new_child);
|
let tree_node = rctree::Node::new(current_abstract_node);
|
||||||
}
|
parent_node.append(tree_node);
|
||||||
// The closing tag is reached
|
},
|
||||||
|
// After visiting any descendants inside the opening tag, finally the closing tag is reached (</NAMESPACE:NAME>)
|
||||||
xmlparser::ElementEnd::Close(..) => {
|
xmlparser::ElementEnd::Close(..) => {
|
||||||
let popped_node = stack.pop().expect(&format!("Encountered extra closing tag when parsing XML layout in file: {}", path)[..]);
|
// Pop the element now that descendants have been parsed and we make our way back up the tree one level
|
||||||
|
let closed_node_with_descendants = stack.pop().expect(&format!("Encountered extra closing tag when parsing XML layout in file: {}", path)[..]);
|
||||||
|
|
||||||
|
// Append this now-complete node to its parent, unless there is no parent, in which case we save this root node as the final result
|
||||||
match stack.last_mut() {
|
match stack.last_mut() {
|
||||||
|
// If a parent node exists
|
||||||
Some(parent_node) => {
|
Some(parent_node) => {
|
||||||
parent_node.append(popped_node);
|
parent_node.append(closed_node_with_descendants);
|
||||||
}
|
},
|
||||||
|
// If this is the root node
|
||||||
None => {
|
None => {
|
||||||
match result {
|
match final_result {
|
||||||
None => result = Some(popped_node),
|
// Save the root element as the final result
|
||||||
|
None => final_result = Some(closed_node_with_descendants),
|
||||||
|
// There can only be one root element in the XML document, but this isn't the first one encountered
|
||||||
Some(_) => panic!("Encountered multiple root-level tags when parsing XML layout in file: {}", path),
|
Some(_) => panic!("Encountered multiple root-level tags when parsing XML layout in file: {}", path),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
// A text node in the space between sibling elements (... SOME TEXT ...)
|
||||||
xmlparser::Token::Text { text } => {
|
xmlparser::Token::Text { text } => {
|
||||||
let parent_node = stack.last_mut().expect(&format!("Encountered text outside the root tag when parsing XML layout in file: {}", path)[..]);
|
// Trim any whitespace from around the string
|
||||||
let text_string = String::from(text.as_str());
|
let text_string = String::from(text.as_str().trim());
|
||||||
|
|
||||||
|
// If the string isn't all whitespace, append a new text node to the parent
|
||||||
|
if !text_string.is_empty() {
|
||||||
|
// Get the tree node which contains this text
|
||||||
|
let parent_node = stack.last_mut().expect(&format!("Encountered text outside the root tag when parsing XML layout in file: {}", path)[..]);
|
||||||
|
|
||||||
if !text_string.trim().is_empty() {
|
// Construct an AST text node with the provided text
|
||||||
let text_node = LayoutAbstractNode::new_text(text_string);
|
let abstract_text_node = LayoutAbstractNode::new_text(text_string);
|
||||||
let new_node = rctree::Node::new(text_node);
|
// Put the AST text node in a new tree node
|
||||||
parent_node.append(new_node);
|
let new_tree_node = rctree::Node::new(abstract_text_node);
|
||||||
|
|
||||||
|
// Attach the new text node on the parent in the tree which contains this text
|
||||||
|
parent_node.append(new_tree_node);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
match final_result {
|
||||||
None => panic!("Invalid syntax when parsing XML layout in file: {}", path),
|
None => panic!("Invalid syntax when parsing XML layout in file: {}", path),
|
||||||
Some(tree) => Ok(tree)
|
Some(tree) => Ok(tree),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_layout_tree(tree_root: &rctree::Node<LayoutAbstractNode>) {
|
||||||
|
for node in tree_root.descendants() {
|
||||||
|
println!("{:?}", node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,7 +46,7 @@ impl<T> ResourceCache<T> {
|
||||||
let id = CacheID::new(last_index);
|
let id = CacheID::new(last_index);
|
||||||
self.name_to_id.insert(String::from(name), id);
|
self.name_to_id.insert(String::from(name), id);
|
||||||
self.resources.push(resource);
|
self.resources.push(resource);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ pub fn compile_from_glsl(device: &wgpu::Device, path: &str, shader_type: glsl_to
|
||||||
Err(message) => {
|
Err(message) => {
|
||||||
println!("Error compiling GLSL to SPIRV shader: {}", message);
|
println!("Error compiling GLSL to SPIRV shader: {}", message);
|
||||||
panic!("{}", message);
|
panic!("{}", message);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let compiled = wgpu::read_spirv(spirv)?;
|
let compiled = wgpu::read_spirv(spirv)?;
|
||||||
let shader = device.create_shader_module(&compiled);
|
let shader = device.create_shader_module(&compiled);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue