import { ExtendedResult, Parser, any, anyNot, disablePreParse, kind, makeEolf, or, repeat, req, resultLog, seq, setTraceName, tracing, withSep, } from "mini-parse"; import { AbstractElem, AbstractElemBase } from "./AbstractElems.js"; import { argsTokens, mainTokens } from "./MatchWgslD.js"; import { lineComment } from "./ParseDirective.js"; /* Basic parsing functions for comment handling, eol, etc. */ export const word = kind(mainTokens.word); export const wordNum = or(word, kind(mainTokens.digits)); export const unknown = any().map((r) => { const { kind, text } = r.value; const deepName = r.ctx._debugNames.join(" > "); resultLog(r, `??? ${kind}: '${text}' ${deepName}`); // throw new Error("Fail fast"); }); export const blockComment: Parser = seq( "/*", repeat(or(() => blockComment, anyNot("*/"))), req("*/") ); export const comment = or(() => lineComment, blockComment); export const eolf: Parser = disablePreParse( makeEolf(argsTokens, argsTokens.ws) ); /** ( a1, b1* ) with optinoal comments, spans lines */ export const wordNumArgs: Parser = seq( "(", withSep(",", wordNum), req(")") ).map((r) => r.value[1]); type ByKind = U extends { kind: T } ? U : never; type TagsType = Record< Exclude, any[] >; /** create an AbstractElem from parse results * @param named keys in the tags result to copy to * like named fields in the abstract elem (as a single value) * @param namedArray keys in the tags result to copy to * like named fields in the abstract elem (as an array) */ export function makeElem< U extends AbstractElem, K extends U["kind"], // 'kind' of AbtractElem "fn" E extends ByKind, // FnElem T extends TagsType, // {name: string[]} >( kind: K, er: ExtendedResult>, tags: (keyof T)[] = [], tagArrays: (keyof T)[] = [] ): Partial { const { start, end } = er; const nv = mapIfDefined(tags, er.tags, true); const av = mapIfDefined(tagArrays, er.tags); return { kind, start, end, ...nv, ...av } as Partial; } function mapIfDefined( keys: (keyof A)[], array: Partial>, firstElemOnly?: boolean ): Partial> { const entries = keys.flatMap((k) => { const ak = array[k]; const v = firstElemOnly ? ak?.[0] : ak; if (v === undefined) return []; else return [[k, v]]; }); return Object.fromEntries(entries); } if (tracing) { const names: Record> = { skipBlockComment: blockComment, comment, wordNumArgs, }; Object.entries(names).forEach(([name, parser]) => { setTraceName(parser, name); }); }