tsv_ts 0.8.0

TypeScript/JS formatter, type stripper and acorn-compatible parser — part of tsv
Documentation
// Control flow statement writers.

use super::expressions::write_expression;
use super::statements::{write_block_statement, write_statement, write_variable_declaration};
use super::{
    Ctx, JsonWriter, close_node, node_header, write_array, write_identifier_plain, write_or_null,
};
use crate::ast;
use tsv_lang::Span;

/// Emits an `IfStatement` node.
pub(super) fn write_if_statement(
    w: &mut JsonWriter,
    if_stmt: &ast::IfStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "IfStatement", span, ctx);
    w.raw(",\"test\":");
    write_expression(w, if_stmt.test, ctx);
    w.raw(",\"consequent\":");
    write_statement(w, if_stmt.consequent, ctx);
    w.raw(",\"alternate\":");
    write_or_null(w, if_stmt.alternate.as_ref(), |w, alt| {
        write_statement(w, alt, ctx);
    });
    close_node(w, "IfStatement", span, ctx);
}

/// Emits a `ForStatement` node. `init`/`test`/`update` are nullable.
pub(super) fn write_for_statement(
    w: &mut JsonWriter,
    for_stmt: &ast::ForStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "ForStatement", span, ctx);
    w.raw(",\"init\":");
    match &for_stmt.init {
        Some(ast::ForInit::VariableDeclaration(decl)) => {
            write_variable_declaration(w, decl, ctx, false);
        }
        Some(ast::ForInit::Expression(expr)) => write_expression(w, expr, ctx),
        None => w.null(),
    }
    w.raw(",\"test\":");
    write_or_null(w, for_stmt.test.as_ref(), |w, test| {
        write_expression(w, test, ctx);
    });
    w.raw(",\"update\":");
    write_or_null(w, for_stmt.update.as_ref(), |w, update| {
        write_expression(w, update, ctx);
    });
    w.raw(",\"body\":");
    write_statement(w, for_stmt.body, ctx);
    close_node(w, "ForStatement", span, ctx);
}

/// Emit a `for`-`in`/`for`-`of` `left` (an untagged declaration-or-pattern).
fn write_for_in_of_left(w: &mut JsonWriter, left: &ast::ForInOfLeft<'_>, ctx: &Ctx<'_>) {
    match left {
        ast::ForInOfLeft::VariableDeclaration(decl) => {
            write_variable_declaration(w, decl, ctx, false);
        }
        ast::ForInOfLeft::Pattern(expr) => write_expression(w, expr, ctx),
    }
}

/// Emits a `ForInStatement` node.
pub(super) fn write_for_in_statement(
    w: &mut JsonWriter,
    for_in: &ast::ForInStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "ForInStatement", span, ctx);
    w.raw(",\"left\":");
    write_for_in_of_left(w, for_in.left, ctx);
    w.raw(",\"right\":");
    write_expression(w, for_in.right, ctx);
    w.raw(",\"body\":");
    write_statement(w, for_in.body, ctx);
    close_node(w, "ForInStatement", span, ctx);
}

/// Emits a `ForOfStatement` node. Field order: `await`, `left`, `right`,
/// `body`.
pub(super) fn write_for_of_statement(
    w: &mut JsonWriter,
    for_of: &ast::ForOfStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "ForOfStatement", span, ctx);
    w.raw(",\"await\":");
    w.bool(for_of.r#await);
    w.raw(",\"left\":");
    write_for_in_of_left(w, for_of.left, ctx);
    w.raw(",\"right\":");
    write_expression(w, for_of.right, ctx);
    w.raw(",\"body\":");
    write_statement(w, for_of.body, ctx);
    close_node(w, "ForOfStatement", span, ctx);
}

/// Emits a `WhileStatement` node.
pub(super) fn write_while_statement(
    w: &mut JsonWriter,
    while_stmt: &ast::WhileStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "WhileStatement", span, ctx);
    w.raw(",\"test\":");
    write_expression(w, while_stmt.test, ctx);
    w.raw(",\"body\":");
    write_statement(w, while_stmt.body, ctx);
    close_node(w, "WhileStatement", span, ctx);
}

/// Emits a `WithStatement` node. Field order: `object`, `body`.
pub(super) fn write_with_statement(
    w: &mut JsonWriter,
    with_stmt: &ast::WithStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "WithStatement", span, ctx);
    w.raw(",\"object\":");
    write_expression(w, with_stmt.object, ctx);
    w.raw(",\"body\":");
    write_statement(w, with_stmt.body, ctx);
    close_node(w, "WithStatement", span, ctx);
}

/// Emits a `DoWhileStatement` node. Field order: `body`, `test`.
pub(super) fn write_do_while_statement(
    w: &mut JsonWriter,
    do_while: &ast::DoWhileStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "DoWhileStatement", span, ctx);
    w.raw(",\"body\":");
    write_statement(w, do_while.body, ctx);
    w.raw(",\"test\":");
    write_expression(w, do_while.test, ctx);
    close_node(w, "DoWhileStatement", span, ctx);
}

/// Emits a `SwitchStatement` node (each case a `SwitchCase`).
pub(super) fn write_switch_statement(
    w: &mut JsonWriter,
    switch_stmt: &ast::SwitchStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "SwitchStatement", span, ctx);
    w.raw(",\"discriminant\":");
    write_expression(w, switch_stmt.discriminant, ctx);
    w.raw(",\"cases\":");
    // acorn initializes `consequent` before parsing `test`, so it serializes first.
    write_array(w, switch_stmt.cases, |w, case| {
        node_header(w, "SwitchCase", case.span, ctx);
        w.raw(",\"consequent\":");
        write_array(w, case.consequent, |w, s| {
            write_statement(w, s, ctx);
        });
        w.raw(",\"test\":");
        write_or_null(w, case.test.as_ref(), |w, t| write_expression(w, t, ctx));
        close_node(w, "SwitchCase", case.span, ctx);
    });
    close_node(w, "SwitchStatement", span, ctx);
}

/// Emits a `TryStatement` node (its `handler` a `CatchClause`). `handler` and
/// `finalizer` are nullable, as is the catch clause's `param`.
pub(super) fn write_try_statement(
    w: &mut JsonWriter,
    try_stmt: &ast::TryStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "TryStatement", span, ctx);
    w.raw(",\"block\":");
    write_block_statement(w, &try_stmt.block, ctx);
    w.raw(",\"handler\":");
    write_or_null(w, try_stmt.handler.as_ref(), |w, clause| {
        node_header(w, "CatchClause", clause.span, ctx);
        w.raw(",\"param\":");
        write_or_null(w, clause.param.as_ref(), |w, p| write_expression(w, p, ctx));
        w.raw(",\"body\":");
        write_block_statement(w, &clause.body, ctx);
        close_node(w, "CatchClause", clause.span, ctx);
    });
    w.raw(",\"finalizer\":");
    write_or_null(w, try_stmt.finalizer.as_ref(), |w, f| {
        write_block_statement(w, f, ctx);
    });
    close_node(w, "TryStatement", span, ctx);
}

/// Emits a `ThrowStatement` node.
pub(super) fn write_throw_statement(
    w: &mut JsonWriter,
    throw_stmt: &ast::ThrowStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "ThrowStatement", span, ctx);
    w.raw(",\"argument\":");
    write_expression(w, throw_stmt.argument, ctx);
    close_node(w, "ThrowStatement", span, ctx);
}

/// Emits a `BreakStatement` node. `label` is nullable.
pub(super) fn write_break_statement(
    w: &mut JsonWriter,
    break_stmt: &ast::BreakStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "BreakStatement", span, ctx);
    w.raw(",\"label\":");
    write_or_null(w, break_stmt.label.as_ref(), |w, id| {
        write_identifier_plain(w, id, ctx);
    });
    close_node(w, "BreakStatement", span, ctx);
}

/// Emits a `ContinueStatement` node. `label` is nullable.
pub(super) fn write_continue_statement(
    w: &mut JsonWriter,
    continue_stmt: &ast::ContinueStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "ContinueStatement", span, ctx);
    w.raw(",\"label\":");
    write_or_null(w, continue_stmt.label.as_ref(), |w, id| {
        write_identifier_plain(w, id, ctx);
    });
    close_node(w, "ContinueStatement", span, ctx);
}

/// Emits a `LabeledStatement` node.
pub(super) fn write_labeled_statement(
    w: &mut JsonWriter,
    labeled: &ast::LabeledStatement<'_>,
    span: Span,
    ctx: &Ctx<'_>,
) {
    node_header(w, "LabeledStatement", span, ctx);
    // acorn assigns `body` before `label`, so it serializes first.
    w.raw(",\"body\":");
    write_statement(w, labeled.body, ctx);
    w.raw(",\"label\":");
    write_identifier_plain(w, &labeled.label, ctx);
    close_node(w, "LabeledStatement", span, ctx);
}