hotwire haku2 into rkgk
really a bodge job right now and it crashes but it's a start
This commit is contained in:
parent
550227da34
commit
5de4f9d7c6
9 changed files with 178 additions and 71 deletions
|
@ -306,6 +306,24 @@ impl Defs {
|
||||||
panic!("image must be a subset of the current defs")
|
panic!("image must be a subset of the current defs")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialize_defs(&self) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
for def in &self.defs {
|
||||||
|
result.push_str(def);
|
||||||
|
result.push('\n');
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_tags(&self) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
for tag in &self.tags {
|
||||||
|
result.push_str(tag);
|
||||||
|
result.push('\n');
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub struct Compiler<'a> {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ClosureSpec {
|
pub struct ClosureSpec {
|
||||||
pub(crate) local_count: u8,
|
pub local_count: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Compiler<'a> {
|
impl<'a> Compiler<'a> {
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.root_module = mod,
|
.root_module = mod,
|
||||||
});
|
});
|
||||||
lib.pie = true;
|
lib.pie = true;
|
||||||
|
lib.bundle_compiler_rt = true;
|
||||||
b.installArtifact(lib);
|
b.installArtifact(lib);
|
||||||
|
|
||||||
const mod_wasm = b.createModule(.{
|
const mod_wasm = b.createModule(.{
|
||||||
|
|
|
@ -9,7 +9,11 @@ const Scratch = @import("scratch.zig");
|
||||||
const value = @import("value.zig");
|
const value = @import("value.zig");
|
||||||
const Vm = @import("vm.zig");
|
const Vm = @import("vm.zig");
|
||||||
|
|
||||||
const allocator = if (builtin.cpu.arch == .wasm32) std.heap.wasm_allocator else @import("allocator.zig").hostAllocator;
|
const allocator =
|
||||||
|
if (builtin.cpu.arch == .wasm32)
|
||||||
|
std.heap.wasm_allocator
|
||||||
|
else
|
||||||
|
@import("allocator.zig").hostAllocator;
|
||||||
|
|
||||||
// Scratch
|
// Scratch
|
||||||
|
|
||||||
|
@ -28,7 +32,9 @@ export fn haku2_scratch_reset(scratch: *Scratch) void {
|
||||||
// Limits
|
// Limits
|
||||||
|
|
||||||
export fn haku2_limits_new() ?*Vm.Limits {
|
export fn haku2_limits_new() ?*Vm.Limits {
|
||||||
return allocator.create(Vm.Limits) catch null;
|
const limits = allocator.create(Vm.Limits) catch return null;
|
||||||
|
limits.* = .{};
|
||||||
|
return limits;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn haku2_limits_destroy(limits: *Vm.Limits) void {
|
export fn haku2_limits_destroy(limits: *Vm.Limits) void {
|
||||||
|
@ -102,9 +108,15 @@ export fn haku2_vm_run_main(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn haku2_vm_has_cont(vm: *const Vm) bool {
|
||||||
|
if (vm.stack.len == 0) return false;
|
||||||
|
const top = vm.top();
|
||||||
|
return top == .ref and top.ref.* == .reticle;
|
||||||
|
}
|
||||||
|
|
||||||
export fn haku2_vm_is_dotter(vm: *const Vm) bool {
|
export fn haku2_vm_is_dotter(vm: *const Vm) bool {
|
||||||
if (vm.stack.len == 0) return false;
|
if (vm.stack.len == 0) return false;
|
||||||
const top = vm.stack[vm.stack_top];
|
const top = vm.top();
|
||||||
return top == .ref and top.ref.* == .reticle and top.ref.reticle == .dotter;
|
return top == .ref and top.ref.* == .reticle and top.ref.reticle == .dotter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
marker::{PhantomData, PhantomPinned},
|
marker::{PhantomData, PhantomPinned},
|
||||||
|
mem::forget,
|
||||||
ptr::{self, NonNull},
|
ptr::{self, NonNull},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ extern "C" {
|
||||||
code_len: usize,
|
code_len: usize,
|
||||||
local_count: u8,
|
local_count: u8,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
fn haku2_vm_has_cont(vm: *const VmC) -> bool;
|
||||||
fn haku2_vm_is_dotter(vm: *const VmC) -> bool;
|
fn haku2_vm_is_dotter(vm: *const VmC) -> bool;
|
||||||
fn haku2_vm_run_dotter(
|
fn haku2_vm_run_dotter(
|
||||||
vm: *mut VmC,
|
vm: *mut VmC,
|
||||||
|
@ -211,10 +213,38 @@ impl Drop for Defs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Code {
|
||||||
|
defs: Defs,
|
||||||
|
main_chunk: Vec<u8>,
|
||||||
|
main_local_count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Code {
|
||||||
|
/// Creates a new instance of `Code` from a valid vector of bytes.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This does not perform any validation, and there is no way to perform such
|
||||||
|
/// validation before constructing this. The bytecode must simply be valid, which is the case
|
||||||
|
/// for bytecode emitted directly by the compiler.
|
||||||
|
///
|
||||||
|
/// Untrusted bytecode should never ever be loaded under any circumstances.
|
||||||
|
pub unsafe fn new(defs: Defs, main_chunk: Vec<u8>, main_local_count: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
defs,
|
||||||
|
main_chunk,
|
||||||
|
main_local_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A VM that is ready to run and loaded with valid bytecode.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
scratch: Scratch,
|
scratch: Scratch,
|
||||||
raw: NonNull<VmC>,
|
code: Code,
|
||||||
|
inner: VmInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -236,17 +266,24 @@ pub struct Dotter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn new(scratch: Scratch, defs: &Defs, limits: &Limits) -> Self {
|
pub fn new(scratch: Scratch, code: Code, limits: &Limits) -> Self {
|
||||||
Self {
|
Self {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - Ownership of s is passed to the VM, so the VM cannot outlive the scratch space.
|
// - Ownership of scratch is passed to the VM, so the VM cannot outlive the scratch space.
|
||||||
// - The VM never gives you any references back, so this is safe to do.
|
// - The VM never gives you any references back, so this is safe to do.
|
||||||
// - The other arguments are only borrowed immutably for construction.
|
// - The other arguments are only borrowed immutably for construction.
|
||||||
raw: NonNull::new(unsafe {
|
inner: VmInner {
|
||||||
haku2_vm_new(scratch.raw.as_ptr(), defs.raw.as_ptr(), limits.raw.as_ptr())
|
raw: NonNull::new(unsafe {
|
||||||
})
|
haku2_vm_new(
|
||||||
.expect("out of memory"),
|
scratch.raw.as_ptr(),
|
||||||
|
code.defs.raw.as_ptr(),
|
||||||
|
limits.raw.as_ptr(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.expect("out of memory"),
|
||||||
|
},
|
||||||
scratch,
|
scratch,
|
||||||
|
code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,19 +292,14 @@ impl Vm {
|
||||||
///
|
///
|
||||||
/// Calling `begin` again during this process will work correctly, and result in another
|
/// Calling `begin` again during this process will work correctly, and result in another
|
||||||
/// continuation being stack on top of the old one---at the expense of a stack slot.
|
/// continuation being stack on top of the old one---at the expense of a stack slot.
|
||||||
///
|
pub fn begin(&mut self) -> Result<(), Exception> {
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The bytecode passed in must be valid, because bytecode validation is done on a best-effort
|
|
||||||
/// basis. Bytecode retrieved out of the compiler is guaranteed to be safe.
|
|
||||||
pub unsafe fn begin(&mut self, code: &[u8], local_count: u8) -> Result<(), Exception> {
|
|
||||||
let ok = unsafe {
|
let ok = unsafe {
|
||||||
haku2_vm_run_main(
|
haku2_vm_run_main(
|
||||||
self.raw.as_ptr(),
|
self.inner.raw.as_ptr(),
|
||||||
self.scratch.raw.as_ptr(),
|
self.scratch.raw.as_ptr(),
|
||||||
code.as_ptr(),
|
self.code.main_chunk.as_ptr(),
|
||||||
code.len(),
|
self.code.main_chunk.len(),
|
||||||
local_count,
|
self.code.main_local_count,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -277,9 +309,14 @@ impl Vm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether `cont()` can be called to run the next continuation.
|
||||||
|
pub fn has_cont(&self) -> bool {
|
||||||
|
unsafe { haku2_vm_has_cont(self.inner.raw.as_ptr()) }
|
||||||
|
}
|
||||||
|
|
||||||
fn is_dotter(&self) -> bool {
|
fn is_dotter(&self) -> bool {
|
||||||
// SAFETY: The pointer is valid.
|
// SAFETY: The pointer is valid.
|
||||||
unsafe { haku2_vm_is_dotter(self.raw.as_ptr()) }
|
unsafe { haku2_vm_is_dotter(self.inner.raw.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns how the VM should continue executing after the previous execution.
|
/// Returns how the VM should continue executing after the previous execution.
|
||||||
|
@ -291,12 +328,12 @@ impl Vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the current scribble on top of the stack.
|
/// Renders the current scribble on top of the stack.
|
||||||
/// If the value on top is not a scribble, throws an exception (indicated by the return type.)
|
/// If the value on top is not a scribble, throws an exception.
|
||||||
///
|
///
|
||||||
/// The rendering is performed by calling into the [`Canvas`] trait.
|
/// The rendering is performed by calling into the [`Canvas`] trait.
|
||||||
pub fn render(&mut self, canvas: &mut dyn Canvas, max_depth: usize) -> Result<(), Exception> {
|
pub fn render(&mut self, canvas: &mut dyn Canvas, max_depth: usize) -> Result<(), Exception> {
|
||||||
let mut wrapped = CanvasC { inner: canvas };
|
let mut wrapped = CanvasC { inner: canvas };
|
||||||
let ok = unsafe { haku2_render(self.raw.as_ptr(), &mut wrapped, max_depth) };
|
let ok = unsafe { haku2_render(self.inner.raw.as_ptr(), &mut wrapped, max_depth) };
|
||||||
if ok {
|
if ok {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -308,7 +345,7 @@ impl Vm {
|
||||||
/// Returns `None` if there's no exception.
|
/// Returns `None` if there's no exception.
|
||||||
pub fn exception(&self) -> Option<Exception> {
|
pub fn exception(&self) -> Option<Exception> {
|
||||||
// SAFETY: The pointer passed to this function is valid.
|
// SAFETY: The pointer passed to this function is valid.
|
||||||
let len = unsafe { haku2_vm_exception_len(self.raw.as_ptr()) };
|
let len = unsafe { haku2_vm_exception_len(self.inner.raw.as_ptr()) };
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -316,12 +353,24 @@ impl Vm {
|
||||||
let mut buffer = vec![0; len];
|
let mut buffer = vec![0; len];
|
||||||
// SAFETY: The length of the buffer is as indicated by haku2_vm_exception_len.
|
// SAFETY: The length of the buffer is as indicated by haku2_vm_exception_len.
|
||||||
unsafe {
|
unsafe {
|
||||||
haku2_vm_exception_render(self.raw.as_ptr(), buffer.as_mut_ptr());
|
haku2_vm_exception_render(self.inner.raw.as_ptr(), buffer.as_mut_ptr());
|
||||||
}
|
}
|
||||||
Some(Exception {
|
Some(Exception {
|
||||||
message: String::from_utf8_lossy(&buffer).into_owned(),
|
message: String::from_utf8_lossy(&buffer).into_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take the `Scratch` out of the VM for reuse in another one.
|
||||||
|
/// The scratch memory will be reset (no bytes will be consumed.)
|
||||||
|
pub fn into_scratch(self) -> Scratch {
|
||||||
|
let Vm {
|
||||||
|
mut scratch,
|
||||||
|
code: _,
|
||||||
|
inner: _,
|
||||||
|
} = self;
|
||||||
|
scratch.reset();
|
||||||
|
scratch
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContDotter<'_> {
|
impl ContDotter<'_> {
|
||||||
|
@ -334,7 +383,7 @@ impl ContDotter<'_> {
|
||||||
|
|
||||||
let ok = unsafe {
|
let ok = unsafe {
|
||||||
haku2_vm_run_dotter(
|
haku2_vm_run_dotter(
|
||||||
self.vm.raw.as_ptr(),
|
self.vm.inner.raw.as_ptr(),
|
||||||
self.vm.scratch.raw.as_ptr(),
|
self.vm.scratch.raw.as_ptr(),
|
||||||
from_x,
|
from_x,
|
||||||
from_y,
|
from_y,
|
||||||
|
@ -351,7 +400,12 @@ impl ContDotter<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Vm {
|
#[derive(Debug)]
|
||||||
|
struct VmInner {
|
||||||
|
raw: NonNull<VmC>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VmInner {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// SAFETY: The pointer passed is non-null.
|
// SAFETY: The pointer passed is non-null.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -54,6 +54,6 @@ fn renderRec(vm: *Vm, canvas: *Canvas, val: Value, depth: usize, max_depth: usiz
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(vm: *Vm, canvas: *Canvas, max_depth: usize) !void {
|
pub fn render(vm: *Vm, canvas: *Canvas, max_depth: usize) !void {
|
||||||
const val = try vm.pop();
|
const val = vm.stack[vm.stack_top - 1];
|
||||||
try renderRec(vm, canvas, val, 0, max_depth);
|
try renderRec(vm, canvas, val, 0, max_depth);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,14 @@ pub fn pop(vm: *Vm) Error!Value {
|
||||||
return vm.stack[vm.stack_top];
|
return vm.stack[vm.stack_top];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn top(vm: *const Vm) Value {
|
||||||
|
if (vm.stack_top > 0) {
|
||||||
|
return vm.stack[vm.stack_top - 1];
|
||||||
|
} else {
|
||||||
|
return .nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pushCall(vm: *Vm, frame: CallFrame) Error!void {
|
pub fn pushCall(vm: *Vm, frame: CallFrame) Error!void {
|
||||||
if (vm.call_stack_top >= vm.call_stack.len) {
|
if (vm.call_stack_top >= vm.call_stack.len) {
|
||||||
return vm.throw("too much recursion", .{});
|
return vm.throw("too much recursion", .{});
|
||||||
|
|
|
@ -371,47 +371,7 @@ impl SessionLoop {
|
||||||
|
|
||||||
// TODO: Auto save. This'll need us to compute which chunks will be affected
|
// TODO: Auto save. This'll need us to compute which chunks will be affected
|
||||||
// by the interactions.
|
// by the interactions.
|
||||||
} // wall::EventKind::SetBrush { brush } => {
|
}
|
||||||
// // SetBrush is not dropped because it is a very important event.
|
|
||||||
// _ = self
|
|
||||||
// .render_commands_tx
|
|
||||||
// .send(RenderCommand::SetBrush {
|
|
||||||
// brush: brush.clone(),
|
|
||||||
// })
|
|
||||||
// .await;
|
|
||||||
// }
|
|
||||||
// wall::EventKind::Plot { points } => {
|
|
||||||
// let chunks_to_modify: Vec<_> =
|
|
||||||
// chunks_to_modify(&self.wall, points).into_iter().collect();
|
|
||||||
// match self.chunk_images.load(chunks_to_modify.clone()).await {
|
|
||||||
// Ok(_) => {
|
|
||||||
// // We drop commands if we take too long to render instead of lagging
|
|
||||||
// // the WebSocket thread.
|
|
||||||
// // Theoretically this will yield much better responsiveness, but it _will_
|
|
||||||
// // result in some visual glitches if we're getting bottlenecked.
|
|
||||||
// let (done_tx, done_rx) = oneshot::channel();
|
|
||||||
// let send_result =
|
|
||||||
// self.render_commands_tx.try_send(RenderCommand::Plot {
|
|
||||||
// points: points.clone(),
|
|
||||||
// done: done_tx,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if send_result.is_err() {
|
|
||||||
// info!(
|
|
||||||
// ?points,
|
|
||||||
// "render thread is overloaded, dropping request to draw points"
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let auto_save = Arc::clone(&self.auto_save);
|
|
||||||
// tokio::spawn(async move {
|
|
||||||
// _ = done_rx.await;
|
|
||||||
// auto_save.request(chunks_to_modify).await;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Err(err) => error!(?err, "while loading chunks for render command"),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.wall.event(wall::Event {
|
self.wall.event(wall::Event {
|
||||||
|
@ -516,6 +476,8 @@ impl SessionLoop {
|
||||||
|
|
||||||
Interaction::Dotter { from, to, num } => {
|
Interaction::Dotter { from, to, num } => {
|
||||||
if brush_ok {
|
if brush_ok {
|
||||||
|
jumpstart_trampoline2(&mut haku);
|
||||||
|
|
||||||
if let Some(tramp) = jumpstart_trampoline(&mut haku, &mut trampoline) {
|
if let Some(tramp) = jumpstart_trampoline(&mut haku, &mut trampoline) {
|
||||||
let cont = haku.cont(tramp);
|
let cont = haku.cont(tramp);
|
||||||
if cont == Cont::Dotter {
|
if cont == Cont::Dotter {
|
||||||
|
@ -598,6 +560,7 @@ fn chunks_to_modify(
|
||||||
|
|
||||||
chunks
|
chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jumpstart_trampoline<'a>(
|
fn jumpstart_trampoline<'a>(
|
||||||
haku: &mut Haku,
|
haku: &mut Haku,
|
||||||
trampoline: &'a mut Option<Trampoline>,
|
trampoline: &'a mut Option<Trampoline>,
|
||||||
|
@ -608,6 +571,14 @@ fn jumpstart_trampoline<'a>(
|
||||||
trampoline.as_mut()
|
trampoline.as_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn jumpstart_trampoline2(haku: &mut Haku) {
|
||||||
|
if !haku.has_cont2() {
|
||||||
|
if let Err(e) = haku.eval_brush2() {
|
||||||
|
error!("eval_brush2: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(wall, haku, value))]
|
#[instrument(skip(wall, haku, value))]
|
||||||
fn draw_to_chunks(
|
fn draw_to_chunks(
|
||||||
wall: &Wall,
|
wall: &Wall,
|
||||||
|
|
|
@ -55,6 +55,8 @@ pub struct Haku {
|
||||||
vm: Vm,
|
vm: Vm,
|
||||||
vm_image: VmImage,
|
vm_image: VmImage,
|
||||||
|
|
||||||
|
vm2: Option<haku2::Vm>,
|
||||||
|
|
||||||
brush: Option<(ChunkId, ClosureSpec)>,
|
brush: Option<(ChunkId, ClosureSpec)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +90,7 @@ impl Haku {
|
||||||
defs_image,
|
defs_image,
|
||||||
vm,
|
vm,
|
||||||
vm_image,
|
vm_image,
|
||||||
|
vm2: None,
|
||||||
brush: None,
|
brush: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,9 +143,31 @@ impl Haku {
|
||||||
bail!("diagnostics were emitted");
|
bail!("diagnostics were emitted");
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk_id = self.system.add_chunk(chunk).context("too many chunks")?;
|
let chunk_id = self
|
||||||
|
.system
|
||||||
|
.add_chunk(chunk.clone())
|
||||||
|
.context("too many chunks")?;
|
||||||
self.brush = Some((chunk_id, closure_spec));
|
self.brush = Some((chunk_id, closure_spec));
|
||||||
|
|
||||||
|
// haku2 setup
|
||||||
|
{
|
||||||
|
let scratch = self
|
||||||
|
.vm2
|
||||||
|
.take()
|
||||||
|
.map(|vm| vm.into_scratch())
|
||||||
|
.unwrap_or_else(|| haku2::Scratch::new(self.limits.memory));
|
||||||
|
let defs = haku2::Defs::parse(&self.defs.serialize_defs(), &self.defs.serialize_tags());
|
||||||
|
// SAFETY: The code is fresh out of the compiler oven, so it is guaranteed to be valid.
|
||||||
|
// Well, more or less. There may lurk bugs.
|
||||||
|
let code = unsafe { haku2::Code::new(defs, chunk.bytecode, closure_spec.local_count) };
|
||||||
|
let limits = haku2::Limits::new(haku2::LimitsSpec {
|
||||||
|
stack_capacity: self.limits.stack_capacity,
|
||||||
|
call_stack_capacity: self.limits.call_stack_capacity,
|
||||||
|
fuel: self.limits.fuel as u32,
|
||||||
|
});
|
||||||
|
self.vm2 = Some(haku2::Vm::new(scratch, code, &limits))
|
||||||
|
}
|
||||||
|
|
||||||
info!("brush set successfully");
|
info!("brush set successfully");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -170,6 +195,16 @@ impl Haku {
|
||||||
Ok(scribble)
|
Ok(scribble)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), err(level = Level::INFO))]
|
||||||
|
pub fn eval_brush2(&mut self) -> eyre::Result<()> {
|
||||||
|
let vm = self
|
||||||
|
.vm2
|
||||||
|
.as_mut()
|
||||||
|
.ok_or_eyre("brush is not compiled and ready to be used")?;
|
||||||
|
vm.begin().context("an exception occurred during begin()")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, pixmap, value, translation), err(level = Level::INFO))]
|
#[instrument(skip(self, pixmap, value, translation), err(level = Level::INFO))]
|
||||||
pub fn render_value(
|
pub fn render_value(
|
||||||
&self,
|
&self,
|
||||||
|
@ -194,6 +229,14 @@ impl Haku {
|
||||||
trampoline.cont(&self.vm)
|
trampoline.cont(&self.vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_cont2(&mut self) -> bool {
|
||||||
|
self.vm2.as_mut().expect("VM is not started").has_cont()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cont2(&mut self) -> haku2::Cont<'_> {
|
||||||
|
self.vm2.as_mut().expect("VM is not started").cont()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dotter(
|
pub fn dotter(
|
||||||
&mut self,
|
&mut self,
|
||||||
trampoline: &mut Trampoline,
|
trampoline: &mut Trampoline,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue