mirror of
https://github.com/danog/dart-sass.git
synced 2024-12-02 09:37:49 +01:00
Fix a couple infinite-loop bugs.
This commit is contained in:
parent
d276bfb206
commit
90d9ed03cc
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user