Skip to content

Commit

Permalink
Added "or" keyword and allowed arbitrary logical expression in guards.
Browse files Browse the repository at this point in the history
  • Loading branch information
meri committed Dec 20, 2015
1 parent c247775 commit 7762705
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 7 deletions.
64 changes: 57 additions & 7 deletions lib/less/parser/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,7 @@ var Parser = function Parser(context, imports, fileInfo) {
conditions: function () {
var a, b, index = parserInput.i, condition;

//console.log("conditions");
a = this.condition();
if (a) {
while (true) {
Expand All @@ -1597,11 +1598,61 @@ var Parser = function Parser(context, imports, fileInfo) {
}
},
condition: function () {
var entities = this.entities, index = parserInput.i, negate = false,
var result, logical, next;
function insideCondition(me) {
return me.negatedCondition() || me.parenthesisCondition();
}
function logicalOperator() {
return parserInput.$str("and") || parserInput.$str("or");
}

//console.log("condition");
result = insideCondition(this);
if (!result) {
return ;
}
logical = logicalOperator();
if (logical) {
next = this.condition();
if (next) {
result = new(tree.Condition)(logical, result, next);
} else {
//FIXME: meri error or just return
return ;
}
}
return result;
},
negatedCondition: function () {
//console.log("negatedCondition");
if (parserInput.$str("not")) {
var result = this.parenthesisCondition();
if (result) {
//console.log("negating");
if (result.negate) {
result.negate = false;
} else {
result.negate = true;
}
}
return result;
}
},
parenthesisCondition: function () {
var body;
//console.log("parenthesisCondition");
if (!parserInput.$str("(")) {
return ;
}
body = this.condition() || this.atomicCondition();
expectChar(')');
return body;
},
atomicCondition: function () {
var entities = this.entities, index = parserInput.i,
a, b, c, op;

if (parserInput.$str("not")) { negate = true; }
expectChar('(');
//console.log("atomicCondition");
a = this.addition() || entities.keyword() || entities.quoted();
if (a) {
if (parserInput.$char('>')) {
Expand Down Expand Up @@ -1630,15 +1681,14 @@ var Parser = function Parser(context, imports, fileInfo) {
if (op) {
b = this.addition() || entities.keyword() || entities.quoted();
if (b) {
c = new(tree.Condition)(op, a, b, index, negate);
c = new(tree.Condition)(op, a, b, index, false);
} else {
error('expected expression');
}
} else {
c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, false);
}
expectChar(')');
return parserInput.$str("and") ? new(tree.Condition)('and', c, this.condition()) : c;
return c;
}
},

Expand Down
24 changes: 24 additions & 0 deletions test/css/mixins-guards.css
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,27 @@
#guarded-deeper {
should: match 1;
}
#parenthesisNot-true {
parenthesisNot: just-value;
parenthesisNot: negated twice 1;
parenthesisNot: negated twice 2;
parenthesisNot: negated twice 3;
}
#parenthesisNot-false {
parenthesisNot: negated once inside;
parenthesisNot: negated once outside;
parenthesisNot: negated once middle;
}
#orderOfEvaluation-false-false-true {
no-parenthesis: evaluated true 3;
with-parenthesis: evaluated true;
}
#orderOfEvaluation-false-false-false {
orderOfEvaluation: evaluated false;
}
#orderOfEvaluation-true-true-false {
no-parenthesis: evaluated true 1;
no-parenthesis: evaluated true 2;
no-parenthesis: evaluated true 4;
with-parenthesis: evaluated true;
}
60 changes: 60 additions & 0 deletions test/less/mixins-guards.less
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,63 @@
.guarded-mixin-for-root() when (@guarded-mixin-for-root) {}
}
#ns > .guarded-mixin-for-root();
// various combinations of nested or, and, paranthesis and negation
.parenthesisNot(@value) when ((((@value)))) {
parenthesisNot: just-value;
}
.parenthesisNot(@value) when (((not(@value)))) {
parenthesisNot: negated once inside;
}
.parenthesisNot(@value) when not((((@value)))) {
parenthesisNot: negated once outside;
}
.parenthesisNot(@value) when ((not((@value)))) {
parenthesisNot: negated once middle;
}
.parenthesisNot(@value) when not(((not(@value)))) {
parenthesisNot: negated twice 1;
}
.parenthesisNot(@value) when (not((not(@value)))) {
parenthesisNot: negated twice 2;
}
.parenthesisNot(@value) when ((not(not(@value)))) {
parenthesisNot: negated twice 3;
}
.parenthesisNot (...) when (default()) {
parenthesisNot: none matched;
}

#parenthesisNot-true {
.parenthesisNot(true);
}
#parenthesisNot-false {
.parenthesisNot(false);
}

.orderOfEvaluation(@a1, @a2, @a3) when ((@a1) and (@a2) or (@a3)) {
no-parenthesis: evaluated true 1;
}
.orderOfEvaluation(@a1, @a2, @a3) when ((@a1) and (@a2) or not (@a3)) {
no-parenthesis: evaluated true 2;
}
.orderOfEvaluation(@a1, @a2, @a3) when (not (@a1) and (@a2) or (@a3)) {
no-parenthesis: evaluated true 3;
}
.orderOfEvaluation(@a1, @a2, @a3) when ((((@a1) and (@a2) or (@a3)))) {
no-parenthesis: evaluated true 4;
}
.orderOfEvaluation(@a1, @a2, @a3) when (((@a1) and (@a2)) or (@a3)) {
with-parenthesis: evaluated true;
}
.orderOfEvaluation(...) when (default()) {
orderOfEvaluation: evaluated false;
}
#orderOfEvaluation-false-false-true {
.orderOfEvaluation(false, false, true);
}
#orderOfEvaluation-false-false-false {
.orderOfEvaluation(false, false, false);
}
#orderOfEvaluation-true-true-false {
.orderOfEvaluation(true, true, false);
}

0 comments on commit 7762705

Please sign in to comment.