From 56c0d32ea0c81ad9913e4e512952b3be25688504 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 18 May 2023 11:52:16 +0100 Subject: Fix #2526 --- src/check_stmt.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/check_stmt.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 388a64e00..1e3b35c21 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -402,6 +402,12 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O Type *assignment_type = lhs->type; + if (rhs->mode == Addressing_Type && is_type_polymorphic(rhs->type)) { + gbString t = type_to_string(rhs->type); + error(rhs->expr, "Invalid use of a non-specialized polymorphic type '%s'", t); + gb_string_free(t); + } + switch (lhs->mode) { case Addressing_Invalid: return nullptr; -- cgit v1.2.3 From d5a8f2298e68c64f2f9e2fe5d0c6ab528db627a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 May 2023 12:37:26 +0100 Subject: Restrict `---` to variable declarations only --- src/check_decl.cpp | 2 +- src/check_expr.cpp | 31 +++++++++++++++++++++++++------ src/check_stmt.cpp | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src/check_stmt.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index e97e86e8b..b16215571 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -123,7 +123,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l // an extra allocation TEMPORARY_ALLOCATOR_GUARD(); auto operands = array_make(temporary_allocator(), 0, 2*lhs_count); - check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false); + check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, UnpackFlag_AllowOk|UnpackFlag_AllowUndef); isize rhs_count = operands.count; isize max = gb_min(lhs_count, rhs_count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1552b1ef5..e0e74a3aa 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5144,8 +5144,20 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array } +typedef u32 UnpackFlags; +enum UnpackFlag : u32 { + UnpackFlag_None = 0, + UnpackFlag_AllowOk = 1<<0, + UnpackFlag_IsVariadic = 1<<1, + UnpackFlag_AllowUndef = 1<<2, +}; + + +gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, UnpackFlags flags) { + bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; + bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0; + bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; -gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, bool allow_ok, bool is_variadic) { bool optional_ok = false; isize tuple_index = 0; for_array(i, rhs) { @@ -5184,7 +5196,13 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } } - check_expr_base(c, &o, rhs[i], type_hint); + if (allow_undef && rhs[i] != nullptr && rhs[i]->kind == Ast_Undef) { + o.type = t_untyped_undef; + o.mode = Addressing_Value; + o.expr = rhs[i]; + } else { + check_expr_base(c, &o, rhs[i], type_hint); + } if (o.mode == Addressing_NoValue) { error_operand_no_value(&o); o.mode = Addressing_Invalid; @@ -5968,7 +5986,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); } if (operand->mode != Addressing_ProcGroup) { - check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic); + check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); } } @@ -6025,7 +6043,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op isize lhs_count = -1; bool is_variadic = false; lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); - check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic); + check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); CallArgumentData data = {}; CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data); @@ -6101,7 +6119,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } - check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, false); + check_unpack_arguments(c, lhs, lhs_count, &operands, args, UnpackFlag_None); if (lhs != nullptr) { gb_free(heap_allocator(), lhs); @@ -6462,7 +6480,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O lhs_count = params->variables.count; } - check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false); + check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, UnpackFlag_None); } } @@ -9583,6 +9601,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_ast_node(u, Undef, node); o->mode = Addressing_Value; o->type = t_untyped_undef; + error(node, "Use of --- outside of variable declaration"); case_end; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1e3b35c21..6c69ad59f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2176,7 +2176,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { auto operands = array_make(heap_allocator(), 0, 2*rs->results.count); defer (array_free(&operands)); - check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, true, false); + check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk); if (result_count == 0 && rs->results.count > 0) { error(rs->results[0], "No return values expected"); -- cgit v1.2.3 From 97490c6445cb3ba85f470e64e6ed6d24394c421a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 May 2023 23:17:06 +0100 Subject: Basic support for `#reverse for in` on normal arrays --- src/check_stmt.cpp | 21 ++++++++++++++++ src/llvm_backend_stmt.cpp | 64 ++++++++++++++++++++++++++++++++++------------- src/parser.cpp | 11 ++++++++ src/parser.hpp | 1 + 4 files changed, 79 insertions(+), 18 deletions(-) (limited to 'src/check_stmt.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6c69ad59f..c64de40c7 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1461,6 +1461,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) bool is_map = false; bool use_by_reference_for_value = false; bool is_soa = false; + bool is_reverse = rs->reverse; Ast *expr = unparen_expr(rs->expr); @@ -1476,6 +1477,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } array_add(&vals, x.type); array_add(&vals, t_int); + + if (is_reverse) { + error(node, "#reverse for is not yet supported with ranges"); + } } else { Operand operand = {Addressing_Invalid}; check_expr_base(ctx, &operand, expr, nullptr); @@ -1488,6 +1493,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) gb_string_free(t); goto skip_expr_range_stmt; } else { + if (is_reverse) { + error(node, "#reverse for is not supported for enum types"); + } array_add(&vals, operand.type); array_add(&vals, t_int); add_type_info_type(ctx, operand.type); @@ -1503,6 +1511,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) array_add(&vals, t_int); add_package_dependency(ctx, "runtime", "string_decode_rune"); } + if (is_reverse) { + error(node, "#reverse for is not supported for string types"); + } break; case Type_EnumeratedArray: @@ -1534,6 +1545,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) is_map = true; array_add(&vals, t->Map.key); array_add(&vals, t->Map.value); + if (is_reverse) { + error(node, "#reverse for is not supported for map types"); + } break; case Type_Tuple: @@ -1570,6 +1584,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; } + if (is_reverse) { + error(node, "#reverse for is not supported for multiple return valued parameters"); + } } break; @@ -1579,6 +1596,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->Struct.soa_elem); array_add(&vals, t_int); + + if (is_reverse) { + error(node, "#reverse for is not yet supported for #soa types"); + } } break; } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 125913ac5..60468c7f0 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -249,7 +249,8 @@ gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) { gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr, - lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { + lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_, + bool is_reverse) { lbModule *m = p->module; lbValue count = {}; @@ -267,23 +268,50 @@ gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_ lbBlock *body = nullptr; - lbAddr index = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1)); + lbAddr index = {}; + lbValue incr = {}; + lbValue cond = {}; - loop = lb_create_block(p, "for.index.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); + index = lb_add_local_generated(p, t_int, false); - lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int); - lb_addr_store(p, index, incr); + if (!is_reverse) { + lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1)); - body = lb_create_block(p, "for.index.body"); - done = lb_create_block(p, "for.index.done"); - if (count.value == nullptr) { - GB_ASSERT(count_ptr.value != nullptr); - count = lb_emit_load(p, count_ptr); + loop = lb_create_block(p, "for.index.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int); + lb_addr_store(p, index, incr); + + body = lb_create_block(p, "for.index.body"); + done = lb_create_block(p, "for.index.done"); + if (count.value == nullptr) { + GB_ASSERT(count_ptr.value != nullptr); + count = lb_emit_load(p, count_ptr); + } + cond = lb_emit_comp(p, Token_Lt, incr, count); + } else { + // NOTE(bill): REVERSED LOGIC + if (count.value == nullptr) { + GB_ASSERT(count_ptr.value != nullptr); + count = lb_emit_load(p, count_ptr); + } + count = lb_emit_conv(p, count, t_int); + lb_addr_store(p, index, count); + + loop = lb_create_block(p, "for.index.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int); + lb_addr_store(p, index, incr); + + body = lb_create_block(p, "for.index.body"); + done = lb_create_block(p, "for.index.done"); + cond = lb_emit_comp(p, Token_GtEq, incr, lb_const_int(m, t_int, 0)); } - lbValue cond = lb_emit_comp(p, Token_Lt, incr, count); + lb_emit_if(p, cond, body, done); lb_start_block(p, body); @@ -820,7 +848,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc } lbAddr count_ptr = lb_add_local_generated(p, t_int, false); lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count)); - lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); + lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); break; } case Type_EnumeratedArray: { @@ -830,7 +858,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc } lbAddr count_ptr = lb_add_local_generated(p, t_int, false); lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count)); - lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); + lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); break; } case Type_DynamicArray: { @@ -840,7 +868,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc array = lb_emit_load(p, array); } count_ptr = lb_emit_struct_ep(p, array, 1); - lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done); + lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); break; } case Type_Slice: { @@ -853,7 +881,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc count_ptr = lb_add_local_generated(p, t_int, false).addr; lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); } - lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done); + lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); break; } case Type_Basic: { diff --git a/src/parser.cpp b/src/parser.cpp index 1b48dce87..afdb1078d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4759,6 +4759,17 @@ gb_internal Ast *parse_stmt(AstFile *f) { return stmt; } else if (tag == "unroll") { return parse_unrolled_for_loop(f, name); + } else if (tag == "reverse") { + Ast *for_stmt = parse_for_stmt(f); + if (for_stmt->kind == Ast_RangeStmt) { + if (for_stmt->RangeStmt.reverse) { + syntax_error(token, "#reverse already applied to a 'for in' statement"); + } + for_stmt->RangeStmt.reverse = true; + } else { + syntax_error(token, "#reverse can only be applied to a 'for in' statement"); + } + return for_stmt; } else if (tag == "include") { syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?"); s = ast_bad_stmt(f, token, f->curr_token); diff --git a/src/parser.hpp b/src/parser.hpp index d4883f287..6ba4ef6d6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -529,6 +529,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Token in_token; \ Ast *expr; \ Ast *body; \ + bool reverse; \ }) \ AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \ Scope *scope; \ -- cgit v1.2.3 From f07453d0aee436ba8c0f81cedfde5db3a7bbe1b4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 May 2023 23:24:03 +0100 Subject: Support `#reverse` on `#soa` arrays --- src/check_stmt.cpp | 4 ---- src/llvm_backend_stmt.cpp | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'src/check_stmt.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c64de40c7..73aaa1c37 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1596,10 +1596,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->Struct.soa_elem); array_add(&vals, t_int); - - if (is_reverse) { - error(node, "#reverse for is not yet supported for #soa types"); - } } break; } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 60468c7f0..da7fdaead 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -730,6 +730,8 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lbBlock *body = nullptr; lbBlock *done = nullptr; + bool is_reverse = rs->reverse; + lb_open_scope(p, scope); @@ -751,19 +753,40 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lbAddr index = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1)); - loop = lb_create_block(p, "for.soa.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); + lbValue incr = {}; + lbValue cond = {}; - lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int); - lb_addr_store(p, index, incr); + if (!is_reverse) { + lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1)); + + loop = lb_create_block(p, "for.soa.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int); + lb_addr_store(p, index, incr); - body = lb_create_block(p, "for.soa.body"); - done = lb_create_block(p, "for.soa.done"); + body = lb_create_block(p, "for.soa.body"); + done = lb_create_block(p, "for.soa.done"); - lbValue cond = lb_emit_comp(p, Token_Lt, incr, count); + cond = lb_emit_comp(p, Token_Lt, incr, count); + } else { + // NOTE(bill): REVERSED LOGIC + lb_addr_store(p, index, count); + + loop = lb_create_block(p, "for.soa.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int); + lb_addr_store(p, index, incr); + + body = lb_create_block(p, "for.soa.body"); + done = lb_create_block(p, "for.soa.done"); + + cond = lb_emit_comp(p, Token_GtEq, incr, lb_const_int(p->module, t_int, 0)); + } lb_emit_if(p, cond, body, done); lb_start_block(p, body); -- cgit v1.2.3 From b848ae7abb87e3c6a6cb75669d532683dfac5518 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 May 2023 23:27:42 +0100 Subject: Improve error message for `#reverse` on an interval --- src/check_stmt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_stmt.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 73aaa1c37..bf55be072 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1479,7 +1479,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) array_add(&vals, t_int); if (is_reverse) { - error(node, "#reverse for is not yet supported with ranges"); + error(node, "#reverse for is not supported with ranges, prefer an explicit for loop with init, condition, and post arguments"); } } else { Operand operand = {Addressing_Invalid}; @@ -1546,7 +1546,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) array_add(&vals, t->Map.key); array_add(&vals, t->Map.value); if (is_reverse) { - error(node, "#reverse for is not supported for map types"); + error(node, "#reverse for is not supported for map types, as maps are unordered"); } break; -- cgit v1.2.3 From e0530df98af6e7f520dbdb7324f69dbb1dfaf763 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 May 2023 23:45:21 +0100 Subject: Support `#reverse` for strings --- src/check_stmt.cpp | 9 ++++--- src/llvm_backend_stmt.cpp | 66 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 22 deletions(-) (limited to 'src/check_stmt.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index bf55be072..bdfa24460 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1509,10 +1509,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) if (is_type_string(t) && t->Basic.kind != Basic_cstring) { array_add(&vals, t_rune); array_add(&vals, t_int); - add_package_dependency(ctx, "runtime", "string_decode_rune"); - } - if (is_reverse) { - error(node, "#reverse for is not supported for string types"); + if (is_reverse) { + add_package_dependency(ctx, "runtime", "string_decode_last_rune"); + } else { + add_package_dependency(ctx, "runtime", "string_decode_rune"); + } } break; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index da7fdaead..7f677b238 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -480,7 +480,8 @@ gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type, - lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { + lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_, + bool is_reverse) { lbModule *m = p->module; lbValue count = lb_const_int(m, t_int, 0); Type *expr_type = base_type(expr.type); @@ -499,35 +500,64 @@ gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_t lbBlock *done = nullptr; lbBlock *body = nullptr; + loop = lb_create_block(p, "for.string.loop"); + body = lb_create_block(p, "for.string.body"); + done = lb_create_block(p, "for.string.done"); lbAddr offset_ = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + lbValue offset = {}; + lbValue cond = {}; - loop = lb_create_block(p, "for.string.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); + if (!is_reverse) { + lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + lb_emit_jump(p, loop); + lb_start_block(p, loop); - body = lb_create_block(p, "for.string.body"); - done = lb_create_block(p, "for.string.done"); + offset = lb_addr_load(p, offset_); + cond = lb_emit_comp(p, Token_Lt, offset, count); + } else { + // NOTE(bill): REVERSED LOGIC + lb_addr_store(p, offset_, count); - lbValue offset = lb_addr_load(p, offset_); - lbValue cond = lb_emit_comp(p, Token_Lt, offset, count); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + offset = lb_addr_load(p, offset_); + cond = lb_emit_comp(p, Token_Gt, offset, lb_const_int(m, t_int, 0)); + } lb_emit_if(p, cond, body, done); lb_start_block(p, body); - lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); - lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); - auto args = array_make(permanent_allocator(), 1); - args[0] = lb_emit_string(p, str_elem, str_len); - lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args); - lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); - lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int)); + lbValue rune_and_len = {}; + if (!is_reverse) { + lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); + lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_emit_string(p, str_elem, str_len); + + rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args); + lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); + lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int)); + + idx = offset; + } else { + // NOTE(bill): REVERSED LOGIC + lbValue str_elem = lb_string_elem(p, expr); + lbValue str_len = offset; + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_emit_string(p, str_elem, str_len); + + rune_and_len = lb_emit_runtime_call(p, "string_decode_last_rune", args); + lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); + lb_addr_store(p, offset_, lb_emit_arith(p, Token_Sub, offset, len, t_int)); + + idx = lb_addr_load(p, offset_); + } - idx = offset; if (val_type != nullptr) { val = lb_emit_struct_ev(p, rune_and_len, 0); } @@ -919,7 +949,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc } Type *t = base_type(string.type); GB_ASSERT(!is_type_cstring(t)); - lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done); + lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); break; } case Type_Tuple: -- cgit v1.2.3