Added some log and started testing array manip. Fixed some errors already

This commit is contained in:
Adrien Bouvais 2025-01-25 21:15:04 +01:00
parent 4066803ecd
commit baf6cd2284
11 changed files with 112 additions and 57 deletions

View File

@ -9,3 +9,13 @@ User (
best_friend: User,
friends: []User,
)
ArrayTest (
array_int: []int,
array_float: []float,
array_str: []str,
array_bool: []bool,
array_date: []date,
array_time: []time,
array_datetime: []datetime,
)

View File

@ -27,6 +27,7 @@ schema_engine: SchemaEngine = undefined,
thread_engine: ThreadEngine = undefined,
pub fn init(allocator: Allocator, potential_main_path: ?[]const u8, potential_schema_path: ?[]const u8) Self {
log.debug("DatabaseEngine Initializing.", .{});
var self = Self{ .allocator = allocator };
self.thread_engine = ThreadEngine.init(self.allocator) catch {
@ -34,12 +35,13 @@ pub fn init(allocator: Allocator, potential_main_path: ?[]const u8, potential_sc
self.state = .MissingThreadEngine;
return self;
};
log.debug("ThreadEngine initialized.", .{});
const potential_main_path_or_environment_variable = potential_main_path orelse getEnvVariable(self.allocator, "ZIPPONDB_PATH");
if (potential_main_path_or_environment_variable) |main_path| {
setLogPath(main_path);
log.info("Found ZIPPONDB_PATH: {s}.", .{main_path});
log.debug("Found ZIPPONDB_PATH: {s}.", .{main_path});
self.file_engine = FileEngine.init(self.allocator, main_path, self.thread_engine.thread_pool) catch {
log.err("Error when init FileEngine", .{});
self.state = .MissingFileEngine;
@ -53,10 +55,11 @@ pub fn init(allocator: Allocator, potential_main_path: ?[]const u8, potential_sc
self.state = .MissingSchemaEngine;
} else {
log.info("No ZIPPONDB_PATH found.", .{});
log.debug("No ZIPPONDB_PATH found.", .{});
self.state = .MissingFileEngine;
return self;
}
log.debug("FileEngine initialized.", .{});
if (self.file_engine.isSchemaFileInDir() and potential_schema_path == null) {
const schema_path = std.fmt.bufPrint(&path_buffer, "{s}/schema", .{self.file_engine.path_to_ZipponDB_dir}) catch {
@ -64,7 +67,7 @@ pub fn init(allocator: Allocator, potential_main_path: ?[]const u8, potential_sc
return self;
};
log.info("Schema founded in the database directory.", .{});
log.debug("Schema founded in the database directory.", .{});
self.schema_engine = SchemaEngine.init(self.allocator, schema_path, &self.file_engine) catch |err| {
log.err("Error when init SchemaEngine: {any}", .{err});
self.state = .MissingSchemaEngine;
@ -80,13 +83,14 @@ pub fn init(allocator: Allocator, potential_main_path: ?[]const u8, potential_sc
self.file_engine.schema_engine = self.schema_engine;
self.state = .Ok;
log.debug("SchemaEngine initialized.", .{});
return self;
}
log.info("Database don't have any schema yet, trying to add one.", .{});
if (potential_schema_path == null) log.info("Database don't have any schema yet, trying to add one.", .{});
const potential_schema_path_or_environment_variable = potential_schema_path orelse getEnvVariable(self.allocator, "ZIPPONDB_SCHEMA");
if (potential_schema_path_or_environment_variable) |schema_path| {
log.info("Found schema path {s}.", .{schema_path});
log.debug("Found schema path {s}.", .{schema_path});
self.schema_engine = SchemaEngine.init(self.allocator, schema_path, &self.file_engine) catch |err| {
log.err("Error when init SchemaEngine: {any}", .{err});
self.state = .MissingSchemaEngine;
@ -105,8 +109,9 @@ pub fn init(allocator: Allocator, potential_main_path: ?[]const u8, potential_sc
};
self.state = .Ok;
log.debug("SchemaEngine initialized.", .{});
} else {
log.info(config.HELP_MESSAGE.no_schema, .{self.file_engine.path_to_ZipponDB_dir});
log.debug(config.HELP_MESSAGE.no_schema, .{self.file_engine.path_to_ZipponDB_dir});
}
return self;

View File

@ -312,7 +312,8 @@ 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
// TODO: Also be able to it for array to array. Like names in ['something']
// And it is true if at least one value are shared between array.
.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),

View File

@ -26,6 +26,7 @@ thread_pool: *Pool, // same pool as the ThreadEngine
schema_engine: SchemaEngine = undefined, // This is init after the FileEngine and I attach after. Do I need to init after tho ?
pub fn init(allocator: std.mem.Allocator, path: []const u8, thread_pool: *Pool) ZipponError!Self {
log.debug("FileEngine Initializing with path {s}", .{path});
return Self{
.allocator = allocator,
.path_to_ZipponDB_dir = std.fmt.bufPrint(&path_to_ZipponDB_dir_buffer, "{s}", .{path}) catch return ZipponError.MemoryError,

View File

@ -148,7 +148,6 @@ fn updateEntitiesOneFile(
dir: std.fs.Dir,
sync_context: *ThreadSyncContext,
) void {
log.debug("{any}\n", .{@TypeOf(writer)});
var data_buffer: [config.BUFFER_SIZE]u8 = undefined;
var fa = std.heap.FixedBufferAllocator.init(&data_buffer);
defer fa.reset();

View File

@ -7,7 +7,7 @@ const Tokenizer = @import("tokenizer.zig").Tokenizer;
const Parser = @import("parser.zig").Parser;
const ZipponError = @import("error").ZipponError;
const log = std.log.scoped(.schemaEngine);
const log = std.log.scoped(.schema);
/// Manage everything that is relate to the schema
/// This include keeping in memory the schema and schema file, and some functions to get like all members of a specific struct.
@ -23,13 +23,13 @@ struct_array: []SchemaStruct,
null_terminated: [:0]u8,
pub fn init(parent_allocator: Allocator, path: []const u8, file_engine: *FileEngine) ZipponError!Self {
log.debug("SchemaEngine Initializing with path {s}", .{path});
const arena = parent_allocator.create(std.heap.ArenaAllocator) catch return ZipponError.MemoryError;
errdefer arena.deinit();
arena.* = std.heap.ArenaAllocator.init(parent_allocator);
const allocator = arena.allocator();
var buffer: [config.BUFFER_SIZE]u8 = undefined;
log.debug("Trying to init a SchemaEngine with path {s}", .{path});
const len: usize = try FileEngine.readSchemaFile(path, &buffer);
const null_terminated = std.fmt.bufPrintZ(&schema_buffer, "{s}", .{buffer[0..len]}) catch return ZipponError.MemoryError;
@ -57,6 +57,7 @@ pub fn init(parent_allocator: Allocator, path: []const u8, file_engine: *FileEng
}
pub fn deinit(self: *Self) void {
log.debug("Deinit SchemaEngine.", .{});
const parent_allocator = self.arena.child_allocator;
self.arena.deinit();
parent_allocator.destroy(self.arena);

View File

@ -27,23 +27,26 @@ test "Clear" {
try testParsing(db, "DELETE User {}");
}
// Basic
// ===============================================================
test "ADD" {
const db = DB{ .path = "test1", .schema = "schema/test" };
try testParsing(db, "ADD User (name = 'Bob', email='bob@email.com', age=55, scores=[ 1 ], best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bob', email='bob@email.com', age=55, scores=[ 666 123 331 ], best_friend=none, friends=none, bday=2000/11/01, a_time=12:04:54, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bob', email='bob@email.com', age=55, scores=[ 666, 123, 331 ], best_friend=none, friends=none, bday=2000/11/01, a_time=12:04:54, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bob', email='bob@email.com', age=-55, scores=[ 33 ], best_friend=none, friends=none, bday=2000/01/04, a_time=12:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Boba', email='boba@email.com', age=20, scores=[ ], best_friend=none, friends=none, bday=2000/06/06, a_time=04:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bob', email='bob@email.com', age=-55, scores=[ 1 ], best_friend={name='Bob'}, friends=none, bday=2000/01/01, a_time=12:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bou', email='bob@email.com', age=66, scores=[ 1 ], best_friend={name = 'Boba'}, friends={name = 'Bob'}, bday=2000/01/01, a_time=02:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bobibou', email='bob@email.com', age=66, scores=[ 1 ], best_friend={name = 'Boba'}, friends=[1]{name = 'Bob'}, bday=2000/01/01, a_time=02:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bob', email='bob@email.com', age=-55, scores=[ 1, ], best_friend={name='Bob'}, friends=none, bday=2000/01/01, a_time=12:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bou', email='bob@email.com', age=66, scores=[ 1, ], best_friend={name = 'Boba'}, friends={name = 'Bob'}, bday=2000/01/01, a_time=02:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'Bobibou', email='bob@email.com', age=66, scores=[ 1, ], best_friend={name = 'Boba'}, friends=[1]{name = 'Bob'}, bday=2000/01/01, a_time=02:04:54.8741, last_order=2000/01/01-12:45)");
try testParsing(db, "GRAB User {}");
}
test "ADD batch" {
const db = DB{ .path = "test1", .schema = "schema/test" };
try testParsing(db, "ADD User (name = 'ewq', email='ewq@email.com', age=22, scores=[ ], best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45) (name = 'Roger', email='roger@email.com', age=10, scores=[ 1 11 111 123 562345 123451234 34623465234 12341234 ], best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'ewq', email='ewq@email.com', age=22, scores=[ ], best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45) (name = 'Roger', email='roger@email.com', age=10, scores=[ 1, 11, 111, 123, 562345, 123451234, 34623465234, 12341234 ], best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45)");
try testParsing(db, "ADD User (name = 'qwe', email='qwe@email.com', age=57, scores=[ ], best_friend=none, friends=none, bday=2000/01/01, a_time=12:04, last_order=2000/01/01-12:45) ('Rodrigo', 'bob@email.com', 55, [ 1 ], {name = 'qwe'}, none, 2000/01/01, 12:04, 2000/01/01-12:45)");
try testParsing(db, "GRAB User [name, best_friend] {name = 'Rodrigo'}");
@ -93,6 +96,17 @@ test "Specific query" {
try testParsing(db, "GRAB User [1]");
}
// Array manipulation
// ===============================================================
test "GRAB name IN" {
const db = DB{ .path = "test1", .schema = "schema/test" };
try testParsing(db, "GRAB User {name IN ['Bob', 'Bobinou']}");
}
// Single Struct Relationship
// ===============================================================
test "UPDATE relationship" {
const db = DB{ .path = "test1", .schema = "schema/test" };
try testParsing(db, "UPDATE User [1] {name='Bob'} TO (best_friend = {name='Boba'} )");
@ -124,11 +138,6 @@ 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" };
@ -139,11 +148,17 @@ test "GRAB Relationship dot" {
try testParsing(db, "GRAB User [1] {}");
}
// Cleaning
// ===============================================================
test "DELETE" {
const db = DB{ .path = "test1", .schema = "schema/test" };
try testParsing(db, "DELETE User {}");
}
// 3 Struct Relationship
// ===============================================================
test "3 struct base" {
const db = DB{ .path = "test2", .schema = "schema/test-3struct" };
try testParsing(db, "DELETE User {}");
@ -172,7 +187,10 @@ test "3 struct both side" {
fn testParsing(db: DB, source: [:0]const u8) !void {
const allocator = std.testing.allocator;
var db_engine = DBEngine.init(allocator, db.path, db.schema);
defer db_engine.deinit();
defer {
db_engine.deinit();
std.debug.print("\n\n-------------------------------\n\n", .{});
}
var parser = Parser.init(
&db_engine.file_engine,
@ -181,13 +199,15 @@ fn testParsing(db: DB, source: [:0]const u8) !void {
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 {
const allocator = std.testing.allocator;
var db_engine = DBEngine.init(allocator, db.path, db.schema);
defer db_engine.deinit();
defer {
db_engine.deinit();
std.debug.print("\n\n-------------------------------\n\n", .{});
}
var parser = Parser.init(
&db_engine.file_engine,
@ -196,5 +216,4 @@ fn expectParsingError(db: DB, source: [:0]const u8, err: ZipponError) !void {
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

@ -16,9 +16,8 @@ pub fn myLog(
comptime format: []const u8,
args: anytype,
) void {
_ = message_level;
_ = scope;
if (true) {
if (message_level == .debug) {
std.debug.print(format, args);
std.debug.print("\n", .{});
}

View File

@ -8,18 +8,20 @@ const log = std.log.scoped(.thread);
pub const ThreadEngine = @This();
allocator: std.mem.Allocator,
thread_arena: *std.heap.ThreadSafeAllocator,
thread_pool: *Pool,
pub fn init(allocator: std.mem.Allocator) !ThreadEngine {
log.debug("ThreadEngine Initializing.", .{});
const thread_arena = try allocator.create(std.heap.ThreadSafeAllocator);
thread_arena.* = std.heap.ThreadSafeAllocator{
.child_allocator = allocator,
};
const cpu_core = if (CPU_CORE == 0) std.Thread.getCpuCount() catch 1 else CPU_CORE;
log.info("Using {d} cpu core", .{cpu_core});
log.info("Using {d}Mb stack size", .{std.Thread.SpawnConfig.default_stack_size / 1024 / 1024});
log.debug(" Using {d} cpu core.", .{cpu_core});
log.debug(" Using {d}Mb stack size.", .{std.Thread.SpawnConfig.default_stack_size / 1024 / 1024});
const thread_pool = try allocator.create(std.Thread.Pool);
try thread_pool.init(std.Thread.Pool.Options{
@ -28,23 +30,25 @@ pub fn init(allocator: std.mem.Allocator) !ThreadEngine {
});
return ThreadEngine{
.allocator = allocator,
.thread_pool = thread_pool,
.thread_arena = thread_arena,
};
}
pub fn deinit(self: *ThreadEngine) void {
const parent_allocator = self.thread_arena.allocator();
log.debug("Deinit ThreadEngine.", .{});
self.thread_pool.deinit();
parent_allocator.destroy(self.thread_arena);
parent_allocator.destroy(self.thread_pool);
self.allocator.destroy(self.thread_arena);
self.allocator.destroy(self.thread_pool);
}
// Not tested, for later when config is runtime
pub fn setCpuCore(self: *ThreadEngine, cpu_core: usize) void {
log.debug("Set CPU count to {d}.", .{cpu_core});
self.thread_pool.deinit();
self.thread_pool.init(std.Thread.Pool.Options{
.allocator = self.thread_arena.allocator(),
.allocator = self.allocator,
.n_jobs = cpu_core,
});
}

View File

@ -71,7 +71,12 @@ pub fn parseCondition(
.expect_operation => {
condition.operation = try self.parseComparisonOperator(token);
if (condition.operation == .in) condition.data_type = switch (condition.data_type) {
state = .expect_value;
},
.expect_value => {
var data_type = condition.data_type;
if (condition.operation == .in) data_type = switch (condition.data_type) {
.int => .int_array,
.float => .float_array,
.str => .str_array,
@ -79,14 +84,11 @@ pub fn parseCondition(
.date => .date_array,
.time => .time_array,
.datetime => .datetime_array,
else => condition.data_type,
.link, .link_array => data_type,
else => unreachable,
};
log.debug("Condition operation {any}\n", .{condition.operation});
state = .expect_value;
},
.expect_value => {
condition.value = try self.parseConditionValue(allocator, struct_name, member_name, condition.data_type, &token);
condition.value = try self.parseConditionValue(allocator, struct_name, member_name, data_type, &token);
state = .end;
},
@ -171,12 +173,12 @@ pub fn checkConditionValidity(
},
.in => switch (condition.data_type) {
.link, .int_array, .float_array, .str_array, .bool_array, .time_array, .date_array, .datetime_array => {},
.link, .int, .float, .str, .bool, .time, .date, .datetime => {},
else => unreachable,
},
.not_in => switch (condition.data_type) {
.link, .int_array, .float_array, .str_array, .bool_array, .time_array, .date_array, .datetime_array => {},
.link, .int, .float, .str, .bool, .time, .date, .datetime => {},
else => unreachable,
},
}

View File

@ -35,7 +35,7 @@ pub fn parseConditionValue(
) ZipponError!ConditionValue {
const start_index = token.loc.start;
if (data_type.is_array()) switch (token.tag) {
if (data_type.is_array() and data_type != .link_array) switch (token.tag) {
.l_bracket => token.* = self.toker.next(),
else => return printError(
"Error: expecting [ to start array.",
@ -150,14 +150,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .int_literal) return printError(
if (token.tag == .int_literal) array.append(s2t.parseInt(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError;
if (token.tag == .int_literal or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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;
}
return try ConditionValue.initArrayInt(array.toOwnedSlice() catch return ZipponError.MemoryError);
@ -180,14 +182,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .float_literal) return printError(
if (token.tag == .float_literal) array.append(s2t.parseFloat(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError;
if (token.tag == .float_literal or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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);
@ -210,14 +214,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .bool_literal_false and token.tag != .bool_literal_true) return printError(
if (token.tag == .bool_literal_false or token.tag == .bool_literal_false) array.append(s2t.parseBool(self.toker.getTokenSlice(token.*))) catch return ZipponError.MemoryError;
if (token.tag == .bool_literal_false or token.tag == .bool_literal_false or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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);
@ -240,14 +246,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .string_literal) return printError(
if (token.tag == .string_literal) array.append(self.toker.getTokenSlice(token.*)) catch return ZipponError.MemoryError;
if (token.tag == .string_literal or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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);
@ -270,14 +278,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .date_literal and token.tag != .keyword_now) return printError(
if (token.tag == .date_literal or token.tag == .keyword_now) array.append(s2t.parseDate(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError;
if (token.tag == .date_literal or token.tag == .keyword_now or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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);
@ -300,14 +310,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .time_literal and token.tag != .keyword_now) return printError(
if (token.tag == .time_literal or token.tag == .keyword_now) array.append(s2t.parseTime(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError;
if (token.tag == .time_literal or token.tag == .keyword_now or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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);
@ -330,14 +342,16 @@ pub fn parseConditionValue(
token.* = self.toker.next();
} else first = false;
if (token.tag != .datetime_literal and token.tag != .date_literal and token.tag != .keyword_now) return printError(
if (token.tag == .datetime_literal or token.tag == .date_literal or token.tag == .keyword_now) array.append(s2t.parseDatetime(self.toker.getTokenSlice(token.*)).toUnix()) catch return ZipponError.MemoryError;
if (token.tag == .datetime_literal or token.tag == .date_literal or token.tag == .keyword_now or token.tag == .comma) continue;
if (token.tag == .r_bracket) break;
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);