Moved benchmark and test to src. Implemented array without testing yet

This commit is contained in:
Adrien Bouvais 2025-01-25 19:11:01 +01:00
parent a476cef2df
commit 78e8b67b80
13 changed files with 554 additions and 547 deletions

View File

@ -34,7 +34,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
.name = "CLI tokenizer",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
tests1.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
const run_tests1 = b.addRunArtifact(tests1);
@ -44,7 +44,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
.name = "CLI tokenizer",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
const run_tests2 = b.addRunArtifact(tests2);
@ -53,7 +53,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
.name = "ZiQL tokenizer",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
const run_tests3 = b.addRunArtifact(tests3);
@ -62,18 +62,18 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
.name = "Schema tokenizer",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
tests4.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
tests4.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
const run_tests4 = b.addRunArtifact(tests4);
const tests5 = b.addTest(.{
.root_source_file = b.path("test.zig"),
.root_source_file = b.path("src/test.zig"),
.target = target,
.optimize = optimize,
.name = "ZiQL parser",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
tests5.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
tests5.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
@ -86,7 +86,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
.name = "Filter tree",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
tests6.root_module.addImport("dtype", b.createModule(.{ .root_source_file = b.path("lib/types/out.zig") }));
tests6.root_module.addImport("config", b.createModule(.{ .root_source_file = b.path("lib/config.zig") }));
@ -111,7 +111,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
.name = "File parsing",
.test_runner = b.path("test_runner.zig"),
.test_runner = b.path("src/test_runner.zig"),
});
const run_tests1 = b.addRunArtifact(tests1);
@ -124,7 +124,7 @@ pub fn build(b: *std.Build) void {
{
const benchmark = b.addExecutable(.{
.name = "benchmark",
.root_source_file = b.path("benchmark.zig"),
.root_source_file = b.path("src/benchmark.zig"),
.target = target,
.optimize = optimize,
});

View File

@ -6,34 +6,10 @@ pub fn parseInt(value_str: []const u8) i32 {
return std.fmt.parseInt(i32, value_str, 10) catch return 0;
}
pub fn parseArrayInt(allocator: std.mem.Allocator, array_str: []const u8) ![]const i32 {
var array = std.ArrayList(i32).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseInt(x));
}
return try array.toOwnedSlice();
}
pub fn parseFloat(value_str: []const u8) f64 {
return std.fmt.parseFloat(f64, value_str) catch return 0;
}
pub fn parseArrayFloat(allocator: std.mem.Allocator, array_str: []const u8) ![]const f64 {
var array = std.ArrayList(f64).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseFloat(x));
}
return try array.toOwnedSlice();
}
pub fn parseBool(value_str: []const u8) bool {
return (value_str[0] != '0');
}
@ -48,30 +24,6 @@ pub fn parseDate(value_str: []const u8) DateTime {
return DateTime.init(year, month - 1, day - 1, 0, 0, 0, 0);
}
pub fn parseArrayDate(allocator: std.mem.Allocator, array_str: []const u8) ![]const DateTime {
var array = std.ArrayList(DateTime).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseDate(x));
}
return try array.toOwnedSlice();
}
pub fn parseArrayDateUnix(allocator: std.mem.Allocator, array_str: []const u8) ![]const u64 {
var array = std.ArrayList(u64).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseDate(x).toUnix());
}
return array.toOwnedSlice();
}
pub fn parseTime(value_str: []const u8) DateTime {
if (std.mem.eql(u8, value_str, "NOW")) return DateTime.now();
@ -83,30 +35,6 @@ pub fn parseTime(value_str: []const u8) DateTime {
return DateTime.init(0, 0, 0, hours, minutes, seconds, milliseconds);
}
pub fn parseArrayTime(allocator: std.mem.Allocator, array_str: []const u8) ![]const DateTime {
var array = std.ArrayList(DateTime).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseTime(x));
}
return try array.toOwnedSlice();
}
pub fn parseArrayTimeUnix(allocator: std.mem.Allocator, array_str: []const u8) ![]const u64 {
var array = std.ArrayList(u64).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseTime(x).toUnix());
}
return try array.toOwnedSlice();
}
pub fn parseDatetime(value_str: []const u8) DateTime {
if (std.mem.eql(u8, value_str, "NOW")) return DateTime.now();
@ -121,155 +49,31 @@ pub fn parseDatetime(value_str: []const u8) DateTime {
return DateTime.init(year, month - 1, day - 1, hours, minutes, seconds, milliseconds);
}
pub fn parseArrayDatetime(allocator: std.mem.Allocator, array_str: []const u8) ![]const DateTime {
var array = std.ArrayList(DateTime).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseDatetime(x));
}
return try array.toOwnedSlice();
}
pub fn parseArrayDatetimeUnix(allocator: std.mem.Allocator, array_str: []const u8) ![]const u64 {
var array = std.ArrayList(u64).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseDatetime(x).toUnix());
}
return try array.toOwnedSlice();
}
pub fn parseArrayBool(allocator: std.mem.Allocator, array_str: []const u8) ![]const bool {
var array = std.ArrayList(bool).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(parseBool(x));
}
return try array.toOwnedSlice();
}
pub fn parseArrayUUID(allocator: std.mem.Allocator, array_str: []const u8) ![]const UUID {
var array = std.ArrayList(UUID).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
const uuid = try UUID.parse(x);
try array.append(uuid);
}
return try array.toOwnedSlice();
}
pub fn parseArrayUUIDBytes(allocator: std.mem.Allocator, array_str: []const u8) ![]const [16]u8 {
var array = std.ArrayList([16]u8).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], " ");
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
const uuid = try UUID.parse(x);
try array.append(uuid.bytes);
}
return try array.toOwnedSlice();
}
// FIXME: I think it will not work if there is a ' inside the string, even \', need to fix that
pub fn parseArrayStr(allocator: std.mem.Allocator, array_str: []const u8) ![]const []const u8 {
var array = std.ArrayList([]const u8).init(allocator);
var it = std.mem.splitAny(u8, array_str[1 .. array_str.len - 1], "'");
_ = it.next(); // SSkip first token that is empty
while (it.next()) |x| {
if (std.mem.eql(u8, " ", x) or std.mem.eql(u8, "", x)) continue;
try array.append(x);
}
if (array.items.len > 0) allocator.free(array.pop()); // Remove the last because empty like the first one
return try array.toOwnedSlice();
}
test "Value parsing: Int" {
const allocator = std.testing.allocator;
// Int
const values: [3][]const u8 = .{ "1", "42", "Hello" };
const expected_values: [3]i32 = .{ 1, 42, 0 };
for (values, 0..) |value, i| {
try std.testing.expect(parseInt(value) == expected_values[i]);
}
// Int array
const array_str = "[1 14 44 42 hello]";
const array = try parseArrayInt(allocator, array_str);
defer allocator.free(array);
const expected_array: [5]i32 = .{ 1, 14, 44, 42, 0 };
try std.testing.expect(std.mem.eql(i32, array, &expected_array));
}
test "Value parsing: Float" {
const allocator = std.testing.allocator;
// Float
const values: [3][]const u8 = .{ "1.3", "65.991", "Hello" };
const expected_values: [3]f64 = .{ 1.3, 65.991, 0 };
for (values, 0..) |value, i| {
try std.testing.expect(parseFloat(value) == expected_values[i]);
}
// Float array
const array_str = "[1.5 14.3 44.9999 42 hello]";
const array = try parseArrayFloat(allocator, array_str);
defer allocator.free(array);
const expected_array: [5]f64 = .{ 1.5, 14.3, 44.9999, 42, 0 };
try std.testing.expect(std.mem.eql(f64, array, &expected_array));
}
test "Value parsing: String" {
// Note that I dont parse string because I dont need to, a string is a string
const allocator = std.testing.allocator;
// string array
const array_str = "['Hello' 'How are you doing ?' '']";
const array = try parseArrayStr(allocator, array_str);
defer allocator.free(array);
const expected_array: [3][]const u8 = .{ "Hello", "How are you doing ?", "" };
for (array, expected_array) |parsed, expected| {
std.debug.print("{s} : {s}\n", .{ parsed, expected });
try std.testing.expect(std.mem.eql(u8, parsed, expected));
}
}
test "Value parsing: Bool array" {
const allocator = std.testing.allocator;
const values: [3][]const u8 = .{ "1", "Hello", "0" };
const expected_values: [3]bool = .{ true, true, false };
for (values, 0..) |value, i| {
try std.testing.expect(parseBool(value) == expected_values[i]);
}
// Bool array
const array_str = "[1 0 0 1 1]";
const array = try parseArrayBool(allocator, array_str);
defer allocator.free(array);
const expected_array: [5]bool = .{ true, false, false, true, true };
try std.testing.expect(std.mem.eql(bool, array, &expected_array));
}
test "Value parsing: Date" {
const allocator = std.testing.allocator;
// Date
const values: [3][]const u8 = .{ "1920/01/01", "1998/01/21", "2024/12/31" };
const expected_values: [3]DateTime = .{
DateTime.init(1920, 0, 0, 0, 0, 0, 0),
@ -279,24 +83,9 @@ test "Value parsing: Date" {
for (values, 0..) |value, i| {
try std.testing.expect(expected_values[i].compareDate(parseDate(value)));
}
// Date array
const array_str = "[1920/01/01 1998/01/21 2024/12/31]";
const array = try parseArrayDate(allocator, array_str);
defer allocator.free(array);
const expected_array: [3]DateTime = .{
DateTime.init(1920, 0, 0, 0, 0, 0, 0),
DateTime.init(1998, 0, 20, 0, 0, 0, 0),
DateTime.init(2024, 11, 30, 0, 0, 0, 0),
};
for (array, expected_array) |parsed, expected| {
try std.testing.expect(expected.compareDate(parsed));
}
}
test "Value parsing: Time" {
const allocator = std.testing.allocator;
const values: [4][]const u8 = .{ "12:45:00.0000", "18:12:53.7491", "02:30:10", "12:30" };
const expected_values: [4]DateTime = .{
DateTime.init(0, 0, 0, 12, 45, 0, 0),
@ -307,25 +96,9 @@ test "Value parsing: Time" {
for (values, 0..) |value, i| {
try std.testing.expect(expected_values[i].compareTime(parseTime(value)));
}
// Time array
const array_str = "[12:45:00.0000 18:12:53.7491 02:30:10 12:30]";
const array = try parseArrayTime(allocator, array_str);
defer allocator.free(array);
const expected_array: [4]DateTime = .{
DateTime.init(0, 0, 0, 12, 45, 0, 0),
DateTime.init(0, 0, 0, 18, 12, 53, 7491),
DateTime.init(0, 0, 0, 2, 30, 10, 0),
DateTime.init(0, 0, 0, 12, 30, 0, 0),
};
for (array, expected_array) |parsed, expected| {
try std.testing.expect(expected.compareTime(parsed));
}
}
test "Value parsing: Datetime" {
const allocator = std.testing.allocator;
const values: [4][]const u8 = .{ "1920/01/01-12:45:00.0000", "1920/01/01-18:12:53.7491", "1920/01/01-02:30:10", "1920/01/01-12:30" };
const expected_values: [4]DateTime = .{
DateTime.init(1920, 0, 0, 12, 45, 0, 0),
@ -336,18 +109,4 @@ test "Value parsing: Datetime" {
for (values, 0..) |value, i| {
try std.testing.expect(expected_values[i].compareDatetime(parseDatetime(value)));
}
// Time array
const array_str = "[1920/01/01-12:45:00.0000 1920/01/01-18:12:53.7491 1920/01/01-02:30:10 1920/01/01-12:30]";
const array = try parseArrayDatetime(allocator, array_str);
defer allocator.free(array);
const expected_array: [4]DateTime = .{
DateTime.init(1920, 0, 0, 12, 45, 0, 0),
DateTime.init(1920, 0, 0, 18, 12, 53, 7491),
DateTime.init(1920, 0, 0, 2, 30, 10, 0),
DateTime.init(1920, 0, 0, 12, 30, 0, 0),
};
for (array, expected_array) |parsed, expected| {
try std.testing.expect(expected.compareDatetime(parsed));
}
}

View File

@ -1,6 +1,8 @@
User (
name: str,
email: str,
age: int,
address: str,
)
Order (

View File

@ -1,6 +1,6 @@
const std = @import("std");
const dtype = @import("dtype");
const DBEngine = @import("src/cli/core.zig");
const DBEngine = @import("cli/core.zig");
const ZipponError = @import("error").ZipponError;
const names = [_][]const u8{ "Alice", "Bob", "Charlie", "Dave", "Eve" };
@ -8,13 +8,15 @@ const emails = [_][]const u8{ "alice@email.com", "bob@email.com", "charlie@email
const dates = [_][]const u8{ "2000/01/01", "1954/04/02", "1998/01/21", "1977/12/31" };
const times = [_][]const u8{ "12:04", "20:45:11", "03:11:13", "03:00:01.0152" };
const datetimes = [_][]const u8{ "2000/01/01-12:04", "1954/04/02-20:45:11", "1998/01/21-03:11:13", "1977/12/31-03:00:01.0153" };
const scores = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const ages = [_][]const u8{ "15", "11", "53", "34", "96", "64" };
const address = [_][]const u8{ "01 rue Notre Dame", "11 street St Bob", "Route to Heaven bis", "Here", "Not here", "Maybe here" };
pub const std_options = std.Options{
.log_level = .info,
.logFn = myLog,
};
const NUMBER_OF_RUN: usize = 10;
var date_buffer: [64]u8 = undefined;
var date_fa = std.heap.FixedBufferAllocator.init(&date_buffer);
const date_allocator = date_fa.allocator();
@ -144,19 +146,23 @@ pub fn benchmark(allocator: std.mem.Allocator) !void {
var writer = array.writer();
try writer.print(
"ADD User (name = '{s}', email='{s}', orders=none)",
"ADD User (name = '{s}', email='{s}', age={s}, address='{s}')",
.{
names[rng.uintAtMost(usize, names.len - 1)],
emails[rng.uintAtMost(usize, emails.len - 1)],
ages[rng.uintAtMost(usize, ages.len - 1)],
address[rng.uintAtMost(usize, address.len - 1)],
},
);
for (0..users_count - 1) |_| {
try writer.print(
"('{s}', '{s}', none)",
"('{s}', '{s}', {s}, '{s}')",
.{
names[rng.uintAtMost(usize, names.len - 1)],
emails[rng.uintAtMost(usize, emails.len - 1)],
ages[rng.uintAtMost(usize, ages.len - 1)],
address[rng.uintAtMost(usize, address.len - 1)],
},
);
}
@ -173,7 +179,7 @@ pub fn benchmark(allocator: std.mem.Allocator) !void {
}
// Order
{
if (false) {
// Linked array not yet implemented and array manipulation not tested
const null_term_query_str = try std.fmt.bufPrintZ(
&line_buffer, // I dont like 'category = {name='Book'}'. Maybe att a IS keyword ?
@ -203,6 +209,8 @@ pub fn benchmark(allocator: std.mem.Allocator) !void {
// Run query
{
var read_time: f64 = 0;
var read_write_time: f64 = 0;
const queries = [_][]const u8{
"GRAB User {}",
"GRAB User {name='asd'}",
@ -212,24 +220,78 @@ pub fn benchmark(allocator: std.mem.Allocator) !void {
"GRAB Category {}",
"GRAB Item {}",
"GRAB Order {}",
"GRAB Order [from, items, quantity, at] {at > 2024}",
"GRAB Order [from, items, quantity, at] {}",
"DELETE User {}",
};
// Run benchmarks
for (queries) |query| {
const start_time = std.time.nanoTimestamp();
for (queries, 0..) |query, j| {
var time_buff: [NUMBER_OF_RUN]f64 = undefined;
for (0..NUMBER_OF_RUN) |i| {
const start_time = std.time.nanoTimestamp();
// Execute the query here
const null_term_query_str = try std.fmt.bufPrintZ(&line_buffer, "{s}", .{query});
db_engine.runQuery(null_term_query_str);
// Execute the query here
const null_term_query_str = try std.fmt.bufPrintZ(&line_buffer, "{s}", .{query});
db_engine.runQuery(null_term_query_str);
const end_time = std.time.nanoTimestamp();
const duration = @as(f64, @floatFromInt(end_time - start_time)) / 1e6;
const end_time = std.time.nanoTimestamp();
time_buff[i] = @as(f64, @floatFromInt(end_time - start_time)) / 1e6;
}
std.debug.print(
"Query: \t{s}\nTime: \t{d:>6.2} ± {d:<6.2}ms | Min {d:>8.2}ms | Max {d:>8.2}ms\n\n",
.{ query, mean(time_buff), std_dev(time_buff), min(time_buff), max(time_buff) },
);
std.debug.print("Query: \t\t{s}\nDuration: \t{d:.6} ms\n\n", .{ query, duration });
if (j == 0) read_write_time = mean(time_buff);
if (j == 1) read_time = mean(time_buff);
}
std.debug.print(
"Read: \t{d:.0} Entity/second\t*Include small condition\n",
.{@as(f64, @floatFromInt(users_count)) / (read_time / 1000)},
);
std.debug.print(
"Write: \t{d:.0} Entity/second\n",
.{@as(f64, @floatFromInt(users_count)) / ((read_write_time - read_time) / 1000)},
);
}
}
std.debug.print("=====================================\n\n", .{});
}
fn min(array: [NUMBER_OF_RUN]f64) f64 {
var current_min: f64 = 999999999999;
for (array) |value| {
if (value < current_min) current_min = value;
}
return current_min;
}
fn max(array: [NUMBER_OF_RUN]f64) f64 {
var current_max: f64 = 0;
for (array) |value| {
if (value > current_max) current_max = value;
}
return current_max;
}
fn mean(array: [NUMBER_OF_RUN]f64) f64 {
var total: f64 = 0;
for (array) |value| {
total += value;
}
return total / @as(f64, @floatFromInt(NUMBER_OF_RUN));
}
fn variance(array: [NUMBER_OF_RUN]f64) f64 {
const m = mean(array);
var square_diff: f64 = 0;
for (array) |value| {
square_diff += (value - m) * (value - m);
}
return square_diff / @as(f64, @floatFromInt(NUMBER_OF_RUN));
}
fn std_dev(array: [NUMBER_OF_RUN]f64) f64 {
const vari = variance(array);
return @sqrt(vari);
}

View File

@ -69,6 +69,18 @@ pub const ConditionValue = union(enum) {
link: *std.AutoHashMap(UUID, void),
link_array: *std.AutoHashMap(UUID, void),
pub fn init(dtype: DataType, value: []const u8) ConditionValue {
return switch (dtype) {
.int => ConditionValue.initInt(value),
.float => ConditionValue.initFloat(value),
.bool => ConditionValue.initBool(value),
.date => ConditionValue.initDate(value),
.time => ConditionValue.initTime(value),
.datetime => ConditionValue.initDateTime(value),
.str => ConditionValue.initStr(value[1 .. value.len - 1]),
};
}
pub fn initInt(value: []const u8) ConditionValue {
return ConditionValue{ .int = s2t.parseInt(value) };
}
@ -102,32 +114,24 @@ pub const ConditionValue = union(enum) {
}
// Array
pub fn initArrayInt(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .int_array = s2t.parseArrayInt(allocator, value) catch return ZipponError.ParsingValueError };
pub fn initArrayInt(value: []const i32) ZipponError!ConditionValue {
return ConditionValue{ .int_array = value };
}
pub fn initArrayFloat(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .float_array = s2t.parseArrayFloat(allocator, value) catch return ZipponError.ParsingValueError };
pub fn initArrayFloat(value: []const f64) ZipponError!ConditionValue {
return ConditionValue{ .float_array = value };
}
pub fn initArrayStr(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .str_array = s2t.parseArrayStr(allocator, value) catch return ZipponError.ParsingValueError };
pub fn initArrayStr(value: []const []const u8) ZipponError!ConditionValue {
return ConditionValue{ .str_array = value };
}
pub fn initArrayBool(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .bool_array = s2t.parseArrayBool(allocator, value) catch return ZipponError.ParsingValueError };
pub fn initArrayBool(value: []const bool) ZipponError!ConditionValue {
return ConditionValue{ .bool_array = value };
}
pub fn initArrayDate(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .unix_array = s2t.parseArrayDateUnix(allocator, value) catch return ZipponError.ParsingValueError };
}
pub fn initArrayTime(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .unix_array = s2t.parseArrayTimeUnix(allocator, value) catch return ZipponError.ParsingValueError };
}
pub fn initArrayDateTime(allocator: std.mem.Allocator, value: []const u8) ZipponError!ConditionValue {
return ConditionValue{ .unix_array = s2t.parseArrayDatetimeUnix(allocator, value) catch return ZipponError.ParsingValueError };
pub fn initArrayUnix(value: []const u64) ZipponError!ConditionValue {
return ConditionValue{ .unix_array = value };
}
pub fn initLink(value: *std.AutoHashMap(UUID, void)) ConditionValue {
@ -308,13 +312,28 @@ pub const Filter = struct {
else => unreachable,
},
// TODO: Add stuff to compare array, now condition with value as int, operator as in and to compare as []int should exist
.in => switch (condition.data_type) {
.link => condition.value.link.contains(UUID{ .bytes = row_value.UUID }),
.int => in(i32, row_value.Int, condition.value.int_array),
.float => in(f64, row_value.Float, condition.value.float_array),
.str => inStr(row_value.Str, condition.value.str_array),
.bool => in(bool, row_value.Bool, condition.value.bool_array),
.date => in(u64, row_value.Unix, condition.value.unix_array),
.time => in(u64, row_value.Unix, condition.value.unix_array),
.datetime => in(u64, row_value.Unix, condition.value.unix_array),
else => unreachable,
},
.not_in => switch (condition.data_type) {
.link => !condition.value.link.contains(UUID{ .bytes = row_value.UUID }),
.int => !in(i32, row_value.Int, condition.value.int_array),
.float => !in(f64, row_value.Float, condition.value.float_array),
.str => !inStr(row_value.Str, condition.value.str_array),
.bool => !in(bool, row_value.Bool, condition.value.bool_array),
.date => !in(u64, row_value.Unix, condition.value.unix_array),
.time => !in(u64, row_value.Unix, condition.value.unix_array),
.datetime => !in(u64, row_value.Unix, condition.value.unix_array),
else => unreachable,
},
};
@ -343,6 +362,16 @@ pub const Filter = struct {
.empty => std.debug.print("Empty", .{}),
}
}
fn in(comptime T: type, value: T, array: []const T) bool {
for (array) |v| if (v == value) return true;
return false;
}
fn inStr(value: []const u8, array: []const []const u8) bool {
for (array) |v| if (std.mem.eql(u8, v, value)) return true;
return false;
}
};
test "Evaluate" {

View File

@ -8,7 +8,7 @@ const DataType = dtype.DataType;
const DateTime = dtype.DateTime;
const UUID = dtype.UUID;
// TODO: Move this from FileEngine
// TODO: Move this outside of FileEngine and make it faster
const ZipponError = @import("error").ZipponError;

View File

@ -61,7 +61,6 @@ pub fn parse(self: *Parser, allocator: Allocator, struct_array: *std.ArrayList(S
},
.eof => state = .end,
else => {
std.debug.print("{s}\n", .{self.toker.getTokenSlice(token)});
return printError(
"Error parsing schema: Expected a struct name",
ZipponError.SynthaxError,

View File

@ -1,8 +1,8 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const Parser = @import("src/ziql/parser.zig");
const Tokenizer = @import("src/ziql/tokenizer.zig").Tokenizer;
const DBEngine = @import("src/cli/core.zig");
const Parser = @import("ziql/parser.zig");
const Tokenizer = @import("ziql/tokenizer.zig").Tokenizer;
const DBEngine = @import("cli/core.zig");
const ZipponError = @import("error").ZipponError;
const DB = struct {
@ -124,6 +124,11 @@ test "GRAB Relationship AdditionalData Filtered" {
try testParsing(db, "GRAB User [2; name, best_friend] {best_friend !IN {}}");
}
test "GRAB name IN" {
const db = DB{ .path = "test1", .schema = "schema/test" };
try testParsing(db, "GRAB User {name IN ['Bob' 'Bobinou']}");
}
test "GRAB Relationship dot" {
// DO I add this ? I'm not sure about this feature
const db = DB{ .path = "test1", .schema = "schema/test" };
@ -174,7 +179,9 @@ fn testParsing(db: DB, source: [:0]const u8) !void {
&db_engine.schema_engine,
);
std.debug.print("Running: {s}\n", .{source});
try parser.parse(allocator, source);
std.debug.print("\n\n-------------------------------\n\n", .{});
}
fn expectParsingError(db: DB, source: [:0]const u8, err: ZipponError) !void {
@ -187,5 +194,7 @@ fn expectParsingError(db: DB, source: [:0]const u8, err: ZipponError) !void {
&db_engine.schema_engine,
);
std.debug.print("Running: {s}\n", .{source});
try std.testing.expectError(err, parser.parse(allocator, source));
std.debug.print("\n\n-------------------------------\n\n", .{});
}

View File

@ -67,7 +67,6 @@ pub usingnamespace @import("parts/newData.zig");
pub usingnamespace @import("parts/value.zig");
pub usingnamespace @import("parts/filter.zig");
pub usingnamespace @import("parts/additionalData.zig");
pub usingnamespace @import("utils.zig");
toker: *Tokenizer = undefined,
file_engine: *FileEngine,

View File

@ -71,11 +71,21 @@ pub fn parseCondition(
.expect_operation => {
condition.operation = try self.parseComparisonOperator(token);
if (condition.operation == .in) condition.data_type = switch (condition.data_type) {
.int => .int_array,
.float => .float_array,
.str => .str_array,
.bool => .bool_array,
.date => .date_array,
.time => .time_array,
.datetime => .datetime_array,
else => condition.data_type,
};
log.debug("Condition operation {any}\n", .{condition.operation});
state = .expect_value;
},
.expect_value => {
log.debug("Parse condition value of member {s}", .{member_name});
condition.value = try self.parseConditionValue(allocator, struct_name, member_name, condition.data_type, &token);
state = .end;
},
@ -87,3 +97,87 @@ pub fn parseCondition(
return condition;
}
pub fn checkConditionValidity(
self: Self,
condition: Condition,
token: Token,
) ZipponError!void {
switch (condition.operation) {
.equal => switch (condition.data_type) {
.int, .float, .str, .bool, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, str, bool, date, time, datetime can be compare with =",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.different => switch (condition.data_type) {
.int, .float, .str, .bool, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, str, bool, date, time, datetime can be compare with !=",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.superior_or_equal => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with >=",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.superior => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with >",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.inferior_or_equal => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with <=",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.inferior => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with <",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.in => switch (condition.data_type) {
.link, .int_array, .float_array, .str_array, .bool_array, .time_array, .date_array, .datetime_array => {},
else => unreachable,
},
.not_in => switch (condition.data_type) {
.link, .int_array, .float_array, .str_array, .bool_array, .time_array, .date_array, .datetime_array => {},
else => unreachable,
},
}
}

View File

@ -1,5 +1,6 @@
const std = @import("std");
const dtype = @import("dtype");
const s2t = dtype.s2t;
const UUID = dtype.UUID;
const Allocator = std.mem.Allocator;
const Token = @import("../tokenizer.zig").Token;
@ -12,9 +13,10 @@ const ZipponError = @import("error").ZipponError;
var buff: [1024]u8 = undefined;
var zero_map_buf: [1024 * 4]u8 = undefined;
var zero_map_buf: [200]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&zero_map_buf);
var zero_map = std.AutoHashMap(UUID, void).init(fba.allocator());
var empty_map = std.AutoHashMap(UUID, void).init(fba.allocator());
const Self = @import("../parser.zig");
@ -23,148 +25,324 @@ pub fn initZeroMap() ZipponError!void {
}
/// To run just after a condition like = or > or >= to get the corresponding ConditionValue that you need to compare
pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []const u8, member_name: []const u8, data_type: dtype.DataType, token: *Token) ZipponError!ConditionValue {
pub fn parseConditionValue(
self: Self,
allocator: Allocator,
struct_name: []const u8,
member_name: []const u8,
data_type: dtype.DataType,
token: *Token,
) ZipponError!ConditionValue {
const start_index = token.loc.start;
const expected_tag: ?Token.Tag = switch (data_type) {
.int => .int_literal,
.float => .float_literal,
.str => .string_literal,
.self => .uuid_literal,
.int_array => .int_literal,
.float_array => .float_literal,
.str_array => .string_literal,
.bool, .bool_array, .link, .link_array, .date, .time, .datetime, .date_array, .time_array, .datetime_array => null, // handle separately
if (data_type.is_array()) switch (token.tag) {
.l_bracket => token.* = self.toker.next(),
else => return printError(
"Error: expecting [ to start array.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
};
// Check if the all next tokens are the right one
if (expected_tag) |tag| {
if (data_type.is_array()) {
token.* = try self.checkTokensInArray(tag);
switch (data_type) {
.self => unreachable,
.int => if (token.tag != .int_literal) {
return printError(
"Error: Wrong type. Expected: int.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
if (token.tag != tag) {
const msg = std.fmt.bufPrint(&buff, "Error: Wrong type. Expected: {any}", .{tag}) catch return ZipponError.MemoryError;
return printError(
msg,
return ConditionValue.initInt(self.toker.buffer[start_index..token.loc.end]);
},
.float => if (token.tag != .float_literal) {
return printError(
"Error: Wrong type. Expected: float.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
return ConditionValue.initFloat(self.toker.buffer[start_index..token.loc.end]);
},
.str => if (token.tag != .string_literal) {
return printError(
"Error: Wrong type. Expected: string.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
return ConditionValue.initStr(self.toker.buffer[start_index..token.loc.end]);
},
.bool => if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) {
return printError(
"Error: Wrong type. Expected: bool.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
return ConditionValue.initBool(self.toker.buffer[start_index..token.loc.end]);
},
.date => if (token.tag != .date_literal and token.tag != .keyword_now) {
return printError(
"Error: Wrong type. Expected: date.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
return ConditionValue.initDate(self.toker.buffer[start_index..token.loc.end]);
},
.time => if (token.tag != .time_literal and token.tag != .keyword_now) {
return printError(
"Error: Wrong type. Expected: time.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
return ConditionValue.initTime(self.toker.buffer[start_index..token.loc.end]);
},
.datetime => if (token.tag != .date_literal and token.tag != .datetime_literal and token.tag != .keyword_now) {
return printError(
"Error: Wrong type. Expected: datetime.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
} else {
return ConditionValue.initDateTime(self.toker.buffer[start_index..token.loc.end]);
},
.int_array => {
var array = std.ArrayList(i32).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .int_literal) return printError(
"Error: Wrong type. Expected int.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(s2t.parseInt(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError;
}
}
} else switch (data_type) {
.bool => if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) {
return printError(
"Error: Expected bool",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.bool_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) {
return printError(
"Error: Expected bool or ]",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.date => if (token.tag != .date_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected date",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.date_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .date_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected date",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.time => if (token.tag != .time_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected time",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.time_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .time_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected time",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.datetime => if (token.tag != .datetime_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected datetime",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.datetime_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .datetime_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected datetime",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.link, .link_array => {},
else => unreachable,
}
// And finally create the ConditionValue
switch (data_type) {
.int => return ConditionValue.initInt(self.toker.buffer[start_index..token.loc.end]),
.float => return ConditionValue.initFloat(self.toker.buffer[start_index..token.loc.end]),
.str => return ConditionValue.initStr(self.toker.buffer[start_index + 1 .. token.loc.end - 1]),
.date => return ConditionValue.initDate(self.toker.buffer[start_index..token.loc.end]),
.time => return ConditionValue.initTime(self.toker.buffer[start_index..token.loc.end]),
.datetime => return ConditionValue.initDateTime(self.toker.buffer[start_index..token.loc.end]),
.bool => return ConditionValue.initBool(self.toker.buffer[start_index..token.loc.end]),
.int_array => return try ConditionValue.initArrayInt(allocator, self.toker.buffer[start_index..token.loc.end]),
.str_array => return try ConditionValue.initArrayStr(allocator, self.toker.buffer[start_index..token.loc.end]),
.bool_array => return try ConditionValue.initArrayBool(allocator, self.toker.buffer[start_index..token.loc.end]),
.float_array => return try ConditionValue.initArrayFloat(allocator, self.toker.buffer[start_index..token.loc.end]),
.date_array => return try ConditionValue.initArrayDate(allocator, self.toker.buffer[start_index..token.loc.end]),
.time_array => return try ConditionValue.initArrayTime(allocator, self.toker.buffer[start_index..token.loc.end]),
.datetime_array => return try ConditionValue.initArrayDateTime(allocator, self.toker.buffer[start_index..token.loc.end]),
return try ConditionValue.initArrayInt(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.float_array => {
var array = std.ArrayList(f64).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .float_literal) return printError(
"Error: Wrong type. Expected float.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(s2t.parseFloat(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError;
}
return try ConditionValue.initArrayFloat(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.bool_array => {
var array = std.ArrayList(bool).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .bool_literal_false and token.tag != .bool_literal_true) return printError(
"Error: Wrong type. Expected bool.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(s2t.parseBool(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError;
}
return try ConditionValue.initArrayBool(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.str_array => {
var array = std.ArrayList([]const u8).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .string_literal) return printError(
"Error: Wrong type. Expected str.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(self.toker.getTokenSlice(token.*)) catch return ZipponError.MemoryError;
}
return try ConditionValue.initArrayStr(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.date_array => {
var array = std.ArrayList(u64).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .date_literal and token.tag != .keyword_now) return printError(
"Error: Wrong type. Expected date.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(s2t.parseDate(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError;
}
return try ConditionValue.initArrayUnix(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.time_array => {
var array = std.ArrayList(u64).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .time_literal and token.tag != .keyword_now) return printError(
"Error: Wrong type. Expected time.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(s2t.parseTime(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError;
}
return try ConditionValue.initArrayUnix(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.datetime_array => {
var array = std.ArrayList(u64).init(allocator);
errdefer array.deinit();
var first = true;
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (!first) {
if (token.tag != .comma) return printError(
"Error: Expected comma.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
token.* = self.toker.next();
} else first = false;
if (token.tag != .datetime_literal and token.tag != .date_literal and token.tag != .keyword_now) return printError(
"Error: Wrong type. Expected datetime.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
array.append(s2t.parseDatetime(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError;
}
return try ConditionValue.initArrayUnix(array.toOwnedSlice() catch return ZipponError.MemoryError);
},
.link => switch (token.tag) {
.keyword_none => {
_ = self.toker.next();
@ -239,12 +417,11 @@ pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []cons
token.loc.end,
),
},
.link_array => switch (token.tag) {
.keyword_none => {
const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError;
map.* = std.AutoHashMap(UUID, void).init(allocator);
_ = self.toker.next();
return ConditionValue.initArrayLink(map);
return ConditionValue.initArrayLink(&empty_map);
},
.l_brace, .l_bracket => {
var filter: ?Filter = null;
@ -292,6 +469,5 @@ pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []cons
token.loc.end,
),
},
.self => unreachable,
}
}

View File

@ -1,122 +0,0 @@
const std = @import("std");
const config = @import("config");
const Allocator = std.mem.Allocator;
const Token = @import("tokenizer.zig").Token;
const Condition = @import("../dataStructure/filter.zig").Condition;
const printError = @import("../utils.zig").printError;
const ZipponError = @import("error").ZipponError;
const Self = @import("parser.zig");
/// Check if all token in an array is of one specific type
pub fn checkTokensInArray(self: Self, tag: Token.Tag) ZipponError!Token {
var token = self.toker.next();
while (token.tag != .r_bracket) : (token = self.toker.next()) {
if (token.tag != tag) return printError(
"Error: Wrong type.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
return token;
}
/// Will check if what is compared is ok, like comparing if a string is superior to another string is not for example.
pub fn checkConditionValidity(
self: Self,
condition: Condition,
token: Token,
) ZipponError!void {
switch (condition.operation) {
.equal => switch (condition.data_type) {
.int, .float, .str, .bool, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, str, bool, date, time, datetime can be compare with =",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.different => switch (condition.data_type) {
.int, .float, .str, .bool, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, str, bool, date, time, datetime can be compare with !=",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.superior_or_equal => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with >=",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.superior => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with >",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.inferior_or_equal => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with <=",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.inferior => switch (condition.data_type) {
.int, .float, .date, .time, .datetime => {},
else => return printError(
"Error: Only int, float, date, time, datetime can be compare with <",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.in => switch (condition.data_type) {
.link => {},
else => return printError(
"Error: Only link can be compare with IN.",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.not_in => switch (condition.data_type) {
.link => {},
else => return printError(
"Error: Only link can be compare with !IN.",
ZipponError.ConditionError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
}
}