Compare commits
17 Commits
31651dc96a
...
85f4957661
| Author | SHA1 | Date | |
|---|---|---|---|
| 85f4957661 | |||
| 2756957f9b | |||
| 4f2aad8065 | |||
| f2b7817cac | |||
| 0a3d82a562 | |||
| 6363bc3bd1 | |||
| 868550703f | |||
| eb3c3814ec | |||
| fa42b20136 | |||
| 0b23707041 | |||
| b0deb958d2 | |||
| d03910f6f0 | |||
| a6f67d3f0d | |||
| 9fb8ec9454 | |||
| 99f8ae059c | |||
| 1e8e14ed67 | |||
| 11e948d500 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,2 +1,3 @@
|
|||||||
*.dll filter=lfs diff=lfs merge=lfs -text
|
*.dll filter=lfs diff=lfs merge=lfs -text
|
||||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.so filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"files.exclude":{
|
|
||||||
"**/.zig-cache": true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
44
castle.code-workspace
Normal file
44
castle.code-workspace
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"name": "cjit",
|
||||||
|
"path": "packages/cjit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "js",
|
||||||
|
"path": "packages/js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "media",
|
||||||
|
"path": "packages/media"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "myid",
|
||||||
|
"path": "packages/myid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sciter",
|
||||||
|
"path": "packages/sciter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tcc",
|
||||||
|
"path": "packages/tcc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vecmath",
|
||||||
|
"path": "packages/vecmath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x11",
|
||||||
|
"path": "packages/x11"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.zig-cache": true,
|
||||||
|
},
|
||||||
|
"files.associations": {
|
||||||
|
"**/packages/tcc/vendor/*.{def,h}": "c",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
44
packages/cjit/build.zig
Normal file
44
packages/cjit/build.zig
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{
|
||||||
|
.whitelist = &.{
|
||||||
|
.{
|
||||||
|
.cpu_arch = .x86_64,
|
||||||
|
.os_tag = .windows,
|
||||||
|
.abi = .gnu,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.cpu_arch = .x86_64,
|
||||||
|
.os_tag = .linux,
|
||||||
|
.abi = .gnu,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const module = b.addModule("cjit", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const module_internal_test = b.addTest(.{ .root_module = module });
|
||||||
|
const run_internal_test = b.addRunArtifact(module_internal_test);
|
||||||
|
|
||||||
|
const module_external_test = b.addTest(.{
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.resolveTargetQuery(.{}),
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("test/root.zig"),
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "cjit", .module = module },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const run_external_test = b.addRunArtifact(module_external_test);
|
||||||
|
|
||||||
|
const step_test = b.step("test", "Run tests");
|
||||||
|
step_test.dependOn(&run_internal_test.step);
|
||||||
|
step_test.dependOn(&run_external_test.step);
|
||||||
|
}
|
||||||
11
packages/cjit/build.zig.zon
Normal file
11
packages/cjit/build.zig.zon
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.{
|
||||||
|
.name = .cjit,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.minimum_zig_version = "0.15.2",
|
||||||
|
.paths = .{
|
||||||
|
"src",
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
},
|
||||||
|
.fingerprint = 0xaec0accc19243440,
|
||||||
|
}
|
||||||
154
packages/cjit/src/Runtime.zig
Normal file
154
packages/cjit/src/Runtime.zig
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const tokens = @import("tokens.zig");
|
||||||
|
const types = @import("types.zig");
|
||||||
|
|
||||||
|
const Sections = @import("Sections.zig");
|
||||||
|
const StackValue = @import("StackValue.zig");
|
||||||
|
const Tokenizer = tokens.Tokenizer;
|
||||||
|
const Type = types.Type;
|
||||||
|
|
||||||
|
pub const virtual_stack_size = 256;
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
|
symbols_needed: std.StringHashMapUnmanaged(ExternSymbol) = .{},
|
||||||
|
symbols_provided: std.StringHashMapUnmanaged(InternSymbol) = .{},
|
||||||
|
symbols_located: std.StringHashMapUnmanaged(LocatedSymbol) = .{},
|
||||||
|
relocation_table: std.ArrayList(Relocation) = .{},
|
||||||
|
/// Bounded, preallocated with the capacity of `virtual_stack_size`.
|
||||||
|
virtual_stack: std.ArrayList(StackValue),
|
||||||
|
tokenizer: Tokenizer,
|
||||||
|
sections: Sections = .{},
|
||||||
|
|
||||||
|
pub const ExternSymbol = struct {
|
||||||
|
name: []const u8,
|
||||||
|
c_type: Type,
|
||||||
|
ptr: ?*anyopaque,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const InternSymbol = struct {
|
||||||
|
name: []const u8,
|
||||||
|
public: bool,
|
||||||
|
c_type: Type,
|
||||||
|
location: Location,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Location = union(enum) {
|
||||||
|
text: usize,
|
||||||
|
data: usize,
|
||||||
|
rodata: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const LocatedSymbol = struct {
|
||||||
|
name: []const u8,
|
||||||
|
public: bool,
|
||||||
|
c_type: Type,
|
||||||
|
ptr: ?*anyopaque,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Relocation = struct {
|
||||||
|
addr: usize,
|
||||||
|
location: Location,
|
||||||
|
type: RelocationType,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RelocationType = enum {
|
||||||
|
global_offset_table,
|
||||||
|
rip_disp32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !Self {
|
||||||
|
var arena: std.heap.ArenaAllocator = .init(allocator);
|
||||||
|
const arena_allocator = arena.allocator();
|
||||||
|
errdefer arena.deinit();
|
||||||
|
|
||||||
|
const virtual_stack_buffer = try arena_allocator.alloc(StackValue, virtual_stack_size);
|
||||||
|
const tokenizer = try Tokenizer.init(arena_allocator);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.arena = arena,
|
||||||
|
.virtual_stack = .initBuffer(virtual_stack_buffer),
|
||||||
|
.tokenizer = tokenizer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.symbols_needed.deinit(self.allocator);
|
||||||
|
self.symbols_provided.deinit(self.allocator);
|
||||||
|
self.symbols_located.deinit(self.allocator);
|
||||||
|
self.relocation_table.deinit(self.allocator);
|
||||||
|
self.arena.deinit();
|
||||||
|
// TODO deinit sections (stage-depentent)
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(self: *Self, filename: []const u8, code: []const u8) !void {
|
||||||
|
self.tokenizer.setSource(filename, code);
|
||||||
|
while (try self.tokenizer.nextToken(self.arena.allocator())) |token| {
|
||||||
|
_ = token;
|
||||||
|
std.debug.panic("Not implemented", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setSymbol(self: *Self, comptime T: type, name: []const u8, ptr: *const T) !void {
|
||||||
|
const symbol = self.symbols_needed.getPtr(name) orelse return error.SymbolNotFound;
|
||||||
|
if (!types.isCompatible(T, symbol.c_type)) return error.IncompatibleType;
|
||||||
|
|
||||||
|
// TODO Figure out const-correctness
|
||||||
|
symbol.ptr = @ptrCast(@constCast(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn link(self: *Self) !void {
|
||||||
|
try self.sections.relocateSections(self.allocator);
|
||||||
|
|
||||||
|
const text_base = @intFromPtr(self.sections.text.data.items.ptr);
|
||||||
|
const data_base = @intFromPtr(self.sections.data.data.items.ptr);
|
||||||
|
const rodata_base = @intFromPtr(self.sections.rodata.data.items.ptr);
|
||||||
|
|
||||||
|
for (self.relocation_table.items) |relocation| {
|
||||||
|
const target_addr = switch (relocation.location) {
|
||||||
|
.text => |offset| text_base + offset,
|
||||||
|
.data => |offset| data_base + offset,
|
||||||
|
.rodata => |offset| rodata_base + offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (relocation.type) {
|
||||||
|
.global_offset_table => {
|
||||||
|
std.mem.writeInt(
|
||||||
|
usize,
|
||||||
|
self.sections.rodata.data.items[relocation.addr..][0..@sizeOf(usize)],
|
||||||
|
target_addr,
|
||||||
|
builtin.cpu.arch.endian(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
.rip_disp32 => {
|
||||||
|
const rip = text_base + relocation.addr + 4;
|
||||||
|
const disp64: isize = @bitCast(rip -% target_addr);
|
||||||
|
const disp32 = std.math.cast(i32, disp64) orelse return error.RelocationError;
|
||||||
|
std.mem.writeInt(
|
||||||
|
i32,
|
||||||
|
self.sections.text.data.items[relocation.addr..][0..4],
|
||||||
|
disp32,
|
||||||
|
builtin.cpu.arch.endian(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.relocation_table.clearAndFree(self.allocator);
|
||||||
|
|
||||||
|
try self.sections.protectSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getSymbol(self: *const Self, comptime T: type, name: []const u8) ?*const T {
|
||||||
|
const symbol = self.symbols_located.get(name) orelse return null;
|
||||||
|
return @ptrCast(@alignCast(symbol.ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(self: *Self, comptime T: type) error{OutOfMemory}!*T {
|
||||||
|
return self.arena.allocator().create(T);
|
||||||
|
}
|
||||||
185
packages/cjit/src/Sections.zig
Normal file
185
packages/cjit/src/Sections.zig
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
text: Section = .{ .protection = .executable },
|
||||||
|
data: Section = .{ .protection = .read_write },
|
||||||
|
rodata: Section = .{ .protection = .read_only },
|
||||||
|
|
||||||
|
pub const Section = struct {
|
||||||
|
data: std.ArrayList(u8) = .{},
|
||||||
|
protection: Protection,
|
||||||
|
|
||||||
|
pub const Protection = enum {
|
||||||
|
executable,
|
||||||
|
read_only,
|
||||||
|
read_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn writeValue(self: *Section, value: anytype, allocator: std.mem.Allocator) !void {
|
||||||
|
const T = @TypeOf(value);
|
||||||
|
std.debug.assert(std.meta.hasUniqueRepresentation(T));
|
||||||
|
const bytes = std.mem.asBytes(&value);
|
||||||
|
try self.writeBytes(bytes, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writeByte(self: *Section, byte: u8, allocator: std.mem.Allocator) !void {
|
||||||
|
try self.data.append(allocator, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writeBytes(self: *Section, data: []const u8, allocator: std.mem.Allocator) !void {
|
||||||
|
try self.data.appendSlice(allocator, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alignForward(self: *Section, alignment: u16, allocator: std.mem.Allocator) !void {
|
||||||
|
const ptr = self.data.items.len;
|
||||||
|
const ptr_aligned = std.mem.alignForward(usize, ptr, alignment);
|
||||||
|
const padding = ptr_aligned - ptr;
|
||||||
|
|
||||||
|
try self.data.appendNTimes(allocator, 0, padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pageCount(self: Section) usize {
|
||||||
|
const page_size = std.heap.pageSize();
|
||||||
|
const section_size = self.data.items.len;
|
||||||
|
return @divFloor(section_size + page_size - 1, page_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn relocateSections(self: *Self, allocator: std.mem.Allocator) !void {
|
||||||
|
const page_size = std.heap.pageSize();
|
||||||
|
|
||||||
|
const text_pages = self.text.pageCount();
|
||||||
|
const text_bytes = text_pages * page_size;
|
||||||
|
|
||||||
|
const data_pages = self.data.pageCount();
|
||||||
|
const data_bytes = data_pages * page_size;
|
||||||
|
|
||||||
|
const rodata_pages = self.rodata.pageCount();
|
||||||
|
const rodata_bytes = rodata_pages * page_size;
|
||||||
|
|
||||||
|
const total_pages = text_pages + data_pages + rodata_pages;
|
||||||
|
const total_bytes = text_bytes + data_bytes + rodata_bytes;
|
||||||
|
std.debug.assert(total_bytes == total_pages * page_size);
|
||||||
|
|
||||||
|
const ptr: [*]u8 = sw: switch (builtin.os.tag) {
|
||||||
|
.windows => {
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const ntdll = windows.ntdll;
|
||||||
|
|
||||||
|
var base_addr: ?*anyopaque = null;
|
||||||
|
var size: windows.SIZE_T = total_bytes;
|
||||||
|
const status = ntdll.NtAllocateVirtualMemory(
|
||||||
|
windows.GetCurrentProcess(),
|
||||||
|
@ptrCast(&base_addr),
|
||||||
|
0,
|
||||||
|
&size,
|
||||||
|
windows.MEM_COMMIT | windows.MEM_RESERVE,
|
||||||
|
windows.PAGE_READWRITE,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (status == .SUCCESS) {
|
||||||
|
break :sw @ptrCast(base_addr);
|
||||||
|
} else {
|
||||||
|
return error.OutOfMemory;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.linux => {
|
||||||
|
const linux = std.os.linux;
|
||||||
|
|
||||||
|
const rc = linux.mmap(
|
||||||
|
null,
|
||||||
|
total_bytes,
|
||||||
|
linux.PROT.READ | linux.PROT.WRITE,
|
||||||
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
const status: linux.E = .init(rc);
|
||||||
|
|
||||||
|
if (status == .SUCCESS) {
|
||||||
|
break :sw @ptrFromInt(rc);
|
||||||
|
} else {
|
||||||
|
return error.OutOfMemory;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => @compileError("Operating system " ++ @tagName(builtin.os.tag) ++ " not supported"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const text_slice = ptr[0..text_bytes];
|
||||||
|
const data_slice = ptr[text_bytes .. text_bytes + data_bytes];
|
||||||
|
const rodata_slice = ptr[text_bytes + data_bytes .. text_bytes + data_bytes + rodata_bytes];
|
||||||
|
|
||||||
|
@memcpy(text_slice[0..self.text.data.items.len], self.text.data.items);
|
||||||
|
@memcpy(data_slice[0..self.data.data.items.len], self.data.data.items);
|
||||||
|
@memcpy(rodata_slice[0..self.rodata.data.items.len], self.rodata.data.items);
|
||||||
|
|
||||||
|
self.text.data.clearAndFree(allocator);
|
||||||
|
self.data.data.clearAndFree(allocator);
|
||||||
|
self.rodata.data.clearAndFree(allocator);
|
||||||
|
|
||||||
|
self.text.data = .{ .items = text_slice, .capacity = text_bytes };
|
||||||
|
self.data.data = .{ .items = data_slice, .capacity = data_bytes };
|
||||||
|
self.rodata.data = .{ .items = rodata_slice, .capacity = rodata_bytes };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn protectSections(self: *Self) !void {
|
||||||
|
const sections = [_]*Section{ &self.text, &self.data, &self.rodata };
|
||||||
|
|
||||||
|
for (sections) |section| {
|
||||||
|
switch (builtin.os.tag) {
|
||||||
|
.windows => {
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const ntdll = windows.ntdll;
|
||||||
|
|
||||||
|
const protection = switch (section.protection) {
|
||||||
|
.executable => windows.PAGE_EXECUTE,
|
||||||
|
.read_only => windows.PAGE_READONLY,
|
||||||
|
.read_write => windows.PAGE_READWRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
var base_addr: ?*anyopaque = section.data.items.ptr;
|
||||||
|
var size: windows.SIZE_T = section.data.capacity;
|
||||||
|
var old_protection: u32 = undefined;
|
||||||
|
|
||||||
|
const status = ntdll.NtProtectVirtualMemory(
|
||||||
|
windows.GetCurrentProcess(),
|
||||||
|
&base_addr,
|
||||||
|
&size,
|
||||||
|
protection,
|
||||||
|
&old_protection,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (status != .SUCCESS) {
|
||||||
|
return error.ProtectionError;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.linux => {
|
||||||
|
const linux = std.os.linux;
|
||||||
|
|
||||||
|
const protection: usize = switch (section.protection) {
|
||||||
|
.executable => linux.PROT.EXEC,
|
||||||
|
.read_only => linux.PROT.READ,
|
||||||
|
.read_write => linux.PROT.READ | linux.PROT.WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rc = linux.mprotect(
|
||||||
|
section.data.items.ptr,
|
||||||
|
section.data.capacity,
|
||||||
|
protection,
|
||||||
|
);
|
||||||
|
const status: linux.E = .init(rc);
|
||||||
|
|
||||||
|
if (status != .SUCCESS) {
|
||||||
|
return error.ProtectionError;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => @compileError("Operating system " ++ @tagName(builtin.os.tag) ++ " not supported"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeSections(self: *Self) void {
|
||||||
|
_ = self;
|
||||||
|
std.debug.panic("Not implemented", .{});
|
||||||
|
}
|
||||||
20
packages/cjit/src/StackValue.zig
Normal file
20
packages/cjit/src/StackValue.zig
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const types = @import("types.zig");
|
||||||
|
const x86_64 = @import("x86_64.zig");
|
||||||
|
|
||||||
|
const Register = x86_64.Register;
|
||||||
|
const Type = types.Type;
|
||||||
|
|
||||||
|
pub const Value = union(enum) {
|
||||||
|
register: Register,
|
||||||
|
constant: u64,
|
||||||
|
symbol: []const u8,
|
||||||
|
/// Displacement in bytes from current value of base pointer register.
|
||||||
|
stack: i32,
|
||||||
|
cpu_flags: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
c_type: Type,
|
||||||
|
value: Value,
|
||||||
31
packages/cjit/src/includes/builtin.h
Normal file
31
packages/cjit/src/includes/builtin.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define abs(value) __builtin_abs(value)
|
||||||
|
#define byteswap(value) __builtin_byteswap(value)
|
||||||
|
#define ceil(value) __builtin_ceil(value)
|
||||||
|
#define clz(value) __builtin_clz(value)
|
||||||
|
#define containerof(ptr, type, member) __builtin_containerof(ptr, type, member)
|
||||||
|
#define cos(value) __builtin_cos(value)
|
||||||
|
#define ctz(value) __builtin_ctz(value)
|
||||||
|
#define embedfile(path) __builtin_embedfile(path)
|
||||||
|
#define exp(value) __builtin_exp(value)
|
||||||
|
#define exp2(value) __builtin_exp2(value)
|
||||||
|
#define floor(value) __builtin_floor(value)
|
||||||
|
#define frameaddress() __builtin_frameaddress()
|
||||||
|
#define log(value) __builtin_log(value)
|
||||||
|
#define log10(value) __builtin_log10(value)
|
||||||
|
#define log2(value) __builtin_log2(value)
|
||||||
|
#define max(...) __builtin_max(__VA_ARGS__)
|
||||||
|
#define memcpy(dest, src, count) __builtin_memcpy(dest, src, count)
|
||||||
|
#define memmove(dest, src, count) __builtin_memmove(dest, src, count)
|
||||||
|
#define memset(value) __builtin_memset(value)
|
||||||
|
#define min(...) __builtin_min(__VA_ARGS__)
|
||||||
|
#define popcount(value) __builtin_popcount(value)
|
||||||
|
#define returnaddress() __builtin_returnaddress()
|
||||||
|
#define round(value) __builtin_round(value)
|
||||||
|
#define sin(value) __builtin_sin(value)
|
||||||
|
#define sqrt(value) __builtin_sqrt(value)
|
||||||
|
#define tan(value) __builtin_tan(value)
|
||||||
|
#define trunc(value) __builtin_trunc(value)
|
||||||
|
#define typename(type) __builtin_typename(type)
|
||||||
|
#define typeof(...) __builtin_typeof(__VA_ARGS__)
|
||||||
7
packages/cjit/src/includes/stdalign.h
Normal file
7
packages/cjit/src/includes/stdalign.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define alignas _Alignas
|
||||||
|
#define alignof _Alignof
|
||||||
|
|
||||||
|
#define __alignas_is_defined 1
|
||||||
|
#define __alignof_is_defined 1
|
||||||
7
packages/cjit/src/includes/stdbool.h
Normal file
7
packages/cjit/src/includes/stdbool.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define bool _Bool
|
||||||
|
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#define __bool_true_false_are_defined 1
|
||||||
9
packages/cjit/src/includes/stddef.h
Normal file
9
packages/cjit/src/includes/stddef.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef long ptrdiff_t;
|
||||||
|
typedef long max_align_t;
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
|
||||||
|
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||||
118
packages/cjit/src/includes/stdint.h
Normal file
118
packages/cjit/src/includes/stdint.h
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long int64_t;
|
||||||
|
|
||||||
|
typedef int8_t int_fast8_t;
|
||||||
|
typedef int16_t int_fast16_t;
|
||||||
|
typedef int32_t int_fast32_t;
|
||||||
|
typedef int64_t int_fast64_t;
|
||||||
|
|
||||||
|
typedef int8_t int_least8_t;
|
||||||
|
typedef int16_t int_least16_t;
|
||||||
|
typedef int32_t int_least32_t;
|
||||||
|
typedef int64_t int_least64_t;
|
||||||
|
|
||||||
|
typedef int64_t intmax_t;
|
||||||
|
typedef int64_t intptr_t;
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned long uint64_t;
|
||||||
|
|
||||||
|
typedef uint8_t uint_fast8_t;
|
||||||
|
typedef uint16_t uint_fast16_t;
|
||||||
|
typedef uint32_t uint_fast32_t;
|
||||||
|
typedef uint64_t uint_fast64_t;
|
||||||
|
|
||||||
|
typedef uint8_t uint_least8_t;
|
||||||
|
typedef uint16_t uint_least16_t;
|
||||||
|
typedef uint32_t uint_least32_t;
|
||||||
|
typedef uint64_t uint_least64_t;
|
||||||
|
|
||||||
|
typedef uint64_t uintmax_t;
|
||||||
|
typedef uint64_t uintptr_t;
|
||||||
|
|
||||||
|
#define INT8_MIN (-0x80)
|
||||||
|
#define INT16_MIN (-0x8000)
|
||||||
|
#define INT32_MIN (-0x80000000)
|
||||||
|
#define INT64_MIN (-0x8000000000000000L)
|
||||||
|
|
||||||
|
#define INT_FAST8_MIN INT8_MIN
|
||||||
|
#define INT_FAST16_MIN INT16_MIN
|
||||||
|
#define INT_FAST32_MIN INT32_MIN
|
||||||
|
#define INT_FAST64_MIN INT64_MIN
|
||||||
|
|
||||||
|
#define INT_LEAST8_MIN INT8_MIN
|
||||||
|
#define INT_LEAST16_MIN INT16_MIN
|
||||||
|
#define INT_LEAST32_MIN INT32_MIN
|
||||||
|
#define INT_LEAST64_MIN INT64_MIN
|
||||||
|
|
||||||
|
#define INTPTR_MIN INT64_MIN
|
||||||
|
#define INTMAX_MIN INT64_MIN
|
||||||
|
|
||||||
|
#define INT8_MAX (0x7F)
|
||||||
|
#define INT16_MAX (0x7FFF)
|
||||||
|
#define INT32_MAX (0x7FFFFFFF)
|
||||||
|
#define INT64_MAX (0x7FFFFFFFFFFFFFFFL)
|
||||||
|
|
||||||
|
#define INT_FAST8_MAX INT8_MAX
|
||||||
|
#define INT_FAST16_MAX INT16_MAX
|
||||||
|
#define INT_FAST32_MAX INT32_MAX
|
||||||
|
#define INT_FAST64_MAX INT64_MAX
|
||||||
|
|
||||||
|
#define INT_LEAST8_MAX INT8_MAX
|
||||||
|
#define INT_LEAST16_MAX INT16_MAX
|
||||||
|
#define INT_LEAST32_MAX INT32_MAX
|
||||||
|
#define INT_LEAST64_MAX INT64_MAX
|
||||||
|
|
||||||
|
#define INTPTR_MAX INT64_MAX
|
||||||
|
#define INTMAX_MAX INT64_MAX
|
||||||
|
|
||||||
|
#define UINT8_MAX (0xFF)
|
||||||
|
#define UINT16_MAX (0xFFFF)
|
||||||
|
#define UINT32_MAX (0xFFFFFFFFU)
|
||||||
|
#define UINT64_MAX (0xFFFFFFFFFFFFFFFFUL)
|
||||||
|
|
||||||
|
#define UINT_FAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_FAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
#define UINT_LEAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_LEAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_LEAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_LEAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
#define UINTPTR_MAX UINT64_MAX
|
||||||
|
#define UINTMAX_MAX UINT64_MAX
|
||||||
|
|
||||||
|
#define INT8_C(value) value
|
||||||
|
#define INT16_C(value) value
|
||||||
|
#define INT32_C(value) value
|
||||||
|
#define INT64_C(value) value ## L
|
||||||
|
|
||||||
|
#define INTMAX_C(value) value ## L
|
||||||
|
|
||||||
|
#define UINT8_C(value) value
|
||||||
|
#define UINT16_C(value) value
|
||||||
|
#define UINT32_C(value) value ## U
|
||||||
|
#define UINT64_C(value) value ## UL
|
||||||
|
|
||||||
|
#define UINTMAX_C(value) value ## UL
|
||||||
|
|
||||||
|
#define PTRDIFF_MIN (-0x8000000000000000L)
|
||||||
|
#define PTRDIFF_MAX (0x7FFFFFFFFFFFFFFFL)
|
||||||
|
|
||||||
|
#define SIZE_MAX (0xFFFFFFFFFFFFFFFFUL)
|
||||||
|
|
||||||
|
#define WINT_MIN (-0x80000000)
|
||||||
|
#define WINT_MAX (0x7FFFFFFF)
|
||||||
|
|
||||||
|
#define WCHAR_MIN (0)
|
||||||
|
#define WCHAR_MAX (0x10FFFF)
|
||||||
|
|
||||||
|
#endif
|
||||||
3
packages/cjit/src/includes/stdnoreturn.h
Normal file
3
packages/cjit/src/includes/stdnoreturn.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define noreturn _Noreturn
|
||||||
19
packages/cjit/src/root.zig
Normal file
19
packages/cjit/src/root.zig
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
pub const Runtime = @import("Runtime.zig");
|
||||||
|
pub const Sections = @import("Sections.zig");
|
||||||
|
pub const StackValue = @import("StackValue.zig");
|
||||||
|
pub const tokens = @import("tokens.zig");
|
||||||
|
pub const types = @import("types.zig");
|
||||||
|
pub const x86_64 = @import("x86_64.zig");
|
||||||
|
|
||||||
|
pub const call: std.builtin.CallingConvention = switch (builtin.cpu.arch) {
|
||||||
|
.aarch64 => .{ .aarch64_aapcs = .{} },
|
||||||
|
.x86_64 => .{ .x86_64_sysv = .{} },
|
||||||
|
else => @compileError("Architecture " ++ @tagName(builtin.cpu.arch) ++ " not supported"),
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
std.testing.refAllDeclsRecursive(@This());
|
||||||
|
}
|
||||||
7
packages/cjit/src/tokens.zig
Normal file
7
packages/cjit/src/tokens.zig
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub const Builtin = @import("tokens/Builtin.zig").Builtin;
|
||||||
|
pub const Constant = @import("tokens/Constant.zig").Constant;
|
||||||
|
pub const Keyword = @import("tokens/Keyword.zig").Keyword;
|
||||||
|
pub const Punctuator = @import("tokens/Punctuator.zig").Punctuator;
|
||||||
|
pub const Token = @import("tokens/Token.zig").Token;
|
||||||
|
pub const Tokenizer = @import("tokens/Tokenizer.zig");
|
||||||
|
pub const Utf8Iterator = @import("tokens/Utf8Iterator.zig");
|
||||||
156
packages/cjit/src/tokens/Builtin.zig
Normal file
156
packages/cjit/src/tokens/Builtin.zig
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const Builtin = enum {
|
||||||
|
/// Usage: `__builtin_abs(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any integer or real type. Equivalent to
|
||||||
|
/// `value < 0 ? -value : value`. Noop for unsigned integer types.
|
||||||
|
__builtin_abs,
|
||||||
|
/// Usage: `__builtin_byteswap(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any integer type.
|
||||||
|
__builtin_byteswap,
|
||||||
|
/// Usage: `__builtin_ceil(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_ceil,
|
||||||
|
/// Usage: `__builtin_clz(value)`
|
||||||
|
///
|
||||||
|
/// Count leading zeroes. `value` can be any integer type. The return type
|
||||||
|
/// is `int`.
|
||||||
|
__builtin_clz,
|
||||||
|
/// Usage `__builtin_containerof(ptr, type, member)`
|
||||||
|
///
|
||||||
|
/// `ptr` must be an pointer to a struct or a union. `type` must be a type.
|
||||||
|
/// `member` must be an identifier. Given `ptr` is a pointer to a given
|
||||||
|
/// member of `type`, returns a pointer to the entire container.
|
||||||
|
__builtin_containerof,
|
||||||
|
/// Usage: `__builtin_cos(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_cos,
|
||||||
|
/// Usage: `__builtin_ctz(value)`
|
||||||
|
///
|
||||||
|
/// Count trailing zeroes. `value` can be any integer type. The return type
|
||||||
|
/// is `int`.
|
||||||
|
__builtin_ctz,
|
||||||
|
/// Usage: `__builtin_embedfile(path)`
|
||||||
|
///
|
||||||
|
/// `path` must be a string literal. The return type is `const char *`. The
|
||||||
|
/// data is null-terminated.
|
||||||
|
__builtin_embedfile,
|
||||||
|
/// Usage `__builtin_exp(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type. Calculates e^value.
|
||||||
|
__builtin_exp,
|
||||||
|
/// Usage `__builtin_exp2(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type. Calculates 2^value.
|
||||||
|
__builtin_exp2,
|
||||||
|
/// Usage: `__bultin_floor(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_floor,
|
||||||
|
/// Usage: `__builtin_frameaddress()`
|
||||||
|
///
|
||||||
|
/// Returns the value of base pointer. The return type is equivalent to
|
||||||
|
/// `uintptr_t`.
|
||||||
|
__builtin_frameaddress,
|
||||||
|
/// Usage: `__builtin_log(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type. Calculates natural logarithm (base e).
|
||||||
|
__builtin_log,
|
||||||
|
/// Usage: `__builtin_log10(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type. Calculates base 10 logarithm.
|
||||||
|
__builtin_log10,
|
||||||
|
/// Usage: `__builtin_log2(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type. Calculates base 2 logarithm.
|
||||||
|
__builtin_log2,
|
||||||
|
/// Usage: `__builtin_max(...)`
|
||||||
|
///
|
||||||
|
/// The arguments can be any integer or real types. NaN values are ignored.
|
||||||
|
__builtin_max,
|
||||||
|
/// Usage: `__builtin_memcpy(dest, src, count)`
|
||||||
|
///
|
||||||
|
/// `dest` and `src` must be pointers. The pointers are reinterpreted as
|
||||||
|
/// pointers to `char`. `count` is coerced to the equivalent of `size_t`.
|
||||||
|
/// `dest` must be a non-const pointer. The regions must not overlap.
|
||||||
|
__builtin_memcpy,
|
||||||
|
/// Usage: `__builtin_memmove(dest, src, count)`
|
||||||
|
///
|
||||||
|
/// `dest` and `src` must be pointers. The pointers are reinterpreted as
|
||||||
|
/// pointers to `char`. `count` is coerced to the equivalent of `size_t`.
|
||||||
|
/// `dest` must be a non-const pointer. The regions may overlap.
|
||||||
|
__builtin_memmove,
|
||||||
|
/// Usage: `__builtin_memset(dest, ch, count)`
|
||||||
|
///
|
||||||
|
/// `dest` must be a pointer. The pointer is reinterpreted as pointer to
|
||||||
|
/// `char`. `ch` is cast to `unsigned char`. `dest` must be a non-const
|
||||||
|
// pointer.
|
||||||
|
__builtin_memset,
|
||||||
|
/// Usage: `__builtin_min(...)`
|
||||||
|
///
|
||||||
|
/// The arguments can be any integer or real types. NaN values are ignored.
|
||||||
|
__builtin_min,
|
||||||
|
/// Usage: `__builtin_offsetof(type, member)`
|
||||||
|
///
|
||||||
|
/// `type` must be a type. `member` must be an identifier.
|
||||||
|
__builtin_offsetof,
|
||||||
|
/// Usage: `__builtin_popcount(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any integer type. The return type is `int`.
|
||||||
|
__builtin_popcount,
|
||||||
|
/// Usage: `__builtin_returnaddress()`
|
||||||
|
///
|
||||||
|
/// Returns the address of the instruction to run after current function
|
||||||
|
/// returns. The return type is equivalent to `uintptr_t`.
|
||||||
|
__builtin_returnaddress,
|
||||||
|
/// Usage: `__builtin_round(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_round,
|
||||||
|
/// Usage: `__builtin_sin(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_sin,
|
||||||
|
/// Usage: `__builtin_sqrt(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_sqrt,
|
||||||
|
/// Usage: `__builtin_tan(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_tan,
|
||||||
|
/// Usage: `__builtin_trunc(value)`
|
||||||
|
///
|
||||||
|
/// `value` can be any real type.
|
||||||
|
__builtin_trunc,
|
||||||
|
/// Usage: `__builtin_typename(type)`
|
||||||
|
///
|
||||||
|
/// `type` must be a type. The return type is `const char *`.
|
||||||
|
__builtin_typename,
|
||||||
|
/// Usage: `__builtin_typeof(...)`
|
||||||
|
__builtin_typeof,
|
||||||
|
|
||||||
|
pub const map: std.StaticStringMap(Builtin) = blk: {
|
||||||
|
const fields = @typeInfo(Builtin).@"enum".fields;
|
||||||
|
|
||||||
|
var kvs_list: [fields.len]struct { []const u8, Builtin } = undefined;
|
||||||
|
for (fields, 0..) |field, i| {
|
||||||
|
kvs_list[i] = .{ field.name, @field(Builtin, field.name) };
|
||||||
|
}
|
||||||
|
|
||||||
|
break :blk .initComptime(kvs_list);
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn isBuiltin(identifier: []const u8) ?Builtin {
|
||||||
|
if (std.mem.startsWith(u8, identifier, "__builtin_")) {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
return map.get(identifier);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
14
packages/cjit/src/tokens/Constant.zig
Normal file
14
packages/cjit/src/tokens/Constant.zig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const Constant = union(enum) {
|
||||||
|
int: i32,
|
||||||
|
long: i64,
|
||||||
|
long_long: i64,
|
||||||
|
unsigned_int: u32,
|
||||||
|
unsigned_long: u64,
|
||||||
|
unsigned_long_long: u64,
|
||||||
|
float: f32,
|
||||||
|
double: f64,
|
||||||
|
character: u8,
|
||||||
|
wide_character: i32,
|
||||||
|
};
|
||||||
63
packages/cjit/src/tokens/Keyword.zig
Normal file
63
packages/cjit/src/tokens/Keyword.zig
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const Keyword = enum {
|
||||||
|
_Alignas,
|
||||||
|
_Alignof,
|
||||||
|
_Atomic,
|
||||||
|
_Bool,
|
||||||
|
_Complex,
|
||||||
|
_Generic,
|
||||||
|
_Imaginary,
|
||||||
|
_Noreturn,
|
||||||
|
_Static_assert,
|
||||||
|
_Thread_local,
|
||||||
|
auto,
|
||||||
|
@"break",
|
||||||
|
case,
|
||||||
|
char,
|
||||||
|
@"const",
|
||||||
|
@"continue",
|
||||||
|
default,
|
||||||
|
do,
|
||||||
|
double,
|
||||||
|
@"else",
|
||||||
|
@"enum",
|
||||||
|
@"extern",
|
||||||
|
float,
|
||||||
|
@"for",
|
||||||
|
goto,
|
||||||
|
@"if",
|
||||||
|
@"inline",
|
||||||
|
int,
|
||||||
|
long,
|
||||||
|
register,
|
||||||
|
restrict,
|
||||||
|
@"return",
|
||||||
|
short,
|
||||||
|
signed,
|
||||||
|
sizeof,
|
||||||
|
static,
|
||||||
|
@"struct",
|
||||||
|
@"switch",
|
||||||
|
typedef,
|
||||||
|
@"union",
|
||||||
|
unsigned,
|
||||||
|
void,
|
||||||
|
@"volatile",
|
||||||
|
@"while",
|
||||||
|
|
||||||
|
pub const map: std.StaticStringMap(Keyword) = blk: {
|
||||||
|
const fields = @typeInfo(Keyword).@"enum".fields;
|
||||||
|
|
||||||
|
var kvs_list: [fields.len]struct { []const u8, Keyword } = undefined;
|
||||||
|
for (fields, 0..) |field, i| {
|
||||||
|
kvs_list[i] = .{ field.name, @field(Keyword, field.name) };
|
||||||
|
}
|
||||||
|
|
||||||
|
break :blk .initComptime(kvs_list);
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn isKeyword(identifier: []const u8) ?Keyword {
|
||||||
|
return map.get(identifier);
|
||||||
|
}
|
||||||
|
};
|
||||||
70
packages/cjit/src/tokens/Punctuator.zig
Normal file
70
packages/cjit/src/tokens/Punctuator.zig
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const Punctuator = enum(u32) {
|
||||||
|
// three characters
|
||||||
|
@"..." = strToInt3("..."),
|
||||||
|
@"<<=" = strToInt3("<<="),
|
||||||
|
@">>=" = strToInt3(">>="),
|
||||||
|
// two characters
|
||||||
|
@"--" = strToInt2("--"),
|
||||||
|
@"-=" = strToInt2("-="),
|
||||||
|
@"->" = strToInt2("->"),
|
||||||
|
@"!=" = strToInt2("!="),
|
||||||
|
@"*=" = strToInt2("*="),
|
||||||
|
@"/=" = strToInt2("/="),
|
||||||
|
@"&&" = strToInt2("&&"),
|
||||||
|
@"&=" = strToInt2("&="),
|
||||||
|
@"##" = strToInt2("##"),
|
||||||
|
@"%=" = strToInt2("%="),
|
||||||
|
@"^=" = strToInt2("^="),
|
||||||
|
@"++" = strToInt2("++"),
|
||||||
|
@"+=" = strToInt2("+="),
|
||||||
|
@"<<" = strToInt2("<<"),
|
||||||
|
@"<=" = strToInt2("<="),
|
||||||
|
@"==" = strToInt2("=="),
|
||||||
|
@">=" = strToInt2(">="),
|
||||||
|
@">>" = strToInt2(">>"),
|
||||||
|
@"|=" = strToInt2("|="),
|
||||||
|
@"||" = strToInt2("||"),
|
||||||
|
// single character
|
||||||
|
@"-" = strToInt1("-"),
|
||||||
|
@"," = strToInt1(","),
|
||||||
|
@";" = strToInt1(";"),
|
||||||
|
@":" = strToInt1(":"),
|
||||||
|
@"!" = strToInt1("!"),
|
||||||
|
@"?" = strToInt1("?"),
|
||||||
|
@"." = strToInt1("."),
|
||||||
|
@"(" = strToInt1("("),
|
||||||
|
@")" = strToInt1(")"),
|
||||||
|
@"[" = strToInt1("["),
|
||||||
|
@"]" = strToInt1("]"),
|
||||||
|
@"{" = strToInt1("{"),
|
||||||
|
@"}" = strToInt1("}"),
|
||||||
|
@"*" = strToInt1("*"),
|
||||||
|
@"/" = strToInt1("/"),
|
||||||
|
@"&" = strToInt1("&"),
|
||||||
|
@"#" = strToInt1("#"),
|
||||||
|
@"%" = strToInt1("%"),
|
||||||
|
@"^" = strToInt1("^"),
|
||||||
|
@"+" = strToInt1("+"),
|
||||||
|
@"<" = strToInt1("<"),
|
||||||
|
@"=" = strToInt1("="),
|
||||||
|
@">" = strToInt1(">"),
|
||||||
|
@"|" = strToInt1("|"),
|
||||||
|
@"~" = strToInt1("~"),
|
||||||
|
|
||||||
|
pub const line_continuation_lf = strToInt2("\\\n");
|
||||||
|
pub const line_continuation_crlf = strToInt3("\\\r\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
fn strToInt1(str: *const [1]u8) u32 {
|
||||||
|
return @as(u8, @bitCast(str.*));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strToInt2(str: *const [2]u8) u32 {
|
||||||
|
return @as(u16, @bitCast(str.*));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strToInt3(str: *const [3]u8) u32 {
|
||||||
|
return @as(u24, @bitCast(str.*));
|
||||||
|
}
|
||||||
16
packages/cjit/src/tokens/Token.zig
Normal file
16
packages/cjit/src/tokens/Token.zig
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Builtin = @import("Builtin.zig").Builtin;
|
||||||
|
const Constant = @import("Constant.zig").Constant;
|
||||||
|
const Keyword = @import("Keyword.zig").Keyword;
|
||||||
|
const Punctuator = @import("Punctuator.zig").Punctuator;
|
||||||
|
|
||||||
|
pub const Token = union(enum) {
|
||||||
|
builtin: Builtin,
|
||||||
|
constant: Constant,
|
||||||
|
keyword: Keyword,
|
||||||
|
punctuator: Punctuator,
|
||||||
|
identifier: []const u8,
|
||||||
|
string_literal: [:0]const u8,
|
||||||
|
wide_string_literal: [:0]const u32,
|
||||||
|
};
|
||||||
263
packages/cjit/src/tokens/Tokenizer.zig
Normal file
263
packages/cjit/src/tokens/Tokenizer.zig
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const Builtin = @import("Builtin.zig").Builtin;
|
||||||
|
const Keyword = @import("Keyword.zig").Keyword;
|
||||||
|
const Punctuator = @import("Punctuator.zig").Punctuator;
|
||||||
|
const Token = @import("Token.zig").Token;
|
||||||
|
const Utf8Iterator = @import("Utf8Iterator.zig");
|
||||||
|
|
||||||
|
pub const max_string_length = 4096;
|
||||||
|
pub const max_wide_string_length = 4096;
|
||||||
|
|
||||||
|
filename: []const u8 = &.{},
|
||||||
|
it: Utf8Iterator = .init(&.{}),
|
||||||
|
defines: std.StringHashMapUnmanaged([]Token) = .{},
|
||||||
|
/// Bounded, preallocated with the capacity of `max_string_length`.
|
||||||
|
string: std.ArrayList(u8),
|
||||||
|
/// Bounded, preallocated with the capacity of `max_wide_string_length`.
|
||||||
|
wide_string: std.ArrayList(u32),
|
||||||
|
|
||||||
|
pub fn init(arena_allocator: std.mem.Allocator) !Self {
|
||||||
|
const string_buffer = try arena_allocator.alloc(u8, max_string_length);
|
||||||
|
const wide_string_buffer = try arena_allocator.alloc(u32, max_wide_string_length);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.string = .initBuffer(string_buffer),
|
||||||
|
.wide_string = .initBuffer(wide_string_buffer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setSource(self: *Self, filename: []const u8, code: []const u8) void {
|
||||||
|
self.filename = filename;
|
||||||
|
self.it = .init(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nextToken(self: *Self, arena_allocator: std.mem.Allocator) !?Token {
|
||||||
|
try self.skipWhitespace();
|
||||||
|
|
||||||
|
// TODO Skip C and C++ style comments
|
||||||
|
// TODO Preprocessor directives
|
||||||
|
|
||||||
|
const cp = try self.peekCodepointSkipLineContinuation() orelse return null;
|
||||||
|
|
||||||
|
switch (cp) {
|
||||||
|
// Identifier start
|
||||||
|
'A'...'Z', '_', 'a'...'z', 128...std.math.maxInt(u21) => {
|
||||||
|
// This is an identifier, with the possible exception of:
|
||||||
|
// - wide string: L"
|
||||||
|
// - wide char: L'
|
||||||
|
// - any keyword
|
||||||
|
|
||||||
|
if (cp == 'L') {
|
||||||
|
const state = self.it.save();
|
||||||
|
|
||||||
|
self.it.advanceCodepoint(cp);
|
||||||
|
const cp2 = try self.peekCodepointSkipLineContinuation() orelse 0;
|
||||||
|
|
||||||
|
switch (cp2) {
|
||||||
|
// Wide string
|
||||||
|
'\"' => {
|
||||||
|
self.it.advanceCodepoint(cp2);
|
||||||
|
self.wide_string.clearRetainingCapacity();
|
||||||
|
// TODO Parse wide string
|
||||||
|
},
|
||||||
|
// Wide char
|
||||||
|
'\'' => {
|
||||||
|
self.it.advanceCodepoint(cp2);
|
||||||
|
// TODO Parse wide char
|
||||||
|
},
|
||||||
|
// Identifier or keyword
|
||||||
|
else => {
|
||||||
|
self.it.restore(state);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const identifier_start = self.it.ptr;
|
||||||
|
self.it.advanceCodepoint(cp);
|
||||||
|
|
||||||
|
var next_cp = try self.peekCodepointSkipLineContinuation();
|
||||||
|
while (next_cp != null and isIdentifierMiddle(next_cp.?)) {
|
||||||
|
self.it.advanceCodepoint(next_cp.?);
|
||||||
|
next_cp = try self.peekCodepointSkipLineContinuation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const identifier = self.it.str[identifier_start..self.it.ptr];
|
||||||
|
|
||||||
|
// TODO Preprocessor
|
||||||
|
|
||||||
|
if (Keyword.isKeyword(identifier)) |keyword| {
|
||||||
|
return .{ .keyword = keyword };
|
||||||
|
} else if (Builtin.isBuiltin(identifier)) |builtin| {
|
||||||
|
return .{ .builtin = builtin };
|
||||||
|
} else {
|
||||||
|
return .{ .identifier = try arena_allocator.dupe(u8, identifier) };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// String
|
||||||
|
'\"' => {
|
||||||
|
self.it.advanceCodepoint(cp);
|
||||||
|
self.string.clearRetainingCapacity();
|
||||||
|
// TODO Parse string
|
||||||
|
},
|
||||||
|
// Char
|
||||||
|
'\'' => {
|
||||||
|
self.it.advanceCodepoint(cp);
|
||||||
|
// TODO Parse char
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Higher code points should've been already handled. The code below may
|
||||||
|
// assume that `cp` is an ASCII character.
|
||||||
|
std.debug.assert(cp < 128);
|
||||||
|
|
||||||
|
// TODO Numeric constants
|
||||||
|
|
||||||
|
const cp3 = self.it.peekThreeBytes().?;
|
||||||
|
|
||||||
|
switch (cp3 & 0x00_FF_FF_FF) {
|
||||||
|
inline @intFromEnum(Punctuator.@"..."),
|
||||||
|
@intFromEnum(Punctuator.@"<<="),
|
||||||
|
@intFromEnum(Punctuator.@">>="),
|
||||||
|
=> |p| {
|
||||||
|
self.it.ptr += 3;
|
||||||
|
self.it.col += 3;
|
||||||
|
return .{
|
||||||
|
.punctuator = @enumFromInt(p),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cp3 & 0x00_00_FF_FF) {
|
||||||
|
inline @intFromEnum(Punctuator.@"--"),
|
||||||
|
@intFromEnum(Punctuator.@"-="),
|
||||||
|
@intFromEnum(Punctuator.@"->"),
|
||||||
|
@intFromEnum(Punctuator.@"!="),
|
||||||
|
@intFromEnum(Punctuator.@"*="),
|
||||||
|
@intFromEnum(Punctuator.@"/="),
|
||||||
|
@intFromEnum(Punctuator.@"&&"),
|
||||||
|
@intFromEnum(Punctuator.@"&="),
|
||||||
|
@intFromEnum(Punctuator.@"##"),
|
||||||
|
@intFromEnum(Punctuator.@"%="),
|
||||||
|
@intFromEnum(Punctuator.@"^="),
|
||||||
|
@intFromEnum(Punctuator.@"++"),
|
||||||
|
@intFromEnum(Punctuator.@"+="),
|
||||||
|
@intFromEnum(Punctuator.@"<<"),
|
||||||
|
@intFromEnum(Punctuator.@"<="),
|
||||||
|
@intFromEnum(Punctuator.@"=="),
|
||||||
|
@intFromEnum(Punctuator.@">="),
|
||||||
|
@intFromEnum(Punctuator.@">>"),
|
||||||
|
@intFromEnum(Punctuator.@"|="),
|
||||||
|
@intFromEnum(Punctuator.@"||"),
|
||||||
|
=> |p| {
|
||||||
|
self.it.ptr += 2;
|
||||||
|
self.it.col += 2;
|
||||||
|
return .{
|
||||||
|
.punctuator = @enumFromInt(p),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cp3 & 0x00_00_00_FF) {
|
||||||
|
inline @intFromEnum(Punctuator.@"-"),
|
||||||
|
@intFromEnum(Punctuator.@","),
|
||||||
|
@intFromEnum(Punctuator.@";"),
|
||||||
|
@intFromEnum(Punctuator.@":"),
|
||||||
|
@intFromEnum(Punctuator.@"!"),
|
||||||
|
@intFromEnum(Punctuator.@"?"),
|
||||||
|
@intFromEnum(Punctuator.@"."),
|
||||||
|
@intFromEnum(Punctuator.@"("),
|
||||||
|
@intFromEnum(Punctuator.@")"),
|
||||||
|
@intFromEnum(Punctuator.@"["),
|
||||||
|
@intFromEnum(Punctuator.@"]"),
|
||||||
|
@intFromEnum(Punctuator.@"{"),
|
||||||
|
@intFromEnum(Punctuator.@"}"),
|
||||||
|
@intFromEnum(Punctuator.@"*"),
|
||||||
|
@intFromEnum(Punctuator.@"/"),
|
||||||
|
@intFromEnum(Punctuator.@"&"),
|
||||||
|
@intFromEnum(Punctuator.@"#"),
|
||||||
|
@intFromEnum(Punctuator.@"%"),
|
||||||
|
@intFromEnum(Punctuator.@"^"),
|
||||||
|
@intFromEnum(Punctuator.@"+"),
|
||||||
|
@intFromEnum(Punctuator.@"<"),
|
||||||
|
@intFromEnum(Punctuator.@"="),
|
||||||
|
@intFromEnum(Punctuator.@">"),
|
||||||
|
@intFromEnum(Punctuator.@"|"),
|
||||||
|
@intFromEnum(Punctuator.@"~"),
|
||||||
|
=> |p| {
|
||||||
|
self.it.ptr += 1;
|
||||||
|
self.it.col += 1;
|
||||||
|
return .{
|
||||||
|
.punctuator = @enumFromInt(p),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.InvalidToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peekCodepointSkipLineContinuation(self: *Self) !?u21 {
|
||||||
|
while (self.skipLineContinuation()) {}
|
||||||
|
const cp = try self.it.peekCodepoint();
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Line continuation is defined as a backslash followed imediatelly by LF or
|
||||||
|
/// CRLF. Return whether a line continuation was encountered and therefore
|
||||||
|
/// skipped past.
|
||||||
|
fn skipLineContinuation(self: *Self) bool {
|
||||||
|
if (self.it.peekThreeBytes()) |b| {
|
||||||
|
@branchHint(.likely);
|
||||||
|
if (b & 0x00_00_FF_FF == Punctuator.line_continuation_lf) {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
self.it.ptr += 2;
|
||||||
|
self.it.line += 1;
|
||||||
|
self.it.col = 1;
|
||||||
|
return true;
|
||||||
|
} else if (b & 0x00_FF_FF_FF == Punctuator.line_continuation_crlf) {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
self.it.ptr += 3;
|
||||||
|
self.it.line += 1;
|
||||||
|
self.it.col = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skipWhitespace(self: *Self) !void {
|
||||||
|
while (try self.peekCodepointSkipLineContinuation()) |cp| {
|
||||||
|
switch (cp) {
|
||||||
|
// <Character Tabulation> (HT, TAB)
|
||||||
|
0x0009,
|
||||||
|
// <End of Line> (EOL, LF, NL)
|
||||||
|
0x000A,
|
||||||
|
// <Line Tabulation> (VT)
|
||||||
|
0x000B,
|
||||||
|
// <Form Feed> (FF)
|
||||||
|
0x000C,
|
||||||
|
// <Carriage Return> (CR)
|
||||||
|
0x000D,
|
||||||
|
// Space (SP)
|
||||||
|
0x0020,
|
||||||
|
=> self.it.advanceCodepoint(cp),
|
||||||
|
else => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isIdentifierMiddle(code_point: u21) bool {
|
||||||
|
// zig fmt: off
|
||||||
|
return code_point >= '0' and code_point <= '9'
|
||||||
|
or code_point >= 'A' and code_point <= 'Z'
|
||||||
|
or code_point == '_'
|
||||||
|
or code_point >= 'a' and code_point <= 'z'
|
||||||
|
or code_point >= 128;
|
||||||
|
// zig fmt: on
|
||||||
|
}
|
||||||
99
packages/cjit/src/tokens/Utf8Iterator.zig
Normal file
99
packages/cjit/src/tokens/Utf8Iterator.zig
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
str: []const u8,
|
||||||
|
ptr: usize,
|
||||||
|
line: usize,
|
||||||
|
col: usize,
|
||||||
|
|
||||||
|
pub const State = struct {
|
||||||
|
ptr: usize,
|
||||||
|
line: usize,
|
||||||
|
col: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(str: []const u8) Self {
|
||||||
|
return .{
|
||||||
|
.str = str,
|
||||||
|
.ptr = 0,
|
||||||
|
.line = 1,
|
||||||
|
.col = 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(self: Self) State {
|
||||||
|
return .{
|
||||||
|
.ptr = self.ptr,
|
||||||
|
.line = self.line,
|
||||||
|
.col = self.col,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn restore(self: *Self, state: State) void {
|
||||||
|
self.ptr = state.ptr;
|
||||||
|
self.line = state.line;
|
||||||
|
self.col = state.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peekByte(self: *Self) ?u8 {
|
||||||
|
if (self.ptr >= self.str.len) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.str[self.ptr];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peekCodepoint(self: Self) !?u21 {
|
||||||
|
if (self.ptr >= self.str.len) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cp_len = std.unicode.utf8ByteSequenceLength(self.str[self.ptr]) catch return error.InvalidUtf8;
|
||||||
|
if (self.ptr + cp_len > self.str.len) return error.InvalidUtf8;
|
||||||
|
|
||||||
|
const cp_slice = self.str[self.ptr .. self.ptr + cp_len];
|
||||||
|
const cp = std.unicode.utf8Decode(cp_slice) catch return error.InvalidUtf8;
|
||||||
|
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peekThreeBytes(self: Self) ?u32 {
|
||||||
|
var bytes: [3]u8 = .{ 0, 0, 0 };
|
||||||
|
|
||||||
|
const bytes_left = self.str.len - self.ptr;
|
||||||
|
sw: switch (bytes_left) {
|
||||||
|
0 => return null,
|
||||||
|
1 => {
|
||||||
|
bytes[0] = self.str[self.ptr];
|
||||||
|
return @as(u24, @bitCast(bytes));
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
bytes[1] = self.str[self.ptr + 1];
|
||||||
|
continue :sw 1;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
bytes[2] = self.str[self.ptr + 2];
|
||||||
|
continue :sw 2;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call with value returned by `peekCodepoint`.
|
||||||
|
pub fn advanceCodepoint(self: *Self, cp: u21) void {
|
||||||
|
std.debug.assert(blk: {
|
||||||
|
const actual_cp = self.peekCodepoint() catch break :blk false;
|
||||||
|
break :blk cp == actual_cp;
|
||||||
|
});
|
||||||
|
|
||||||
|
const cp_len = std.unicode.utf8CodepointSequenceLength(cp) catch unreachable;
|
||||||
|
|
||||||
|
self.ptr += cp_len;
|
||||||
|
|
||||||
|
if (cp == '\n') {
|
||||||
|
self.line += 1;
|
||||||
|
// NOTE Columns start as 1, it will be incremented below.
|
||||||
|
self.col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.col += 1;
|
||||||
|
}
|
||||||
201
packages/cjit/src/types.zig
Normal file
201
packages/cjit/src/types.zig
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const Type = union(enum) {
|
||||||
|
signed_char: void,
|
||||||
|
signed_short: void,
|
||||||
|
signed_int: void,
|
||||||
|
signed_long: void,
|
||||||
|
signed_long_long: void,
|
||||||
|
|
||||||
|
unsigned_char: void,
|
||||||
|
unsigned_short: void,
|
||||||
|
unsigned_int: void,
|
||||||
|
unsigned_long: void,
|
||||||
|
unsigned_long_long: void,
|
||||||
|
|
||||||
|
float: void,
|
||||||
|
double: void,
|
||||||
|
long_double: void,
|
||||||
|
|
||||||
|
void: void,
|
||||||
|
noreturn: void,
|
||||||
|
char: void,
|
||||||
|
bool: void,
|
||||||
|
|
||||||
|
@"enum": *const Enum,
|
||||||
|
@"struct": *const Struct,
|
||||||
|
@"union": *const Union,
|
||||||
|
array: *const Array,
|
||||||
|
function: *const Function,
|
||||||
|
pointer: *const Pointer,
|
||||||
|
|
||||||
|
pub fn sizeOf(self: Type) ?usize {
|
||||||
|
return switch (self) {
|
||||||
|
.signed_char => 1,
|
||||||
|
.signed_short => 2,
|
||||||
|
.signed_int => 4,
|
||||||
|
.signed_long => 8,
|
||||||
|
.signed_long_long => 8,
|
||||||
|
|
||||||
|
.unsigned_char => 1,
|
||||||
|
.unsigned_short => 2,
|
||||||
|
.unsigned_int => 4,
|
||||||
|
.unsigned_long => 8,
|
||||||
|
.unsigned_long_long => 8,
|
||||||
|
|
||||||
|
.float => 4,
|
||||||
|
.double => 8,
|
||||||
|
.long_double => 8,
|
||||||
|
|
||||||
|
.void => null,
|
||||||
|
.noreturn => null,
|
||||||
|
.char => 1,
|
||||||
|
.bool => 1,
|
||||||
|
|
||||||
|
.@"enum" => 4,
|
||||||
|
.@"struct" => |s| s.size,
|
||||||
|
.@"union" => |u| u.size,
|
||||||
|
.array => |a| if (a.length) |l| (if (sizeOf(a.child)) |c| l * c else null) else 8,
|
||||||
|
.function => null,
|
||||||
|
.pointer => 8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alignOf(self: Type) ?u16 {
|
||||||
|
return switch (self) {
|
||||||
|
.signed_char => 1,
|
||||||
|
.signed_short => 2,
|
||||||
|
.signed_int => 4,
|
||||||
|
.signed_long => 8,
|
||||||
|
.signed_long_long => 8,
|
||||||
|
|
||||||
|
.unsigned_char => 1,
|
||||||
|
.unsigned_short => 2,
|
||||||
|
.unsigned_int => 4,
|
||||||
|
.unsigned_long => 8,
|
||||||
|
.unsigned_long_long => 8,
|
||||||
|
|
||||||
|
.float => 4,
|
||||||
|
.double => 8,
|
||||||
|
.long_double => 8,
|
||||||
|
|
||||||
|
.void => null,
|
||||||
|
.noreturn => null,
|
||||||
|
.char => 1,
|
||||||
|
.bool => 1,
|
||||||
|
|
||||||
|
.@"enum" => 4,
|
||||||
|
.@"struct" => |s| s.@"align",
|
||||||
|
.@"union" => |u| u.@"align",
|
||||||
|
.array => |a| if (a.length != null) alignOf(a.child) else 8,
|
||||||
|
.function => null,
|
||||||
|
.pointer => 8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Enum = struct {
|
||||||
|
name: []const u8,
|
||||||
|
constants: []const EnumConstant,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const EnumConstant = struct {
|
||||||
|
name: []const u8,
|
||||||
|
value: i32,
|
||||||
|
inferred: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Struct = struct {
|
||||||
|
name: []const u8,
|
||||||
|
fields: []const StructField,
|
||||||
|
size: usize,
|
||||||
|
@"align": u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const StructField = struct {
|
||||||
|
name: []const u8,
|
||||||
|
type: Type,
|
||||||
|
offset: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Union = struct {
|
||||||
|
name: []const u8,
|
||||||
|
fields: []const UnionField,
|
||||||
|
size: usize,
|
||||||
|
@"align": u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const UnionField = struct {
|
||||||
|
name: []const u8,
|
||||||
|
type: Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Array = struct {
|
||||||
|
child: Type,
|
||||||
|
length: ?usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Function = struct {
|
||||||
|
arguments: []const FunctionArgument,
|
||||||
|
@"return": Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const FunctionArgument = struct {
|
||||||
|
name: []const u8,
|
||||||
|
type: Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Pointer = struct {
|
||||||
|
child: Type,
|
||||||
|
@"const": bool,
|
||||||
|
@"volatile": bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn isCompatible(comptime ZigType: type, c_type: Type) bool {
|
||||||
|
return switch (@typeInfo(ZigType)) {
|
||||||
|
.type => false,
|
||||||
|
.void => c_type == .void,
|
||||||
|
.bool => c_type == .bool,
|
||||||
|
.noreturn => c_type == .noreturn,
|
||||||
|
.int => |zig_int| switch (c_type) {
|
||||||
|
.signed_char => zig_int.signedness == .signed and zig_int.bits == 8,
|
||||||
|
.signed_short => zig_int.signedness == .signed and zig_int.bits == 16,
|
||||||
|
.signed_int => zig_int.signedness == .signed and zig_int.bits == 32,
|
||||||
|
.signed_long => zig_int.signedness == .signed and zig_int.bits == 64,
|
||||||
|
.signed_long_long => zig_int.signedness == .signed and zig_int.bits == 64,
|
||||||
|
|
||||||
|
.unsigned_char => zig_int.signedness == .unsigned and zig_int.bits == 8,
|
||||||
|
.unsigned_short => zig_int.signedness == .unsigned and zig_int.bits == 16,
|
||||||
|
.unsigned_int => zig_int.signedness == .unsigned and zig_int.bits == 32,
|
||||||
|
.unsigned_long => zig_int.signedness == .unsigned and zig_int.bits == 64,
|
||||||
|
.unsigned_long_long => zig_int.signedness == .unsigned and zig_int.bits == 64,
|
||||||
|
|
||||||
|
.char => zig_int.bits = 8,
|
||||||
|
|
||||||
|
else => false,
|
||||||
|
},
|
||||||
|
.float => |zig_float| switch (c_type) {
|
||||||
|
.float => zig_float.bits = 32,
|
||||||
|
.double => zig_float.bits = 64,
|
||||||
|
.long_double => zig_float.bits = 64,
|
||||||
|
},
|
||||||
|
.pointer => @compileError("TODO"),
|
||||||
|
.array => @compileError("TODO"),
|
||||||
|
.@"struct" => @compileError("TODO"),
|
||||||
|
.comptime_float => false,
|
||||||
|
.comptime_int => false,
|
||||||
|
.undefined => true,
|
||||||
|
.null => @compileError("TODO"),
|
||||||
|
.optional => @compileError("TODO"),
|
||||||
|
.error_union => false,
|
||||||
|
.error_set => false,
|
||||||
|
.@"enum" => @compileError("TODO"),
|
||||||
|
.@"union" => @compileError("TODO"),
|
||||||
|
.@"fn" => false,
|
||||||
|
.@"opaque" => @compileError("TODO"),
|
||||||
|
.frame => false,
|
||||||
|
.@"anyframe" => false,
|
||||||
|
.vector => false,
|
||||||
|
.enum_literal => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
445
packages/cjit/src/x86_64.zig
Normal file
445
packages/cjit/src/x86_64.zig
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const tokens = @import("tokens.zig");
|
||||||
|
const types = @import("types.zig");
|
||||||
|
|
||||||
|
const Location = Runtime.Location;
|
||||||
|
const Runtime = @import("Runtime.zig");
|
||||||
|
const StackValue = @import("StackValue.zig");
|
||||||
|
const Type = types.Type;
|
||||||
|
|
||||||
|
pub const Register = union(enum) {
|
||||||
|
gpr: Gpr,
|
||||||
|
xmm: Xmm,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Gpr = enum(u4) {
|
||||||
|
rax = 0,
|
||||||
|
rcx = 1,
|
||||||
|
rdx = 2,
|
||||||
|
rbx = 3,
|
||||||
|
rsp = 4,
|
||||||
|
rbp = 5,
|
||||||
|
rsi = 6,
|
||||||
|
rdi = 7,
|
||||||
|
r8 = 8,
|
||||||
|
r9 = 9,
|
||||||
|
r10 = 10,
|
||||||
|
r11 = 11,
|
||||||
|
r12 = 12,
|
||||||
|
r13 = 13,
|
||||||
|
r14 = 14,
|
||||||
|
r15 = 15,
|
||||||
|
|
||||||
|
pub fn reg(self: Gpr) u3 {
|
||||||
|
return @truncate(@intFromEnum(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn x(self: Gpr) bool {
|
||||||
|
return @intFromEnum(self) & 0b1000 != 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Xmm = enum(u4) {
|
||||||
|
xmm0 = 0,
|
||||||
|
xmm1 = 1,
|
||||||
|
xmm2 = 2,
|
||||||
|
xmm3 = 3,
|
||||||
|
xmm4 = 4,
|
||||||
|
xmm5 = 5,
|
||||||
|
xmm6 = 6,
|
||||||
|
xmm7 = 7,
|
||||||
|
xmm8 = 8,
|
||||||
|
xmm9 = 9,
|
||||||
|
xmm10 = 10,
|
||||||
|
xmm11 = 11,
|
||||||
|
xmm12 = 12,
|
||||||
|
xmm13 = 13,
|
||||||
|
xmm14 = 14,
|
||||||
|
xmm15 = 15,
|
||||||
|
|
||||||
|
pub fn reg(self: Xmm) u3 {
|
||||||
|
return @truncate(@intFromEnum(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn x(self: Xmm) bool {
|
||||||
|
return @intFromEnum(self) & 0b1000 != 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- EMIT HELPERS ------------------------------------------------------------
|
||||||
|
|
||||||
|
pub const Rex = packed struct(u8) {
|
||||||
|
b: bool = false,
|
||||||
|
x: bool = false,
|
||||||
|
r: bool = false,
|
||||||
|
w: bool = false,
|
||||||
|
/// MUST always be the default value
|
||||||
|
prefix: u4 = 0b0100,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ModRM = packed struct(u8) {
|
||||||
|
rm: u3,
|
||||||
|
reg: u3,
|
||||||
|
mod: u2,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SIB = packed struct(u8) {
|
||||||
|
base: u3,
|
||||||
|
index: u3,
|
||||||
|
scale: u2,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn op16(rt: *Runtime) !void {
|
||||||
|
try rt.sections.text.writeByte(0x66, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rex(rt: *Runtime, value: Rex) !void {
|
||||||
|
try rt.sections.text.writeByte(@bitCast(value), rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op(rt: *Runtime, value: u8) !void {
|
||||||
|
try rt.sections.text.writeByte(value, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op2(rt: *Runtime, v0: u8, v1: u8) !void {
|
||||||
|
const bytes: [2]u8 = .{ v0, v1 };
|
||||||
|
try rt.sections.text.writeBytes(&bytes, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn op3(rt: *Runtime, v0: u8, v1: u8, v2: u8) !void {
|
||||||
|
const bytes: [3]u8 = .{ v0, v1, v2 };
|
||||||
|
try rt.sections.text.writeBytes(&bytes, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn modrm(rt: *Runtime, value: ModRM) !void {
|
||||||
|
try rt.sections.text.writeByte(@bitCast(value), rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sib(rt: *Runtime, value: SIB) !void {
|
||||||
|
try rt.sections.text.writeByte(@bitCast(value), rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn imm8(rt: *Runtime, value: u8) !void {
|
||||||
|
try rt.sections.text.writeByte(value, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn imm16(rt: *Runtime, value: u16) !void {
|
||||||
|
var bytes: [2]u8 = undefined;
|
||||||
|
std.mem.writeInt(u16, &bytes, value, .little);
|
||||||
|
try rt.sections.text.writeBytes(&bytes, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn imm32(rt: *Runtime, value: u32) !void {
|
||||||
|
var bytes: [4]u8 = undefined;
|
||||||
|
std.mem.writeInt(u32, &bytes, value, .little);
|
||||||
|
try rt.sections.text.writeBytes(&bytes, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn imm64(rt: *Runtime, value: u64) !void {
|
||||||
|
var bytes: [8]u8 = undefined;
|
||||||
|
std.mem.writeInt(u64, &bytes, value, .little);
|
||||||
|
try rt.sections.text.writeBytes(&bytes, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disp8(rt: *Runtime, value: i8) !void {
|
||||||
|
try rt.sections.text.writeByte(@bitCast(value), rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disp32(rt: *Runtime, value: i32) !void {
|
||||||
|
var bytes: [4]u8 = undefined;
|
||||||
|
std.mem.writeInt(i32, &bytes, value, .little);
|
||||||
|
try rt.sections.text.writeBytes(&bytes, rt.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub const Operation = enum {
|
||||||
|
add,
|
||||||
|
bit_and,
|
||||||
|
bit_not,
|
||||||
|
bit_or,
|
||||||
|
bit_xor,
|
||||||
|
bool_and,
|
||||||
|
bool_not,
|
||||||
|
bool_or,
|
||||||
|
cmp_eq,
|
||||||
|
cmp_gt,
|
||||||
|
cmp_gte,
|
||||||
|
cmp_lt,
|
||||||
|
cmp_lte,
|
||||||
|
cmp_neq,
|
||||||
|
div,
|
||||||
|
mod,
|
||||||
|
mul,
|
||||||
|
neg,
|
||||||
|
sar,
|
||||||
|
shl,
|
||||||
|
shr,
|
||||||
|
sub,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn opFloat(rt: *Runtime, operation: Operation) !void {
|
||||||
|
_ = rt;
|
||||||
|
_ = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opInt(rt: *Runtime, operation: Operation) !void {
|
||||||
|
_ = rt;
|
||||||
|
_ = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cvtIntToFloat(rt: *Runtime) !void {
|
||||||
|
_ = rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cvtFloatToInt(rt: *Runtime) !void {
|
||||||
|
_ = rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cvtFloatToFloat(rt: *Runtime, target: Type) !void {
|
||||||
|
const top = vsTop(rt);
|
||||||
|
|
||||||
|
switch (top.c_type) {
|
||||||
|
.float => switch (target) {
|
||||||
|
.float => {
|
||||||
|
// do nothing
|
||||||
|
},
|
||||||
|
.double, .long_double => {
|
||||||
|
// CVTSS2SD xmm1, xmm2/m32
|
||||||
|
// F3 0F 5A /r
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.double, .long_double => switch (target) {
|
||||||
|
.float => {
|
||||||
|
// CVTSD2SS xmm1, xmm2/m64
|
||||||
|
// F2 0F 5A /r
|
||||||
|
},
|
||||||
|
.double, .long_double => {
|
||||||
|
// do nothing
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- LOAD AND STORE ----------------------------------------------------------
|
||||||
|
|
||||||
|
/// Load value into register. The value must be 1, 2, 4 or 8 bytes long.
|
||||||
|
pub fn load(rt: *Runtime, dst_register: Register, src_value: *const StackValue) !void {
|
||||||
|
const size = src_value.c_type.sizeOf().?;
|
||||||
|
std.debug.assert(size == 1 or size == 2 or size == 4 or size == 8);
|
||||||
|
|
||||||
|
switch (src_value.value) {
|
||||||
|
.register => |src_register| {
|
||||||
|
if (std.meta.eql(dst_register, src_register)) return;
|
||||||
|
// TODO
|
||||||
|
},
|
||||||
|
.constant => |constant| switch (dst_register) {
|
||||||
|
.gpr => |dest_gpr| switch (size) {
|
||||||
|
1 => {
|
||||||
|
// MOV r8, imm8
|
||||||
|
// B0+ rb ib
|
||||||
|
if (@intFromEnum(dest_gpr) >= 4) {
|
||||||
|
// NOTE spl, bpl, sil and dil need an empty REX prefix,
|
||||||
|
// otherwise ah, ch, dh and bh would be used.
|
||||||
|
try rex(rt, .{ .r = dest_gpr.x() });
|
||||||
|
}
|
||||||
|
try op(rt, 0xB0 | @as(u8, dest_gpr.reg()));
|
||||||
|
try imm8(rt, @truncate(constant));
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
// MOV r16, imm16
|
||||||
|
// B8+ rw iw
|
||||||
|
try op16(rt);
|
||||||
|
if (@intFromEnum(dest_gpr) >= 8) {
|
||||||
|
try rex(rt, .{ .r = dest_gpr.x() });
|
||||||
|
}
|
||||||
|
try op(rt, 0xB8 | @as(u8, dest_gpr.reg()));
|
||||||
|
try imm16(rt, @truncate(constant));
|
||||||
|
},
|
||||||
|
4 => {
|
||||||
|
// MOV r32, imm32
|
||||||
|
// B8+ rd id
|
||||||
|
if (@intFromEnum(dest_gpr) >= 8) {
|
||||||
|
try rex(rt, .{ .r = dest_gpr.x() });
|
||||||
|
}
|
||||||
|
try op(rt, 0xB8 | @as(u8, dest_gpr.reg()));
|
||||||
|
try imm32(rt, @truncate(constant));
|
||||||
|
},
|
||||||
|
8 => {
|
||||||
|
// MOV r64, imm64
|
||||||
|
// REX.W + B8+ rd io
|
||||||
|
try rex(rt, .{ .r = dest_gpr.x(), .w = true });
|
||||||
|
try op(rt, 0xB8 | @as(u8, dest_gpr.reg()));
|
||||||
|
try imm64(rt, constant);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.xmm => |dest_xmm| {
|
||||||
|
var bytes: [8]u8 = undefined;
|
||||||
|
std.mem.writeInt(u64, &bytes, @truncate(constant), .little);
|
||||||
|
const data = bytes[0..size];
|
||||||
|
|
||||||
|
// MOVD xmm, r/m32
|
||||||
|
// 66 0F 6E /r
|
||||||
|
|
||||||
|
// MOVQ xmm, r/m64
|
||||||
|
// 66 REX.W 0F 6E /r
|
||||||
|
|
||||||
|
try op(rt, 0x66);
|
||||||
|
if (@intFromEnum(dest_xmm) >= 8 or size == 8) {
|
||||||
|
try rex(rt, .{ .r = dest_xmm.x(), .w = size == 8 });
|
||||||
|
}
|
||||||
|
try op2(rt, 0x0F, 0x6E);
|
||||||
|
// [rip + disp32]
|
||||||
|
try modrm(rt, .{ .mod = 0b00, .reg = dest_xmm.reg(), .rm = Gpr.rbp.reg() });
|
||||||
|
try allocRodataDisp32(rt, data);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.symbol => |symbol| {},
|
||||||
|
.stack => |disp| {
|
||||||
|
const disp_small = std.math.minInt(i8) <= disp and disp <= std.math.maxInt(i8);
|
||||||
|
const rex_prefix: Rex = .{
|
||||||
|
.r = switch (dst_register) {
|
||||||
|
.gpr => |dest_gpr| dest_gpr.x(),
|
||||||
|
.xmm => |dest_xmm| dest_xmm.x(),
|
||||||
|
},
|
||||||
|
.w = size == 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mod: u2 = if (disp_small) 0b01 else 0b10;
|
||||||
|
const reg: u3 = switch (dst_register) {
|
||||||
|
.gpr => |dest_gpr| dest_gpr.reg(),
|
||||||
|
.xmm => |dest_xmm| dest_xmm.reg(),
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (dst_register) {
|
||||||
|
.gpr => |dest_gpr| {
|
||||||
|
switch (size) {
|
||||||
|
1 => {
|
||||||
|
// MOV r8, r/m8
|
||||||
|
// 8A /r
|
||||||
|
if (@intFromEnum(dest_gpr) >= 4) {
|
||||||
|
// NOTE spl, bpl, sil and dil need an empty REX prefix,
|
||||||
|
// otherwise ah, ch, dh and bh would be used.
|
||||||
|
try rex(rt, rex_prefix);
|
||||||
|
}
|
||||||
|
try op(rt, 0x8A);
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
// MOV r16, r/m16
|
||||||
|
// 8B /r
|
||||||
|
try op16(rt);
|
||||||
|
if (@intFromEnum(dest_gpr) >= 8) {
|
||||||
|
try rex(rt, rex_prefix);
|
||||||
|
}
|
||||||
|
try op(rt, 0x8B);
|
||||||
|
},
|
||||||
|
4 => {
|
||||||
|
// MOV r32, r/m32
|
||||||
|
// 8B /r
|
||||||
|
if (@intFromEnum(dest_gpr) >= 8) {
|
||||||
|
try rex(rt, rex_prefix);
|
||||||
|
}
|
||||||
|
try op(rt, 0x8B);
|
||||||
|
},
|
||||||
|
8 => {
|
||||||
|
// MOV r64, r/m64
|
||||||
|
// REX.W + 8B /r
|
||||||
|
try rex(rt, rex_prefix);
|
||||||
|
try op(rt, 0x8B);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.xmm => |dest_xmm| {
|
||||||
|
// MOVD xmm, r/m32
|
||||||
|
// 66 0F 6E /r
|
||||||
|
|
||||||
|
// MOVQ xmm, r/m64
|
||||||
|
// 66 REX.W 0F 6E /r
|
||||||
|
|
||||||
|
try op(rt, 0x66);
|
||||||
|
if (@intFromEnum(dest_xmm) >= 8 or size == 8) {
|
||||||
|
try rex(rt, rex_prefix);
|
||||||
|
}
|
||||||
|
try op2(rt, 0x0F, 0x6E);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// [rbp + disp8/32]
|
||||||
|
try modrm(rt, .{ .mod = mod, .reg = reg, .rm = Gpr.rbp.reg() });
|
||||||
|
if (disp_small) {
|
||||||
|
try disp8(rt, @intCast(disp));
|
||||||
|
} else {
|
||||||
|
try disp32(rt, disp);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.cpu_flags => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Store register into value.
|
||||||
|
pub fn store(rt: *Runtime, dst_value: *const StackValue, src_register: Register) !void {
|
||||||
|
const size = dst_value.c_type.sizeOf().?;
|
||||||
|
std.debug.assert(size == 1 or size == 2 or size == 4 or size == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- STACK OPERATIONS --------------------------------------------------------
|
||||||
|
|
||||||
|
/// Caller asserts that the stack is not empty.
|
||||||
|
pub fn vsTop(rt: *Runtime) *StackValue {
|
||||||
|
const vs = rt.virtual_stack.items;
|
||||||
|
return &vs[vs.len - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Caller asserts that the stack has at least two values.
|
||||||
|
pub fn vsSwap(rt: *Runtime) void {
|
||||||
|
const vs = rt.virtual_stack.items;
|
||||||
|
std.mem.swap(StackValue, &vs[vs.len - 1], &vs[vs.len - 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure the top of the stack is in an XMM register. Returns the id of the
|
||||||
|
/// register. Caller asserts that the stack is not empty.
|
||||||
|
pub fn vsEnsureXmm(rt: *Runtime) Xmm {
|
||||||
|
const top = vsTop(rt);
|
||||||
|
switch (top.value) {
|
||||||
|
.register => {},
|
||||||
|
.constant => {},
|
||||||
|
.symbol => {},
|
||||||
|
.stack => {},
|
||||||
|
.cpu_flags => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure the top of the stack is in a GPR register. Returns the id of the
|
||||||
|
/// register. Caller asserts that teh stack is not empty.
|
||||||
|
pub fn vsEnsureGpr(rt: *Runtime) Gpr {
|
||||||
|
const top = vsTop(rt);
|
||||||
|
switch (top.value) {
|
||||||
|
.register => {},
|
||||||
|
.constant => {},
|
||||||
|
.symbol => {},
|
||||||
|
.stack => {},
|
||||||
|
.cpu_flags => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- DATA ALLOCATIONS --------------------------------------------------------
|
||||||
|
|
||||||
|
/// Reserve `data.len` bytes in rodata and fill it with `data`, then add a
|
||||||
|
/// placeholder dips32 part of an instruction and a relocation entry for it.
|
||||||
|
pub fn allocRodataDisp32(rt: *Runtime, data: []const u8) !void {
|
||||||
|
const addr = rt.sections.text.data.items.len;
|
||||||
|
const location: Location = .{ .rodata = rt.sections.rodata.data.items.len };
|
||||||
|
|
||||||
|
try rt.sections.rodata.writeBytes(data, rt.allocator);
|
||||||
|
try disp32(rt, 0);
|
||||||
|
try rt.relocation_table.append(rt.allocator, .{
|
||||||
|
.addr = addr,
|
||||||
|
.location = location,
|
||||||
|
.type = .rip_disp32,
|
||||||
|
});
|
||||||
|
}
|
||||||
32
packages/cjit/test/root.zig
Normal file
32
packages/cjit/test/root.zig
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const cjit = @import("cjit");
|
||||||
|
|
||||||
|
fn add(a: i32, b: i32) callconv(cjit.call) i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
var rt: cjit.Runtime = try .init(std.testing.allocator);
|
||||||
|
defer rt.deinit();
|
||||||
|
|
||||||
|
try rt.compile("test.c",
|
||||||
|
\\int add(int a, int b);
|
||||||
|
\\
|
||||||
|
\\int add_one(int x)
|
||||||
|
\\{
|
||||||
|
\\ return add(x, 1);
|
||||||
|
\\}
|
||||||
|
);
|
||||||
|
|
||||||
|
try rt.setSymbol(fn (i32, i32) callconv(cjit.call) i32, "add", &add);
|
||||||
|
try rt.link();
|
||||||
|
|
||||||
|
const add_one = rt.getSymbol(fn (i32) callconv(cjit.call) i32, "add_one").?;
|
||||||
|
|
||||||
|
try std.testing.expectEqual(-9, add_one(-10));
|
||||||
|
try std.testing.expectEqual(11, add_one(10));
|
||||||
|
|
||||||
|
const add_ptr = rt.getSymbol(fn (i32, i32) callconv(cjit.call) i32, "add").?;
|
||||||
|
|
||||||
|
try std.testing.expectEqual(add_ptr, &add);
|
||||||
|
}
|
||||||
@@ -6,6 +6,18 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
const root_module = b.addModule("media", .{
|
const root_module = b.addModule("media", .{
|
||||||
.root_source_file = b.path("src/root.zig"),
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
.link_libc = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
root_module.addCSourceFile(.{
|
||||||
|
.file = b.path("src/stbi/stb_image.c"),
|
||||||
|
.flags = &.{
|
||||||
|
"-std=c17",
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
},
|
||||||
|
.language = .c,
|
||||||
|
});
|
||||||
|
|
||||||
root_module.addImport("vecmath", vm_module);
|
root_module.addImport("vecmath", vm_module);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,3 +66,46 @@ pub const Dynamic = struct {
|
|||||||
@memset(self.data[0 .. self.width * self.height], color);
|
@memset(self.data[0 .. self.width * self.height], color);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Hdr = struct {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
|
||||||
|
data: [*]vm.ColorHdr,
|
||||||
|
|
||||||
|
pub fn initBuffer(width: u32, height: u32, buffer: []vm.ColorHdr) @This() {
|
||||||
|
std.debug.assert(buffer.len == width * height);
|
||||||
|
return .{
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.data = buffer.ptr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initAlloc(width: u32, height: u32, allocator: std.mem.Allocator) !@This() {
|
||||||
|
const buffer = try allocator.alloc(vm.ColorHdr, width * height);
|
||||||
|
return .{
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.data = buffer.ptr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
|
||||||
|
allocator.free(self.data[0 .. self.width * self.height]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getPixel(self: *const @This(), x: u32, y: u32) vm.ColorHdr {
|
||||||
|
std.debug.assert(x < self.width and y < self.height);
|
||||||
|
return self.data[y * self.width + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setPixel(self: *@This(), x: u32, y: u32, color: vm.ColorHdr) void {
|
||||||
|
std.debug.assert(x < self.width and y < self.height);
|
||||||
|
self.data[y * self.width + x] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill(self: *@This(), color: vm.ColorHdr) void {
|
||||||
|
@memset(self.data[0 .. self.width * self.height], color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ pub const audio = @import("audio.zig");
|
|||||||
pub const image = @import("image.zig");
|
pub const image = @import("image.zig");
|
||||||
pub const qoa = @import("qoa.zig");
|
pub const qoa = @import("qoa.zig");
|
||||||
pub const qoi = @import("qoi.zig");
|
pub const qoi = @import("qoi.zig");
|
||||||
|
pub const stbi = @import("stbi.zig");
|
||||||
|
|||||||
303
packages/media/src/stbi.zig
Normal file
303
packages/media/src/stbi.zig
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const image = @import("image.zig");
|
||||||
|
const vm = @import("vecmath");
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
allocations: std.AutoHashMapUnmanaged(*anyopaque, usize) = .empty,
|
||||||
|
mutex: std.Thread.Mutex = .{},
|
||||||
|
allocated_bytes: usize = 0,
|
||||||
|
|
||||||
|
const alignment: std.mem.Alignment = .@"16";
|
||||||
|
const VoidPtr = ?*align(alignment.toByteUnits()) anyopaque;
|
||||||
|
const log = std.log.scoped(.stbi);
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) Self {
|
||||||
|
return .{
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
std.log.scoped(.deinit).debug("Deinitializing {*}", .{self});
|
||||||
|
if (self.allocated_bytes > 0) {
|
||||||
|
log.warn("{d} byte(s) still allocated while deinitializing", .{self.allocated_bytes});
|
||||||
|
}
|
||||||
|
if (self.allocations.size > 0) {
|
||||||
|
log.warn("{d} allocation(s) still tracked while deinitializing", .{self.allocations.size});
|
||||||
|
var it = self.allocations.iterator();
|
||||||
|
var index: usize = 0;
|
||||||
|
while (it.next()) |entry| : (index += 1) {
|
||||||
|
log.warn("Leaked allocation ({d}/{d}) at 0x{x} of {d} byte(s)", .{
|
||||||
|
index + 1,
|
||||||
|
self.allocations.size,
|
||||||
|
@intFromPtr(entry.key_ptr.*),
|
||||||
|
entry.value_ptr.*,
|
||||||
|
});
|
||||||
|
const memory = @as([*]align(alignment.toByteUnits()) u8, @ptrCast(@alignCast(entry.key_ptr.*)))[0..entry.value_ptr.*];
|
||||||
|
self.allocator.free(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocations.deinit(self.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
const import = struct {
|
||||||
|
extern fn stbi_load_from_memory(buffer: [*]const u8, len: i32, x: ?*i32, y: ?*i32, channels_in_file: ?*i32, desired_channels: i32) ?[*]align(alignment.toByteUnits()) u8;
|
||||||
|
extern fn stbi_load_16_from_memory(buffer: [*]const u8, len: i32, x: ?*i32, y: ?*i32, channels_in_file: ?*i32, desired_channels: i32) ?[*]align(alignment.toByteUnits()) u16;
|
||||||
|
extern fn stbi_loadf_from_memory(buffer: [*]const u8, len: i32, x: ?*i32, y: ?*i32, channels_in_file: ?*i32, desired_channels: i32) ?[*]align(alignment.toByteUnits()) f32;
|
||||||
|
|
||||||
|
extern fn stbi_load_from_callbacks(callbacks: *const IoCallbacks, ctx: ?*anyopaque, x: ?*i32, y: ?*i32, channels_in_file: ?*i32, desired_channels: i32) ?[*]align(alignment.toByteUnits()) u8;
|
||||||
|
extern fn stbi_load_16_from_callbacks(callbacks: *const IoCallbacks, ctx: ?*anyopaque, x: ?*i32, y: ?*i32, channels_in_file: ?*i32, desired_channels: i32) ?[*]align(alignment.toByteUnits()) u16;
|
||||||
|
extern fn stbi_loadf_from_callbacks(callbacks: *const IoCallbacks, ctx: ?*anyopaque, x: ?*i32, y: ?*i32, channels_in_file: ?*i32, desired_channels: i32) ?[*]align(alignment.toByteUnits()) f32;
|
||||||
|
|
||||||
|
extern fn stbi_info_from_memory(buffer: [*]const u8, len: i32, x: ?*i32, y: ?*i32, channels_in_file: ?*i32) i32;
|
||||||
|
extern fn stbi_is_16_bit_from_memory(buffer: [*]const u8, len: i32) i32;
|
||||||
|
extern fn stbi_is_hdr_from_memory(buffer: [*]const u8, len: i32) i32;
|
||||||
|
|
||||||
|
extern fn stbi_info_from_callbacks(callbacks: *const IoCallbacks, ctx: ?*anyopaque, x: ?*i32, y: ?*i32, channels_in_file: ?*i32) i32;
|
||||||
|
extern fn stbi_is_16_bit_from_callbacks(callbacks: *const IoCallbacks, ctx: ?*anyopaque) i32;
|
||||||
|
extern fn stbi_is_hdr_from_callbacks(callbacks: *const IoCallbacks, ctx: ?*anyopaque) i32;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn loadStaticBuf(self: *Self, comptime W: u32, comptime H: u32, buf: []const u8) !image.Static(W, H) {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
|
||||||
|
const res = import.stbi_load_from_memory(buf.ptr, @intCast(buf.len), &x, &y, null, 4) orelse return error.StbiError;
|
||||||
|
defer castle_media_stbi_free(res);
|
||||||
|
|
||||||
|
if (x != W or y != H) return error.WrongDimensions;
|
||||||
|
|
||||||
|
return .{ .data = @as(*const [W * H]vm.Color, @ptrCast(@alignCast(res))).* };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadStaticIo(self: *Self, comptime W: u32, comptime H: u32, reader: *std.io.Reader) !image.Static(W, H) {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
|
||||||
|
const res = import.stbi_load_from_callbacks(&.std_io_reader_interface, reader, &x, &y, null, 4) orelse return error.StbiError;
|
||||||
|
defer castle_media_stbi_free(res);
|
||||||
|
|
||||||
|
if (x != W or y != H) return error.WrongDimensions;
|
||||||
|
|
||||||
|
return .{ .data = @as(*const [W * H]vm.Color, @ptrCast(@alignCast(res))).* };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// On success, must free memory by calling `freeDynamic` method.
|
||||||
|
pub fn loadDynamicBuf(self: *Self, buf: []const u8) !image.Dynamic {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
|
||||||
|
const res = import.stbi_load_from_memory(buf.ptr, @intCast(buf.len), &x, &y, null, 4) orelse return error.StbiError;
|
||||||
|
|
||||||
|
const buffer_ptr: [*]vm.Color = @ptrCast(@alignCast(res));
|
||||||
|
const ux: u32 = @intCast(x);
|
||||||
|
const uy: u32 = @intCast(y);
|
||||||
|
|
||||||
|
return .initBuffer(ux, uy, buffer_ptr[0 .. ux * uy]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// On success, must free memory by calling `freeDynamic` method.
|
||||||
|
pub fn loadDynamicIo(self: *Self, reader: *std.io.Reader) !image.Dynamic {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
|
||||||
|
const res = import.stbi_load_from_callbacks(&.std_io_reader_interface, reader, &x, &y, null, 4) orelse return error.StbiError;
|
||||||
|
|
||||||
|
const buffer_ptr: [*]vm.Color = @ptrCast(@alignCast(res));
|
||||||
|
const ux: u32 = @intCast(x);
|
||||||
|
const uy: u32 = @intCast(y);
|
||||||
|
|
||||||
|
return .initBuffer(ux, uy, buffer_ptr[0 .. ux * uy]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// On success, must free memory by calling `freeHdr` method.
|
||||||
|
pub fn loadHdrBuf(self: *Self, buf: []const u8) !image.Hdr {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
|
||||||
|
const res_f32 = import.stbi_loadf_from_memory(buf.ptr, @intCast(buf.len), &x, &y, null, 4) orelse return error.StbiError;
|
||||||
|
defer castle_media_stbi_free(res_f32);
|
||||||
|
|
||||||
|
const ux: u32 = @intCast(x);
|
||||||
|
const uy: u32 = @intCast(y);
|
||||||
|
const buffer_ptr_f32: [*]vm.Vector4 = @ptrCast(res_f32);
|
||||||
|
const buffer_ptr_f16: [*]vm.ColorHdr = @ptrCast(castle_media_stbi_malloc(ux * uy * @sizeOf(vm.ColorHdr)) orelse return error.OutOfMemory);
|
||||||
|
errdefer castle_media_stbi_free(buffer_ptr_f16);
|
||||||
|
|
||||||
|
for (buffer_ptr_f16[0 .. ux * uy], buffer_ptr_f32[0 .. ux * uy]) |*sample_f16, sample_f32| {
|
||||||
|
sample_f16.* = .init(
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.x)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.y)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.z)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.w)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .initBuffer(ux, uy, buffer_ptr_f16[0 .. ux * uy]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// On success, must free memory by calling `freeHdr` method.
|
||||||
|
pub fn loadHdrIo(self: *Self, reader: *std.io.Reader) !image.Hdr {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
var x: i32 = undefined;
|
||||||
|
var y: i32 = undefined;
|
||||||
|
|
||||||
|
const res_f32 = import.stbi_loadf_from_callbacks(&.std_io_reader_interface, reader, &x, &y, null, 4) orelse return error.StbiError;
|
||||||
|
defer castle_media_stbi_free(res_f32);
|
||||||
|
|
||||||
|
const ux: u32 = @intCast(x);
|
||||||
|
const uy: u32 = @intCast(y);
|
||||||
|
const buffer_ptr_f32: [*]vm.Vector4 = @ptrCast(res_f32);
|
||||||
|
const buffer_ptr_f16: [*]vm.ColorHdr = @ptrCast(castle_media_stbi_malloc(ux * uy * @sizeOf(vm.ColorHdr)) orelse return error.OutOfMemory);
|
||||||
|
errdefer castle_media_stbi_free(buffer_ptr_f16);
|
||||||
|
|
||||||
|
for (buffer_ptr_f16[0 .. ux * uy], buffer_ptr_f32[0 .. ux * uy]) |*sample_f16, sample_f32| {
|
||||||
|
sample_f16.* = .init(
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.x)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.y)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.z)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
std.math.clamp(@as(f16, @floatCast(sample_f32.w)), -std.math.floatMax(f16), std.math.floatMax(f16)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .initBuffer(ux, uy, buffer_ptr_f16[0 .. ux * uy]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeDynamic(self: *Self, img: image.Dynamic) void {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
castle_media_stbi_free(@ptrCast(@alignCast(img.data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeHdr(self: *Self, img: image.Hdr) void {
|
||||||
|
current_self = self;
|
||||||
|
defer current_self = undefined;
|
||||||
|
|
||||||
|
castle_media_stbi_free(@ptrCast(@alignCast(img.data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- IO INTERFACE ------------------------------------------------------------
|
||||||
|
|
||||||
|
pub const IoCallbacks = extern struct {
|
||||||
|
/// Fill `data` with `size` bytes. Return number of bytes actually read.
|
||||||
|
read: ?*const fn (ctx: ?*anyopaque, data: [*]u8, size: i32) callconv(.c) i32,
|
||||||
|
/// Skip the next `n` bytes, or backtrack `-n` bytes if `n < 0`.
|
||||||
|
skip: ?*const fn (ctx: ?*anyopaque, n: i32) callconv(.c) i32,
|
||||||
|
/// Return non-zero value if at the end of file/data.
|
||||||
|
eof: ?*const fn (cxt: ?*anyopaque) callconv(.c) i32,
|
||||||
|
|
||||||
|
pub const std_io_reader_interface: IoCallbacks = .{
|
||||||
|
.read = stdIoReader_ReadFn,
|
||||||
|
.skip = stdIoReader_SkipFn,
|
||||||
|
.eof = stdIoReader_EofFn,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn stdIoReader_ReadFn(ctx: ?*anyopaque, data: [*]u8, size: i32) callconv(.c) i32 {
|
||||||
|
const reader: *std.Io.Reader = @ptrCast(@alignCast(ctx.?));
|
||||||
|
const bytes_read = reader.readSliceShort(data[0..@intCast(size)]) catch return 0;
|
||||||
|
return @intCast(bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stdIoReader_SkipFn(ctx: ?*anyopaque, n: i32) callconv(.c) i32 {
|
||||||
|
const reader: *std.Io.Reader = @ptrCast(@alignCast(ctx.?));
|
||||||
|
// NOTE stb_image.h actually discards the return value from this
|
||||||
|
// callback. If an actual error occurs, we're cooked (but it will be
|
||||||
|
// very likely caught as a parsing error later).
|
||||||
|
_ = reader.discardAll(@intCast(n)) catch return 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stdIoReader_EofFn(ctx: ?*anyopaque) callconv(.c) i32 {
|
||||||
|
const reader: *std.Io.Reader = @ptrCast(@alignCast(ctx.?));
|
||||||
|
|
||||||
|
_ = reader.peekByte() catch return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- MALLOC INTERFACE --------------------------------------------------------
|
||||||
|
|
||||||
|
threadlocal var current_self: *Self = undefined;
|
||||||
|
|
||||||
|
export fn castle_media_stbi_malloc(size: usize) callconv(.c) VoidPtr {
|
||||||
|
const self = current_self;
|
||||||
|
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
|
||||||
|
self.allocations.ensureUnusedCapacity(self.allocator, 1) catch return null;
|
||||||
|
const memory = self.allocator.alignedAlloc(u8, alignment, size) catch return null;
|
||||||
|
|
||||||
|
self.allocations.putAssumeCapacityNoClobber(memory.ptr, size);
|
||||||
|
self.allocated_bytes += size;
|
||||||
|
//log.debug("Allocated {d} bytes(s) at 0x{x}", .{ size, @intFromPtr(memory.ptr) });
|
||||||
|
|
||||||
|
return memory.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn castle_media_stbi_realloc(maybe_ptr: VoidPtr, size: usize) callconv(.c) VoidPtr {
|
||||||
|
const self = current_self;
|
||||||
|
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
|
||||||
|
// NOTE If we were pedantic, we would consider the fact that we might not
|
||||||
|
// need unused capacity if the memory doesn't get relocated.
|
||||||
|
self.allocations.ensureUnusedCapacity(self.allocator, 1) catch return null;
|
||||||
|
|
||||||
|
const old_memory = if (maybe_ptr) |ptr| blk_then: {
|
||||||
|
const old_size = self.allocations.get(ptr).?;
|
||||||
|
break :blk_then @as([*]align(alignment.toByteUnits()) u8, @ptrCast(ptr))[0..old_size];
|
||||||
|
} else blk_else: {
|
||||||
|
break :blk_else @as([]align(alignment.toByteUnits()) u8, &.{});
|
||||||
|
};
|
||||||
|
|
||||||
|
const memory = self.allocator.realloc(old_memory, size) catch return null;
|
||||||
|
|
||||||
|
if (maybe_ptr) |ptr| {
|
||||||
|
const old_size = self.allocations.fetchRemove(ptr).?.value;
|
||||||
|
self.allocated_bytes -= old_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocations.putAssumeCapacityNoClobber(memory.ptr, size);
|
||||||
|
self.allocated_bytes += size;
|
||||||
|
//log.debug("Reallocated into {d} bytes(s) at 0x{x} from 0x{x}", .{ size, @intFromPtr(memory.ptr), @intFromPtr(maybe_ptr) });
|
||||||
|
|
||||||
|
return memory.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn castle_media_stbi_free(maybe_ptr: VoidPtr) callconv(.c) void {
|
||||||
|
const self = current_self;
|
||||||
|
|
||||||
|
if (maybe_ptr) |ptr| {
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
|
||||||
|
const size = self.allocations.fetchRemove(ptr).?.value;
|
||||||
|
self.allocated_bytes -= size;
|
||||||
|
const memory = @as([*]align(alignment.toByteUnits()) u8, @ptrCast(ptr))[0..size];
|
||||||
|
|
||||||
|
self.allocator.free(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
packages/media/src/stbi/stb_image.c
Normal file
17
packages/media/src/stbi/stb_image.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *castle_media_stbi_malloc(size_t size);
|
||||||
|
void *castle_media_stbi_realloc(void *ptr, size_t size);
|
||||||
|
void castle_media_stbi_free(void *ptr);
|
||||||
|
|
||||||
|
#define STBI_MALLOC(size) castle_media_stbi_malloc(size)
|
||||||
|
#define STBI_REALLOC(ptr, size) castle_media_stbi_realloc(ptr, size)
|
||||||
|
#define STBI_FREE(ptr) castle_media_stbi_free(ptr)
|
||||||
|
|
||||||
|
#define STBI_NO_STDIO
|
||||||
|
#define STBI_ONLY_JPEG
|
||||||
|
#define STBI_ONLY_PNG
|
||||||
|
#define STBI_ONLY_HDR
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
7988
packages/media/src/stbi/stb_image.h
Normal file
7988
packages/media/src/stbi/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
|
||||||
const target = b.resolveTargetQuery(.{
|
|
||||||
.cpu_arch = .x86_64,
|
|
||||||
.os_tag = .windows,
|
|
||||||
.abi = .msvc,
|
|
||||||
});
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
|
||||||
|
|
||||||
const zigwin32 = b.dependency("zigwin32", .{});
|
|
||||||
const zigwin32_mod = zigwin32.module("win32");
|
|
||||||
zigwin32_mod.resolved_target = target;
|
|
||||||
zigwin32_mod.optimize = optimize;
|
|
||||||
|
|
||||||
const exe_mod = b.createModule(.{
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
exe_mod.addImport("win32", zigwin32_mod);
|
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "sciter",
|
|
||||||
.root_module = exe_mod,
|
|
||||||
});
|
|
||||||
|
|
||||||
b.installArtifact(exe);
|
|
||||||
b.getInstallStep().dependOn(&b.addInstallBinFile(b.path("vendor/sciter.dll"), "sciter.dll").step);
|
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
|
||||||
if (b.args) |args| {
|
|
||||||
run_cmd.addArgs(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
.{
|
|
||||||
.name = .sciter,
|
|
||||||
.version = "0.0.0",
|
|
||||||
.minimum_zig_version = "0.15.2",
|
|
||||||
.paths = .{
|
|
||||||
"src",
|
|
||||||
"vendor",
|
|
||||||
"build.zig",
|
|
||||||
"build.zig.zon",
|
|
||||||
},
|
|
||||||
.fingerprint = 0x51b124a630f074d7,
|
|
||||||
.dependencies = .{
|
|
||||||
.zigwin32 = .{
|
|
||||||
.url = "https://github.com/marlersoft/zigwin32/archive/5587b16fa040573846a6bf531301f6206d31a6bf.zip",
|
|
||||||
.hash = "zigwin32-25.0.28-preview-AAAAAICM5AMResOGQnQ85mfe60TTOQeMtt7GRATUOKoP",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Sciter Demo</title>
|
|
||||||
<style>
|
|
||||||
html {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-size: 16px;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
background-color: white;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
#hello {
|
|
||||||
width: 120px;
|
|
||||||
height: 32px;
|
|
||||||
|
|
||||||
margin: 1*;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
border: 1px solid black;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
line-height: 32px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p id="hello">Hello, World!</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
const sciter = @import("sciter.zig");
|
|
||||||
const std = @import("std");
|
|
||||||
const wam = @import("win32").ui.windows_and_messaging;
|
|
||||||
const win32 = @import("win32").foundation;
|
|
||||||
|
|
||||||
const L = std.unicode.utf8ToUtf16LeStringLiteral;
|
|
||||||
const WINAPI = @import("std").builtin.CallingConvention.winapi;
|
|
||||||
|
|
||||||
const html = @embedFile("index.html");
|
|
||||||
|
|
||||||
const min_track_size: win32.POINT = .{ .x = 640, .y = 480 };
|
|
||||||
|
|
||||||
var sciter_api: *sciter.API = undefined;
|
|
||||||
|
|
||||||
pub fn wWinMain(
|
|
||||||
hInstance: std.os.windows.HINSTANCE,
|
|
||||||
hPrevInstance: ?std.os.windows.HINSTANCE,
|
|
||||||
lpCmdLine: [*:0]u16,
|
|
||||||
nCmdShow: i32,
|
|
||||||
) i32 {
|
|
||||||
_ = hPrevInstance;
|
|
||||||
_ = lpCmdLine;
|
|
||||||
|
|
||||||
const sciter_module = std.os.windows.LoadLibraryW(L("sciter.dll")) catch |err| {
|
|
||||||
_ = wam.MessageBoxW(
|
|
||||||
null,
|
|
||||||
switch (err) {
|
|
||||||
error.FileNotFound => L("Couldn't find sciter.dll."),
|
|
||||||
else => L("An unknown error occured while trying to load sciter.dll."),
|
|
||||||
},
|
|
||||||
L("Critical error"),
|
|
||||||
wam.MB_ICONHAND,
|
|
||||||
);
|
|
||||||
std.posix.exit(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sciter_api_fn: *const fn () ?*sciter.API = @ptrCast(std.os.windows.kernel32.GetProcAddress(sciter_module, "SciterAPI") orelse {
|
|
||||||
_ = wam.MessageBoxW(null, L("Couldn't load Sciter API."), L("Critical error"), wam.MB_ICONHAND);
|
|
||||||
std.posix.exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
sciter_api = sciter_api_fn() orelse {
|
|
||||||
_ = wam.MessageBoxW(null, L("Couldn't load Sciter API."), L("Critical error"), wam.MB_ICONHAND);
|
|
||||||
std.posix.exit(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
std.debug.print("Sciter API version is: 0x{X:0>8}\n", .{sciter_api.version});
|
|
||||||
|
|
||||||
const wc = std.mem.zeroInit(wam.WNDCLASSEXW, .{
|
|
||||||
.cbSize = @sizeOf(wam.WNDCLASSEXW),
|
|
||||||
.lpfnWndProc = &WindowProc,
|
|
||||||
.hInstance = hInstance,
|
|
||||||
.hIcon = wam.LoadIconW(null, wam.IDI_APPLICATION),
|
|
||||||
.hCursor = wam.LoadCursorW(null, wam.IDC_ARROW),
|
|
||||||
.lpszClassName = L("SCITER_WINDOW"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const atom = wam.RegisterClassExW(&wc);
|
|
||||||
std.debug.assert(atom != 0);
|
|
||||||
|
|
||||||
const hwnd = wam.CreateWindowExW(
|
|
||||||
wam.WS_EX_APPWINDOW,
|
|
||||||
wc.lpszClassName,
|
|
||||||
L("Sciter Demo"),
|
|
||||||
wam.WS_OVERLAPPEDWINDOW,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
wc.hInstance,
|
|
||||||
null,
|
|
||||||
) orelse {
|
|
||||||
_ = wam.MessageBoxW(null, L("Couldn't create window."), L("Critical error"), wam.MB_ICONHAND);
|
|
||||||
std.posix.exit(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = sciter_api.SciterLoadHtml(hwnd, html, html.len, L("/"));
|
|
||||||
_ = wam.ShowWindow(hwnd, @bitCast(nCmdShow));
|
|
||||||
|
|
||||||
var msg = std.mem.zeroes(wam.MSG);
|
|
||||||
while (wam.GetMessageW(&msg, null, 0, 0) > 0) {
|
|
||||||
_ = wam.TranslateMessage(&msg);
|
|
||||||
_ = wam.DispatchMessageW(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return @bitCast(@as(u32, @truncate(msg.wParam)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn WindowProc(
|
|
||||||
hwnd: win32.HWND,
|
|
||||||
uMsg: u32,
|
|
||||||
wParam: win32.WPARAM,
|
|
||||||
lParam: win32.LPARAM,
|
|
||||||
) callconv(WINAPI) win32.LRESULT {
|
|
||||||
switch (uMsg) {
|
|
||||||
wam.WM_DESTROY => {
|
|
||||||
wam.PostQuitMessage(0);
|
|
||||||
},
|
|
||||||
wam.WM_GETMINMAXINFO => {
|
|
||||||
const mmi: *wam.MINMAXINFO = @ptrFromInt(@as(usize, @bitCast(lParam)));
|
|
||||||
mmi.ptMinTrackSize = min_track_size;
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
var handled: sciter.Bool = .FALSE;
|
|
||||||
const result = sciter_api.SciterProcND(hwnd, uMsg, wParam, lParam, &handled);
|
|
||||||
if (handled != .FALSE) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wam.DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
@@ -1,641 +0,0 @@
|
|||||||
pub const CStr = [*:0]const u8;
|
|
||||||
pub const CWStr = [*:0]const u16;
|
|
||||||
|
|
||||||
pub const Element = opaque {};
|
|
||||||
pub const HElement = *Element;
|
|
||||||
|
|
||||||
pub const Node = opaque {};
|
|
||||||
pub const HNode = *Node;
|
|
||||||
|
|
||||||
pub const SArchive = opaque {};
|
|
||||||
pub const HSArchive = *SArchive;
|
|
||||||
|
|
||||||
/// - Windows: `HWND`
|
|
||||||
/// - OS X: `NSView*`
|
|
||||||
/// - Linux/GTK: `GtkWidget*`
|
|
||||||
pub const HWindow = *anyopaque;
|
|
||||||
|
|
||||||
pub const BehaviorEventParams = extern struct {
|
|
||||||
cmd: BehaviorEvents,
|
|
||||||
he_target: ?HElement,
|
|
||||||
he: ?HElement,
|
|
||||||
reason: extern union {
|
|
||||||
click: enum(usize) { BY_MOUSE_CLICK, BY_KEY_CLICK, SYNTHESIZED, BY_MOUSE_ON_ICON },
|
|
||||||
edit_changed: enum(usize) { BY_INS_CHAR, BY_INS_CHARS, BY_DEL_CHAR, BY_DEL_CHARS, BY_UNDO_REDO },
|
|
||||||
custom: usize,
|
|
||||||
},
|
|
||||||
data: Value,
|
|
||||||
name: ?CWStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
const BehaviorEvents = enum(u32) {
|
|
||||||
BUTTON_CLICK = 0,
|
|
||||||
BUTTON_PRESS = 1,
|
|
||||||
|
|
||||||
VALUE_CHANGED = 2,
|
|
||||||
VALUE_CHANGING = 3,
|
|
||||||
|
|
||||||
SELECTION_CHANGED = 5,
|
|
||||||
SELECTION_CHANGING = 0xC,
|
|
||||||
|
|
||||||
POPUP_REQUEST = 7,
|
|
||||||
POPUP_READY = 8,
|
|
||||||
POPUP_DISMISSED = 9,
|
|
||||||
|
|
||||||
MENU_ITEM_ACTIVE = 0xA,
|
|
||||||
MENU_ITEM_CLICK = 0xB,
|
|
||||||
|
|
||||||
CONTEXT_MENU_REQUEST = 0x10,
|
|
||||||
|
|
||||||
VISUAL_STATUS_CHANGED = 0x11,
|
|
||||||
DISABLED_STATUS_CHANGED = 0x12,
|
|
||||||
|
|
||||||
POPUP_DISMISSING = 0x13,
|
|
||||||
|
|
||||||
CONTENT_CHANGED = 0x15,
|
|
||||||
|
|
||||||
HYPERLINK_CLICK = 0x80,
|
|
||||||
|
|
||||||
ELEMENT_COLLAPSED = 0x90,
|
|
||||||
ELEMENT_EXPANDED = 0x91,
|
|
||||||
|
|
||||||
ACTIVATE_CHILD = 0x92,
|
|
||||||
|
|
||||||
FORM_SUBMIT = 0x96,
|
|
||||||
FORM_RESET = 0x97,
|
|
||||||
|
|
||||||
DOCUMENT_COMPLETE = 0x98,
|
|
||||||
|
|
||||||
HISTORY_PUSH = 0x99,
|
|
||||||
HISTORY_DROP = 0x9A,
|
|
||||||
HISTORY_PRIOR = 0x9B,
|
|
||||||
HISTORY_NEXT = 0x9C,
|
|
||||||
HISTORY_STATE_CHANGED = 0x9D,
|
|
||||||
|
|
||||||
CLOSE_POPUP = 0x9E,
|
|
||||||
REQUEST_TOOLTIP = 0x9F,
|
|
||||||
|
|
||||||
ANIMATION = 0xA0,
|
|
||||||
TRANSITION = 0xA1,
|
|
||||||
SWIPE = 0xB0,
|
|
||||||
|
|
||||||
DOCUMENT_CREATED = 0xC0,
|
|
||||||
DOCUMENT_CLOSE_REQUEST = 0xC1,
|
|
||||||
DOCUMENT_CLOSE = 0xC2,
|
|
||||||
DOCUMENT_READY = 0xC3,
|
|
||||||
DOCUMENT_PARSED = 0xC4,
|
|
||||||
//DOCUMENT_RELOAD = 0xC5,
|
|
||||||
DOCUMENT_CLOSING = 0xC6,
|
|
||||||
CONTAINER_CLOSE_REQUEST = 0xC7,
|
|
||||||
CONTAINER_CLOSING = 0xC8,
|
|
||||||
|
|
||||||
VIDEO_INITIALIZED = 0xD1,
|
|
||||||
VIDEO_STARTED = 0xD2,
|
|
||||||
VIDEO_STOPPED = 0xD3,
|
|
||||||
VIDEO_BIND_RQ = 0xD4,
|
|
||||||
|
|
||||||
VIDEO_FRAME_REQUEST = 0xD8,
|
|
||||||
|
|
||||||
PAGINATION_STARTS = 0xE0,
|
|
||||||
PAGINATION_PAGE = 0xE1,
|
|
||||||
PAGINATION_ENDS = 0xE2,
|
|
||||||
|
|
||||||
CUSTOM = 0xF0,
|
|
||||||
|
|
||||||
EGL_RENDER = 0x20,
|
|
||||||
|
|
||||||
/// All custom event codes shall be greater than this number. All codes
|
|
||||||
/// below this will be used solely by application - Sciter will not
|
|
||||||
/// intrepret it and will do just dispatching. To send event notifications
|
|
||||||
/// with these codes use SciterSend/PostEvent API.
|
|
||||||
FIRST_APPLICATION_EVENT_CODE = 0x100,
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Bool = enum(u32) {
|
|
||||||
FALSE = 0,
|
|
||||||
TRUE = 1,
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const DomResult = enum(i32) {
|
|
||||||
OK = 0,
|
|
||||||
INVALID_HWND = 1,
|
|
||||||
INVALID_HANDLE = 2,
|
|
||||||
PASSIVE_HANDLE = 3,
|
|
||||||
INVALID_PARAMETER = 4,
|
|
||||||
OPERATION_FAILED = 5,
|
|
||||||
OK_NOT_HANDLED = -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const CtlType = enum(u32) {
|
|
||||||
NO = 0,
|
|
||||||
UNKNOWN = 1,
|
|
||||||
|
|
||||||
EDIT = 2,
|
|
||||||
NUMERIC = 3,
|
|
||||||
CLICKABLE = 4,
|
|
||||||
BUTTON = 5,
|
|
||||||
CHECKBOX = 6,
|
|
||||||
RADIO = 7,
|
|
||||||
SELECT_SINGLE = 8,
|
|
||||||
SELECT_MULTIPLE = 9,
|
|
||||||
DD_SELECT = 10,
|
|
||||||
TEXTAREA = 11,
|
|
||||||
HTMLAREA = 12,
|
|
||||||
PASSWORD = 13,
|
|
||||||
PROGRESS = 14,
|
|
||||||
SLIDER = 15,
|
|
||||||
DECIMAL = 16,
|
|
||||||
CURRENCY = 17,
|
|
||||||
SCROLLBAR = 18,
|
|
||||||
LIST = 19,
|
|
||||||
RICHTEXT = 20,
|
|
||||||
CALENDAR = 21,
|
|
||||||
DATE = 22,
|
|
||||||
TIME = 23,
|
|
||||||
FILE = 24,
|
|
||||||
PATH = 25,
|
|
||||||
|
|
||||||
HYPERLINK = 26,
|
|
||||||
FORM = 27,
|
|
||||||
|
|
||||||
MENUBAR = 28,
|
|
||||||
MENU = 29,
|
|
||||||
MENUBUTTON = 30,
|
|
||||||
|
|
||||||
FRAME = 31,
|
|
||||||
FRAMESET = 32,
|
|
||||||
|
|
||||||
TOOLTIP = 33,
|
|
||||||
|
|
||||||
HIDDEN = 34,
|
|
||||||
URL = 35,
|
|
||||||
TOOLBAR = 36,
|
|
||||||
|
|
||||||
WINDOW = 37,
|
|
||||||
|
|
||||||
LABEL = 38,
|
|
||||||
IMAGE = 39,
|
|
||||||
PLAINTEXT = 40,
|
|
||||||
|
|
||||||
SELECT_TREE = 41,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ElementAreas = packed struct {
|
|
||||||
relative: enum(u4) {
|
|
||||||
ROOT = 0x1,
|
|
||||||
SELF = 0x2,
|
|
||||||
CONTAINER = 0x3,
|
|
||||||
VIEW = 0x4,
|
|
||||||
_,
|
|
||||||
} = @enumFromInt(0x0),
|
|
||||||
|
|
||||||
area: enum(u4) {
|
|
||||||
CONTENT_BOX = 0x0,
|
|
||||||
PADDING_BOX = 0x1,
|
|
||||||
BORDER_BOX = 0x2,
|
|
||||||
MARGIN_BOX = 0x3,
|
|
||||||
|
|
||||||
BACK_IMAGE_AREA = 0x4,
|
|
||||||
FORE_IMAGE_AREA = 0x5,
|
|
||||||
|
|
||||||
SCROLLABLE_AREA = 0x6,
|
|
||||||
_,
|
|
||||||
} = .CONTENT_BOX,
|
|
||||||
|
|
||||||
_pad8: u8 = 0,
|
|
||||||
|
|
||||||
as_ppx: bool = false,
|
|
||||||
|
|
||||||
_pad17: u15 = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const MethodParams = extern struct {
|
|
||||||
method_id: u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const NodeType = enum(u32) { ELEMENT, TEXT, COMMENT };
|
|
||||||
|
|
||||||
pub const NodeInsTarget = enum(u32) { BEFORE, AFTER, APPEND, PREPEND };
|
|
||||||
|
|
||||||
pub const Point = extern struct {
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Rect = extern struct {
|
|
||||||
left: i32,
|
|
||||||
top: i32,
|
|
||||||
right: i32,
|
|
||||||
bottom: u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const RequestParam = extern struct {
|
|
||||||
name: CWStr,
|
|
||||||
value: CWStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const RequestType = enum(u32) {
|
|
||||||
GET_ASYNC,
|
|
||||||
POST_ASYNC,
|
|
||||||
GET_SYNC,
|
|
||||||
POST_SYNC,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ResourceType = enum(u32) {
|
|
||||||
HTML = 0,
|
|
||||||
IMAGE = 1,
|
|
||||||
STYLE = 2,
|
|
||||||
CURSOR = 3,
|
|
||||||
SCRIPT = 4,
|
|
||||||
RAW = 5,
|
|
||||||
FONT,
|
|
||||||
SOUND,
|
|
||||||
FORCE_DWORD = 0xFFFFFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const SetElementHtml = enum(u32) {
|
|
||||||
SIH_REPLACE_CONTENT = 0,
|
|
||||||
SIH_INSERT_AT_START = 1,
|
|
||||||
SIH_APPEND_AFTER_LAST = 2,
|
|
||||||
SOH_REPLACE = 3,
|
|
||||||
SOH_INSERT_BEFORE = 4,
|
|
||||||
SOH_INSERT_AFTER = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Size = extern struct {
|
|
||||||
cx: i32,
|
|
||||||
cy: i32,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Value = extern struct {
|
|
||||||
type: ValueType,
|
|
||||||
unit: extern union {
|
|
||||||
value: ValueUnit,
|
|
||||||
/// For when `Value.type == .OBJECT`
|
|
||||||
object: ValueUnitObject,
|
|
||||||
},
|
|
||||||
data: u64,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ValueType = enum(u32) {
|
|
||||||
UNDEFINED = 0,
|
|
||||||
NULL = 1,
|
|
||||||
BOOL = 2,
|
|
||||||
i32 = 3,
|
|
||||||
FLOAT = 4,
|
|
||||||
STRING = 5,
|
|
||||||
DATE = 6,
|
|
||||||
BIG_INT = 7,
|
|
||||||
LENGTH = 8,
|
|
||||||
ARRAY = 9,
|
|
||||||
MAP = 10,
|
|
||||||
FUNCTION = 11,
|
|
||||||
BYTES = 12,
|
|
||||||
OBJECT = 13,
|
|
||||||
RESOURCE = 15,
|
|
||||||
DURATION = 17,
|
|
||||||
ANGLE = 18,
|
|
||||||
COLOR = 19,
|
|
||||||
ASSET = 21,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ValueUnit = enum(u32) {
|
|
||||||
EM = 1,
|
|
||||||
EX = 2,
|
|
||||||
PR = 3,
|
|
||||||
SP = 4,
|
|
||||||
|
|
||||||
PX = 7,
|
|
||||||
IN = 8,
|
|
||||||
CM = 9,
|
|
||||||
MM = 10,
|
|
||||||
PT = 11,
|
|
||||||
PC = 12,
|
|
||||||
DIP = 13,
|
|
||||||
|
|
||||||
PR_WIDTH = 16,
|
|
||||||
PR_HEIGHT = 17,
|
|
||||||
PR_VIEW_WIDTH = 18,
|
|
||||||
PR_VIEW_HEIGHT = 19,
|
|
||||||
PR_VIEW_MIN = 20,
|
|
||||||
PR_VIEW_MAX = 21,
|
|
||||||
|
|
||||||
REM = 22,
|
|
||||||
PPX = 23,
|
|
||||||
CH = 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ValueUnitObject = enum(u32) {
|
|
||||||
ARRAY = 0,
|
|
||||||
OBJECT = 1,
|
|
||||||
CLASS = 2,
|
|
||||||
NATIVE = 3,
|
|
||||||
FUNCTION = 4,
|
|
||||||
ERROR = 5,
|
|
||||||
BUFFER = 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ValueResult = enum(i32) {
|
|
||||||
OK_TRUE = -1,
|
|
||||||
OK = 0,
|
|
||||||
BAD_PARAMETER = 1,
|
|
||||||
INCOMPATIBLE_TYPE = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const OutputSubsystems = enum(u32) {
|
|
||||||
DOM = 0,
|
|
||||||
CSSS,
|
|
||||||
CSS,
|
|
||||||
TIS,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const CallbackNotification = extern struct {
|
|
||||||
code: u32,
|
|
||||||
hwnd: HWindow,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const XMsgCode = enum(u32) {
|
|
||||||
CREATE = 0,
|
|
||||||
DESTROY = 1,
|
|
||||||
SIZE = 2,
|
|
||||||
PAINT = 3,
|
|
||||||
RESOLUTION = 4,
|
|
||||||
HEARTBIT = 5,
|
|
||||||
MOUSE = 6,
|
|
||||||
KEY = 7,
|
|
||||||
FOCUS = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const XMsg = extern struct {
|
|
||||||
msg: XMsgCode,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const OmAsset = extern struct {
|
|
||||||
isa: *OmAssetClass,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const OmAssetClass = extern struct {
|
|
||||||
asset_add_ref: *const fn (thing: *OmAsset) callconv(.c) c_long,
|
|
||||||
asset_release: *const fn (thing: *OmAsset) callconv(.c) c_long,
|
|
||||||
asset_get_interface: *const fn (thing: *OmAsset, name: CStr, out: *?*anyopaque) callconv(.c) c_long,
|
|
||||||
asset_get_passport: *const fn (thins: *OmAsset) callconv(.c) ?*OmPassport,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const OmPassport = opaque {};
|
|
||||||
|
|
||||||
pub const ValueStringCvtType = enum(u32) {
|
|
||||||
CVT_SIMPLE,
|
|
||||||
CVT_JSON_LITERAL,
|
|
||||||
CVT_JSON_MAP,
|
|
||||||
CVT_XJSON_LITERAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ByteReceiver = fn (str: [*]const u8, num_bytes: u32, param: ?*anyopaque) callconv(.c) void;
|
|
||||||
const DebugOutputProc = fn (param: ?*anyopaque, subsystem: OutputSubsystems, severity: u32, text: [*]const u16, text_length: u32) callconv(.c) void;
|
|
||||||
const ElementCallback = fn (he: HElement, param: ?*anyopaque) callconv(.c) Bool;
|
|
||||||
const ElementComparator = fn (he1: HElement, he2: HElement, param: ?*anyopaque) callconv(.c) i32;
|
|
||||||
const ElementEventProc = fn (tag: ?*anyopaque, he: HElement, evtg: u32, prms: ?*anyopaque) callconv(.c) Bool;
|
|
||||||
const HostCallback = fn (pns: *CallbackNotification, callback_param: ?*anyopaque) callconv(.c) u32;
|
|
||||||
const KeyValueCallback = fn (param: ?*anyopaque, pkey: *const Value, pval: *const Value) callconv(.c) Bool;
|
|
||||||
const NativeFunctorInvoke = fn (tag: ?*anyopaque, argc: u32, argv: [*]const Value, retval: *Value) callconv(.c) void;
|
|
||||||
const NativeFunctorRelease = fn (tag: ?*anyopaque) callconv(.c) void;
|
|
||||||
const StrReceiver = fn (str: [*]const u8, num_bytes: u32, param: ?*anyopaque) callconv(.c) void;
|
|
||||||
const WindowDelegate = fn (hwnd: HWindow, msg: u32, wParam: usize, lParam: isize, pbHandled: *Bool) callconv(.c) isize;
|
|
||||||
const WStrReceiver = fn (str: [*]const u16, num_bytes: u32, param: ?*anyopaque) callconv(.c) void;
|
|
||||||
|
|
||||||
pub const API = extern struct {
|
|
||||||
version: u32,
|
|
||||||
|
|
||||||
SciterClassName: *const fn () callconv(.c) CWStr,
|
|
||||||
SciterVersion: *const fn (n: u32) callconv(.c) u32,
|
|
||||||
SciterDataReady: *const fn (hwnd: HWindow, uri: CWStr, data: [*]const u8, dataLength: u32) callconv(.c) Bool,
|
|
||||||
SciterDataReadyAsync: *const fn (hwnd: HWindow, uri: CWStr, data: [*]const u8, dataLength: u32, requestId: ?*anyopaque) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterProc: *const fn (hwnd: HWindow, msg: u32, wParam: usize, lParam: isize) callconv(.c) isize,
|
|
||||||
SciterProcND: *const fn (hwnd: HWindow, msg: u32, wParam: usize, lParam: isize, pbHandled: *Bool) callconv(.c) isize,
|
|
||||||
|
|
||||||
SciterLoadFile: *const fn (hwnd: HWindow, filename: CWStr) callconv(.c) Bool,
|
|
||||||
SciterLoadHtml: *const fn (hwnd: HWindow, html: [*]const u8, htmlSize: u32, baseUrl: CWStr) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterSetCallback: *const fn (hwnd: HWindow, cb: ?*HostCallback, cbParam: ?*anyopaque) callconv(.c) void,
|
|
||||||
SciterSetMasterCSS: *const fn (utf8: [*]const u8, numBytes: u32) callconv(.c) Bool,
|
|
||||||
SciterAppendMasterCSS: *const fn (utf8: [*]const u8, numBytes: u32) callconv(.c) Bool,
|
|
||||||
SciterSetCSS: *const fn (hwnd: HWindow, utf8: [*]const u8, numBytes: u32, baseUrl: CWStr, mediaType: CWStr) callconv(.c) Bool,
|
|
||||||
SciterSetMediaType: *const fn (hwnd: HWindow, mediaType: CWStr) callconv(.c) Bool,
|
|
||||||
SciterSetMediaVars: *const fn (hwnd: HWindow, mediaVars: *const Value) callconv(.c) Bool,
|
|
||||||
SciterGetMinWidth: *const fn (hwnd: HWindow) callconv(.c) u32,
|
|
||||||
SciterGetMinHeight: *const fn (hwnd: HWindow, width: u32) callconv(.c) u32,
|
|
||||||
SciterCall: *const fn (hWnd: HWindow, functionName: CStr, argc: u32, argv: [*]const Value, retval: *Value) callconv(.c) Bool,
|
|
||||||
SciterEval: *const fn (hwnd: HWindow, script: [*]const u16, scriptLength: u32, pretval: *Value) callconv(.c) Bool,
|
|
||||||
SciterUpdateWindow: *const fn (hwnd: HWindow) callconv(.c) void,
|
|
||||||
/// Win32 MSG
|
|
||||||
SciterTranslateMessage: *const fn (lpMsg: *anyopaque) callconv(.c) Bool,
|
|
||||||
SciterSetOption: *const fn (hWnd: HWindow, option: u32, value: usize) callconv(.c) Bool,
|
|
||||||
SciterGetPPI: *const fn (hwnd: HWindow, px: *u32, py: *u32) callconv(.c) void,
|
|
||||||
SciterGetViewExpando: *const fn (hwnd: HWindow, pval: *Value) callconv(.c) Bool,
|
|
||||||
/// ID2D1RenderTarget
|
|
||||||
SciterRenderD2D: *const fn (hwnd: HWindow, prt: *anyopaque) callconv(.c) Bool,
|
|
||||||
/// ID2D1Factory
|
|
||||||
SciterD2DFactory: *const fn (ppf: *anyopaque) callconv(.c) Bool,
|
|
||||||
/// IDWriteFactory
|
|
||||||
SciterDWFactory: *const fn (ppf: *anyopaque) callconv(.c) Bool,
|
|
||||||
SciterGraphicsCaps: *const fn (pcaps: *u32) callconv(.c) Bool,
|
|
||||||
SciterSetHomeURL: *const fn (hwnd: HWindow, baseUrl: CWStr) callconv(.c) Bool,
|
|
||||||
SciterCreateNSView: *anyopaque,
|
|
||||||
SciterCreateWidget: *anyopaque,
|
|
||||||
SciterCreateWindow: *const fn (creationFlags: u32, frame: *Rect, delegate: *const WindowDelegate, delegateParam: ?*anyopaque, parent: HWindow) callconv(.c) HWindow,
|
|
||||||
|
|
||||||
SciterSetupDebugOutput: *const fn (hwndOrNull: ?HWindow, param: ?*anyopaque, pfOutput: ?*DebugOutputProc) callconv(.c) void,
|
|
||||||
|
|
||||||
// --- DOM API -------------------------------------------------------------
|
|
||||||
|
|
||||||
Sciter_UseElement: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
Sciter_UnuseElement: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetRootElement: *const fn (hwnd: HWindow, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetFocusElement: *const fn (hwnd: HWindow, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterFindElement: *const fn (hwnd: HWindow, pt: Point, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetChildrenCount: *const fn (he: HElement, count: *u32) callconv(.c) DomResult,
|
|
||||||
SciterGetNthChild: *const fn (he: HElement, n: u32, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetParentElement: *const fn (he: HElement, p_parent_he: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetElementHtmlCB: *const fn (he: HElement, outer: Bool, rcv: *const ByteReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterGetElementTextCB: *const fn (he: HElement, rcv: *const WStrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSetElementText: *const fn (he: HElement, utf16: [*]const u16, length: u32) callconv(.c) DomResult,
|
|
||||||
SciterGetAttributeCount: *const fn (he: HElement, p_count: *u32) callconv(.c) DomResult,
|
|
||||||
SciterGetNthAttributeNameCB: *const fn (he: HElement, n: u32, rcv: *const StrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterGetNthAttributeValueCB: *const fn (he: HElement, n: u32, rcv: *const WStrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterGetAttributeByNameCB: *const fn (he: HElement, name: CStr, rcv: *const WStrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSetAttributeByName: *const fn (he: HElement, name: CStr, value: CWStr) callconv(.c) DomResult,
|
|
||||||
SciterClearAttributes: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetElementIndex: *const fn (he: HElement, p_index: *u32) callconv(.c) DomResult,
|
|
||||||
SciterGetElementType: *const fn (he: HElement, p_type: *CStr) callconv(.c) DomResult,
|
|
||||||
SciterGetElementTypeCB: *const fn (he: HElement, rcv: *const StrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterGetStyleAttributeCB: *const fn (he: HElement, name: CStr, rcv: *const WStrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSetStyleAttribute: *const fn (he: HElement, name: CStr, value: CWStr) callconv(.c) DomResult,
|
|
||||||
SciterGetElementLocation: *const fn (he: HElement, p_location: *Rect, areas: ElementAreas) callconv(.c) DomResult,
|
|
||||||
SciterScrollToView: *const fn (he: HElement, SciterScrollFlags: u32) callconv(.c) DomResult,
|
|
||||||
SciterUpdateElement: *const fn (he: HElement, andForceRender: Bool) callconv(.c) DomResult,
|
|
||||||
SciterRefreshElementArea: *const fn (he: HElement, rc: Rect) callconv(.c) DomResult,
|
|
||||||
SciterSetCapture: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterReleaseCapture: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetElementHwnd: *const fn (he: HElement, p_hwnd: *HWindow, rootWindow: Bool) callconv(.c) DomResult,
|
|
||||||
SciterCombineURL: *const fn (he: HElement, szUrlBuffer: [*]u16, UrlBufferSize: u32) callconv(.c) DomResult,
|
|
||||||
SciterSelectElements: *const fn (he: HElement, CSS_selectors: CStr, callback: *const ElementCallback, param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSelectElementsW: *const fn (he: HElement, CSS_selectors: CWStr, callback: *const ElementCallback, param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSelectParent: *const fn (he: HElement, selector: CStr, depth: u32, heFound: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterSelectParentW: *const fn (he: HElement, selector: CWStr, depth: u32, heFound: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterSetElementHtml: *const fn (he: HElement, html: [*]const u8, htmlLength: u32, where: SetElementHtml) callconv(.c) DomResult,
|
|
||||||
SciterGetElementUID: *const fn (he: HElement, puid: *u32) callconv(.c) DomResult,
|
|
||||||
SciterGetElementByUID: *const fn (hwnd: HWindow, uid: u32, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterShowPopup: *const fn (hePopup: HElement, heAnchor: HElement, placement: u32) callconv(.c) DomResult,
|
|
||||||
SciterShowPopupAt: *const fn (hePopup: HElement, pos: Point, placement: u32) callconv(.c) DomResult,
|
|
||||||
SciterHidePopup: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterGetElementState: *const fn (he: HElement, pstateBits: *u32) callconv(.c) DomResult,
|
|
||||||
SciterSetElementState: *const fn (he: HElement, stateBitsToSet: u32, stateBitsToClear: u32, updateView: Bool) callconv(.c) DomResult,
|
|
||||||
SciterCreateElement: *const fn (tagname: CStr, textOrNull: ?CWStr, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterCloneElement: *const fn (he: HElement, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterInsertElement: *const fn (he: HElement, hparent: HElement, index: u32) callconv(.c) DomResult,
|
|
||||||
SciterDetachElement: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterDeleteElement: *const fn (he: HElement) callconv(.c) DomResult,
|
|
||||||
SciterSetTimer: *const fn (he: HElement, milliseconds: u32, timer_id: usize) callconv(.c) DomResult,
|
|
||||||
SciterDetachEventHandler: *const fn (he: HElement, pep: *const ElementEventProc, tag: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterAttachEventHandler: *const fn (he: HElement, pep: *const ElementEventProc, tag: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterWindowAttachEventHandler: *const fn (hwndLayout: HWindow, pep: *const ElementEventProc, tag: ?*anyopaque, subscription: u32) callconv(.c) DomResult,
|
|
||||||
SciterWindowDetachEventHandler: *const fn (hwndLayout: HWindow, pep: *const ElementEventProc, tag: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSendEvent: *const fn (he: HElement, appEventCode: u32, heSource: HElement, reason: usize, handled: *Bool) callconv(.c) DomResult,
|
|
||||||
SciterPostEvent: *const fn (he: HElement, appEventCode: u32, heSource: HElement, reason: usize) callconv(.c) DomResult,
|
|
||||||
SciterCallBehaviorMethod: *const fn (he: HElement, params: *MethodParams) callconv(.c) DomResult,
|
|
||||||
SciterRequestElementData: *const fn (he: HElement, url: CWStr, dataType: u32, initiator: HElement) callconv(.c) DomResult,
|
|
||||||
SciterHttpRequest: *const fn (he: HElement, url: CWStr, dataType: ResourceType, requestType: RequestType, requestParams: [*]RequestParam, nParams: u32) callconv(.c) DomResult,
|
|
||||||
SciterGetScrollInfo: *const fn (he: HElement, scrollPos: *Point, viewRect: *Rect, contentSize: *Size) callconv(.c) DomResult,
|
|
||||||
SciterSetScrollPos: *const fn (he: HElement, scrollPos: Point, smooth: Bool) callconv(.c) DomResult,
|
|
||||||
SciterGetElementIntrinsicWidths: *const fn (he: HElement, pMinWidth: *i32, pMaxWidth: *i32) callconv(.c) DomResult,
|
|
||||||
SciterGetElementIntrinsicHeight: *const fn (he: HElement, forWidth: i32, pHeight: *i32) callconv(.c) DomResult,
|
|
||||||
SciterIsElementVisible: *const fn (he: HElement, pVisible: *Bool) callconv(.c) DomResult,
|
|
||||||
SciterIsElementEnabled: *const fn (he: HElement, pEnabled: *Bool) callconv(.c) DomResult,
|
|
||||||
SciterSortElements: *const fn (he: HElement, firstIndex: u32, lastIndex: u32, cmpFunc: *const ElementComparator, cmpFuncParam: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterSwapElements: *const fn (he1: HElement, he2: HElement) callconv(.c) DomResult,
|
|
||||||
SciterTraverseUIEvent: *const fn (evt: u32, eventCtlStruct: ?*anyopaque, bOutProcessed: *Bool) callconv(.c) DomResult,
|
|
||||||
SciterCallScriptingMethod: *const fn (he: HElement, name: CStr, argv: [*]const Value, argc: u32, retval: *Value) callconv(.c) DomResult,
|
|
||||||
SciterCallScriptingFunction: *const fn (he: HElement, name: CStr, argv: [*]const Value, argc: u32, retval: *Value) callconv(.c) DomResult,
|
|
||||||
SciterEvalElementScript: *const fn (he: HElement, script: [*]const u16, scriptLength: u32, retval: *Value) callconv(.c) DomResult,
|
|
||||||
SciterAttachHwndToElement: *const fn (he: HElement, hwnd: HWindow) callconv(.c) DomResult,
|
|
||||||
SciterControlGetType: *const fn (he: HElement, pType: *CtlType) callconv(.c) DomResult,
|
|
||||||
SciterGetValue: *const fn (he: HElement, pval: *Value) callconv(.c) DomResult,
|
|
||||||
SciterSetValue: *const fn (he: HElement, pval: *const Value) callconv(.c) DomResult,
|
|
||||||
SciterGetExpando: *const fn (he: HElement, pval: *Value, forceCreation: Bool) callconv(.c) DomResult,
|
|
||||||
SciterGetObject: *const fn (he: HElement, pval: *void, forceCreation: Bool) callconv(.c) DomResult,
|
|
||||||
SciterGetElementNamespace: *const fn (he: HElement, pval: *void) callconv(.c) DomResult,
|
|
||||||
SciterGetHighlightedElement: *const fn (hwnd: HWindow, phe: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterSetHighlightedElement: *const fn (hwnd: HWindow, he: HElement) callconv(.c) DomResult,
|
|
||||||
|
|
||||||
// --- DOM NODE API --------------------------------------------------------
|
|
||||||
|
|
||||||
SciterNodeAddRef: *const fn (hn: HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeRelease: *const fn (hn: HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeCastFromElement: *const fn (he: HElement, phn: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeCastToElement: *const fn (hn: HNode, he: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterNodeFirstChild: *const fn (hn: HNode, phn: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeLastChild: *const fn (hn: HNode, phn: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeNextSibling: *const fn (hn: HNode, phn: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodePrevSibling: *const fn (hn: HNode, phn: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeParent: *const fn (hnode: HNode, pheParent: *HElement) callconv(.c) DomResult,
|
|
||||||
SciterNodeNthChild: *const fn (hnode: HNode, n: u32, phn: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeChildrenCount: *const fn (hnode: HNode, pn: *u32) callconv(.c) DomResult,
|
|
||||||
SciterNodeType: *const fn (hnode: HNode, pNodeType: *NodeType) callconv(.c) DomResult,
|
|
||||||
SciterNodeGetText: *const fn (hnode: HNode, rcv: *const WStrReceiver, rcv_param: ?*anyopaque) callconv(.c) DomResult,
|
|
||||||
SciterNodeSetText: *const fn (hnode: HNode, text: [*]const u16, textLength: u32) callconv(.c) DomResult,
|
|
||||||
SciterNodeInsert: *const fn (hnode: HNode, where: NodeInsTarget, what: HNode) callconv(.c) DomResult,
|
|
||||||
SciterNodeRemove: *const fn (hnode: HNode, finalize: Bool) callconv(.c) DomResult,
|
|
||||||
SciterCreateTextNode: *const fn (text: [*]const u16, textLength: u32, phnode: *HNode) callconv(.c) DomResult,
|
|
||||||
SciterCreateCommentNode: *const fn (text: [*]const u16, textLength: u32, phnode: *HNode) callconv(.c) DomResult,
|
|
||||||
|
|
||||||
// --- Value API -----------------------------------------------------------
|
|
||||||
|
|
||||||
ValueInit: *const fn (pval: *Value) callconv(.c) u32,
|
|
||||||
ValueClear: *const fn (pval: *Value) callconv(.c) u32,
|
|
||||||
ValueCompare: *const fn (pval1: *const Value, pval2: *const Value) callconv(.c) u32,
|
|
||||||
ValueCopy: *const fn (pdst: *Value, psrc: *const Value) callconv(.c) u32,
|
|
||||||
ValueIsolate: *const fn (pdst: *Value) callconv(.c) u32,
|
|
||||||
ValueType: *const fn (pval: *const Value, pType: *u32, pUnits: *u32) callconv(.c) u32,
|
|
||||||
ValueStringData: *const fn (pval: *const Value, pChars: *[*]const u16, pNumChars: *u32) callconv(.c) u32,
|
|
||||||
ValueStringDataSet: *const fn (pval: *Value, chars: [*]const u16, numChars: u32, units: u32) callconv(.c) u32,
|
|
||||||
ValueIntData: *const fn (pval: *const Value, pData: *i32) callconv(.c) u32,
|
|
||||||
ValueIntDataSet: *const fn (pval: *Value, data: i32, type: u32, units: u32) callconv(.c) u32,
|
|
||||||
ValueInt64Data: *const fn (pval: *const Value, pData: *i64) callconv(.c) u32,
|
|
||||||
ValueInt64DataSet: *const fn (pval: *Value, data: i64, type: u32, units: u32) callconv(.c) u32,
|
|
||||||
ValueFloatData: *const fn (pval: *const Value, pData: *f64) callconv(.c) u32,
|
|
||||||
ValueFloatDataSet: *const fn (pval: *Value, data: f64, type: u32, units: u32) callconv(.c) u32,
|
|
||||||
ValueBinaryData: *const fn (pval: *const Value, pBytes: *[*]const u8, pnBytes: *u32) callconv(.c) u32,
|
|
||||||
ValueBinaryDataSet: *const fn (pval: *Value, pBytes: [*]const u8, nBytes: u32, type: u32, units: u32) callconv(.c) u32,
|
|
||||||
ValueElementsCount: *const fn (pval: *const Value, pn: *i32) callconv(.c) u32,
|
|
||||||
ValueNthElementValue: *const fn (pval: *const Value, n: i32, pretval: *Value) callconv(.c) u32,
|
|
||||||
ValueNthElementValueSet: *const fn (pval: *Value, n: i32, pval_to_set: *const Value) callconv(.c) u32,
|
|
||||||
ValueNthElementKey: *const fn (pval: *const Value, n: i32, pretval: *Value) callconv(.c) u32,
|
|
||||||
ValueEnumElements: *const fn (pval: *const Value, penum: *const KeyValueCallback, param: ?*anyopaque) callconv(.c) u32,
|
|
||||||
ValueSetValueToKey: *const fn (pval: *Value, pkey: *const Value, pval_to_set: *const Value) callconv(.c) u32,
|
|
||||||
ValueGetValueOfKey: *const fn (pval: *const Value, pkey: *const Value, pretval: *Value) callconv(.c) u32,
|
|
||||||
ValueToString: *const fn (pval: *Value, how: ValueStringCvtType) callconv(.c) u32,
|
|
||||||
ValueFromString: *const fn (pval: *Value, str: [*]const u16, strLength: u32, how: ValueStringCvtType) callconv(.c) u32,
|
|
||||||
ValueInvoke: *const fn (pval: *const Value, pthis: *Value, argc: u32, argv: *const Value, pretval: *Value, url: CWStr) callconv(.c) u32,
|
|
||||||
ValueNativeFunctorSet: *const fn (pval: *Value, pinvoke: *const NativeFunctorInvoke, prelease: *const NativeFunctorRelease, tag: *void) callconv(.c) u32,
|
|
||||||
ValueIsNativeFunctor: *const fn (pval: *const Value) callconv(.c) Bool,
|
|
||||||
|
|
||||||
// Used to be script VM API
|
|
||||||
|
|
||||||
reserved1: *anyopaque,
|
|
||||||
reserved2: *anyopaque,
|
|
||||||
reserved3: *anyopaque,
|
|
||||||
reserved4: *anyopaque,
|
|
||||||
|
|
||||||
SciterOpenArchive: *const fn (archiveData: [*]const u8, archiveDataLength: u32) callconv(.c) HSArchive,
|
|
||||||
SciterGetArchiveItem: *const fn (harc: HSArchive, path: CWStr, pdata: *[*]const u8, pdataLength: *u32) callconv(.c) Bool,
|
|
||||||
SciterCloseArchive: *const fn (harc: HSArchive) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterFireEvent: *const fn (evt: *const BehaviorEventParams, post: Bool, handled: *Bool) callconv(.c) DomResult,
|
|
||||||
|
|
||||||
SciterGetCallbackParam: *const fn (hwnd: HWindow) callconv(.c) ?*anyopaque,
|
|
||||||
SciterPostCallback: *const fn (hwnd: HWindow, wparam: isize, lparam: usize, timeoutms: u32) callconv(.c) isize,
|
|
||||||
|
|
||||||
GetSciterGraphicsAPI: *const fn () callconv(.c) *GraphicsAPI,
|
|
||||||
GetSciterRequestAPI: *const fn () callconv(.c) *RequestAPI,
|
|
||||||
|
|
||||||
/// IDXGISwapChain
|
|
||||||
SciterCreateOnDirectXWindow: *const fn (hwnd: HWindow, pSwapChain: *anyopaque) callconv(.c) Bool,
|
|
||||||
SciterRenderOnDirectXWindow: *const fn (hwnd: HWindow, elementToRenderOrNull: HElement, frontLayer: Bool) callconv(.c) Bool,
|
|
||||||
/// IDXGISurface
|
|
||||||
SciterRenderOnDirectXTexture: *const fn (hwnd: HWindow, elementToRenderOrNull: HElement, surface: *anyopaque) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterProcX: *const fn (hwnd: HWindow, pMsg: *XMsg) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterAtomValue: *const fn (name: CStr) callconv(.c) u64,
|
|
||||||
SciterAtomNameCB: *const fn (atomv: u64, rcv: *const StrReceiver, rcv_param: ?*anyopaque) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterSetGlobalAsset: *const fn (pass: *OmAsset) callconv(.c) Bool,
|
|
||||||
SciterGetElementAsset: *const fn (el: HElement, nameAtom: u64, ppass: *?*OmAsset) callconv(.c) DomResult,
|
|
||||||
|
|
||||||
SciterSetVariable: *const fn (hwndOrNull: HWindow, name: CStr, pvalToSet: *const Value) callconv(.c) u32,
|
|
||||||
SciterGetVariable: *const fn (hwndOrNull: HWindow, name: CStr, pvalToGet: *Value) callconv(.c) u32,
|
|
||||||
|
|
||||||
SciterElementUnwrap: *const fn (pval: *const Value, ppElement: *HElement) callconv(.c) u32,
|
|
||||||
SciterElementWrap: *const fn (pval: *Value, pElement: HElement) callconv(.c) u32,
|
|
||||||
|
|
||||||
SciterNodeUnwrap: *const fn (pval: *const Value, ppNode: *HNode) callconv(.c) u32,
|
|
||||||
SciterNodeWrap: *const fn (pval: *Value, pNode: HNode) callconv(.c) u32,
|
|
||||||
|
|
||||||
SciterReleaseGlobalAsset: *const fn (pass: *OmAsset) callconv(.c) Bool,
|
|
||||||
|
|
||||||
SciterExec: *const fn (appCmd: u32, p1: usize, p2: usize) callconv(.c) isize,
|
|
||||||
SciterWindowExec: *const fn (hwnd: HWindow, windowCmd: u32, p1: usize, p2: usize) callconv(.c) isize,
|
|
||||||
|
|
||||||
SciterEGLGetProcAddress: *const fn (procName: CStr) callconv(.c) ?*anyopaque,
|
|
||||||
SciterEGLSendEvent: *const fn (he: HElement, eventCode: u32, reason: usize) callconv(.c) DomResult,
|
|
||||||
SciterRequestAnimationFrameEvent: *const fn (he: HElement, eventCode: u32, reason: usize) callconv(.c) DomResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO These APIs are actually well-known structs with function pointers in
|
|
||||||
// them, which may provide useful functionality
|
|
||||||
|
|
||||||
pub const GraphicsAPI = opaque {};
|
|
||||||
pub const RequestAPI = opaque {};
|
|
||||||
BIN
packages/sciter/vendor/sciter.dll
(Stored with Git LFS)
vendored
BIN
packages/sciter/vendor/sciter.dll
(Stored with Git LFS)
vendored
Binary file not shown.
30
packages/vecmath/src/colors/ColorHdr.zig
Normal file
30
packages/vecmath/src/colors/ColorHdr.zig
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const vm = @import("../root.zig");
|
||||||
|
|
||||||
|
pub const ColorHdr = extern struct {
|
||||||
|
r: f16,
|
||||||
|
g: f16,
|
||||||
|
b: f16,
|
||||||
|
a: f16,
|
||||||
|
|
||||||
|
pub const Array = [4]f16;
|
||||||
|
|
||||||
|
pub const zero = init(0, 0, 0, 0);
|
||||||
|
pub const one = init(1, 1, 1, 1);
|
||||||
|
|
||||||
|
pub inline fn init(r: f16, g: f16, b: f16, a: f16) ColorHdr {
|
||||||
|
return .{ .r = r, .g = g, .b = b, .a = a };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn initArray(array: Array) ColorHdr {
|
||||||
|
return @bitCast(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn asArray(self: ColorHdr) Array {
|
||||||
|
return @bitCast(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format(self: ColorHdr, w: *std.io.Writer) !void {
|
||||||
|
try w.print("ColorHdr[{d}, {d}, {d}, {d}]", .{ self.r, self.g, self.b, self.a });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ const std = @import("std");
|
|||||||
// --- COLORS ------------------------------------------------------------------
|
// --- COLORS ------------------------------------------------------------------
|
||||||
|
|
||||||
pub const Color = @import("colors/Color.zig").Color;
|
pub const Color = @import("colors/Color.zig").Color;
|
||||||
|
pub const ColorHdr = @import("colors/ColorHdr.zig").ColorHdr;
|
||||||
|
|
||||||
// --- MATRICES ----------------------------------------------------------------
|
// --- MATRICES ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
9
packages/x11/build.zig
Normal file
9
packages/x11/build.zig
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const mod = b.addModule("x11", .{
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.linkSystemLibrary("X11", .{});
|
||||||
|
}
|
||||||
11
packages/x11/build.zig.zon
Normal file
11
packages/x11/build.zig.zon
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.{
|
||||||
|
.name = .x11,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.minimum_zig_version = "0.15.2",
|
||||||
|
.paths = .{
|
||||||
|
"src",
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
},
|
||||||
|
.fingerprint = 0x3220e772d0ef0e80,
|
||||||
|
}
|
||||||
3182
packages/x11/src/root.zig
Normal file
3182
packages/x11/src/root.zig
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user