const std = @import("std"); const dtype = @import("dtype"); const UUID = dtype.UUID; const Allocator = std.mem.Allocator; const Token = @import("../tokenizer.zig").Token; const Filter = @import("../../dataStructure/filter.zig").Filter; const ConditionValue = @import("../../dataStructure/filter.zig").ConditionValue; const AdditionalData = @import("../../dataStructure/additionalData.zig").AdditionalData; const printError = @import("../../utils.zig").printError; const ZipponError = @import("error").ZipponError; const Self = @import("../parser.zig"); /// 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 { 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 }; // Check if the all next tokens are the right one if (expected_tag) |tag| { if (data_type.is_array()) { token.* = try self.checkTokensInArray(tag); } else { if (token.tag != tag) { return printError( "Error: Wrong type", // TODO: Print the expected type ZipponError.SynthaxError, self.toker.buffer, token.loc.start, token.loc.end, ); } } } 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]), .link => switch (token.tag) { .keyword_none => { // TODO: Stop creating a map if empty, can be null or something. Or maybe just keep one map link that in memory, so I dont create it everytime const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError; map.* = std.AutoHashMap(UUID, void).init(allocator); map.put(dtype.Zero, {}) catch return ZipponError.MemoryError; _ = self.toker.next(); return ConditionValue.initLink(map); }, .uuid_literal => { const uuid = UUID.parse(self.toker.buffer[start_index..token.loc.end]) catch return ZipponError.InvalidUUID; if (!self.schema_engine.isUUIDExist(struct_name, uuid)) return printError( "Error: UUID do not exist in database.", ZipponError.SynthaxError, self.toker.buffer, token.loc.start, token.loc.end, ); const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError; map.* = std.AutoHashMap(UUID, void).init(allocator); map.put(uuid, {}) catch return ZipponError.MemoryError; _ = self.toker.next(); return ConditionValue.initLink(map); }, .l_brace, .l_bracket => { var filter: ?Filter = null; defer if (filter != null) filter.?.deinit(); var additional_data_arena = std.heap.ArenaAllocator.init(allocator); defer additional_data_arena.deinit(); var additional_data = AdditionalData.init(additional_data_arena.allocator()); if (token.tag == .l_bracket) { try self.parseAdditionalData(allocator, &additional_data, struct_name); token.* = self.toker.next(); } additional_data.limit = 1; const link_sstruct = try self.schema_engine.linkedStructName(struct_name, member_name); if (token.tag == .l_brace) filter = try self.parseFilter( allocator, link_sstruct.name, false, ) else return printError( "Error: Expected filter", ZipponError.SynthaxError, self.toker.buffer, token.loc.start, token.loc.end, ); filter = switch (filter.?.root.*) { .empty => null, else => filter, }; // Here I have the filter and additionalData const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError; map.* = std.AutoHashMap(UUID, void).init(allocator); try self.file_engine.populateVoidUUIDMap( link_sstruct.name, filter, map, &additional_data, ); return ConditionValue.initLink(map); }, else => return printError( "Error: Expected uuid or none", ZipponError.SynthaxError, self.toker.buffer, token.loc.start, 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); }, .l_brace, .l_bracket => { var filter: ?Filter = null; defer if (filter != null) filter.?.deinit(); var additional_data_arena = std.heap.ArenaAllocator.init(allocator); defer additional_data_arena.deinit(); var additional_data = AdditionalData.init(additional_data_arena.allocator()); if (token.tag == .l_bracket) { try self.parseAdditionalData(allocator, &additional_data, struct_name); token.* = self.toker.next(); } const link_sstruct = try self.schema_engine.linkedStructName(struct_name, member_name); if (token.tag == .l_brace) filter = try self.parseFilter(allocator, link_sstruct.name, false) else return printError( "Error: Expected filter", ZipponError.SynthaxError, self.toker.buffer, token.loc.start, token.loc.end, ); filter = switch (filter.?.root.*) { .empty => null, else => filter, }; // Here I have the filter and additionalData const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError; map.* = std.AutoHashMap(UUID, void).init(allocator); try self.file_engine.populateVoidUUIDMap( struct_name, filter, map, &additional_data, ); return ConditionValue.initArrayLink(map); }, else => return printError( "Error: Expected uuid or none", ZipponError.SynthaxError, self.toker.buffer, token.loc.start, token.loc.end, ), }, .self => unreachable, } }