diff --git a/core/_preload.odin b/core/_preload.odin index 9153f2b55..a86eee836 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -339,7 +339,7 @@ __bounds_check_error :: proc(file: string, line, column: int, index, count: int) if 0 <= index && index < count { return; } - fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..%d\n", + fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n", file, line, column, index, count); __debug_trap(); } @@ -348,7 +348,7 @@ __slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) if 0 <= low && low <= high && high <= max { return; } - fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n", + fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..<%d..<%d]\n", file, line, column, low, high, max); __debug_trap(); } @@ -356,7 +356,7 @@ __substring_expr_error :: proc(file: string, line, column: int, low, high: int) if 0 <= low && low <= high { return; } - fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..%d]\n", + fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..<%d]\n", file, line, column, low, high); __debug_trap(); } @@ -395,7 +395,7 @@ __mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr { } __mem_compare :: proc(a, b: ^byte, n: int) -> int { - for i in 0..n { + for i in 0.. string { // TODO(bill): make this work with a buffer that's not big enough assert(len(buf) >= n); - buf = buf[..n]; + buf = buf[0.. int { data: [_BUFFER_SIZE]byte; - buf := data[..0]; + buf := data[0..<0]; bprint(^buf, ..args); - os.write(fd, buf[..len(buf)]); + os.write(fd, buf); return len(buf); } fprintln :: proc(fd: os.Handle, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := data[..0]; + buf := data[0..<0]; bprintln(^buf, ..args); - os.write(fd, buf[..len(buf)]); + os.write(fd, buf); return len(buf); } fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := data[..0]; + buf := data[0..<0]; bprintf(^buf, fmt, ..args); - os.write(fd, buf[..len(buf)]); + os.write(fd, buf); return len(buf); } @@ -82,9 +82,9 @@ printf :: proc(fmt: string, args: ..any) -> int { fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { data: [_BUFFER_SIZE]byte; - buf := data[..0]; + buf := data[0..<0]; write_type(^buf, info); - os.write(fd, buf[..len(buf)]); + os.write(fd, buf); } write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { @@ -305,15 +305,15 @@ bprintln :: proc(buf: ^[]byte, args: ..any) -> int { sprint :: proc(buf: []byte, args: ..any) -> string { count := bprint(^buf, ..args); - return cast(string)buf[..count]; + return cast(string)buf[0.. string { count := bprintln(^buf, ..args); - return cast(string)buf[..count]; + return cast(string)buf[0.. string { count := bprintf(^buf, fmt, ..args); - return cast(string)buf[..count]; + return cast(string)buf[0.. len(str) { write_byte(fi.buf, str[0]); fmt_write_padding(fi, fi.width - len(str)); - write_string(fi.buf, str[1..]); + write_string(fi.buf, str[1..<]); } else { _pad(fi, str); } @@ -628,7 +628,7 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) { fi.space = false; defer fi.space = space; - for i in 0..len(s) { + for i in 0.. 0 && space { write_byte(fi.buf, ' '); } @@ -776,7 +776,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '['); defer write_byte(fi.buf, ']'); - for i in 0..info.count { + for i in 0.. 0 { write_string(fi.buf, ", "); } @@ -793,7 +793,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '['); defer write_byte(fi.buf, ']'); array := cast(^raw.Dynamic_Array)v.data; - for i in 0..array.len { + for i in 0.. 0 { write_string(fi.buf, ", "); } @@ -815,7 +815,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { entry_type := union_cast(^Struct)ed.elem; entry_size := ed.elem_size; - for i in 0..entries.len { + for i in 0.. 0 { write_string(fi.buf, ", "); } @@ -844,7 +844,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '['); defer write_byte(fi.buf, ']'); slice := cast(^[]byte)v.data; - for i in 0..len(slice) { + for _, i in slice { if i > 0 { write_string(fi.buf, ", "); } @@ -856,7 +856,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { write_byte(fi.buf, '<'); defer write_byte(fi.buf, '>'); - for i in 0..info.count { + for i in 0.. 0 { write_string(fi.buf, ", "); } @@ -1011,7 +1011,7 @@ bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { i++; } if i > prev_i { - write_string(b, fmt[prev_i..i]); + write_string(b, fmt[prev_i..= end { break; diff --git a/core/hash.odin b/core/hash.odin index 5ed4863e0..2f9659f7a 100644 --- a/core/hash.odin +++ b/core/hash.odin @@ -175,7 +175,7 @@ murmur64 :: proc(data: []byte) -> u64 { } // TODO(bill): Fix this - #no_bounds_check data8 := slice_to_bytes(data32[i..])[..3]; + #no_bounds_check data8 := slice_to_bytes(data32[i..])[..<3]; match len { case 3: h2 ~= cast(u32)data8[2] << 16; diff --git a/core/math.odin b/core/math.odin index 44e9b50b4..8ad563035 100644 --- a/core/math.odin +++ b/core/math.odin @@ -160,8 +160,8 @@ mat4_identity :: proc() -> Mat4 { } mat4_transpose :: proc(m: Mat4) -> Mat4 { - for j in 0..4 { - for i in 0..4 { + for j in 0..<4 { + for i in 0..<4 { m[i][j], m[j][i] = m[j][i], m[i][j]; } } @@ -170,8 +170,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 { mul :: proc(a, b: Mat4) -> Mat4 { c: Mat4; - for j in 0..4 { - for i in 0..4 { + for j in 0..<4 { + for i in 0..<4 { c[j][i] = a[0][i]*b[j][0] + a[1][i]*b[j][1] + a[2][i]*b[j][2] + diff --git a/core/mem.odin b/core/mem.odin index f3396b7ac..27146a60d 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -96,7 +96,7 @@ Arena_Temp_Memory :: struct { init_arena_from_memory :: proc(using a: ^Arena, data: []byte) { backing = Allocator{}; - memory = data[..0]; + memory = data[0..<0]; temp_count = 0; } @@ -169,7 +169,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory { end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) { assert(len(arena.memory) >= original_count); assert(arena.temp_count > 0); - arena.memory = arena.memory[..original_count]; + arena.memory = arena.memory[0.. proc() #cc_c { if name[len(name)-1] == 0 { - name = name[..len(name)-1]; + name = name[0.. []string { } } - return cast(string)buf[..i]; + return cast(string)buf[0.. 0 { m := min(digs.count, digs.decimal_point); - append(buf, ..digs.digits[..m]); + append(buf, ..digs.digits[0.. 0 { append(buf, '.'); - for i in 0..prec { + for i in 0.. (rune, int) { } start = max(start, 0); - r, size = decode_rune(s[start..end]); + r, size = decode_rune(s[start..mode = Addressing_Value; } + if (se->low == NULL && se->high != NULL) { + error(se->interval0, "1st index is required if a 2nd index is specified"); + // It is okay to continue as it will assume the 1st index is zero + } + if (se->index3 && (se->high == NULL || se->max == NULL)) { error(se->close, "2nd and 3rd indices are required in a 3-index slice"); o->mode = Addressing_Invalid; @@ -5739,6 +5745,16 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return kind; } + if (se->index3 && se->interval0.kind != se->interval1.kind) { + error(se->close, "The interval separators for in a 3-index slice must be the same"); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + + + TokenKind interval_kind = se->interval0.kind; + i64 indices[2] = {0}; AstNode *nodes[3] = {se->low, se->high, se->max}; for (isize i = 0; i < gb_count_of(nodes); i++) { diff --git a/src/check_stmt.c b/src/check_stmt.c index ca3bc9ac9..78d646302 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -771,7 +771,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { TokenKind op = Token_Lt; switch (ie->op.kind) { - case Token_Ellipsis: op = Token_Lt; break; + case Token_Ellipsis: op = Token_LtEq; break; + case Token_HalfClosed: op = Token_Lt; break; default: error(ie->op, "Invalid range operator"); break; } bool ok = compare_exact_values(op, a, b); diff --git a/src/ir.c b/src/ir.c index 6fb03d7e0..aaddaf84a 100644 --- a/src/ir.c +++ b/src/ir.c @@ -4905,6 +4905,17 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { if (se->low != NULL) low = ir_build_expr(proc, se->low); if (se->high != NULL) high = ir_build_expr(proc, se->high); if (se->max != NULL) max = ir_build_expr(proc, se->max); + + + if (high != NULL && se->interval0.kind == Token_Ellipsis) { + high = ir_emit_arith(proc, Token_Add, high, v_one, t_int); + } + + if (max != NULL && se->interval1.kind == Token_Ellipsis) { + GB_ASSERT(se->interval0.kind == se->interval1.kind); + max = ir_emit_arith(proc, Token_Add, max, v_one, t_int); + } + irValue *addr = ir_build_addr(proc, se->expr).addr; irValue *base = ir_emit_load(proc, addr); Type *type = base_type(ir_type(base)); @@ -5553,7 +5564,8 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type TokenKind op = Token_Lt; switch (node->op.kind) { - case Token_Ellipsis: op = Token_Lt; break; + case Token_Ellipsis: op = Token_LtEq; break; + case Token_HalfClosed: op = Token_Lt; break; default: GB_PANIC("Invalid interval operator"); break; } irValue *cond = ir_emit_comp(proc, op, ir_emit_load(proc, value), upper); diff --git a/src/parser.c b/src/parser.c index 31d14db78..d9b20fca6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -105,6 +105,7 @@ typedef enum FieldFlag { FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_immutable, } FieldListTag; + AstNodeArray make_ast_node_array(AstFile *f) { AstNodeArray a; // array_init(&a, gb_arena_allocator(&f->arena)); @@ -155,9 +156,11 @@ AST_NODE_KIND(_ExprBegin, "", i32) \ AST_NODE_KIND(SelectorExpr, "selector expression", struct { Token token; AstNode *expr, *selector; }) \ AST_NODE_KIND(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \ AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \ - AST_NODE_KIND(SliceExpr, "slice expression", struct { \ + AST_NODE_KIND(SliceExpr, "slice expression", struct { \ AstNode *expr; \ Token open, close; \ + Token interval0; \ + Token interval1; \ bool index3; \ AstNode *low, *high, *max; \ }) \ @@ -686,11 +689,13 @@ AstNode *ast_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open, T } -AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, bool index3, AstNode *low, AstNode *high, AstNode *max) { +AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, Token interval0, Token interval1, bool index3, AstNode *low, AstNode *high, AstNode *max) { AstNode *result = make_ast_node(f, AstNode_SliceExpr); result->SliceExpr.expr = expr; result->SliceExpr.open = open; result->SliceExpr.close = close; + result->SliceExpr.interval0 = interval0; + result->SliceExpr.interval1 = interval1; result->SliceExpr.index3 = index3; result->SliceExpr.low = low; result->SliceExpr.high = high; @@ -1980,15 +1985,19 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { f->expr_level++; open = expect_token(f, Token_OpenBracket); - if (f->curr_token.kind != Token_Ellipsis) { + if (f->curr_token.kind != Token_Ellipsis && + f->curr_token.kind != Token_HalfClosed) { indices[0] = parse_expr(f, false); } bool is_index = true; - while (f->curr_token.kind == Token_Ellipsis && ellipsis_count < gb_count_of(ellipses)) { + while ((f->curr_token.kind == Token_Ellipsis || + f->curr_token.kind == Token_HalfClosed) + && ellipsis_count < gb_count_of(ellipses)) { ellipses[ellipsis_count++] = f->curr_token; next_token(f); if (f->curr_token.kind != Token_Ellipsis && + f->curr_token.kind != Token_HalfClosed && f->curr_token.kind != Token_CloseBracket && f->curr_token.kind != Token_EOF) { indices[ellipsis_count] = parse_expr(f, false); @@ -2013,7 +2022,7 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { indices[2] = ast_bad_expr(f, ellipses[1], close); } } - operand = ast_slice_expr(f, operand, open, close, index3, indices[0], indices[1], indices[2]); + operand = ast_slice_expr(f, operand, open, close, ellipses[0], ellipses[1], index3, indices[0], indices[1], indices[2]); } else { operand = ast_index_expr(f, operand, indices[0], open, close); } @@ -2301,6 +2310,7 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) { allow_token(f, Token_in); AstNode *expr = parse_expr(f, false); switch (f->curr_token.kind) { + case Token_HalfClosed: case Token_Ellipsis: { Token op = f->curr_token; next_token(f); diff --git a/src/tokenizer.c b/src/tokenizer.c index 469620450..ba491e73c 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -75,7 +75,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ TOKEN_KIND(Token_Period, "."), \ TOKEN_KIND(Token_Comma, ","), \ TOKEN_KIND(Token_Ellipsis, ".."), \ - TOKEN_KIND(Token_HalfOpenRange, "..<"), \ + TOKEN_KIND(Token_HalfClosed, "..<"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ @@ -872,7 +872,7 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = Token_Ellipsis; if (t->curr_rune == '<') { advance_to_next_rune(t); - token.kind = Token_HalfOpenRange; + token.kind = Token_HalfClosed; } } break;