<commit_before>var assert = require("assert");
var Syntax = require("./types").Syntax;
var printComment = require("./comments").print;
var linesModule = require("./lines");
var fromString = linesModule.fromString;
var concat = linesModule.concat;
var normalizeOptions = require("./options").normalize;
var getReprinter = require("./patcher").getReprinter;
var types = require("./types").namedTypes;
var Path = require("./path").Path;

function Printer(options) {
    assert.ok(this instanceof Printer);

    options = normalizeOptions(options);

    function printWithComments(path) {
        assert.ok(path instanceof Path);

        var without = print(path);
        var node = path.node;
        var orig = node.original;
        var comments = node.comments || (orig && orig.comments);

        if (comments) {
            var printed = comments.map(printComment);
            if (without)
                printed.push(without);
            return fromString("\n").join(printed);
        }

        return without;
    }

    function print(path, includeComments) {
        if (includeComments)
            return printWithComments(path);

        assert.ok(path instanceof Path);

        var reprinter = getReprinter(path);
        if (reprinter)
            return reprinter(printRootGenerically);

        return printRootGenerically(path);
    }

    // Print the root node generically, but then resume reprinting its
    // children non-generically.
    function printRootGenerically(path) {
        return genericPrint(path, options, printWithComments);
    }

    // Print the entire AST generically.
    function printGenerically(path) {
        return genericPrint(path, options, printGenerically);
    }

    this.print = function(ast) {
        if (!ast) return "";
        return print(new Path(ast), true).toString(options);
    };

    this.printGenerically = function(ast) {
        if (!ast) return "";
        return printGenerically(new Path(ast)).toString(options);
    };
}

exports.Printer = Printer;

function genericPrint(path, options, printPath) {
    var lines = genericPrintNoParens(path.node, options, function(node) {
        if (!node)
            return fromString("");

        if (typeof node === "string")
            return fromString(node, options.tabWidth);

        return printPath(path.cons(node));
    });

    if (path.needsParens())
        return concat(["(", lines, ")"]);

    return lines;
}

function genericPrintNoParens(n, options, print) {
    switch (n.type) {
    case Syntax.File:
        n = n.program;
        types.Program.assert(n);

        // intentionally fall through...

    case Syntax.Program:
        return maybeAddSemicolon(
            fromString("\n\n").join(n.body.map(print)));

    case Syntax.EmptyStatement:
        return fromString("");

    case Syntax.ExpressionStatement:
        return concat([print(n.expression), ";"]);

    case Syntax.BinaryExpression:
    case Syntax.LogicalExpression:
    case Syntax.AssignmentExpression:
        return fromString(" ").join([
            print(n.left),
            print(n.operator),
            print(n.right)
        ]);

    case Syntax.MemberExpression:<commit_msg>Use printNakedBlockStatement to print Program bodies.<commit_after>var assert = require("assert");
var Syntax = require("./types").Syntax;
var printComment = require("./comments").print;
var linesModule = require("./lines");
var fromString = linesModule.fromString;
var concat = linesModule.concat;
var normalizeOptions = require("./options").normalize;
var getReprinter = require("./patcher").getReprinter;
var types = require("./types").namedTypes;
var Path = require("./path").Path;

function Printer(options) {
    assert.ok(this instanceof Printer);

    options = normalizeOptions(options);

    function printWithComments(path) {
        assert.ok(path instanceof Path);

        var without = print(path);
        var node = path.node;
        var orig = node.original;
        var comments = node.comments || (orig && orig.comments);

        if (comments) {
            var printed = comments.map(printComment);
            if (without)
                printed.push(without);
            return fromString("\n").join(printed);
        }

        return without;
    }

    function print(path, includeComments) {
        if (includeComments)
            return printWithComments(path);

        assert.ok(path instanceof Path);

        var reprinter = getReprinter(path);
        if (reprinter)
            return reprinter(printRootGenerically);

        return printRootGenerically(path);
    }

    // Print the root node generically, but then resume reprinting its
    // children non-generically.
    function printRootGenerically(path) {
        return genericPrint(path, options, printWithComments);
    }

    // Print the entire AST generically.
    function printGenerically(path) {
        return genericPrint(path, options, printGenerically);
    }

    this.print = function(ast) {
        if (!ast) return "";
        return print(new Path(ast), true).toString(options);
    };

    this.printGenerically = function(ast) {
        if (!ast) return "";
        return printGenerically(new Path(ast)).toString(options);
    };
}

exports.Printer = Printer;

function genericPrint(path, options, printPath) {
    var lines = genericPrintNoParens(path.node, options, function(node) {
        if (!node)
            return fromString("");

        if (typeof node === "string")
            return fromString(node, options.tabWidth);

        return printPath(path.cons(node));
    });

    if (path.needsParens())
        return concat(["(", lines, ")"]);

    return lines;
}

function genericPrintNoParens(n, options, print) {
    switch (n.type) {
    case Syntax.File:
        n = n.program;
        types.Program.assert(n);

        // intentionally fall through...

    case Syntax.Program:
        return maybeAddSemicolon(
            printNakedBlockStatement({
                type: Syntax.BlockStatement,
                body: n.body
            }, print)
        );

    case Syntax.EmptyStatement:
        return fromString("");

    case Syntax.ExpressionStatement:
        return concat([print(n.expression), ";"]);

    case Syntax.BinaryExpression:
    case Syntax.LogicalExpression:
    case Syntax.AssignmentExpression:
        return fromString(" ").join([
            print(n.left),
            print(n.operator),
            print(n.right)
        ]);

    case Syntax.MemberExpression:
{'fraction_non_alphanumeric': 0.1210727969348659, 'fraction_numerical': 0.0, 'mean_word_length': 2.575890410958904, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '3045653', 'n_tokens_mistral': 1822, 'n_tokens_neox': 1751, 'n_words': 419}