Source: utility/AstPrinter.js

'use strict';

/**
 * Traverses a collection of ASTs and converts each node to a printable string.
 * Used mainly for testing purposes.
 */
class AstPrinter {

  /**
   * Converts a collection of ASTs into strings and prints them to the console.
   * @param  {Statement[]} statements Collection of ASTs to print.
   * @return {string} String representing the collection of ASTs.
   */
  print(statements) {
    const output = [];

    for(let statement of statements) {
      output.push(statement.accept(this));
    }

    return output.filter((o) => o !== undefined).join('\n');
  }

  _parenthesize(name, ...expressions) {
    expressions = expressions.filter((e) => e !== undefined)
      .map((e) => e.accept(this)).join(' ');

    return `( ${name}${expressions.length > 0 ? ` ${expressions}` : ''} )`;
  }

  // Statements
  visitBlockStatement(statement) {
    const statements = statement.statements.map((s) => s.accept(this)).join(' ; ');

    return `( block${statements.length > 0 ? ` ${statements}` : ''} )`;
  }

  visitExpressionStatement(statement) {
    return this._parenthesize('statement', statement.expression);
  }

  visitPrintStatement(statement) {
    return this._parenthesize('print', statement.expression);
  }

  visitVariableStatement(statement) {
    return this._parenthesize(`declare ${statement.name.lexeme}`, statement.initializer);
  }

  // Expressions
  visitAssignmentExpression(expression) {
    return this._parenthesize(`assign ${expression.name.lexeme}`, expression.value);
  }

  visitBinaryExpression(expression) {
    return this._parenthesize(expression.operator.lexeme, expression.left, expression.right);
  }

  visitGroupingExpression(expression) {
    return this._parenthesize('group', expression.expression);
  }

  visitLiteralExpression(expression) {
    return `${expression.value}`;
  }

  visitUnaryExpression(expression) {
    return this._parenthesize(expression.operator.lexeme, expression.right);
  }

  visitVariableExpression(expression) {
    return this._parenthesize(`var ${expression.name.lexeme}`);
  }
}

module.exports = AstPrinter;