refactor == and != order of operations
This commit is contained in:
parent
697ff3d12f
commit
c07bb7ecce
@ -272,10 +272,12 @@ fn index(mut args: CallArgs, scope: &Scope, super_selector: &Selector) -> SassRe
|
||||
// evaluated prior to checking equality, but
|
||||
// it is still dirty.
|
||||
// Potential input to fuzz: index(1px 1in 1cm, 96px + 1rem)
|
||||
let index = match list
|
||||
.into_iter()
|
||||
.position(|v| v.equals(value.clone(), args.span()).unwrap())
|
||||
{
|
||||
let index = match list.into_iter().position(|v| {
|
||||
v.equals(value.clone(), args.span())
|
||||
.unwrap()
|
||||
.is_true(args.span())
|
||||
.unwrap()
|
||||
}) {
|
||||
Some(v) => Number::from(v + 1),
|
||||
None => return Ok(Value::Null),
|
||||
};
|
||||
|
@ -17,7 +17,7 @@ impl SassMap {
|
||||
|
||||
pub fn get(self, key: &Value, span: Span) -> SassResult<Option<Value>> {
|
||||
for (k, v) in self.0 {
|
||||
if k.equals(key.clone(), span)? {
|
||||
if k.equals(key.clone(), span)?.node.is_true(span)? {
|
||||
return Ok(Some(v));
|
||||
}
|
||||
}
|
||||
|
@ -313,8 +313,14 @@ impl Value {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn equals(self, other: Value, span: Span) -> SassResult<bool> {
|
||||
Ok(match self.eval(span)?.node {
|
||||
pub fn equals(self, mut other: Value, span: Span) -> SassResult<Spanned<Value>> {
|
||||
if let Self::Paren(..) = other {
|
||||
other = other.eval(span)?.node
|
||||
}
|
||||
|
||||
let precedence = Op::Equal.precedence();
|
||||
|
||||
Ok(Value::bool(match self {
|
||||
Self::Ident(s1, ..) => match other {
|
||||
Self::Ident(s2, ..) => s1 == s2,
|
||||
_ => false,
|
||||
@ -336,8 +342,75 @@ impl Value {
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
Self::BinaryOp(left, op2, right) => {
|
||||
if op2.precedence() >= precedence {
|
||||
Self::BinaryOp(left, op2, right).eval(span)?.node == other
|
||||
} else {
|
||||
return Self::BinaryOp(
|
||||
left,
|
||||
op2,
|
||||
Box::new(
|
||||
Self::BinaryOp(right, Op::Equal, Box::new(other))
|
||||
.eval(span)?
|
||||
.node,
|
||||
),
|
||||
)
|
||||
.eval(span);
|
||||
}
|
||||
}
|
||||
s => s == other.eval(span)?.node,
|
||||
})
|
||||
.span(span))
|
||||
}
|
||||
|
||||
pub fn not_equals(self, mut other: Value, span: Span) -> SassResult<Spanned<Value>> {
|
||||
if let Self::Paren(..) = other {
|
||||
other = other.eval(span)?.node
|
||||
}
|
||||
|
||||
let precedence = Op::Equal.precedence();
|
||||
|
||||
Ok(Value::bool(match self {
|
||||
Self::Ident(s1, ..) => match other {
|
||||
Self::Ident(s2, ..) => s1 != s2,
|
||||
_ => true,
|
||||
},
|
||||
Self::Dimension(n, unit) => match other {
|
||||
Self::Dimension(n2, unit2) => {
|
||||
if !unit.comparable(&unit2) {
|
||||
true
|
||||
} else if unit == unit2 {
|
||||
n != n2
|
||||
} else if unit == Unit::None || unit2 == Unit::None {
|
||||
true
|
||||
} else {
|
||||
n != (n2
|
||||
* UNIT_CONVERSION_TABLE[unit.to_string().as_str()]
|
||||
[unit2.to_string().as_str()]
|
||||
.clone())
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
},
|
||||
Self::BinaryOp(left, op2, right) => {
|
||||
if op2.precedence() >= precedence {
|
||||
Self::BinaryOp(left, op2, right).eval(span)?.node != other
|
||||
} else {
|
||||
return Self::BinaryOp(
|
||||
left,
|
||||
op2,
|
||||
Box::new(
|
||||
Self::BinaryOp(right, Op::NotEqual, Box::new(other))
|
||||
.eval(span)?
|
||||
.node,
|
||||
),
|
||||
)
|
||||
.eval(span);
|
||||
}
|
||||
}
|
||||
s => s != other.eval(span)?.node,
|
||||
})
|
||||
.span(span))
|
||||
}
|
||||
|
||||
pub fn unary_op_plus(self, span: Span) -> SassResult<Self> {
|
||||
@ -352,8 +425,8 @@ impl Value {
|
||||
Self::BinaryOp(lhs, op, rhs) => match op {
|
||||
Op::Plus => lhs.add(*rhs, span)?,
|
||||
Op::Minus => lhs.sub(*rhs, span)?,
|
||||
Op::Equal => Self::bool(lhs.equals(*rhs, span)?),
|
||||
Op::NotEqual => Self::bool(!lhs.equals(*rhs, span)?),
|
||||
Op::Equal => lhs.equals(*rhs, span)?.node,
|
||||
Op::NotEqual => lhs.not_equals(*rhs, span)?.node,
|
||||
Op::Mul => lhs.mul(*rhs, span)?,
|
||||
Op::Div => lhs.div(*rhs, span)?,
|
||||
Op::Rem => lhs.rem(*rhs, span)?,
|
||||
|
@ -301,6 +301,7 @@ fn eat_op<I: Iterator<Item = Token>>(
|
||||
}
|
||||
Op::And | Op::Or => {
|
||||
devour_whitespace(iter);
|
||||
// special case when the value is literally "and" or "or"
|
||||
if iter.peek().is_none() {
|
||||
space_separated.push(Value::Ident(op.to_string(), QuoteKind::None).span(op.span));
|
||||
} else if let Some(left) = space_separated.pop() {
|
||||
|
@ -25,6 +25,16 @@ test!(
|
||||
);
|
||||
test!(
|
||||
comparison,
|
||||
"a {\n color: 1 < 1 and 1 < 1;;\n}\n",
|
||||
"a {\n color: 1 < 1 and 1 < 1;\n}\n",
|
||||
"a {\n color: false;\n}\n"
|
||||
);
|
||||
test!(
|
||||
equals_then_or,
|
||||
"a {\n color: a or b==c;\n}\n",
|
||||
"a {\n color: a;\n}\n"
|
||||
);
|
||||
test!(
|
||||
not_equals_then_or,
|
||||
"a {\n color: a or b !=c;\n}\n",
|
||||
"a {\n color: a;\n}\n"
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user