parseman 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5539,9 +5539,10 @@ function compileRuleMap(ruleMap, opts) {
5539
5539
  ].join("\n");
5540
5540
  return { keys: perEntry.map((e) => e.key), replacement };
5541
5541
  }
5542
- function compileLinkable(ruleMapArg, ns) {
5542
+ function compileLinkable(ruleMapArg, ns, opts) {
5543
5543
  if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
5544
5544
  for (const [, rule] of ruleMapArg) markUnusedValues(rule);
5545
+ const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
5545
5546
  const ruleMap = ruleMapArg.filter(([, val]) => {
5546
5547
  const d = val._def;
5547
5548
  if (d.tag !== "lazy") return true;
@@ -5572,7 +5573,8 @@ function compileLinkable(ruleMapArg, ns) {
5572
5573
  capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
5573
5574
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
5574
5575
  ns,
5575
- deferFirstSetRefs: true
5576
+ deferFirstSetRefs: true,
5577
+ ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
5576
5578
  };
5577
5579
  const seen = /* @__PURE__ */ new Map();
5578
5580
  const ruleNames = /* @__PURE__ */ new Map();
@@ -5635,7 +5637,10 @@ function compileLinkable(ruleMapArg, ns) {
5635
5637
  ctx.indent = 1;
5636
5638
  ctx.failLabel = "_pfail";
5637
5639
  ctx.recordFail = true;
5640
+ const savedTrivia = ctx.activeTrivia;
5641
+ if (rule._meta.isTrivia) ctx.activeTrivia = void 0;
5638
5642
  const body = emit(resolved, ctx, "_pos");
5643
+ ctx.activeTrivia = savedTrivia;
5639
5644
  ctx.indent = savedIndent;
5640
5645
  ctx.failLabel = savedFail;
5641
5646
  ctx.recordFail = savedRec;
@@ -6129,6 +6134,23 @@ ${body}
6129
6134
  };
6130
6135
 
6131
6136
  // src/compiler/linker.ts
6137
+ function pickPieces(pieces, names) {
6138
+ const winner = /* @__PURE__ */ new Map();
6139
+ for (const pc of pieces) for (const k of pc.keys) winner.set(k, pc);
6140
+ for (const n of names) {
6141
+ if (!winner.has(n)) throw new Error(`pick: rule "${n}" is not in this grammar (available: ${[...winner.keys()].join(", ")})`);
6142
+ }
6143
+ const keep = /* @__PURE__ */ new Set();
6144
+ const visit = (n) => {
6145
+ const w = winner.get(n);
6146
+ if (keep.has(n) || !w) return;
6147
+ keep.add(n);
6148
+ for (const d of w.deps.get(n) ?? []) visit(d);
6149
+ };
6150
+ for (const n of names) visit(n);
6151
+ const filt = (m, pc) => new Map([...m].filter(([k]) => keep.has(k) && winner.get(k) === pc));
6152
+ return pieces.map((pc) => ({ ...pc, keys: pc.keys.filter((k) => keep.has(k) && winner.get(k) === pc), ruleFns: filt(pc.ruleFns, pc), wrappers: filt(pc.wrappers, pc), deps: filt(pc.deps, pc) })).filter((pc) => pc.keys.length > 0);
6153
+ }
6132
6154
  function fusedBody(pieces) {
6133
6155
  const winner = /* @__PURE__ */ new Map();
6134
6156
  for (const p of pieces) for (const k of p.keys) winner.set(k, p);
@@ -6148,7 +6170,7 @@ function fusedBody(pieces) {
6148
6170
  ...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
6149
6171
  ...needsHostReads ? [HOST_READS_DECL] : [],
6150
6172
  // Each contributing artifact's namespaced private prelude (regexes, _pf, …).
6151
- ...[...new Set(contributingPieces.flatMap((p) => p.prelude))],
6173
+ ...new Set(contributingPieces.flatMap((p) => p.prelude)),
6152
6174
  // The winning `_r_<Name>` function for each rule (one per name → no redeclare).
6153
6175
  ...[...winner].map(([k, p]) => p.ruleFns.get(k))
6154
6176
  ];
@@ -6189,9 +6211,9 @@ ${body}
6189
6211
  function isIRPiece(p) {
6190
6212
  return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
6191
6213
  }
6192
- function materializePiece(p) {
6214
+ function materializePiece(p, trivia2) {
6193
6215
  if (!isIRPiece(p)) return p;
6194
- const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns);
6216
+ const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, trivia2 ? { trivia: trivia2 } : void 0);
6195
6217
  if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
6196
6218
  return pieces;
6197
6219
  }
@@ -6897,11 +6919,13 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
6897
6919
  warn(init.start, `${label2}: rule map couldn't be inlined`);
6898
6920
  return null;
6899
6921
  }
6900
- return { replacement: compiled.replacement, ruleMap };
6922
+ return { replacement: compiled.replacement, ruleMap, ...gTrivia ? { trivia: gTrivia } : {} };
6901
6923
  };
6902
6924
  const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
6903
6925
  const isComposeCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "compose";
6926
+ const isPickCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "pick";
6904
6927
  const localRuleMaps = /* @__PURE__ */ new Map();
6928
+ const localGrammarTrivia = /* @__PURE__ */ new Map();
6905
6929
  const nsFor = (label2) => `_${(0, import_node_crypto.createHash)("sha1").update(`${id}#${label2}`).digest("hex").slice(0, 8)}_`;
6906
6930
  const stripIndent = (s) => s.replace(/\n[ \t]+/g, "\n");
6907
6931
  const serializePieces = (p) => {
@@ -6915,7 +6939,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
6915
6939
  const serializeItem = (it) => isSpread(it) ? `...(${it.__spreadLocal}[Symbol.for('parseman.composedPieces')] ?? [])` : isIR(it) ? `{ ns: ${JSON.stringify(it.ns)}, ir: ${JSON.stringify(it.ir)} }` : serializePieces(it);
6916
6940
  const serializeList = (list) => `[${list.map(serializeItem).join(", ")}]`;
6917
6941
  const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)}, enumerable: false })`;
6918
- const localComposedPieces = /* @__PURE__ */ new Map();
6942
+ const localComposedCarried = /* @__PURE__ */ new Map();
6943
+ const localComposedTrivia = /* @__PURE__ */ new Map();
6919
6944
  const importedPiecesCache = /* @__PURE__ */ new Map();
6920
6945
  const resolveModulePieces = (file, exportName, seen) => {
6921
6946
  const mod = parseModuleCached(file);
@@ -6949,7 +6974,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
6949
6974
  }
6950
6975
  try {
6951
6976
  const list = new Function(...stubNames, `return (${literal2})`)(...stubVals);
6952
- return list.map(materializePiece);
6977
+ return list;
6953
6978
  } catch {
6954
6979
  return null;
6955
6980
  }
@@ -6969,32 +6994,108 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
6969
6994
  importedPiecesCache.set(localName, result2);
6970
6995
  return result2;
6971
6996
  };
6972
- const localArg = (rm, label2) => {
6997
+ const materializeCarried = (items, composing) => {
6998
+ const out = [];
6999
+ for (const it of items) {
7000
+ if (isSpread(it)) {
7001
+ for (const p of importedPieces(it.__spreadLocal) ?? []) out.push(materializePiece(p, composing));
7002
+ } else if (isIR(it)) {
7003
+ out.push(materializePiece(it, composing));
7004
+ } else {
7005
+ out.push(it);
7006
+ }
7007
+ }
7008
+ return out;
7009
+ };
7010
+ const localCarried = (rm, label2, composing) => {
6973
7011
  const entries = [...rm];
6974
7012
  const ns = nsFor(label2);
6975
- const p = compileLinkable(entries, ns);
6976
- if (!p) return null;
6977
7013
  const ir = serializeRuleMap(entries);
6978
- return ir ? { pieces: [p], ir: { ns, ir } } : { pieces: [p] };
7014
+ if (ir) return { carried: [{ ns, ir }] };
7015
+ const p = compileLinkable(entries, ns, composing ? { trivia: composing } : void 0);
7016
+ return p ? { carried: [p] } : null;
6979
7017
  };
6980
- const argPieces = (arg, label2) => {
7018
+ const argPieces = (arg, label2, composing) => {
7019
+ if (isPickCall(arg)) {
7020
+ const pargs = arg.arguments;
7021
+ const inner = pargs[0];
7022
+ const namesArg = pargs[1];
7023
+ if (!inner || namesArg?.type !== "ArrayExpression") return null;
7024
+ const names = [];
7025
+ for (const el of namesArg.elements ?? []) {
7026
+ const v2 = el?.value;
7027
+ if ((el?.type === "Literal" || el?.type === "StringLiteral") && typeof v2 === "string") names.push(v2);
7028
+ else return null;
7029
+ }
7030
+ const innerArg = argPieces(inner, `${label2}_pick`);
7031
+ if (!innerArg) return null;
7032
+ try {
7033
+ return { carried: pickPieces(materializeCarried(innerArg.carried, ownTrivia(inner)), names) };
7034
+ } catch (e) {
7035
+ warn(arg.start, `pick(): ${e.message}`);
7036
+ return null;
7037
+ }
7038
+ }
6981
7039
  if (isRulesCall(arg)) {
6982
- const factory = arg.arguments[0];
7040
+ const rulesArgs = arg.arguments;
7041
+ const a0 = rulesArgs[0];
7042
+ const a1 = rulesArgs[1];
7043
+ const optionsFirst = a0?.type === "ObjectExpression";
7044
+ const factory = optionsFirst ? a1 : a0;
6983
7045
  const rm = factory ? evaluateParserFactory(factory, scope, code, []) : null;
6984
- return rm ? localArg(rm, label2) : null;
7046
+ return rm ? localCarried(rm, label2, composing) : null;
6985
7047
  }
6986
7048
  if (arg.type === "Identifier") {
6987
7049
  const name = arg.name;
6988
7050
  const rm = localRuleMaps.get(name);
6989
- if (rm) return localArg(rm, label2);
6990
- const composed = localComposedPieces.get(name);
6991
- if (composed) return { pieces: composed };
7051
+ if (rm) return localCarried(rm, label2, composing);
7052
+ const composed = localComposedCarried.get(name);
7053
+ if (composed) return { carried: composed };
6992
7054
  const pieces = importedPieces(name);
6993
7055
  if (!pieces) return null;
6994
- return importBindings.has(name) ? { pieces, spreadLocal: name } : { pieces };
7056
+ return { carried: importBindings.has(name) ? [{ __spreadLocal: name }] : [...pieces] };
6995
7057
  }
6996
7058
  return null;
6997
7059
  };
7060
+ const rulesCallTrivia = (el) => {
7061
+ const rulesArgs = el.arguments;
7062
+ const a0 = rulesArgs[0];
7063
+ const a1 = rulesArgs[1];
7064
+ const optExpr = a0?.type === "ObjectExpression" ? a0 : a1?.type === "ObjectExpression" ? a1 : void 0;
7065
+ const triviaProp = (optExpr?.properties ?? []).find(
7066
+ (p) => p.key?.name === "trivia"
7067
+ );
7068
+ if (!triviaProp?.value) return void 0;
7069
+ return evaluateExpr(triviaProp.value, scope, code, []) ?? void 0;
7070
+ };
7071
+ const composingTrivia = (elements) => {
7072
+ for (let i = elements.length - 1; i >= 0; i--) {
7073
+ const el = elements[i];
7074
+ if (!el) continue;
7075
+ if (isRulesCall(el)) {
7076
+ const t = rulesCallTrivia(el);
7077
+ if (t) return t;
7078
+ continue;
7079
+ }
7080
+ if (el.type === "Identifier") {
7081
+ const t = localGrammarTrivia.get(el.name);
7082
+ if (t) return t;
7083
+ }
7084
+ }
7085
+ return void 0;
7086
+ };
7087
+ const ownTrivia = (arg) => {
7088
+ if (isRulesCall(arg)) return rulesCallTrivia(arg);
7089
+ if (isPickCall(arg)) {
7090
+ const inner = arg.arguments[0];
7091
+ return inner ? ownTrivia(inner) : void 0;
7092
+ }
7093
+ if (arg.type === "Identifier") {
7094
+ const name = arg.name;
7095
+ return localGrammarTrivia.get(name) ?? localComposedTrivia.get(name);
7096
+ }
7097
+ return void 0;
7098
+ };
6998
7099
  const compileComposeCall = (init) => {
6999
7100
  const args = init.arguments;
7000
7101
  const arr = args[0];
@@ -7003,21 +7104,19 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
7003
7104
  return null;
7004
7105
  }
7005
7106
  const elements = arr.elements;
7006
- const pieces = [];
7107
+ const composing = composingTrivia(elements);
7007
7108
  const carried = [];
7008
7109
  for (let i = 0; i < elements.length; i++) {
7009
- const r = argPieces(elements[i], `compose${init.start}_${i}`);
7110
+ const r = argPieces(elements[i], `compose${init.start}_${i}`, composing);
7010
7111
  if (!r) {
7011
7112
  warn(init.start, `compose(): argument ${i} isn't a build-resolvable grammar; falling back to runtime`);
7012
7113
  return null;
7013
7114
  }
7014
- pieces.push(...r.pieces);
7015
- if (r.spreadLocal) carried.push({ __spreadLocal: r.spreadLocal });
7016
- else if (r.ir) carried.push(r.ir);
7017
- else carried.push(...r.pieces);
7115
+ carried.push(...r.carried);
7018
7116
  }
7117
+ const pieces = materializeCarried(carried, composing);
7019
7118
  try {
7020
- return { replacement: emitFusedSource(pieces), pieces, carried };
7119
+ return { replacement: emitFusedSource(pieces), carried, ...composing ? { trivia: composing } : {} };
7021
7120
  } catch (e) {
7022
7121
  warn(init.start, `compose(): ${e.message}; falling back to runtime`);
7023
7122
  return null;
@@ -7102,6 +7201,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
7102
7201
  const compiledRules = compileRulesFactory(init, varName);
7103
7202
  if (!compiledRules) continue;
7104
7203
  localRuleMaps.set(varName, compiledRules.ruleMap);
7204
+ if (compiledRules.trivia) localGrammarTrivia.set(varName, compiledRules.trivia);
7105
7205
  let replacement = compiledRules.replacement;
7106
7206
  if (exportPrefix) {
7107
7207
  const ns = nsFor(varName);
@@ -7117,7 +7217,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
7117
7217
  if (isComposeCall(init)) {
7118
7218
  const fused = compileComposeCall(init);
7119
7219
  if (!fused) continue;
7120
- localComposedPieces.set(varName, fused.pieces);
7220
+ localComposedCarried.set(varName, fused.carried);
7221
+ if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
7121
7222
  const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
7122
7223
  replacements.push({ start: init.start, end: init.end, replacement });
7123
7224
  continue;