handle_match.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. // TODO: Some handling is producing erroneous nodes, but wasn't diagnosing and
  8. // needed to. A more specific diagnostic could be added, but we should probably
  9. // have a larger look at this code and how it produces parse errors. This may be
  10. // good to re-examine when someone is working on implementing match checking.
  11. static auto DiagnoseMatchParseTODO(Context& context) -> void {
  12. CARBON_DIAGNOSTIC(MatchParseTODO, Error, "TODO: improve match parsing");
  13. context.emitter().Emit(*context.position(), MatchParseTODO);
  14. }
  15. static auto HandleStatementsBlockStart(Context& context, State finish,
  16. NodeKind equal_greater, NodeKind starter,
  17. NodeKind complete) -> void {
  18. auto state = context.PopState();
  19. if (!context.PositionIs(Lex::TokenKind::EqualGreater)) {
  20. if (!state.has_error) {
  21. CARBON_DIAGNOSTIC(ExpectedMatchCaseArrow, Error,
  22. "expected `=>` introducing statement block");
  23. context.emitter().Emit(*context.position(), ExpectedMatchCaseArrow);
  24. }
  25. context.AddLeafNode(equal_greater, *context.position(), /*has_error=*/true);
  26. context.AddNode(starter, *context.position(), /*has_error=*/true);
  27. context.AddNode(complete, *context.position(), /*has_error=*/true);
  28. context.SkipPastLikelyEnd(*context.position());
  29. return;
  30. }
  31. context.AddLeafNode(equal_greater, context.Consume());
  32. if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) {
  33. if (!state.has_error) {
  34. CARBON_DIAGNOSTIC(ExpectedMatchCaseBlock, Error,
  35. "expected `{{` after `=>`");
  36. context.emitter().Emit(*context.position(), ExpectedMatchCaseBlock);
  37. }
  38. context.AddNode(starter, *context.position(), /*has_error=*/true);
  39. context.AddNode(complete, *context.position(), /*has_error=*/true);
  40. context.SkipPastLikelyEnd(*context.position());
  41. return;
  42. }
  43. context.AddNode(starter, context.Consume(), state.has_error);
  44. context.PushState(state, finish);
  45. context.PushState(State::StatementScopeLoop);
  46. }
  47. static auto EmitUnexpectedTokenAndRecover(Context& context) -> void {
  48. CARBON_DIAGNOSTIC(UnexpectedTokenInMatchCasesBlock, Error,
  49. "unexpected `{0}`; expected `case`, `default` or `}`",
  50. Lex::TokenKind);
  51. context.emitter().Emit(*context.position(), UnexpectedTokenInMatchCasesBlock,
  52. context.PositionKind());
  53. context.ReturnErrorOnState();
  54. context.SkipPastLikelyEnd(*context.position());
  55. }
  56. auto HandleMatchIntroducer(Context& context) -> void {
  57. auto state = context.PopState();
  58. context.AddLeafNode(NodeKind::Placeholder, *context.position());
  59. context.PushState(state, State::MatchConditionFinish);
  60. context.PushState(State::ParenConditionAsMatch);
  61. context.ConsumeAndDiscard();
  62. }
  63. auto HandleMatchConditionFinish(Context& context) -> void {
  64. auto state = context.PopState();
  65. context.ReplacePlaceholderNode(state.subtree_start, NodeKind::MatchIntroducer,
  66. state.token);
  67. if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) {
  68. if (!state.has_error) {
  69. CARBON_DIAGNOSTIC(ExpectedMatchCasesBlock, Error,
  70. "expected `{{` starting block with cases");
  71. context.emitter().Emit(*context.position(), ExpectedMatchCasesBlock);
  72. }
  73. context.AddNode(NodeKind::MatchStatementStart, *context.position(),
  74. /*has_error=*/true);
  75. context.AddNode(NodeKind::MatchStatement, *context.position(),
  76. /*has_error=*/true);
  77. context.SkipPastLikelyEnd(*context.position());
  78. return;
  79. }
  80. context.AddNode(NodeKind::MatchStatementStart, context.Consume(),
  81. state.has_error);
  82. state.has_error = false;
  83. if (context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) {
  84. CARBON_DIAGNOSTIC(ExpectedMatchCases, Error, "expected cases");
  85. context.emitter().Emit(*context.position(), ExpectedMatchCases);
  86. state.has_error = true;
  87. }
  88. context.PushState(state, State::MatchStatementFinish);
  89. context.PushState(State::MatchCaseLoop);
  90. }
  91. auto HandleMatchCaseLoop(Context& context) -> void {
  92. context.PopAndDiscardState();
  93. if (context.PositionIs(Lex::TokenKind::Case)) {
  94. context.PushState(State::MatchCaseLoop);
  95. context.PushState(State::MatchCaseIntroducer);
  96. } else if (context.PositionIs(Lex::TokenKind::Default)) {
  97. context.PushState(State::MatchCaseLoopAfterDefault);
  98. context.PushState(State::MatchDefaultIntroducer);
  99. } else if (!context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) {
  100. EmitUnexpectedTokenAndRecover(context);
  101. context.PushState(State::MatchCaseLoop);
  102. }
  103. }
  104. auto HandleMatchCaseLoopAfterDefault(Context& context) -> void {
  105. context.PopAndDiscardState();
  106. Lex::TokenKind kind = context.PositionKind();
  107. if (kind == Lex::TokenKind::Case or kind == Lex::TokenKind::Default) {
  108. CARBON_DIAGNOSTIC(UnreachableMatchCase, Error,
  109. "unreachable case; `{0}` occurs after the `default`",
  110. Lex::TokenKind);
  111. context.emitter().Emit(*context.position(), UnreachableMatchCase, kind);
  112. context.ReturnErrorOnState();
  113. context.PushState(State::MatchCaseLoopAfterDefault);
  114. context.SkipPastLikelyEnd(*context.position());
  115. return;
  116. } else if (kind != Lex::TokenKind::CloseCurlyBrace) {
  117. EmitUnexpectedTokenAndRecover(context);
  118. context.PushState(State::MatchCaseLoopAfterDefault);
  119. }
  120. }
  121. auto HandleMatchCaseIntroducer(Context& context) -> void {
  122. auto state = context.PopState();
  123. context.AddLeafNode(NodeKind::MatchCaseIntroducer, context.Consume());
  124. context.PushState(state, State::MatchCaseAfterPattern);
  125. context.PushState(State::Pattern);
  126. }
  127. auto HandleMatchCaseAfterPattern(Context& context) -> void {
  128. auto state = context.PopState();
  129. if (state.has_error) {
  130. context.AddNode(NodeKind::MatchCaseStart, *context.position(),
  131. /*has_error=*/true);
  132. context.AddNode(NodeKind::MatchCase, *context.position(),
  133. /*has_error=*/true);
  134. context.SkipPastLikelyEnd(*context.position());
  135. return;
  136. }
  137. context.PushState(state, State::MatchCaseStart);
  138. if (context.PositionIs(Lex::TokenKind::If)) {
  139. context.PushState(State::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(State::Expr);
  145. } else {
  146. if (!state.has_error) {
  147. DiagnoseMatchParseTODO(context);
  148. }
  149. context.AddLeafNode(NodeKind::MatchCaseGuardStart, *context.position(),
  150. true);
  151. context.AddInvalidParse(*context.position());
  152. state = context.PopState();
  153. context.AddNode(NodeKind::MatchCaseGuard, *context.position(),
  154. /*has_error=*/true);
  155. state = context.PopState();
  156. context.AddNode(NodeKind::MatchCaseStart, *context.position(),
  157. /*has_error=*/true);
  158. context.AddNode(NodeKind::MatchCase, *context.position(),
  159. /*has_error=*/true);
  160. context.SkipPastLikelyEnd(*context.position());
  161. return;
  162. }
  163. }
  164. }
  165. auto HandleMatchCaseGuardFinish(Context& context) -> void {
  166. auto state = context.PopState();
  167. auto close_paren = context.ConsumeIf(Lex::TokenKind::CloseParen);
  168. if (close_paren) {
  169. context.AddNode(NodeKind::MatchCaseGuard, *close_paren, state.has_error);
  170. } else {
  171. if (!state.has_error) {
  172. DiagnoseMatchParseTODO(context);
  173. }
  174. context.AddNode(NodeKind::MatchCaseGuard, *context.position(),
  175. /*has_error=*/true);
  176. context.ReturnErrorOnState();
  177. context.SkipPastLikelyEnd(*context.position());
  178. return;
  179. }
  180. }
  181. auto HandleMatchCaseStart(Context& context) -> void {
  182. HandleStatementsBlockStart(context, State::MatchCaseFinish,
  183. NodeKind::MatchCaseEqualGreater,
  184. NodeKind::MatchCaseStart, NodeKind::MatchCase);
  185. }
  186. auto HandleMatchCaseFinish(Context& context) -> void {
  187. auto state = context.PopState();
  188. context.AddNode(NodeKind::MatchCase,
  189. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  190. state.has_error);
  191. }
  192. auto HandleMatchDefaultIntroducer(Context& context) -> void {
  193. context.AddLeafNode(NodeKind::MatchDefaultIntroducer, context.Consume());
  194. HandleStatementsBlockStart(
  195. context, State::MatchDefaultFinish, NodeKind::MatchDefaultEqualGreater,
  196. NodeKind::MatchDefaultStart, NodeKind::MatchDefault);
  197. }
  198. auto HandleMatchDefaultFinish(Context& context) -> void {
  199. auto state = context.PopState();
  200. context.AddNode(NodeKind::MatchDefault,
  201. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  202. state.has_error);
  203. }
  204. auto HandleMatchStatementFinish(Context& context) -> void {
  205. auto state = context.PopState();
  206. context.AddNode(NodeKind::MatchStatement,
  207. context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace),
  208. state.has_error);
  209. }
  210. } // namespace Carbon::Parse