# Copyright 2022 Mattia Giambirtone & All Contributors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import ../frontend/meta/errors import ../frontend/meta/bytecode import ../frontend/compiler import multibyte import ../config import std/strformat import std/strutils import std/times export ast type Serializer* = ref object file: string filename: string chunk: Chunk Serialized* = ref object ## Wrapper returned by ## the Serializer.read* ## procedures to store ## metadata version*: tuple[major, minor, patch: int] branch*: string commit*: string compileDate*: int chunk*: Chunk proc `$`*(self: Serialized): string = result = &"Serialized(version={self.version.major}.{self.version.minor}.{self.version.patch}, branch={self.branch}), commitHash={self.commit}, date={self.compileDate}, chunk={self.chunk[]}" proc error(self: Serializer, message: string) = ## Raises a formatted SerializationError exception raise SerializationError(msg: message, file: self.filename) proc newSerializer*(self: Serializer = nil): Serializer = new(result) if self != nil: result = self result.file = "" result.filename = "" result.chunk = nil proc writeHeaders(self: Serializer, stream: var seq[byte]) = ## Writes the Peon bytecode headers in-place into a byte stream stream.extend(PeonBytecodeMarker.toBytes()) stream.add(byte(PEON_VERSION.major)) stream.add(byte(PEON_VERSION.minor)) stream.add(byte(PEON_VERSION.patch)) stream.add(byte(len(PEON_BRANCH))) stream.extend(PEON_BRANCH.toBytes()) stream.extend(PEON_COMMIT_HASH.toBytes()) stream.extend(getTime().toUnixFloat().int().toBytes()) proc writeLineData(self: Serializer, stream: var seq[byte]) = ## Writes line information for debugging ## bytecode instructions stream.extend(len(self.chunk.lines).toQuad()) for b in self.chunk.lines: stream.extend(b.toTriple()) proc writeCFIData(self: Serializer, stream: var seq[byte]) = ## Writes Call Frame Information for debugging ## functions stream.extend(len(self.chunk.cfi).toQuad()) stream.extend(self.chunk.cfi) proc writeConstants(self: Serializer, stream: var seq[byte]) = ## Writes the constants table in-place into the ## given stream stream.extend(self.chunk.consts.len().toQuad()) for constant in self.chunk.consts: stream.add(constant) proc writeCode(self: Serializer, stream: var seq[byte]) = ## Writes the bytecode from the given chunk to the ## given source stream stream.extend(self.chunk.code.len.toTriple()) stream.extend(self.chunk.code) proc readHeaders(self: Serializer, stream: seq[byte], serialized: Serialized): int = ## Reads the bytecode headers from a given stream ## of bytes var stream = stream if stream[0..