feat(zig): native Arboricx bundle parser and C ABI
This commit is contained in:
128
ext/zig/src/reduce.zig
Normal file
128
ext/zig/src/reduce.zig
Normal file
@@ -0,0 +1,128 @@
|
||||
const std = @import("std");
|
||||
const tree = @import("tree.zig");
|
||||
const Arena = @import("arena.zig").Arena;
|
||||
|
||||
pub const ReduceError = error{
|
||||
FuelExhausted,
|
||||
InvalidApply,
|
||||
OutOfMemory,
|
||||
};
|
||||
|
||||
/// Reduce a term to weak head normal form.
|
||||
pub fn reduce(root: u32, arena: *Arena, fuel: u64) ReduceError!u32 {
|
||||
var remaining = fuel;
|
||||
return try whnf(root, arena, &remaining);
|
||||
}
|
||||
|
||||
fn whnf(term: u32, arena: *Arena, fuel: *u64) ReduceError!u32 {
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
var current = term;
|
||||
|
||||
while (true) {
|
||||
switch (arena.get(current).*) {
|
||||
.leaf, .stem, .fork => return current,
|
||||
.app => |app| {
|
||||
const orig = current;
|
||||
const func_idx = app.func;
|
||||
const arg_idx = app.arg;
|
||||
|
||||
// Reduce function to WHNF
|
||||
const f = try whnf(func_idx, arena, fuel);
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
|
||||
switch (arena.get(f).*) {
|
||||
// apply Leaf b = Stem b
|
||||
.leaf => {
|
||||
arena.get(orig).* = .{ .stem = .{ .child = arg_idx } };
|
||||
return orig;
|
||||
},
|
||||
// apply (Stem a) b = Fork a b
|
||||
.stem => |s| {
|
||||
const a = s.child;
|
||||
arena.get(orig).* = .{ .fork = .{ .left = a, .right = arg_idx } };
|
||||
return orig;
|
||||
},
|
||||
.fork => |fork_f| {
|
||||
const left_idx = fork_f.left;
|
||||
const right_idx = fork_f.right;
|
||||
|
||||
// Reduce left child of Fork
|
||||
const left = try whnf(left_idx, arena, fuel);
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
|
||||
switch (arena.get(left).*) {
|
||||
// apply (Fork Leaf a) _ = a
|
||||
.leaf => {
|
||||
const result = try whnf(right_idx, arena, fuel);
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
if (orig != result) {
|
||||
arena.get(orig).* = arena.get(result).*;
|
||||
}
|
||||
return orig;
|
||||
},
|
||||
// apply (Fork (Stem a) b) c = (a c) (b c)
|
||||
.stem => |s| {
|
||||
const a = s.child;
|
||||
const inner1 = try arena.alloc(.{ .app = .{ .func = a, .arg = arg_idx } });
|
||||
const inner2 = try arena.alloc(.{ .app = .{ .func = right_idx, .arg = arg_idx } });
|
||||
arena.get(orig).* = .{ .app = .{ .func = inner1, .arg = inner2 } };
|
||||
current = orig;
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
continue;
|
||||
},
|
||||
.fork => {
|
||||
// Reduce argument
|
||||
const arg = try whnf(arg_idx, arena, fuel);
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
|
||||
switch (arena.get(arg).*) {
|
||||
// apply (Fork (Fork a b) c) Leaf = a
|
||||
.leaf => {
|
||||
const a_idx = arena.get(left).fork.left;
|
||||
const result = try whnf(a_idx, arena, fuel);
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
if (orig != result) {
|
||||
arena.get(orig).* = arena.get(result).*;
|
||||
}
|
||||
return orig;
|
||||
},
|
||||
// apply (Fork (Fork a b) c) (Stem u) = b u
|
||||
.stem => |s| {
|
||||
const b_idx = arena.get(left).fork.right;
|
||||
const u = s.child;
|
||||
arena.get(orig).* = .{ .app = .{ .func = b_idx, .arg = u } };
|
||||
current = orig;
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
continue;
|
||||
},
|
||||
// apply (Fork (Fork a b) c) (Fork u v) = (c u) v
|
||||
.fork => |arg_fork| {
|
||||
const c_idx = right_idx;
|
||||
const u = arg_fork.left;
|
||||
const v = arg_fork.right;
|
||||
const inner = try arena.alloc(.{ .app = .{ .func = c_idx, .arg = u } });
|
||||
arena.get(orig).* = .{ .app = .{ .func = inner, .arg = v } };
|
||||
current = orig;
|
||||
if (fuel.* == 0) return error.FuelExhausted;
|
||||
fuel.* -= 1;
|
||||
continue;
|
||||
},
|
||||
.app => return error.InvalidApply,
|
||||
}
|
||||
},
|
||||
.app => return error.InvalidApply,
|
||||
}
|
||||
},
|
||||
.app => return error.InvalidApply,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user