in lib/parser.dart [751:845]
MixinDefinition? processMixin() {
_next();
var name = identifier();
var params = <TreeNode>[];
// Any parameters?
if (_maybeEat(TokenKind.LPAREN)) {
var mustHaveParam = false;
var keepGoing = true;
while (keepGoing) {
var varDef = processVariableOrDirective(mixinParameter: true);
if (varDef is VarDefinitionDirective || varDef is VarDefinition) {
params.add(varDef as TreeNode);
} else if (mustHaveParam) {
_warning('Expecting parameter', _makeSpan(_peekToken.span));
keepGoing = false;
}
if (_maybeEat(TokenKind.COMMA)) {
mustHaveParam = true;
continue;
}
keepGoing = !_maybeEat(TokenKind.RPAREN);
}
}
_eat(TokenKind.LBRACE);
var productions = <TreeNode>[];
MixinDefinition? mixinDirective;
var start = _peekToken.span;
while (!_maybeEat(TokenKind.END_OF_FILE)) {
var directive = processDirective();
if (directive != null) {
productions.add(directive);
continue;
}
var declGroup = processDeclarations(checkBrace: false);
if (declGroup.declarations.any((decl) {
return decl is Declaration && decl is! IncludeMixinAtDeclaration;
})) {
var newDecls = <Declaration>[];
productions.forEach((include) {
// If declGroup has items that are declarations then we assume
// this mixin is a declaration mixin not a top-level mixin.
if (include is IncludeDirective) {
newDecls.add(IncludeMixinAtDeclaration(include, include.span));
} else {
_warning('Error mixing of top-level vs declarations mixins',
_makeSpan(include.span as FileSpan));
}
});
declGroup.declarations.insertAll(0, newDecls);
productions = [];
} else {
// Declarations are just @includes make it a list of productions
// not a declaration group (anything else is a ruleset). Make it a
// list of productions, not a declaration group.
for (var decl in declGroup.declarations) {
productions
.add(decl is IncludeMixinAtDeclaration ? decl.include : decl);
}
;
declGroup.declarations.clear();
}
if (declGroup.declarations.isNotEmpty) {
if (productions.isEmpty) {
mixinDirective = MixinDeclarationDirective(
name.name, params, false, declGroup, _makeSpan(start));
break;
} else {
for (var decl in declGroup.declarations) {
productions
.add(decl is IncludeMixinAtDeclaration ? decl.include : decl);
}
}
} else {
mixinDirective = MixinRulesetDirective(
name.name, params, false, productions, _makeSpan(start));
break;
}
}
if (productions.isNotEmpty) {
mixinDirective = MixinRulesetDirective(
name.name, params, false, productions, _makeSpan(start));
}
_eat(TokenKind.RBRACE);
return mixinDirective;
}