handle_match.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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/parse/context.h"
  5. #include "toolchain/parse/handle.h"
  6. namespace Carbon::Parse {
  7. static auto HandleMatchHandlerStart(Context& context, NodeKind label_kind)
  8. -> void {
  9. auto state = context.PopState();
  10. if (!context.PositionIs(Lex::TokenKind::EqualGreater)) {
  11. if (!state.has_error) {
  12. CARBON_DIAGNOSTIC(ExpectedMatchCaseArrow, Error,
  13. "expected `=>` introducing statement block");
  14. context.emitter().Emit(*context.position(), ExpectedMatchCaseArrow);
  15. }
  16. context.AddNode(label_kind, *context.position(), /*has_error=*/true);
  17. context.AddNode(NodeKind::MatchHandlerStart, *context.position(),
  18. /*has_error=*/true);
  19. context.AddNode(NodeKind::MatchHandler, *context.position(),
  20. /*has_error=*/true);
  21. context.SkipPastLikelyEnd(*context.position());
  22. return;
  23. }
  24. context.AddLeafNode(label_kind, context.Consume());
  25. if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) {
  26. if (!state.has_error) {
  27. CARBON_DIAGNOSTIC(ExpectedMatchCaseBlock, Error,
  28. "expected `{{` after `=>`");
  29. context.emitter().Emit(*context.position(), ExpectedMatchCaseBlock);
  30. }
  31. context.AddNode(NodeKind::MatchHandlerStart, *context.position(),
  32. /*has_error=*/true);
  33. context.AddNode(NodeKind::MatchHandler, *context.position(),
  34. /*has_error=*/true);
  35. context.SkipPastLikelyEnd(*context.position());
  36. return;
  37. }
  38. context.AddNode(NodeKind::MatchHandlerStart, context.Consume(),
  39. state.has_error);
  40. context.PushState(state, StateKind::MatchHandlerFinish);
  41. context.PushState(StateKind::StatementScopeLoop);
  42. }
  43. static auto EmitUnexpectedTokenAndRecover(Context& context) -> void {
  44. CARBON_DIAGNOSTIC(UnexpectedTokenInMatchCasesBlock, Error,
  45. "unexpected `{0}`; expected `case`, `default` or `}`",
  46. Lex::TokenKind);
  47. context.emitter().Emit(*context.position(), UnexpectedTokenInMatchCasesBlock,
  48. context.PositionKind());
  49. context.ReturnErrorOnState();
  50. context.SkipPastLikelyEnd(*context.position());
  51. }
  52. auto HandleMatchIntroducer(Context& context) -> void {
  53. auto state = context.PopState();
  54. context.AddLeafNode(NodeKind::Placeholder, *context.position());
  55. context.PushState(state, StateKind::MatchConditionFinish);
  56. context.PushState(StateKind::ParenConditionAsMatch);
  57. context.ConsumeAndDiscard();
  58. }
  59. auto HandleMatchConditionFinish(Context& context) -> void {
  60. auto state = context.PopState();
  61. context.ReplacePlaceholderNode(state.subtree_start, NodeKind::MatchIntroducer,
  62. state.token);
  63. if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) {
  64. if (!state.has_error) {
  65. CARBON_DIAGNOSTIC(ExpectedMatchCasesBlock, Error,
  66. "expected `{{` starting block with cases");
  67. context.emitter().Emit(*context.position(), ExpectedMatchCasesBlock);
  68. }
  69. context.AddNode(NodeKind::MatchStatementStart, *context.position(),
  70. /*has_error=*/true);
  71. context.AddNode(NodeKind::MatchStatement, *context.position(),
  72. /*has_error=*/true);
  73. context.SkipPastLikelyEnd(*context.position());
  74. return;
  75. }
  76. context.AddNode(NodeKind::MatchStatementStart, context.Consume(),
  77. state.has_error);
  78. state.has_error = false;
  79. if (context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) {
  80. CARBON_DIAGNOSTIC(ExpectedMatchCases, Error, "expected cases");
  81. context.emitter().Emit(*context.position(), ExpectedMatchCases);
  82. state.has_error = true;
  83. }
  84. context.PushState(state, StateKind::MatchStatementFinish);
  85. context.PushState(StateKind::MatchCaseLoop);
  86. }
  87. auto HandleMatchCaseLoop(Context& context) -> void {
  88. context.PopAndDiscardState();
  89. if (context.PositionIs(Lex::TokenKind::Case)) {
  90. context.PushState(StateKind::MatchCaseLoop);
  91. context.PushState(StateKind::MatchCaseIntroducer);
  92. } else if (context.PositionIs(Lex::TokenKind::Default)) {
  93. context.PushState(StateKind::MatchCaseLoopAfterDefault);
  94. context.PushState(StateKind::MatchDefaultIntroducer);
  95. } else if (!context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) {
  96. EmitUnexpectedTokenAndRecover(context);
  97. context.PushState(StateKind::MatchCaseLoop);
  98. }
  99. }
  100. auto HandleMatchCaseLoopAfterDefault(Context& context) -> void {
  101. context.PopAndDiscardState();
  102. Lex::TokenKind kind = context.PositionKind();
  103. if (kind == Lex::TokenKind::Case or kind == Lex::TokenKind::Default) {
  104. CARBON_DIAGNOSTIC(UnreachableMatchCase, Error,
  105. "unreachable case; `{0}` occurs after the `default`",
  106. Lex::TokenKind);
  107. context.emitter().Emit(*context.position(), UnreachableMatchCase, kind);
  108. context.ReturnErrorOnState();
  109. context.PushState(StateKind::MatchCaseLoopAfterDefault);
  110. context.SkipPastLikelyEnd(*context.position());
  111. return;
  112. } else if (kind != Lex::TokenKind::CloseCurlyBrace) {
  113. EmitUnexpectedTokenAndRecover(context);
  114. context.PushState(StateKind::MatchCaseLoopAfterDefault);
  115. }
  116. }
  117. auto HandleMatchCaseIntroducer(Context& context) -> void {
  118. auto state = context.PopState();
  119. context.AddLeafNode(NodeKind::MatchCaseIntroducer, context.Consume());
  120. context.PushState(state, StateKind::MatchCaseAfterPattern);
  121. context.PushStateForPattern(StateKind::Pattern, /*in_var_pattern=*/false,
  122. /*in_unused_pattern=*/false,
  123. PrecedenceGroup::ForTopLevelPattern());
  124. }
  125. auto HandleMatchCaseAfterPattern(Context& context) -> void {
  126. auto state = context.PopState();
  127. if (state.has_error) {
  128. context.AddNode(NodeKind::MatchCase, *context.position(),
  129. /*has_error=*/true);
  130. context.AddNode(NodeKind::MatchHandlerStart, *context.position(),
  131. /*has_error=*/true);
  132. context.AddNode(NodeKind::MatchHandler, *context.position(),
  133. /*has_error=*/true);
  134. context.SkipPastLikelyEnd(*context.position());
  135. return;
  136. }
  137. context.PushState(state, StateKind::MatchCaseStart);
  138. if (context.PositionIs(Lex::TokenKind::If)) {
  139. context.PushState(StateKind::MatchCaseGuardFinish);
  140. context.AddLeafNode(NodeKind::MatchCaseGuardIntroducer, context.Consume());
  141. auto open_paren = context.ConsumeIf(Lex::TokenKind::OpenParen);
  142. if (open_paren) {
  143. context.AddLeafNode(NodeKind::MatchCaseGuardStart, *open_paren);
  144. context.PushState(StateKind::Expr);
  145. } else {
  146. if (!state.has_error) {
  147. CARBON_DIAGNOSTIC(ExpectedMatchCaseGuardOpenParen, Error,
  148. "expected `(` after `if`");
  149. context.emitter().Emit(*context.position(),
  150. ExpectedMatchCaseGuardOpenParen);
  151. }
  152. context.AddLeafNode(NodeKind::MatchCaseGuardStart, *context.position(),
  153. /*has_error=*/true);
  154. context.AddInvalidParse(*context.position());
  155. state = context.PopState();
  156. context.AddNode(NodeKind::MatchCaseGuard, *context.position(),
  157. /*has_error=*/true);
  158. state = context.PopState();
  159. context.AddNode(NodeKind::MatchCase, *context.position(),
  160. /*has_error=*/true);
  161. context.AddNode(NodeKind::MatchHandlerStart, *context.position(),
  162. /*has_error=*/true);
  163. context.AddNode(NodeKind::MatchHandler, *context.position(),
  164. /*has_error=*/true);
  165. context.SkipPastLikelyEnd(*context.position());
  166. return;
  167. }
  168. }
  169. }
  170. auto HandleMatchCaseGuardFinish(Context& context) -> void {
  171. auto state = context.PopState();
  172. auto close_paren = context.ConsumeIf(Lex::TokenKind::CloseParen);
  173. if (close_paren) {
  174. context.AddNode(NodeKind::MatchCaseGuard, *close_paren, state.has_error);
  175. } else {
  176. if (!state.has_error) {
  177. CARBON_DIAGNOSTIC(ExpectedMatchCaseGuardCloseParen, Error,
  178. "expected `)`");
  179. context.emitter().Emit(*context.position(),
  180. ExpectedMatchCaseGuardCloseParen);
  181. }
  182. context.AddNode(NodeKind::MatchCaseGuard, *context.position(),
  183. /*has_error=*/true);
  184. context.ReturnErrorOnState();
  185. context.SkipPastLikelyEnd(*context.position());
  186. return;
  187. }
  188. }
  189. auto HandleMatchCaseStart(Context& context) -> void {
  190. HandleMatchHandlerStart(context, NodeKind::MatchCase);
  191. }
  192. auto HandleMatchDefaultIntroducer(Context& context) -> void {
  193. context.AddLeafNode(NodeKind::MatchDefaultIntroducer, context.Consume());
  194. HandleMatchHandlerStart(context, NodeKind::MatchDefault);
  195. }
  196. auto HandleMatchHandlerFinish(Context& context) -> void {
  197. auto state = context.PopState();
  198. context.AddNode(NodeKind::MatchHandler,
  199. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  200. state.has_error);
  201. }
  202. auto HandleMatchStatementFinish(Context& context) -> void {
  203. auto state = context.PopState();
  204. context.AddNode(NodeKind::MatchStatement,
  205. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  206. state.has_error);
  207. }
  208. } // namespace Carbon::Parse