Fix a couple infinite-loop bugs.

This commit is contained in:
Natalie Weizenbaum 2016-10-16 12:09:42 -07:00
parent d276bfb206
commit 90d9ed03cc
2 changed files with 39 additions and 28 deletions

View File

@ -166,7 +166,7 @@ List<List<ComplexSelectorComponent>> weave(
/// identical to the intersection of all elements matched by `A X` and all
/// elements matched by `B X`. Some `AB_i` are elided to reduce the size of
/// the output.
List<List<ComplexSelectorComponent>> _weaveParents(
Iterable<List<ComplexSelectorComponent>> _weaveParents(
List<ComplexSelectorComponent> parents1,
List<ComplexSelectorComponent> parents2) {
var queue1 = new Queue<ComplexSelectorComponent>.from(parents1);
@ -226,12 +226,13 @@ List<List<ComplexSelectorComponent>> _weaveParents(
choices.addAll(finalCombinator);
return paths(choices.where((choice) => choice.isNotEmpty))
.map((path) => path.expand((group) => group));
.map((path) => path.expand((group) => group).toList());
}
/// If the first element of [queue] has a `::root` selector, removes and returns
/// that element.
CompoundSelector _firstIfRoot(Queue<ComplexSelectorComponent> queue) {
if (queue.isEmpty) return null;
var first = queue.first as CompoundSelector;
if (!_hasRoot(first)) return null;
@ -282,12 +283,12 @@ List<List<List<ComplexSelectorComponent>>> _mergeFinalCombinators(
var combinators1 = <Combinator>[];
while (components1.last is Combinator) {
combinators1.add(components1.last as Combinator);
combinators1.add(components1.removeLast() as Combinator);
}
var combinators2 = <Combinator>[];
while (components2.last is Combinator) {
combinators2.add(components2.last as Combinator);
combinators2.add(components2.removeLast() as Combinator);
}
if (combinators1.length > 1 || combinators2.length > 1) {

View File

@ -260,18 +260,16 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
}
}
void visitEachRule(EachRule node) {
Value visitEachRule(EachRule node) {
var list = node.list.accept(this);
var setVariables = node.variables.length == 1
? (value) => _environment.setLocalVariable(node.variables.first, value)
: (value) => _setMultipleVariables(node.variables, value);
_environment.scope(() {
for (var element in list.asList) {
return _environment.scope(() {
return _handleReturn(list.asList, (element) {
setVariables(element);
for (var child in node.children) {
child.accept(this);
}
}
return _handleReturn(node.children, (child) => child.accept(this));
});
}, semiGlobal: true);
}
@ -342,7 +340,7 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
}, through: (node) => node is CssStyleRule);
}
void visitForRule(ForRule node) {
Value visitForRule(ForRule node) {
var from = _addExceptionSpan(node.from.span,
() => node.from.accept(this).assertNumber().assertInt());
var to = _addExceptionSpan(
@ -351,15 +349,16 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
// TODO: coerce units
var direction = from > to ? -1 : 1;
if (!node.isExclusive) to += direction;
if (from == to) return;
if (from == to) return null;
_environment.scope(() {
return _environment.scope(() {
for (var i = from; i != to; i += direction) {
_environment.setLocalVariable(node.variable, new SassNumber(i));
for (var child in node.children) {
child.accept(this);
}
var result =
_handleReturn(node.children, (child) => child.accept(this));
if (result != null) return result;
}
return null;
}, semiGlobal: true);
}
@ -368,7 +367,7 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
.setFunction(new UserDefinedCallable(node, _environment.closure()));
}
void visitIfRule(IfRule node) {
Value visitIfRule(IfRule node) {
var clause = node.clauses
.firstWhere((pair) => pair.item1.accept(this).isTruthy,
orElse: () => null)
@ -376,11 +375,9 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
node.lastClause;
if (clause == null) return null;
_environment.scope(() {
for (var child in clause) {
child.accept(this);
}
}, semiGlobal: true);
return _environment.scope(
() => _handleReturn(clause, (child) => child.accept(this)),
semiGlobal: true);
}
void visitImportRule(ImportRule node) {
@ -640,13 +637,14 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
}
}
void visitWhileRule(WhileRule node) {
_environment.scope(() {
Value visitWhileRule(WhileRule node) {
return _environment.scope(() {
while (node.condition.accept(this).isTruthy) {
for (var child in node.children) {
child.accept(this);
}
var result =
_handleReturn(node.children, (child) => child.accept(this));
if (result != null) return result;
}
return null;
}, semiGlobal: true);
}
@ -1086,6 +1084,18 @@ class _PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
// ## Utilities
/// Runs [callback] for each value in [list] until it returns a [Value].
///
/// Returns the value returned by [callback], or `null` if it only ever
/// returned `null`.
Value _handleReturn/*<T>*/(List/*<T>*/ list, Value callback(/*=T*/ value)) {
for (var value in list) {
var result = callback(value);
if (result != null) return result;
}
return null;
}
/// Runs [callback] with [environment] as the current environment.
/*=T*/ _withEnvironment/*<T>*/(Environment environment, /*=T*/ callback()) {
var oldEnvironment = _environment;