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 15372x 15372x 15372x 15372x 61379x 880838x 880838x 880838x 61379x 15372x 15372x 15372x 15372x 15372x 15372x 632620x 632620x 632620x 632620x 632620x 632620x 632620x 429068x 429068x 429068x 429068x 429068x 1155081x 1155081x 726308x 726308x 726308x 726308x 726308x 726308x 726308x 726308x 353956x 353956x 353956x 726308x 726308x 1155081x 372057x 372057x 1155081x 429068x 429068x 429068x 632620x 632620x 632620x 632620x 15372x 15372x 15372x  
/** @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;
}