All files / src/compiler/phases visitors.js

95.89% Statements 70/73
100% Branches 11/11
66.66% Functions 4/6
95.89% Lines 70/73

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 742x 2x 2x   2x 2x     2x 2x 2x 2x 2x 2x 2x 2x 2x 15161x 15161x 15161x 15161x 60554x 841394x 841394x 841394x 60554x 15161x 15161x 15161x 15161x 15161x 15161x 608559x 608559x 608559x 608559x 608559x 608559x 608559x 415039x 415039x 415039x 415039x 415039x 1120529x 1120529x 705783x 705783x 705783x 705783x 705783x 705783x 705783x 705783x 326622x 326622x 326622x 705783x 705783x 1120529x 378868x 378868x 1120529x 415039x 415039x 415039x 608559x 608559x 608559x 608559x 15161x 15161x 15161x  
/** @import { Visitors, Context } from 'zimmerframe' */
const overrides = {
	visit() {
		throw new Error('Cannot call visit() during analysis');
	},
	stop() {
		throw new Error('Cannot call stop() during analysis');
	}
};
 
/**
 * @template {{ type: string }} T
 * @template U
 * @param  {...Visitors<T, U>} tasks
 * @returns
 */
export function merge(...tasks) {
	/** @type {Record<string, any[]>} */
	const visitors = {};
 
	for (const task of tasks) {
		for (const key in task) {
			if (!visitors[key]) visitors[key] = [];
			visitors[key].push(task[key]);
		}
	}
 
	/** @type {Visitors<T, U>} */
	// @ts-expect-error
	const combined = {};
 
	for (const key in visitors) {
		const fns = visitors[key];
 
		/**
		 * @param {T} node
		 * @param {Context<T, U>} context
		 */
		function visitor(node, context) {
			/**
			 * @param {number} i
			 * @param {U} state
			 */
			function go(i, state) {
				const fn = fns[i];
				if (!fn) return context.next(state);
 
				let called_next = false;
 
				fn(node, {
					...context,
					...overrides,
					state,
					next(next_state = state) {
						called_next = true;
						go(i + 1, next_state);
					}
				});
 
				if (!called_next) {
					go(i + 1, state);
				}
			}
 
			go(0, context.state);
		}
 
		// @ts-expect-error
		combined[key] = visitor;
	}
 
	return combined;
}