Add more css

This commit is contained in:
Adrian Wozniak 2020-04-30 18:27:47 +02:00
parent c036891396
commit 6cc90f07b4
2 changed files with 188 additions and 171 deletions

View File

@ -224,9 +224,9 @@ impl CssParser {
}
pub fn parse(mut self) -> Result<Vec<Selector>, String> {
while let Some(token) = self.consume() {
while let Some(_) = self.peek() {
let selector = self
.parse_selector(token.as_str())
.parse_selector()
.map_err(|error| self.failed_here(error))?;
self.selectors.push(selector);
self.skip_white();
@ -234,39 +234,26 @@ impl CssParser {
Ok(self.selectors)
}
fn parse_selector(&mut self, token: &str) -> Result<Selector, String> {
fn parse_selector(&mut self) -> Result<Selector, String> {
let mut path = vec![];
if let Ok(part) = token.parse::<SelectorPart>() {
path.push(part);
self.parse_selector_path(&mut path)?;
}
self.skip_white();
let block = self
.expect_consume()
.and_then(|s| self.parse_block(s.as_str()))?;
.and_then(|s| self.parse_block(&path, s.as_str()))?;
Ok(Selector { path, block })
}
fn parse_selector_path(&mut self, path: &mut Vec<SelectorPart>) -> Result<(), String> {
self.skip_white();
while let Some(token) = self.peek() {
if token.as_str() == "{" {
break;
}
match self.expect_consume()?.parse::<SelectorPart>() {
Ok(part) => {
while let Ok(PropertyValue::Other(part)) = self.parse_token() {
path.push(part);
}
_ => break,
};
self.skip_white();
}
Ok(())
}
fn parse_block(&mut self, token: &str) -> Result<Block, String> {
fn parse_block(&mut self, path: &Vec<SelectorPart>, token: &str) -> Result<Block, String> {
if token != "{" {
return Err(format!("expect to find block but found {:?}", token));
}
@ -288,7 +275,7 @@ impl CssParser {
block.properties.push(Property::CommentBlock(comment))
}
_ => {
let prop = self.parse_property(token.as_str())?;
let prop = self.parse_property(path, token.as_str())?;
block.properties.push(prop);
self.skip_white();
}
@ -297,7 +284,7 @@ impl CssParser {
Ok(block)
}
fn parse_property(&mut self, s: &str) -> Result<Property, String> {
fn parse_property(&mut self, path: &Vec<SelectorPart>, s: &str) -> Result<Property, String> {
let prop = match s {
"align-content" => Property::AlignContent(self.parse_full_token()?),
"align-items" => Property::AlignItems(self.parse_full_token()?),
@ -526,6 +513,14 @@ impl CssParser {
// "word-wrap" => Property::WordWrap,
// "writing-mode" => Property::WritingMode,
"z-index" => Property::ZIndex(self.parse_full_token()?),
_ if s.starts_with("--") && s.len() > 2 => {
if path == &vec![SelectorPart::PseudoSelector("host".to_string())] {
let value: PropertyValue<String> = self.parse_full_token()?;
Property::VariableDefinition(s[2..].to_string(), value)
} else {
return Err(format!("invalid property {:?}", s));
}
}
_ => {
let _x = 1;
return Err(format!("invalid property {:?}", s));
@ -542,23 +537,6 @@ impl CssParser {
s.parse::<ExpectedType>()
}
fn parse_expected_prop_value<ExpectedType>(&mut self) -> ValueResult<ExpectedType>
where
ExpectedType: FromStr<Err = String>,
{
match self.try_parse_variable() {
Some(v) => {
self.skip_white();
self.consume_expected(";")?;
Ok(PropertyValue::Variable(v))
}
_ => {
let s = self.expect_consume()?;
s.parse::<ExpectedType>().map(|v| PropertyValue::Other(v))
}
}
}
fn next_is_semicolon(&mut self) -> bool {
self.peek().map(|s| s.as_str() == ";").unwrap_or_default()
}
@ -599,6 +577,34 @@ pub enum SelectorPart {
BeforeSiblingBound,
}
impl ParseToken<SelectorPart> for CssParser {
fn parse_token(&mut self) -> ValueResult<SelectorPart> {
let mut buffer = String::new();
self.skip_white();
while let Some(s) = self.peek().cloned() {
match s.as_str() {
"{" if buffer.is_empty() => return Err("end of selector".to_string()),
"{" | ">" | "~" | "+" | ":" | "(" | "[" | "#" | "." if !buffer.is_empty() => {
return Ok(PropertyValue::Other(buffer.parse::<SelectorPart>()?));
}
_ if !buffer.is_empty() && s.starts_with(".") | s.starts_with("#") => {
return Ok(PropertyValue::Other(buffer.parse::<SelectorPart>()?));
}
_ => {
self.expect_consume()?;
buffer.push_str(s.as_str())
}
};
self.skip_white();
}
if buffer.is_empty() {
Err("".to_string())
} else {
Ok(PropertyValue::Other(buffer.parse::<SelectorPart>()?))
}
}
}
impl FromStr for SelectorPart {
type Err = String;
@ -606,7 +612,8 @@ impl FromStr for SelectorPart {
if s.trim().is_empty() {
return Err("invalid selector".to_string());
}
let s = match s {
let _x = 1;
let p = match s {
">" => SelectorPart::ParentBound,
"+" => SelectorPart::AfterSiblingBound,
"~" => SelectorPart::BeforeSiblingBound,
@ -617,7 +624,7 @@ impl FromStr for SelectorPart {
}
_ => SelectorPart::TagName(s.to_string()),
};
Ok(s)
Ok(p)
}
}
@ -1469,6 +1476,15 @@ pub enum Property {
mod tests {
use super::*;
impl Selector {
pub fn new(path: Vec<SelectorPart>, props: Vec<Property>) -> Self {
Self {
path,
block: Block { properties: props },
}
}
}
/// we assume currently we hit property name
/// display : block;
/// ^
@ -1929,14 +1945,10 @@ mod tests {
path: vec![SelectorPart::Class("bar".to_string())],
block: Block { properties: vec![] },
},
Selector {
path: vec![SelectorPart::Class("foz".to_string())],
block: Block { properties: vec![] },
},
Selector {
path: vec![SelectorPart::Class("baz".to_string())],
block: Block {
properties: vec![
Selector::new(vec![SelectorPart::Class("foz".to_string())], vec![]),
Selector::new(
vec![SelectorPart::Class("baz".to_string())],
vec![
Property::Display(PropertyValue::Other(DisplayProperty::Block)),
Property::JustifyContent(PropertyValue::Other(
JustifyContentProperty::SpaceBetween,
@ -1954,8 +1966,7 @@ mod tests {
PropertyValue::Other(255),
))),
],
},
},
),
]);
assert_eq!(res, expected);
}
@ -1969,16 +1980,15 @@ mod tests {
let tokens = CssTokenizer::new(include_str!("../../tests/full.css")).tokenize();
let res = CssParser::new("./jirs-css/tests/full.css", tokens).parse();
let expected = vec![
Selector {
path: vec![
Selector::new(
vec![
SelectorPart::TagName("p".to_string()),
SelectorPart::ParentBound,
SelectorPart::Id("foo".to_string()),
SelectorPart::AfterSiblingBound,
SelectorPart::Class("bar".to_string()),
],
block: Block {
properties: vec![
vec![
AlignContent(Other(AlignContentProperty::SpaceBetween)),
AlignItems(Other(AlignItemsProperty::Center)),
AlignSelf(Other(AlignSelfProperty::Auto)),
@ -2028,43 +2038,33 @@ mod tests {
Position(Other(PositionProperty::Relative)),
ZIndex(Other(ZIndexProperty::Number(-2))),
],
},
},
Selector {
path: vec![
),
Selector::new(
vec![
SelectorPart::TagName("p".to_string()),
SelectorPart::ParentBound,
SelectorPart::Id("foo".to_string()),
SelectorPart::BeforeSiblingBound,
SelectorPart::Class("bar".to_string()),
],
block: Block {
properties: vec![
vec![
AlignContent(Variable(VariableUsage("align-content".to_string()))),
AlignItems(Variable(VariableUsage("align-items".to_string()))),
AlignSelf(Variable(VariableUsage("align-self".to_string()))),
All(Variable(VariableUsage("all".to_string()))),
Animation(Variable(VariableUsage("animation".to_string()))),
AnimationDelay(Variable(VariableUsage("animation-delay".to_string()))),
AnimationDirection(Variable(VariableUsage(
"animation-direction".to_string(),
))),
AnimationDuration(Variable(VariableUsage(
"animation-duration".to_string(),
))),
AnimationDirection(Variable(VariableUsage("animation-direction".to_string()))),
AnimationDuration(Variable(VariableUsage("animation-duration".to_string()))),
AnimationIterationCount(Variable(VariableUsage(
"animation-iteration-count".to_string(),
))),
AnimationName(Variable(VariableUsage("animation-name".to_string()))),
AnimationPlayState(Variable(VariableUsage(
"animation-play-state".to_string(),
))),
AnimationPlayState(Variable(VariableUsage("animation-play-state".to_string()))),
AnimationTimingFunction(Variable(VariableUsage(
"animation-timing-function".to_string(),
))),
BackfaceVisibility(Variable(VariableUsage(
"backface-visibility".to_string(),
))),
BackfaceVisibility(Variable(VariableUsage("backface-visibility".to_string()))),
BackgroundAttachment(Variable(VariableUsage(
"background-attachment".to_string(),
))),
@ -2082,8 +2082,20 @@ mod tests {
Position(Variable(VariableUsage("position".to_string()))),
ZIndex(Variable(VariableUsage("z-index".to_string()))),
],
},
},
),
Selector::new(
vec![SelectorPart::PseudoSelector("host".to_string())],
vec![
Property::VariableDefinition(
"clear".to_string(),
PropertyValue::Other("clear".to_string()),
),
Property::VariableDefinition(
"from-var".to_string(),
PropertyValue::Variable(VariableUsage("clear".to_string())),
),
],
),
];
if let Ok(v) = res.as_ref() {
for (idx, selector) in v.into_iter().enumerate() {

View File

@ -53,3 +53,8 @@ p > #foo ~ .bar {
position: var(--position);
z-index: var(--z-index);
}
:host {
--clear: clear;
--from-var: var(--clear);
}