lang: slice ranges take the same bound markers as for-header ranges
xs[1..=3] (end inclusive), xs[0<..<4] (both exclusive), xs[..=2] (prefix form with markers, implicit 0 start), xs[2<..] (open end, exclusive start), and xs[..] (whole collection) — lowered as lo+1 / hi+1 on the existing subslice op. Strings slice through the same path. An explicit end marker requires an end expression, matching the for-header rule. Regression: examples/0052-basic-slice-range-bounds.sx.
This commit is contained in:
@@ -594,8 +594,12 @@ pub const IndexExpr = struct {
|
||||
|
||||
pub const SliceExpr = struct {
|
||||
object: *Node,
|
||||
start: ?*Node = null,
|
||||
end: ?*Node = null,
|
||||
start: ?*Node = null, // null = 0
|
||||
end: ?*Node = null, // null = len
|
||||
/// `<..` family — slice begins one past `start`.
|
||||
start_exclusive: bool = false,
|
||||
/// `..=` family — slice includes `end`.
|
||||
end_inclusive: bool = false,
|
||||
};
|
||||
|
||||
pub const PointerTypeExpr = struct {
|
||||
|
||||
@@ -1207,8 +1207,10 @@ pub fn lowerIndexExpr(self: *Lowering, ie: *const ast.IndexExpr) Ref {
|
||||
|
||||
pub fn lowerSliceExpr(self: *Lowering, se: *const ast.SliceExpr) Ref {
|
||||
const obj = self.lowerExpr(se.object);
|
||||
const lo = if (se.start) |s| self.lowerExpr(s) else self.builder.constInt(0, .s64);
|
||||
const hi = if (se.end) |e| self.lowerExpr(e) else self.builder.emit(.{ .length = .{ .operand = obj } }, .s64);
|
||||
var lo = if (se.start) |s| self.lowerExpr(s) else self.builder.constInt(0, .s64);
|
||||
if (se.start_exclusive) lo = self.builder.add(lo, self.builder.constInt(1, .s64), .s64);
|
||||
var hi = if (se.end) |e| self.lowerExpr(e) else self.builder.emit(.{ .length = .{ .operand = obj } }, .s64);
|
||||
if (se.end_inclusive) hi = self.builder.add(hi, self.builder.constInt(1, .s64), .s64);
|
||||
// Infer result slice type from the object
|
||||
const obj_ty = self.inferExprType(se.object);
|
||||
// Subslice of string stays string (same {ptr, i64} layout, correct type category)
|
||||
|
||||
@@ -2575,26 +2575,45 @@ pub const Parser = struct {
|
||||
const saved_hdr_idx = self.in_for_header;
|
||||
self.in_for_header = false;
|
||||
defer self.in_for_header = saved_hdr_idx;
|
||||
if (self.current.tag == .dot_dot) {
|
||||
// [..end]
|
||||
if (rangeTokenInfo(self.current.tag)) |rt| {
|
||||
// Prefix form: [..end] / [..=end] / [..] — implicit 0 start
|
||||
// (a start marker applies to it: [<..end] begins at 1).
|
||||
self.advance();
|
||||
const end_expr = try self.parseExpr();
|
||||
if (rt.end_marked and self.current.tag == .r_bracket) {
|
||||
return self.fail("a range with an explicit end marker ('..=' / '..<') requires an end expression — the open form is '..'");
|
||||
}
|
||||
const end_expr: ?*ast.Node = if (self.current.tag != .r_bracket)
|
||||
try self.parseExpr()
|
||||
else
|
||||
null;
|
||||
try self.expect(.r_bracket);
|
||||
expr = try self.createNode(expr.span.start, .{ .slice_expr = .{
|
||||
.object = expr, .start = null, .end = end_expr,
|
||||
.object = expr,
|
||||
.start = null,
|
||||
.end = end_expr,
|
||||
.start_exclusive = rt.start_exclusive,
|
||||
.end_inclusive = rt.end_inclusive,
|
||||
} });
|
||||
} else {
|
||||
const first = try self.parseExpr();
|
||||
if (self.current.tag == .dot_dot) {
|
||||
// [start..end] or [start..]
|
||||
if (rangeTokenInfo(self.current.tag)) |rt| {
|
||||
// [start..end] or [start..] — same bound-marker matrix
|
||||
// as the for-header ranges.
|
||||
self.advance();
|
||||
if (rt.end_marked and self.current.tag == .r_bracket) {
|
||||
return self.fail("a range with an explicit end marker ('..=' / '..<') requires an end expression — the open form is 'a..'");
|
||||
}
|
||||
const end_expr: ?*ast.Node = if (self.current.tag != .r_bracket)
|
||||
try self.parseExpr()
|
||||
else
|
||||
null;
|
||||
try self.expect(.r_bracket);
|
||||
expr = try self.createNode(expr.span.start, .{ .slice_expr = .{
|
||||
.object = expr, .start = first, .end = end_expr,
|
||||
.object = expr,
|
||||
.start = first,
|
||||
.end = end_expr,
|
||||
.start_exclusive = rt.start_exclusive,
|
||||
.end_inclusive = rt.end_inclusive,
|
||||
} });
|
||||
} else {
|
||||
// [index] — normal index access
|
||||
|
||||
Reference in New Issue
Block a user