Browse Source

Basic support for `#reverse for in` on normal arrays

gingerBill 2 years ago
parent
commit
97490c6445
4 changed files with 79 additions and 18 deletions
  1. 21 0
      src/check_stmt.cpp
  2. 46 18
      src/llvm_backend_stmt.cpp
  3. 11 0
      src/parser.cpp
  4. 1 0
      src/parser.hpp

+ 21 - 0
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;
 			}

+ 46 - 18
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: {

+ 11 - 0
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);

+ 1 - 0
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; \