Skip to content

Commit

Permalink
Add bytecode header and docs. Refactor builtins
Browse files Browse the repository at this point in the history
  • Loading branch information
bgk- committed Dec 5, 2024
1 parent 33ad0f9 commit d50f796
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 374 deletions.
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = "topiary",
.version = "0.14.1",
.version = "0.15.0",
.paths = .{""},
.dependencies = .{},
}
181 changes: 181 additions & 0 deletions docs/bytecode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Bytecode Spec

Little endianness

## Header

Starting Positions of each Section

| Name | Type |
|-------------------------------|------|
| [Globals](#Globals) | u64 |
| [Boughs](#Boughs) | u64 |
| [Instructions](#Instructions) | u64 |
| [Debug Info](#Debug) | u64 |
| [Constants](#Constants) | u64 |
| [UUIDS](#UUIDs) | u64 |
| [Localization](#Localization) | u64 |

## Globals

| Name | Type |
|-------|--------------------------|
| Count | u64 |
| Items | [Global](#Global)[Count] |

### Global

| Name | Type |
|------------|------------|
| Length | u8 |
| Name | u8[Length] |
| Index | u32 |
| Is Extern | u8 |
| Is Mutable | u8 |

## Boughs

| Name | Type |
|-------|------------------------|
| Count | u64 |
| Items | [Bough](#Bough)[Count] |

### Bough

| Name | Type |
|----------|------------|
| Length | u8 |
| Name | u8[Length] |
| Position | u32 |

## Instructions

| Name | Type |
|--------------|------|
| Count | u64 |
| Instructions | u8[] |

## Constants

| Name | Type |
|-------|------------------------------|
| Count | u64 |
| Items | [Constant](#Constant)[Count] |

### Constant

| Name | Type |
|-------|-------------------------------------------------------------------------------------------------------------------|
| Type | u8 |
| Value | [Nil](#NilVoid) \| [Void](#NilVoid) \| [Bool](#Bool) \| [Number](#Number) \| [Visit](#Visit) \| [Object](#Object) |

#### Nil/Void

Empty

#### Bool

| Name | Type |
|----------|------------|
| Value | u8 |


#### Number

Stringified value up to 5 decimal places

| Name | Type |
|--------|------------|
| Length | u8 |
| Value | u8[Length] |

#### Visit

| Name | Type |
|----------|------|
| Value | u32 |

#### Object

| Name | Type |
|-------|-------------------------------------------------------------|
| Value | [String](#String) \| [Function](#Function) \| [Enum](#Enum) |

#### String

| Name | Type |
|--------|------------|
| Length | u16 |
| Value | u8[Length] |

#### Function

| Name | Type |
|--------------|------------------------------|
| Arity | u8 |
| Is Method | u8 |
| Locals Count | u16 |
| Count | u16 |
| Instructions | u8[Count] |
| Debug Count | u32 |
| Debug Info | [Debug](#Debug)[Debug Count] |

## Debug

| Name | Type |
|-----------|------------------------|
| Length | u16 |
| File Name | u8[Length] |
| Count | u16 |
| Range | [Range](#Range)[Count] |

#### Range

| Name | Type |
|-------|------|
| Start | u32 |
| End | u32 |
| Line | u32 |

#### Enum

| Name | Type |
|-------------|---------------------------------|
| Length | u16 |
| Name | u8[Length] |
| Is Sequence | u8 |
| Count | u8 |
| Items | [Enum Value](#EnumValue)[Count] |

#### EnumValue

| Name | Type |
|-------------|-------------------|
| Length | u16 |
| Name | u8[Length] |

## UUIDs

| Name | Type |
|-------|----------------------|
| Count | u64 |
| Items | [UUID](#UUID)[Count] |

## UUID

| Name | Type |
|-------|--------|
| Value | u8[17] |

## Localization

| Name | Type |
|-------|-----------|
| Count | u128 |
| Items | u8[Count] |






33 changes: 31 additions & 2 deletions src/backend/bytecode.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub const Bytecode = struct {
boughs: []BoughJump,
loc: []const u8,

const sectionCount = 7;
pub const BoughJump = struct { name: []const u8, ip: C.JUMP };

pub const GlobalSymbol = struct {
Expand Down Expand Up @@ -46,8 +47,17 @@ pub const Bytecode = struct {
allocator.free(self.loc);
}

pub fn serialize(self: *Bytecode, writer: anytype) !void {
// Keep symbols first for easier deserialization in other systems
pub fn serialize(self: *Bytecode, seekable: anytype) !void {
var writer = seekable.writer();
const isSeekable = @hasField(@TypeOf(seekable.*), "getPos");
const headerPos = if (isSeekable) try seekable.getPos() else 0;
var section: u8 = 0;
// globals, boughs, instructions, debug info, constants, uuids, loc
while (section < sectionCount) : (section += 1) {
try writer.writeInt(u64, 0, .little); // Placeholder for section offset
}

const globalPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u64, @as(u64, @intCast(self.global_symbols.len)), .little);
for (self.global_symbols) |sym| {
try writer.writeInt(u8, @as(u8, @intCast(sym.name.len)), .little);
Expand All @@ -57,30 +67,49 @@ pub const Bytecode = struct {
try writer.writeByte(if (sym.is_mutable) 1 else 0);
}

const boughPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u64, @as(u64, @intCast(self.boughs.len)), .little);
for (self.boughs) |bough| {
try writer.writeInt(u16, @as(u16, @intCast(bough.name.len)), .little);
try writer.writeAll(bough.name);
try writer.writeInt(C.JUMP, bough.ip, .little);
}

const instPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u64, @as(u64, @intCast(self.instructions.len)), .little);
try writer.writeAll(self.instructions);

const debugPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u16, @as(u16, @intCast(self.debug_info.len)), .little);
for (self.debug_info) |debug| try debug.serialize(writer);

const constPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u64, @as(u64, @intCast(self.constants.len)), .little);
for (self.constants) |constant| try constant.serialize(writer);

const uuidPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u64, @as(u64, @intCast(self.uuids.len)), .little);
for (self.uuids) |uuid| try writer.writeAll(&uuid);

const locPos = if (isSeekable) try seekable.getPos() else 0;
try writer.writeInt(u128, @as(u128, @intCast(self.loc.len)), .little);
try writer.writeAll(self.loc);

if (isSeekable) {
try seekable.seekTo(headerPos);
try writer.writeInt(u64, globalPos, .little);
try writer.writeInt(u64, boughPos, .little);
try writer.writeInt(u64, instPos, .little);
try writer.writeInt(u64, debugPos, .little);
try writer.writeInt(u64, constPos, .little);
try writer.writeInt(u64, uuidPos, .little);
try writer.writeInt(u64, locPos, .little);
}
}

pub fn deserialize(allocator: std.mem.Allocator, reader: anytype) !Bytecode {
// skip headers
try reader.skipBytes(sectionCount * @sizeOf(u64), .{});
const globals_count = try reader.readInt(u64, .little);
var global_symbols = try allocator.alloc(GlobalSymbol, globals_count);
var count: usize = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/backend/compiler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ pub const Compiler = struct {

pub fn compile(self: *Compiler) Error!void {
const tree = self.module.entry.tree;
inline for (builtins) |builtin| {
_ = try self.builtins.define(builtin.name, false, false);
for (builtins.keys()) |name| {
_ = try self.builtins.define(name, false, false);
}

try self.initializeConstants();
Expand Down
5 changes: 2 additions & 3 deletions src/cli/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,9 @@ pub fn main() !void {
if (std.fs.path.dirname(out_path.?)) |dir_name| {
try dir.makePath(dir_name);
}
const file = try dir.createFile(out_path.?, .{});
var file = try dir.createFile(out_path.?, .{});
defer file.close();
const writer = file.writer();
bytecode.serialize(writer) catch |err| {
bytecode.serialize(&file) catch |err| {
return checkVerbose(err);
};
return;
Expand Down
9 changes: 4 additions & 5 deletions src/export/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub export fn calculateCompileSize(path_ptr: [*:0]const u8, log_ptr: usize, log_
const logger = ExportLogger{ .on_log = @ptrFromInt(log_ptr), .severity = @enumFromInt(log_severity), .allocator = alloc };
logger.log("Calculating Compile size", .{}, .debug);
var counter = std.io.countingWriter(std.io.null_writer);
writeBytecode(std.mem.sliceTo(path_ptr, 0), counter.writer(), logger);
writeBytecode(std.mem.sliceTo(path_ptr, 0), &counter, logger);
return counter.bytes_written;
}

Expand All @@ -37,12 +37,11 @@ pub export fn calculateCompileSize(path_ptr: [*:0]const u8, log_ptr: usize, log_
pub export fn compile(path_ptr: [*:0]const u8, out_ptr: [*]u8, max: usize, log_ptr: usize, log_severity: u8) callconv(.C) usize {
const logger = ExportLogger{ .on_log = @ptrFromInt(log_ptr), .severity = @enumFromInt(log_severity), .allocator = alloc };
var fbs = std.io.fixedBufferStream(out_ptr[0..max]);
const writer = fbs.writer();
writeBytecode(std.mem.sliceTo(path_ptr, 0), writer, logger);
writeBytecode(std.mem.sliceTo(path_ptr, 0), &fbs, logger);
return fbs.pos;
}

fn writeBytecode(path: []const u8, writer: anytype, logger: ExportLogger) void {
fn writeBytecode(path: []const u8, seekable: anytype, logger: ExportLogger) void {
var arena = std.heap.ArenaAllocator.init(alloc);
defer arena.deinit();
const comp_alloc = arena.allocator();
Expand Down Expand Up @@ -102,7 +101,7 @@ fn writeBytecode(path: []const u8, writer: anytype, logger: ExportLogger) void {
return;
};

bytecode.serialize(writer) catch |err| {
bytecode.serialize(seekable) catch |err| {
logger.log("Could not serialize bytecode: {s}", .{@errorName(err)}, .err);
return;
};
Expand Down
Loading

0 comments on commit d50f796

Please sign in to comment.