4Deserialises the binary ``.phsb`` format into a :class:`~phasor.Bytecode.Bytecode` object.
7from __future__
import annotations
11from pathlib
import Path
13from .Bytecode
import Bytecode
14from .Instruction
import Instruction
15from .Metadata
import (
16 HEADER_SIZE, MAGIC, SEC_CONSTANTS, SEC_FUNCTIONS,
17 SEC_INSTRUCTIONS, SEC_VARIABLES, VERSION,
19from .OpCode
import OpCode
20from .Value
import Value, ValueType
24 """Deserialises ``.phsb`` into :class:`~phasor.Bytecode.Bytecode`."""
27 """Initialise the deserializer with an empty data buffer and zero read position."""
32 """Parse a raw ``.phsb`` byte buffer into a :class:`~phasor.Bytecode.Bytecode` object.
35 data: Raw bytes of a ``.phsb`` file.
38 A fully populated :class:`~phasor.Bytecode.Bytecode` instance.
41 ValueError: If the magic number, version, or CRC-32 checksum is invalid,
42 or if any section tag is unexpected.
49 data_start = self.
_pos
50 actual_crc = zlib.crc32(self.
_data[data_start:]) & 0xFFFFFFFF
51 if actual_crc != checksum:
53 f
"Bytecode checksum mismatch: "
54 f
"expected {checksum:#010x}, got {actual_crc:#010x}"
65 """Read a ``.phsb`` file from disk and deserialise it.
68 path: Path to the ``.phsb`` file to load.
71 A fully populated :class:`~phasor.Bytecode.Bytecode` instance.
73 data = Path(path).read_bytes()
77 """Read and validate the 16-byte file header.
80 The CRC-32 checksum stored in the header, to be verified against
81 the actual data after reading.
84 ValueError: If the magic number does not equal :data:`~phasor.Metadata.MAGIC`
85 or the version does not equal :data:`~phasor.Metadata.VERSION`.
90 f
"Invalid magic number: expected {MAGIC:#010x}, got {magic:#010x}"
94 if version != VERSION:
96 f
"Unsupported version: {version:#010x} (expected {VERSION:#010x})"
104 """Read the :data:`~phasor.Metadata.SEC_CONSTANTS` section and append entries to :attr:`bytecode.constants <phasor.Bytecode.Bytecode.constants>`."""
106 if section_id != SEC_CONSTANTS:
108 f
"Expected constants section (0x{SEC_CONSTANTS:02x}), "
109 f
"got 0x{section_id:02x}"
112 for _
in range(count):
116 """Read the :data:`~phasor.Metadata.SEC_VARIABLES` section and populate :attr:`bytecode.variables <phasor.Bytecode.Bytecode.variables>` and :attr:`~phasor.Bytecode.Bytecode.next_var_index`."""
118 if section_id != SEC_VARIABLES:
120 f
"Expected variables section (0x{SEC_VARIABLES:02x}), "
121 f
"got 0x{section_id:02x}"
125 for _
in range(count):
128 bytecode.variables[name] = index
131 """Read the :data:`~phasor.Metadata.SEC_FUNCTIONS` section and populate :attr:`bytecode.function_entries <phasor.Bytecode.Bytecode.function_entries>`."""
133 if section_id != SEC_FUNCTIONS:
135 f
"Expected functions section (0x{SEC_FUNCTIONS:02x}), "
136 f
"got 0x{section_id:02x}"
139 for _
in range(count):
142 bytecode.function_entries[name] = address
145 """Read the :data:`~phasor.Metadata.SEC_INSTRUCTIONS` section and populate :attr:`bytecode.instructions <phasor.Bytecode.Bytecode.instructions>`."""
147 if section_id != SEC_INSTRUCTIONS:
149 f
"Expected instructions section (0x{SEC_INSTRUCTIONS:02x}), "
150 f
"got 0x{section_id:02x}"
153 for _
in range(count):
158 bytecode.instructions.append(
Instruction(opcode, op1, op2, op3))
161 """Read a type-tagged value and return the corresponding :class:`~phasor.Value.Value`."""
173 raise ValueError(f
"Unknown value type tag: {tag}")
176 """Raise ``ValueError`` if fewer than *n* bytes remain in the buffer."""
179 f
"Unexpected end of data at offset {self._pos} "
180 f
"(need {n} more bytes)"
184 """Read and return the next unsigned byte from the buffer."""
191 """Read and return the next little-endian unsigned 16-bit integer from the buffer."""
193 (v,) = struct.unpack_from(
"<H", self.
_data, self.
_pos)
198 """Read and return the next little-endian unsigned 32-bit integer from the buffer."""
200 (v,) = struct.unpack_from(
"<I", self.
_data, self.
_pos)
205 """Read and return the next little-endian signed 32-bit integer from the buffer."""
207 (v,) = struct.unpack_from(
"<i", self.
_data, self.
_pos)
212 """Read and return the next little-endian signed 64-bit integer from the buffer."""
214 (v,) = struct.unpack_from(
"<q", self.
_data, self.
_pos)
219 """Read and return the next little-endian IEEE 754 double from the buffer."""
221 (v,) = struct.unpack_from(
"<d", self.
_data, self.
_pos)
226 """Read a length-prefixed UTF-8 string (uint16 length + bytes) and return it."""
229 s = self.
_data[self.
_pos : self.
_pos + length].decode(
"utf-8")
Bytecode deserialize(self, bytes data)
None _require(self, int n)
None _read_function_entries(self, Bytecode bytecode)
None _read_instructions(self, Bytecode bytecode)
Bytecode load_from_file(self, Path path)
None _read_variable_mapping(self, Bytecode bytecode)
None _read_constant_pool(self, Bytecode bytecode)