parseman 0.9.0 → 0.10.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.
@@ -1099,24 +1099,70 @@ function not(combinator) {
1099
1099
  };
1100
1100
  }
1101
1101
 
1102
+ // src/compiler/build-arity.ts
1103
+ var PARAM_LIST_RE = (
1104
+ // (params) => ... | function name?(params) ... | single-ident arrow `x => ...`
1105
+ /^(?:function\b[^(]*\(([^)]*)\)|\(([^)]*)\)\s*=>|([A-Za-z_$][\w$]*)\s*=>)/
1106
+ );
1107
+ var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
1108
+ function confirmedBuildArity(src) {
1109
+ const s = src.trim();
1110
+ const m = PARAM_LIST_RE.exec(s);
1111
+ if (!m) return null;
1112
+ if (m[3] !== void 0) return 1;
1113
+ const inner = (m[1] ?? m[2] ?? "").trim();
1114
+ if (inner === "") return 0;
1115
+ const parts = inner.split(",");
1116
+ for (const part of parts) {
1117
+ if (!CONFIRMABLE_PARAM_RE.test(part.trim())) return null;
1118
+ }
1119
+ if (/\barguments\b/.test(s)) return null;
1120
+ return parts.length;
1121
+ }
1122
+ function buildReadsTrivia(def) {
1123
+ const src = def.buildSrc ?? def.build.toString();
1124
+ const arity = confirmedBuildArity(src);
1125
+ if (arity === null) return true;
1126
+ return arity >= 4;
1127
+ }
1128
+ function buildReadsState(def) {
1129
+ const src = def.buildSrc ?? def.build.toString();
1130
+ const arity = confirmedBuildArity(src);
1131
+ if (arity === null) return true;
1132
+ return arity >= 5;
1133
+ }
1134
+
1102
1135
  // src/combinators/node.ts
1103
- function node(type, combinator, build) {
1136
+ function collapseChild(child) {
1137
+ return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
1138
+ }
1139
+ function node(type, combinator, build, opts) {
1104
1140
  const meta = {
1105
1141
  firstSet: combinator._meta.firstSet,
1106
1142
  canMatchNewline: combinator._meta.canMatchNewline,
1107
1143
  isTrivia: false
1108
1144
  };
1145
+ const collapse = opts?.collapse === true;
1146
+ const def = collapse ? { tag: "node", type, parser: combinator, build, collapse: true } : { tag: "node", type, parser: combinator, build };
1147
+ const capturesTrivia = buildReadsTrivia(def);
1148
+ const clonesState = buildReadsState(def);
1109
1149
  return {
1110
1150
  _tag: "node",
1111
1151
  _meta: meta,
1112
- _def: { tag: "node", type, parser: combinator, build },
1152
+ _def: def,
1113
1153
  parse(input, pos, ctx) {
1114
1154
  const saved = beginCstNodeCapture(ctx);
1155
+ if (!capturesTrivia) ctx.captureTrivia = false;
1115
1156
  const r = combinator.parse(input, pos, ctx);
1116
1157
  const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
1117
1158
  if (!r.ok) return r;
1118
- const state = ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
1119
- const built = build(children, rawChildren, r.span, triviaLog, state);
1159
+ const built = collapse && children.length === 1 ? collapseChild(children[0]) : build(
1160
+ children,
1161
+ rawChildren,
1162
+ r.span,
1163
+ triviaLog,
1164
+ clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0
1165
+ );
1120
1166
  const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
1121
1167
  const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
1122
1168
  if (saved.buf !== void 0 || saved.ch !== void 0) {
@@ -2519,25 +2565,34 @@ function emitNode(def, ctx, pos) {
2519
2565
  ctx.buildSrcs.push(def.buildSrc ?? null);
2520
2566
  }
2521
2567
  const i = ind(ctx);
2568
+ const capturesTrivia = mkType !== null || buildReadsTrivia(def);
2569
+ const clonesState = buildReadsState(def);
2522
2570
  const chV = v(ctx, "_ch");
2523
2571
  const rawV = v(ctx, "_raw");
2524
- const tlV = v(ctx, "_tl");
2572
+ const tlV = capturesTrivia ? v(ctx, "_tl") : "_EMPTY_TL";
2573
+ if (!capturesTrivia) ctx.needsEmptyTl = true;
2525
2574
  const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
2575
+ const allocStmt = capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
2576
+ const innerTl = capturesTrivia ? tlV : "undefined";
2526
2577
  const stmts = [
2527
- `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []`,
2578
+ allocStmt,
2528
2579
  `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
2529
- `${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${tlV}`
2580
+ `${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
2530
2581
  ];
2531
2582
  const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
2532
2583
  stmts.push(...innerStmts);
2533
2584
  stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
2534
2585
  stmts.push(...emitIfFail(ctx, `!${okVar}`, failBody(ctx, '"node"', pos)));
2535
- const stV = v(ctx, "_nst");
2536
- stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
2586
+ let stV = "undefined";
2587
+ if (clonesState) {
2588
+ stV = v(ctx, "_nst");
2589
+ stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
2590
+ }
2537
2591
  const ndV = v(ctx, "_nd");
2538
2592
  const ndExpr = mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `_build[${buildIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV})`;
2593
+ const finalExpr = def.collapse ? `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})` : ndExpr;
2539
2594
  stmts.push(
2540
- `${i}const ${ndV} = ${ndExpr}`,
2595
+ `${i}const ${ndV} = ${finalExpr}`,
2541
2596
  `${i}if (${sc}) ${sc}.push(${ndV})`,
2542
2597
  `${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && ${ndV}._tag === 'node') ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
2543
2598
  );
@@ -2929,7 +2984,9 @@ function compile(combinator, mapFnSources) {
2929
2984
  const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
2930
2985
  ` : "";
2931
2986
  const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
2987
+ const emptyTlDecls = ctx.needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [];
2932
2988
  const source = [
2989
+ ...emptyTlDecls,
2933
2990
  ...ctx.regexDecls,
2934
2991
  "",
2935
2992
  ...namedPrelude,
@@ -2941,6 +2998,7 @@ function compile(combinator, mapFnSources) {
2941
2998
  `}`
2942
2999
  ].join("\n");
2943
3000
  const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
3001
+ ...emptyTlDecls,
2944
3002
  ...ctx.regexDecls,
2945
3003
  collatorDecl,
2946
3004
  ...namedPrelude,
@@ -3013,6 +3071,7 @@ function compileRuleMap(ruleMap) {
3013
3071
  const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
3014
3072
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
3015
3073
  const hoistedDecls = [
3074
+ ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "",
3016
3075
  ...ctx.regexDecls.map((d) => ` ${d}`),
3017
3076
  collatorDecl ? ` ${collatorDecl.trim()}` : "",
3018
3077
  mfDecl,
@@ -3054,10 +3113,12 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
3054
3113
  ].join("\n");
3055
3114
  const mfDecl = mapFnSources?.length ? ` const _mf = [${mapFnSources.join(", ")}]` : "";
3056
3115
  const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
3057
- const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl;
3116
+ const emptyTlDecl = ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "";
3117
+ const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl || !!emptyTlDecl;
3058
3118
  if (!needsWrapper) return innerFn;
3059
3119
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
3060
3120
  const hoistedDecls = [
3121
+ emptyTlDecl,
3061
3122
  ...ctx.regexDecls.map((d) => ` ${d}`),
3062
3123
  collatorDecl ? ` ${collatorDecl.trim()}` : "",
3063
3124
  mfDecl,
@@ -3258,6 +3319,20 @@ function scopeGet(scope, name, mfs) {
3258
3319
  if (isCombinator(entry)) return entry;
3259
3320
  return null;
3260
3321
  }
3322
+ function staticCollapseOption(expr) {
3323
+ if (expr.type !== "ObjectExpression") return false;
3324
+ for (const prop of expr.properties) {
3325
+ const p = prop;
3326
+ if (p.computed) continue;
3327
+ const key = p.key;
3328
+ const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
3329
+ if (name === "collapse") {
3330
+ const val = p.value;
3331
+ return (val.type === "Literal" || val.type === "BooleanLiteral") && val.value === true;
3332
+ }
3333
+ }
3334
+ return false;
3335
+ }
3261
3336
  function exprToCombi(node2, scope, code, mfs) {
3262
3337
  if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
3263
3338
  if (node2.type !== "CallExpression") return null;
@@ -3306,15 +3381,16 @@ function exprToCombi(node2, scope, code, mfs) {
3306
3381
  }
3307
3382
  }
3308
3383
  if (callee.name === "node" && code !== void 0) {
3309
- const [typeArg, parserArg, buildArg] = node2.arguments;
3384
+ const [typeArg, parserArg, buildArg, optsArg] = node2.arguments;
3310
3385
  if (!typeArg || !parserArg || !buildArg || typeArg.type === "SpreadElement" || parserArg.type === "SpreadElement" || buildArg.type === "SpreadElement") return null;
3311
3386
  const typeVal = anyValue(typeArg, scope, code);
3312
3387
  if (typeof typeVal !== "string") return null;
3313
3388
  const inner = anyValue(parserArg, scope, code, mfs);
3314
3389
  if (!isCombinator(inner)) return null;
3315
3390
  const buildSrc = code.slice(buildArg.start, buildArg.end);
3391
+ const collapse = optsArg !== void 0 && optsArg.type !== "SpreadElement" ? staticCollapseOption(optsArg) : false;
3316
3392
  try {
3317
- const combi = node(typeVal, inner, () => null);
3393
+ const combi = node(typeVal, inner, () => null, collapse ? { collapse: true } : void 0);
3318
3394
  if (combi._def.tag === "node") combi._def.buildSrc = buildSrc;
3319
3395
  return combi;
3320
3396
  } catch {