Home Manual Reference Source

src/transform/visitor.js

import {ast} from '@formal-language/grammar';

import {map} from '@iterable-iterator/map';
import {any} from '@iterable-iterator/reduce';

import grammar from '../grammar.js';

const t = ast.transform;
const cmap = ast.cmap;
const recurse = (nonterminal, production) => (tree, match, ctx) => ({
	type: 'node',
	nonterminal,
	production,
	children: cmap(
		async (x) => (x.type === 'leaf' ? x : t(x, match, ctx)),
		tree.children,
	),
});

const skip = (tree) => tree;

// Move to @formal-languague/grammar/ast.visitor
function generateVisitor(grammar) {
	const transform = {};

	for (const [nonterminal, productions] of grammar.productions.entries()) {
		const nonterminalTransform = {};

		for (const [key, rules] of productions.entries()) {
			if (any(map((x) => x.type === 'node', rules))) {
				nonterminalTransform[key] = recurse(nonterminal, key);
			} else {
				// TODO test if this actually is faster
				nonterminalTransform[key] = skip;
			}
		}

		transform[nonterminal] = nonterminalTransform;
	}

	return transform;
}

export const extend = (transform, extension) => {
	const result = {};
	for (const key in transform) {
		if (Object.prototype.hasOwnProperty.call(transform, key)) {
			result[key] = Object.assign({}, transform[key], extension[key]);
		}
	}

	return result;
};

export const visitor = generateVisitor(grammar);