From 168c11e006bbfe446d9653cb1c1f87c74b584772 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 18 Feb 2025 12:50:34 +0100 Subject: [PATCH] `{| |}` expression blocks deprecated. --- lib/std/core/allocators/dynamic_arena.c3 | 21 ++++++---- lib/std/core/string.c3 | 26 +++++++------ lib/std/core/string_to_real.c3 | 5 +-- lib/std/os/subprocess.c3 | 38 ++++++++++--------- releasenotes.md | 1 + .../examples/contextfree/guess_number.c3 | 12 +++--- src/compiler/compiler_internal.h | 2 +- src/compiler/sema_expr.c | 13 +++++++ test/src/tester.py | 8 ++++ .../test_suite/defer/defer_and_expr_block.c3t | 1 + test/test_suite/defer/defer_catch_err.c3t | 1 + test/test_suite/defer/defer_with_rethrow.c3 | 1 + test/test_suite/defer/defer_with_return.c3 | 1 + .../errors/else_unreachable_in_block.c3 | 1 + .../expr_block_labelled_break.c3 | 2 +- .../expression_block/expr_block_no_assign.c3 | 1 + .../expression_block_break.c3 | 1 + .../expression_block_no_end_return.c3 | 1 + .../expressions/bool_conversions.c3t | 1 + .../generic/generic_lambda_complex.c3t | 1 + .../macro_body_ref_hash_constant_type.c3t | 1 + test/test_suite/statements/defer_in_block.c3t | 1 + .../vector/vector_conversion_scalar.c3 | 1 + test/unit/regression/catch_err.c3 | 12 +++--- test/unit/stdlib/math/matrix.c3 | 16 ++++---- test/unit/stdlib/math/quaternion.c3 | 12 +++--- 26 files changed, 114 insertions(+), 67 deletions(-) diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index 6ab7e248a..7d1b9556f 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -164,14 +164,21 @@ fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type { alignment = alignment_for_allocation(alignment); DynamicArenaPage* page = self.page; - void* ptr = {| + + void* ptr @noinit; + do SET_DONE: + { if (!page && self.unused_page) { self.page = page = self.unused_page; self.unused_page = page.prev_arena; page.prev_arena = null; } - if (!page) return self._alloc_new(size, alignment); + if (!page) + { + ptr = self._alloc_new(size, alignment)!; + break SET_DONE; + } void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment); usz new_used = start - page.memory + size; if ALLOCATE_NEW: (new_used > page.total) @@ -188,15 +195,15 @@ fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type break ALLOCATE_NEW; } } - return self._alloc_new(size, alignment); + ptr = self._alloc_new(size, alignment)!; + break SET_DONE; } page.used = new_used; assert(start + size == page.memory + page.used); - void* mem = start; - DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem - 1; + ptr = start; + DynamicArenaChunk* chunk = (DynamicArenaChunk*)ptr - 1; chunk.size = size; - return mem; - |}!; + }; if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT); return ptr; } diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index c4eff6e49..3bccacec6 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -780,26 +780,28 @@ macro String.to_integer(string, $Type, int base = 10) $Type value = 0; while (index != len) { - char c = {| - char ch = string[index++]; - if (base_used != 16 || ch < 'A') return (char)(ch - '0'); - if (ch <= 'F') return (char)(ch - 'A' + 10); - if (ch < 'a') return NumberConversion.MALFORMED_INTEGER?; - if (ch > 'f') return NumberConversion.MALFORMED_INTEGER?; - return (char)(ch - 'a' + 10); - |}!; + char c = string[index++]; + switch + { + case base_used != 16 || c < 'A': c -= '0'; + case c <= 'F': c -= 'A' - 10; + case c < 'a' || c > 'f': return NumberConversion.MALFORMED_INTEGER?; + default: c -= 'a' - 10; + } if (c >= base_used) return NumberConversion.MALFORMED_INTEGER?; - value = {| + do + { if (is_negative) { $Type new_value = value * base_used - c; if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?; - return new_value; + value = new_value; + break; } $Type new_value = value * base_used + c; if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?; - return new_value; - |}!; + value = new_value; + }; } return value; } diff --git a/lib/std/core/string_to_real.c3 b/lib/std/core/string_to_real.c3 index 6e746dd17..952b82432 100644 --- a/lib/std/core/string_to_real.c3 +++ b/lib/std/core/string_to_real.c3 @@ -376,10 +376,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign) else { got_digit = true; - int d = {| - if (c > '9') return (c | 32) + 10 - 'a'; - return c - '0'; - |}; + int d = c > '9' ? ((c | 32) + 10 - 'a') : (c - '0'); switch { case dc < 8: diff --git a/lib/std/os/subprocess.c3 b/lib/std/os/subprocess.c3 index 234b82856..b1f90e16f 100644 --- a/lib/std/os/subprocess.c3 +++ b/lib/std/os/subprocess.c3 @@ -75,10 +75,12 @@ fn void! create_named_pipe_helper(void** rd, void **wr) @local @if(env::WIN32) fn WString convert_command_line_win32(String[] command_line) @inline @if(env::WIN32) @local { DString str = dstring::temp_with_capacity(512); - foreach (i, s : command_line) + foreach LINE: (i, s : command_line) { if (i != 0) str.append(' '); - bool needs_escape = {| + + do CHECK_WS: + { foreach (c : s) { switch (c) @@ -86,16 +88,12 @@ fn WString convert_command_line_win32(String[] command_line) @inline @if(env::WI case '\t': case ' ': case '\v': - return true; + break CHECK_WS; } } - return false; - |}; - if (!needs_escape) - { str.append(s); - continue; - } + continue LINE; + }; str.append('"'); foreach (j, c : s) { @@ -178,12 +176,13 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str start_info.hStdOutput = wr; - {| + do + { if (options.combined_stdout_stderr) { stderr = stdout; start_info.hStdError = start_info.hStdOutput; - return; + break; } if (options.read_async) { @@ -202,8 +201,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str if (!stderr) return SubProcessResult.FAILED_TO_OPEN_STDERR?; } start_info.hStdError = wr; - - |}!; + }; void *event_output; void *event_error; if (options.read_async) @@ -323,11 +321,17 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str CFile stdin = libc::fdopen(stdinfd[1], "wb"); libc::close(stdoutfd[1]); CFile stdout = libc::fdopen(stdoutfd[0], "rb"); - CFile stderr = {| - if (options.combined_stdout_stderr) return stdout; + CFile stderr @noinit; + do + { + if (options.combined_stdout_stderr) + { + stderr = stdout; + break; + } libc::close(stderrfd[1]); - return libc::fdopen(stderrfd[0], "rb"); - |}; + stderr = libc::fdopen(stderrfd[0], "rb"); + }; return { .stdin_file = stdin, .stdout_file = stdout, diff --git a/releasenotes.md b/releasenotes.md index 086c157a2..35fe7399d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -5,6 +5,7 @@ ### Changes / improvements - Increase precedence of `(Foo) { 1, 2 }` - Add `--enable-new-generics` to enable `Foo{int}` generic syntax. +- `{| |}` expression blocks deprecated. ### Fixes diff --git a/resources/examples/contextfree/guess_number.c3 b/resources/examples/contextfree/guess_number.c3 index b53ae70b8..81df037cc 100644 --- a/resources/examples/contextfree/guess_number.c3 +++ b/resources/examples/contextfree/guess_number.c3 @@ -53,11 +53,13 @@ fn void! Game.play(Game *game) fn void Game.report(Game* game, int guess) { - String desc = {| - if (guess < game.answer) return "too low"; - if (guess > game.answer) return "too high"; - return "the answer"; - |}; + String desc @noinit; + switch + { + case guess < game.answer: desc = "too low"; + case guess > game.answer: desc = "too high"; + default: desc = "the answer"; + } io::printfn("%d is %s.\n", guess, desc); } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index ea291741a..938609fca 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -65,7 +65,7 @@ typedef uint16_t FileId; #define PRINT_ERROR_LAST(...) print_error_at(c->prev_span, __VA_ARGS__) #define RETURN_PRINT_ERROR_LAST(...) do { print_error_at(c->prev_span, __VA_ARGS__); return false; } while (0) #define SEMA_NOTE(_node, ...) sema_note_prev_at((_node)->span, __VA_ARGS__) -#define SEMA_DEPRECATED(_node, ...) do { if (compiler.build.test_output) print_error_at((_node)->span, __VA_ARGS__); if (!compiler.build.silence_deprecation) \ +#define SEMA_DEPRECATED(_node, ...) do { if (compiler.build.test_output && !compiler.build.silence_deprecation) print_error_at((_node)->span, __VA_ARGS__); if (!compiler.build.silence_deprecation) \ sema_note_prev_at((_node)->span, __VA_ARGS__); } while (0) #define EXPAND_EXPR_STRING(str_) (str_)->const_expr.bytes.len, (str_)->const_expr.bytes.ptr diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 36542eef2..c9a0aa97c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -8215,6 +8215,19 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe context->block_exit_ref = stored_block_exit; context_pop_returns(context, saved_returns); + if (!compiler.build.silence_deprecation) + { + static_assert(ALLOW_DEPRECATED_6, "Fix deprecation"); + if (type_no_optional(expr->type) == type_void) + { + SEMA_DEPRECATED(expr, "Expression blocks have been deprecated. For this type of expression block, use `do { ... };` blocks instead."); + } + else + { + SEMA_DEPRECATED(expr, "Expression blocks have been deprecated. Depending on your code, using `do { ... };` with a variable outside of the block may work fine. There is a possibility that these blocks will be replaced by inline macros."); + } + } + return success; } diff --git a/test/src/tester.py b/test/src/tester.py index 803f5250f..bbc36fd65 100644 --- a/test/src/tester.py +++ b/test/src/tester.py @@ -64,6 +64,7 @@ class Issues: self.debuginfo = False self.safe = False self.arch = None + self.no_deprecation = False self.current_file = None self.files = [] self.errors = {} @@ -135,6 +136,8 @@ class Issues: opts = "" for opt in self.opts: opts += ' ' + opt + if self.no_deprecation: + opts += " --silence-deprecation" if self.safe: opts += " --safe=yes" else: @@ -181,6 +184,9 @@ class Issues: if line.startswith("target:"): self.arch = line[7:].strip() return + if line.startswith("deprecation:"): + self.no_deprecation = line[12:].strip() == "no" + return if line.startswith("file:"): if self.current_file: self.current_file.close() @@ -205,6 +211,8 @@ class Issues: self.warnings[self.current_file.filename + ":%d" % (self.line + self.current_file.line_offset)] = line elif line.startswith("target:"): self.arch = line[7:].strip() + elif line.startswith("deprecation:"): + self.no_deprecation = line[12:].strip() == "no" elif line.startswith("error:"): line = line[6:].strip() self.errors[self.current_file.filename + ":%d" % (self.line + self.current_file.line_offset)] = line diff --git a/test/test_suite/defer/defer_and_expr_block.c3t b/test/test_suite/defer/defer_and_expr_block.c3t index 1b02e5e28..ad9c6c30a 100644 --- a/test/test_suite/defer/defer_and_expr_block.c3t +++ b/test/test_suite/defer/defer_and_expr_block.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +// #deprecation: no module foo; extern fn void printf(char*,...); diff --git a/test/test_suite/defer/defer_catch_err.c3t b/test/test_suite/defer/defer_catch_err.c3t index a96bf8d15..c13c2c084 100644 --- a/test/test_suite/defer/defer_catch_err.c3t +++ b/test/test_suite/defer/defer_catch_err.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +// #deprecation: no module foo; import std::io; diff --git a/test/test_suite/defer/defer_with_rethrow.c3 b/test/test_suite/defer/defer_with_rethrow.c3 index beb9d1a47..f107bc3be 100644 --- a/test/test_suite/defer/defer_with_rethrow.c3 +++ b/test/test_suite/defer/defer_with_rethrow.c3 @@ -1,3 +1,4 @@ +// #deprecation: no fn int! foo() { return 1; } diff --git a/test/test_suite/defer/defer_with_return.c3 b/test/test_suite/defer/defer_with_return.c3 index 7502af75a..a0ec5c368 100644 --- a/test/test_suite/defer/defer_with_return.c3 +++ b/test/test_suite/defer/defer_with_return.c3 @@ -1,3 +1,4 @@ +// #deprecation: no fn int! bar() { defer { diff --git a/test/test_suite/errors/else_unreachable_in_block.c3 b/test/test_suite/errors/else_unreachable_in_block.c3 index 1d8c1a2c4..b0d0ac5d9 100644 --- a/test/test_suite/errors/else_unreachable_in_block.c3 +++ b/test/test_suite/errors/else_unreachable_in_block.c3 @@ -1,3 +1,4 @@ +// #deprecation: no module test; import std; fn void main() diff --git a/test/test_suite/expression_block/expr_block_labelled_break.c3 b/test/test_suite/expression_block/expr_block_labelled_break.c3 index 22738b1f4..08c01fee4 100644 --- a/test/test_suite/expression_block/expr_block_labelled_break.c3 +++ b/test/test_suite/expression_block/expr_block_labelled_break.c3 @@ -1,4 +1,4 @@ - +// #deprecation: no fn void test() { for FOO: (int i = 0; i < 100; i++) diff --git a/test/test_suite/expression_block/expr_block_no_assign.c3 b/test/test_suite/expression_block/expr_block_no_assign.c3 index a27fbcbc1..98aaea52a 100644 --- a/test/test_suite/expression_block/expr_block_no_assign.c3 +++ b/test/test_suite/expression_block/expr_block_no_assign.c3 @@ -1,3 +1,4 @@ +// #deprecation: no module helloworld; fn void main() diff --git a/test/test_suite/expression_block/expression_block_break.c3 b/test/test_suite/expression_block/expression_block_break.c3 index 6b8ae0550..0412bfc60 100644 --- a/test/test_suite/expression_block/expression_block_break.c3 +++ b/test/test_suite/expression_block/expression_block_break.c3 @@ -1,3 +1,4 @@ +// #deprecation: no module fe; import std::io; extern fn int printf(char *str, ...); diff --git a/test/test_suite/expression_block/expression_block_no_end_return.c3 b/test/test_suite/expression_block/expression_block_no_end_return.c3 index 19e7f74da..2a2905a40 100644 --- a/test/test_suite/expression_block/expression_block_no_end_return.c3 +++ b/test/test_suite/expression_block/expression_block_no_end_return.c3 @@ -1,3 +1,4 @@ +// #deprecation: no module foob; fn void main() diff --git a/test/test_suite/expressions/bool_conversions.c3t b/test/test_suite/expressions/bool_conversions.c3t index e25f402c4..972be92db 100644 --- a/test/test_suite/expressions/bool_conversions.c3t +++ b/test/test_suite/expressions/bool_conversions.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +// #deprecation: no fn bool f0_0(void* a0) @private { return (bool)a0; } diff --git a/test/test_suite/generic/generic_lambda_complex.c3t b/test/test_suite/generic/generic_lambda_complex.c3t index 90b686df6..76b281b14 100644 --- a/test/test_suite/generic/generic_lambda_complex.c3t +++ b/test/test_suite/generic/generic_lambda_complex.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +// #deprecation: no <* @require Type.kindof == STRUCT *> module abc(); diff --git a/test/test_suite/macros/macro_body_ref_hash_constant_type.c3t b/test/test_suite/macros/macro_body_ref_hash_constant_type.c3t index e324965c2..37d722654 100644 --- a/test/test_suite/macros/macro_body_ref_hash_constant_type.c3t +++ b/test/test_suite/macros/macro_body_ref_hash_constant_type.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +// #deprecation: no module test; import std::io; diff --git a/test/test_suite/statements/defer_in_block.c3t b/test/test_suite/statements/defer_in_block.c3t index 153f72d48..2421a0b02 100644 --- a/test/test_suite/statements/defer_in_block.c3t +++ b/test/test_suite/statements/defer_in_block.c3t @@ -1,4 +1,5 @@ // #target: macos-x64 +// #deprecation: no module foo; extern fn void printf(char*,...); diff --git a/test/test_suite/vector/vector_conversion_scalar.c3 b/test/test_suite/vector/vector_conversion_scalar.c3 index 54a394073..1b99dc30c 100644 --- a/test/test_suite/vector/vector_conversion_scalar.c3 +++ b/test/test_suite/vector/vector_conversion_scalar.c3 @@ -1,3 +1,4 @@ +// #deprecation: no fn void test2(int[<2>] x) {} fn void main() { diff --git a/test/unit/regression/catch_err.c3 b/test/unit/regression/catch_err.c3 index 0840207d9..171abf6f4 100644 --- a/test/unit/regression/catch_err.c3 +++ b/test/unit/regression/catch_err.c3 @@ -3,19 +3,19 @@ module catch_err @test; fn void test() { anyfault a; - int! z = {| + int! z = fn int!(anyfault* a) { const ABC = 4; int! x = SearchResult.MISSING?; - defer (catch err) a = err; + defer (catch err) *a = err; return x; - |}; + }(&a); assert(a == SearchResult.MISSING); anyfault y; - z = {| + z = fn int!(anyfault* y) { const ABC = 4; int! x = 1; - defer (catch err) y = err; + defer (catch err) *y = err; return x; - |}; + }(&y); assert(!y); } \ No newline at end of file diff --git a/test/unit/stdlib/math/matrix.c3 b/test/unit/stdlib/math/matrix.c3 index 56dad46f7..3ed8f1e2a 100644 --- a/test/unit/stdlib/math/matrix.c3 +++ b/test/unit/stdlib/math/matrix.c3 @@ -3,7 +3,7 @@ import std::math; fn void test_mat4() { - {| + { Matrix4 mat = MATRIX4_IDENTITY; Matrix4 mat2 = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; Matrix4 calc = mat.mul(mat2); @@ -11,17 +11,17 @@ fn void test_mat4() Matrix4 translated = mat.translate(Vec3{0.0, 0.0, 0.0}); assert(translated.m == mat.m); - |}; + }; - {| + { Matrix4 mat = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; Matrix4 mat2 = { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 }; Matrix4 calc = mat.mul(mat2); Matrix4 value = { 56, 46, 36, 26, 152, 126, 100, 74, 56, 46, 36, 26, 152, 126, 100, 74 }; assert(calc.m == value.m); - |}; + }; - {| + { Matrix4 result = { 0.988936, 0.000000, -0.148340, -0.988936, -0.014599, 0.995146, -0.097325, -2.970838, @@ -58,9 +58,9 @@ fn void test_mat4() assert(math::round_to_decimals((double[<16>])result_transposed.m, 4) == math::round_to_decimals((double[<16>])look_at.transpose().m, 4)); assert(math::round_to_decimals((float[<16>])result_transposed_f.m, 4) == math::round_to_decimals((float[<16>])look_at_f.transpose().m, 4)); - |}; + }; - {| + { Matrix4 result = { 1.857087, 0.000000, 0.000000, 0.000000, 0.000000, 2.414214, @@ -82,7 +82,7 @@ fn void test_mat4() assert(math::round_to_decimals((double[<16>])result.m, 4) == math::round_to_decimals((double[<16>])perspective.m, 4)); assert(math::round_to_decimals((float[<16>])result_f.m, 4) == math::round_to_decimals((float[<16>])perspective_f.m, 4)); - |}; + }; } diff --git a/test/unit/stdlib/math/quaternion.c3 b/test/unit/stdlib/math/quaternion.c3 index 5bd39e603..2e2c8dec0 100644 --- a/test/unit/stdlib/math/quaternion.c3 +++ b/test/unit/stdlib/math/quaternion.c3 @@ -3,14 +3,14 @@ import std::math; fn void test() { - {| + { Quaternion rotation = QUATERNION_IDENTITY; Quaternionf rotation_f = QUATERNIONF_IDENTITY; assert(rotation.v == {0,0,0,1}); assert(rotation.v == {0,0,0,1}); - |}; + }; - {| + { Quaternion rotation = QUATERNION_IDENTITY; Matrix4 identity_matrix = MATRIX4_IDENTITY; @@ -19,9 +19,9 @@ fn void test() assert((double[<16>])rotation.to_matrix().m == (double[<16>])identity_matrix.m); assert((float[<16>])rotation_f.to_matrixf().m == (float[<16>])identity_matrix_f.m); - |}; + }; - {| + { Matrix4 result = { 0.428571, -0.285714, 0.857143, 0.000000, 0.857143, 0.428571, -0.285714, 0.000000, @@ -34,5 +34,5 @@ fn void test() assert(math::round_to_decimals((double[<16>])result.m, 2) == math::round_to_decimals((double[<16>])rotation.m, 2)); assert(math::round_to_decimals((float[<16>])result.m, 2) == math::round_to_decimals((float[<16>])rotation_f.m, 2)); - |}; + }; } \ No newline at end of file