Skip to documentation
SLOP

tiny.pluck.runtime

Reference tiny.pluck runtime

Defined in tiny.pluck.

API (97)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callstiny.pluckruntime
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callersruntime.ClosureisSelfLoopruntime.Envdeinitruntime.Closuredeinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersruntime.ClosureisSelfLoopruntime.Enveqlruntime.Envtailruntime.Closureeql
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callersruntimeClosureruntime.Closureformat
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsNo direct callersruntime.Envlenruntime.Closurehash
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsNo direct callsprivate sourcelib.pluck.src.evaluatorcompileAbstest sourcelib.pluck.src.runtimetest: closure creationruntime.Closureinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsruntime.Closuredeinitruntime.Closureeqltest sourcelib.pluck.src.runtimetest: closure creationruntime.Envfirstruntime.EnvisEmptyruntime.ClosureisSelfLoop
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.pluck.src.evaluatorcompileYruntime.ClosuremakeSelfLoop
Static calls · unresolved targets: 1 · external targets: 3.
Called byCallsNo direct callsruntime.Closuredeinitruntime.LazyEnumeratorThunkdeinitWithEnvruntime.LazyKCThunkdeinitWithEnvruntime.Envdeinit
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callsruntime.Closureeqlruntime.Enveql
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsruntime.ClosureisSelfLoopruntime.Envfirst
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsruntime.EnvConsgetruntime.Envget
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callsruntime.ClosureisSelfLoopruntime.EnvisEmpty
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsruntime.Closurehashruntime.Envlen
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callerstiny.choirbackends.artifact.Symboldeinitruntime.EnvparseEnv
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsNo direct callsruntime.Closureeqlruntime.Envtail
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersruntime.Envgetruntime.EnvConsget
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsevaluatorcombineIntDistsprivate sourcelib.pluck.src.evaluatorcompileMkIntprivate sourcelib.pluck.src.evaluatorcreateWeightedIntDisttest sourcelib.pluck.src.evaluatortest: combineIntDists - combines two ...test sourcelib.pluck.src.evaluatortest: enumerateIntDist - deterministi...+2 moreruntime.IntDistinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsruntime.LazyEnumeratorThunkdeinitWithEnvruntime.LazyEnumeratorThunkdeinit
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersruntime.Envdeinitruntime.LazyEnumeratorThunkdeinitruntime.LazyEnumeratorThunkdeinitWithEnv
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersruntimeLazyEnumeratorThunkruntime.LazyEnumeratorThunkformat
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callerstiny.sysenvgetruntime.LazyEnumeratorThunkinit
Static calls · unresolved targets: 0 · external targets: 4.
Called byCallsNo direct callstest sourcelib.pluck.src.evaluatortest: ThunkRegistry basic operationstest sourcelib.pluck.src.evaluatortest: ThunkRegistry refineVariable re...test sourcelib.pluck.src.profiling.internal.incrementaltest: BENCHMARK: ThunkRegistry refine...runtime.LazyKCThunkdeinitWithEnvruntime.LazyKCThunkUnioninitruntime.LazyKCThunkdeinit
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callersruntime.Envdeinitruntime.LazyKCThunkdeinitruntime.LazyKCThunkdeinitWithEnv
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersruntimeLazyKCThunkruntime.LazyKCThunkformat
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsevaluatormakeThunktest sourcelib.pluck.src.evaluatortest: ThunkRegistry basic operationstest sourcelib.pluck.src.evaluatortest: ThunkRegistry refineVariable re...test sourcelib.pluck.src.profiling.internal.incrementaltest: BENCHMARK: ThunkRegistry refine...test sourcelib.pluck.src.toplevel.querytest: query thunk cache clearing drop...tiny.sysenvgetruntime.LazyKCThunkinit
Static calls · unresolved targets: 0 · external targets: 4.
Called byCallsevaluatorjoinMonadruntime.LazyKCThunkdeinitruntime.LazyKCThunkUnioninit
Static calls · unresolved targets: 5 · external targets: 6.
Called byCallsNo direct callsprivate sourcelib.pluck.src.evaluatorextractListForcingThunksruntime.RuntimeValuedeinit
Static calls · unresolved targets: 0 · external targets: 5.
Called byCallsNo direct callersruntimeIntDistruntimeLazyKCThunkruntime.RuntimeValuemaybeNatruntime.RuntimeValueformat
Static calls · unresolved targets: 3 · external targets: 2.
Called byCallsNo direct callsprivate sourcelib.pluck.src.evaluatorcompileAbsprivate sourcelib.pluck.src.evaluatorcompileYruntime.RuntimeValueinitClosure
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsprivate sourcelib.pluck.src.evaluator.ConfigPrependerprependprivate sourcelib.pluck.src.evaluator.GetArgsContinuationcontprivate sourcelib.pluck.src.evaluator.PBoolContinuationcontprivate sourcelib.pluck.src.evaluatorcompileConstructprivate sourcelib.pluck.src.evaluatorcompileGetConfig+18 moreruntime.RuntimeValueinitConstructed
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate sourcelib.pluck.src.evaluator.CompileFlipContinuationcontprivate sourcelib.pluck.src.evaluator.IntDistEqSecondContin...contprivate sourcelib.pluck.src.evaluator.NativeEqSecondContinu...contprivate sourcelib.pluck.src.evaluatorcompileGetConfigprivate sourcelib.pluck.src.evaluatorevaluateLazyKCThunk+3 moreruntime.RuntimeValueinitConstructedruntime.RuntimeValueinitFalse
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.pluck.src.evaluator.CompileAppContinuationcontprivate sourcelib.pluck.src.evaluatorcompileConstructprivate sourcelib.pluck.src.evaluatorcompileDefinedtest sourcelib.pluck.src.evaluatortest: joinMonad collapses constructor...test sourcelib.pluck.src.evaluatortest: joinMonad collapses list constr...+2 moreruntime.RuntimeValueinitLazyKCThunk
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsevaluatorjoinMonadruntime.RuntimeValueinitLazyKCThunkUnion
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsevaluatorenumerateIntDistprivate sourcelib.pluck.src.evaluator.ConfigPrependerprependprivate sourcelib.pluck.src.evaluator.FloatBinopSecondConti...contprivate sourcelib.pluck.src.evaluator.GetConstructorContinu...contprivate sourcelib.pluck.src.evaluator.PBoolContinuationcont+13 moreruntime.RuntimeValueinitNative
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate sourcelib.pluck.src.evaluator.CompileFlipContinuationcontprivate sourcelib.pluck.src.evaluator.IntDistEqSecondContin...contprivate sourcelib.pluck.src.evaluator.NativeEqSecondContinu...contprivate sourcelib.pluck.src.evaluatorcompileGetConfigprivate sourcelib.pluck.src.evaluatorevaluateLazyKCThunk+6 moreruntime.RuntimeValueinitConstructedruntime.RuntimeValueinitTrue
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersruntime.RuntimeValueinitConstructedruntime.RuntimeValueinitUnit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsruntimefromValueruntime.RuntimeValueisThunk
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsruntime.RuntimeValueformatruntime.RuntimeValuemaybeNat
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callstest sourcelib.pluck.src.runtimetest: state varsruntime.StateVarsexhausted
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.pluck.src.runtimetest: state varsruntime.StateVarsinit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.pluck.src.runtimetest: state varsruntime.StateVarsinitWithFuel
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersruntimefindFirstThunkIntoruntimefindFirstThunk
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsevaluatorinferFullDistributionruntimefindFirstThunkprivate sourcelib.pluck.src.runtimefindFirstThunkInnerruntimefindFirstThunkInto
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersruntime.RuntimeValueisThunkruntimefromValue
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callsevaluatorinferFullDistributionruntimegetValueAtPath
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersruntime.RuntimeValueinitConstructedruntimepluckList
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallstest sourcelib.pluck.src.runtimetest: runtime value bounded nat conve...test sourcelib.pluck.src.runtimetest: runtime value nat conversiontest sourcelib.pluck.src.toplevel.querytest: weightedResultsToQueryResult me...runtime.RuntimeValueinitConstructedruntimepluckNat
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsevaluatorinferFullDistributionruntime.RuntimeValueinitConstructedruntimereplaceAtPath
Static calls · unresolved targets: 0 · external targets: 2.

Source: lib/pluck/src/root.zig:21

zig
pub const runtime = @import("runtime.zig");

Source: lib/pluck/src/runtime.zig

zig
const std = @import("std");const Allocator = std.mem.Allocator;const pexpr = @import("pexpr.zig");const PExpr = pexpr.PExpr;const Symbol = pexpr.Symbol;const bdd = @import("bdd.zig");const Bdd = bdd.Bdd;pub const Env = union(enum) {    cons: *EnvCons,    nil: void,    const Self = @This();    pub const empty: Self = .nil;    pub fn get(self: Self, name: Symbol) ?*RuntimeValue {        return switch (self) {            .cons => |c| c.get(name),            .nil => null,        };    }    pub fn tail(self: Self) ?Self {        return switch (self) {            .cons => |c| c.tail,            .nil => null,        };    }    pub fn first(self: Self) ?*RuntimeValue {        return switch (self) {            .cons => |c| c.val,            .nil => null,        };    }    pub fn firstName(self: Self) ?Symbol {        return switch (self) {            .cons => |c| c.name,            .nil => null,        };    }    pub fn isEmpty(self: Self) bool {        return self == .nil;    }    pub fn len(self: Self) usize {        return switch (self) {            .cons => |c| 1 + c.tail.len(),            .nil => 0,        };    }    pub fn extend(self: Self, allocator: Allocator, name: Symbol, val: *RuntimeValue) !Self {        const cons = try allocator.create(EnvCons);        cons.* = EnvCons{            .name = name,            .val = val,            .tail = self,        };        return Self{ .cons = cons };    }    pub fn deinit(self: Self, allocator: Allocator) void {        switch (self) {            .cons => |c| {                c.tail.deinit(allocator);                allocator.destroy(c);            },            .nil => {},        }    }    pub fn parseEnv(self: Self, allocator: Allocator) ![]Symbol {        var names: std.ArrayList(Symbol) = .empty;        errdefer names.deinit(allocator);        var current = self;        while (current != .nil) {            const cons = current.cons;            try names.append(allocator, cons.name);            current = cons.tail;        }        return names.toOwnedSlice(allocator);    }    pub fn format(        self: Self,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        _ = fmt;        _ = options;        try writer.writeAll("[");        var current = self;        var first_item = true;        while (current != .nil) {            if (!first_item) try writer.writeAll(", ");            const cons = current.cons;            try writer.print("{s}={}", .{ cons.name, cons.val });            current = cons.tail;            first_item = false;        }        try writer.writeAll("]");    }    pub fn eql(self: Self, other: Self) bool {        var a = self;        var b = other;        while (true) {            switch (a) {                .nil => return b == .nil,                .cons => |ac| {                    switch (b) {                        .nil => return false,                        .cons => |bc| {                            if (!std.mem.eql(u8, ac.name, bc.name)) return false;                            if (!ac.val.eql(bc.val)) return false;                            a = ac.tail;                            b = bc.tail;                        },                    }                },            }        }    }    pub fn hash(self: Self) u64 {        var h = std.hash.Wyhash.init(0);        var current = self;        while (current != .nil) {            const cons = current.cons;            h.update(cons.name);            h.update(std.mem.asBytes(&cons.val.hash()));            current = cons.tail;        }        return h.final();    }};pub const EnvCons = struct {    name: Symbol,    val: *RuntimeValue,    tail: Env,    pub fn get(self: *EnvCons, name: Symbol) ?*RuntimeValue {        if (std.mem.eql(u8, self.name, name)) {            return self.val;        }        return self.tail.get(name);    }};pub const IntDist = struct {    bits: []Bdd,    pub fn init(bits: []Bdd) IntDist {        return IntDist{ .bits = bits };    }    pub fn eql(self: IntDist, other: IntDist, manager: *@import("bdd.zig").Manager) Allocator.Error!Bdd {        if (self.bits.len != other.bits.len) {            return Bdd.FALSE;        }        var result = Bdd.TRUE;        for (self.bits, other.bits) |a, b| {            result = try manager.bddAnd(result, try manager.bddIff(a, b));            if (result.isFalse()) {                return Bdd.FALSE;            }        }        return result;    }    pub fn format(        self: IntDist,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        _ = fmt;        _ = options;        try writer.print("IntDist{{{d}}}", .{self.bits.len});    }};pub const NativeValueData = union(enum) {    int: i64,    float: f64,    symbol: Symbol,    bool_val: bool,    pexpr: *PExpr,    int_dist: IntDist,    pub fn eql(self: NativeValueData, other: NativeValueData) bool {        if (@as(std.meta.Tag(NativeValueData), self) != @as(std.meta.Tag(NativeValueData), other)) {            return false;        }        return switch (self) {            .int => |i| i == other.int,            .float => |f| f == other.float,            .symbol => |s| std.mem.eql(u8, s, other.symbol),            .bool_val => |b| b == other.bool_val,            .pexpr => |p| p == other.pexpr,            .int_dist => |d| {                if (d.bits.len != other.int_dist.bits.len) return false;                for (d.bits, other.int_dist.bits) |a, b| {                    if (a.toRaw() != b.toRaw()) return false;                }                return true;            },        };    }    pub fn hash(self: NativeValueData) u64 {        var h = std.hash.Wyhash.init(0);        h.update(std.mem.asBytes(&@as(u8, @backingInt(self))));        switch (self) {            .int => |i| h.update(std.mem.asBytes(&i)),            .float => |f| h.update(std.mem.asBytes(&f)),            .symbol => |s| h.update(s),            .bool_val => |b| h.update(std.mem.asBytes(&b)),            .pexpr => |p| h.update(std.mem.asBytes(&@intFromPtr(p))),            .int_dist => |d| {                for (d.bits) |bit| {                    h.update(std.mem.asBytes(&bit.toRaw()));                }            },        }        return h.final();    }    pub fn format(        self: NativeValueData,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        _ = fmt;        _ = options;        switch (self) {            .int => |i| try writer.print("{d}", .{i}),            .float => |f| try writer.print("{d}", .{f}),            .symbol => |s| try writer.print("'{s}", .{s}),            .bool_val => |b| try writer.print("{}", .{b}),            .pexpr => |p| try writer.print("{}", .{p}),            .int_dist => |d| try writer.print("{}", .{d}),        }    }};pub const ConstructedValue = struct {    constructor: Symbol,    args: []*RuntimeValue,    pub fn eql(self: ConstructedValue, other: ConstructedValue) bool {        if (!std.mem.eql(u8, self.constructor, other.constructor)) return false;        if (self.args.len != other.args.len) return false;        for (self.args, other.args) |a, b| {            if (!a.eql(b)) return false;        }        return true;    }    pub fn hash(self: ConstructedValue) u64 {        var h = std.hash.Wyhash.init(0);        h.update(self.constructor);        for (self.args) |arg| {            h.update(std.mem.asBytes(&arg.hash()));        }        return h.final();    }};pub const RuntimeValue = struct {    data: Data,    pub const Data = union(enum) {        native: NativeValueData,        constructed: ConstructedValue,        closure: *Closure,        lazy_kc_thunk: *LazyKCThunk,        lazy_kc_thunk_union: *LazyKCThunkUnion,        lazy_enum_thunk: *LazyEnumeratorThunk,    };    const Self = @This();    pub fn initNative(allocator: Allocator, native: NativeValueData) !*Self {        const val = try allocator.create(Self);        val.* = Self{ .data = .{ .native = native } };        return val;    }    pub fn initConstructed(allocator: Allocator, constructor: Symbol, args: []*Self) !*Self {        const val = try allocator.create(Self);        val.* = Self{ .data = .{ .constructed = .{ .constructor = constructor, .args = args } } };        return val;    }    pub fn initTrue(allocator: Allocator) !*Self {        return initConstructed(allocator, "True", &[_]*Self{});    }    pub fn initFalse(allocator: Allocator) !*Self {        return initConstructed(allocator, "False", &[_]*Self{});    }    pub fn initUnit(allocator: Allocator) !*Self {        return initConstructed(allocator, "Unit", &[_]*Self{});    }    pub fn initClosure(allocator: Allocator, closure: *Closure) !*Self {        const val = try allocator.create(Self);        val.* = Self{ .data = .{ .closure = closure } };        return val;    }    pub fn initLazyKCThunk(allocator: Allocator, thunk: *LazyKCThunk) !*Self {        const val = try allocator.create(Self);        val.* = Self{ .data = .{ .lazy_kc_thunk = thunk } };        return val;    }    pub fn initLazyKCThunkUnion(allocator: Allocator, thunk_union: *LazyKCThunkUnion) !*Self {        const val = try allocator.create(Self);        val.* = Self{ .data = .{ .lazy_kc_thunk_union = thunk_union } };        return val;    }    pub fn deinit(self: *Self, allocator: Allocator) void {        switch (self.data) {            .constructed => |c| {                for (c.args) |arg| {                    arg.deinit(allocator);                }                allocator.free(c.args);            },            .closure => |cl| cl.deinit(allocator),            .lazy_kc_thunk => |t| t.deinit(allocator),            .lazy_kc_thunk_union => |t| t.deinit(allocator),            .lazy_enum_thunk => |t| t.deinit(allocator),            .native => |n| {                switch (n) {                    .int_dist => |d| allocator.free(d.bits),                    else => {},                }            },        }        allocator.destroy(self);    }    pub fn eql(self: *const Self, other: *const Self) bool {        if (@as(std.meta.Tag(Data), self.data) != @as(std.meta.Tag(Data), other.data)) {            return false;        }        return switch (self.data) {            .native => |n| n.eql(other.data.native),            .constructed => |c| c.eql(other.data.constructed),            .closure => |cl| cl.eql(other.data.closure),            .lazy_kc_thunk => |t| t == other.data.lazy_kc_thunk,            .lazy_kc_thunk_union => |t| t == other.data.lazy_kc_thunk_union,            .lazy_enum_thunk => |t| t == other.data.lazy_enum_thunk,        };    }    pub fn hash(self: *const Self) u64 {        var h = std.hash.Wyhash.init(0);        h.update(std.mem.asBytes(&@as(u8, @backingInt(self.data))));        switch (self.data) {            .native => |n| h.update(std.mem.asBytes(&n.hash())),            .constructed => |c| h.update(std.mem.asBytes(&c.hash())),            .closure => |cl| h.update(std.mem.asBytes(&cl.hash())),            .lazy_kc_thunk => |t| h.update(std.mem.asBytes(&@intFromPtr(t))),            .lazy_kc_thunk_union => |t| h.update(std.mem.asBytes(&@intFromPtr(t))),            .lazy_enum_thunk => |t| h.update(std.mem.asBytes(&@intFromPtr(t))),        }        return h.final();    }    pub fn isThunk(self: *const Self) bool {        return switch (self.data) {            .lazy_kc_thunk, .lazy_kc_thunk_union, .lazy_enum_thunk => true,            else => false,        };    }    pub fn isTrue(self: *const Self) bool {        return switch (self.data) {            .constructed => |c| std.mem.eql(u8, c.constructor, "True") and c.args.len == 0,            else => false,        };    }    pub fn isFalse(self: *const Self) bool {        return switch (self.data) {            .constructed => |c| std.mem.eql(u8, c.constructor, "False") and c.args.len == 0,            else => false,        };    }    pub fn maybeIntDist(self: *const Self) ?IntDist {        return switch (self.data) {            .native => |n| switch (n) {                .int_dist => |d| d,                else => null,            },            else => null,        };    }    pub fn maybeNat(self: *const Self) ?i64 {        switch (self.data) {            .constructed => |c| {                if (std.mem.eql(u8, c.constructor, "O") and c.args.len == 0) {                    return 0;                } else if (std.mem.eql(u8, c.constructor, "S") and c.args.len == 1) {                    if (c.args[0].maybeNat()) |inner| {                        return inner + 1;                    }                }                return null;            },            .lazy_kc_thunk => |thunk| {                switch (thunk.expr) {                    .pexpr => |expr| return Self.maybeNatFromPExpr(expr),                    .thunk => return null,                }            },            else => return null,        }    }    fn maybeNatFromPExpr(expr: *const @import("pexpr.zig").PExpr) ?i64 {        if (expr.head == .construct) {            const constructor = expr.head.construct.constructor;            if (std.mem.eql(u8, constructor, "O") and expr.args.len == 0) {                return 0;            } else if (std.mem.eql(u8, constructor, "S") and expr.args.len == 1) {                return if (Self.maybeNatFromPExpr(expr.args[0])) |inner| inner + 1 else null;            }        }        return null;    }    pub fn maybeNatBounded(self: *const Self, max_value: i64) ?i64 {        var current: *const Self = self;        var count: i64 = 0;        while (true) {            switch (current.data) {                .constructed => |c| {                    if (std.mem.eql(u8, c.constructor, "O") and c.args.len == 0) {                        return count;                    } else if (std.mem.eql(u8, c.constructor, "S") and c.args.len == 1) {                        count += 1;                        if (count > max_value) {                            return null;                        }                        current = c.args[0];                    } else {                        return null;                    }                },                else => return null,            }        }    }    pub fn maybeList(self: *const Self, allocator: Allocator) !?[]*Self {        var items: std.ArrayList(*Self) = .empty;        errdefer items.deinit(allocator);        var current = self;        while (true) {            switch (current.data) {                .constructed => |c| {                    if (std.mem.eql(u8, c.constructor, "Nil") and c.args.len == 0) {                        const slice = try items.toOwnedSlice(allocator);                        return slice;                    } else if (std.mem.eql(u8, c.constructor, "Cons") and c.args.len == 2) {                        try items.append(allocator, c.args[0]);                        current = c.args[1];                    } else {                        items.deinit(allocator);                        return null;                    }                },                else => {                    items.deinit(allocator);                    return null;                },            }        }    }    pub fn maybePair(self: *const Self) ?struct { fst: *Self, snd: *Self } {        switch (self.data) {            .constructed => |c| {                if (std.mem.eql(u8, c.constructor, "Pair") and c.args.len == 2) {                    return .{ .fst = c.args[0], .snd = c.args[1] };                }                return null;            },            else => return null,        }    }    pub fn format(        self: *const Self,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        switch (self.data) {            .native => |n| {                switch (n) {                    .int => |i| try writer.print("{d}", .{i}),                    .float => |f| try writer.print("{d}", .{f}),                    .symbol => |s| try writer.writeAll(s),                    .bool_val => |b| try writer.writeAll(if (b) "True" else "False"),                    .pexpr => |p| try writer.print("{any}", .{p}),                    .int_dist => |d| try writer.print("IntDist({d} bits)", .{d.bits.len}),                }            },            .constructed => |c| {                if (self.maybeNat()) |n| {                    try writer.print("{d}", .{n});                    return;                }                if (std.mem.eql(u8, c.constructor, "True") and c.args.len == 0) {                    try writer.writeAll("True");                    return;                }                if (std.mem.eql(u8, c.constructor, "False") and c.args.len == 0) {                    try writer.writeAll("False");                    return;                }                if (std.mem.eql(u8, c.constructor, "Unit") and c.args.len == 0) {                    try writer.writeAll("()");                    return;                }                try writer.print("({s}", .{c.constructor});                for (c.args) |arg| {                    try writer.writeAll(" ");                    try arg.format(fmt, options, writer);                }                try writer.writeAll(")");            },            .closure => |cl| try writer.print("{any}", .{cl}),            .lazy_kc_thunk => |t| try writer.print("LazyKCThunk({any})", .{t.expr}),            .lazy_kc_thunk_union => |t| try t.format(fmt, options, writer),            .lazy_enum_thunk => |t| try writer.print("LazyEnumThunk(id={d})", .{t.id}),        }    }};pub const FromValueResult = struct {    value: ConvertedValue,    concrete: bool,};pub const ConvertedValue = union(enum) {    bool_val: bool,    int: i64,    unit: void,    list: []*RuntimeValue,    pair: struct { fst: *RuntimeValue, snd: *RuntimeValue },    original: *RuntimeValue,};pub fn fromValue(val: *RuntimeValue) FromValueResult {    switch (val.data) {        .constructed => |c| {            if (std.mem.eql(u8, c.constructor, "True") and c.args.len == 0) {                return .{ .value = .{ .bool_val = true }, .concrete = true };            }            if (std.mem.eql(u8, c.constructor, "False") and c.args.len == 0) {                return .{ .value = .{ .bool_val = false }, .concrete = true };            }            if (std.mem.eql(u8, c.constructor, "Unit") and c.args.len == 0) {                return .{ .value = .unit, .concrete = true };            }            if (val.maybeNat()) |n| {                return .{ .value = .{ .int = n }, .concrete = true };            }            if (std.mem.eql(u8, c.constructor, "Pair") and c.args.len == 2) {                const fst_result = fromValue(c.args[0]);                const snd_result = fromValue(c.args[1]);                if (fst_result.concrete and snd_result.concrete) {                    return .{ .value = .{ .pair = .{ .fst = c.args[0], .snd = c.args[1] } }, .concrete = true };                }                return .{ .value = .{ .original = val }, .concrete = false };            }            if (std.mem.eql(u8, c.constructor, "Nil") and c.args.len == 0) {                return .{ .value = .{ .original = val }, .concrete = true };            }            if (std.mem.eql(u8, c.constructor, "Cons") and c.args.len == 2) {                var concrete = true;                var current: *RuntimeValue = val;                while (true) {                    switch (current.data) {                        .constructed => |inner| {                            if (std.mem.eql(u8, inner.constructor, "Nil") and inner.args.len == 0) {                                break;                            } else if (std.mem.eql(u8, inner.constructor, "Cons") and inner.args.len == 2) {                                if (inner.args[0].isThunk()) {                                    concrete = false;                                    break;                                }                                current = inner.args[1];                            } else {                                break;                            }                        },                        else => {                            concrete = current.isThunk() == false;                            break;                        },                    }                }                return .{ .value = .{ .original = val }, .concrete = concrete };            }            for (c.args) |arg| {                if (arg.isThunk()) {                    return .{ .value = .{ .original = val }, .concrete = false };                }            }            return .{ .value = .{ .original = val }, .concrete = true };        },        .native => return .{ .value = .{ .original = val }, .concrete = true },        .closure => return .{ .value = .{ .original = val }, .concrete = true },        .lazy_kc_thunk, .lazy_kc_thunk_union, .lazy_enum_thunk => {            return .{ .value = .{ .original = val }, .concrete = false };        },    }}pub fn pluckNat(allocator: Allocator, n: i64) !*RuntimeValue {    if (n <= 0) {        return RuntimeValue.initConstructed(allocator, "O", &[_]*RuntimeValue{});    }    const pred = try pluckNat(allocator, n - 1);    errdefer pred.deinit(allocator);    const args = try allocator.alloc(*RuntimeValue, 1);    args[0] = pred;    return RuntimeValue.initConstructed(allocator, "S", args);}pub fn pluckList(allocator: Allocator, items: []*RuntimeValue) !*RuntimeValue {    var result = try RuntimeValue.initConstructed(allocator, "Nil", &[_]*RuntimeValue{});    var i = items.len;    while (i > 0) {        i -= 1;        const args = try allocator.alloc(*RuntimeValue, 2);        args[0] = items[i];        args[1] = result;        result = try RuntimeValue.initConstructed(allocator, "Cons", args);    }    return result;}pub const Closure = struct {    expr: ClosureExpr,    env: Env,    name: Symbol,    pub const ClosureExpr = union(enum) {        pexpr: *PExpr,        thunk: *RuntimeValue,    };    const Self = @This();    pub fn init(allocator: Allocator, expr: *PExpr, env: Env, name: Symbol) !*Self {        const closure = try allocator.create(Self);        closure.* = Self{            .expr = .{ .pexpr = expr },            .env = env,            .name = name,        };        return closure;    }    pub fn initWithThunk(allocator: Allocator, thunk: *RuntimeValue, env: Env, name: Symbol) !*Self {        const closure = try allocator.create(Self);        closure.* = Self{            .expr = .{ .thunk = thunk },            .env = env,            .name = name,        };        return closure;    }    pub fn makeSelfLoop(        allocator: Allocator,        body: *PExpr,        env: Env,        rec_name: Symbol,        nonrec_name: Symbol,    ) !*Self {        const closure = try allocator.create(Self);        errdefer allocator.destroy(closure);        const closure_val = try allocator.create(RuntimeValue);        errdefer allocator.destroy(closure_val);        closure_val.* = RuntimeValue{ .data = .{ .closure = closure } };        const new_env = try env.extend(allocator, rec_name, closure_val);        errdefer new_env.deinit(allocator);        closure.* = Self{            .expr = .{ .pexpr = body },            .env = new_env,            .name = nonrec_name,        };        return closure;    }    pub fn isSelfLoop(self: *const Self) bool {        if (self.env.isEmpty()) return false;        if (self.env.first()) |first_val| {            if (first_val.data == .closure) {                return first_val.data.closure == self;            }        }        return false;    }    pub fn deinit(self: *Self, allocator: Allocator) void {        if (!self.isSelfLoop()) {            self.env.deinit(allocator);        }        allocator.destroy(self);    }    pub fn eql(self: *const Self, other: *const Self) bool {        if (!std.mem.eql(u8, self.name, other.name)) return false;        switch (self.expr) {            .pexpr => |p| {                if (other.expr != .pexpr) return false;                if (p != other.expr.pexpr) return false;            },            .thunk => |t| {                if (other.expr != .thunk) return false;                if (t != other.expr.thunk) return false;            },        }        if (self.isSelfLoop() and other.isSelfLoop()) {            const self_tail = self.env.tail() orelse return true;            const other_tail = other.env.tail() orelse return true;            return self_tail.eql(other_tail);        }        return self.env.eql(other.env);    }    pub fn hash(self: *const Self) u64 {        var h = std.hash.Wyhash.init(0);        switch (self.expr) {            .pexpr => |p| h.update(std.mem.asBytes(&@intFromPtr(p))),            .thunk => |t| h.update(std.mem.asBytes(&@intFromPtr(t))),        }        h.update(self.name);        h.update(std.mem.asBytes(&self.env.len()));        return h.final();    }    pub fn format(        self: *const Self,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        _ = fmt;        _ = options;        try writer.print("Closure((λ{s} -> ", .{self.name});        switch (self.expr) {            .pexpr => |p| try writer.print("{}", .{p}),            .thunk => try writer.writeAll("<thunk>"),        }        try writer.writeAll("), env=[");        var env = self.env;        var first_item = true;        while (env != .nil) {            if (!first_item) try writer.writeAll(", ");            const cons = env.cons;            if (cons.val.data == .closure and cons.val.data.closure == self) {                try writer.writeAll("[recursive]");            } else {                try writer.print("{}", .{cons.val});            }            env = cons.tail;            first_item = false;        }        try writer.writeAll("])");    }};pub const Callstack = []const i32;pub const GuardedWorld = struct {    value: *RuntimeValue,    guard: Bdd,};pub const GuardedWorlds = struct {    worlds: []GuardedWorld,    validity_guard: Bdd,};pub const RuntimeValueContext = struct {    pub fn hash(_: RuntimeValueContext, key: *RuntimeValue) u64 {        return key.hash();    }    pub fn eql(_: RuntimeValueContext, a: *RuntimeValue, b: *RuntimeValue) bool {        return a.eql(b);    }};pub const NestedWorld = struct {    result: GuardedWorlds,    guard: Bdd,};pub const LazyKCThunk = struct {    expr: ThunkExpr,    env: Env,    cache: std.ArrayList(GuardedWorlds),    callstack: []i32,    strict_order_index: i32,    allocator: Allocator,    pub const ThunkExpr = union(enum) {        pexpr: *PExpr,        thunk: *LazyKCThunk,    };    const Self = @This();    pub fn init(        allocator: Allocator,        expr: *PExpr,        env: Env,        strict_order_index: i32,        callstack: []const i32,    ) !*Self {        if (expr.head == .var_ref) {            if (env.get(expr.head.var_ref.name)) |val| {                if (val.data == .lazy_kc_thunk) {                    return val.data.lazy_kc_thunk;                }            }        }        const thunk = try allocator.create(Self);        errdefer allocator.destroy(thunk);        const callstack_copy = try allocator.dupe(i32, callstack);        errdefer allocator.free(callstack_copy);        thunk.* = Self{            .expr = .{ .pexpr = expr },            .env = env,            .cache = .empty,            .callstack = callstack_copy,            .strict_order_index = strict_order_index,            .allocator = allocator,        };        return thunk;    }    pub fn deinit(self: *Self, allocator: Allocator) void {        allocator.free(self.callstack);        for (self.cache.items) |gw| {            allocator.free(gw.worlds);        }        self.cache.deinit(allocator);        allocator.destroy(self);    }    pub fn deinitWithEnv(self: *Self, allocator: Allocator) void {        self.env.deinit(allocator);        self.deinit(allocator);    }    pub fn format(        self: *const Self,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        try writer.writeAll("LazyKCThunk(");        switch (self.expr) {            .pexpr => |p| try p.format(fmt, options, writer),            .thunk => try writer.writeAll("<nested-thunk>"),        }        try writer.writeAll(")");    }};pub const LazyKCThunkUnion = struct {    thunks: []ThunkGuard,    allocator: Allocator,    pub const ThunkGuard = struct {        thunk: *LazyKCThunk,        guard: Bdd,    };    const Self = @This();    pub const ThunkInput = struct {        value: *RuntimeValue,        outer_guard: Bdd,    };    pub fn init(allocator: Allocator, manager: *bdd.Manager, worlds: []const ThunkInput) !*Self {        var uniq_thunks: std.ArrayList(*LazyKCThunk) = .empty;        defer uniq_thunks.deinit(allocator);        var uniq_guards: std.ArrayList(Bdd) = .empty;        defer uniq_guards.deinit(allocator);        var thunk_indices = std.AutoHashMap(*LazyKCThunk, usize).init(allocator);        defer thunk_indices.deinit();        for (worlds) |input| {            switch (input.value.data) {                .lazy_kc_thunk_union => |union_thunk| {                    for (union_thunk.thunks) |inner| {                        const combined_guard = try manager.bddAnd(inner.guard, input.outer_guard);                        if (thunk_indices.get(inner.thunk)) |idx| {                            uniq_guards.items[idx] = try manager.bddOr(uniq_guards.items[idx], combined_guard);                        } else {                            try thunk_indices.put(inner.thunk, uniq_thunks.items.len);                            try uniq_thunks.append(allocator, inner.thunk);                            try uniq_guards.append(allocator, combined_guard);                        }                    }                },                .lazy_kc_thunk => |thunk| {                    if (thunk_indices.get(thunk)) |idx| {                        uniq_guards.items[idx] = try manager.bddOr(uniq_guards.items[idx], input.outer_guard);                    } else {                        try thunk_indices.put(thunk, uniq_thunks.items.len);                        try uniq_thunks.append(allocator, thunk);                        try uniq_guards.append(allocator, input.outer_guard);                    }                },                else => {                    return error.InvalidThunkUnion;                },            }        }        const result = try allocator.create(Self);        errdefer allocator.destroy(result);        const thunks = try allocator.alloc(ThunkGuard, uniq_thunks.items.len);        for (thunks, uniq_thunks.items, uniq_guards.items) |*t, thunk, guard| {            t.* = .{ .thunk = thunk, .guard = guard };        }        result.* = Self{            .thunks = thunks,            .allocator = allocator,        };        return result;    }    pub fn deinit(self: *Self, allocator: Allocator) void {        allocator.free(self.thunks);        allocator.destroy(self);    }    pub fn format(        self: *const Self,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        try writer.print("LazyKCThunkUnion{{{d}}}(", .{self.thunks.len});        for (self.thunks, 0..) |tg, i| {            try tg.thunk.format(fmt, options, writer);            if (i < self.thunks.len - 1) {                try writer.writeAll(" | ");            }        }        try writer.writeAll(")");    }};pub const LazyEnumeratorThunk = struct {    expr: *PExpr,    env: Env,    callstack: []i32,    strict_order_index: i32,    id: u32,    const Self = @This();    pub fn init(        allocator: Allocator,        expr: *PExpr,        env: Env,        callstack: []const i32,        strict_order_index: i32,        next_id: *u32,    ) !*Self {        if (expr.head == .var_ref) {            if (env.get(expr.head.var_ref.name)) |val| {                if (val.data == .lazy_enum_thunk) {                    return val.data.lazy_enum_thunk;                }            }        }        const thunk = try allocator.create(Self);        errdefer allocator.destroy(thunk);        const callstack_copy = try allocator.dupe(i32, callstack);        errdefer allocator.free(callstack_copy);        const id = next_id.*;        next_id.* += 1;        thunk.* = Self{            .expr = expr,            .env = env,            .callstack = callstack_copy,            .strict_order_index = strict_order_index,            .id = id,        };        return thunk;    }    pub fn deinit(self: *Self, allocator: Allocator) void {        allocator.free(self.callstack);        allocator.destroy(self);    }    pub fn deinitWithEnv(self: *Self, allocator: Allocator) void {        self.env.deinit(allocator);        self.deinit(allocator);    }    pub fn format(        self: *const Self,        comptime fmt: []const u8,        options: std.fmt.Options,        writer: anytype,    ) !void {        _ = fmt;        _ = options;        try writer.print("LazyEnumeratorThunk(id={d}, {})", .{ self.id, self.expr });    }};pub const StateVars = struct {    initial_fuel: i64,    remaining_fuel: i64,    const Self = @This();    pub fn init() Self {        return Self{ .initial_fuel = 0, .remaining_fuel = 0 };    }    pub fn initWithFuel(fuel: i64) Self {        return Self{ .initial_fuel = fuel, .remaining_fuel = fuel };    }    pub fn exhausted(self: *const Self) bool {        return self.initial_fuel > 0 and self.remaining_fuel <= 0;    }    pub fn consumeFuel(self: *Self) bool {        if (self.initial_fuel == 0) {            return true;        }        if (self.remaining_fuel > 0) {            self.remaining_fuel -= 1;            return true;        }        return false;    }    pub fn reset(self: *Self) void {        self.remaining_fuel = self.initial_fuel;    }};pub const ThunkPath = []const usize;pub fn findFirstThunk(allocator: Allocator, val: *RuntimeValue) !?[]usize {    var path: std.ArrayList(usize) = .empty;    errdefer path.deinit(allocator);    if (try findFirstThunkInto(allocator, val, &path)) {        const slice = try path.toOwnedSlice(allocator);        return slice;    }    path.deinit(allocator);    return null;}pub fn findFirstThunkInto(allocator: Allocator, val: *RuntimeValue, path: *std.ArrayList(usize)) !bool {    path.clearRetainingCapacity();    return findFirstThunkInner(allocator, val, path);}fn findFirstThunkInner(allocator: Allocator, val: *RuntimeValue, path: *std.ArrayList(usize)) !bool {    switch (val.data) {        .lazy_kc_thunk, .lazy_kc_thunk_union, .lazy_enum_thunk => {            return true;        },        .constructed => |c| {            for (c.args, 0..) |arg, i| {                try path.append(allocator, i);                if (try findFirstThunkInner(allocator, arg, path)) {                    return true;                }                _ = path.pop();            }        },        .native => |n| {            if (n == .pexpr) {}        },        .closure => {},    }    return false;}pub fn getValueAtPath(val: *RuntimeValue, path: []const usize) ?*RuntimeValue {    if (path.len == 0) return val;    switch (val.data) {        .constructed => |c| {            if (path[0] >= c.args.len) return null;            return getValueAtPath(c.args[path[0]], path[1..]);        },        else => return null,    }}pub fn replaceAtPath(    allocator: Allocator,    val: *RuntimeValue,    path: []const usize,    new_val: *RuntimeValue,) !*RuntimeValue {    if (path.len == 0) return new_val;    switch (val.data) {        .constructed => |c| {            const new_args = try allocator.alloc(*RuntimeValue, c.args.len);            errdefer allocator.free(new_args);            @memcpy(new_args, c.args);            if (path[0] < c.args.len) {                new_args[path[0]] = try replaceAtPath(allocator, c.args[path[0]], path[1..], new_val);            }            return RuntimeValue.initConstructed(allocator, c.constructor, new_args);        },        else => return val,    }}test "empty environment" {    const env = Env.empty;    try std.testing.expect(env.isEmpty());    try std.testing.expectEqual(@as(usize, 0), env.len());    try std.testing.expectEqual(@as(?*RuntimeValue, null), env.get("x"));}test "environment extension and lookup" {    const allocator = std.testing.allocator;    const val = try RuntimeValue.initNative(allocator, .{ .int = 42 });    defer val.deinit(allocator);    var env = Env.empty;    env = try env.extend(allocator, "x", val);    defer env.deinit(allocator);    try std.testing.expect(!env.isEmpty());    try std.testing.expectEqual(@as(usize, 1), env.len());    try std.testing.expectEqual(val, env.get("x").?);    try std.testing.expectEqual(@as(?*RuntimeValue, null), env.get("y"));}test "runtime value nat conversion" {    const allocator = std.testing.allocator;    const nat3 = try pluckNat(allocator, 3);    defer nat3.deinit(allocator);    try std.testing.expectEqual(@as(?i64, 3), nat3.maybeNat());}test "runtime value bounded nat conversion" {    const allocator = std.testing.allocator;    const nat50 = try pluckNat(allocator, 50);    defer nat50.deinit(allocator);    try std.testing.expectEqual(@as(?i64, 50), nat50.maybeNatBounded(100));    try std.testing.expectEqual(@as(?i64, 50), nat50.maybeNatBounded(50));    try std.testing.expectEqual(@as(?i64, null), nat50.maybeNatBounded(49));    const nat0 = try pluckNat(allocator, 0);    defer nat0.deinit(allocator);    try std.testing.expectEqual(@as(?i64, 0), nat0.maybeNatBounded(100));}test "runtime value true/false" {    const allocator = std.testing.allocator;    const true_val = try RuntimeValue.initTrue(allocator);    defer true_val.deinit(allocator);    const false_val = try RuntimeValue.initFalse(allocator);    defer false_val.deinit(allocator);    try std.testing.expect(true_val.isTrue());    try std.testing.expect(!true_val.isFalse());    try std.testing.expect(!false_val.isTrue());    try std.testing.expect(false_val.isFalse());}test "closure creation" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    var types = try pexpr.TypeRegistry.initWithDefaults(allocator);    var defs = pexpr.Definitions.init(allocator);    const expr = try pexpr.parseExpr(allocator, "(λ x -> x)", &types, &defs);    const body = expr.args[0];    const closure = try Closure.init(allocator, body, Env.empty, "x");    try std.testing.expect(!closure.isSelfLoop());    try std.testing.expectEqualStrings("x", closure.name);}test "state vars" {    const state = StateVars.init();    try std.testing.expectEqual(@as(i64, 0), state.initial_fuel);    try std.testing.expect(!state.exhausted());    var limited_state = StateVars.initWithFuel(3);    try std.testing.expect(!limited_state.exhausted());    try std.testing.expect(limited_state.consumeFuel());    try std.testing.expect(limited_state.consumeFuel());    try std.testing.expect(limited_state.consumeFuel());    try std.testing.expect(limited_state.exhausted());    try std.testing.expect(!limited_state.consumeFuel());    limited_state.reset();    try std.testing.expect(!limited_state.exhausted());}

Complete caller list for runtime.IntDist.init

7 direct callers.

Complete caller list for runtime.RuntimeValue.initConstructed

23 direct callers.

Complete caller list for runtime.RuntimeValue.initFalse

8 direct callers.

Complete caller list for runtime.RuntimeValue.initLazyKCThunk

7 direct callers.

Complete caller list for runtime.RuntimeValue.initNative

18 direct callers.

Complete caller list for runtime.RuntimeValue.initTrue

11 direct callers.

Audit

Definitions97
Public names104
Members61
Version26.7.0
Revisiondaab053ee433