handle_import_and_package.cpp 9.1 KB

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