Compare commits

..

No commits in common. "ad73ea6508318aad88684a6a7b35f823d393ea51" and "0f4a9fcaa75658f86599492259290cab06279e87" have entirely different histories.

6 changed files with 14 additions and 176 deletions

View File

@ -2,26 +2,11 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const nice = b.addModule("nice", .{
.root_source_file = .{ .path = "src/nice.zig" },
.source_file = .{ .path = "src/nice.zig" },
});
const tests = b.addTest(.{
.name = "nice-unit-tests",
.root_source_file = .{ .path = "tests/main.zig" },
.target = target,
.optimize = optimize,
});
tests.root_module.addImport("nice", nice);
const run_main_tests = b.addRunArtifact(tests);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&b.addInstallArtifact(tests, .{}).step);
test_step.dependOn(&run_main_tests.step);
add_examples(b, .{
.target = target,
.nice_mod = nice,
@ -29,7 +14,7 @@ pub fn build(b: *std.Build) void {
}
const ExampleOptions = struct {
target: std.Build.ResolvedTarget,
target: std.zig.CrossTarget,
nice_mod: *std.Build.Module,
};
@ -44,7 +29,7 @@ const examples = [_]Example{
.{ .name = "reify", .file = "examples/reify.zig" },
};
pub fn add_examples(b: *std.Build, options: ExampleOptions) void {
pub fn add_examples(b: *std.build, options: ExampleOptions) void {
const example_step = b.step("examples", "build examples");
inline for (examples) |example| {
@ -55,7 +40,7 @@ pub fn add_examples(b: *std.Build, options: ExampleOptions) void {
.optimize = .Debug,
});
ex_exe.root_module.addImport("nice", options.nice_mod);
ex_exe.addModule("nice", options.nice_mod);
const install = b.addInstallArtifact(ex_exe, .{});
example_step.dependOn(&install.step);
}

View File

@ -50,7 +50,7 @@ pub const Options = struct {
// If an empty document is parsed, this defines what value type should be the
// resulting document root object. The default behavior is to emit an error if the
// document is empty.
default_object: enum { scalar, list, map, fail } = .fail,
default_object: enum { string, list, map, fail } = .fail,
// Only used by the parseTo family of functions.
// If false, and a mapping contains additional keys that do not map to the fields of
@ -80,8 +80,10 @@ pub const Options = struct {
// an error if the destination is a boolean type. By default, these comparisons are
// case-sensitive. See the `case_insensitive_scalar_coersion` option to change
// this.
truthy_boolean_scalars: []const []const u8 = &.{ "true", "True", "yes", "on" },
falsy_boolean_scalars: []const []const u8 = &.{ "false", "False", "no", "off" },
boolean_scalars: struct { truthy: []const []const u8, falsy: []const []const u8 } = .{
.truthy = &.{ "true", "True", "yes", "on" },
.falsy = &.{ "false", "False", "no", "off" },
},
// Only used by the parseTo family of functions.
// A list of strings. Scalars in the doucment that match any of the values listed

View File

@ -59,7 +59,7 @@ pub const State = struct {
switch (state.mode) {
.initial => switch (options.default_object) {
.scalar => state.document.root = Value.emptyScalar(),
.string => state.document.root = Value.emptyString(),
.list => state.document.root = Value.newList(arena_alloc),
.map => state.document.root = Value.newMap(arena_alloc),
.fail => {

View File

@ -82,14 +82,14 @@ pub const Value = union(enum) {
inline .scalar, .string => |str, tag| {
if (tag == .string and !options.coerce_strings) return error.BadValue;
if (options.case_insensitive_scalar_coersion) {
for (options.truthy_boolean_scalars) |check|
for (options.boolean_scalars.truthy) |check|
if (std.ascii.eqlIgnoreCase(str, check)) return true;
for (options.falsy_boolean_scalars) |check|
for (options.boolean_scalars.falsy) |check|
if (std.ascii.eqlIgnoreCase(str, check)) return false;
} else {
for (options.truthy_boolean_scalars) |check|
for (options.boolean_scalars.truthy) |check|
if (std.mem.eql(u8, str, check)) return true;
for (options.falsy_boolean_scalars) |check|
for (options.boolean_scalars.falsy) |check|
if (std.mem.eql(u8, str, check)) return false;
}

View File

@ -1,5 +0,0 @@
comptime {
if (@import("builtin").is_test) {
_ = @import("./reify.zig");
}
}

View File

@ -1,144 +0,0 @@
const std = @import("std");
const nice = @import("nice");
fn reifyScalar(comptime scalar: []const u8, expected: anytype) !void {
try reifyScalarWithOptions(scalar, expected, .{});
}
fn reifyScalarWithOptions(comptime scalar: []const u8, expected: anytype, options: nice.parser.Options) !void {
const allocator = std.testing.allocator;
var diagnostics = nice.Diagnostics{};
const parsed = try nice.parseBufferTo(
@TypeOf(expected),
allocator,
scalar ++ "\n",
&diagnostics,
options,
);
defer parsed.deinit();
try std.testing.expectEqual(expected, parsed.value);
}
test "reify integer" {
try reifyScalar("123", @as(u8, 123));
try reifyScalar("0123", @as(u8, 123));
try reifyScalar("1_23", @as(u8, 123));
try reifyScalar("-01_23", @as(i8, -123));
}
test "reify hexadecimal" {
try reifyScalar("0x123", @as(i64, 0x123));
try reifyScalar("0x0123", @as(i64, 0x123));
try reifyScalar("0x01_23", @as(i64, 0x123));
try reifyScalar("-0x01_23", @as(i64, -0x123));
}
test "reify octal" {
try reifyScalar("0o123", @as(i64, 0o123));
try reifyScalar("0o0123", @as(i64, 0o123));
try reifyScalar("0o01_23", @as(i64, 0o123));
try reifyScalar("-0o01_23", @as(i64, -0o123));
}
test "reify binary" {
try reifyScalar("0b1011", @as(i5, 0b1011));
try reifyScalar("0b01011", @as(i5, 0b1011));
try reifyScalar("0b010_11", @as(i5, 0b1011));
try reifyScalar("-0b010_11", @as(i5, -0b1011));
}
test "reify float" {
try reifyScalar("0.25", @as(f32, 0.25));
try reifyScalar("0.2_5", @as(f32, 0.25));
try reifyScalar("00.250", @as(f32, 0.25));
try reifyScalar("-0.25", @as(f32, -0.25));
}
test "reify hexfloat" {
try reifyScalar("0x0.25", @as(f64, 0x0.25));
try reifyScalar("0x0.2_5", @as(f64, 0x0.25));
try reifyScalar("0x0.250p1", @as(f64, 0x0.25p1));
try reifyScalar("-0x0.25", @as(f64, -0x0.25));
}
test "reify true" {
try reifyScalar("true", true);
try reifyScalar("True", true);
try reifyScalar("yes", true);
try reifyScalar("on", true);
}
test "reify false" {
try reifyScalar("false", false);
try reifyScalar("False", false);
try reifyScalar("no", false);
try reifyScalar("off", false);
}
test "reify custom true" {
const options = nice.parser.Options{ .truthy_boolean_scalars = &.{"correct"} };
try reifyScalarWithOptions("correct", true, options);
}
test "reify true case insensitive" {
try std.testing.expectError(error.BadValue, reifyScalar("TRUE", true));
const options = nice.parser.Options{ .case_insensitive_scalar_coersion = true };
try reifyScalarWithOptions("TRUE", true, options);
}
test "reify custom false" {
const options = nice.parser.Options{ .falsy_boolean_scalars = &.{"incorrect"} };
try reifyScalarWithOptions("incorrect", false, options);
}
test "reify false case insensitive" {
try std.testing.expectError(error.BadValue, reifyScalar("FALSE", false));
const options = nice.parser.Options{ .case_insensitive_scalar_coersion = true };
try reifyScalarWithOptions("FALSE", false, options);
}
test "reify null" {
try reifyScalar("null", @as(?u8, null));
try reifyScalar("nil", @as(?u8, null));
try reifyScalar("None", @as(?u8, null));
}
test "reify custom null" {
const options = nice.parser.Options{ .null_scalars = &.{"nothing"} };
try reifyScalarWithOptions("nothing", @as(?u8, null), options);
}
test "reify null case insensitive" {
// this is a little weird because when the null string mismatches, it will try to
// parse the child optional type and produce either a value or an error from that,
// so the error received depends on whether or not the optional child type fails to
// parse the given value.
try std.testing.expectError(error.InvalidCharacter, reifyScalar("NULL", @as(?u8, null)));
const options = nice.parser.Options{ .case_insensitive_scalar_coersion = true };
try reifyScalarWithOptions("NULL", @as(?u8, null), options);
}
test "reify void" {
// A void scalar cannot exist on its own as it is not distinguishable from an empty
// document.
const Void = struct { void: void };
try reifyScalar("void:", Void{ .void = void{} });
}
test "reify void scalar" {
const options = nice.parser.Options{ .default_object = .scalar };
try reifyScalarWithOptions("", void{}, options);
}
test "reify enum" {
const Enum = enum { one, two };
try reifyScalar(".one", Enum.one);
}
test "reify enum no dot" {
const options = nice.parser.Options{ .expect_enum_dot = false };
const Enum = enum { one, two };
try reifyScalarWithOptions("two", Enum.two, options);
}