Skip to content

Commit b602f67

Browse files
committed
Add bit count syntax to packet diagram
1 parent d16e46a commit b602f67

File tree

3 files changed

+127
-15
lines changed

3 files changed

+127
-15
lines changed

packages/mermaid/src/diagrams/packet/packet.spec.ts

+91
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe('packet diagrams', () => {
3030
[
3131
[
3232
{
33+
"bits": 11,
3334
"end": 10,
3435
"label": "test",
3536
"start": 0,
@@ -49,11 +50,13 @@ describe('packet diagrams', () => {
4950
[
5051
[
5152
{
53+
"bits": 11,
5254
"end": 10,
5355
"label": "test",
5456
"start": 0,
5557
},
5658
{
59+
"bits": 1,
5760
"end": 11,
5861
"label": "single",
5962
"start": 11,
@@ -63,6 +66,58 @@ describe('packet diagrams', () => {
6366
`);
6467
});
6568

69+
it('should handle bit counts', async () => {
70+
const str = `packet-beta
71+
8bits: "byte"
72+
16bits: "word"
73+
`;
74+
await expect(parser.parse(str)).resolves.not.toThrow();
75+
expect(getPacket()).toMatchInlineSnapshot(`
76+
[
77+
[
78+
{
79+
"bits": 8,
80+
"end": 7,
81+
"label": "byte",
82+
"start": 0,
83+
},
84+
{
85+
"bits": 16,
86+
"end": 23,
87+
"label": "word",
88+
"start": 8,
89+
},
90+
],
91+
]
92+
`);
93+
});
94+
95+
it('should handle bit counts with bit or bits', async () => {
96+
const str = `packet-beta
97+
8bit: "byte"
98+
16bits: "word"
99+
`;
100+
await expect(parser.parse(str)).resolves.not.toThrow();
101+
expect(getPacket()).toMatchInlineSnapshot(`
102+
[
103+
[
104+
{
105+
"bits": 8,
106+
"end": 7,
107+
"label": "byte",
108+
"start": 0,
109+
},
110+
{
111+
"bits": 16,
112+
"end": 23,
113+
"label": "word",
114+
"start": 8,
115+
},
116+
],
117+
]
118+
`);
119+
});
120+
66121
it('should split into multiple rows', async () => {
67122
const str = `packet-beta
68123
0-10: "test"
@@ -73,25 +128,29 @@ describe('packet diagrams', () => {
73128
[
74129
[
75130
{
131+
"bits": 11,
76132
"end": 10,
77133
"label": "test",
78134
"start": 0,
79135
},
80136
{
137+
"bits": 20,
81138
"end": 31,
82139
"label": "multiple",
83140
"start": 11,
84141
},
85142
],
86143
[
87144
{
145+
"bits": 31,
88146
"end": 63,
89147
"label": "multiple",
90148
"start": 32,
91149
},
92150
],
93151
[
94152
{
153+
"bits": 26,
95154
"end": 90,
96155
"label": "multiple",
97156
"start": 64,
@@ -111,18 +170,21 @@ describe('packet diagrams', () => {
111170
[
112171
[
113172
{
173+
"bits": 17,
114174
"end": 16,
115175
"label": "test",
116176
"start": 0,
117177
},
118178
{
179+
"bits": 14,
119180
"end": 31,
120181
"label": "multiple",
121182
"start": 17,
122183
},
123184
],
124185
[
125186
{
187+
"bits": 31,
126188
"end": 63,
127189
"label": "multiple",
128190
"start": 32,
@@ -142,6 +204,16 @@ describe('packet diagrams', () => {
142204
);
143205
});
144206

207+
it('should throw error if numbers are not continuous with bit counts', async () => {
208+
const str = `packet-beta
209+
16bits: "test"
210+
18-20: "error"
211+
`;
212+
await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot(
213+
`[Error: Packet block 18 - 20 is not contiguous. It should start from 16.]`
214+
);
215+
});
216+
145217
it('should throw error if numbers are not continuous for single packets', async () => {
146218
const str = `packet-beta
147219
0-16: "test"
@@ -152,6 +224,16 @@ describe('packet diagrams', () => {
152224
);
153225
});
154226

227+
it('should throw error if numbers are not continuous for single packets with bit counts', async () => {
228+
const str = `packet-beta
229+
16 bits: "test"
230+
18: "error"
231+
`;
232+
await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot(
233+
`[Error: Packet block 18 - 18 is not contiguous. It should start from 16.]`
234+
);
235+
});
236+
155237
it('should throw error if numbers are not continuous for single packets - 2', async () => {
156238
const str = `packet-beta
157239
0-16: "test"
@@ -172,4 +254,13 @@ describe('packet diagrams', () => {
172254
`[Error: Packet block 25 - 20 is invalid. End must be greater than start.]`
173255
);
174256
});
257+
258+
it('should throw error if bit count is 0', async () => {
259+
const str = `packet-beta
260+
0bits: "test"
261+
`;
262+
await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot(
263+
`[Error: Packet block 0 is invalid. Cannot have a zero bit field.]`
264+
);
265+
});
175266
});

packages/mermaid/src/diagrams/packet/parser.ts

+30-14
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,39 @@ const maxPacketSize = 10_000;
1010

1111
const populate = (ast: Packet) => {
1212
populateCommonDb(ast, db);
13-
let lastByte = -1;
13+
let lastBit = -1;
1414
let word: PacketWord = [];
1515
let row = 1;
1616
const { bitsPerRow } = db.getConfig();
17-
for (let { start, end, label } of ast.blocks) {
18-
if (end && end < start) {
17+
18+
for (let { start, end, bits, label } of ast.blocks) {
19+
if (start !== undefined && end !== undefined && end < start) {
1920
throw new Error(`Packet block ${start} - ${end} is invalid. End must be greater than start.`);
2021
}
21-
if (start !== lastByte + 1) {
22+
if (start == undefined) {
23+
start = lastBit + 1;
24+
}
25+
if (start !== lastBit + 1) {
2226
throw new Error(
2327
`Packet block ${start} - ${end ?? start} is not contiguous. It should start from ${
24-
lastByte + 1
28+
lastBit + 1
2529
}.`
2630
);
2731
}
28-
lastByte = end ?? start;
29-
log.debug(`Packet block ${start} - ${lastByte} with label ${label}`);
32+
if (bits === 0) {
33+
throw new Error(`Packet block ${start} is invalid. Cannot have a zero bit field.`);
34+
}
35+
if (end == undefined) {
36+
end = start + (bits ?? 1) - 1;
37+
}
38+
if (bits == undefined) {
39+
bits = end - start + 1;
40+
}
41+
lastBit = end;
42+
log.debug(`Packet block ${start} - ${lastBit} with label ${label}`);
3043

3144
while (word.length <= bitsPerRow + 1 && db.getPacket().length < maxPacketSize) {
32-
const [block, nextBlock] = getNextFittingBlock({ start, end, label }, row, bitsPerRow);
45+
const [block, nextBlock] = getNextFittingBlock({ start, end, bits, label }, row, bitsPerRow);
3346
word.push(block);
3447
if (block.end + 1 === row * bitsPerRow) {
3548
db.pushWord(word);
@@ -39,7 +52,7 @@ const populate = (ast: Packet) => {
3952
if (!nextBlock) {
4053
break;
4154
}
42-
({ start, end, label } = nextBlock);
55+
({ start, end, bits, label } = nextBlock);
4356
}
4457
}
4558
db.pushWord(word);
@@ -50,9 +63,8 @@ const getNextFittingBlock = (
5063
row: number,
5164
bitsPerRow: number
5265
): [Required<PacketBlock>, PacketBlock | undefined] => {
53-
if (block.end === undefined) {
54-
block.end = block.start;
55-
}
66+
assert(block.start !== undefined, 'start should have been set during first phase');
67+
assert(block.end !== undefined, 'end should have been set during first phase');
5668

5769
if (block.start > block.end) {
5870
throw new Error(`Block start ${block.start} is greater than block end ${block.end}.`);
@@ -62,16 +74,20 @@ const getNextFittingBlock = (
6274
return [block as Required<PacketBlock>, undefined];
6375
}
6476

77+
const rowEnd = row * bitsPerRow - 1;
78+
const rowStart = row * bitsPerRow;
6579
return [
6680
{
6781
start: block.start,
68-
end: row * bitsPerRow - 1,
82+
end: rowEnd,
6983
label: block.label,
84+
bits: rowEnd - block.start,
7085
},
7186
{
72-
start: row * bitsPerRow,
87+
start: rowStart,
7388
end: block.end,
7489
label: block.label,
90+
bits: block.end - rowStart,
7591
},
7692
];
7793
};

packages/parser/src/language/packet/packet.langium

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ entry Packet:
1212
;
1313

1414
PacketBlock:
15-
start=INT('-' end=INT)? ':' label=STRING EOL
15+
(
16+
start=INT('-' (end=INT | bits=INT'bit''s'?))?
17+
| bits=INT'bit''s'?
18+
)
19+
':' label=STRING
20+
EOL
1621
;
1722

1823
terminal INT returns number: /0|[1-9][0-9]*/;

0 commit comments

Comments
 (0)