Update attribute parser with refactored symbol names and coments

This commit is contained in:
Keavon Chambers 2020-11-01 01:43:21 -07:00
parent 0eed8878ff
commit 400e9477f4
1 changed files with 34 additions and 35 deletions

View File

@ -4,7 +4,7 @@ use crate::layout_abstract_types::*;
use crate::layout_system::*; use crate::layout_system::*;
pub struct AttributeParser { pub struct AttributeParser {
capture_attribute_declaration_parameter_regex: regex::Regex, capture_attribute_prop_definition_regex: regex::Regex,
capture_attribute_type_sequences_regex: regex::Regex, capture_attribute_type_sequences_regex: regex::Regex,
match_integer_regex: regex::Regex, match_integer_regex: regex::Regex,
match_decimal_regex: regex::Regex, match_decimal_regex: regex::Regex,
@ -15,8 +15,8 @@ pub struct AttributeParser {
impl AttributeParser { impl AttributeParser {
// Prebuild all the regex patterns // 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_prop_definition_regex: regex::Regex = regex::Regex::new(
// Parameter: ?: (?, ... | ...) = ? // Prop definition: ?: (?, ... | ...) = ?
r"^\s*(\w*)\s*(:)\s*(\()\s*((?:(?:\w+)(?:\s*,\s*\w+)*)(?:\s*\|\s*(?:(?:\w+)(?:\s*,\s*\w+)*))*)\s*(\))\s*(=)\s*([\s\w'\[\]@%\-.,]+|`[^`]*`|\[\[.*\]\])\s*$", r"^\s*(\w*)\s*(:)\s*(\()\s*((?:(?:\w+)(?:\s*,\s*\w+)*)(?:\s*\|\s*(?:(?:\w+)(?:\s*,\s*\w+)*))*)\s*(\))\s*(=)\s*([\s\w'\[\]@%\-.,]+|`[^`]*`|\[\[.*\]\])\s*$",
) )
.unwrap(); .unwrap();
@ -62,7 +62,7 @@ impl AttributeParser {
let capture_color_name_in_palette_regex = regex::Regex::new(r"\s*'(.*)'\s*").unwrap(); let capture_color_name_in_palette_regex = regex::Regex::new(r"\s*'(.*)'\s*").unwrap();
Self { Self {
capture_attribute_declaration_parameter_regex, capture_attribute_prop_definition_regex,
capture_attribute_type_sequences_regex, capture_attribute_type_sequences_regex,
match_integer_regex, match_integer_regex,
match_decimal_regex, match_decimal_regex,
@ -71,16 +71,16 @@ impl AttributeParser {
} }
} }
pub fn parse_attribute_argument_types(&self, input: &str) -> Vec<TypeValueOrArgument> { pub fn parse_attribute_argument_types(&self, input: &str) -> Vec<TypedValueOrVariableName> {
let attribute_types = input.split(",").map(|piece| piece.trim()).collect::<Vec<&str>>(); let attribute_types = input.split(",").map(|piece| piece.trim()).collect::<Vec<&str>>();
let list = attribute_types let list = attribute_types
.iter() .iter()
.map(|attribute_type| self.parse_attribute_argument_type(attribute_type)) .map(|attribute_type| self.parse_attribute_argument_type(attribute_type))
.collect::<Vec<TypeValueOrArgument>>(); .collect::<Vec<TypedValueOrVariableName>>();
list list
} }
pub fn parse_attribute_argument_type(&self, attribute_type: &str) -> TypeValueOrArgument { pub fn parse_attribute_argument_type(&self, attribute_type: &str) -> TypedValueOrVariableName {
// Match with the regular expression // Match with the regular expression
let captures = self let captures = self
.capture_attribute_type_sequences_regex .capture_attribute_type_sequences_regex
@ -90,8 +90,8 @@ impl AttributeParser {
// Match against the captured values as a list of tokens // Match against the captured values as a list of tokens
let tokens = captures.as_ref().map(|c| c.as_slice()); let tokens = captures.as_ref().map(|c| c.as_slice());
match tokens { match tokens {
// Argument: {{?}} // Variable name: {{?}}
Some(["{{", name, "}}"]) => TypeValueOrArgument::VariableArgument(String::from(*name)), Some(["{{", name, "}}"]) => TypedValueOrVariableName::VariableName(String::from(*name)),
// Layout: [[?]] // Layout: [[?]]
Some(["[[", xml_syntax, "]]"]) => { Some(["[[", xml_syntax, "]]"]) => {
// Remove any whitespace in order to test if any XML syntax is present // Remove any whitespace in order to test if any XML syntax is present
@ -109,21 +109,21 @@ impl AttributeParser {
}; };
// Return the `Layout` typed value with the empty vector or vector with the parsed XML fragment // Return the `Layout` typed value with the empty vector or vector with the parsed XML fragment
TypeValueOrArgument::TypeValue(TypeValue::Layout(layout_entries)) TypedValueOrVariableName::TypedValue(TypedValue::Layout(layout_entries))
}, },
// 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 let integer = value
.parse::<i64>() .parse::<i64>()
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]); .expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
TypeValueOrArgument::TypeValue(TypeValue::Integer(integer)) TypedValueOrVariableName::TypedValue(TypedValue::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 let decimal = value
.parse::<f64>() .parse::<f64>()
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]); .expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
TypeValueOrArgument::TypeValue(TypeValue::Decimal(decimal)) TypedValueOrVariableName::TypedValue(TypedValue::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") => {
@ -131,7 +131,7 @@ impl AttributeParser {
.parse::<f64>() .parse::<f64>()
.expect(&format!("Invalid value `{}` specified in the attribute type`{}` when parsing XML layout", value, attribute_type)[..]); .expect(&format!("Invalid value `{}` specified in the attribute type`{}` when parsing XML layout", value, attribute_type)[..]);
let dimension = Dimension::AbsolutePx(pixels); let dimension = Dimension::AbsolutePx(pixels);
TypeValueOrArgument::TypeValue(TypeValue::Dimension(dimension)) TypedValueOrVariableName::TypedValue(TypedValue::Dimension(dimension))
}, },
// Percent: ?% // Percent: ?%
Some([value, "%"]) => { Some([value, "%"]) => {
@ -139,7 +139,7 @@ impl AttributeParser {
.parse::<f64>() .parse::<f64>()
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]); .expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
let dimension = Dimension::Percent(percent); let dimension = Dimension::Percent(percent);
TypeValueOrArgument::TypeValue(TypeValue::Dimension(dimension)) TypedValueOrVariableName::TypedValue(TypedValue::Dimension(dimension))
}, },
// PercentRemainder: ?@ // PercentRemainder: ?@
Some([value, "@"]) => { Some([value, "@"]) => {
@ -147,19 +147,18 @@ impl AttributeParser {
.parse::<f64>() .parse::<f64>()
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]); .expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
let dimension = Dimension::PercentRemainder(percent_remainder); let dimension = Dimension::PercentRemainder(percent_remainder);
TypeValueOrArgument::TypeValue(TypeValue::Dimension(dimension)) TypedValueOrVariableName::TypedValue(TypedValue::Dimension(dimension))
}, },
// Inner: inner // Inner: inner
Some([inner]) if inner.eq_ignore_ascii_case("inner") => TypeValueOrArgument::TypeValue(TypeValue::Dimension(Dimension::Inner)), Some([inner]) if inner.eq_ignore_ascii_case("inner") => TypedValueOrVariableName::TypedValue(TypedValue::Dimension(Dimension::Inner)),
// Width: width // Width: width
Some([width]) if width.eq_ignore_ascii_case("width") => TypeValueOrArgument::TypeValue(TypeValue::Dimension(Dimension::Width)), Some([width]) if width.eq_ignore_ascii_case("width") => TypedValueOrVariableName::TypedValue(TypedValue::Dimension(Dimension::Width)),
// Height: height // Height: height
Some([height]) if height.eq_ignore_ascii_case("height") => TypeValueOrArgument::TypeValue(TypeValue::Dimension(Dimension::Height)), Some([height]) if height.eq_ignore_ascii_case("height") => TypedValueOrVariableName::TypedValue(TypedValue::Dimension(Dimension::Height)),
// TemplateString: `? ... {{?}} ...` // TemplateString: `? ... {{?}} ...`
Some(["`", string, "`"]) => { Some(["`", string, "`"]) => {
let segments = self.parse_text_template_sequence(string); let segments = self.parse_text_template_sequence(string);
TypedValueOrVariableName::TypedValue(TypedValue::TemplateString(segments))
TypeValueOrArgument::TypeValue(TypeValue::TemplateString(segments))
}, },
// Color: [?] // Color: [?]
Some(["[", color_name, "]"]) => { Some(["[", color_name, "]"]) => {
@ -193,33 +192,33 @@ impl AttributeParser {
}, },
}; };
TypeValueOrArgument::TypeValue(TypeValue::Color(color)) TypedValueOrVariableName::TypedValue(TypedValue::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)) TypedValueOrVariableName::TypedValue(TypedValue::Bool(boolean))
}, },
// None: none // None: none
Some([none]) if none.eq_ignore_ascii_case("none") => TypeValueOrArgument::TypeValue(TypeValue::None), Some([none]) if none.eq_ignore_ascii_case("none") => TypedValueOrVariableName::TypedValue(TypedValue::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),
} }
} }
pub fn parse_attribute_parameter_declaration(&self, attribute_declaration: &str) -> VariableParameter { pub fn parse_attribute_prop_definition(&self, attribute_declaration: &str) -> PropDefinition {
// Match with the regular expression // Match with the regular expression
let captures = self let captures = self
.capture_attribute_declaration_parameter_regex .capture_attribute_prop_definition_regex
.captures(attribute_declaration) .captures(attribute_declaration)
.map(|captures| captures.iter().skip(1).flat_map(|c| c).map(|c| c.as_str()).collect::<Vec<_>>()); .map(|captures| captures.iter().skip(1).flat_map(|c| c).map(|c| c.as_str()).collect::<Vec<_>>());
// Match against the captured values as a list of tokens // Match against the captured values as a list of tokens
let tokens = captures.as_ref().map(|c| c.as_slice()); let tokens = captures.as_ref().map(|c| c.as_slice());
match tokens { match tokens {
// Parameter: ?: (?, ... | ...) = ? // Prop definition: ?: (?, ... | ...) = ?
Some([name, ":", "(", raw_types_list, ")", "=", default_value]) => { Some([name, ":", "(", raw_types_list, ")", "=", default_value]) => {
// Variable name bound in the parameter // Variable name bound in the prop definition
let name = String::from(*name); let name = String::from(*name);
// Split the type sequences up into a list of options separated by vertical bars // Split the type sequences up into a list of options separated by vertical bars
@ -258,24 +257,24 @@ impl AttributeParser {
}) })
.collect::<Vec<Vec<TypeName>>>(); .collect::<Vec<Vec<TypeName>>>();
// Required default value for the variable parameter if not provided // Split the provided default values into a sequence
let default_type_sequence = default_value let default_type_sequence = default_value
.split(",") .split(",")
.map(|individual_type| match self.parse_attribute_argument_type(individual_type) { .map(|individual_type| match self.parse_attribute_argument_type(individual_type) {
TypeValueOrArgument::TypeValue(type_value) => type_value, TypedValueOrVariableName::TypedValue(type_value) => type_value,
TypeValueOrArgument::VariableArgument(variable_value) => { TypedValueOrVariableName::VariableName(variable_value) => {
panic!( panic!(
"Found the default variable value `{:?}` in the attribute declaration `{}` (which only allows typed values) when parsing XML layout", "Found the default variable name `{:?}` in the attribute declaration `{}` (which only allows typed values) when parsing XML layout",
variable_value, attribute_declaration variable_value, attribute_declaration
); );
}, },
}) })
.collect::<Vec<TypeValue>>(); .collect::<Vec<TypedValue>>();
// TODO: Verify the default types match the specified allowed types // TODO: Verify the default types match the specified allowed types
// Return the parameter // Return the prop definition
VariableParameter::new(name, type_sequence_options, default_type_sequence) PropDefinition::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),
@ -294,7 +293,7 @@ impl AttributeParser {
// Based on whether we are alternating to a string or template, push the appropriate abstract token // Based on whether we are alternating to a string or template, push the appropriate abstract token
let segment = match is_template { let segment = match is_template {
false => TemplateStringSegment::String(String::from(part)), false => TemplateStringSegment::String(String::from(part)),
true => TemplateStringSegment::Argument(TypeValueOrArgument::VariableArgument(String::from(part))), true => TemplateStringSegment::Argument(TypedValueOrVariableName::VariableName(String::from(part))),
}; };
segments.push(segment); segments.push(segment);
} }