precedence.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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/parser/precedence.h"
  5. #include <utility>
  6. #include "common/check.h"
  7. namespace Carbon {
  8. namespace {
  9. enum PrecedenceLevel : int8_t {
  10. // Sentinel representing the absence of any operator.
  11. Highest,
  12. // Terms.
  13. TermPrefix,
  14. // Numeric.
  15. NumericPrefix,
  16. NumericPostfix,
  17. Modulo,
  18. Multiplicative,
  19. Additive,
  20. // Bitwise.
  21. BitwisePrefix,
  22. BitwiseAnd,
  23. BitwiseOr,
  24. BitwiseXor,
  25. BitShift,
  26. // Type formation.
  27. TypePostfix,
  28. // Sentinel representing a type context.
  29. Type,
  30. // Logical.
  31. LogicalPrefix,
  32. Relational,
  33. LogicalAnd,
  34. LogicalOr,
  35. // Conditional.
  36. If,
  37. // Assignment.
  38. SimpleAssignment,
  39. CompoundAssignment,
  40. // Sentinel representing a context in which any operator can appear.
  41. Lowest,
  42. };
  43. constexpr int8_t NumPrecedenceLevels = Lowest + 1;
  44. // A precomputed lookup table determining the relative precedence of two
  45. // precedence groups.
  46. struct OperatorPriorityTable {
  47. constexpr OperatorPriorityTable() : table() {
  48. // Start with a list of <higher precedence>, <lower precedence>
  49. // relationships.
  50. MarkHigherThan({Highest}, {TermPrefix});
  51. MarkHigherThan({TermPrefix}, {NumericPrefix, BitwisePrefix, LogicalPrefix,
  52. NumericPostfix, TypePostfix});
  53. MarkHigherThan({NumericPrefix, NumericPostfix},
  54. {Modulo, Multiplicative, BitShift});
  55. MarkHigherThan({Multiplicative}, {Additive});
  56. MarkHigherThan({BitwisePrefix},
  57. {BitwiseAnd, BitwiseOr, BitwiseXor, BitShift});
  58. MarkHigherThan({TypePostfix}, {Type});
  59. MarkHigherThan(
  60. {Modulo, Additive, BitwiseAnd, BitwiseOr, BitwiseXor, BitShift, Type},
  61. {Relational});
  62. MarkHigherThan({Relational, LogicalPrefix}, {LogicalAnd, LogicalOr});
  63. MarkHigherThan({LogicalAnd, LogicalOr}, {If});
  64. MarkHigherThan({If}, {SimpleAssignment, CompoundAssignment});
  65. MarkHigherThan({SimpleAssignment, CompoundAssignment}, {Lowest});
  66. // Compute the transitive closure of the above relationships: if we parse
  67. // `a $ b @ c` as `(a $ b) @ c` and parse `b @ c % d` as `(b @ c) % d`,
  68. // then we will parse `a $ b @ c % d` as `((a $ b) @ c) % d` and should
  69. // also parse `a $ bc % d` as `(a $ bc) % d`.
  70. MakeTransitivelyClosed();
  71. // Make the relation symmetric. If we parse `a $ b @ c` as `(a $ b) @ c`
  72. // then we want to parse `a @ b $ c` as `a @ (b $ c)`.
  73. MakeSymmetric();
  74. // Fill in the diagonal, which represents operator associativity.
  75. AddAssociativityRules();
  76. ConsistencyCheck();
  77. }
  78. constexpr void MarkHigherThan(
  79. std::initializer_list<PrecedenceLevel> higher_group,
  80. std::initializer_list<PrecedenceLevel> lower_group) {
  81. for (auto higher : higher_group) {
  82. for (auto lower : lower_group) {
  83. table[higher][lower] = OperatorPriority::LeftFirst;
  84. }
  85. }
  86. }
  87. constexpr void MakeTransitivelyClosed() {
  88. // A naive algorithm compiles acceptably fast for now (~0.5s). This should
  89. // be revisited if we see compile time problems after adding precedence
  90. // groups; it's easy to do this faster.
  91. bool changed = false;
  92. do {
  93. changed = false;
  94. // NOLINTNEXTLINE(modernize-loop-convert)
  95. for (int8_t a = 0; a != NumPrecedenceLevels; ++a) {
  96. for (int8_t b = 0; b != NumPrecedenceLevels; ++b) {
  97. if (table[a][b] == OperatorPriority::LeftFirst) {
  98. for (int8_t c = 0; c != NumPrecedenceLevels; ++c) {
  99. if (table[b][c] == OperatorPriority::LeftFirst &&
  100. table[a][c] != OperatorPriority::LeftFirst) {
  101. table[a][c] = OperatorPriority::LeftFirst;
  102. changed = true;
  103. }
  104. }
  105. }
  106. }
  107. }
  108. } while (changed);
  109. }
  110. constexpr void MakeSymmetric() {
  111. for (int8_t a = 0; a != NumPrecedenceLevels; ++a) {
  112. for (int8_t b = 0; b != NumPrecedenceLevels; ++b) {
  113. if (table[a][b] == OperatorPriority::LeftFirst) {
  114. CARBON_CHECK(table[b][a] != OperatorPriority::LeftFirst)
  115. << "inconsistent lookup table entries";
  116. table[b][a] = OperatorPriority::RightFirst;
  117. }
  118. }
  119. }
  120. }
  121. constexpr void AddAssociativityRules() {
  122. // Associativity rules occupy the diagonal
  123. // For prefix operators, RightFirst would mean `@@x` is `@(@x)` and
  124. // Ambiguous would mean it's an error. LeftFirst is meaningless. For now we
  125. // allow all prefix operators to be repeated.
  126. for (PrecedenceLevel prefix :
  127. {TermPrefix, NumericPrefix, BitwisePrefix, LogicalPrefix, If}) {
  128. table[prefix][prefix] = OperatorPriority::RightFirst;
  129. }
  130. // Postfix operators are symmetric with prefix operators.
  131. for (PrecedenceLevel postfix : {NumericPostfix, TypePostfix}) {
  132. table[postfix][postfix] = OperatorPriority::LeftFirst;
  133. }
  134. // Traditionally-associative operators are given left-to-right
  135. // associativity.
  136. for (PrecedenceLevel assoc :
  137. {Multiplicative, Additive, BitwiseAnd, BitwiseOr, BitwiseXor,
  138. LogicalAnd, LogicalOr}) {
  139. table[assoc][assoc] = OperatorPriority::LeftFirst;
  140. }
  141. // Assignment is given right-to-left associativity in order to support
  142. // chained assignment.
  143. table[SimpleAssignment][SimpleAssignment] = OperatorPriority::RightFirst;
  144. // For other operators, there isn't an obvious answer and we require
  145. // explicit parentheses.
  146. }
  147. constexpr void ConsistencyCheck() {
  148. for (int8_t level = 0; level != NumPrecedenceLevels; ++level) {
  149. if (level != Highest) {
  150. CARBON_CHECK(table[Highest][level] == OperatorPriority::LeftFirst &&
  151. table[level][Highest] == OperatorPriority::RightFirst)
  152. << "Highest is not highest priority";
  153. }
  154. if (level != Lowest) {
  155. CARBON_CHECK(table[Lowest][level] == OperatorPriority::RightFirst &&
  156. table[level][Lowest] == OperatorPriority::LeftFirst)
  157. << "Lowest is not lowest priority";
  158. }
  159. }
  160. }
  161. OperatorPriority table[NumPrecedenceLevels][NumPrecedenceLevels];
  162. };
  163. } // namespace
  164. auto PrecedenceGroup::ForPostfixExpression() -> PrecedenceGroup {
  165. return PrecedenceGroup(Highest);
  166. }
  167. auto PrecedenceGroup::ForTopLevelExpression() -> PrecedenceGroup {
  168. return PrecedenceGroup(Lowest);
  169. }
  170. auto PrecedenceGroup::ForType() -> PrecedenceGroup {
  171. return PrecedenceGroup(Type);
  172. }
  173. auto PrecedenceGroup::ForLeading(TokenKind kind)
  174. -> std::optional<PrecedenceGroup> {
  175. switch (kind) {
  176. case TokenKind::Star:
  177. return PrecedenceGroup(TermPrefix);
  178. case TokenKind::Not:
  179. return PrecedenceGroup(LogicalPrefix);
  180. case TokenKind::Minus:
  181. case TokenKind::MinusMinus:
  182. case TokenKind::PlusPlus:
  183. return PrecedenceGroup(NumericPrefix);
  184. case TokenKind::Tilde:
  185. return PrecedenceGroup(BitwisePrefix);
  186. case TokenKind::If:
  187. return PrecedenceGroup(If);
  188. default:
  189. return std::nullopt;
  190. }
  191. }
  192. auto PrecedenceGroup::ForTrailing(TokenKind kind, bool infix)
  193. -> std::optional<Trailing> {
  194. switch (kind) {
  195. // Assignment operators.
  196. case TokenKind::Equal:
  197. return Trailing{.level = SimpleAssignment, .is_binary = true};
  198. case TokenKind::PlusEqual:
  199. case TokenKind::MinusEqual:
  200. case TokenKind::StarEqual:
  201. case TokenKind::SlashEqual:
  202. case TokenKind::PercentEqual:
  203. case TokenKind::AmpEqual:
  204. case TokenKind::PipeEqual:
  205. case TokenKind::GreaterGreaterEqual:
  206. case TokenKind::LessLessEqual:
  207. return Trailing{.level = CompoundAssignment, .is_binary = true};
  208. // Logical operators.
  209. case TokenKind::And:
  210. return Trailing{.level = LogicalAnd, .is_binary = true};
  211. case TokenKind::Or:
  212. return Trailing{.level = LogicalOr, .is_binary = true};
  213. // Bitwise operators.
  214. case TokenKind::Amp:
  215. return Trailing{.level = BitwiseAnd, .is_binary = true};
  216. case TokenKind::Pipe:
  217. return Trailing{.level = BitwiseOr, .is_binary = true};
  218. case TokenKind::Xor:
  219. return Trailing{.level = BitwiseXor, .is_binary = true};
  220. case TokenKind::GreaterGreater:
  221. case TokenKind::LessLess:
  222. return Trailing{.level = BitShift, .is_binary = true};
  223. // Relational operators.
  224. case TokenKind::EqualEqual:
  225. case TokenKind::ExclaimEqual:
  226. case TokenKind::Less:
  227. case TokenKind::LessEqual:
  228. case TokenKind::Greater:
  229. case TokenKind::GreaterEqual:
  230. case TokenKind::LessEqualGreater:
  231. return Trailing{.level = Relational, .is_binary = true};
  232. // Additive operators.
  233. case TokenKind::Plus:
  234. case TokenKind::Minus:
  235. return Trailing{.level = Additive, .is_binary = true};
  236. // Multiplicative operators.
  237. case TokenKind::Slash:
  238. return Trailing{.level = Multiplicative, .is_binary = true};
  239. case TokenKind::Percent:
  240. return Trailing{.level = Modulo, .is_binary = true};
  241. // `*` could be multiplication or pointer type formation.
  242. case TokenKind::Star:
  243. return infix ? Trailing{.level = Multiplicative, .is_binary = true}
  244. : Trailing{.level = TypePostfix, .is_binary = false};
  245. // Postfix operators.
  246. case TokenKind::MinusMinus:
  247. case TokenKind::PlusPlus:
  248. return Trailing{.level = NumericPostfix, .is_binary = false};
  249. // Prefix-only operators.
  250. case TokenKind::Tilde:
  251. case TokenKind::Not:
  252. break;
  253. // Symbolic tokens that might be operators eventually.
  254. case TokenKind::Backslash:
  255. case TokenKind::Caret:
  256. case TokenKind::CaretEqual:
  257. case TokenKind::Comma:
  258. case TokenKind::TildeEqual:
  259. case TokenKind::Exclaim:
  260. case TokenKind::LessGreater:
  261. case TokenKind::Question:
  262. case TokenKind::Colon:
  263. break;
  264. // Symbolic tokens that are intentionally not operators.
  265. case TokenKind::At:
  266. case TokenKind::LessMinus:
  267. case TokenKind::MinusGreater:
  268. case TokenKind::EqualGreater:
  269. case TokenKind::ColonEqual:
  270. case TokenKind::Period:
  271. case TokenKind::Semi:
  272. break;
  273. default:
  274. break;
  275. }
  276. return std::nullopt;
  277. }
  278. auto PrecedenceGroup::GetPriority(PrecedenceGroup left, PrecedenceGroup right)
  279. -> OperatorPriority {
  280. static constexpr OperatorPriorityTable Lookup;
  281. return Lookup.table[left.level_][right.level_];
  282. }
  283. } // namespace Carbon