Skip to documentation
SLOP

tiny.pluck.toplevel.script

Reference tiny.pluck toplevel script

Defined in toplevel.

API (10)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallstest sourcelib.pluck.src.toplevel.scripttest: parseSource classifies top-leve...private sourcelib.pluck.src.toplevel.scriptscanSourcetoplevel.scriptparseSource
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.pluck.src.toplevel.scriptscanSourcetoplevel.scriptparseSourceForms
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/pluck/src/toplevel/root.zig:7

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

Source: lib/pluck/src/toplevel/script.zig

zig
const std = @import("std");const pluck = @import("../root.zig");const Allocator = std.mem.Allocator;const pexpr = pluck.pexpr;const context_owner = @import("context.zig");const ToplevelContext = context_owner.ToplevelContext;const top_types = @import("types.zig");const ToplevelError = top_types.ToplevelError;const SourceLocation = top_types.SourceLocation;const SourceSpan = top_types.SourceSpan;const result_owner = @import("result.zig");const QueryResult = result_owner.QueryResult;const forms_owner = @import("forms.zig");const source_owner = @import("source.zig");pub const FormKind = enum {    definition,    type_definition,    query,    expression,};pub const SourceForm = struct {    kind: FormKind,    source: []const u8,    name: ?[]const u8,    span: SourceSpan,    location: SourceLocation,};pub const SourceForms = struct {    allocator: Allocator,    items: []SourceForm,    pub fn deinit(self: *SourceForms) void {        self.allocator.free(self.items);        self.items = &[_]SourceForm{};    }};pub const QueryRecord = struct {    form_index: usize,    form: SourceForm,    result: QueryResult,};pub const Execution = struct {    allocator: Allocator,    forms: []SourceForm,    queries: []QueryRecord,    pub fn deinit(self: *Execution) void {        for (self.queries) |*query| {            query.result.deinit();        }        self.allocator.free(self.queries);        self.allocator.free(self.forms);        self.queries = &[_]QueryRecord{};        self.forms = &[_]SourceForm{};    }};pub fn parseSource(allocator: Allocator, source: []const u8) ToplevelError!SourceForms {    return scanSource(allocator, source, null);}pub fn parseSourceForms(self: *ToplevelContext, allocator: Allocator, source: []const u8) ToplevelError!SourceForms {    self.last_error_span = null;    return scanSource(allocator, source, &self.last_error_span);}pub fn executeSource(self: *ToplevelContext, allocator: Allocator, source: []const u8) ToplevelError!Execution {    var parsed = try parseSourceForms(self, allocator, source);    errdefer parsed.deinit();    const prebound_defs = try source_owner.prebindSexprDefs(self, source);    defer if (prebound_defs.len > 0) self.allocator.free(prebound_defs);    errdefer source_owner.rollbackPreboundDefs(self, prebound_defs);    var queries: std.ArrayListUnmanaged(QueryRecord) = .empty;    errdefer {        for (queries.items) |*query| {            query.result.deinit();        }        queries.deinit(allocator);    }    for (parsed.items, 0..) |form, form_index| {        const maybe_result = forms_owner.processFormSexpr(self, form.source) catch |err| {            self.last_error_span = form.span;            return err;        };        if (maybe_result) |result| {            var query_result = result;            query_result.source_location = form.location;            queries.append(allocator, .{                .form_index = form_index,                .form = form,                .result = query_result,            }) catch |err| {                query_result.deinit();                return switch (err) {                    error.OutOfMemory => ToplevelError.OutOfMemory,                };            };        }    }    return .{        .allocator = allocator,        .forms = parsed.items,        .queries = queries.toOwnedSlice(allocator) catch return ToplevelError.OutOfMemory,    };}fn scanSource(allocator: Allocator, source: []const u8, error_span: ?*?SourceSpan) ToplevelError!SourceForms {    var forms: std.ArrayListUnmanaged(SourceForm) = .empty;    errdefer forms.deinit(allocator);    var pos: usize = 0;    while (pos < source.len) {        pos = source_owner.skipWhitespaceAndComments(source, pos);        if (pos >= source.len) break;        const form_start = pos;        const form_end = source_owner.findFormEnd(source, pos) orelse {            if (error_span) |out| out.* = source_owner.spanFromOffsets(source, form_start, source.len);            return ToplevelError.ParseError;        };        pos = form_end;        const form_source = source[form_start..form_end];        if (form_source.len == 0) continue;        const tokens = pexpr.tokenize(allocator, form_source) catch return ToplevelError.OutOfMemory;        defer pexpr.freeTokens(allocator, tokens);        if (tokens.len == 0) continue;        const span = source_owner.spanFromOffsets(source, form_start, form_end);        try forms.append(allocator, .{            .kind = classify(tokens),            .source = form_source,            .name = formName(tokens),            .span = span,            .location = source_owner.locationFromSpan(span),        });    }    return .{        .allocator = allocator,        .items = forms.toOwnedSlice(allocator) catch return ToplevelError.OutOfMemory,    };}fn classify(tokens: []const pexpr.Token) FormKind {    if (tokens.len >= 2 and std.mem.eql(u8, tokens[0], "(")) {        if (std.mem.eql(u8, tokens[1], "define")) return .definition;        if (std.mem.eql(u8, tokens[1], "define-type")) return .type_definition;        if (std.mem.eql(u8, tokens[1], "query")) return .query;    }    return .expression;}fn formName(tokens: []const pexpr.Token) ?[]const u8 {    return switch (classify(tokens)) {        .definition => definitionName(tokens),        .type_definition => if (tokens.len >= 3 and source_owner.isIdentifier(tokens[2])) tokens[2] else null,        .query => queryName(tokens),        .expression => null,    };}fn definitionName(tokens: []const pexpr.Token) ?[]const u8 {    if (tokens.len < 4) return null;    if (std.mem.eql(u8, tokens[2], "(")) {        if (tokens.len >= 4 and source_owner.isIdentifier(tokens[3])) return tokens[3];        return null;    }    if (source_owner.isIdentifier(tokens[2])) return tokens[2];    return null;}fn queryName(tokens: []const pexpr.Token) ?[]const u8 {    if (tokens.len <= 4) return null;    if (source_owner.isIdentifier(tokens[2]) and !std.mem.eql(u8, tokens[3], ")")) return tokens[2];    return null;}test "parseSource classifies top-level forms" {    const source =        \\(define p 0.5)        \\(define-type coin (Heads) (Tails))        \\(query coin-query (Marginal (flip p)))        \\(Marginal True)    ;    var parsed = try parseSource(std.testing.allocator, source);    defer parsed.deinit();    try std.testing.expectEqual(@as(usize, 4), parsed.items.len);    try std.testing.expectEqual(FormKind.definition, parsed.items[0].kind);    try std.testing.expectEqualStrings("p", parsed.items[0].name.?);    try std.testing.expectEqual(FormKind.type_definition, parsed.items[1].kind);    try std.testing.expectEqualStrings("coin", parsed.items[1].name.?);    try std.testing.expectEqual(FormKind.query, parsed.items[2].kind);    try std.testing.expectEqualStrings("coin-query", parsed.items[2].name.?);    try std.testing.expectEqual(FormKind.expression, parsed.items[3].kind);    try std.testing.expect(parsed.items[3].name == null);}test "parseSourceForms records unmatched form span" {    var ctx = try ToplevelContext.init(std.testing.allocator);    defer ctx.deinit();    try std.testing.expectError(ToplevelError.ParseError, ctx.parseSourceForms(std.testing.allocator, "(Marginal True"));    const span = ctx.lastErrorSpan().?;    try std.testing.expectEqual(@as(usize, 0), span.start.offset);    try std.testing.expectEqual(@as(usize, 14), span.end.offset);}test "executeSource collects query records" {    var ctx = try ToplevelContext.init(std.testing.allocator);    defer ctx.deinit();    const source =        \\(define p 0.5)        \\(Marginal (flip p))    ;    var execution = try ctx.executeSource(std.testing.allocator, source);    defer execution.deinit();    try std.testing.expectEqual(@as(usize, 2), execution.forms.len);    try std.testing.expectEqual(@as(usize, 1), execution.queries.len);    try std.testing.expectEqual(@as(usize, 1), execution.queries[0].form_index);    try std.testing.expectEqual(FormKind.expression, execution.queries[0].form.kind);    try std.testing.expectEqual(@as(u32, 1), execution.queries[0].result.source_location.?.start_line);    var found_true = false;    for (execution.queries[0].result.outcomes) |outcome| {        if (std.mem.eql(u8, outcome.value_str, "True")) {            found_true = true;            try std.testing.expectApproxEqAbs(@as(f64, 0.5), outcome.probability, 1e-9);        }    }    try std.testing.expect(found_true);}

Audit

Definitions11
Public names19
Members17
Version26.7.0
Revisiondaab053ee433