Skip to main content

Module parser

Module parser 

Source
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:

  1. the token after the break carries Token::preceded_by_newline;
  2. the token before the break can end an expression — an identifier, self, a literal, ), ], }, ?, or ... (see ends_expression);
  3. 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;
  4. the parser is not inside a (, [, or < group (see Parser::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 from file.