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
|
||||
*.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", .{
|
||||
.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);
|
||||
}
|
||||
|
||||
@@ -66,3 +66,46 @@ pub const Dynamic = struct {
|
||||
@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 qoa = @import("qoa.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 ------------------------------------------------------------------
|
||||
|
||||
pub const Color = @import("colors/Color.zig").Color;
|
||||
pub const ColorHdr = @import("colors/ColorHdr.zig").ColorHdr;
|
||||
|
||||
// --- 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