Skip to content

Instantly share code, notes, and snippets.

@DutchGhost
Last active May 1, 2020 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DutchGhost/4d7bd8a818c27fbef2f56b2a02d7738b to your computer and use it in GitHub Desktop.
Save DutchGhost/4d7bd8a818c27fbef2f56b2a02d7738b to your computer and use it in GitHub Desktop.
zig build test fails on this
const std = @import("std");
const testing = std.testing;
const meta = std.meta;
pub const Type = union(enum) {
Character,
};
pub const Ammount = union(enum) {
Infinite,
Ammount: usize,
};
const Any = struct {};
fn starts_with(comptime T: type, slice: []const T, pattern: []const T) bool {
if (slice.len < pattern.len) return false;
return std.mem.eql(T, slice[0..pattern.len], pattern);
}
const ParseError = error{Invalid};
pub fn parsing(comptime T: type, comptime Desc: var) type {
return struct {
pub fn parse(s: []const u8) ParseError!T {
var slice = s;
var r: T = undefined;
inline for (meta.fields(@TypeOf(Desc))) |field| {
// Does the name begin with `skip`,
comptime var is_skip = starts_with(u8, field.name, "skip");
switch (@field(Desc, field.name).kind) {
.Character => {
// Grab out the filter clause
const filter = @field(Desc, field.name).filter;
// If we put in a literal character
// as the filter clause, then try match
// against that
if (@TypeOf(filter) == comptime_int) {
const c = slice[0];
if (c == filter) {
// Skip assigning a found clause
// if its a skipper
if (comptime !is_skip) {
@field(r, field.name) = c;
}
slice = slice[1..];
} else {
return ParseError.Invalid;
}
}
// If we don't care what character,
// `Any` matches anything
if (@TypeOf(filter) == Any) {
if (comptime !is_skip) {
@field(r, field.name) = s[0];
}
slice = slice[1..];
}
},
else => unreachable,
}
}
return r;
}
};
}
fn isWhitespace(c: *const u8) bool {
return c.* == ' ';
}
test "basic add functionality" {
const x = struct {
c: u8,
pub usingnamespace parsing(@This(), .{
.skip = .{
.kind = .Character,
.filter = ' ',
},
.skip1 = .{
.kind = .Character,
.filter = ' ',
},
.c = .{
.kind = .Character,
.filter = '1',
},
});
};
var parsed = try x.parse(" 1");
std.debug.assert(parsed.c == '1');
}
const std = @import("std");
const testing = std.testing;
const meta = std.meta;
pub const Type = union(enum) {
Character,
};
const Any = struct {};
fn starts_with(comptime T: type, slice: []const T, pattern: []const T) bool {
if (slice.len < pattern.len) return false;
return std.mem.eql(T, slice[0..pattern.len], pattern);
}
const ParseError = error{Invalid};
pub fn parsing(comptime T: type, comptime Description: var) type {
return struct {
fn parseCharacter(comptime fieldName: []const u8, result: *T, s: []const u8) ParseError!usize {
comptime var is_skip = starts_with(u8, fieldName, "skip");
const filter = @field(Description, fieldName).filter;
const matches = switch (@TypeOf(filter)) {
Any => true,
comptime_int => filter == s[0],
fn (*const u8) bool => filter(&s[0]),
else => @compileError("Type `" ++ @typeName(filter) ++ "` is not handled."),
};
if (matches) {
if (!is_skip) {
@field(result, fieldName) = s[0];
}
return 1;
} else {
return ParseError.Invalid;
}
}
pub fn parse(s: []const u8) ParseError!T {
var slice = s;
var r: T = undefined;
comptime var slice_idx = @as(usize, 0);
inline for (meta.fields(@TypeOf(Description))) |field| {
switch (@field(Description, field.name).kind) {
.Character => {
var ammount = try parseCharacter(field.name, &r, slice);
slice = slice[ammount..];
},
else => unreachable,
}
}
return r;
}
};
}
fn isWhitespace(c: *const u8) bool {
return c.* == ' ';
}
test "basic character parse" {
const x = struct {
c: u8,
pub usingnamespace parsing(@This(), .{
.skip = .{
.kind = .Character,
.filter = isWhitespace,
},
.skip1 = .{
.kind = .Character,
.filter = Any{},
},
.c = .{
.kind = .Character,
.filter = Any{},
},
});
};
var parsed = try x.parse(" a2");
std.debug.assert(parsed.c == '2');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment