handle_modifier.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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/check/context.h"
  5. #include "toolchain/check/decl_state.h"
  6. #include "toolchain/lex/token_kind.h"
  7. namespace Carbon::Check {
  8. CARBON_DIAGNOSTIC(ModifierPrevious, Note, "`{0}` previously appeared here.",
  9. Lex::TokenKind);
  10. static auto EmitRepeatedDiagnostic(Context& context, Parse::NodeId first_node,
  11. Parse::NodeId second_node) -> void {
  12. CARBON_DIAGNOSTIC(ModifierRepeated, Error, "`{0}` repeated on declaration.",
  13. Lex::TokenKind);
  14. context.emitter()
  15. .Build(second_node, ModifierRepeated, context.token_kind(second_node))
  16. .Note(first_node, ModifierPrevious, context.token_kind(first_node))
  17. .Emit();
  18. }
  19. static auto EmitNotAllowedWithDiagnostic(Context& context,
  20. Parse::NodeId first_node,
  21. Parse::NodeId second_node) -> void {
  22. CARBON_DIAGNOSTIC(ModifierNotAllowedWith, Error,
  23. "`{0}` not allowed on declaration with `{1}`.",
  24. Lex::TokenKind, Lex::TokenKind);
  25. context.emitter()
  26. .Build(second_node, ModifierNotAllowedWith,
  27. context.token_kind(second_node), context.token_kind(first_node))
  28. .Note(first_node, ModifierPrevious, context.token_kind(first_node))
  29. .Emit();
  30. }
  31. static auto HandleModifier(Context& context, Parse::NodeId parse_node,
  32. KeywordModifierSet keyword) -> bool {
  33. auto& s = context.decl_state_stack().innermost();
  34. bool is_access = !!(keyword & KeywordModifierSet::Access);
  35. auto& saw_modifier = is_access ? s.saw_access_modifier : s.saw_decl_modifier;
  36. if (!!(s.modifier_set & keyword)) {
  37. EmitRepeatedDiagnostic(context, saw_modifier, parse_node);
  38. } else if (saw_modifier.is_valid()) {
  39. EmitNotAllowedWithDiagnostic(context, saw_modifier, parse_node);
  40. } else if (is_access && s.saw_decl_modifier.is_valid()) {
  41. CARBON_DIAGNOSTIC(ModifierMustAppearBefore, Error,
  42. "`{0}` must appear before `{1}`.", Lex::TokenKind,
  43. Lex::TokenKind);
  44. context.emitter()
  45. .Build(parse_node, ModifierMustAppearBefore,
  46. context.token_kind(parse_node),
  47. context.token_kind(s.saw_decl_modifier))
  48. .Note(s.saw_decl_modifier, ModifierPrevious,
  49. context.token_kind(s.saw_decl_modifier))
  50. .Emit();
  51. } else {
  52. s.modifier_set |= keyword;
  53. saw_modifier = parse_node;
  54. if (is_access || !s.saw_access_modifier.is_valid()) {
  55. s.first_node = parse_node;
  56. }
  57. }
  58. return true;
  59. }
  60. #define CARBON_PARSE_NODE_KIND(...)
  61. #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name, ...) \
  62. auto Handle##Name##Modifier(Context& context, Parse::NodeId parse_node) \
  63. -> bool { \
  64. return HandleModifier(context, parse_node, KeywordModifierSet::Name); \
  65. }
  66. #include "toolchain/parse/node_kind.def"
  67. } // namespace Carbon::Check