handle_match.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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.PushState(StateKind::Pattern);
  122. }
  123. auto HandleMatchCaseAfterPattern(Context& context) -> void {
  124. auto state = context.PopState();
  125. if (state.has_error) {
  126. context.AddNode(NodeKind::MatchCase, *context.position(),
  127. /*has_error=*/true);
  128. context.AddNode(NodeKind::MatchHandlerStart, *context.position(),
  129. /*has_error=*/true);
  130. context.AddNode(NodeKind::MatchHandler, *context.position(),
  131. /*has_error=*/true);
  132. context.SkipPastLikelyEnd(*context.position());
  133. return;
  134. }
  135. context.PushState(state, StateKind::MatchCaseStart);
  136. if (context.PositionIs(Lex::TokenKind::If)) {
  137. context.PushState(StateKind::MatchCaseGuardFinish);
  138. context.AddLeafNode(NodeKind::MatchCaseGuardIntroducer, context.Consume());
  139. auto open_paren = context.ConsumeIf(Lex::TokenKind::OpenParen);
  140. if (open_paren) {
  141. context.AddLeafNode(NodeKind::MatchCaseGuardStart, *open_paren);
  142. context.PushState(StateKind::Expr);
  143. } else {
  144. if (!state.has_error) {
  145. CARBON_DIAGNOSTIC(ExpectedMatchCaseGuardOpenParen, Error,
  146. "expected `(` after `if`");
  147. context.emitter().Emit(*context.position(),
  148. ExpectedMatchCaseGuardOpenParen);
  149. }
  150. context.AddLeafNode(NodeKind::MatchCaseGuardStart, *context.position(),
  151. /*has_error=*/true);
  152. context.AddInvalidParse(*context.position());
  153. state = context.PopState();
  154. context.AddNode(NodeKind::MatchCaseGuard, *context.position(),
  155. /*has_error=*/true);
  156. state = context.PopState();
  157. context.AddNode(NodeKind::MatchCase, *context.position(),
  158. /*has_error=*/true);
  159. context.AddNode(NodeKind::MatchHandlerStart, *context.position(),
  160. /*has_error=*/true);
  161. context.AddNode(NodeKind::MatchHandler, *context.position(),
  162. /*has_error=*/true);
  163. context.SkipPastLikelyEnd(*context.position());
  164. return;
  165. }
  166. }
  167. }
  168. auto HandleMatchCaseGuardFinish(Context& context) -> void {
  169. auto state = context.PopState();
  170. auto close_paren = context.ConsumeIf(Lex::TokenKind::CloseParen);
  171. if (close_paren) {
  172. context.AddNode(NodeKind::MatchCaseGuard, *close_paren, state.has_error);
  173. } else {
  174. if (!state.has_error) {
  175. CARBON_DIAGNOSTIC(ExpectedMatchCaseGuardCloseParen, Error,
  176. "expected `)`");
  177. context.emitter().Emit(*context.position(),
  178. ExpectedMatchCaseGuardCloseParen);
  179. }
  180. context.AddNode(NodeKind::MatchCaseGuard, *context.position(),
  181. /*has_error=*/true);
  182. context.ReturnErrorOnState();
  183. context.SkipPastLikelyEnd(*context.position());
  184. return;
  185. }
  186. }
  187. auto HandleMatchCaseStart(Context& context) -> void {
  188. HandleMatchHandlerStart(context, NodeKind::MatchCase);
  189. }
  190. auto HandleMatchDefaultIntroducer(Context& context) -> void {
  191. context.AddLeafNode(NodeKind::MatchDefaultIntroducer, context.Consume());
  192. HandleMatchHandlerStart(context, NodeKind::MatchDefault);
  193. }
  194. auto HandleMatchHandlerFinish(Context& context) -> void {
  195. auto state = context.PopState();
  196. context.AddNode(NodeKind::MatchHandler,
  197. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  198. state.has_error);
  199. }
  200. auto HandleMatchStatementFinish(Context& context) -> void {
  201. auto state = context.PopState();
  202. context.AddNode(NodeKind::MatchStatement,
  203. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  204. state.has_error);
  205. }
  206. } // namespace Carbon::Parse