mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-04 12:54:08 +01:00 
			
		
		
		
	Add bit count syntax to packet diagram
This commit is contained in:
		@@ -30,6 +30,7 @@ describe('packet diagrams', () => {
 | 
			
		||||
      [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 11,
 | 
			
		||||
            "end": 10,
 | 
			
		||||
            "label": "test",
 | 
			
		||||
            "start": 0,
 | 
			
		||||
@@ -49,11 +50,13 @@ describe('packet diagrams', () => {
 | 
			
		||||
      [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 11,
 | 
			
		||||
            "end": 10,
 | 
			
		||||
            "label": "test",
 | 
			
		||||
            "start": 0,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 1,
 | 
			
		||||
            "end": 11,
 | 
			
		||||
            "label": "single",
 | 
			
		||||
            "start": 11,
 | 
			
		||||
@@ -63,6 +66,58 @@ describe('packet diagrams', () => {
 | 
			
		||||
    `);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle bit counts', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    8bits: "byte"
 | 
			
		||||
    16bits: "word"
 | 
			
		||||
    `;
 | 
			
		||||
    await expect(parser.parse(str)).resolves.not.toThrow();
 | 
			
		||||
    expect(getPacket()).toMatchInlineSnapshot(`
 | 
			
		||||
      [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 8,
 | 
			
		||||
            "end": 7,
 | 
			
		||||
            "label": "byte",
 | 
			
		||||
            "start": 0,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 16,
 | 
			
		||||
            "end": 23,
 | 
			
		||||
            "label": "word",
 | 
			
		||||
            "start": 8,
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      ]
 | 
			
		||||
    `);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should handle bit counts with bit or bits', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    8bit: "byte"
 | 
			
		||||
    16bits: "word"
 | 
			
		||||
    `;
 | 
			
		||||
    await expect(parser.parse(str)).resolves.not.toThrow();
 | 
			
		||||
    expect(getPacket()).toMatchInlineSnapshot(`
 | 
			
		||||
      [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 8,
 | 
			
		||||
            "end": 7,
 | 
			
		||||
            "label": "byte",
 | 
			
		||||
            "start": 0,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 16,
 | 
			
		||||
            "end": 23,
 | 
			
		||||
            "label": "word",
 | 
			
		||||
            "start": 8,
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      ]
 | 
			
		||||
    `);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should split into multiple rows', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    0-10: "test"
 | 
			
		||||
@@ -73,11 +128,13 @@ describe('packet diagrams', () => {
 | 
			
		||||
      [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 11,
 | 
			
		||||
            "end": 10,
 | 
			
		||||
            "label": "test",
 | 
			
		||||
            "start": 0,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 20,
 | 
			
		||||
            "end": 31,
 | 
			
		||||
            "label": "multiple",
 | 
			
		||||
            "start": 11,
 | 
			
		||||
@@ -85,6 +142,7 @@ describe('packet diagrams', () => {
 | 
			
		||||
        ],
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 31,
 | 
			
		||||
            "end": 63,
 | 
			
		||||
            "label": "multiple",
 | 
			
		||||
            "start": 32,
 | 
			
		||||
@@ -92,6 +150,7 @@ describe('packet diagrams', () => {
 | 
			
		||||
        ],
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 26,
 | 
			
		||||
            "end": 90,
 | 
			
		||||
            "label": "multiple",
 | 
			
		||||
            "start": 64,
 | 
			
		||||
@@ -111,11 +170,13 @@ describe('packet diagrams', () => {
 | 
			
		||||
      [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 17,
 | 
			
		||||
            "end": 16,
 | 
			
		||||
            "label": "test",
 | 
			
		||||
            "start": 0,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 14,
 | 
			
		||||
            "end": 31,
 | 
			
		||||
            "label": "multiple",
 | 
			
		||||
            "start": 17,
 | 
			
		||||
@@ -123,6 +184,7 @@ describe('packet diagrams', () => {
 | 
			
		||||
        ],
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "bits": 31,
 | 
			
		||||
            "end": 63,
 | 
			
		||||
            "label": "multiple",
 | 
			
		||||
            "start": 32,
 | 
			
		||||
@@ -142,6 +204,16 @@ describe('packet diagrams', () => {
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should throw error if numbers are not continuous with bit counts', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    16bits: "test"
 | 
			
		||||
    18-20: "error"
 | 
			
		||||
    `;
 | 
			
		||||
    await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot(
 | 
			
		||||
      `[Error: Packet block 18 - 20 is not contiguous. It should start from 16.]`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should throw error if numbers are not continuous for single packets', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    0-16: "test"
 | 
			
		||||
@@ -152,6 +224,16 @@ describe('packet diagrams', () => {
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should throw error if numbers are not continuous for single packets with bit counts', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    16 bits: "test"
 | 
			
		||||
    18: "error"
 | 
			
		||||
    `;
 | 
			
		||||
    await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot(
 | 
			
		||||
      `[Error: Packet block 18 - 18 is not contiguous. It should start from 16.]`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should throw error if numbers are not continuous for single packets - 2', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    0-16: "test"
 | 
			
		||||
@@ -172,4 +254,13 @@ describe('packet diagrams', () => {
 | 
			
		||||
      `[Error: Packet block 25 - 20 is invalid. End must be greater than start.]`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should throw error if bit count is 0', async () => {
 | 
			
		||||
    const str = `packet-beta
 | 
			
		||||
    0bits: "test"
 | 
			
		||||
    `;
 | 
			
		||||
    await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot(
 | 
			
		||||
      `[Error: Packet block 0 is invalid. Cannot have a zero bit field.]`
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -10,26 +10,39 @@ const maxPacketSize = 10_000;
 | 
			
		||||
 | 
			
		||||
const populate = (ast: Packet) => {
 | 
			
		||||
  populateCommonDb(ast, db);
 | 
			
		||||
  let lastByte = -1;
 | 
			
		||||
  let lastBit = -1;
 | 
			
		||||
  let word: PacketWord = [];
 | 
			
		||||
  let row = 1;
 | 
			
		||||
  const { bitsPerRow } = db.getConfig();
 | 
			
		||||
  for (let { start, end, label } of ast.blocks) {
 | 
			
		||||
    if (end && end < start) {
 | 
			
		||||
 | 
			
		||||
  for (let { start, end, bits, label } of ast.blocks) {
 | 
			
		||||
    if (start !== undefined && end !== undefined && end < start) {
 | 
			
		||||
      throw new Error(`Packet block ${start} - ${end} is invalid. End must be greater than start.`);
 | 
			
		||||
    }
 | 
			
		||||
    if (start !== lastByte + 1) {
 | 
			
		||||
    if (start == undefined) {
 | 
			
		||||
      start = lastBit + 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (start !== lastBit + 1) {
 | 
			
		||||
      throw new Error(
 | 
			
		||||
        `Packet block ${start} - ${end ?? start} is not contiguous. It should start from ${
 | 
			
		||||
          lastByte + 1
 | 
			
		||||
          lastBit + 1
 | 
			
		||||
        }.`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    lastByte = end ?? start;
 | 
			
		||||
    log.debug(`Packet block ${start} - ${lastByte} with label ${label}`);
 | 
			
		||||
    if (bits === 0) {
 | 
			
		||||
      throw new Error(`Packet block ${start} is invalid. Cannot have a zero bit field.`);
 | 
			
		||||
    }
 | 
			
		||||
    if (end == undefined) {
 | 
			
		||||
      end = start + (bits ?? 1) - 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (bits == undefined) {
 | 
			
		||||
      bits = end - start + 1;
 | 
			
		||||
    }
 | 
			
		||||
    lastBit = end;
 | 
			
		||||
    log.debug(`Packet block ${start} - ${lastBit} with label ${label}`);
 | 
			
		||||
 | 
			
		||||
    while (word.length <= bitsPerRow + 1 && db.getPacket().length < maxPacketSize) {
 | 
			
		||||
      const [block, nextBlock] = getNextFittingBlock({ start, end, label }, row, bitsPerRow);
 | 
			
		||||
      const [block, nextBlock] = getNextFittingBlock({ start, end, bits, label }, row, bitsPerRow);
 | 
			
		||||
      word.push(block);
 | 
			
		||||
      if (block.end + 1 === row * bitsPerRow) {
 | 
			
		||||
        db.pushWord(word);
 | 
			
		||||
@@ -39,7 +52,7 @@ const populate = (ast: Packet) => {
 | 
			
		||||
      if (!nextBlock) {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      ({ start, end, label } = nextBlock);
 | 
			
		||||
      ({ start, end, bits, label } = nextBlock);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  db.pushWord(word);
 | 
			
		||||
@@ -50,9 +63,8 @@ const getNextFittingBlock = (
 | 
			
		||||
  row: number,
 | 
			
		||||
  bitsPerRow: number
 | 
			
		||||
): [Required<PacketBlock>, PacketBlock | undefined] => {
 | 
			
		||||
  if (block.end === undefined) {
 | 
			
		||||
    block.end = block.start;
 | 
			
		||||
  }
 | 
			
		||||
  assert(block.start !== undefined, 'start should have been set during first phase');
 | 
			
		||||
  assert(block.end !== undefined, 'end should have been set during first phase');
 | 
			
		||||
 | 
			
		||||
  if (block.start > block.end) {
 | 
			
		||||
    throw new Error(`Block start ${block.start} is greater than block end ${block.end}.`);
 | 
			
		||||
@@ -62,16 +74,20 @@ const getNextFittingBlock = (
 | 
			
		||||
    return [block as Required<PacketBlock>, undefined];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const rowEnd = row * bitsPerRow - 1;
 | 
			
		||||
  const rowStart = row * bitsPerRow;
 | 
			
		||||
  return [
 | 
			
		||||
    {
 | 
			
		||||
      start: block.start,
 | 
			
		||||
      end: row * bitsPerRow - 1,
 | 
			
		||||
      end: rowEnd,
 | 
			
		||||
      label: block.label,
 | 
			
		||||
      bits: rowEnd - block.start,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      start: row * bitsPerRow,
 | 
			
		||||
      start: rowStart,
 | 
			
		||||
      end: block.end,
 | 
			
		||||
      label: block.label,
 | 
			
		||||
      bits: block.end - rowStart,
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,12 @@ entry Packet:
 | 
			
		||||
;
 | 
			
		||||
 | 
			
		||||
PacketBlock:
 | 
			
		||||
  start=INT('-' end=INT)? ':' label=STRING EOL
 | 
			
		||||
  (
 | 
			
		||||
    start=INT('-' (end=INT | bits=INT'bit''s'?))? 
 | 
			
		||||
    | bits=INT'bit''s'?
 | 
			
		||||
  )
 | 
			
		||||
  ':' label=STRING
 | 
			
		||||
  EOL
 | 
			
		||||
;
 | 
			
		||||
 | 
			
		||||
terminal INT returns number: /0|[1-9][0-9]*/;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user