handle_period.cpp 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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/diagnostics/format_providers.h"
  5. #include "toolchain/parse/context.h"
  6. #include "toolchain/parse/handle.h"
  7. namespace Carbon::Parse {
  8. // Handles PeriodAs variants and ArrowExpr.
  9. // TODO: This currently only supports identifiers on the rhs, but will in the
  10. // future need to handle things like `object.(Interface.member)` for qualifiers.
  11. static auto HandlePeriodOrArrow(Context& context, NodeKind node_kind,
  12. StateKind paren_state_kind, bool is_arrow)
  13. -> void {
  14. auto state = context.PopState();
  15. // We're handling `.something` or `->something`.
  16. auto dot = context.ConsumeChecked(is_arrow ? Lex::TokenKind::MinusGreater
  17. : Lex::TokenKind::Period);
  18. if (context.ConsumeAndAddLeafNodeIf(
  19. Lex::TokenKind::Identifier,
  20. NodeKind::IdentifierNameNotBeforeSignature)) {
  21. // OK, `.` identifier.
  22. } else if (context.ConsumeAndAddLeafNodeIf(Lex::TokenKind::Base,
  23. NodeKind::BaseName)) {
  24. // OK, `.base`.
  25. } else if (node_kind != NodeKind::StructFieldDesignator &&
  26. context.ConsumeAndAddLeafNodeIf(Lex::TokenKind::IntLiteral,
  27. NodeKind::IntLiteral)) {
  28. // OK, '.42'.
  29. } else if (paren_state_kind != StateKind::Invalid &&
  30. context.PositionIs(Lex::TokenKind::OpenParen)) {
  31. state.kind = paren_state_kind;
  32. context.PushState(state);
  33. context.PushState(StateKind::OnlyParenExpr);
  34. return;
  35. } else {
  36. CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPeriodOrArrow, Error,
  37. "expected identifier after `{0:->|.}`",
  38. Diagnostics::BoolAsSelect);
  39. context.emitter().Emit(*context.position(),
  40. ExpectedIdentifierAfterPeriodOrArrow, is_arrow);
  41. // If we see a keyword, assume it was intended to be a name.
  42. // TODO: Should keywords be valid here?
  43. if (context.PositionKind().is_keyword()) {
  44. context.AddLeafNode(NodeKind::IdentifierNameNotBeforeSignature,
  45. context.Consume(), /*has_error=*/true);
  46. } else {
  47. context.AddLeafNode(NodeKind::IdentifierNameNotBeforeSignature,
  48. *context.position(), /*has_error=*/true);
  49. // Indicate the error to the parent state so that it can avoid producing
  50. // more errors.
  51. context.ReturnErrorOnState();
  52. }
  53. }
  54. context.AddNode(node_kind, dot, state.has_error);
  55. }
  56. auto HandlePeriodAsExpr(Context& context) -> void {
  57. HandlePeriodOrArrow(context, NodeKind::MemberAccessExpr,
  58. StateKind::CompoundMemberAccess,
  59. /*is_arrow=*/false);
  60. }
  61. auto HandlePeriodAsStruct(Context& context) -> void {
  62. HandlePeriodOrArrow(context, NodeKind::StructFieldDesignator,
  63. StateKind::Invalid,
  64. /*is_arrow=*/false);
  65. }
  66. auto HandleArrowExpr(Context& context) -> void {
  67. HandlePeriodOrArrow(context, NodeKind::PointerMemberAccessExpr,
  68. StateKind::CompoundPointerMemberAccess,
  69. /*is_arrow=*/true);
  70. }
  71. auto HandleCompoundMemberAccess(Context& context) -> void {
  72. auto state = context.PopState();
  73. context.AddNode(NodeKind::MemberAccessExpr, state.token, state.has_error);
  74. }
  75. auto HandleCompoundPointerMemberAccess(Context& context) -> void {
  76. auto state = context.PopState();
  77. context.AddNode(NodeKind::PointerMemberAccessExpr, state.token,
  78. state.has_error);
  79. }
  80. } // namespace Carbon::Parse