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 15241x 15241x 15241x 15241x 60872x 846208x 846208x 846208x 60872x 15241x 15241x 15241x 15241x 15241x 15241x 612057x 612057x 612057x 612057x 612057x 612057x 612057x 417965x 417965x 417965x 417965x 417965x 1128441x 1128441x 710769x 710769x 710769x 710769x 710769x 710769x 710769x 710769x 328958x 328958x 328958x 710769x 710769x 1128441x 381518x 381518x 1128441x 417965x 417965x 417965x 612057x 612057x 612057x 612057x 15241x 15241x 15241x  
/** @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;
}