Skip to content

Commit 80c1882

Browse files
committed
Added context variables on parsing process
1 parent b472b40 commit 80c1882

File tree

2 files changed

+101
-18
lines changed

2 files changed

+101
-18
lines changed

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,42 @@ These options can be used in all parsers.
519519
});
520520
```
521521

522+
### Context variables
523+
You can use some special fields while parsing to traverse your structure. These
524+
context variables will be removed after the parsing process:
525+
- `$parent` - This field references the parent structure. This variable will be
526+
`null` while parsing the root structure.
527+
```js
528+
var parser = new Parser()
529+
.nest("header", {
530+
type: new Parser().uint32("length"),
531+
})
532+
.array("data", {
533+
type: "int32",
534+
length: function() {
535+
return this.$parent.header.length
536+
}
537+
})
538+
```
539+
- `$root` - This field references the root structure.
540+
```js
541+
var parser = new Parser()
542+
.nest("header", {
543+
type: new Parser().uint32("length"),
544+
})
545+
.nest("data", {
546+
type: new Parser()
547+
.uint32("value")
548+
.array("data", {
549+
type: "int32",
550+
length: function() {
551+
return this.$root.header.length
552+
}
553+
}),
554+
})
555+
556+
```
557+
522558
## Examples
523559
See `example/` for real-world examples.
524560

lib/binary_parser.ts

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -670,34 +670,38 @@ export class Parser {
670670

671671
private addRawCode(ctx: Context) {
672672
ctx.pushCode('var offset = 0;');
673-
674-
if (this.constructorFn) {
675-
ctx.pushCode('var vars = new constructorFn();');
676-
} else {
677-
ctx.pushCode('var vars = {};');
678-
}
673+
ctx.pushCode(
674+
`var vars = ${this.constructorFn ? 'new constructorFn()' : '{}'};`
675+
);
676+
ctx.pushCode('vars.$parent = null;');
677+
ctx.pushCode('vars.$root = vars;');
679678

680679
this.generate(ctx);
681680

682681
this.resolveReferences(ctx);
683682

683+
ctx.pushCode('delete vars.$parent;');
684+
ctx.pushCode('delete vars.$root;');
684685
ctx.pushCode('return vars;');
685686
}
686687

687688
private addAliasedCode(ctx: Context) {
688-
ctx.pushCode(`function ${FUNCTION_PREFIX + this.alias}(offset) {`);
689-
690-
if (this.constructorFn) {
691-
ctx.pushCode('var vars = new constructorFn();');
692-
} else {
693-
ctx.pushCode('var vars = {};');
694-
}
689+
ctx.pushCode(
690+
`function ${FUNCTION_PREFIX + this.alias}(offset, parent, root) {`
691+
);
692+
ctx.pushCode(
693+
`var vars = ${this.constructorFn ? 'new constructorFn()' : '{}'};`
694+
);
695+
ctx.pushCode('vars.$parent = parent || null;');
696+
ctx.pushCode('vars.$root = root || vars;');
695697

696698
this.generate(ctx);
697699

698700
ctx.markResolved(this.alias);
699701
this.resolveReferences(ctx);
700702

703+
ctx.pushCode('delete vars.$parent;');
704+
ctx.pushCode('delete vars.$root;');
701705
ctx.pushCode('return { offset: offset, result: vars };');
702706
ctx.pushCode('}');
703707

@@ -1088,18 +1092,28 @@ export class Parser {
10881092
);
10891093
ctx.pushCode(`offset += ${PRIMITIVE_SIZES[type as PrimitiveTypes]};`);
10901094
} else {
1095+
const parentVar = ctx.generateVariable();
10911096
const tempVar = ctx.generateTmpVariable();
1092-
ctx.pushCode(`var ${tempVar} = ${FUNCTION_PREFIX + type}(offset);`);
1097+
ctx.pushCode(
1098+
`var ${tempVar} = ${
1099+
FUNCTION_PREFIX + type
1100+
}(offset, ${parentVar}, ${parentVar}.$root);`
1101+
);
10931102
ctx.pushCode(
10941103
`var ${item} = ${tempVar}.result; offset = ${tempVar}.offset;`
10951104
);
10961105
if (type !== this.alias) ctx.addReference(type);
10971106
}
10981107
} else if (type instanceof Parser) {
1108+
const parentVar = ctx.generateVariable();
10991109
ctx.pushCode(`var ${item} = {};`);
11001110

11011111
ctx.pushScope(item);
1112+
ctx.pushCode(`${item}.$parent = ${parentVar};`);
1113+
ctx.pushCode(`${item}.$root = ${parentVar}.$root;`);
11021114
type.generate(ctx);
1115+
ctx.pushCode(`delete ${item}.$parent`);
1116+
ctx.pushCode(`delete ${item}.$root`);
11031117
ctx.popScope();
11041118
}
11051119

@@ -1136,7 +1150,11 @@ export class Parser {
11361150
ctx.pushCode(`offset += ${PRIMITIVE_SIZES[type as PrimitiveTypes]}`);
11371151
} else {
11381152
const tempVar = ctx.generateTmpVariable();
1139-
ctx.pushCode(`var ${tempVar} = ${FUNCTION_PREFIX + type}(offset);`);
1153+
ctx.pushCode(
1154+
`var ${tempVar} = ${
1155+
FUNCTION_PREFIX + type
1156+
}(offset, ${varName}.$parent, ${varName}.$root);`
1157+
);
11401158
ctx.pushCode(
11411159
`${varName} = ${tempVar}.result; offset = ${tempVar}.offset;`
11421160
);
@@ -1151,8 +1169,14 @@ export class Parser {
11511169

11521170
private generateChoice(ctx: Context) {
11531171
const tag = ctx.generateOption(this.options.tag);
1172+
const nestVar = ctx.generateVariable(this.varName);
1173+
11541174
if (this.varName) {
1155-
ctx.pushCode(`${ctx.generateVariable(this.varName)} = {};`);
1175+
ctx.pushCode(`${nestVar} = {};`);
1176+
1177+
const parentVar = ctx.generateVariable();
1178+
ctx.pushCode(`${nestVar}.$parent = ${parentVar};`);
1179+
ctx.pushCode(`${nestVar}.$root = ${parentVar}.$root;`);
11561180
}
11571181
ctx.pushCode(`switch(${tag}) {`);
11581182
Object.keys(this.options.choices).forEach((tag) => {
@@ -1169,22 +1193,37 @@ export class Parser {
11691193
ctx.generateError(`"Met undefined tag value " + ${tag} + " at choice"`);
11701194
}
11711195
ctx.pushCode('}');
1196+
1197+
if (this.varName) {
1198+
ctx.pushCode(`delete ${nestVar}.$parent`);
1199+
ctx.pushCode(`delete ${nestVar}.$root`);
1200+
}
11721201
}
11731202

11741203
private generateNest(ctx: Context) {
11751204
const nestVar = ctx.generateVariable(this.varName);
11761205

11771206
if (this.options.type instanceof Parser) {
11781207
if (this.varName) {
1208+
const parentVar = ctx.generateVariable();
11791209
ctx.pushCode(`${nestVar} = {};`);
1210+
ctx.pushCode(`${nestVar}.$parent = ${parentVar};`);
1211+
ctx.pushCode(`${nestVar}.$root = ${parentVar}.$root;`);
11801212
}
11811213
ctx.pushPath(this.varName);
11821214
this.options.type.generate(ctx);
11831215
ctx.popPath(this.varName);
1216+
if (this.varName) {
1217+
ctx.pushCode(`delete ${nestVar}.$parent`);
1218+
ctx.pushCode(`delete ${nestVar}.$root`);
1219+
}
11841220
} else if (aliasRegistry[this.options.type]) {
1221+
const parentVar = ctx.generateVariable();
11851222
const tempVar = ctx.generateTmpVariable();
11861223
ctx.pushCode(
1187-
`var ${tempVar} = ${FUNCTION_PREFIX + this.options.type}(offset);`
1224+
`var ${tempVar} = ${
1225+
FUNCTION_PREFIX + this.options.type
1226+
}(offset, ${parentVar}, ${parentVar}.$root);`
11881227
);
11891228
ctx.pushCode(
11901229
`${nestVar} = ${tempVar}.result; offset = ${tempVar}.offset;`
@@ -1283,14 +1322,22 @@ export class Parser {
12831322
ctx.pushCode(`offset = ${offset};`);
12841323

12851324
if (this.options.type instanceof Parser) {
1325+
const parentVar = ctx.generateVariable();
12861326
ctx.pushCode(`${nestVar} = {};`);
1327+
ctx.pushCode(`${nestVar}.$parent = ${parentVar};`);
1328+
ctx.pushCode(`${nestVar}.$root = ${parentVar}.$root;`);
12871329
ctx.pushPath(this.varName);
12881330
this.options.type.generate(ctx);
12891331
ctx.popPath(this.varName);
1332+
ctx.pushCode(`delete ${nestVar}.$parent`);
1333+
ctx.pushCode(`delete ${nestVar}.$root`);
12901334
} else if (aliasRegistry[this.options.type]) {
1335+
const parentVar = ctx.generateVariable();
12911336
const tempVar = ctx.generateTmpVariable();
12921337
ctx.pushCode(
1293-
`var ${tempVar} = ${FUNCTION_PREFIX + this.options.type}(offset);`
1338+
`var ${tempVar} = ${
1339+
FUNCTION_PREFIX + this.options.type
1340+
}(offset, ${parentVar}, ${parentVar}.$root);`
12941341
);
12951342
ctx.pushCode(
12961343
`${nestVar} = ${tempVar}.result; offset = ${tempVar}.offset;`

0 commit comments

Comments
 (0)