mirror of
https://github.com/ziglang/zig.git
synced 2026-01-15 03:45:22 +00:00
The logic for putting ranges into the else prong is moved from AstGen to Sema. However, logic to emit multi-items the same as single-items cannot be done until TZIR supports mapping multiple items to the same block of code. This will be simple to represent when we do the upcoming TZIR memory layout changes. Not yet implemented in this commit is the validation of duplicate values. The trick is going to be emitting error messages with accurate source locations, without adding extra source nodes to the ZIR switch instruction. This will be done by computing the respective AST node based on the switch node (which we do have available), only when a compile error occurs and we need to know the source location to attach the message to.
80 lines
2.0 KiB
Zig
80 lines
2.0 KiB
Zig
const std = @import("std");
|
|
const Order = std.math.Order;
|
|
const Value = @import("value.zig").Value;
|
|
const RangeSet = @This();
|
|
|
|
ranges: std.ArrayList(Range),
|
|
|
|
pub const Range = struct {
|
|
start: Value,
|
|
end: Value,
|
|
src: usize,
|
|
};
|
|
|
|
pub fn init(allocator: *std.mem.Allocator) RangeSet {
|
|
return .{
|
|
.ranges = std.ArrayList(Range).init(allocator),
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *RangeSet) void {
|
|
self.ranges.deinit();
|
|
}
|
|
|
|
pub fn add(self: *RangeSet, start: Value, end: Value, src: usize) !?usize {
|
|
for (self.ranges.items) |range| {
|
|
if ((start.compare(.gte, range.start) and start.compare(.lte, range.end)) or
|
|
(end.compare(.gte, range.start) and end.compare(.lte, range.end)))
|
|
{
|
|
// ranges overlap
|
|
return range.src;
|
|
}
|
|
}
|
|
try self.ranges.append(.{
|
|
.start = start,
|
|
.end = end,
|
|
.src = src,
|
|
});
|
|
return null;
|
|
}
|
|
|
|
/// Assumes a and b do not overlap
|
|
fn lessThan(_: void, a: Range, b: Range) bool {
|
|
return a.start.compare(.lt, b.start);
|
|
}
|
|
|
|
pub fn spans(self: *RangeSet, start: Value, end: Value) !bool {
|
|
if (self.ranges.items.len == 0)
|
|
return false;
|
|
|
|
std.sort.sort(Range, self.ranges.items, {}, lessThan);
|
|
|
|
if (!self.ranges.items[0].start.eql(start) or
|
|
!self.ranges.items[self.ranges.items.len - 1].end.eql(end))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var space: Value.BigIntSpace = undefined;
|
|
|
|
var counter = try std.math.big.int.Managed.init(self.ranges.allocator);
|
|
defer counter.deinit();
|
|
|
|
// look for gaps
|
|
for (self.ranges.items[1..]) |cur, i| {
|
|
// i starts counting from the second item.
|
|
const prev = self.ranges.items[i];
|
|
|
|
// prev.end + 1 == cur.start
|
|
try counter.copy(prev.end.toBigInt(&space));
|
|
try counter.addScalar(counter.toConst(), 1);
|
|
|
|
const cur_start_int = cur.start.toBigInt(&space);
|
|
if (!cur_start_int.eq(counter.toConst())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|