ambiguous keyword operators are not treated as function calls
This commit is contained in:
parent
00a7659e69
commit
48de92fdc0
@ -232,6 +232,65 @@ impl<'a> Parser<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_fn_call(
|
||||
&mut self,
|
||||
mut s: String,
|
||||
lower: String,
|
||||
) -> SassResult<Spanned<IntermediateValue>> {
|
||||
if lower == "min" || lower == "max" {
|
||||
match self.try_parse_min_max(&lower, true)? {
|
||||
Some(val) => {
|
||||
self.toks.truncate_iterator_to_cursor();
|
||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(
|
||||
Value::String(val, QuoteKind::None),
|
||||
))
|
||||
.span(self.span_before));
|
||||
}
|
||||
None => {
|
||||
self.toks.reset_cursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let as_ident = Identifier::from(&s);
|
||||
let func = match self.scopes.get_fn(as_ident, self.global_scope) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
if let Some(f) = GLOBAL_FUNCTIONS.get(as_ident.as_str()) {
|
||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Function(
|
||||
SassFunction::Builtin(f.clone(), as_ident),
|
||||
self.parse_call_args()?,
|
||||
))
|
||||
.span(self.span_before));
|
||||
} else {
|
||||
// check for special cased CSS functions
|
||||
match unvendor(&lower) {
|
||||
"calc" | "element" | "expression" => {
|
||||
s = lower;
|
||||
self.parse_calc_args(&mut s)?;
|
||||
}
|
||||
"url" => match self.try_parse_url()? {
|
||||
Some(val) => s = val,
|
||||
None => s.push_str(&self.parse_call_args()?.to_css_string()?),
|
||||
},
|
||||
_ => s.push_str(&self.parse_call_args()?.to_css_string()?),
|
||||
}
|
||||
|
||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(
|
||||
Value::String(s, QuoteKind::None),
|
||||
))
|
||||
.span(self.span_before));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let call_args = self.parse_call_args()?;
|
||||
Ok(
|
||||
IntermediateValue::Value(HigherIntermediateValue::Function(func, call_args))
|
||||
.span(self.span_before),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_ident_value(
|
||||
&mut self,
|
||||
predicate: &dyn Fn(&mut PeekMoreIterator<IntoIter<Token>>) -> bool,
|
||||
@ -255,72 +314,22 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
match self.toks.peek() {
|
||||
Some(Token { kind: '(', .. }) => {
|
||||
self.toks.next();
|
||||
|
||||
if lower == "min" || lower == "max" {
|
||||
match self.try_parse_min_max(&lower, true)? {
|
||||
Some(val) => {
|
||||
self.toks.truncate_iterator_to_cursor();
|
||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(
|
||||
Value::String(val, QuoteKind::None),
|
||||
))
|
||||
.span(span));
|
||||
}
|
||||
None => {
|
||||
self.toks.reset_cursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let as_ident = Identifier::from(&s);
|
||||
let func = match self.scopes.get_fn(as_ident, self.global_scope) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
if let Some(f) = GLOBAL_FUNCTIONS.get(as_ident.as_str()) {
|
||||
return Ok(IntermediateValue::Value(
|
||||
HigherIntermediateValue::Function(
|
||||
SassFunction::Builtin(f.clone(), as_ident),
|
||||
self.parse_call_args()?,
|
||||
),
|
||||
)
|
||||
.span(span));
|
||||
} else {
|
||||
// check for special cased CSS functions
|
||||
match unvendor(&lower) {
|
||||
"calc" | "element" | "expression" => {
|
||||
s = lower;
|
||||
self.parse_calc_args(&mut s)?;
|
||||
}
|
||||
"url" => match self.try_parse_url()? {
|
||||
Some(val) => s = val,
|
||||
None => s.push_str(&self.parse_call_args()?.to_css_string()?),
|
||||
},
|
||||
_ => s.push_str(&self.parse_call_args()?.to_css_string()?),
|
||||
}
|
||||
|
||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Literal(
|
||||
Value::String(s, QuoteKind::None),
|
||||
))
|
||||
.span(span));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let call_args = self.parse_call_args()?;
|
||||
return Ok(IntermediateValue::Value(HigherIntermediateValue::Function(
|
||||
func, call_args,
|
||||
))
|
||||
.span(span));
|
||||
}
|
||||
Some(Token { kind: '.', .. }) => {
|
||||
if !predicate(self.toks) {
|
||||
if !is_keyword_operator(&s) {
|
||||
match self.toks.peek() {
|
||||
Some(Token { kind: '(', .. }) => {
|
||||
self.span_before = span;
|
||||
self.toks.next();
|
||||
return self.parse_module_item(&s, span);
|
||||
|
||||
return self.parse_fn_call(s, lower);
|
||||
}
|
||||
Some(Token { kind: '.', .. }) => {
|
||||
if !predicate(self.toks) {
|
||||
self.toks.next();
|
||||
return self.parse_module_item(&s, span);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// check for named colors
|
||||
@ -1356,3 +1365,7 @@ fn parse_i64(s: &str) -> i64 {
|
||||
.iter()
|
||||
.fold(0, |total, this| total * 10 + i64::from(this - b'0'))
|
||||
}
|
||||
|
||||
fn is_keyword_operator(s: &str) -> bool {
|
||||
matches!(s, "and" | "or" | "not")
|
||||
}
|
||||
|
@ -41,3 +41,45 @@ test!(
|
||||
"a {\n $primary: #f2ece4;\n $accent: #e1d7d2;\n color: radial-gradient($primary, $accent);\n}\n",
|
||||
"a {\n color: radial-gradient(#f2ece4, #e1d7d2);\n}\n"
|
||||
);
|
||||
test!(
|
||||
fn_named_not_is_evaluated_as_unary_op,
|
||||
"a {\n color: not(true);\n}\n",
|
||||
"a {\n color: false;\n}\n"
|
||||
);
|
||||
test!(
|
||||
fn_named_true_is_plain_css,
|
||||
"a {\n color: true(true);\n}\n",
|
||||
"a {\n color: true(true);\n}\n"
|
||||
);
|
||||
test!(
|
||||
fn_named_false_is_plain_css,
|
||||
"a {\n color: false(true);\n}\n",
|
||||
"a {\n color: false(true);\n}\n"
|
||||
);
|
||||
test!(
|
||||
fn_named_null_is_plain_css,
|
||||
"a {\n color: null(true);\n}\n",
|
||||
"a {\n color: null(true);\n}\n"
|
||||
);
|
||||
test!(
|
||||
fn_named_and_is_evaluated_as_binop,
|
||||
"a {\n color: true and(foo);\n}\n",
|
||||
"a {\n color: foo;\n}\n"
|
||||
);
|
||||
test!(
|
||||
fn_named_or_is_evaluated_as_binop,
|
||||
"a {\n color: true or(foo);\n}\n",
|
||||
"a {\n color: true;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "this is not currently parsed correctly"]
|
||||
fn_named_and_alone_is_not_evaluated_as_binop,
|
||||
"a {\n color: and(foo);\n}\n",
|
||||
"a {\n color: and(foo);\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "this is not currently parsed correctly"]
|
||||
fn_named_or_alone_is_not_evaluated_as_binop,
|
||||
"a {\n color: or(foo);\n}\n",
|
||||
"a {\n color: or(foo);\n}\n"
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user