thi-ng/umbrella

View on GitHub
packages/parse/src/xform/print.ts

Summary

Maintainability
A
55 mins
Test Coverage
import type { Fn } from "@thi.ng/api";
import type { Parser, ScopeTransform } from "../api.js";
import { xform } from "../combinators/xform.js";
import { __indent } from "../utils.js";

/**
 * Side effect only. Higher order scope transform. Traverses current AST
 * node and all children and prints each node's ID, result and reader
 * state (if available). Also see {@link print}.
 *
 * @remarks
 * The optional `fn` function is used to print each AST node (default:
 * `console.log`).
 *
 * @param scope -
 * @param ctx -
 * @param level -
 */
export const xfPrint = (fn: Fn<string, void> = console.log) => {
    const $print: ScopeTransform<any> = (scope, _, level = 0) => {
        if (!scope) return;
        const prefix = __indent(level);
        const state = scope.state;
        const info = state ? ` (${state.l}:${state.c})` : "";
        fn(`${prefix}${scope.id}${info}: ${JSON.stringify(scope.result)}`);
        if (scope.children) {
            for (let c of scope.children) {
                $print(c, _, level + 1);
            }
        }
        return scope;
    };
    return $print;
};

/**
 * Syntax sugar for `xform(parser, xfPrint)`.
 *
 * @example
 * ```ts tangle:../../export/print.ts
 * import { ALPHA, defContext, lit, oneOrMore, print, seq } from "@thi.ng/parse";
 *
 * print(seq([lit("["), oneOrMore(ALPHA), lit("]")]))(defContext("[abc]"));
 * // seq: null
 * //   lit: "["
 * //   repeat1: null
 * //     oneOf: "a"
 * //     oneOf: "b"
 * //     oneOf: "c"
 * //   lit: "]"
 * ```
 *
 * @param parser -
 */
export const print = <T>(parser: Parser<T>, fn?: Fn<string, void>) =>
    xform(parser, xfPrint(fn));