declFuncExpr method
Implementation
FuncExpr declFuncExpr() {
consume(TokenType.kFunc, 'Expected "function" before declaration.');
final List<RawExpr> idParts = [];
final Token start = peek();
Token token = start;
bool desugarSelf = false;
// Assume true. The next step will read a name, if any,
// and change this to false if no name was read.
if (token.type == TokenType.kRaw) {
addIDPart() {
idParts.add(
RawExpr(
consume(
TokenType.kRaw,
'Expected valid identifier in function name.',
),
),
);
}
do {
addIDPart();
switch (peek().type) {
case TokenType.kDot:
advance();
case TokenType.kColon:
advance();
// Break early. The grammar allows only the last
// ID part to contain a colon.
desugarSelf = true;
addIDPart();
break;
default:
}
token = peek();
} while (token.type != TokenType.kLParen);
consume(
TokenType.kLParen,
'Missing left parentheses after function name.',
);
} else {
consume(
TokenType.kLParen,
'Expected an unnamed function to have an argument list wrapped in parentheses.',
);
}
final List<DeclArg> args = [
if (desugarSelf)
DeclArg(Token.synthesized('self', type: TokenType.kSelf)),
];
while (peek().type != TokenType.kRParen) {
final arg = advance();
if (!vars.contains(arg.type)) {
throw '${arg.pos} Expected argument name in declaration.';
}
args.add(DeclArg(arg));
if (peek().type == TokenType.kComma) {
advance();
}
}
if (args.isNotEmpty) {
final int count = args
.where((e) => e.id.type == TokenType.kSpread)
.length;
if (count > 1 || (count == 1 && args.last.id.type != TokenType.kSpread)) {
throw 'Varargs can only appear once at the end of an argument list.';
}
}
consume(
TokenType.kRParen,
'Expected closing parentheses after argument list.',
);
final List<Stmt> body = bodyStmt(terminal: TokenType.kEnd);
consume(TokenType.kEnd, 'Expected "end" after function body.');
// No name expression was found. This must be an anonymous function.
if (idParts.isEmpty) {
return FuncExpr.anonymous(start, body: body, args: args);
}
return FuncExpr.named(start, body: body, args: args, idParts: idParts);
}