parseman 0.20.0 → 0.22.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.
- package/dist/combinators/grammar.d.ts +8 -0
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts +12 -0
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +3 -1
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/cst/trivia-kinds.d.ts +16 -0
- package/dist/cst/trivia-kinds.d.ts.map +1 -1
- package/dist/functional/run.d.ts +9 -0
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +51 -11
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -11
- package/dist/index.js.map +2 -2
- package/dist/plugin/index.cjs +65 -15
- package/dist/plugin/index.cjs.map +2 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +65 -15
- package/dist/plugin/index.js.map +2 -2
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAuBA,OAAO,WAAW,MAAM,cAAc,CAAA;AAiBtC,MAAM,MAAM,uBAAuB,GAAG;IACpC,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;;;AA4MD,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAA;IAC3C,kFAAkF;IAClF,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAA;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,aAAa,cAA6B,EAC1C,kBAAkB,UAAQ,GACzB,oBAAoB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAuBA,OAAO,WAAW,MAAM,cAAc,CAAA;AAiBtC,MAAM,MAAM,uBAAuB,GAAG;IACpC,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;;;AA4MD,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAA;IAC3C,kFAAkF;IAClF,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAA;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,aAAa,cAA6B,EAC1C,kBAAkB,UAAQ,GACzB,oBAAoB,GAAG,IAAI,CA0oB7B"}
|
package/dist/plugin/index.js
CHANGED
|
@@ -1219,13 +1219,25 @@ function tryFastLabeledScan(input, cur, trivia2) {
|
|
|
1219
1219
|
}
|
|
1220
1220
|
function recordTriviaChunks(ctx, chunks) {
|
|
1221
1221
|
const kinds = ctx.triviaKindLabels;
|
|
1222
|
+
const mask = ctx._triviaCaptureMask;
|
|
1222
1223
|
for (const ch of chunks) {
|
|
1223
1224
|
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1224
1225
|
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
1225
|
-
|
|
1226
|
+
if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
|
|
1227
|
+
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1228
|
+
}
|
|
1226
1229
|
}
|
|
1227
1230
|
}
|
|
1228
1231
|
}
|
|
1232
|
+
function triviaKindMask(labels, keep) {
|
|
1233
|
+
if (!labels) return void 0;
|
|
1234
|
+
let mask = 0;
|
|
1235
|
+
for (const name of keep) {
|
|
1236
|
+
const idx = labels.indexOf(name);
|
|
1237
|
+
if (idx >= 0) mask |= 1 << idx;
|
|
1238
|
+
}
|
|
1239
|
+
return mask;
|
|
1240
|
+
}
|
|
1229
1241
|
|
|
1230
1242
|
// src/combinators/trivia-skip.ts
|
|
1231
1243
|
var NOOP_COMMIT = () => {
|
|
@@ -1682,7 +1694,9 @@ function tagRule(r, key) {
|
|
|
1682
1694
|
r._ruleName = key;
|
|
1683
1695
|
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1684
1696
|
}
|
|
1685
|
-
function rules(
|
|
1697
|
+
function rules(a, b) {
|
|
1698
|
+
const factory = typeof a === "function" ? a : b;
|
|
1699
|
+
const options = typeof a === "function" ? b : a;
|
|
1686
1700
|
const cache = {};
|
|
1687
1701
|
const proxy = new Proxy(cache, {
|
|
1688
1702
|
get(target, key) {
|
|
@@ -1710,6 +1724,12 @@ function rules(factory) {
|
|
|
1710
1724
|
cache[key] = parser2;
|
|
1711
1725
|
}
|
|
1712
1726
|
}
|
|
1727
|
+
if (options?.trivia !== void 0) {
|
|
1728
|
+
for (const key of Object.keys(definitions)) {
|
|
1729
|
+
const rule = cache[key];
|
|
1730
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1713
1733
|
for (const key of Object.keys(definitions)) {
|
|
1714
1734
|
markUnusedValues(cache[key]);
|
|
1715
1735
|
}
|
|
@@ -1877,10 +1897,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
1877
1897
|
const saved = beginCstNodeCapture(ctx);
|
|
1878
1898
|
const savedFields = ctx._fields;
|
|
1879
1899
|
ctx._fields = capturesFields ? [] : void 0;
|
|
1900
|
+
const savedMask = ctx._triviaCaptureMask;
|
|
1901
|
+
if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
|
|
1902
|
+
ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
|
|
1903
|
+
}
|
|
1880
1904
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1881
1905
|
const r = combinator.parse(input, pos, ctx);
|
|
1882
1906
|
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
1883
1907
|
ctx._fields = savedFields;
|
|
1908
|
+
ctx._triviaCaptureMask = savedMask;
|
|
1884
1909
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1885
1910
|
if (!r.ok) return r;
|
|
1886
1911
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
@@ -2018,7 +2043,13 @@ function parser(opts, root) {
|
|
|
2018
2043
|
trivia: opts.trivia,
|
|
2019
2044
|
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
2020
2045
|
} : {},
|
|
2021
|
-
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {}
|
|
2046
|
+
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
|
|
2047
|
+
// Kind-filter for per-node capture. Resolve against this scope's trivia
|
|
2048
|
+
// labels — this parser's own trivia if it declares one, else the INHERITED
|
|
2049
|
+
// labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
|
|
2050
|
+
// trivia is inherited rather than re-declared here. No labels → undefined
|
|
2051
|
+
// (capture all).
|
|
2052
|
+
...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
|
|
2022
2053
|
};
|
|
2023
2054
|
const result = root.parse(input, pos ?? 0, ctx);
|
|
2024
2055
|
if (trackLines) {
|
|
@@ -3168,7 +3199,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
|
|
|
3168
3199
|
` if (${m.end} > _e) {`,
|
|
3169
3200
|
` if (_cap) {`,
|
|
3170
3201
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
|
|
3171
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
3202
|
+
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
|
|
3172
3203
|
` }`,
|
|
3173
3204
|
` _e = ${m.end}`,
|
|
3174
3205
|
` continue`,
|
|
@@ -3284,7 +3315,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
|
|
|
3284
3315
|
` const _ce = _e + _m${i}[0].length`,
|
|
3285
3316
|
` if (_cap) {`,
|
|
3286
3317
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
3287
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3318
|
+
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3288
3319
|
` }`,
|
|
3289
3320
|
` _e = _ce`,
|
|
3290
3321
|
` _matched = true`,
|
|
@@ -3322,7 +3353,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
|
|
|
3322
3353
|
` const _ce = _r${i}.span.end`,
|
|
3323
3354
|
` if (_cap) {`,
|
|
3324
3355
|
` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
|
|
3325
|
-
` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3356
|
+
` if (_ctx._cstTriviaLog !== undefined && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
|
|
3326
3357
|
` }`,
|
|
3327
3358
|
` _e = _ce`,
|
|
3328
3359
|
` _matched = true`,
|
|
@@ -4720,6 +4751,7 @@ function emitNode(def, ctx, pos) {
|
|
|
4720
4751
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
4721
4752
|
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
4722
4753
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
4754
|
+
const smk = structural ? v(ctx, "_smk") : null;
|
|
4723
4755
|
if (structural) ctx.needsHostReads = true;
|
|
4724
4756
|
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
4725
4757
|
const allocStmt = structural ? `${i}const ${capTLv} = ${hostTriviaGate}, ${capSTv} = _ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6))${capFv ? `, ${capFv} = _ctx.build !== undefined && _hostReads(_ctx.build, 2)` : ""}
|
|
@@ -4731,15 +4763,15 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4731
4763
|
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
4732
4764
|
const stmts = [
|
|
4733
4765
|
allocStmt,
|
|
4734
|
-
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
4735
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
4766
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
4767
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
4736
4768
|
];
|
|
4737
4769
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
4738
4770
|
stmts.push(...innerStmts);
|
|
4739
4771
|
if (sf && fArr) {
|
|
4740
4772
|
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
4741
4773
|
}
|
|
4742
|
-
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
4774
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
4743
4775
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
4744
4776
|
let stV = "undefined";
|
|
4745
4777
|
if (structural) {
|
|
@@ -5292,6 +5324,7 @@ function ruleDependencies(ruleMap) {
|
|
|
5292
5324
|
}
|
|
5293
5325
|
function compile(combinator, mapFnSources) {
|
|
5294
5326
|
markUnusedValues(combinator);
|
|
5327
|
+
const grammarTrivia = combinator._meta.grammarTrivia;
|
|
5295
5328
|
const ctx = {
|
|
5296
5329
|
vars: 0,
|
|
5297
5330
|
indent: 1,
|
|
@@ -5310,7 +5343,8 @@ function compile(combinator, mapFnSources) {
|
|
|
5310
5343
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5311
5344
|
namedFnDecls: [],
|
|
5312
5345
|
capturing: hasNodeDef(combinator),
|
|
5313
|
-
lazyUsage: analyzeLazyUsage(combinator)
|
|
5346
|
+
lazyUsage: analyzeLazyUsage(combinator),
|
|
5347
|
+
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5314
5348
|
};
|
|
5315
5349
|
const r = emit(combinator, ctx, "_pos");
|
|
5316
5350
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
|
|
@@ -5386,8 +5420,9 @@ function publicRuleWrapperSource(rule, fnSource) {
|
|
|
5386
5420
|
if (labels === void 0) return fnSource;
|
|
5387
5421
|
return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
|
|
5388
5422
|
}
|
|
5389
|
-
function compileRuleMap(ruleMap) {
|
|
5423
|
+
function compileRuleMap(ruleMap, opts) {
|
|
5390
5424
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
5425
|
+
const grammarTrivia = opts?.trivia;
|
|
5391
5426
|
const ctx = {
|
|
5392
5427
|
vars: 0,
|
|
5393
5428
|
indent: 1,
|
|
@@ -5406,7 +5441,8 @@ function compileRuleMap(ruleMap) {
|
|
|
5406
5441
|
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
5407
5442
|
namedFnDecls: [],
|
|
5408
5443
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
5409
|
-
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule))
|
|
5444
|
+
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
5445
|
+
...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {}
|
|
5410
5446
|
};
|
|
5411
5447
|
const seenNames = /* @__PURE__ */ new Map();
|
|
5412
5448
|
const ruleNames = /* @__PURE__ */ new Map();
|
|
@@ -5418,7 +5454,13 @@ function compileRuleMap(ruleMap) {
|
|
|
5418
5454
|
ruleNames.set(rule, n === 0 ? base : `${base}$${n}`);
|
|
5419
5455
|
}
|
|
5420
5456
|
ctx.ruleNames = ruleNames;
|
|
5421
|
-
const perEntry = ruleMap.map(([key, rule]) =>
|
|
5457
|
+
const perEntry = ruleMap.map(([key, rule]) => {
|
|
5458
|
+
const savedTrivia = ctx.activeTrivia;
|
|
5459
|
+
if (rule._meta.isTrivia) ctx.activeTrivia = void 0;
|
|
5460
|
+
const r = emit(rule, ctx, "_pos");
|
|
5461
|
+
ctx.activeTrivia = savedTrivia;
|
|
5462
|
+
return { key, rule, r };
|
|
5463
|
+
});
|
|
5422
5464
|
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
5423
5465
|
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
5424
5466
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
@@ -6797,7 +6839,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
6797
6839
|
};
|
|
6798
6840
|
const compileRulesFactory = (init, label2) => {
|
|
6799
6841
|
const args = init.arguments;
|
|
6800
|
-
const
|
|
6842
|
+
const arg0 = args[0];
|
|
6843
|
+
const arg1 = args[1];
|
|
6844
|
+
const optionsFirst = arg0?.type === "ObjectExpression";
|
|
6845
|
+
const factoryArg = optionsFirst ? arg1 : arg0;
|
|
6801
6846
|
if (!factoryArg) {
|
|
6802
6847
|
warn(init.start, `${label2}: rules() needs a factory argument`);
|
|
6803
6848
|
return null;
|
|
@@ -6807,7 +6852,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
6807
6852
|
warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
|
|
6808
6853
|
return null;
|
|
6809
6854
|
}
|
|
6810
|
-
const
|
|
6855
|
+
const optionsArg = optionsFirst ? arg0 : arg1;
|
|
6856
|
+
const triviaValue = optionsArg?.type === "ObjectExpression" ? (optionsArg.properties ?? []).find(
|
|
6857
|
+
(p) => p.key?.name === "trivia"
|
|
6858
|
+
)?.value : void 0;
|
|
6859
|
+
const gTrivia = triviaValue ? evaluateExpr(triviaValue, scope, code, []) : void 0;
|
|
6860
|
+
const compiled = compileRuleMap([...ruleMap], gTrivia ? { trivia: gTrivia } : void 0);
|
|
6811
6861
|
if (!compiled) {
|
|
6812
6862
|
warn(init.start, `${label2}: rule map couldn't be inlined`);
|
|
6813
6863
|
return null;
|