Skip to documentation
SLOP

tiny.smg.command.rules.add

Reference tiny.smg command rules add

Defined in command.rules.

API (1)

Actions

Public operations.

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

Source

Called byCallstest; no linktools.smg.src.command.rules.addtest: parse add builds deny dead-targ...test; no linktools.smg.src.command.rules.addtest: parse add builds invariant rule...test; no linktools.smg.src.command.rules.addtest: parse add builds namespace impo...test; no linktools.smg.src.command.rules.addtest: parse add rejects empty-target ...test; no linktools.smg.src.command.rules.addtest: parse add rejects incomplete na...+2 moreprivate; no linktools.smg.src.command.rules.addaddKindprivate; no linktools.smg.src.command.rules.adddenyRuleprivate; no linktools.smg.src.command.rules.addinvariantRuleprivate; no linktools.smg.src.command.rules.addquantifiedRulecommand.rules.addparse
Static calls · unresolved targets: 0 · external targets: 0.

Source: tools/smg/src/command/rules/add.zig

zig
const std = @import("std");const smg = @import("../../root.zig");const model = smg.model;const options = smg.cli.options;const output = smg.cli.output;const rules_mod = smg.rules;const text = smg.text;const QuantifiedAdd = struct {    selector: []const u8,    assertion: []const u8,};const AddKind = union(enum) {    deny: []const u8,    invariant: []const u8,    quantified: QuantifiedAdd,};pub fn parse(allocator: std.mem.Allocator, args: []const []const u8, name: []const u8) !rules_mod.Rule {    return switch (try addKind(allocator, args)) {        .deny => |pattern| try denyRule(allocator, args, name, pattern),        .invariant => |invariant| try invariantRule(allocator, args, name, invariant),        .quantified => |quantified| try quantifiedRule(allocator, args, name, quantified),    };}fn addKind(allocator: std.mem.Allocator, args: []const []const u8) !AddKind {    const deny = options.flagValue(args, "--deny");    const exclude_source = options.flagValue(args, "--exclude-source");    const allow_empty_target = options.hasFlag(args, "--allow-empty-target");    const invariant = options.flagValue(args, "--invariant");    const forall = options.flagValue(args, "--forall");    const assertion = options.flagValue(args, "--assert");    var kind_count: usize = 0;    if (deny != null) kind_count += 1;    if (invariant != null) kind_count += 1;    if (forall != null) kind_count += 1;    if (kind_count > 1) {        try output.writeErrFmt(allocator, "Error: specify exactly one of --deny, --invariant, or --forall.\n", .{});        return error.RuleValidation;    }    if (kind_count == 0) {        try output.writeErrFmt(allocator, "Error: specify one of --deny, --invariant, or --forall.\n", .{});        return error.RuleValidation;    }    if (forall != null and assertion == null) {        try output.writeErrFmt(allocator, "Error: --assert is required with --forall.\n", .{});        return error.RuleValidation;    }    if (forall == null and assertion != null) {        try output.writeErrFmt(allocator, "Error: --assert may only be used with --forall.\n", .{});        return error.RuleValidation;    }    if (deny == null and exclude_source != null) {        try output.writeErrFmt(            allocator,            "Error: --exclude-source may only be used with --deny.\n",            .{},        );        return error.RuleValidation;    }    if (deny == null and allow_empty_target) {        try output.writeErrFmt(            allocator,            "Error: --allow-empty-target may only be used with --deny.\n",            .{},        );        return error.RuleValidation;    }    if (deny) |pattern| return .{ .deny = pattern };    if (invariant) |value| return .{ .invariant = value };    return .{ .quantified = .{ .selector = forall.?, .assertion = assertion.? } };}fn denyRule(allocator: std.mem.Allocator, args: []const []const u8, name: []const u8, pattern: []const u8) !rules_mod.Rule {    _ = rules_mod.parseDenyPattern(pattern) catch |err| {        if (err == error.InvalidDenyPattern) {            try output.writeErrFmt(allocator, "Error: invalid deny pattern: '{s}'\n", .{pattern});            return error.RuleValidation;        }        return err;    };    return .{        .name = try allocator.dupe(u8, name),        .type = try allocator.dupe(u8, "deny"),        .pattern = try allocator.dupe(u8, pattern),        .exclude_source = if (options.flagValue(args, "--exclude-source")) |value|            try allocator.dupe(u8, value)        else            null,        .allow_empty_target = options.hasFlag(args, "--allow-empty-target"),        .scope = try ruleScope(allocator, args),    };}fn invariantRule(allocator: std.mem.Allocator, args: []const []const u8, name: []const u8, invariant: []const u8) !rules_mod.Rule {    if (options.flagValue(args, "--baseline")) |baseline| {        if (!std.mem.eql(u8, invariant, "namespace-handle-imports")) {            try output.writeErrFmt(                allocator,                "Error: --baseline may only be used with the namespace-handle-imports invariant.\n",                .{},            );            return error.RuleValidation;        }        rules_mod.validateNamespaceHandleImportBaseline(baseline) catch {            try output.writeErrFmt(allocator, "Error: --baseline must be COUNT:SHA256.\n", .{});            return error.RuleValidation;        };    }    return .{        .name = try allocator.dupe(u8, name),        .type = try allocator.dupe(u8, "invariant"),        .invariant = try allocator.dupe(u8, invariant),        .params = try ruleParams(allocator, args),        .scope = try ruleScope(allocator, args),    };}fn quantifiedRule(allocator: std.mem.Allocator, args: []const []const u8, name: []const u8, quantified: QuantifiedAdd) !rules_mod.Rule {    const unknown_metrics = rules_mod.unknownAssertionMetrics(allocator, quantified.assertion) catch |err| {        if (try rules_mod.assertionErrorMessage(allocator, quantified.assertion, err)) |message| {            try output.writeErrFmt(allocator, "Error: {s}\n", .{message});            return error.RuleValidation;        }        return err;    };    if (unknown_metrics.len != 0) {        try output.writeErrFmt(allocator, "Error: unknown metric identifier(s) in rule '{s}': {s}\n", .{ name, try text.list.joinStrings(allocator, unknown_metrics, ", ") });        return error.RuleValidation;    }    return .{        .name = try allocator.dupe(u8, name),        .type = try allocator.dupe(u8, "quantified"),        .selector = try allocator.dupe(u8, quantified.selector),        .assertion = try allocator.dupe(u8, quantified.assertion),        .scope = try ruleScope(allocator, args),    };}fn ruleScope(allocator: std.mem.Allocator, args: []const []const u8) !?[]const u8 {    return if (options.flagValue(args, "--scope")) |value| try allocator.dupe(u8, value) else null;}fn ruleParams(allocator: std.mem.Allocator, args: []const []const u8) ![]const model.Pair {    var out: std.ArrayList(model.Pair) = .empty;    if (options.flagValue(args, "--entry-points")) |entry| {        try out.append(allocator, .{ .key = try allocator.dupe(u8, "entry_points"), .value = try allocator.dupe(u8, entry) });    }    if (options.flagValue(args, "--baseline")) |baseline| {        try out.append(allocator, .{ .key = try allocator.dupe(u8, "baseline"), .value = try allocator.dupe(u8, baseline) });    }    return try out.toOwnedSlice(allocator);}test "parse add builds invariant rule params" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const args = &.{ "add", "live", "--invariant", "no-dead-code", "--entry-points", "main,cli.*", "--scope", "tools.smg.*" };    const rule = try parse(allocator, args, "live");    try std.testing.expectEqualStrings("live", rule.name);    try std.testing.expectEqualStrings("invariant", rule.type);    try std.testing.expectEqualStrings("no-dead-code", rule.invariant.?);    try std.testing.expectEqualStrings("tools.smg.*", rule.scope.?);    try std.testing.expectEqual(@as(usize, 1), rule.params.len);    try std.testing.expectEqualStrings("entry_points", rule.params[0].key);    try std.testing.expectEqualStrings("main,cli.*", rule.params[0].value);}test "parse add builds namespace import baseline" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const args = &.{        "add",        "root-handles",        "--invariant",        "namespace-handle-imports",        "--baseline",        "3:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",    };    const rule = try parse(allocator, args, "root-handles");    try std.testing.expectEqual(@as(usize, 1), rule.params.len);    try std.testing.expectEqualStrings("baseline", rule.params[0].key);    try std.testing.expectEqualStrings(        "3:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",        rule.params[0].value,    );}test "parse add rejects namespace import baseline for other invariants" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const args = &.{ "add", "acyclic", "--invariant", "no-cycles", "--baseline", "0:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" };    try std.testing.expectError(error.RuleValidation, parse(allocator, args, "acyclic"));}test "parse add rejects incomplete namespace import baseline" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const args = &.{ "add", "root-handles", "--invariant", "namespace-handle-imports", "--baseline", "0:00" };    try std.testing.expectError(error.RuleValidation, parse(allocator, args, "root-handles"));}test "parse add builds deny dead-target policy" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const args = &.{        "add",        "no-back-root",        "--deny",        "pkg.feature.* -[imports]-> pkg.feature.root",        "--exclude-source",        "*.test",        "--allow-empty-target",    };    const rule = try parse(allocator, args, "no-back-root");    try std.testing.expectEqualStrings("deny", rule.type);    try std.testing.expectEqualStrings(        "pkg.feature.* -[imports]-> pkg.feature.root",        rule.pattern.?,    );    try std.testing.expectEqualStrings("*.test", rule.exclude_source.?);    try std.testing.expect(rule.allow_empty_target);}test "parse add rejects empty-target policy for non-deny rules" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const args = &.{ "add", "acyclic", "--invariant", "no-cycles", "--allow-empty-target" };    try std.testing.expectError(error.RuleValidation, parse(allocator, args, "acyclic"));}

Source: tools/smg/src/command/rules/root.zig:1

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

Complete caller list for command.rules.add.parse

7 direct callers.

Audit

Definitions2
Public names3
Members0
Version26.7.0
Revisiondaab053ee433