handle_import_and_package.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/base/shared_value_stores.h"
  5. #include "toolchain/lex/token_kind.h"
  6. #include "toolchain/lex/tokenized_buffer.h"
  7. #include "toolchain/parse/context.h"
  8. #include "toolchain/parse/handle.h"
  9. #include "toolchain/parse/node_ids.h"
  10. #include "toolchain/parse/node_kind.h"
  11. namespace Carbon::Parse {
  12. // Provides common error exiting logic that skips to the semi, if present.
  13. static auto OnParseError(Context& context, Context::StateStackEntry state,
  14. NodeKind declaration) -> void {
  15. context.AddNode(declaration, context.SkipPastLikelyEnd(state.token),
  16. /*has_error=*/true);
  17. }
  18. // Determines whether the specified modifier appears within the introducer of
  19. // the given declaration.
  20. // TODO: Restructure how we handle packaging declarations to avoid the need to
  21. // do this.
  22. static auto HasModifier(Context& context, Context::StateStackEntry state,
  23. Lex::TokenKind modifier) -> bool {
  24. for (Lex::TokenIterator it(state.token); it != context.position(); ++it) {
  25. if (context.tokens().GetKind(*it) == modifier) {
  26. return true;
  27. }
  28. }
  29. return false;
  30. }
  31. // Handles everything after the declaration's introducer.
  32. static auto HandleDeclContent(Context& context, Context::StateStackEntry state,
  33. NodeKind declaration, bool is_export,
  34. bool is_impl,
  35. llvm::function_ref<void()> on_parse_error)
  36. -> void {
  37. Tree::PackagingNames names{
  38. .node_id = ImportDeclId(NodeId(state.subtree_start)),
  39. .is_export = is_export};
  40. if (declaration != NodeKind::LibraryDecl) {
  41. if (auto package_name_token =
  42. context.ConsumeIf(Lex::TokenKind::Identifier)) {
  43. if (names.is_export) {
  44. names.is_export = false;
  45. state.has_error = true;
  46. CARBON_DIAGNOSTIC(ExportImportPackage, Error,
  47. "`export` cannot be used when importing a package");
  48. context.emitter().Emit(*package_name_token, ExportImportPackage);
  49. }
  50. names.package_id = context.tokens().GetIdentifier(*package_name_token);
  51. context.AddLeafNode(NodeKind::PackageName, *package_name_token);
  52. } else if (declaration == NodeKind::PackageDecl ||
  53. !context.PositionIs(Lex::TokenKind::Library)) {
  54. CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPackage, Error,
  55. "expected identifier after `package`");
  56. CARBON_DIAGNOSTIC(ExpectedIdentifierAfterImport, Error,
  57. "expected identifier or `library` after `import`");
  58. context.emitter().Emit(*context.position(),
  59. declaration == NodeKind::PackageDecl
  60. ? ExpectedIdentifierAfterPackage
  61. : ExpectedIdentifierAfterImport);
  62. on_parse_error();
  63. return;
  64. }
  65. }
  66. // Parse the optional library keyword.
  67. bool accept_default = !names.package_id.has_value();
  68. if (declaration == NodeKind::LibraryDecl) {
  69. auto library_id = context.ParseLibraryName(accept_default);
  70. if (!library_id) {
  71. on_parse_error();
  72. return;
  73. }
  74. names.library_id = *library_id;
  75. } else {
  76. auto next_kind = context.PositionKind();
  77. if (next_kind == Lex::TokenKind::Library) {
  78. if (auto library_id = context.ParseLibrarySpecifier(accept_default)) {
  79. names.library_id = *library_id;
  80. } else {
  81. on_parse_error();
  82. return;
  83. }
  84. } else if (next_kind == Lex::TokenKind::StringLiteral ||
  85. (accept_default && next_kind == Lex::TokenKind::Default)) {
  86. // If we come across a string literal and we didn't parse `library
  87. // "..."` yet, then most probably the user forgot to add `library`
  88. // before the library name.
  89. CARBON_DIAGNOSTIC(MissingLibraryKeyword, Error,
  90. "missing `library` keyword");
  91. context.emitter().Emit(*context.position(), MissingLibraryKeyword);
  92. on_parse_error();
  93. return;
  94. }
  95. }
  96. if (auto semi = context.ConsumeIf(Lex::TokenKind::Semi)) {
  97. if (declaration == NodeKind::ImportDecl) {
  98. context.AddImport(names);
  99. } else {
  100. context.set_packaging_decl(names, is_impl);
  101. }
  102. context.AddNode(declaration, *semi, state.has_error);
  103. } else {
  104. context.DiagnoseExpectedDeclSemi(context.tokens().GetKind(state.token));
  105. on_parse_error();
  106. }
  107. }
  108. // Returns true if currently in a valid state for imports, false otherwise. May
  109. // update the packaging state respectively.
  110. static auto VerifyInImports(Context& context, Lex::TokenIndex intro_token)
  111. -> bool {
  112. switch (context.packaging_state()) {
  113. case Context::PackagingState::FileStart:
  114. // `package` is no longer allowed, but `import` may repeat.
  115. context.set_packaging_state(Context::PackagingState::InImports);
  116. return true;
  117. case Context::PackagingState::InImports:
  118. return true;
  119. case Context::PackagingState::AfterNonPackagingDecl: {
  120. context.set_packaging_state(
  121. Context::PackagingState::InImportsAfterNonPackagingDecl);
  122. CARBON_DIAGNOSTIC(ImportTooLate, Error,
  123. "`import` declarations must come after the `package` "
  124. "declaration (if present) and before any other "
  125. "entities in the file");
  126. CARBON_DIAGNOSTIC(FirstDecl, Note, "first declaration is here");
  127. context.emitter()
  128. .Build(intro_token, ImportTooLate)
  129. .Note(context.first_non_packaging_token(), FirstDecl)
  130. .Emit();
  131. return false;
  132. }
  133. case Context::PackagingState::InImportsAfterNonPackagingDecl:
  134. // There is a sequential block of misplaced `import` statements, which can
  135. // occur if a declaration is added above `import`s. Avoid duplicate
  136. // warnings.
  137. return false;
  138. }
  139. }
  140. // Diagnoses if `export` is used in an `impl` file.
  141. static auto RestrictExportToApi(Context& context,
  142. Context::StateStackEntry& state) -> void {
  143. // Error for both Main//default and every implementation file.
  144. auto packaging = context.tree().packaging_decl();
  145. if (!packaging || packaging->is_impl) {
  146. CARBON_DIAGNOSTIC(ExportFromImpl, Error,
  147. "`export` is only allowed in API files");
  148. context.emitter().Emit(state.token, ExportFromImpl);
  149. state.has_error = true;
  150. }
  151. }
  152. auto HandleImport(Context& context) -> void {
  153. auto state = context.PopState();
  154. auto declaration = NodeKind::ImportDecl;
  155. auto on_parse_error = [&] { OnParseError(context, state, declaration); };
  156. if (VerifyInImports(context, state.token)) {
  157. // Scan the modifiers to see if this import declaration is exported.
  158. bool is_export = HasModifier(context, state, Lex::TokenKind::Export);
  159. if (is_export) {
  160. RestrictExportToApi(context, state);
  161. }
  162. HandleDeclContent(context, state, declaration, is_export,
  163. /*is_impl=*/false, on_parse_error);
  164. } else {
  165. on_parse_error();
  166. }
  167. }
  168. auto HandleExportName(Context& context) -> void {
  169. auto state = context.PopState();
  170. RestrictExportToApi(context, state);
  171. context.PushState(state, State::ExportNameFinish);
  172. context.PushState(State::DeclNameAndParams, state.token);
  173. }
  174. auto HandleExportNameFinish(Context& context) -> void {
  175. auto state = context.PopState();
  176. context.AddNodeExpectingDeclSemi(state, NodeKind::ExportDecl,
  177. Lex::TokenKind::Export,
  178. /*is_def_allowed=*/false);
  179. }
  180. // Handles common logic for `package` and `library`.
  181. static auto HandlePackageAndLibraryDecls(Context& context,
  182. Lex::TokenKind intro_token_kind,
  183. NodeKind declaration) -> void {
  184. auto state = context.PopState();
  185. bool is_impl = HasModifier(context, state, Lex::TokenKind::Impl);
  186. auto on_parse_error = [&] { OnParseError(context, state, declaration); };
  187. if (state.token != Lex::TokenIndex::FirstNonCommentToken) {
  188. CARBON_DIAGNOSTIC(
  189. PackageTooLate, Error,
  190. "the `{0}` declaration must be the first non-comment line",
  191. Lex::TokenKind);
  192. CARBON_DIAGNOSTIC(FirstNonCommentLine, Note,
  193. "first non-comment line is here");
  194. context.emitter()
  195. .Build(state.token, PackageTooLate, intro_token_kind)
  196. .Note(Lex::TokenIndex::FirstNonCommentToken, FirstNonCommentLine)
  197. .Emit();
  198. on_parse_error();
  199. return;
  200. }
  201. // `package`/`library` is no longer allowed, but `import` may repeat.
  202. context.set_packaging_state(Context::PackagingState::InImports);
  203. HandleDeclContent(context, state, declaration, /*is_export=*/false, is_impl,
  204. on_parse_error);
  205. }
  206. auto HandlePackage(Context& context) -> void {
  207. HandlePackageAndLibraryDecls(context, Lex::TokenKind::Package,
  208. NodeKind::PackageDecl);
  209. }
  210. auto HandleLibrary(Context& context) -> void {
  211. HandlePackageAndLibraryDecls(context, Lex::TokenKind::Library,
  212. NodeKind::LibraryDecl);
  213. }
  214. } // namespace Carbon::Parse