Update attribute parser with refactored symbol names and coments
This commit is contained in:
parent
0eed8878ff
commit
400e9477f4
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue