Expand description
The Cove parser.
Turns a token stream into an ast::SourceUnit. Cove has no statement
terminators: ; is not part of the language. Instead, as in Go and Swift,
a newline ends a statement when the line could have ended there. The last
expression of a block is still that block’s value.
§The newline rule
A line break ends the current expression when all of the following hold:
- the token after the break carries
Token::preceded_by_newline; - the token before the break can end an expression — an identifier,
self, a literal,),],},?, or...(seeends_expression); - the parser is at a point where continuing is optional: a postfix
(,<generic argument list, or{trailing closure, or a binary, range, or assignment operator; - the parser is not inside a
(,[, or<group (seeParser::grouped).{is not such a group: the statements of a block do end at newlines.
Two exceptions keep familiar code working. A line that starts with .
continues the previous expression, so a method chain may be split across
lines; this falls out of rule 3, because . is never an optional
continuation. And the continuation keywords else and => are read
across a line break as well, so } followed by a newline and else still
attaches.
Because rule 3 looks at the operator rather than the operand, an operator
at the end of a line continues onto the next line (a + / b is one
expression) while an operator at the start of a line does not (a /
+ b is two statements).
§Keywords whose operand is optional
break and return take an operand or take none, and continue never
takes one. For those, a line break is decisive rather than optional: the
operand must begin on the keyword’s own line, so a break written alone
on its line is a break with no operand and the next line is the next
statement. This is the same rule Go states as inserting a semicolon after
break, continue, and return at the end of a line, and it holds
inside a group as well, unlike rule 4 — a keyword that is already complete
has nothing for the next line to finish. An operand that starts on the
keyword’s line may still run over onto further lines, so return f( /
a, / ) is one return.
§The nesting limit
Recursive descent spends native stack per level of nesting, so the parser
bounds nesting rather than discovering the bound when the stack runs out.
Source that nests deeper than MAX_NESTING_DEPTH levels is a
cove::parse::nesting_too_deep diagnostic like any other and the file is
refused, instead of the process ending in a stack overflow that no caller
can catch. A level is any construct written inside another, and also each
link of a left-associative chain, because the tree such a chain builds is
as deep as the chain is long and everything downstream walks that tree by
recursing. See the constant for what the number is calibrated against.
Parsing never stops at the first error. Every diagnostic is collected and the parser resynchronises at the next plausible declaration or statement, so a single run reports as many independent problems as it can find.
Functions§
- parse
- Parses
tokens, which must be the token stream lexed fromfile.