瀏覽代碼

Treesitter: fix where clause (#2998)

follow up to #2902
mx42 2 年之前
父節點
當前提交
1d2853ef08
共有 2 個文件被更改,包括 50 次插入56 次删除
  1. 50 42
      utils/treesitter/grammar.js
  2. 0 14
      utils/treesitter/test_runner.cpp

+ 50 - 42
utils/treesitter/grammar.js

@@ -18,24 +18,24 @@ function comma_sep(thing) {
 
 // This is based on toolchain/parser/precedence.cpp
 const PREC = {
-  TermPrefix: 11,
-  TermPostfix: 11,
-  NumericPrefix: 10,
-  NumericPostfix: 10,
-  Multiplicative: 9,
-  Additive: 8,
-  BitwisePrefix: 7,
-  BitwiseAnd: 6,
-  BitwiseOr: 6,
-  BitwiseXor: 6,
-  BitShift: 6,
-  TypePostfix: 5,
-  LogicalPrefix: 4,
-  Relational: 3,
-  LogicalAnd: 2,
-  LogicalOr: 2,
+  TermPrefix: 12,
+  TermPostfix: 12,
+  NumericPrefix: 11,
+  NumericPostfix: 11,
+  Multiplicative: 10,
+  Additive: 9,
+  BitwisePrefix: 8,
+  BitwiseAnd: 7,
+  BitwiseOr: 7,
+  BitwiseXor: 7,
+  BitShift: 7,
+  TypePostfix: 6,
+  LogicalPrefix: 5,
+  Relational: 4,
+  LogicalAnd: 3,
+  LogicalOr: 3,
+  IfExpression: 2,
   WhereClause: 1,
-  IfExpression: 1,
 };
 
 module.exports = grammar({
@@ -198,10 +198,11 @@ module.exports = grammar({
         $.paren_pattern,
         // alternative patterns
         // example: Optional(i32).Some(x: i32)
-        seq($._expression, $.paren_pattern)
+        seq($._simple_expression, $.paren_pattern)
       ),
 
-    _pattern: ($) => choice($._pattern_without_expression, $._expression),
+    _pattern: ($) =>
+      choice($._pattern_without_expression, $._simple_expression),
 
     unary_prefix_expression: ($) => {
       const table = [
@@ -252,13 +253,14 @@ module.exports = grammar({
     // This should be non-associative but conflicts are not allowed in tree-sitter
     as_expression: ($) => prec.left(seq($._expression, 'as', $._expression)),
 
-    ref_expression: ($) => prec.right(PREC.TermPrefix, seq('&', $._expression)),
+    ref_expression: ($) =>
+      prec.right(PREC.TermPrefix, seq('&', $._simple_expression)),
 
     deref_expression: ($) =>
-      prec.right(PREC.TermPrefix, seq('*', $._expression)),
+      prec.right(PREC.TermPrefix, seq('*', $._simple_expression)),
 
     fn_type_expression: ($) =>
-      prec.left(seq('__Fn', $.paren_expression, '->', $._expression)),
+      prec.left(seq('__Fn', $.paren_expression, '->', $._simple_expression)),
 
     if_expression: ($) =>
       prec(
@@ -269,7 +271,10 @@ module.exports = grammar({
     paren_expression: ($) => seq('(', comma_sep($._expression), ')'),
 
     index_expression: ($) =>
-      prec(PREC.TermPostfix, seq($._expression, '[', $._expression, ']')),
+      prec(
+        PREC.TermPostfix,
+        seq($._simple_expression, '[', $._expression, ']')
+      ),
 
     designator: ($) => seq('.', choice('base', $.ident)),
 
@@ -277,7 +282,7 @@ module.exports = grammar({
       prec(
         PREC.TermPostfix,
         seq(
-          $._expression,
+          $._simple_expression,
           choice(
             '++',
             '--',
@@ -289,51 +294,54 @@ module.exports = grammar({
       ),
 
     where_clause: ($) =>
-      prec(
-        PREC.WhereClause,
-        choice(
-          seq($._expression, '==', $._expression),
-          seq($._expression, 'impls', $._expression),
-          seq($._expression, '=', $._expression),
-          // TODO: Fix conflict with logical and
-          prec.left(seq($.where_clause, 'and', $.where_clause))
+      choice(
+        seq($._simple_expression, '==', $._simple_expression),
+        seq($._simple_expression, 'impls', $._simple_expression),
+        seq($._simple_expression, '=', $._simple_expression),
+        prec.left(
+          PREC.WhereClause + 1,
+          seq($.where_clause, 'and', $.where_clause)
         )
       ),
 
     where_expression: ($) =>
-      prec.left(PREC.TermPostfix, seq($._expression, 'where', $.where_clause)),
+      prec.left(PREC.WhereClause, seq($._expression, 'where', $.where_clause)),
 
     call_expression: ($) =>
-      prec(PREC.TermPostfix, seq($._expression, $.paren_expression)),
+      prec(PREC.TermPostfix, seq($._simple_expression, $.paren_expression)),
 
     pointer_expression: ($) =>
-      prec(PREC.TypePostfix, seq($._expression, $.postfix_star)),
+      prec(PREC.TypePostfix, seq($._simple_expression, $.postfix_star)),
 
-    _expression: ($) =>
+    _simple_expression: ($) =>
       choice(
         $.array_literal,
-        $.as_expression,
-        $.binary_expression,
         $.builtin_type,
         $.call_expression,
         $.deref_expression,
         $.fn_type_expression,
         $.ident,
-        $.if_expression,
         $.index_expression,
         $.literal,
         $.paren_expression,
         $.pointer_expression,
         $.postfix_expression,
         $.ref_expression,
-        $.unary_prefix_expression,
-        $.where_expression,
         'self',
-        // TODO: Remove these two once `where` clauses don't use the expression rule
         '.Self',
         $.designator
       ),
 
+    _expression: ($) =>
+      choice(
+        $.as_expression,
+        $.binary_expression,
+        $.if_expression,
+        $.unary_prefix_expression,
+        $.where_expression,
+        $._simple_expression
+      ),
+
     var_declaration: ($) =>
       seq(
         'var',

+ 0 - 14
utils/treesitter/test_runner.cpp

@@ -36,18 +36,10 @@ auto main(int argc, char** argv) -> int {
   ts_parser_set_language(parser, tree_sitter_carbon());
 
   std::vector<std::string> failed;
-  std::vector<std::string> skipped;
   for (int i = 1; i < argc; i++) {
     std::string file_path = argv[i];
     std::string source = ReadFile(file_path);
 
-    // `and` in where clauses is not parsed correctly.
-    // TODO: remove once where clause is implemented correctly.
-    if (source.find("where") != std::string::npos &&
-        source.find("and") != std::string::npos) {
-      skipped.push_back(file_path);
-      continue;
-    }
     auto* tree =
         ts_parser_parse_string(parser, nullptr, source.data(), source.size());
 
@@ -64,15 +56,9 @@ auto main(int argc, char** argv) -> int {
     ts_tree_delete(tree);
   }
   ts_parser_delete(parser);
-  for (const auto& file : skipped) {
-    std::cout << "SKIPPED " << file << "\n";
-  }
   for (const auto& file : failed) {
     std::cout << "FAILED " << file << "\n";
   }
-  if (!skipped.empty()) {
-    std::cout << skipped.size() << " tests skipped.\n";
-  }
   if (!failed.empty()) {
     std::cout << failed.size() << " tests failing.\n";
     return 1;