diff --git a/src/parse/value.rs b/src/parse/value.rs index fdc7e94..e94de66 100644 --- a/src/parse/value.rs +++ b/src/parse/value.rs @@ -887,9 +887,9 @@ impl<'a, 'b: 'a> IntermediateValueIterator<'a, 'b> { space_separated.push(right.map_node(|n| Value::UnaryOp(op.node, Box::new(n)))); } } - Op::And | Op::Or => { + Op::And => { self.whitespace(); - // special case when the value is literally "and" or "or" + // special case when the value is literally "and" if self.peek().is_none() { space_separated .push(Value::String(op.to_string(), QuoteKind::None).span(op.span)); @@ -904,6 +904,38 @@ impl<'a, 'b: 'a> IntermediateValueIterator<'a, 'b> { return Err(("Expected expression.", op.span).into()); } } + Op::Or => { + self.whitespace(); + // special case when the value is literally "or" + if self.peek().is_none() { + space_separated + .push(Value::String(op.to_string(), QuoteKind::None).span(op.span)); + } else if let Some(left) = space_separated.pop() { + self.whitespace(); + if left.node.is_true(left.span)? { + // we explicitly ignore errors here as a workaround for short circuiting + while let Some(foo) = self.peek() { + if let Ok(Spanned { + node: IntermediateValue::Comma, + .. + }) = foo + { + break; + } + self.next(); + } + space_separated.push(left); + } else { + let right = self.single_value()?; + space_separated.push( + Value::BinaryOp(Box::new(left.node), op.node, Box::new(right.node)) + .span(left.span.merge(right.span)), + ); + } + } else { + return Err(("Expected expression.", op.span).into()); + } + } _ => { if let Some(left) = space_separated.pop() { self.whitespace(); diff --git a/tests/or.rs b/tests/or.rs index 2aaa7b2..6caeca2 100644 --- a/tests/or.rs +++ b/tests/or.rs @@ -59,3 +59,17 @@ test!( "a {\n color: 1 - OR;\n}\n", "a {\n color: 1-OR;\n}\n" ); +test!( + short_circuits_when_lhs_is_true, + "a {\n color: true or red % foo;\n}\n", + "a {\n color: true;\n}\n" +); +error!( + does_not_short_circuit_when_lhs_is_false, + "a {\n color: false or red % foo;\n}\n", "Error: Undefined operation \"red % foo\"." +); +test!( + short_circuiting_in_comma_separated_list, + "a {\n color: true or red % foo, red;\n}\n", + "a {\n color: true, red;\n}\n" +);