[Toolchain][Parser] Add support for package directive. (#2144)

Summary:

Adds parsing support for the `package` directive as specified by the
`Code and name organization` design doc.

Co-authored-by: ergawy <kareem.ergawy@guardsquare.com>
This commit is contained in:
Kareem Ergawy
2022-09-07 10:54:27 +03:00
committed by GitHub
co-authored by ergawy
parent 84f5fb62e5
commit d44cde3c15
5 changed files with 166 additions and 2 deletions
+84
View File
@@ -448,6 +448,87 @@ auto ParseTree::Parser::ParseCodeBlock() -> llvm::Optional<Node> {
return AddNode(ParseNodeKind::CodeBlock(), open_curly, start, has_errors);
}
auto ParseTree::Parser::ParsePackageDirective() -> Node {
TokenizedBuffer::Token package_intro_token = Consume(TokenKind::Package());
auto package_start = GetSubtreeStartPosition();
auto create_error_node = [&]() {
return AddNode(ParseNodeKind::PackageDirective(), package_intro_token,
package_start,
/*has_error=*/true);
};
CARBON_RETURN_IF_STACK_LIMITED(create_error_node());
auto exit_on_parse_error = [&]() {
SkipPastLikelyEnd(package_intro_token, [&](TokenizedBuffer::Token semi) {
return AddLeafNode(ParseNodeKind::PackageEnd(), semi);
});
return create_error_node();
};
if (!NextTokenIs(TokenKind::Identifier())) {
CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPackage, Error,
"Expected identifier after `package`.");
emitter_.Emit(*position_, ExpectedIdentifierAfterPackage);
return exit_on_parse_error();
}
AddLeafNode(ParseNodeKind::DeclaredName(), Consume(TokenKind::Identifier()));
bool library_parsed = false;
if (tokens_.GetKind(*(position_)) == TokenKind::Library()) {
auto library_start = GetSubtreeStartPosition();
auto library_decl_token = Consume(TokenKind::Library());
if (tokens_.GetKind(*(position_)) != TokenKind::StringLiteral()) {
CARBON_DIAGNOSTIC(
ExpectedLibraryName, Error,
"Expected a string literal to specify the library name.");
emitter_.Emit(*position_, ExpectedLibraryName);
return exit_on_parse_error();
}
AddLeafNode(ParseNodeKind::Literal(), Consume(TokenKind::StringLiteral()));
AddNode(ParseNodeKind::PackageLibrary(), library_decl_token, library_start,
/*has_error=*/false);
library_parsed = true;
}
auto api_or_impl_token = tokens_.GetKind(*(position_));
if (api_or_impl_token == TokenKind::Api()) {
AddLeafNode(ParseNodeKind::PackageApi(), Consume(TokenKind::Api()));
} else if (api_or_impl_token == TokenKind::Impl()) {
AddLeafNode(ParseNodeKind::PackageImpl(), Consume(TokenKind::Impl()));
} else if (!library_parsed &&
api_or_impl_token == TokenKind::StringLiteral()) {
// If we come acroess a string literal and we didn't parse `library "..."`
// yet, then most probably the user forgot to add `library` before the
// library name.
CARBON_DIAGNOSTIC(MissingLibraryKeyword, Error,
"Missing `library` keyword.");
emitter_.Emit(*position_, MissingLibraryKeyword);
return exit_on_parse_error();
} else {
CARBON_DIAGNOSTIC(ExpectedApiOrImpl, Error, "Expected a `api` or `impl`.");
emitter_.Emit(*position_, ExpectedApiOrImpl);
return exit_on_parse_error();
}
if (tokens_.GetKind(*(position_)) != TokenKind::Semi()) {
CARBON_DIAGNOSTIC(ExpectedSemiToEndPackageDirective, Error,
"Expected `;` to end package directive.");
emitter_.Emit(*position_, ExpectedSemiToEndPackageDirective);
return exit_on_parse_error();
}
AddLeafNode(ParseNodeKind::PackageEnd(), Consume(TokenKind::Semi()));
return AddNode(ParseNodeKind::PackageDirective(), package_intro_token,
package_start, /*has_error=*/false);
}
auto ParseTree::Parser::ParseFunctionDeclaration() -> Node {
TokenizedBuffer::Token function_intro_token = Consume(TokenKind::Fn());
auto start = GetSubtreeStartPosition();
@@ -561,6 +642,8 @@ auto ParseTree::Parser::ParseEmptyDeclaration() -> Node {
auto ParseTree::Parser::ParseDeclaration() -> llvm::Optional<Node> {
CARBON_RETURN_IF_STACK_LIMITED(llvm::None);
switch (NextTokenKind()) {
case TokenKind::Package():
return ParsePackageDirective();
case TokenKind::Fn():
return ParseFunctionDeclaration();
case TokenKind::Var():
@@ -574,6 +657,7 @@ auto ParseTree::Parser::ParseDeclaration() -> llvm::Optional<Node> {
break;
}
// Should happen for packages now.
// We didn't recognize an introducer for a valid declaration.
CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error,
"Unrecognized declaration introducer.");