aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-05-29 23:45:21 +0100
committergingerBill <bill@gingerbill.org>2023-05-29 23:45:21 +0100
commite0530df98af6e7f520dbdb7324f69dbb1dfaf763 (patch)
tree6c8e1866becea19ba86f872c6f809bd27888e843
parent6cbce9fdffbeb72406ded5fe9d141e172dadc032 (diff)
Support `#reverse` for strings
-rw-r--r--src/check_stmt.cpp9
-rw-r--r--src/llvm_backend_stmt.cpp66
2 files changed, 53 insertions, 22 deletions
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<lbValue>(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<lbValue>(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<lbValue>(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: