<commit_before>import XCTest
import SwiftSyntax
import SwiftParser
import SwiftOperatorPrecedence

/// Visitor that looks for ExprSequenceSyntax nodes.
private class ExprSequenceSearcher: SyntaxAnyVisitor {
  var foundSequenceExpr = false

  override func visit(
    _ node: SequenceExprSyntax
  ) -> SyntaxVisitorContinueKind {
    foundSequenceExpr = true
    return .skipChildren
  }

  override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind{
    return foundSequenceExpr ? .skipChildren : .visitChildren
  }
}

extension SyntaxProtocol {
  /// Determine whether the given syntax contains an ExprSequence anywhere.
  var containsExprSequence: Bool {
    let searcher = ExprSequenceSearcher(viewMode: .sourceAccurate)
    searcher.walk(self)
    return searcher.foundSequenceExpr
  }
}

public class OperatorPrecedenceTests: XCTestCase {
  func testLogicalExprs() throws {
    let opPrecedence = OperatorPrecedence.logicalOperators
    let parsed = try Parser.parse(source: "x && y || w && v || z")
    let sequenceExpr =
      parsed.statements.first!.item.as(SequenceExprSyntax.self)!
    let foldedExpr = try opPrecedence.foldSingle(sequenceExpr)
    XCTAssertEqual("\(foldedExpr)", "x && y || w && v || z")
    XCTAssertNil(foldedExpr.as(SequenceExprSyntax.self))
  }

  func testSwiftExprs() throws {
    let opPrecedence = OperatorPrecedence.standardOperators
    let parsed = try Parser.parse(source: "(x + y > 17) && x && y || w && v || z")
    let sequenceExpr =
        parsed.statements.first!.item.as(SequenceExprSyntax.self)!
    let foldedExpr = try opPrecedence.foldSingle(sequenceExpr)
    XCTAssertEqual("\(foldedExpr)", "(x + y > 17) && x && y || w && v || z")
    XCTAssertNil(foldedExpr.as(SequenceExprSyntax.self))
  }

  func testNestedSwiftExprs() throws {<commit_msg>Add infrastructure to make it easy to test the result of sequence folding.<commit_after>import XCTest
import SwiftSyntax
import SwiftParser
import SwiftOperatorPrecedence
import _SwiftSyntaxTestSupport

/// Visitor that looks for ExprSequenceSyntax nodes.
private class ExprSequenceSearcher: SyntaxAnyVisitor {
  var foundSequenceExpr = false

  override func visit(
    _ node: SequenceExprSyntax
  ) -> SyntaxVisitorContinueKind {
    foundSequenceExpr = true
    return .skipChildren
  }

  override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind{
    return foundSequenceExpr ? .skipChildren : .visitChildren
  }
}

extension SyntaxProtocol {
  /// Determine whether the given syntax contains an ExprSequence anywhere.
  var containsExprSequence: Bool {
    let searcher = ExprSequenceSearcher(viewMode: .sourceAccurate)
    searcher.walk(self)
    return searcher.foundSequenceExpr
  }
}

/// A syntax rewriter that folds explicitly-parenthesized sequence expressions
/// into  a structured syntax tree.
class ExplicitParenFolder : SyntaxRewriter {
  override func visit(_ node: TupleExprSyntax) -> ExprSyntax {
    // Identify syntax nodes of the form (x + y), which is a
    // TupleExprSyntax(SequenceExpr(x, BinaryOperatorExprSyntax, y))./
    guard node.elementList.count == 1,
          let firstNode = node.elementList.first,
          firstNode.label == nil,
          let sequenceExpr = firstNode.expression.as(SequenceExprSyntax.self),
          sequenceExpr.elements.count == 3,
          let leftOperand = sequenceExpr.elements.first,
          let middleExpr = sequenceExpr.elements.removingFirst().first,
          let operatorExpr = middleExpr.as(BinaryOperatorExprSyntax.self),
          let rightOperand =
            sequenceExpr.elements.removingFirst().removingFirst().first
    else {
      return ExprSyntax(node)
    }

    return ExprSyntax(
      InfixOperatorExprSyntax(
        leftOperand: visit(Syntax(leftOperand)).as(ExprSyntax.self)!,
        operatorOperand: ExprSyntax(operatorExpr),
        rightOperand: visit(Syntax(rightOperand)).as(ExprSyntax.self)!)
      )
  }
}

extension OperatorPrecedence {
  /// Assert that parsing and folding the given "unfolded" source code
  /// produces the same syntax tree as the fully-parenthesized version of
  /// the same source.
  ///
  /// The `expectedSource` should be a fully-parenthesized expression, e.g.,
  /// `(a + (b * c))` that expresses how the initial code should have been
  /// folded.
  func assertExpectedFold(
    _ source: String,
    _ fullyParenthesizedSource: String
  ) throws {
    // Parse and fold the source we're testing.
    let parsed = try Parser.parse(source: source)
    let foldedSyntax = try foldAll(parsed)
    XCTAssertFalse(foldedSyntax.containsExprSequence)

    // Parse and "fold" the parenthesized version.
    let parenthesizedParsed = try Parser.parse(source: fullyParenthesizedSource)
    let parenthesizedSyntax = ExplicitParenFolder().visit(parenthesizedParsed)
    XCTAssertFalse(parenthesizedSyntax.containsExprSequence)

    // Make sure the two have the same structure.
    XCTAssertSameStructure(foldedSyntax, parenthesizedSyntax)
  }
}

public class OperatorPrecedenceTests: XCTestCase {
  func testLogicalExprsSingle() throws {
    let opPrecedence = OperatorPrecedence.logicalOperators
    let parsed = try Parser.parse(source: "x && y || w && v || z")
    let sequenceExpr =
      parsed.statements.first!.item.as(SequenceExprSyntax.self)!
    let foldedExpr = try opPrecedence.foldSingle(sequenceExpr)
    XCTAssertEqual("\(foldedExpr)", "x && y || w && v || z")
    XCTAssertNil(foldedExpr.as(SequenceExprSyntax.self))
  }

  func testLogicalExprs() throws {
    let opPrecedence = OperatorPrecedence.logicalOperators
    try opPrecedence.assertExpectedFold("x && y || w", "((x && y) || w)")
    try opPrecedence.assertExpectedFold("x || y && w", "(x || (y && w))")
  }

  func testSwiftExprs() throws {
    let opPrecedence = OperatorPrecedence.standardOperators
    let parsed = try Parser.parse(source: "(x + y > 17) && x && y || w && v || z")
    let sequenceExpr =
        parsed.statements.first!.item.as(SequenceExprSyntax.self)!
    let foldedExpr = try opPrecedence.foldSingle(sequenceExpr)
    XCTAssertEqual("\(foldedExpr)", "(x + y > 17) && x && y || w && v || z")
    XCTAssertNil(foldedExpr.as(SequenceExprSyntax.self))
  }

  func testNestedSwiftExprs() throws {
{'fraction_non_alphanumeric': 0.09995186908390823, 'fraction_numerical': 0.0016043638697256538, 'mean_word_length': 3.7953846153846156, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5933614', 'n_tokens_mistral': 1861, 'n_tokens_neox': 1808, 'n_words': 468}