handle_decl_scope_loop.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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 <array>
  5. #include "toolchain/lex/token_kind.h"
  6. #include "toolchain/parse/context.h"
  7. #include "toolchain/parse/handle.h"
  8. #include "toolchain/parse/node_kind.h"
  9. namespace Carbon::Parse {
  10. // Finishes an invalid declaration, skipping past its end.
  11. static auto FinishAndSkipInvalidDecl(Context& context, int32_t subtree_start)
  12. -> void {
  13. auto cursor = *context.position();
  14. // Output an invalid parse subtree including everything up to the next `;`
  15. // or end of line.
  16. context.ReplacePlaceholderNode(subtree_start, NodeKind::InvalidParseStart,
  17. cursor, /*has_error=*/true);
  18. context.AddNode(NodeKind::InvalidParseSubtree,
  19. context.SkipPastLikelyEnd(cursor), /*has_error=*/true);
  20. }
  21. // Prints a diagnostic and calls FinishAndSkipInvalidDecl.
  22. static auto HandleUnrecognizedDecl(Context& context, int32_t subtree_start)
  23. -> void {
  24. CARBON_DIAGNOSTIC(UnrecognizedDecl, Error,
  25. "unrecognized declaration introducer");
  26. context.emitter().Emit(*context.position(), UnrecognizedDecl);
  27. FinishAndSkipInvalidDecl(context, subtree_start);
  28. }
  29. // Replaces the introducer placeholder node, and pushes the introducer state for
  30. // processing.
  31. static auto ApplyIntroducer(Context& context, Context::State state,
  32. NodeKind introducer_kind, StateKind next_state_kind)
  33. -> void {
  34. context.ReplacePlaceholderNode(state.subtree_start, introducer_kind,
  35. context.Consume());
  36. // Reuse state here to retain its `subtree_start`.
  37. context.PushState(state, next_state_kind);
  38. }
  39. namespace {
  40. // The kind of context in which a declaration appears.
  41. enum DeclContextKind : int8_t {
  42. RegularContext = 0,
  43. ClassContext = 1,
  44. InterfaceContext = 2,
  45. MaxDeclContextKind = InterfaceContext,
  46. };
  47. // The kind of declaration introduced by an introducer keyword.
  48. enum class DeclIntroducerKind : int8_t {
  49. Unrecognized,
  50. PackagingDecl,
  51. NonPackagingDecl,
  52. };
  53. // Information about a keyword that might be an introducer keyword.
  54. struct DeclIntroducerInfo {
  55. DeclIntroducerKind introducer_kind;
  56. NodeKind node_kind;
  57. StateKind state_kind;
  58. };
  59. } // namespace
  60. static constexpr auto DeclIntroducers = [] {
  61. std::array<DeclIntroducerInfo, MaxDeclContextKind + 1> introducers[] = {
  62. #define CARBON_TOKEN(Name) \
  63. {{{.introducer_kind = DeclIntroducerKind::Unrecognized, \
  64. .node_kind = NodeKind::InvalidParse, \
  65. .state_kind = StateKind::Invalid}, \
  66. {.introducer_kind = DeclIntroducerKind::Unrecognized, \
  67. .node_kind = NodeKind::InvalidParse, \
  68. .state_kind = StateKind::Invalid}, \
  69. {.introducer_kind = DeclIntroducerKind::Unrecognized, \
  70. .node_kind = NodeKind::InvalidParse, \
  71. .state_kind = StateKind::Invalid}}},
  72. #include "toolchain/lex/token_kind.def"
  73. };
  74. auto set = [&](Lex::TokenKind token_kind, NodeKind node_kind,
  75. StateKind state) {
  76. for (int i = 0; i <= MaxDeclContextKind; ++i) {
  77. introducers[token_kind.AsInt()][i] = {
  78. .introducer_kind = DeclIntroducerKind::NonPackagingDecl,
  79. .node_kind = node_kind,
  80. .state_kind = state};
  81. }
  82. };
  83. auto set_contextual = [&](Lex::TokenKind token_kind,
  84. DeclContextKind context_kind, NodeKind node_kind,
  85. StateKind state) {
  86. introducers[token_kind.AsInt()][context_kind] = {
  87. .introducer_kind = DeclIntroducerKind::NonPackagingDecl,
  88. .node_kind = node_kind,
  89. .state_kind = state};
  90. };
  91. auto set_packaging = [&](Lex::TokenKind token_kind, NodeKind node_kind,
  92. StateKind state) {
  93. for (int i = 0; i <= MaxDeclContextKind; ++i) {
  94. introducers[token_kind.AsInt()][i] = {
  95. .introducer_kind = DeclIntroducerKind::PackagingDecl,
  96. .node_kind = node_kind,
  97. .state_kind = state};
  98. }
  99. };
  100. set(Lex::TokenKind::Adapt, NodeKind::AdaptIntroducer,
  101. StateKind::AdaptAfterIntroducer);
  102. set(Lex::TokenKind::Alias, NodeKind::AliasIntroducer, StateKind::Alias);
  103. set(Lex::TokenKind::Base, NodeKind::BaseIntroducer,
  104. StateKind::BaseAfterIntroducer);
  105. set(Lex::TokenKind::Choice, NodeKind::ChoiceIntroducer,
  106. StateKind::ChoiceIntroducer);
  107. set(Lex::TokenKind::Class, NodeKind::ClassIntroducer,
  108. StateKind::TypeAfterIntroducerAsClass);
  109. set(Lex::TokenKind::Constraint, NodeKind::NamedConstraintIntroducer,
  110. StateKind::TypeAfterIntroducerAsNamedConstraint);
  111. set(Lex::TokenKind::Export, NodeKind::ExportIntroducer,
  112. StateKind::ExportName);
  113. // TODO: Treat `extend` as a declaration introducer.
  114. set(Lex::TokenKind::Fn, NodeKind::FunctionIntroducer,
  115. StateKind::FunctionIntroducer);
  116. set(Lex::TokenKind::Impl, NodeKind::ImplIntroducer,
  117. StateKind::ImplAfterIntroducer);
  118. set(Lex::TokenKind::Interface, NodeKind::InterfaceIntroducer,
  119. StateKind::TypeAfterIntroducerAsInterface);
  120. set(Lex::TokenKind::Namespace, NodeKind::NamespaceStart,
  121. StateKind::Namespace);
  122. set(Lex::TokenKind::Require, NodeKind::RequireIntroducer,
  123. StateKind::RequireAfterIntroducer);
  124. set_contextual(Lex::TokenKind::Let, RegularContext, NodeKind::LetIntroducer,
  125. StateKind::Let);
  126. set_contextual(Lex::TokenKind::Let, ClassContext, NodeKind::LetIntroducer,
  127. StateKind::Let);
  128. set_contextual(Lex::TokenKind::Let, InterfaceContext,
  129. NodeKind::AssociatedConstantIntroducer,
  130. StateKind::AssociatedConstant);
  131. set_contextual(Lex::TokenKind::Var, RegularContext,
  132. NodeKind::VariableIntroducer, StateKind::VarAsRegular);
  133. set_contextual(Lex::TokenKind::Var, ClassContext, NodeKind::FieldIntroducer,
  134. StateKind::FieldDecl);
  135. set_packaging(Lex::TokenKind::Package, NodeKind::PackageIntroducer,
  136. StateKind::Package);
  137. set_packaging(Lex::TokenKind::Library, NodeKind::LibraryIntroducer,
  138. StateKind::Library);
  139. set_packaging(Lex::TokenKind::Import, NodeKind::ImportIntroducer,
  140. StateKind::Import);
  141. return std::to_array(introducers);
  142. }();
  143. // Attempts to handle the current token as a declaration introducer.
  144. // Returns true if the current position is a declaration. If we see a
  145. // declaration introducer keyword token, replace the placeholder node and switch
  146. // to a state to parse the rest of the declaration.
  147. static auto TryHandleAsDecl(Context& context, Context::State state,
  148. bool saw_modifier,
  149. DeclContextKind decl_context_kind) -> bool {
  150. const auto& info =
  151. DeclIntroducers[context.PositionKind().AsInt()][decl_context_kind];
  152. switch (info.introducer_kind) {
  153. case DeclIntroducerKind::Unrecognized: {
  154. // A `;` with no modifiers is an empty declaration.
  155. if (!saw_modifier) {
  156. if (auto loc = context.ConsumeIf(Lex::TokenKind::Semi)) {
  157. context.ReplacePlaceholderNode(state.subtree_start,
  158. NodeKind::EmptyDecl, *loc);
  159. return true;
  160. }
  161. }
  162. return false;
  163. }
  164. case DeclIntroducerKind::PackagingDecl: {
  165. // Packaging declarations update the packaging state themselves as needed.
  166. break;
  167. }
  168. case DeclIntroducerKind::NonPackagingDecl: {
  169. // Because a non-packaging keyword was encountered, packaging is complete.
  170. // Misplaced packaging keywords may lead to this being re-triggered.
  171. if (context.packaging_state() !=
  172. Context::PackagingState::AfterNonPackagingDecl) {
  173. if (!context.first_non_packaging_token().has_value()) {
  174. context.set_first_non_packaging_token(*context.position());
  175. }
  176. context.set_packaging_state(
  177. Context::PackagingState::AfterNonPackagingDecl);
  178. }
  179. break;
  180. }
  181. }
  182. ApplyIntroducer(context, state, info.node_kind, info.state_kind);
  183. return true;
  184. }
  185. // Returns true if position_kind could be either an introducer or modifier, and
  186. // should be treated as an introducer.
  187. static auto ResolveAmbiguousTokenAsDeclaration(Context& context,
  188. Lex::TokenKind position_kind)
  189. -> bool {
  190. switch (position_kind) {
  191. case Lex::TokenKind::Base:
  192. case Lex::TokenKind::Export:
  193. case Lex::TokenKind::Extend:
  194. case Lex::TokenKind::Impl:
  195. // This is an ambiguous token, so now we check what the next token is.
  196. // We use the macro for modifiers, including introducers which are
  197. // also modifiers (such as `base`). Other introducer tokens need to be
  198. // added by hand.
  199. switch (context.PositionKind(Lookahead::NextToken)) {
  200. case Lex::TokenKind::Adapt:
  201. case Lex::TokenKind::Alias:
  202. case Lex::TokenKind::Class:
  203. case Lex::TokenKind::Constraint:
  204. case Lex::TokenKind::Extern:
  205. case Lex::TokenKind::Fn:
  206. case Lex::TokenKind::Import:
  207. case Lex::TokenKind::Interface:
  208. case Lex::TokenKind::Let:
  209. case Lex::TokenKind::Library:
  210. case Lex::TokenKind::Namespace:
  211. case Lex::TokenKind::Require:
  212. case Lex::TokenKind::Var:
  213. #define CARBON_PARSE_NODE_KIND(Name)
  214. #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name) case Lex::TokenKind::Name:
  215. #include "toolchain/parse/node_kind.def"
  216. return false;
  217. case Lex::TokenKind::Package:
  218. // `package.foo` is an expression; any other token after `package` is
  219. // a `package` introducer.
  220. return context.PositionKind(static_cast<Lookahead>(2)) ==
  221. Lex::TokenKind::Period;
  222. default:
  223. return true;
  224. }
  225. break;
  226. default:
  227. return false;
  228. }
  229. }
  230. // Returns true if the current position is a modifier, handling it if so.
  231. static auto TryHandleAsModifier(Context& context) -> bool {
  232. auto position_kind = context.PositionKind();
  233. if (ResolveAmbiguousTokenAsDeclaration(context, position_kind)) {
  234. return false;
  235. }
  236. switch (position_kind) {
  237. #define CARBON_PARSE_NODE_KIND(Name)
  238. #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name) \
  239. case Lex::TokenKind::Name: \
  240. context.AddLeafNode(NodeKind::Name##Modifier, context.Consume()); \
  241. return true;
  242. #include "toolchain/parse/node_kind.def"
  243. case Lex::TokenKind::Extern: {
  244. auto extern_token = context.Consume();
  245. if (context.PositionIs(Lex::TokenKind::Library)) {
  246. // `extern library <owning_library>` syntax.
  247. context.ParseLibrarySpecifier(/*accept_default=*/true);
  248. // TODO: Consider error recovery when a non-declaration token is next,
  249. // like a typo of the library name.
  250. context.AddNode(NodeKind::ExternModifierWithLibrary, extern_token,
  251. /*has_error=*/false);
  252. } else {
  253. // `extern` syntax without a library.
  254. context.AddLeafNode(NodeKind::ExternModifier, extern_token);
  255. }
  256. return true;
  257. }
  258. default:
  259. return false;
  260. }
  261. }
  262. static auto HandleDecl(Context& context, DeclContextKind decl_context_kind)
  263. -> void {
  264. auto state = context.PopState();
  265. // Add a placeholder node, to be replaced by the declaration introducer once
  266. // it is found.
  267. context.AddLeafNode(NodeKind::Placeholder, *context.position());
  268. bool saw_modifier = false;
  269. while (TryHandleAsModifier(context)) {
  270. saw_modifier = true;
  271. }
  272. if (!TryHandleAsDecl(context, state, saw_modifier, decl_context_kind)) {
  273. HandleUnrecognizedDecl(context, state.subtree_start);
  274. }
  275. }
  276. auto HandleDeclAsClass(Context& context) -> void {
  277. HandleDecl(context, ClassContext);
  278. }
  279. auto HandleDeclAsInterface(Context& context) -> void {
  280. HandleDecl(context, InterfaceContext);
  281. }
  282. auto HandleDeclAsRegular(Context& context) -> void {
  283. HandleDecl(context, RegularContext);
  284. }
  285. static auto HandleDeclScopeLoop(Context& context, StateKind decl_state_kind)
  286. -> void {
  287. // This maintains the current state unless we're at the end of the scope.
  288. if (context.PositionIs(Lex::TokenKind::CloseCurlyBrace) ||
  289. context.PositionIs(Lex::TokenKind::FileEnd)) {
  290. // This is the end of the scope, so the loop state ends.
  291. context.PopAndDiscardState();
  292. return;
  293. }
  294. context.PushState(decl_state_kind);
  295. }
  296. auto HandleDeclScopeLoopAsClass(Context& context) -> void {
  297. HandleDeclScopeLoop(context, StateKind::DeclAsClass);
  298. }
  299. auto HandleDeclScopeLoopAsInterface(Context& context) -> void {
  300. HandleDeclScopeLoop(context, StateKind::DeclAsInterface);
  301. }
  302. auto HandleDeclScopeLoopAsRegular(Context& context) -> void {
  303. HandleDeclScopeLoop(context, StateKind::DeclAsRegular);
  304. }
  305. } // namespace Carbon::Parse