From a3a20f09e27cf92493bdb92f6a96c29a8ab538d1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 16:55:30 +0100 Subject: [PATCH 01/16] `or_return` built-in procedure --- src/check_builtin.cpp | 122 ++++++++++++++++++++++++++++++++-- src/checker_builtin_procs.hpp | 2 + src/llvm_backend_proc.cpp | 2 + src/llvm_backend_utility.cpp | 42 ++++++++++++ 4 files changed, 161 insertions(+), 7 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 846bea296..77c4ee453 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -48,6 +48,17 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - }; +void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) { + if (right_type == nullptr) { + return; + } + if (!is_type_boolean(right_type) && !type_has_nil(right_type)) { + gbString str = type_to_string(right_type); + error(expr, "'%.*s' expects an \"optional ok\" like value, or an n-valued expression where the last value is either a boolean or can be compared against 'nil', got %s", LIT(name), str); + gb_string_free(str); + } +} + void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) { Type *left_type = nullptr; Type *right_type = nullptr; @@ -70,15 +81,11 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name if (left_type_) *left_type_ = left_type; if (right_type_) *right_type_ = right_type; - if (!is_type_boolean(right_type)) { - gbString str = type_to_string(right_type); - error(x->expr, "'%.*s' expects an \"optional ok\" like value, got %s", LIT(name), str); - gb_string_free(str); - } + check_or_else_right_type(c, x->expr, name, right_type); } -void check_try_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) { +void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) { // TODO(bill): better error message gbString t = type_to_string(x.type); error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t); @@ -108,6 +115,33 @@ void check_try_expr_no_value_error(CheckerContext *c, String const &name, Operan } +void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) { + Type *left_type = nullptr; + Type *right_type = nullptr; + if (x->type->kind == Type_Tuple) { + auto const &vars = x->type->Tuple.variables; + auto lhs = array_slice(vars, 0, vars.count-1); + auto rhs = vars[vars.count-1]; + if (lhs.count == 1) { + left_type = lhs[0]->type; + } else if (lhs.count != 0) { + left_type = alloc_type_tuple(); + left_type->Tuple.variables = array_make_from_ptr(lhs.data, lhs.count, lhs.count); + } + + right_type = rhs->type; + } else { + check_promote_optional_ok(c, x, &left_type, &right_type); + } + + if (left_type_) *left_type_ = left_type; + if (right_type_) *right_type_ = right_type; + + check_or_else_right_type(c, x->expr, name, right_type); +} + + + bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->inlining != ProcInlining_none) { @@ -146,6 +180,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_or_else: + case BuiltinProc_or_return: // NOTE(bill): The arguments may be multi-expr break; @@ -1830,7 +1865,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (left_type != nullptr) { check_assignment(c, &y, left_type, builtin_name); } else { - check_try_expr_no_value_error(c, builtin_name, x, type_hint); + check_or_else_expr_no_value_error(c, builtin_name, x, type_hint); } if (left_type == nullptr) { @@ -1841,6 +1876,79 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return true; } + case BuiltinProc_or_return: { + GB_ASSERT(ce->args.count == 1); + Ast *arg = ce->args[0]; + + Operand x = {}; + check_multi_expr_with_type_hint(c, &x, arg, type_hint); + if (x.mode == Addressing_Invalid) { + operand->mode = Addressing_Value; + operand->type = t_invalid; + return false; + } + + Type *left_type = nullptr; + Type *right_type = nullptr; + check_or_return_split_types(c, &x, builtin_name, &left_type, &right_type); + add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); + + if (right_type == nullptr) { + check_or_else_expr_no_value_error(c, builtin_name, x, type_hint); + } else { + Type *proc_type = base_type(c->curr_proc_sig); + GB_ASSERT(proc_type->kind == Type_Proc); + Type *result_type = proc_type->Proc.results; + if (result_type == nullptr) { + error(call, "'%.*s' requires the current procedure to have at least one return value", LIT(builtin_name)); + } else { + GB_ASSERT(result_type->kind == Type_Tuple); + + auto const &vars = result_type->Tuple.variables; + Type *end_type = vars[vars.count-1]->type; + + if (vars.count > 1) { + if (!proc_type->Proc.has_named_results) { + error(call, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(builtin_name)); + } + } + + Operand rhs = {}; + rhs.type = right_type; + rhs.mode = Addressing_Value; + + // TODO(bill): better error message + if (!check_is_assignable_to(c, &rhs, end_type)) { + gbString a = type_to_string(right_type); + gbString b = type_to_string(end_type); + gbString ret_type = type_to_string(result_type); + error(call, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(builtin_name)); + if (vars.count == 1) { + error_line("\tProcedure return value type: %s\n", ret_type); + } else { + error_line("\tProcedure return value types: (%s)\n", ret_type); + } + gb_string_free(ret_type); + gb_string_free(b); + gb_string_free(a); + } + } + } + + operand->type = left_type; + if (left_type != nullptr) { + operand->mode = Addressing_Value; + } else { + operand->mode = Addressing_NoValue; + } + + if (c->curr_proc_sig == nullptr) { + error(call, "'%.*s' can only be used within a procedure", LIT(builtin_name)); + } + + return true; + } + case BuiltinProc_simd_vector: { Operand x = {}; Operand y = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index a25657abe..bd105f0d7 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -34,6 +34,7 @@ enum BuiltinProcId { BuiltinProc_soa_unzip, BuiltinProc_or_else, + BuiltinProc_or_return, BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures @@ -266,6 +267,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("soa_unzip"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("or_else"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("or_return"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 5b922de4b..b3178e008 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1254,6 +1254,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_or_else: return lb_emit_or_else(p, ce->args[0], ce->args[1], tv); + case BuiltinProc_or_return: + return lb_emit_or_return(p, ce->args[0], tv); // "Intrinsics" diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 5fc5389c9..406b4fc2e 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -364,6 +364,48 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c return res; } +void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); +void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res); + +lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { + lbValue lhs = {}; + lbValue rhs = {}; + lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); + + lbBlock *return_block = lb_create_block(p, "or_return.return"); + lbBlock *continue_block = lb_create_block(p, "or_return.continue"); + + lb_emit_if(p, lb_emit_try_has_value(p, rhs), continue_block, return_block); + lb_start_block(p, return_block); + { + Type *proc_type = base_type(p->type); + Type *results = proc_type->Proc.results; + GB_ASSERT(results != nullptr && results->kind == Type_Tuple); + TypeTuple *tuple = &results->Tuple; + + GB_ASSERT(tuple->variables.count != 0); + + Entity *end_entity = tuple->variables[tuple->variables.count-1]; + rhs = lb_emit_conv(p, rhs, end_entity->type); + if (p->type->Proc.has_named_results) { + GB_ASSERT(end_entity->token.string.len != 0); + + // NOTE(bill): store the named values before returning + lbValue found = map_must_get(&p->module->values, hash_entity(end_entity)); + lb_emit_store(p, found, rhs); + + lb_build_return_stmt(p, {}); + } else { + GB_ASSERT(tuple->variables.count == 1); + lb_build_return_stmt_internal(p, rhs); + } + } + lb_start_block(p, continue_block); + if (tv.type != nullptr) { + return lb_emit_conv(p, lhs, tv.type); + } + return {}; +} void lb_emit_increment(lbProcedure *p, lbValue addr) { From 21cbac755ec2e18e5471c8f8e1406a87156d8043 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 17:14:35 +0100 Subject: [PATCH 02/16] Make `or_else` and `or_return` operators (binary and suffix respectively) --- core/os/os2/errors.odin | 2 +- core/os/os2/file_stream.odin | 2 +- core/testing/runner_windows.odin | 2 +- core/thread/thread_unix.odin | 2 +- core/thread/thread_windows.odin | 2 +- examples/all/all_main.odin | 100 +++++++++++------------ examples/demo/demo.odin | 8 +- src/check_builtin.cpp | 119 --------------------------- src/check_expr.cpp | 136 +++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 6 -- src/llvm_backend_expr.cpp | 8 ++ src/llvm_backend_proc.cpp | 5 -- src/parser.cpp | 38 ++++++++- src/parser.hpp | 2 + src/parser_pos.cpp | 4 + src/tokenizer.cpp | 6 +- 16 files changed, 247 insertions(+), 195 deletions(-) diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index b7e89b493..8dcfe8dd0 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -57,7 +57,7 @@ link_error_delete :: proc(lerr: Maybe(Link_Error)) { is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { - v := or_else(ferr.(Platform_Error), {}); + v := ferr.(Platform_Error) or_else {}; return v.err, v.err != 0; } diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin index 936d9da57..849f0866e 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/os2/file_stream.odin @@ -13,7 +13,7 @@ error_to_io_error :: proc(ferr: Error) -> io.Error { if ferr == nil { return .None; } - return or_else(ferr.(io.Error), .Unknown); + return ferr.(io.Error) or_else .Unknown; } diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin index 03ae9ede9..255d44f1b 100644 --- a/core/testing/runner_windows.odin +++ b/core/testing/runner_windows.odin @@ -68,7 +68,7 @@ Thread_Os_Specific :: struct { thread_create :: proc(procedure: Thread_Proc) -> ^Thread { __windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD { t := (^Thread)(t_); - context = or_else(t.init_context.?, runtime.default_context()); + context = t.init_context.? or_else runtime.default_context(); t.procedure(t); diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index ef17596b8..fa82832ec 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -46,7 +46,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ t.start_gate = {}; t.start_mutex = {}; - context = or_else(t.init_context.?, runtime.default_context()); + context = t.init_context.? or_else runtime.default_context(); t.procedure(t); diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index ad834ddc7..1dfa0c0b6 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -23,7 +23,7 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^ __windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD { t := (^Thread)(t_); - context = or_else(t.init_context.?, runtime.default_context()); + context = t.init_context.? or_else runtime.default_context(); t.procedure(t); diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 9baff266c..e04cf7d49 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -3,57 +3,57 @@ package all // Imports every package // This is useful for knowing what exists and producing documentation with `odin doc` -import "core:bufio" -import "core:bytes" -import "core:c" -import c_tokenizer "core:c/frontend/tokenizer" +import bufio "core:bufio" +import bytes "core:bytes" +import c "core:c" +import c_tokenizer "core:c/frontend/tokenizer" import c_preprocessor "core:c/frontend/preprocessor" -import "core:compress" -import "core:compress/gzip" -import "core:compress/zlib" -import "core:container" -import "core:dynlib" -import "core:encoding" -import "core:encoding/base32" -import "core:encoding/base64" -import "core:encoding/csv" -import "core:encoding/hxa" -import "core:encoding/json" -import "core:fmt" -import "core:hash" -import "core:image" -import "core:image/png" -import "core:io" -import "core:log" -import "core:math" -import "core:math/big" -import "core:math/bits" -import "core:math/fixed" -import "core:math/linalg" -import "core:math/rand" -import "core:mem" -import "core:odin/ast" -import doc_format "core:odin/doc-format" -import "core:odin/format" -import "core:odin/parser" -import "core:odin/printer" +import compress "core:compress" +import gzip "core:compress/gzip" +import zlib "core:compress/zlib" +import container "core:container" +import dynlib "core:dynlib" +import encoding "core:encoding" +import base32 "core:encoding/base32" +import base64 "core:encoding/base64" +import csv "core:encoding/csv" +import hxa "core:encoding/hxa" +import json "core:encoding/json" +import fmt "core:fmt" +import hash "core:hash" +import image "core:image" +import png "core:image/png" +import io "core:io" +import log "core:log" +import math "core:math" +import big "core:math/big" +import bits "core:math/bits" +import fixed "core:math/fixed" +import linalg "core:math/linalg" +import rand "core:math/rand" +import mem "core:mem" +import ast "core:odin/ast" +import doc_format "core:odin/doc-format" +import odin_format "core:odin/format" +import odin_parser "core:odin/parser" +import odin_printer "core:odin/printer" import odin_tokenizer "core:odin/tokenizer" -import "core:os" -import "core:path" -import "core:path/filepath" -import "core:reflect" -import "core:runtime" -import "core:slice" -import "core:sort" -import "core:strconv" -import "core:strings" -import "core:sync" -import "core:sync/sync2" -import "core:text/scanner" -import "core:thread" -import "core:time" -import "core:unicode" -import "core:unicode/utf8" -import "core:unicode/utf16" +import os "core:os" +import path "core:path" +import filepath "core:path/filepath" +import reflect "core:reflect" +import runtime "core:runtime" +import slice "core:slice" +import sort "core:sort" +import strconv "core:strconv" +import strings "core:strings" +import sync "core:sync" +import sync2 "core:sync/sync2" +import scanner "core:text/scanner" +import thread "core:thread" +import time "core:time" +import unicode "core:unicode" +import utf8 "core:unicode/utf8" +import utf16 "core:unicode/utf16" main :: proc(){} diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 2590fdc01..eed633cd6 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2010,7 +2010,7 @@ or_else_procedure :: proc() { i = 123; } // The above can be mapped to 'or_else' - i = or_else(m["hellope"], 123); + i = m["hellope"] or_else 123; assert(i == 123); } @@ -2019,12 +2019,12 @@ or_else_procedure :: proc() { // have optional ok semantics v: union{int, f64}; i: int; - i = or_else(v.(int), 123); - i = or_else(v.?, 123); // Type inference magic + i = v.(int) or_else 123; + i = v.? or_else 123; // Type inference magic assert(i == 123); m: Maybe(int); - i = or_else(m.?, 456); + i = m.? or_else 456; assert(i == 456); } } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 77c4ee453..e1615ce87 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -179,11 +179,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 // NOTE(bill): The first arg may be a Type, this will be checked case by case break; - case BuiltinProc_or_else: - case BuiltinProc_or_return: - // NOTE(bill): The arguments may be multi-expr - break; - case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; @@ -1835,120 +1830,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } - case BuiltinProc_or_else: { - GB_ASSERT(ce->args.count == 2); - Ast *arg = ce->args[0]; - Ast *default_value = ce->args[1]; - - Operand x = {}; - Operand y = {}; - check_multi_expr_with_type_hint(c, &x, arg, type_hint); - if (x.mode == Addressing_Invalid) { - operand->mode = Addressing_Value; - operand->type = t_invalid; - return false; - } - - check_multi_expr_with_type_hint(c, &y, default_value, x.type); - error_operand_no_value(&y); - if (y.mode == Addressing_Invalid) { - operand->mode = Addressing_Value; - operand->type = t_invalid; - return false; - } - - Type *left_type = nullptr; - Type *right_type = nullptr; - check_or_else_split_types(c, &x, builtin_name, &left_type, &right_type); - add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); - - if (left_type != nullptr) { - check_assignment(c, &y, left_type, builtin_name); - } else { - check_or_else_expr_no_value_error(c, builtin_name, x, type_hint); - } - - if (left_type == nullptr) { - left_type = t_invalid; - } - operand->mode = Addressing_Value; - operand->type = left_type; - return true; - } - - case BuiltinProc_or_return: { - GB_ASSERT(ce->args.count == 1); - Ast *arg = ce->args[0]; - - Operand x = {}; - check_multi_expr_with_type_hint(c, &x, arg, type_hint); - if (x.mode == Addressing_Invalid) { - operand->mode = Addressing_Value; - operand->type = t_invalid; - return false; - } - - Type *left_type = nullptr; - Type *right_type = nullptr; - check_or_return_split_types(c, &x, builtin_name, &left_type, &right_type); - add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); - - if (right_type == nullptr) { - check_or_else_expr_no_value_error(c, builtin_name, x, type_hint); - } else { - Type *proc_type = base_type(c->curr_proc_sig); - GB_ASSERT(proc_type->kind == Type_Proc); - Type *result_type = proc_type->Proc.results; - if (result_type == nullptr) { - error(call, "'%.*s' requires the current procedure to have at least one return value", LIT(builtin_name)); - } else { - GB_ASSERT(result_type->kind == Type_Tuple); - - auto const &vars = result_type->Tuple.variables; - Type *end_type = vars[vars.count-1]->type; - - if (vars.count > 1) { - if (!proc_type->Proc.has_named_results) { - error(call, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(builtin_name)); - } - } - - Operand rhs = {}; - rhs.type = right_type; - rhs.mode = Addressing_Value; - - // TODO(bill): better error message - if (!check_is_assignable_to(c, &rhs, end_type)) { - gbString a = type_to_string(right_type); - gbString b = type_to_string(end_type); - gbString ret_type = type_to_string(result_type); - error(call, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(builtin_name)); - if (vars.count == 1) { - error_line("\tProcedure return value type: %s\n", ret_type); - } else { - error_line("\tProcedure return value types: (%s)\n", ret_type); - } - gb_string_free(ret_type); - gb_string_free(b); - gb_string_free(a); - } - } - } - - operand->type = left_type; - if (left_type != nullptr) { - operand->mode = Addressing_Value; - } else { - operand->mode = Addressing_NoValue; - } - - if (c->curr_proc_sig == nullptr) { - error(call, "'%.*s' can only be used within a procedure", LIT(builtin_name)); - } - - return true; - } - case BuiltinProc_simd_vector: { Operand x = {}; Operand y = {}; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f01e9a328..c4715f67e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -114,6 +114,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_); +void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type); +void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); +void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); +void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); + Entity *entity_from_expr(Ast *expr) { expr = unparen_expr(expr); switch (expr->kind) { @@ -2960,6 +2965,25 @@ void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) update_untyped_expr_type(c, te->y, type, final); case_end; + case_ast_node(ore, OrReturnExpr, e); + if (old->value.kind != ExactValue_Invalid) { + // See above note in UnaryExpr case + break; + } + + update_untyped_expr_type(c, ore->expr, type, final); + case_end; + + case_ast_node(oee, OrElseExpr, e); + if (old->value.kind != ExactValue_Invalid) { + // See above note in UnaryExpr case + break; + } + + update_untyped_expr_type(c, oee->x, type, final); + update_untyped_expr_type(c, oee->y, type, final); + case_end; + case_ast_node(pe, ParenExpr, e); update_untyped_expr_type(c, pe->expr, type, final); case_end; @@ -6602,6 +6626,118 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } case_end; + case_ast_node(oe, OrElseExpr, node); + String name = oe->token.string; + Ast *arg = oe->x; + Ast *default_value = oe->y; + + Operand x = {}; + Operand y = {}; + check_multi_expr_with_type_hint(c, &x, arg, type_hint); + if (x.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + return Expr_Expr; + } + + check_multi_expr_with_type_hint(c, &y, default_value, x.type); + error_operand_no_value(&y); + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + return Expr_Expr; + } + + Type *left_type = nullptr; + Type *right_type = nullptr; + check_or_else_split_types(c, &x, name, &left_type, &right_type); + add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); + + if (left_type != nullptr) { + check_assignment(c, &y, left_type, name); + } else { + check_or_else_expr_no_value_error(c, name, x, type_hint); + } + + if (left_type == nullptr) { + left_type = t_invalid; + } + o->mode = Addressing_Value; + o->type = left_type; + return Expr_Expr; + case_end; + + case_ast_node(re, OrReturnExpr, node); + String name = re->token.string; + Operand x = {}; + check_multi_expr_with_type_hint(c, &x, re->expr, type_hint); + if (x.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + return Expr_Expr; + } + + Type *left_type = nullptr; + Type *right_type = nullptr; + check_or_return_split_types(c, &x, name, &left_type, &right_type); + add_type_and_value(&c->checker->info, re->expr, x.mode, x.type, x.value); + + if (right_type == nullptr) { + check_or_else_expr_no_value_error(c, name, x, type_hint); + } else { + Type *proc_type = base_type(c->curr_proc_sig); + GB_ASSERT(proc_type->kind == Type_Proc); + Type *result_type = proc_type->Proc.results; + if (result_type == nullptr) { + error(node, "'%.*s' requires the current procedure to have at least one return value", LIT(name)); + } else { + GB_ASSERT(result_type->kind == Type_Tuple); + + auto const &vars = result_type->Tuple.variables; + Type *end_type = vars[vars.count-1]->type; + + if (vars.count > 1) { + if (!proc_type->Proc.has_named_results) { + error(node, "'%.*s' within a procedure with more than 1 return value requires that the return values are named, allowing for early return", LIT(name)); + } + } + + Operand rhs = {}; + rhs.type = right_type; + rhs.mode = Addressing_Value; + + // TODO(bill): better error message + if (!check_is_assignable_to(c, &rhs, end_type)) { + gbString a = type_to_string(right_type); + gbString b = type_to_string(end_type); + gbString ret_type = type_to_string(result_type); + error(node, "Cannot assign end value of type '%s' to '%s' in '%.*s'", a, b, LIT(name)); + if (vars.count == 1) { + error_line("\tProcedure return value type: %s\n", ret_type); + } else { + error_line("\tProcedure return value types: (%s)\n", ret_type); + } + gb_string_free(ret_type); + gb_string_free(b); + gb_string_free(a); + } + } + } + + o->type = left_type; + if (left_type != nullptr) { + o->mode = Addressing_Value; + } else { + o->mode = Addressing_NoValue; + } + + if (c->curr_proc_sig == nullptr) { + error(node, "'%.*s' can only be used within a procedure", LIT(name)); + } + + return Expr_Expr; + case_end; + case_ast_node(cl, CompoundLit, node); Type *type = type_hint; if (type != nullptr && is_type_untyped(type)) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index bd105f0d7..57b5d7eb9 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -33,9 +33,6 @@ enum BuiltinProcId { BuiltinProc_soa_zip, BuiltinProc_soa_unzip, - BuiltinProc_or_else, - BuiltinProc_or_return, - BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures // "Intrinsics" @@ -266,9 +263,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("soa_zip"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("soa_unzip"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("or_else"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("or_return"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 1c5f03722..e6bb35c0c 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2305,6 +2305,14 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { } case_end; + case_ast_node(oe, OrElseExpr, expr); + return lb_emit_or_else(p, oe->x, oe->y, tv); + case_end; + + case_ast_node(oe, OrReturnExpr, expr); + return lb_emit_or_return(p, oe->expr, tv); + case_end; + case_ast_node(ta, TypeAssertion, expr); TokenPos pos = ast_token(expr).pos; Type *type = tv.type; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b3178e008..03b052c71 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1252,11 +1252,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_soa_unzip: return lb_soa_unzip(p, ce, tv); - case BuiltinProc_or_else: - return lb_emit_or_else(p, ce->args[0], ce->args[1], tv); - case BuiltinProc_or_return: - return lb_emit_or_return(p, ce->args[0], tv); - // "Intrinsics" case BuiltinProc_alloca: diff --git a/src/parser.cpp b/src/parser.cpp index 893ce9891..9e684028d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -685,6 +685,21 @@ Ast *ast_ternary_when_expr(AstFile *f, Ast *x, Ast *cond, Ast *y) { return result; } +Ast *ast_or_else_expr(AstFile *f, Ast *x, Token const &token, Ast *y) { + Ast *result = alloc_ast_node(f, Ast_OrElseExpr); + result->OrElseExpr.x = x; + result->OrElseExpr.token = token; + result->OrElseExpr.y = y; + return result; +} + +Ast *ast_or_return_expr(AstFile *f, Ast *expr, Token const &token) { + Ast *result = alloc_ast_node(f, Ast_OrReturnExpr); + result->OrReturnExpr.expr = expr; + result->OrReturnExpr.token = token; + return result; +} + Ast *ast_type_assertion(AstFile *f, Ast *expr, Token dot, Ast *type) { Ast *result = alloc_ast_node(f, Ast_TypeAssertion); result->TypeAssertion.expr = expr; @@ -1340,6 +1355,8 @@ Token expect_operator(AstFile *f) { // okay } else if (prev.kind == Token_if || prev.kind == Token_when) { // okay + } else if (prev.kind == Token_or_else || prev.kind == Token_or_return) { + // okay } else if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) { String p = token_to_string(prev); syntax_error(f->curr_token, "Expected an operator, got '%.*s'", @@ -2870,6 +2887,8 @@ i32 token_precedence(AstFile *f, TokenKind t) { case Token_Question: case Token_if: case Token_when: + case Token_or_else: + case Token_or_return: return 1; case Token_Ellipsis: case Token_RangeFull: @@ -2924,14 +2943,18 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { // NOTE(bill): This will also catch operators that are not valid "binary" operators break; } - if (op.kind == Token_if || op.kind == Token_when) { - Token prev = f->prev_token; + Token prev = f->prev_token; + switch (op.kind) { + case Token_if: + case Token_when: + case Token_or_else: + case Token_or_return: if (prev.pos.line < op.pos.line) { // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition - break; + goto loop_end; } + break; } - expect_operator(f); // NOTE(bill): error checks too if (op.kind == Token_Question) { @@ -2955,6 +2978,12 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { Token tok_else = expect_token(f, Token_else); Ast *y = parse_expr(f, lhs); expr = ast_ternary_when_expr(f, x, cond, y); + } else if (op.kind == Token_or_else) { + Ast *x = expr; + Ast *y = parse_expr(f, lhs); + expr = ast_or_else_expr(f, x, op, y); + } else if (op.kind == Token_or_return) { + expr = ast_or_return_expr(f, expr, op); } else { Ast *right = parse_binary_expr(f, false, prec+1); if (right == nullptr) { @@ -2965,6 +2994,7 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { lhs = false; } + loop_end:; } return expr; } diff --git a/src/parser.hpp b/src/parser.hpp index c284ec586..579ec5b79 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -385,6 +385,8 @@ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ AST_KIND(TernaryIfExpr, "ternary if expression", struct { Ast *x, *cond, *y; }) \ AST_KIND(TernaryWhenExpr, "ternary when expression", struct { Ast *x, *cond, *y; }) \ + AST_KIND(OrElseExpr, "or_else expression", struct { Ast *x; Token token; Ast *y; }) \ + AST_KIND(OrReturnExpr, "or_return expression", struct { Ast *expr; Token token; }) \ AST_KIND(TypeAssertion, "type assertion", struct { \ Ast *expr; \ Token dot; \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 921836afe..0f2ac438a 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -41,6 +41,8 @@ Token ast_token(Ast *node) { case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x); case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x); + case Ast_OrElseExpr: return ast_token(node->OrElseExpr.x); + case Ast_OrReturnExpr: return ast_token(node->OrReturnExpr.expr); case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr); case Ast_TypeCast: return node->TypeCast.token; case Ast_AutoCast: return node->AutoCast.token; @@ -175,6 +177,8 @@ Token ast_end_token(Ast *node) { case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y); case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y); + case Ast_OrElseExpr: return ast_end_token(node->OrElseExpr.y); + case Ast_OrReturnExpr: return node->OrReturnExpr.token; case Ast_TypeAssertion: return ast_end_token(node->TypeAssertion.type); case Ast_TypeCast: return ast_end_token(node->TypeCast.expr); case Ast_AutoCast: return ast_end_token(node->AutoCast.expr); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index e33c945bc..ad70905f0 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -113,10 +113,12 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_transmute, "transmute"), \ TOKEN_KIND(Token_distinct, "distinct"), \ TOKEN_KIND(Token_using, "using"), \ + TOKEN_KIND(Token_context, "context"), \ + TOKEN_KIND(Token_or_else, "or_else"), \ + TOKEN_KIND(Token_or_return, "or_return"), \ + TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_inline, "inline"), \ TOKEN_KIND(Token_no_inline, "no_inline"), \ - TOKEN_KIND(Token_context, "context"), \ - TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token__KeywordEnd, ""), \ TOKEN_KIND(Token_Count, "") From b8661e0ae01eae2ab8a3475006f0f5c3f099f987 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 17:16:37 +0100 Subject: [PATCH 03/16] Update semi-colon insertion rules for `or_return` --- src/tokenizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index ad70905f0..8772890d9 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -1510,6 +1510,7 @@ semicolon_check:; case Token_continue: case Token_fallthrough: case Token_return: + case Token_or_return: /*fallthrough*/ case Token_Integer: case Token_Float: From c27b8a71fd61a84444a09c09b6be15844c25232d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 17:52:10 +0100 Subject: [PATCH 04/16] Replace `err != nil` with `or_return` where appropriate --- core/math/big/helpers.odin | 96 ++++---- core/math/big/internal.odin | 147 ++++++------ core/math/big/logical.odin | 16 +- core/math/big/prime.odin | 9 +- core/math/big/private.odin | 447 +++++++++++++++++++----------------- core/math/big/public.odin | 91 ++++---- core/math/big/radix.odin | 43 ++-- core/math/big/test.odin | 28 +-- 8 files changed, 450 insertions(+), 427 deletions(-) diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 81a95a215..92fce3c52 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -42,7 +42,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator : Check that `src` is usable and `dest` isn't immutable. */ assert_if_nil(dest); - if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; } + (#force_inline internal_error_if_immutable(dest)) or_return; return #force_inline internal_int_set_from_integer(dest, src, minimize); } @@ -64,8 +64,8 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca assert_if_nil(dest, src); context.allocator = allocator; - if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; } - if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; } + (#force_inline internal_clear_if_uninitialized(src)) or_return; + (#force_inline internal_error_if_immutable(dest)) or_return; return #force_inline internal_int_copy(dest, src, minimize); } @@ -92,8 +92,8 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) assert_if_nil(dest, src); context.allocator = allocator; - if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; } - if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; } + (#force_inline internal_clear_if_uninitialized(src)) or_return; + (#force_inline internal_error_if_immutable(dest)) or_return; return #force_inline internal_int_abs(dest, src); } @@ -113,8 +113,8 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) assert_if_nil(dest, src); context.allocator = allocator; - if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; } - if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; } + (#force_inline internal_clear_if_uninitialized(src)) or_return; + (#force_inline internal_error_if_immutable(dest)) or_return; return #force_inline internal_int_neg(dest, src); } @@ -134,8 +134,8 @@ int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.a assert_if_nil(a); context.allocator = allocator; - if err = #force_inline internal_clear_if_uninitialized(a); err != nil { return {}, err; } - return #force_inline internal_int_bitfield_extract(a, offset, count); + (#force_inline internal_clear_if_uninitialized(a)) or_return; + return #force_inline internal_int_bitfield_extract(a, offset, count); } /* @@ -148,8 +148,8 @@ shrink :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); context.allocator = allocator; - if err = #force_inline internal_clear_if_uninitialized(a); err != nil { return err; } - return #force_inline internal_shrink(a); + (#force_inline internal_clear_if_uninitialized(a)) or_return; + return #force_inline internal_shrink(a); } int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) { @@ -305,8 +305,8 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T, Check that `a` is usable. */ assert_if_nil(a); - if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return T{}, err; } - return #force_inline internal_int_get(a, T); + (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + return #force_inline internal_int_get(a, T); } get :: proc { int_get, }; @@ -315,8 +315,8 @@ int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err Check that `a` is usable. */ assert_if_nil(a); - if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; } - return #force_inline internal_int_get_float(a); + (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + return #force_inline internal_int_get_float(a); } /* @@ -327,8 +327,8 @@ count_bits :: proc(a: ^Int, allocator := context.allocator) -> (count: int, err: Check that `a` is usable. */ assert_if_nil(a); - if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; } - return #force_inline internal_count_bits(a), nil; + (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + return #force_inline internal_count_bits(a), nil; } /* @@ -340,8 +340,8 @@ int_count_lsb :: proc(a: ^Int, allocator := context.allocator) -> (count: int, e Check that `a` is usable. */ assert_if_nil(a); - if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return 0, err; } - return #force_inline internal_int_count_lsb(a); + (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + return #force_inline internal_int_count_lsb(a); } platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) @@ -398,7 +398,7 @@ clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocato assert_if_nil(..args); for i in &args { - if err = #force_inline internal_clear_if_uninitialized_single(i, allocator); err != nil { return nil; } + (#force_inline internal_clear_if_uninitialized_single(i, allocator)) or_return; } return err; } @@ -425,7 +425,7 @@ int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err integers := integers; for a in &integers { - if err = #force_inline internal_clear(a, true, allocator); err != nil { return err; } + (#force_inline internal_clear(a, true, allocator)) or_return; } return nil; } @@ -440,7 +440,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator Check that `src` is usable and `dest` isn't immutable. */ assert_if_nil(dest, src); - if err = #force_inline internal_clear_if_uninitialized(src); err != nil { return err; } + (#force_inline internal_clear_if_uninitialized(src)) or_return; digits = min(digits, len(src.digit), len(dest.digit)); return #force_inline internal_copy_digits(dest, src, digits); @@ -454,7 +454,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator */ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); - if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return err; } + (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; for a.used > 0 && a.digit[a.used - 1] == 0 { a.used -= 1; @@ -472,7 +472,7 @@ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) { */ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) { assert_if_nil(a); - if err = #force_inline internal_clear_if_uninitialized(a, allocator); err != nil { return {}, err; } + (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; size_in_bits := internal_count_bits(a); @@ -488,9 +488,8 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat */ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); - size_in_bytes: int; - if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; } + size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return; l := len(buf); if size_in_bytes > l { return .Buffer_Overflow; } @@ -512,9 +511,8 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co */ int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); - size_in_bytes: int; - if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; } + size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return; l := len(buf); if size_in_bytes > l { return .Buffer_Overflow; } @@ -537,18 +535,17 @@ int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := conte */ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); - size_in_bytes: int; if !signed && a.sign == .Negative { return .Invalid_Argument; } l := len(buf); - if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; } - if size_in_bytes > l { return .Buffer_Overflow; } + size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return; + if size_in_bytes > l { return .Buffer_Overflow; } if a.sign == .Negative { t := &Int{}; defer destroy(t); - if err = internal_complement(t, a, allocator); err != nil { return err; } + internal_complement(t, a, allocator) or_return; size_in_bits := internal_count_bits(t); i := 0; @@ -574,19 +571,18 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato */ int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); - size_in_bytes: int; if !signed && a.sign == .Negative { return .Invalid_Argument; } if a.sign == .Zero_or_Positive { return int_to_bytes_big(a, buf, signed, allocator); } l := len(buf); - if size_in_bytes, err = int_to_bytes_size(a, signed, allocator); err != nil { return err; } - if size_in_bytes > l { return .Buffer_Overflow; } + size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return; + if size_in_bytes > l { return .Buffer_Overflow; } t := &Int{}; defer destroy(t); - if err = internal_complement(t, a, allocator); err != nil { return err; } + internal_complement(t, a, allocator) or_return; size_in_bits := internal_count_bits(t); i := l - 1; @@ -619,8 +615,8 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con } size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; size_in_digits += 0 if size_in_bits % 8 == 0 else 1; - if err = internal_zero(a, false, allocator); err != nil { return err; } - if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + internal_zero(a, false, allocator) or_return; + internal_grow(a, size_in_digits, false, allocator) or_return; if signed { sign = .Zero_or_Positive if buf[0] == 0 else .Negative; @@ -628,7 +624,7 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con } for v in buf { - if err = internal_shl(a, a, 8); err != nil { return err; } + internal_shl(a, a, 8) or_return; a.digit[0] |= DIGIT(v); } a.sign = sign; @@ -656,8 +652,8 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator } size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; size_in_digits += 0 if size_in_bits % 8 == 0 else 1; - if err = internal_zero(a, false, allocator); err != nil { return err; } - if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + internal_zero(a, false, allocator) or_return; + internal_grow(a, size_in_digits, false, allocator) or_return; if signed { sign = .Zero_or_Positive if buf[0] == 0 else .Negative; @@ -665,7 +661,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator } for v in buf { - if err = internal_shl(a, a, 8); err != nil { return err; } + internal_shl(a, a, 8) or_return; if signed && sign == .Negative { a.digit[0] |= DIGIT(255 - v); } else { @@ -674,7 +670,7 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator } a.sign = sign; a.used = size_in_digits; - if err = internal_clamp(a); err != nil { return err; } + internal_clamp(a) or_return; if signed && sign == .Negative { return internal_sub(a, a, 1); @@ -702,8 +698,8 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := } size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; size_in_digits += 0 if size_in_bits % 8 == 0 else 1; - if err = internal_zero(a, false, allocator); err != nil { return err; } - if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + internal_zero(a, false, allocator) or_return; + internal_grow(a, size_in_digits, false, allocator) or_return; if signed { sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative; @@ -712,7 +708,7 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := } for _, i in buf { - if err = internal_shl(a, a, 8); err != nil { return err; } + internal_shl(a, a, 8) or_return; a.digit[0] |= DIGIT(buf[l-i-1]); } a.sign = sign; @@ -740,8 +736,8 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca } size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS; size_in_digits += 0 if size_in_bits % 8 == 0 else 1; - if err = internal_zero(a, false, allocator); err != nil { return err; } - if err = internal_grow(a, size_in_digits, false, allocator); err != nil { return err; } + internal_zero(a, false, allocator) or_return; + internal_grow(a, size_in_digits, false, allocator) or_return; if signed { sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative; @@ -750,7 +746,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca } for _, i in buf { - if err = internal_shl(a, a, 8); err != nil { return err; } + internal_shl(a, a, 8) or_return; if signed && sign == .Negative { a.digit[0] |= DIGIT(255 - buf[l-i-1]); } else { @@ -759,7 +755,7 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca } a.sign = sign; a.used = size_in_digits; - if err = internal_clamp(a); err != nil { return err; } + internal_clamp(a) or_return; if signed && sign == .Negative { return internal_sub(a, a, 1); diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index ba6b04f43..e23c484b2 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -58,7 +58,7 @@ internal_int_add_unsigned :: proc(dest, a, b: ^Int, allocator := context.allocat max_used = x.used; old_used = dest.used; - if err = internal_grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; } + internal_grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)) or_return; dest.used = max_used + 1; /* All parameters have been initialized. @@ -158,7 +158,7 @@ internal_add_signed :: proc { internal_int_add_signed, }; internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) { context.allocator = allocator; - if err = internal_grow(dest, a.used + 1); err != nil { return err; } + internal_grow(dest, a.used + 1) or_return; /* Fast paths for destination and input Int being the same. */ @@ -284,7 +284,7 @@ internal_int_sub_unsigned :: proc(dest, number, decrease: ^Int, allocator := con max_used := x.used; i: int; - if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != nil { return err; } + grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)) or_return; dest.used = max_used; /* All parameters have been initialized. @@ -389,7 +389,7 @@ internal_int_sub_signed :: proc(dest, number, decrease: ^Int, allocator := conte internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) { context.allocator = allocator; - if err = internal_grow(dest, number.used + 1); err != nil { return err; } + internal_grow(dest, number.used + 1) or_return; dest := dest; digit := digit; /* @@ -520,12 +520,12 @@ internal_int_shr1 :: proc(dest, src: ^Int) -> (err: Error) { internal_int_shl1 :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator; - if err = internal_copy(dest, src); err != nil { return err; } + internal_copy(dest, src) or_return; /* Grow `dest` to accommodate the additional bits. */ digits_needed := dest.used + 1; - if err = internal_grow(dest, digits_needed); err != nil { return err; } + internal_grow(dest, digits_needed) or_return; dest.used = digits_needed; mask := (DIGIT(1) << uint(1)) - DIGIT(1); @@ -568,15 +568,14 @@ internal_int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := return #force_inline internal_int_shl1(dest, src); } if #force_inline platform_int_is_power_of_two(int(multiplier)) { - ix: int; - if ix, err = internal_log(multiplier, 2); err != nil { return err; } + ix := internal_log(multiplier, 2) or_return; return internal_shl(dest, src, ix); } /* Ensure `dest` is big enough to hold `src` * `multiplier`. */ - if err = grow(dest, max(src.used + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; } + grow(dest, max(src.used + 1, _DEFAULT_DIGIT_COUNT)) or_return; /* Save the original used count. @@ -722,7 +721,7 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a */ if #force_inline internal_cmp_mag(numerator, denominator) == -1 { if remainder != nil { - if err = internal_copy(remainder, numerator); err != nil { return err; } + internal_copy(remainder, numerator) or_return; } if quotient != nil { internal_zero(quotient); @@ -809,7 +808,7 @@ internal_int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, */ q := &Int{}; - if err = internal_grow(q, numerator.used); err != nil { return 0, err; } + internal_grow(q, numerator.used) or_return; q.used = numerator.used; q.sign = numerator.sign; @@ -853,7 +852,7 @@ internal_div :: proc { internal_int_div, }; Asssumes quotient, numerator and denominator to have been initialized and not to be nil. */ internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) { - if err = #force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator); err != nil { return err; } + (#force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator)) or_return; if remainder.used == 0 || denominator.sign == remainder.sign { return nil; } @@ -865,7 +864,7 @@ internal_mod :: proc{ internal_int_mod, }; remainder = (number + addend) % modulus. */ internal_int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - if err = #force_inline internal_add(remainder, number, addend, allocator); err != nil { return err; } + (#force_inline internal_add(remainder, number, addend, allocator)) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_addmod :: proc { internal_int_addmod, }; @@ -874,7 +873,7 @@ internal_addmod :: proc { internal_int_addmod, }; remainder = (number - decrease) % modulus. */ internal_int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - if err = #force_inline internal_sub(remainder, number, decrease, allocator); err != nil { return err; } + (#force_inline internal_sub(remainder, number, decrease, allocator)) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_submod :: proc { internal_int_submod, }; @@ -883,7 +882,7 @@ internal_submod :: proc { internal_int_submod, }; remainder = (number * multiplicand) % modulus. */ internal_int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - if err = #force_inline internal_mul(remainder, number, multiplicand, allocator); err != nil { return err; } + (#force_inline internal_mul(remainder, number, multiplicand, allocator)) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_mulmod :: proc { internal_int_mulmod, }; @@ -892,7 +891,7 @@ internal_mulmod :: proc { internal_int_mulmod, }; remainder = (number * number) % modulus. */ internal_int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - if err = #force_inline internal_sqr(remainder, number, allocator); err != nil { return err; } + (#force_inline internal_sqr(remainder, number, allocator)) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_sqrmod :: proc { internal_int_sqrmod, }; @@ -915,9 +914,11 @@ internal_int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator return #force_inline internal_set(res, _factorial_table[n]); } - if err = #force_inline internal_set(res, _factorial_table[i - 1]); err != nil { return err; } + (#force_inline internal_set(res, _factorial_table[i - 1])) or_return; for { - if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n { return err; } + if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n { + return err; + } i += 1; } @@ -950,8 +951,8 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator : /* If the modulus is larger than the value, return the value. */ - err = internal_copy(remainder, numerator); - if bits >= (numerator.used * _DIGIT_BITS) || err != nil { + internal_copy(remainder, numerator) or_return; + if bits >= (numerator.used * _DIGIT_BITS) { return; } @@ -1264,7 +1265,7 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo A zero base is a special case. */ if power < 0 { - if err = internal_zero(dest); err != nil { return err; } + internal_zero(dest) or_return; return .Math_Domain_Error; } if power == 0 { return internal_one(dest); } @@ -1293,37 +1294,34 @@ internal_int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allo } g := &Int{}; - if err = internal_copy(g, base); err != nil { return err; } + internal_copy(g, base) or_return; /* Set initial result. */ - if err = internal_one(dest); err != nil { return err; } + internal_one(dest) or_return; - loop: for power > 0 { + defer internal_destroy(g); + + for power > 0 { /* If the bit is set, multiply. */ if power & 1 != 0 { - if err = internal_mul(dest, g, dest); err != nil { - break loop; - } + internal_mul(dest, g, dest) or_return; } /* Square. */ if power > 1 { - if err = #force_inline internal_sqr(g, g); err != nil { - break loop; - } + internal_sqr(g, g) or_return; } /* shift to next bit */ power >>= 1; } - internal_destroy(g); - return err; + return; } /* @@ -1336,7 +1334,7 @@ internal_int_pow_int :: proc(dest: ^Int, base, power: int, allocator := context. base_t := &Int{}; defer internal_destroy(base_t); - if err = internal_set(base_t, base); err != nil { return err; } + internal_set(base_t, base) or_return; return #force_inline internal_int_pow(dest, base_t, power); } @@ -1387,15 +1385,15 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e count := #force_inline internal_count_bits(src); a, b := count >> 1, count & 1; - if err = internal_int_power_of_two(x, a+b, allocator); err != nil { return err; } + internal_int_power_of_two(x, a+b, allocator) or_return; for { /* y = (x + n // x) // 2 */ - if err = internal_div(t1, src, x); err != nil { return err; } - if err = internal_add(t2, t1, x); err != nil { return err; } - if err = internal_shr(y, t2, 1); err != nil { return err; } + internal_div(t1, src, x) or_return; + internal_add(t2, t1, x) or_return; + internal_shr(y, t2, 1) or_return; if c := internal_cmp(y, x); c == 0 || c == 1 { internal_swap(dest, x); @@ -1480,33 +1478,33 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca Start value must be larger than root. */ ilog2 += 2; - if err = internal_int_power_of_two(t2, ilog2); err != nil { return err; } + internal_int_power_of_two(t2, ilog2) or_return; c: int; iterations := 0; for { /* t1 = t2 */ - if err = internal_copy(t1, t2); err != nil { return err; } + internal_copy(t1, t2) or_return; /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ /* t3 = t1**(b-1) */ - if err = internal_pow(t3, t1, n-1); err != nil { return err; } + internal_pow(t3, t1, n-1) or_return; /* numerator */ /* t2 = t1**b */ - if err = internal_mul(t2, t1, t3); err != nil { return err; } + internal_mul(t2, t1, t3) or_return; /* t2 = t1**b - a */ - if err = internal_sub(t2, t2, a); err != nil { return err; } + internal_sub(t2, t2, a) or_return; /* denominator */ /* t3 = t1**(b-1) * b */ - if err = internal_mul(t3, t3, DIGIT(n)); err != nil { return err; } + internal_mul(t3, t3, DIGIT(n)) or_return; /* t3 = (t1**b - a)/(b * t1**(b-1)) */ - if err = internal_div(t3, t2, t3); err != nil { return err; } - if err = internal_sub(t2, t1, t3); err != nil { return err; } + internal_div(t3, t2, t3) or_return; + internal_sub(t2, t1, t3) or_return; /* Number of rounds is at most log_2(root). If it is more it @@ -1526,14 +1524,14 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca iterations = 0; for { - if err = internal_pow(t2, t1, n); err != nil { return err; } + internal_pow(t2, t1, n) or_return; c = internal_cmp(t2, a); if c == 0 { swap(dest, t1); return nil; } else if c == -1 { - if err = internal_add(t1, t1, DIGIT(1)); err != nil { return err; } + internal_add(t1, t1, DIGIT(1)) or_return; } else { break; } @@ -1549,11 +1547,11 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca Correct overshoot from above or from recurrence. */ for { - if err = internal_pow(t2, t1, n); err != nil { return err; } + internal_pow(t2, t1, n) or_return; if internal_cmp(t2, a) != 1 { break; } - if err = internal_sub(t1, t1, DIGIT(1)); err != nil { return err; } + internal_sub(t1, t1, DIGIT(1)) or_return; iterations += 1; if iterations == MAX_ITERATIONS_ROOT_N { @@ -1606,12 +1604,12 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al src := src; - if err = internal_error_if_immutable(dest); err != nil { return err; } + internal_error_if_immutable(dest) or_return; /* Most internal procs asssume an Int to have already been initialize, but as this is one of the procs that initializes, we have to check the following. */ - if err = internal_clear_if_uninitialized_single(dest); err != nil { return err; } + internal_clear_if_uninitialized_single(dest) or_return; dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable. @@ -1631,7 +1629,7 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al internal_set :: proc { internal_int_set_from_integer, internal_int_copy }; internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int) -> (err: Error) { - if err = #force_inline internal_error_if_immutable(dest); err != nil { return err; } + (#force_inline internal_error_if_immutable(dest)) or_return; /* If dest == src, do nothing @@ -1653,7 +1651,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte */ if (dest == src) { return nil; } - if err = internal_error_if_immutable(dest); err != nil { return err; } + internal_error_if_immutable(dest) or_return; /* Grow `dest` to fit `src`. @@ -1661,7 +1659,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte */ needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT); - if err = internal_grow(dest, needed, minimize); err != nil { return err; } + internal_grow(dest, needed, minimize) or_return; /* Copy everything over and zero high digits. @@ -1708,9 +1706,7 @@ internal_int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (er /* Copy `src` to `dest` */ - if err = internal_copy(dest, src); err != nil { - return err; - } + internal_copy(dest, src) or_return; /* Fix sign. @@ -1744,7 +1740,7 @@ internal_int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (er /* Copy `src` to `dest` */ - if err = internal_copy(dest, src); err != nil { return err; } + internal_copy(dest, src) or_return; /* Fix sign. @@ -1953,7 +1949,7 @@ internal_int_power_of_two :: proc(a: ^Int, power: int, allocator := context.allo Grow to accomodate the single bit. */ a.used = (power / _DIGIT_BITS) + 1; - if err = internal_grow(a, a.used); err != nil { return err; } + internal_grow(a, a.used) or_return; /* Zero the entirety. */ @@ -2061,7 +2057,7 @@ internal_int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e /* Grow the destination to accomodate the result. */ - if err = internal_grow(dest, used); err != nil { return err; } + internal_grow(dest, used) or_return; neg_a := #force_inline internal_is_negative(a); neg_b := #force_inline internal_is_negative(b); @@ -2122,7 +2118,7 @@ internal_int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (er /* Grow the destination to accomodate the result. */ - if err = internal_grow(dest, used); err != nil { return err; } + internal_grow(dest, used) or_return; neg_a := #force_inline internal_is_negative(a); neg_b := #force_inline internal_is_negative(b); @@ -2183,7 +2179,7 @@ internal_int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (e /* Grow the destination to accomodate the result. */ - if err = internal_grow(dest, used); err != nil { return err; } + internal_grow(dest, used) or_return; neg_a := #force_inline internal_is_negative(a); neg_b := #force_inline internal_is_negative(b); @@ -2269,21 +2265,21 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all bits := bits; if bits < 0 { return .Invalid_Argument; } - if err = internal_copy(quotient, numerator); err != nil { return err; } + internal_copy(quotient, numerator) or_return; /* Shift right by a certain bit count (store quotient and optional remainder.) `numerator` should not be used after this. */ if remainder != nil { - if err = internal_int_mod_bits(remainder, numerator, bits); err != nil { return err; } + internal_int_mod_bits(remainder, numerator, bits) or_return; } /* Shift by as many digits in the bit count. */ if bits >= _DIGIT_BITS { - if err = internal_shr_digit(quotient, bits / _DIGIT_BITS); err != nil { return err; } + internal_shr_digit(quotient, bits / _DIGIT_BITS) or_return; } /* @@ -2362,9 +2358,8 @@ internal_int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context if src.sign == .Zero_or_Positive { return internal_shr(dest, src, bits); } - if err = internal_int_add_digit(dest, src, DIGIT(1)); err != nil { return err; } - - if err = internal_shr(dest, dest, bits); err != nil { return err; } + internal_int_add_digit(dest, src, DIGIT(1)) or_return; + internal_shr(dest, dest, bits) or_return; return internal_sub(dest, src, DIGIT(1)); } @@ -2380,19 +2375,19 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca if bits < 0 { return .Invalid_Argument; } - if err = internal_copy(dest, src); err != nil { return err; } + internal_copy(dest, src) or_return; /* Grow `dest` to accommodate the additional bits. */ digits_needed := dest.used + (bits / _DIGIT_BITS) + 1; - if err = internal_grow(dest, digits_needed); err != nil { return err; } + internal_grow(dest, digits_needed) or_return; dest.used = digits_needed; /* Shift by as many digits in the bit count as we have. */ if bits >= _DIGIT_BITS { - if err = internal_shl_digit(dest, bits / _DIGIT_BITS); err != nil { return err; } + internal_shl_digit(dest, bits / _DIGIT_BITS) or_return; } /* @@ -2434,12 +2429,14 @@ internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context /* No need to shift a zero. */ - if #force_inline internal_is_zero(quotient) { return {}; } + if #force_inline internal_is_zero(quotient) { + return nil; + } /* Resize `quotient` to accomodate extra digits. */ - if err = #force_inline internal_grow(quotient, quotient.used + digits); err != nil { return err; } + (#force_inline internal_grow(quotient, quotient.used + digits)) or_return; /* Increment the used by the shift amount then copy upwards. @@ -2537,7 +2534,7 @@ internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator : digits += 1; } - if err = #force_inline internal_grow(dest, digits); err != nil { return err; } + (#force_inline internal_grow(dest, digits)) or_return; for i := 0; i < digits; i += 1 { dest.digit[i] = int_random_digit(r) & _MASK; @@ -2600,7 +2597,7 @@ internal_int_init_multi :: proc(integers: ..^Int, allocator := context.allocator integers := integers; for a in &integers { - if err = internal_clear(a); err != nil { return err; } + internal_clear(a) or_return; } return nil; } diff --git a/core/math/big/logical.odin b/core/math/big/logical.odin index 1eb26332a..42b262488 100644 --- a/core/math/big/logical.odin +++ b/core/math/big/logical.odin @@ -25,7 +25,7 @@ int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error assert_if_nil(dest, a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a, b); err != nil { return err; } + internal_clear_if_uninitialized(a, b) or_return; return #force_inline internal_int_and(dest, a, b); } and :: proc { int_and, }; @@ -37,7 +37,7 @@ int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) assert_if_nil(dest, a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a, b); err != nil { return err; } + internal_clear_if_uninitialized(a, b) or_return; return #force_inline internal_int_or(dest, a, b); } or :: proc { int_or, }; @@ -49,7 +49,7 @@ int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error assert_if_nil(dest, a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a, b); err != nil { return err; } + internal_clear_if_uninitialized(a, b) or_return; return #force_inline internal_int_xor(dest, a, b); } xor :: proc { int_xor, }; @@ -64,7 +64,7 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; return #force_inline internal_int_complement(dest, src); } complement :: proc { int_complement, }; @@ -97,7 +97,7 @@ int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato assert_if_nil(quotient); context.allocator = allocator; - if err = internal_clear_if_uninitialized(quotient); err != nil { return err; } + internal_clear_if_uninitialized(quotient) or_return; return #force_inline internal_int_shr_digit(quotient, digits); } shr_digit :: proc { int_shr_digit, }; @@ -109,7 +109,7 @@ int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocato assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; return #force_inline internal_int_shr_signed(dest, src, bits); } @@ -122,7 +122,7 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> ( assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; return #force_inline internal_int_shl(dest, src, bits); } shl :: proc { int_shl, }; @@ -138,7 +138,7 @@ int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato assert_if_nil(quotient); context.allocator = allocator; - if err = internal_clear_if_uninitialized(quotient); err != nil { return err; } + internal_clear_if_uninitialized(quotient) or_return; return #force_inline internal_int_shl_digit(quotient, digits); } shl_digit :: proc { int_shl_digit, }; \ No newline at end of file diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index 81fa2f69b..90eb2e4f7 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -19,12 +19,13 @@ int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res: assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return {}, err; } + internal_clear_if_uninitialized(a) or_return; - rem: DIGIT; for prime in _private_prime_table { - if rem, err = #force_inline int_mod_digit(a, prime); err != nil { return false, err; } - if rem == 0 { return true, nil; } + rem := (#force_inline int_mod_digit(a, prime)) or_return; + if rem == 0 { + return true, nil; + } } /* Default to not divisible. diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 6094e6baf..14c2464d0 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -42,7 +42,7 @@ _private_int_mul :: proc(dest, a, b: ^Int, digits: int, allocator := context.all t := &Int{}; - if err = internal_grow(t, max(digits, _DEFAULT_DIGIT_COUNT)); err != nil { return err; } + internal_grow(t, max(digits, _DEFAULT_DIGIT_COUNT)) or_return; t.used = digits; /* @@ -116,7 +116,7 @@ _private_int_mul_comba :: proc(dest, a, b: ^Int, digits: int, allocator := conte /* Grow the destination as required. */ - if err = internal_grow(dest, digits); err != nil { return err; } + internal_grow(dest, digits) or_return; /* Number of output digits to produce. @@ -198,7 +198,7 @@ _private_int_sqr :: proc(dest, src: ^Int, allocator := context.allocator) -> (er /* Grow `t` to maximum needed size, or `_DEFAULT_DIGIT_COUNT`, whichever is bigger. */ - if err = internal_grow(t, max((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; } + internal_grow(t, max((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)) or_return; t.used = (2 * pa) + 1; #no_bounds_check for ix = 0; ix < pa; ix += 1 { @@ -272,7 +272,7 @@ _private_int_sqr_comba :: proc(dest, src: ^Int, allocator := context.allocator) Grow the destination as required. */ pa := uint(src.used) + uint(src.used); - if err = internal_grow(dest, int(pa)); err != nil { return err; } + internal_grow(dest, int(pa)) or_return; /* Number of output digits to produce. @@ -374,12 +374,12 @@ _private_int_sqr_karatsuba :: proc(dest, src: ^Int, allocator := context.allocat /* Init temps. */ - if err = internal_grow(x0, B); err != nil { return err; } - if err = internal_grow(x1, src.used - B); err != nil { return err; } - if err = internal_grow(t1, src.used * 2); err != nil { return err; } - if err = internal_grow(t2, src.used * 2); err != nil { return err; } - if err = internal_grow(x0x0, B * 2 ); err != nil { return err; } - if err = internal_grow(x1x1, (src.used - B) * 2); err != nil { return err; } + internal_grow(x0, B) or_return; + internal_grow(x1, src.used - B) or_return; + internal_grow(t1, src.used * 2) or_return; + internal_grow(t2, src.used * 2) or_return; + internal_grow(x0x0, B * 2 ) or_return; + internal_grow(x1x1, (src.used - B) * 2) or_return; /* Now shift the digits. @@ -394,28 +394,28 @@ _private_int_sqr_karatsuba :: proc(dest, src: ^Int, allocator := context.allocat /* Now calc the products x0*x0 and x1*x1. */ - if err = internal_sqr(x0x0, x0); err != nil { return err; } - if err = internal_sqr(x1x1, x1); err != nil { return err; } + internal_sqr(x0x0, x0) or_return; + internal_sqr(x1x1, x1) or_return; /* Now calc (x1+x0)^2 */ - if err = internal_add(t1, x0, x1); err != nil { return err; } - if err = internal_sqr(t1, t1); err != nil { return err; } + internal_add(t1, x0, x1) or_return; + internal_sqr(t1, t1) or_return; /* Add x0y0 */ - if err = internal_add(t2, x0x0, x1x1); err != nil { return err; } - if err = internal_sub(t1, t1, t2); err != nil { return err; } + internal_add(t2, x0x0, x1x1) or_return; + internal_sub(t1, t1, t2) or_return; /* Shift by B. */ - if err = internal_shl_digit(t1, B); err != nil { return err; } - if err = internal_shl_digit(x1x1, B * 2); err != nil { return err; } - if err = internal_add(t1, t1, x0x0); err != nil { return err; } - if err = internal_add(dest, t1, x1x1); err != nil { return err; } + internal_shl_digit(t1, B) or_return; + internal_shl_digit(x1x1, B * 2) or_return; + internal_add(t1, t1, x0x0) or_return; + internal_add(dest, t1, x1x1) or_return; return #force_inline internal_clamp(dest); } @@ -435,7 +435,7 @@ _private_int_sqr_toom :: proc(dest, src: ^Int, allocator := context.allocator) - /* Init temps. */ - if err = internal_zero(S0); err != nil { return err; } + internal_zero(S0) or_return; /* B @@ -445,9 +445,9 @@ _private_int_sqr_toom :: proc(dest, src: ^Int, allocator := context.allocator) - /* a = a2 * x^2 + a1 * x + a0; */ - if err = internal_grow(a0, B); err != nil { return err; } - if err = internal_grow(a1, B); err != nil { return err; } - if err = internal_grow(a2, src.used - (2 * B)); err != nil { return err; } + internal_grow(a0, B) or_return; + internal_grow(a1, B) or_return; + internal_grow(a2, src.used - (2 * B)) or_return; a0.used = B; a1.used = B; @@ -462,67 +462,67 @@ _private_int_sqr_toom :: proc(dest, src: ^Int, allocator := context.allocator) - internal_clamp(a2); /** S0 = a0^2; */ - if err = internal_sqr(S0, a0); err != nil { return err; } + internal_sqr(S0, a0) or_return; /** \\S1 = (a2 + a1 + a0)^2 */ /** \\S2 = (a2 - a1 + a0)^2 */ /** \\S1 = a0 + a2; */ /** a0 = a0 + a2; */ - if err = internal_add(a0, a0, a2); err != nil { return err; } + internal_add(a0, a0, a2) or_return; /** \\S2 = S1 - a1; */ /** b = a0 - a1; */ - if err = internal_sub(dest, a0, a1); err != nil { return err; } + internal_sub(dest, a0, a1) or_return; /** \\S1 = S1 + a1; */ /** a0 = a0 + a1; */ - if err = internal_add(a0, a0, a1); err != nil { return err; } + internal_add(a0, a0, a1) or_return; /** \\S1 = S1^2; */ /** a0 = a0^2; */ - if err = internal_sqr(a0, a0); err != nil { return err; } + internal_sqr(a0, a0) or_return; /** \\S2 = S2^2; */ /** b = b^2; */ - if err = internal_sqr(dest, dest); err != nil { return err; } + internal_sqr(dest, dest) or_return; /** \\ S3 = 2 * a1 * a2 */ /** \\S3 = a1 * a2; */ /** a1 = a1 * a2; */ - if err = internal_mul(a1, a1, a2); err != nil { return err; } + internal_mul(a1, a1, a2) or_return; /** \\S3 = S3 << 1; */ /** a1 = a1 << 1; */ - if err = internal_shl(a1, a1, 1); err != nil { return err; } + internal_shl(a1, a1, 1) or_return; /** \\S4 = a2^2; */ /** a2 = a2^2; */ - if err = internal_sqr(a2, a2); err != nil { return err; } + internal_sqr(a2, a2) or_return; /** \\ tmp = (S1 + S2)/2 */ /** \\tmp = S1 + S2; */ /** b = a0 + b; */ - if err = internal_add(dest, a0, dest); err != nil { return err; } + internal_add(dest, a0, dest) or_return; /** \\tmp = tmp >> 1; */ /** b = b >> 1; */ - if err = internal_shr(dest, dest, 1); err != nil { return err; } + internal_shr(dest, dest, 1) or_return; /** \\ S1 = S1 - tmp - S3 */ /** \\S1 = S1 - tmp; */ /** a0 = a0 - b; */ - if err = internal_sub(a0, a0, dest); err != nil { return err; } + internal_sub(a0, a0, dest) or_return; /** \\S1 = S1 - S3; */ /** a0 = a0 - a1; */ - if err = internal_sub(a0, a0, a1); err != nil { return err; } + internal_sub(a0, a0, a1) or_return; /** \\S2 = tmp - S4 -S0 */ /** \\S2 = tmp - S4; */ /** b = b - a2; */ - if err = internal_sub(dest, dest, a2); err != nil { return err; } + internal_sub(dest, dest, a2) or_return; /** \\S2 = S2 - S0; */ /** b = b - S0; */ - if err = internal_sub(dest, dest, S0); err != nil { return err; } + internal_sub(dest, dest, S0) or_return; /** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */ /** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */ - if err = internal_shl_digit( a2, 4 * B); err != nil { return err; } - if err = internal_shl_digit( a1, 3 * B); err != nil { return err; } - if err = internal_shl_digit(dest, 2 * B); err != nil { return err; } - if err = internal_shl_digit( a0, 1 * B); err != nil { return err; } + internal_shl_digit( a2, 4 * B) or_return; + internal_shl_digit( a1, 3 * B) or_return; + internal_shl_digit(dest, 2 * B) or_return; + internal_shl_digit( a0, 1 * B) or_return; - if err = internal_add(a2, a2, a1); err != nil { return err; } - if err = internal_add(dest, dest, a2); err != nil { return err; } - if err = internal_add(dest, dest, a0); err != nil { return err; } - if err = internal_add(dest, dest, S0); err != nil { return err; } + internal_add(a2, a2, a1) or_return; + internal_add(dest, dest, a2) or_return; + internal_add(dest, dest, a0) or_return; + internal_add(dest, dest, S0) or_return; /** a^2 - P */ return #force_inline internal_clamp(dest); @@ -540,7 +540,7 @@ _private_int_div_3 :: proc(quotient, numerator: ^Int, allocator := context.alloc b := _WORD(1) << _WORD(_DIGIT_BITS) / _WORD(3); q := &Int{}; - if err = internal_grow(q, numerator.used); err != nil { return 0, err; } + internal_grow(q, numerator.used) or_return; q.used = numerator.used; q.sign = numerator.sign; @@ -598,17 +598,17 @@ _private_int_div_3 :: proc(quotient, numerator: ^Int, allocator := context.alloc _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator; - if err = error_if_immutable(quotient, remainder); err != nil { return err; } + error_if_immutable(quotient, remainder) or_return; q, x, y, t1, t2 := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}; defer internal_destroy(q, x, y, t1, t2); - if err = internal_grow(q, numerator.used + 2); err != nil { return err; } + internal_grow(q, numerator.used + 2) or_return; q.used = numerator.used + 2; - if err = internal_init_multi(t1, t2); err != nil { return err; } - if err = internal_copy(x, numerator); err != nil { return err; } - if err = internal_copy(y, denominator); err != nil { return err; } + internal_init_multi(t1, t2) or_return; + internal_copy(x, numerator) or_return; + internal_copy(y, denominator) or_return; /* Fix the sign. @@ -624,8 +624,8 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In if norm < _DIGIT_BITS - 1 { norm = (_DIGIT_BITS - 1) - norm; - if err = internal_shl(x, x, norm); err != nil { return err; } - if err = internal_shl(y, y, norm); err != nil { return err; } + internal_shl(x, x, norm) or_return; + internal_shl(y, y, norm) or_return; } else { norm = 0; } @@ -641,12 +641,12 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In y = y*b**{n-t} */ - if err = internal_shl_digit(y, n - t); err != nil { return err; } + internal_shl_digit(y, n - t) or_return; c := internal_cmp(x, y); for c != -1 { q.digit[n - t] += 1; - if err = internal_sub(x, x, y); err != nil { return err; } + internal_sub(x, x, y) or_return; c = internal_cmp(x, y); } @@ -696,7 +696,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In t1.digit[0] = ((t - 1) < 0) ? 0 : y.digit[t - 1]; t1.digit[1] = y.digit[t]; t1.used = 2; - if err = internal_mul(t1, t1, q.digit[(i - t) - 1]); err != nil { return err; } + internal_mul(t1, t1, q.digit[(i - t) - 1]) or_return; /* Find right hand. @@ -709,23 +709,25 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In if t1_t2 := internal_cmp_mag(t1, t2); t1_t2 != 1 { break; } - iter += 1; if iter > 100 { return .Max_Iterations_Reached; } + iter += 1; if iter > 100 { + return .Max_Iterations_Reached; + } } /* Step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ - if err = int_mul_digit(t1, y, q.digit[(i - t) - 1]); err != nil { return err; } - if err = internal_shl_digit(t1, (i - t) - 1); err != nil { return err; } - if err = internal_sub(x, x, t1); err != nil { return err; } + int_mul_digit(t1, y, q.digit[(i - t) - 1]) or_return; + internal_shl_digit(t1, (i - t) - 1) or_return; + internal_sub(x, x, t1) or_return; /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ if x.sign == .Negative { - if err = internal_copy(t1, y); err != nil { return err; } - if err = internal_shl_digit(t1, (i - t) - 1); err != nil { return err; } - if err = internal_add(x, x, t1); err != nil { return err; } + internal_copy(t1, y) or_return; + internal_shl_digit(t1, (i - t) - 1) or_return; + internal_add(x, x, t1) or_return; q.digit[(i - t) - 1] = (q.digit[(i - t) - 1] - 1) & _MASK; } @@ -745,7 +747,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In } if remainder != nil { - if err = internal_shr(x, x, norm); err != nil { return err; } + internal_shr(x, x, norm) or_return; internal_swap(x, remainder); } @@ -770,68 +772,72 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con m := a.used - b.used; k := m / 2; - if m < MUL_KARATSUBA_CUTOFF { return _private_int_div_school(quotient, remainder, a, b); } + if m < MUL_KARATSUBA_CUTOFF { + return _private_int_div_school(quotient, remainder, a, b); + } - if err = internal_init_multi(A1, A2, B1, B0, Q1, Q0, R1, R0, t); err != nil { return err; } + internal_init_multi(A1, A2, B1, B0, Q1, Q0, R1, R0, t) or_return; /* `B1` = `b` / `beta`^`k`, `B0` = `b` % `beta`^`k` */ - if err = internal_shrmod(B1, B0, b, k * _DIGIT_BITS); err != nil { return err; } + internal_shrmod(B1, B0, b, k * _DIGIT_BITS) or_return; /* (Q1, R1) = RecursiveDivRem(A / beta^(2k), B1) */ - if err = internal_shrmod(A1, t, a, 2 * k * _DIGIT_BITS); err != nil { return err; } - if err = _private_div_recursion(Q1, R1, A1, B1); err != nil { return err; } + internal_shrmod(A1, t, a, 2 * k * _DIGIT_BITS) or_return; + _private_div_recursion(Q1, R1, A1, B1) or_return; /* A1 = (R1 * beta^(2k)) + (A % beta^(2k)) - (Q1 * B0 * beta^k) */ - if err = internal_shl_digit(R1, 2 * k); err != nil { return err; } - if err = internal_add(A1, R1, t); err != nil { return err; } - if err = internal_mul(t, Q1, B0); err != nil { return err; } + internal_shl_digit(R1, 2 * k) or_return; + internal_add(A1, R1, t) or_return; + internal_mul(t, Q1, B0) or_return; /* While A1 < 0 do Q1 = Q1 - 1, A1 = A1 + (beta^k * B) */ if internal_cmp(A1, 0) == -1 { - if internal_shl(t, b, k * _DIGIT_BITS); err != nil { return err; } + internal_shl(t, b, k * _DIGIT_BITS) or_return; for { - if err = internal_decr(Q1); err != nil { return err; } - if err = internal_add(A1, A1, t); err != nil { return err; } - if internal_cmp(A1, 0) != -1 { break; } + internal_decr(Q1) or_return; + internal_add(A1, A1, t) or_return; + if internal_cmp(A1, 0) != -1 { + break; + } } } /* (Q0, R0) = RecursiveDivRem(A1 / beta^(k), B1) */ - if internal_shrmod(A1, t, A1, k * _DIGIT_BITS); err != nil { return err; } - if _private_div_recursion(Q0, R0, A1, B1); err != nil { return err; } + internal_shrmod(A1, t, A1, k * _DIGIT_BITS) or_return; + _private_div_recursion(Q0, R0, A1, B1) or_return; /* A2 = (R0*beta^k) + (A1 % beta^k) - (Q0*B0) */ - if err = internal_shl_digit(R0, k); err != nil { return err; } - if err = internal_add(A2, R0, t); err != nil { return err; } - if err = internal_mul(t, Q0, B0); err != nil { return err; } - if err = internal_sub(A2, A2, t); err != nil { return err; } + internal_shl_digit(R0, k) or_return; + internal_add(A2, R0, t) or_return; + internal_mul(t, Q0, B0) or_return; + internal_sub(A2, A2, t) or_return; /* While A2 < 0 do Q0 = Q0 - 1, A2 = A2 + B. */ for internal_cmp(A2, 0) == -1 { - if err = internal_decr(Q0); err != nil { return err; } - if err = internal_add(A2, A2, b); err != nil { return err; } + internal_decr(Q0) or_return; + internal_add(A2, A2, b) or_return; } /* Return q = (Q1*beta^k) + Q0, r = A2. */ - if err = internal_shl_digit(Q1, k); err != nil { return err; } - if err = internal_add(quotient, Q1, Q0); err != nil { return err; } + internal_shl_digit(Q1, k) or_return; + internal_add(quotient, Q1, Q0) or_return; return internal_copy(remainder, A2); } @@ -842,7 +848,7 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator := A, B, Q, Q1, R, A_div, A_mod := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}; defer internal_destroy(A, B, Q, Q1, R, A_div, A_mod); - if err = internal_init_multi(A, B, Q, Q1, R, A_div, A_mod); err != nil { return err; } + internal_init_multi(A, B, Q, Q1, R, A_div, A_mod) or_return; /* Most significant bit of a limb. @@ -859,8 +865,8 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator := /* Use that sigma to normalize B. */ - if err = internal_shl(B, b, sigma); err != nil { return err; } - if err = internal_shl(A, a, sigma); err != nil { return err; } + internal_shl(B, b, sigma) or_return; + internal_shl(A, a, sigma) or_return; /* Fix the sign. @@ -883,20 +889,20 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator := (q, r) = RecursiveDivRem(A / (beta^(m-n)), B) */ j := (m - n) * _DIGIT_BITS; - if err = internal_shrmod(A_div, A_mod, A, j); err != nil { return err; } - if err = _private_div_recursion(Q1, R, A_div, B); err != nil { return err; } + internal_shrmod(A_div, A_mod, A, j) or_return; + _private_div_recursion(Q1, R, A_div, B) or_return; /* Q = (Q*beta!(n)) + q */ - if err = internal_shl(Q, Q, n * _DIGIT_BITS); err != nil { return err; } - if err = internal_add(Q, Q, Q1); err != nil { return err; } + internal_shl(Q, Q, n * _DIGIT_BITS) or_return; + internal_add(Q, Q, Q1) or_return; /* A = (r * beta^(m-n)) + (A % beta^(m-n)) */ - if err = internal_shl(R, R, (m - n) * _DIGIT_BITS); err != nil { return err; } - if err = internal_add(A, R, A_mod); err != nil { return err; } + internal_shl(R, R, (m - n) * _DIGIT_BITS) or_return; + internal_add(A, R, A_mod) or_return; /* m = m - n @@ -907,13 +913,13 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator := /* (q, r) = RecursiveDivRem(A, B) */ - if err = _private_div_recursion(Q1, R, A, B); err != nil { return err; } + _private_div_recursion(Q1, R, A, B) or_return; /* Q = (Q * beta^m) + q, R = r */ - if err = internal_shl(Q, Q, m * _DIGIT_BITS); err != nil { return err; } - if err = internal_add(Q, Q, Q1); err != nil { return err; } + internal_shl(Q, Q, m * _DIGIT_BITS) or_return; + internal_add(Q, Q, Q1) or_return; /* Get sign before writing to dest. @@ -928,7 +934,7 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator := /* De-normalize the remainder. */ - if err = internal_shrmod(R, nil, R, sigma); err != nil { return err; } + internal_shrmod(R, nil, R, sigma) or_return; swap(remainder, R); } return nil; @@ -942,28 +948,29 @@ _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{}; c: int; + defer destroy(ta, tb, tq, q); - goto_end: for { - if err = internal_one(tq); err != nil { break goto_end; } + for { + internal_one(tq) or_return; num_bits, _ := count_bits(numerator); den_bits, _ := count_bits(denominator); n := num_bits - den_bits; - if err = abs(ta, numerator); err != nil { break goto_end; } - if err = abs(tb, denominator); err != nil { break goto_end; } - if err = shl(tb, tb, n); err != nil { break goto_end; } - if err = shl(tq, tq, n); err != nil { break goto_end; } + abs(ta, numerator) or_return; + abs(tb, denominator) or_return; + shl(tb, tb, n) or_return; + shl(tq, tq, n) or_return; for n >= 0 { if c, _ = cmp_mag(ta, tb); c == 0 || c == 1 { // ta -= tb - if err = sub(ta, ta, tb); err != nil { break goto_end; } + sub(ta, ta, tb) or_return; // q += tq - if err = add( q, q, tq); err != nil { break goto_end; } + add( q, q, tq) or_return; } - if err = shr1(tb, tb); err != nil { break goto_end; } - if err = shr1(tq, tq); err != nil { break goto_end; } + shr1(tb, tb) or_return; + shr1(tq, tq) or_return; n -= 1; } @@ -983,9 +990,8 @@ _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int remainder.sign = .Zero_or_Positive if z else numerator.sign; } - break goto_end; + break; } - destroy(ta, tb, tq, q); return err; } @@ -999,17 +1005,17 @@ _private_int_factorial_binary_split :: proc(res: ^Int, n: int, allocator := cont inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}; defer internal_destroy(inner, outer, start, stop, temp); - if err = internal_one(inner, false, allocator); err != nil { return err; } - if err = internal_one(outer, false, allocator); err != nil { return err; } + internal_one(inner, false, allocator) or_return; + internal_one(outer, false, allocator) or_return; bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n)); for i := bits_used; i >= 0; i -= 1 { start := (n >> (uint(i) + 1)) + 1 | 1; stop := (n >> uint(i)) + 1 | 1; - if err = _private_int_recursive_product(temp, start, stop, 0, allocator); err != nil { return err; } - if err = internal_mul(inner, inner, temp, allocator); err != nil { return err; } - if err = internal_mul(outer, outer, inner, allocator); err != nil { return err; } + _private_int_recursive_product(temp, start, stop, 0, allocator) or_return; + internal_mul(inner, inner, temp, allocator) or_return; + internal_mul(outer, outer, inner, allocator) or_return; } shift := n - intrinsics.count_ones(n); @@ -1023,28 +1029,32 @@ _private_int_recursive_product :: proc(res: ^Int, start, stop: int, level := int t1, t2 := &Int{}, &Int{}; defer internal_destroy(t1, t2); - if level > FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS { return .Max_Iterations_Reached; } + if level > FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS { + return .Max_Iterations_Reached; + } num_factors := (stop - start) >> 1; if num_factors == 2 { - if err = internal_set(t1, start, false, allocator); err != nil { return err; } + internal_set(t1, start, false, allocator) or_return; when true { - if err = internal_grow(t2, t1.used + 1, false, allocator); err != nil { return err; } - if err = internal_add(t2, t1, 2, allocator); err != nil { return err; } + internal_grow(t2, t1.used + 1, false, allocator) or_return; + internal_add(t2, t1, 2, allocator) or_return; } else { - if err = add(t2, t1, 2); err != nil { return err; } + add(t2, t1, 2) or_return; } return internal_mul(res, t1, t2, allocator); } if num_factors > 1 { mid := (start + num_factors) | 1; - if err = _private_int_recursive_product(t1, start, mid, level + 1, allocator); err != nil { return err; } - if err = _private_int_recursive_product(t2, mid, stop, level + 1, allocator); err != nil { return err; } + _private_int_recursive_product(t1, start, mid, level + 1, allocator) or_return; + _private_int_recursive_product(t2, mid, stop, level + 1, allocator) or_return; return internal_mul(res, t1, t2, allocator); } - if num_factors == 1 { return #force_inline internal_set(res, start, true, allocator); } + if num_factors == 1 { + return #force_inline internal_set(res, start, true, allocator); + } return #force_inline internal_one(res, true, allocator); } @@ -1067,7 +1077,9 @@ _private_int_recursive_product :: proc(res: ^Int, start, stop: int, level := int _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator; - if res_gcd == nil && res_lcm == nil { return nil; } + if res_gcd == nil && res_lcm == nil { + return nil; + } /* We need a temporary because `res_gcd` is allowed to be `nil`. @@ -1077,10 +1089,10 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. GCD(0, 0) and LCM(0, 0) are both 0. */ if res_gcd != nil { - if err = internal_zero(res_gcd); err != nil { return err; } + internal_zero(res_gcd) or_return; } if res_lcm != nil { - if err = internal_zero(res_lcm); err != nil { return err; } + internal_zero(res_lcm) or_return; } return nil; } else if a.used == 0 { @@ -1088,10 +1100,10 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. We can early out with GCD = B and LCM = 0 */ if res_gcd != nil { - if err = internal_abs(res_gcd, b); err != nil { return err; } + internal_abs(res_gcd, b) or_return; } if res_lcm != nil { - if err = internal_zero(res_lcm); err != nil { return err; } + internal_zero(res_lcm) or_return; } return nil; } else if b.used == 0 { @@ -1099,10 +1111,10 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. We can early out with GCD = A and LCM = 0 */ if res_gcd != nil { - if err = internal_abs(res_gcd, a); err != nil { return err; } + internal_abs(res_gcd, a) or_return; } if res_lcm != nil { - if err = internal_zero(res_lcm); err != nil { return err; } + internal_zero(res_lcm) or_return; } return nil; } @@ -1116,8 +1128,8 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. */ u, v := &Int{}, &Int{}; defer internal_destroy(u, v); - if err = internal_copy(u, a); err != nil { return err; } - if err = internal_copy(v, b); err != nil { return err; } + internal_copy(u, a) or_return; + internal_copy(v, b) or_return; /* Must be positive for the remainder of the algorithm. @@ -1135,18 +1147,18 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. /* Divide the power of two out. */ - if err = internal_shr(u, u, k); err != nil { return err; } - if err = internal_shr(v, v, k); err != nil { return err; } + internal_shr(u, u, k) or_return; + internal_shr(v, v, k) or_return; } /* Divide any remaining factors of two out. */ if u_lsb != k { - if err = internal_shr(u, u, u_lsb - k); err != nil { return err; } + internal_shr(u, u, u_lsb - k) or_return; } if v_lsb != k { - if err = internal_shr(v, v, v_lsb - k); err != nil { return err; } + internal_shr(v, v, v_lsb - k) or_return; } for v.used != 0 { @@ -1163,19 +1175,19 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. /* Subtract smallest from largest. */ - if err = internal_sub(v, v, u); err != nil { return err; } + internal_sub(v, v, u) or_return; /* Divide out all factors of two. */ b, _ := internal_count_lsb(v); - if err = internal_shr(v, v, b); err != nil { return err; } + internal_shr(v, v, b) or_return; } /* Multiply by 2**k which we divided out at the beginning. */ - if err = internal_shl(temp_gcd_res, u, k); err != nil { return err; } + internal_shl(temp_gcd_res, u, k) or_return; temp_gcd_res.sign = .Zero_or_Positive; /* @@ -1195,13 +1207,13 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. /* Store quotient in `t2` such that `t2 * b` is the LCM. */ - if err = internal_div(res_lcm, a, temp_gcd_res); err != nil { return err; } + internal_div(res_lcm, a, temp_gcd_res) or_return; err = internal_mul(res_lcm, res_lcm, b); } else { /* Store quotient in `t2` such that `t2 * a` is the LCM. */ - if err = internal_div(res_lcm, a, temp_gcd_res); err != nil { return err; } + internal_div(res_lcm, a, temp_gcd_res) or_return; err = internal_mul(res_lcm, res_lcm, b); } @@ -1228,12 +1240,15 @@ _private_int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) - if ic == -1 || ic == 0 { return 1 if ic == 0 else 0, nil; } + defer if err != nil { + res = -1; + } - if err = internal_set(bi_base, base, true, allocator); err != nil { return -1, err; } - if err = internal_clear(bracket_mid, false, allocator); err != nil { return -1, err; } - if err = internal_clear(t, false, allocator); err != nil { return -1, err; } - if err = internal_one(bracket_low, false, allocator); err != nil { return -1, err; } - if err = internal_set(bracket_high, base, false, allocator); err != nil { return -1, err; } + internal_set(bi_base, base, true, allocator) or_return; + internal_clear(bracket_mid, false, allocator) or_return; + internal_clear(t, false, allocator) or_return; + internal_one(bracket_low, false, allocator) or_return; + internal_set(bracket_high, base, false, allocator) or_return; low := 0; high := 1; @@ -1248,20 +1263,22 @@ _private_int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) - /* Iterate until `a` is bracketed between low + high. */ - if #force_inline internal_cmp(bracket_high, a) != -1 { break; } + if #force_inline internal_cmp(bracket_high, a) != -1 { + break; + } low = high; - if err = #force_inline internal_copy(bracket_low, bracket_high); err != nil { return -1, err; } + (#force_inline internal_copy(bracket_low, bracket_high)) or_return; high <<= 1; - if err = #force_inline internal_sqr(bracket_high, bracket_high); err != nil { return -1, err; } + (#force_inline internal_sqr(bracket_high, bracket_high)) or_return; } for (high - low) > 1 { mid := (high + low) >> 1; - if err = #force_inline internal_pow(t, bi_base, mid - low); err != nil { return -1, err; } + (#force_inline internal_pow(t, bi_base, mid - low)) or_return; - if err = #force_inline internal_mul(bracket_mid, bracket_low, t); err != nil { return -1, err; } + (#force_inline internal_mul(bracket_mid, bracket_low, t)) or_return; mc := #force_inline internal_cmp(a, bracket_mid); switch mc { @@ -1294,31 +1311,35 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* `b` cannot be negative. */ - if b.sign == .Negative || internal_is_zero(b) { return .Invalid_Argument; } + if b.sign == .Negative || internal_is_zero(b) { + return .Invalid_Argument; + } /* init temps. */ - if err = internal_init_multi(x, y, u, v, A, B, C, D); err != nil { return err; } + internal_init_multi(x, y, u, v, A, B, C, D) or_return; /* `x` = `a` % `b`, `y` = `b` */ - if err = internal_mod(x, a, b); err != nil { return err; } - if err = internal_copy(y, b); err != nil { return err; } + internal_mod(x, a, b) or_return; + internal_copy(y, b) or_return; /* 2. [modified] if x,y are both even then return an error! */ - if internal_is_even(x) && internal_is_even(y) { return .Invalid_Argument; } + if internal_is_even(x) && internal_is_even(y) { + return .Invalid_Argument; + } /* 3. u=x, v=y, A=1, B=0, C=0, D=1 */ - if err = internal_copy(u, x); err != nil { return err; } - if err = internal_copy(v, y); err != nil { return err; } - if err = internal_one(A); err != nil { return err; } - if err = internal_one(D); err != nil { return err; } + internal_copy(u, x) or_return; + internal_copy(v, y) or_return; + internal_one(A) or_return; + internal_one(D) or_return; for { /* @@ -1328,7 +1349,7 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* 4.1 `u` = `u` / 2 */ - if err = internal_int_shr1(u, u); err != nil { return err; } + internal_int_shr1(u, u) or_return; /* 4.2 if `A` or `B` is odd then: @@ -1337,14 +1358,14 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* `A` = (`A`+`y`) / 2, `B` = (`B`-`x`) / 2 */ - if err = internal_add(A, A, y); err != nil { return err; } - if err = internal_add(B, B, x); err != nil { return err; } + internal_add(A, A, y) or_return; + internal_add(B, B, x) or_return; } /* `A` = `A` / 2, `B` = `B` / 2 */ - if err = internal_int_shr1(A, A); err != nil { return err; } - if err = internal_int_shr1(B, B); err != nil { return err; } + internal_int_shr1(A, A) or_return; + internal_int_shr1(B, B) or_return; } /* @@ -1354,7 +1375,7 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* 5.1 `v` = `v` / 2 */ - if err = internal_int_shr1(v, v); err != nil { return err; } + internal_int_shr1(v, v) or_return; /* 5.2 if `C` or `D` is odd then: @@ -1363,14 +1384,14 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* `C` = (`C`+`y`) / 2, `D` = (`D`-`x`) / 2 */ - if err = internal_add(C, C, y); err != nil { return err; } - if err = internal_add(D, D, x); err != nil { return err; } + internal_add(C, C, y) or_return; + internal_add(D, D, x) or_return; } /* `C` = `C` / 2, `D` = `D` / 2 */ - if err = internal_int_shr1(C, C); err != nil { return err; } - if err = internal_int_shr1(D, D); err != nil { return err; } + internal_int_shr1(C, C) or_return; + internal_int_shr1(D, D) or_return; } /* @@ -1380,20 +1401,22 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* `u` = `u` - `v`, `A` = `A` - `C`, `B` = `B` - `D` */ - if err = internal_sub(u, u, v); err != nil { return err; } - if err = internal_sub(A, A, C); err != nil { return err; } - if err = internal_sub(B, B, D); err != nil { return err; } + internal_sub(u, u, v) or_return; + internal_sub(A, A, C) or_return; + internal_sub(B, B, D) or_return; } else { /* v - v - u, C = C - A, D = D - B */ - if err = internal_sub(v, v, u); err != nil { return err; } - if err = internal_sub(C, C, A); err != nil { return err; } - if err = internal_sub(D, D, B); err != nil { return err; } + internal_sub(v, v, u) or_return; + internal_sub(C, C, A) or_return; + internal_sub(D, D, B) or_return; } /* If not zero goto step 4 */ - if internal_is_zero(u) { break; } + if internal_is_zero(u) { + break; + } } /* @@ -1403,20 +1426,22 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator /* If `v` != `1` then there is no inverse. */ - if internal_cmp(v, 1) != 0 { return .Invalid_Argument; } + if internal_cmp(v, 1) != 0 { + return .Invalid_Argument; + } /* If its too low. */ if internal_cmp(C, 0) == -1 { - if err = internal_add(C, C, b); err != nil { return err; } + internal_add(C, C, b) or_return; } /* Too big. */ if internal_cmp(C, 0) != -1 { - if err = internal_sub(C, C, b); err != nil { return err; } + internal_sub(C, C, b) or_return; } /* @@ -1443,35 +1468,39 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* 2. [modified] `b` must be odd. */ - if internal_is_even(b) { return .Invalid_Argument; } + if internal_is_even(b) { + return .Invalid_Argument; + } /* Init all our temps. */ - if err = internal_init_multi(x, y, u, v, B, D); err != nil { return err; } + internal_init_multi(x, y, u, v, B, D) or_return; /* `x` == modulus, `y` == value to invert. */ - if err = internal_copy(x, b); err != nil { return err; } + internal_copy(x, b) or_return; /* We need `y` = `|a|`. */ - if err = internal_mod(y, a, b); err != nil { return err; } + internal_mod(y, a, b) or_return; /* If one of `x`, `y` is zero return an error! */ - if internal_is_zero(x) || internal_is_zero(y) { return .Invalid_Argument; } + if internal_is_zero(x) || internal_is_zero(y) { + return .Invalid_Argument; + } /* 3. `u` = `x`, `v` = `y`, `A` = 1, `B` = 0, `C` = 0, `D` = 1 */ - if err = internal_copy(u, x); err != nil { return err; } - if err = internal_copy(v, y); err != nil { return err; } + internal_copy(u, x) or_return; + internal_copy(v, y) or_return; - if err = internal_one(D); err != nil { return err; } + internal_one(D) or_return; for { /* @@ -1481,7 +1510,7 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* 4.1 `u` = `u` / 2 */ - if err = internal_int_shr1(u, u); err != nil { return err; } + internal_int_shr1(u, u) or_return; /* 4.2 if `B` is odd then: @@ -1490,13 +1519,13 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* `B` = (`B` - `x`) / 2 */ - if err = internal_sub(B, B, x); err != nil { return err; } + internal_sub(B, B, x) or_return; } /* `B` = `B` / 2 */ - if err = internal_int_shr1(B, B); err != nil { return err; } + internal_int_shr1(B, B) or_return; } /* @@ -1506,7 +1535,7 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* 5.1 `v` = `v` / 2 */ - if err = internal_int_shr1(v, v); err != nil { return err; } + internal_int_shr1(v, v) or_return; /* 5.2 if `D` is odd then: @@ -1515,12 +1544,12 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* `D` = (`D` - `x`) / 2 */ - if err = internal_sub(D, D, x); err != nil { return err; } + internal_sub(D, D, x) or_return; } /* `D` = `D` / 2 */ - if err = internal_int_shr1(D, D); err != nil { return err; } + internal_int_shr1(D, D) or_return; } /* @@ -1530,20 +1559,22 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* `u` = `u` - `v`, `B` = `B` - `D` */ - if err = internal_sub(u, u, v); err != nil { return err; } - if err = internal_sub(B, B, D); err != nil { return err; } + internal_sub(u, u, v) or_return; + internal_sub(B, B, D) or_return; } else { /* `v` - `v` - `u`, `D` = `D` - `B` */ - if err = internal_sub(v, v, u); err != nil { return err; } - if err = internal_sub(D, D, B); err != nil { return err; } + internal_sub(v, v, u) or_return; + internal_sub(D, D, B) or_return; } /* If not zero goto step 4. */ - if internal_is_zero(u) { break; } + if internal_is_zero(u) { + break; + } } /* @@ -1553,21 +1584,23 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc /* if `v` != 1 then there is no inverse */ - if internal_cmp(v, 1) != 0 { return .Invalid_Argument; } + if internal_cmp(v, 1) != 0 { + return .Invalid_Argument; + } /* `b` is now the inverse. */ sign = a.sign; for internal_int_is_negative(D) { - if err = internal_add(D, D, b); err != nil { return err; } + internal_add(D, D, b) or_return; } /* Too big. */ for internal_cmp_mag(D, b) != -1 { - if err = internal_sub(D, D, b); err != nil { return err; } + internal_sub(D, D, b) or_return; } swap(dest, D); @@ -1601,7 +1634,9 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int) -> (err: Error) { /* If dest == src, do nothing */ - if dest == src { return nil; } + if dest == src { + return nil; + } digits = min(digits, len(src.digit), len(dest.digit)); mem.copy_non_overlapping(&dest.digit[0], &src.digit[0], size_of(DIGIT) * digits); diff --git a/core/math/big/public.odin b/core/math/big/public.odin index b7a00fbc0..edcee106d 100644 --- a/core/math/big/public.odin +++ b/core/math/big/public.odin @@ -24,7 +24,7 @@ int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error assert_if_nil(dest, a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, a, b); err != nil { return err; } + internal_clear_if_uninitialized(dest, a, b) or_return; /* All parameters have been initialized. */ @@ -41,11 +41,11 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato assert_if_nil(dest, a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return err; } + internal_clear_if_uninitialized(a) or_return; /* Grow destination as required. */ - if err = grow(dest, a.used + 1); err != nil { return err; } + grow(dest, a.used + 1) or_return; /* All parameters have been initialized. @@ -60,7 +60,7 @@ int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) -> assert_if_nil(dest, number, decrease); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, number, decrease); err != nil { return err; } + internal_clear_if_uninitialized(dest, number, decrease) or_return; /* All parameters have been initialized. */ @@ -77,11 +77,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato assert_if_nil(dest, a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return err; } + internal_clear_if_uninitialized(a) or_return; /* Grow destination as required. */ - if err = grow(dest, a.used + 1); err != nil { return err; } + grow(dest, a.used + 1) or_return; /* All parameters have been initialized. @@ -97,11 +97,11 @@ int_halve :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Erro assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; /* Grow destination as required. */ - if dest != src { if err = grow(dest, src.used + 1); err != nil { return err; } } + if dest != src { grow(dest, src.used + 1) or_return } return #force_inline internal_int_shr1(dest, src); } @@ -116,11 +116,11 @@ int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Err assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; /* Grow destination as required. */ - if dest != src { if err = grow(dest, src.used + 1); err != nil { return err; } } + if dest != src { grow(dest, src.used + 1) or_return; } return #force_inline internal_int_shl1(dest, src); } @@ -134,7 +134,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.a assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(src, dest); err != nil { return err; } + internal_clear_if_uninitialized(src, dest) or_return; return #force_inline internal_int_mul_digit(dest, src, multiplier); } @@ -146,7 +146,7 @@ int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) -> assert_if_nil(dest, src, multiplier); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src, multiplier); err != nil { return err; } + internal_clear_if_uninitialized(dest, src, multiplier) or_return; return #force_inline internal_int_mul(dest, src, multiplier); } @@ -166,7 +166,7 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator Early out if neither of the results is wanted. */ if quotient == nil && remainder == nil { return nil; } - if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; } + internal_clear_if_uninitialized(numerator, denominator) or_return; return #force_inline internal_divmod(quotient, remainder, numerator, denominator); } @@ -175,7 +175,7 @@ int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocato assert_if_nil(quotient, numerator); context.allocator = allocator; - if err = internal_clear_if_uninitialized(numerator); err != nil { return 0, err; } + internal_clear_if_uninitialized(numerator) or_return; return #force_inline internal_divmod(quotient, numerator, denominator); } @@ -185,7 +185,7 @@ int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.all assert_if_nil(quotient, numerator, denominator); context.allocator = allocator; - if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; } + internal_clear_if_uninitialized(numerator, denominator) or_return; return #force_inline internal_divmod(quotient, nil, numerator, denominator); } @@ -194,11 +194,10 @@ int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator : assert_if_nil(quotient, numerator); context.allocator = allocator; - if err = internal_clear_if_uninitialized(numerator); err != nil { return err; } + internal_clear_if_uninitialized(numerator) or_return; - remainder: DIGIT; - remainder, err = #force_inline internal_divmod(quotient, numerator, denominator); - return err; + _ = (#force_inline internal_divmod(quotient, numerator, denominator)) or_return; + return; } div :: proc { int_div, int_div_digit, }; @@ -211,7 +210,7 @@ int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.al assert_if_nil(remainder, numerator, denominator); context.allocator = allocator; - if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; } + internal_clear_if_uninitialized(numerator, denominator) or_return; return #force_inline internal_int_mod(remainder, numerator, denominator); } @@ -229,7 +228,7 @@ int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := contex assert_if_nil(remainder, number, addend); context.allocator = allocator; - if err = internal_clear_if_uninitialized(number, addend, modulus); err != nil { return err; } + internal_clear_if_uninitialized(number, addend, modulus) or_return; return #force_inline internal_addmod(remainder, number, addend, modulus); } @@ -242,7 +241,7 @@ int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := cont assert_if_nil(remainder, number, decrease); context.allocator = allocator; - if err = internal_clear_if_uninitialized(number, decrease, modulus); err != nil { return err; } + internal_clear_if_uninitialized(number, decrease, modulus) or_return; return #force_inline internal_submod(remainder, number, decrease, modulus); } @@ -255,7 +254,7 @@ int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := assert_if_nil(remainder, number, multiplicand); context.allocator = allocator; - if err = internal_clear_if_uninitialized(number, multiplicand, modulus); err != nil { return err; } + internal_clear_if_uninitialized(number, multiplicand, modulus) or_return; return #force_inline internal_mulmod(remainder, number, multiplicand, modulus); } @@ -268,7 +267,7 @@ int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.alloca assert_if_nil(remainder, number, modulus); context.allocator = allocator; - if err = internal_clear_if_uninitialized(number, modulus); err != nil { return err; } + internal_clear_if_uninitialized(number, modulus) or_return; return #force_inline internal_sqrmod(remainder, number, modulus); } @@ -312,14 +311,14 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) - n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{}; defer internal_destroy(n_fac, k_fac, n_minus_k_fac); - if err = #force_inline internal_int_factorial(n_minus_k_fac, n - k); err != nil { return err; } - if err = #force_inline internal_int_factorial(k_fac, k); err != nil { return err; } - if err = #force_inline internal_mul(k_fac, k_fac, n_minus_k_fac); err != nil { return err; } + (#force_inline internal_int_factorial(n_minus_k_fac, n - k)) or_return; + (#force_inline internal_int_factorial(k_fac, k)) or_return; + (#force_inline internal_mul(k_fac, k_fac, n_minus_k_fac)) or_return; - if err = #force_inline internal_int_factorial(n_fac, n); err != nil { return err; } - if err = #force_inline internal_div(res, n_fac, k_fac); err != nil { return err; } + (#force_inline internal_int_factorial(n_fac, n)) or_return; + (#force_inline internal_div(res, n_fac, k_fac)) or_return; - return err; + return; } choose :: proc { int_choose_digit, }; @@ -331,7 +330,7 @@ int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator assert_if_nil(a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a, b); err != nil { return err; } + internal_clear_if_uninitialized(a, b) or_return; return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b); } gcd_lcm :: proc { int_gcd_lcm, }; @@ -359,8 +358,8 @@ int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator := context assert_if_nil(remainder, numerator); context.allocator = allocator; - if err = internal_clear_if_uninitialized(remainder, numerator); err != nil { return err; } - if bits < 0 { return .Invalid_Argument; } + internal_clear_if_uninitialized(remainder, numerator) or_return; + if bits < 0 { return .Invalid_Argument; } return #force_inline internal_int_mod_bits(remainder, numerator, bits); } @@ -375,7 +374,7 @@ int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: i assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_int_log(a, base); } @@ -392,7 +391,7 @@ int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) -> assert_if_nil(dest, base); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, base); err != nil { return err; } + internal_clear_if_uninitialized(dest, base) or_return; return #force_inline internal_int_pow(dest, base, power); } @@ -420,7 +419,7 @@ int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error assert_if_nil(dest, src); context.allocator = allocator; - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; return #force_inline internal_int_sqrt(dest, src); } @@ -446,7 +445,7 @@ int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> ( /* Initialize dest + src if needed. */ - if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; } + internal_clear_if_uninitialized(dest, src) or_return; return #force_inline internal_int_root_n(dest, src, n); } @@ -466,7 +465,7 @@ int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return false, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_is_zero(a), nil; } @@ -475,7 +474,7 @@ int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: b assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return false, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_is_positive(a), nil; } @@ -484,7 +483,7 @@ int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: b assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return false, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_is_negative(a), nil; } @@ -493,7 +492,7 @@ int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return false, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_is_even(a), nil; } @@ -502,7 +501,7 @@ int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err: assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return false, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_is_odd(a), nil; } @@ -515,7 +514,7 @@ int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bo assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return false, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_is_power_of_two(a), nil; } @@ -527,7 +526,7 @@ int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison: assert_if_nil(a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a, b); err != nil { return 0, err; } + internal_clear_if_uninitialized(a, b) or_return; return #force_inline internal_cmp(a, b), nil; } @@ -540,7 +539,7 @@ int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) -> assert_if_nil(a); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; } + internal_clear_if_uninitialized(a) or_return; return #force_inline internal_cmp_digit(a, b), nil; } @@ -553,7 +552,7 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re assert_if_nil(a, b); context.allocator = allocator; - if err = internal_clear_if_uninitialized(a, b); err != nil { return 0, err; } + internal_clear_if_uninitialized(a, b) or_return; return #force_inline internal_cmp_mag(a, b), nil; } \ No newline at end of file diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 01c0489d8..e7eee9513 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -26,7 +26,7 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc context.allocator = allocator; a := a; radix := radix; - if err = clear_if_uninitialized(a); err != nil { return "", err; } + clear_if_uninitialized(a) or_return; /* Radix defaults to 10. */ @@ -39,14 +39,9 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc /* Calculate the size of the buffer we need, and - */ - size: int; - /* Exit if calculating the size returned an error. */ - if size, err = radix_size(a, radix, zero_terminate); err != nil { - return "", err; - } + size := radix_size(a, radix, zero_terminate) or_return; /* Allocate the buffer we need. @@ -70,7 +65,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato context.allocator = allocator; a := a; radix := radix; - if err = clear_if_uninitialized(a); err != nil { return "", err; } + clear_if_uninitialized(a) or_return; /* Radix defaults to 10. */ @@ -104,7 +99,7 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) { assert_if_nil(a); a := a; radix := radix; size := size; - if err = clear_if_uninitialized(a); err != nil { return 0, err; } + clear_if_uninitialized(a) or_return; /* Radix defaults to 10. */ @@ -117,9 +112,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter We weren't given a size. Let's compute it. */ if size == -1 { - if size, err = radix_size(a, radix, zero_terminate); err != nil { - return 0, err; - } + size = radix_size(a, radix, zero_terminate) or_return; } /* @@ -256,12 +249,14 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc /* Set the integer to the default of zero. */ - if err = internal_zero(res); err != nil { return err; } + internal_zero(res) or_return; /* We'll interpret an empty string as zero. */ - if len(input) == 0 { return nil; } + if len(input) == 0 { + return nil; + } /* If the leading digit is a minus set the sign to negative. @@ -301,8 +296,8 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.alloc break; } - if err = internal_mul(res, res, DIGIT(radix)); err != nil { return err; } - if err = internal_add(res, res, DIGIT(y)); err != nil { return err; } + internal_mul(res, res, DIGIT(radix)) or_return; + internal_add(res, res, DIGIT(y)) or_return; input = input[1:]; } @@ -333,7 +328,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con assert_if_nil(a); if radix < 2 || radix > 64 { return -1, .Invalid_Argument; } - if err = clear_if_uninitialized(a); err != nil { return {}, err; } + clear_if_uninitialized(a) or_return; if internal_is_zero(a) { if zero_terminate { @@ -352,22 +347,22 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con digit = a.digit, }; - if size, err = internal_log(t, DIGIT(radix)); err != nil { return {}, err; } + size = internal_log(t, DIGIT(radix)) or_return; } else { la, k := &Int{}, &Int{}; defer internal_destroy(la, k); /* la = floor(log_2(a)) + 1 */ bit_count := internal_count_bits(a); - if err = internal_set(la, bit_count); err != nil { return {}, err; } + internal_set(la, bit_count) or_return; /* k = floor(2^29/log_2(radix)) + 1 */ lb := _log_bases; - if err = internal_set(k, lb[radix]); err != nil { return {}, err; } + internal_set(k, lb[radix]) or_return; /* n = floor((la * k) / 2^29) + 1 */ - if err = internal_mul(k, la, k); err != nil { return 0, err; } - if err = internal_shr(k, k, _RADIX_SIZE_SCALE); err != nil { return {}, err; } + internal_mul(k, la, k) or_return; + internal_shr(k, k, _RADIX_SIZE_SCALE) or_return; /* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */ /* n = n + 1 + EOS + sign */ @@ -440,8 +435,8 @@ _itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false temp, denominator := &Int{}, &Int{}; - if err = internal_copy(temp, a); err != nil { return 0, err; } - if err = internal_set(denominator, radix); err != nil { return 0, err; } + internal_copy(temp, a) or_return; + internal_set(denominator, radix) or_return; available := len(buffer); if zero_terminate { diff --git a/core/math/big/test.odin b/core/math/big/test.odin index 64d822ee1..a57625d79 100644 --- a/core/math/big/test.odin +++ b/core/math/big/test.odin @@ -49,7 +49,7 @@ PyRes :: struct { if bb.used == 1 { if err = #force_inline internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; } } else { - if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; } + if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; } } r: cstring; @@ -70,7 +70,7 @@ PyRes :: struct { if bb.used == 1 { if err = #force_inline internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; } } else { - if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; } + if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; } } r: cstring; @@ -88,7 +88,7 @@ PyRes :: struct { if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; } if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; } - if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; } + if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; } r: cstring; r, err = int_itoa_cstring(product, 16, context.temp_allocator); @@ -104,7 +104,7 @@ PyRes :: struct { defer internal_destroy(aa, square); if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; } - if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; } + if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; } r: cstring; r, err = int_itoa_cstring(square, 16, context.temp_allocator); @@ -124,7 +124,7 @@ PyRes :: struct { if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; } if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; } - if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; } + if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; } r: cstring; r, err = int_itoa_cstring(quotient, 16, context.temp_allocator); @@ -145,7 +145,7 @@ PyRes :: struct { defer internal_destroy(aa); if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; } - if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; } + if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; } #force_inline internal_zero(aa); aa.digit[0] = DIGIT(l) & _MASK; @@ -170,7 +170,7 @@ PyRes :: struct { defer internal_destroy(dest, bb); if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; } - if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; } + if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; } r: cstring; r, err = int_itoa_cstring(dest, 16, context.temp_allocator); @@ -189,7 +189,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; } - if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; } + if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); @@ -208,7 +208,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; } - if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; } + if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); @@ -227,7 +227,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; } - if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; } + if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); @@ -246,7 +246,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; } - if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; } + if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); @@ -265,7 +265,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; } - if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; } + if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); @@ -284,7 +284,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; } - if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; } + if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); @@ -303,7 +303,7 @@ PyRes :: struct { defer internal_destroy(src); if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; } - if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; } + if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; } r: cstring; r, err = int_itoa_cstring(src, 16, context.temp_allocator); From b071a07c86f39f3f37ff74dcb05266cf4cbd9540 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 17:56:24 +0100 Subject: [PATCH 05/16] Replace uses of `err != nil` with `or_return` where appropriate --- core/encoding/hxa/read.odin | 85 ++++++++++++++----------------------- 1 file changed, 32 insertions(+), 53 deletions(-) diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index 991d8f4f1..0cf58dce0 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -67,17 +67,9 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } read_name :: proc(r: ^Reader) -> (value: string, err: Read_Error) { - len: u8; - data: []byte; - len, err = read_value(r, u8); - if err != nil { - return; - } - data, err = read_array(r, byte, int(len)); - if err == nil { - value = string(data[:len]); - } - return; + len := read_value(r, u8) or_return; + data := read_array(r, byte, int(len)) or_return; + return string(data[:len]), nil; } read_meta :: proc(r: ^Reader, capacity: u32le) -> (meta_data: []Meta, err: Read_Error) { @@ -85,10 +77,9 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato count := 0; defer meta_data = meta_data[:count]; for m in &meta_data { - if m.name, err = read_name(r); err != nil { return }; + m.name = read_name(r) or_return; - type: Meta_Value_Type; - if type, err = read_value(r, Meta_Value_Type); err != nil { return } + type := read_value(r, Meta_Value_Type) or_return; if type > max(Meta_Value_Type) { if r.print_error { fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type))); @@ -96,22 +87,15 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato err = .Invalid_Data; return; } - array_length: u32le; - if array_length, err = read_value(r, u32le); err != nil { return } + array_length := read_value(r, u32le) or_return; switch type { - case .Int64: - if m.value, err = read_array(r, i64le, int(array_length)); err != nil { return } - case .Double: - if m.value, err = read_array(r, f64le, int(array_length)); err != nil { return } - case .Node: - if m.value, err = read_array(r, Node_Index, int(array_length)); err != nil { return } - case .Text: - if m.value, err = read_string(r, int(array_length)); err != nil { return } - case .Binary: - if m.value, err = read_array(r, byte, int(array_length)); err != nil { return } - case .Meta: - if m.value, err = read_meta(r, array_length); err != nil { return } + case .Int64: m.value = read_array(r, i64le, int(array_length)) or_return; + case .Double: m.value = read_array(r, f64le, int(array_length)) or_return; + case .Node: m.value = read_array(r, Node_Index, int(array_length)) or_return; + case .Text: m.value = read_string(r, int(array_length)) or_return; + case .Binary: m.value = read_array(r, byte, int(array_length)) or_return; + case .Meta: m.value = read_meta(r, array_length) or_return; } count += 1; @@ -120,16 +104,14 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } read_layer_stack :: proc(r: ^Reader, capacity: u32le) -> (layers: Layer_Stack, err: Read_Error) { - stack_count: u32le; - if stack_count, err = read_value(r, u32le); err != nil { return } + stack_count := read_value(r, u32le) or_return; layer_count := 0; layers = make(Layer_Stack, stack_count); defer layers = layers[:layer_count]; for layer in &layers { - type: Layer_Data_Type; - if layer.name, err = read_name(r); err != nil { return } - if layer.components, err = read_value(r, u8); err != nil { return } - if type, err = read_value(r, Layer_Data_Type); err != nil { return } + layer.name = read_name(r) or_return; + layer.components = read_value(r, u8) or_return; + type := read_value(r, Layer_Data_Type) or_return; if type > max(type) { if r.print_error { fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type))); @@ -140,10 +122,10 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato data_len := int(layer.components) * int(capacity); switch type { - case .Uint8: if layer.data, err = read_array(r, u8, data_len); err != nil { return } - case .Int32: if layer.data, err = read_array(r, i32le, data_len); err != nil { return } - case .Float: if layer.data, err = read_array(r, f32le, data_len); err != nil { return } - case .Double: if layer.data, err = read_array(r, f64le, data_len); err != nil { return } + case .Uint8: layer.data = read_array(r, u8, data_len) or_return; + case .Int32: layer.data = read_array(r, i32le, data_len) or_return; + case .Float: layer.data = read_array(r, f32le, data_len) or_return; + case .Double: layer.data = read_array(r, f64le, data_len) or_return; } layer_count += 1; } @@ -177,8 +159,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato for node_idx in 0.. max(Node_Type) { if r.print_error { fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type))); @@ -188,9 +169,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } node_count += 1; - meta_data_count: u32le; - if meta_data_count, err = read_value(r, u32le); err != nil { return } - if node.meta_data, err = read_meta(r, meta_data_count); err != nil { return } + node.meta_data = read_meta(r, read_value(r, u32le) or_return) or_return; switch type { case .Meta_Only: @@ -198,35 +177,35 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato case .Geometry: g: Node_Geometry; - if g.vertex_count, err = read_value(r, u32le); err != nil { return } - if g.vertex_stack, err = read_layer_stack(r, g.vertex_count); err != nil { return } - if g.edge_corner_count, err = read_value(r, u32le); err != nil { return } - if g.corner_stack, err = read_layer_stack(r, g.edge_corner_count); err != nil { return } + g.vertex_count = read_value(r, u32le) or_return; + g.vertex_stack = read_layer_stack(r, g.vertex_count) or_return; + g.edge_corner_count = read_value(r, u32le) or_return; + g.corner_stack = read_layer_stack(r, g.edge_corner_count) or_return; if header.version > 2 { - if g.edge_stack, err = read_layer_stack(r, g.edge_corner_count); err != nil { return } + g.edge_stack = read_layer_stack(r, g.edge_corner_count) or_return; } - if g.face_count, err = read_value(r, u32le); err != nil { return } - if g.face_stack, err = read_layer_stack(r, g.face_count); err != nil { return } + g.face_count = read_value(r, u32le) or_return; + g.face_stack = read_layer_stack(r, g.face_count) or_return; node.content = g; case .Image: img: Node_Image; - if img.type, err = read_value(r, Image_Type); err != nil { return } + img.type = read_value(r, Image_Type) or_return; dimensions := int(img.type); if img.type == .Image_Cube { dimensions = 2; } img.resolution = {1, 1, 1}; for d in 0.. Date: Sun, 15 Aug 2021 18:13:56 +0100 Subject: [PATCH 06/16] Add more uses of `or_return` --- core/bufio/writer.odin | 4 +- core/compress/zlib/zlib.odin | 77 ++++++------------------ core/encoding/csv/writer.odin | 41 +++---------- core/image/png/png.odin | 39 +++--------- core/path/filepath/match.odin | 5 +- core/sync/sync2/primitives_pthreads.odin | 2 +- 6 files changed, 41 insertions(+), 127 deletions(-) diff --git a/core/bufio/writer.odin b/core/bufio/writer.odin index cb6b39525..f2b33d591 100644 --- a/core/bufio/writer.odin +++ b/core/bufio/writer.odin @@ -183,9 +183,7 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) { for { if writer_available(b) == 0 { - if ferr := writer_flush(b); ferr != nil { - return n, ferr; - } + writer_flush(b) or_return; } if b.max_consecutive_empty_writes <= 0 { b.max_consecutive_empty_writes = DEFAULT_MAX_CONSECUTIVE_EMPTY_READS; diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index 0de9a6ec6..7a48d9440 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -442,24 +442,22 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f return E_General.Unknown_Compression_Method; } - cinfo := (cmf >> 4) & 0xf; - if cinfo > 7 { + if cinfo := (cmf >> 4) & 0xf; cinfo > 7 { return E_ZLIB.Unsupported_Window_Size; } flg, _ := compress.read_u8(ctx); - fcheck := flg & 0x1f; + fcheck := flg & 0x1f; fcheck_computed := (cmf << 8 | flg) & 0x1f; if fcheck != fcheck_computed { return E_General.Checksum_Failed; } - fdict := (flg >> 5) & 1; /* We don't handle built-in dictionaries for now. They're application specific and PNG doesn't use them. */ - if fdict != 0 { + if fdict := (flg >> 5) & 1; fdict != 0 { return E_ZLIB.FDICT_Unsupported; } @@ -473,10 +471,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f } // Parse ZLIB stream without header. - err = inflate_raw(z=ctx, expected_output_size=expected_output_size); - if err != nil { - return err; - } + inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return; if !raw { compress.discard_to_next_byte_lsb(ctx); @@ -527,23 +522,14 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all z_repeat: ^Huffman_Table; z_offset: ^Huffman_Table; codelength_ht: ^Huffman_Table; - - z_repeat, err = allocate_huffman_table(allocator=context.allocator); - if err != nil { - return err; - } - z_offset, err = allocate_huffman_table(allocator=context.allocator); - if err != nil { - return err; - } - codelength_ht, err = allocate_huffman_table(allocator=context.allocator); - if err != nil { - return err; - } defer free(z_repeat); defer free(z_offset); defer free(codelength_ht); + z_repeat = allocate_huffman_table(allocator=context.allocator) or_return; + z_offset = allocate_huffman_table(allocator=context.allocator) or_return; + codelength_ht = allocate_huffman_table(allocator=context.allocator) or_return; + final := u32(0); type := u32(0); @@ -560,8 +546,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all // Discard bits until next byte boundary compress.discard_to_next_byte_lsb(z); - uncompressed_len := i16(compress.read_bits_lsb(z, 16)); - length_check := i16(compress.read_bits_lsb(z, 16)); + uncompressed_len := i16(compress.read_bits_lsb(z, 16)); + length_check := i16(compress.read_bits_lsb(z, 16)); // fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check); @@ -586,14 +572,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all // log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type); if type == 1 { // Use fixed code lengths. - err = build_huffman(z_repeat, Z_FIXED_LENGTH[:]); - if err != nil { - return err; - } - err = build_huffman(z_offset, Z_FIXED_DIST[:]); - if err != nil { - return err; - } + build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return; + build_huffman(z_offset, Z_FIXED_DIST[:]) or_return; } else { lencodes: [286+32+137]u8; codelength_sizes: [19]u8; @@ -611,19 +591,13 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all s := compress.read_bits_lsb(z, 3); codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s); } - err = build_huffman(codelength_ht, codelength_sizes[:]); - if err != nil { - return err; - } + build_huffman(codelength_ht, codelength_sizes[:]) or_return; n = 0; c: u16; for n < ntot { - c, err = decode_huffman(z, codelength_ht); - if err != nil { - return err; - } + c = decode_huffman(z, codelength_ht) or_return; if c < 0 || c >= 19 { return E_Deflate.Huffman_Bad_Code_Lengths; @@ -664,21 +638,10 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all return E_Deflate.Huffman_Bad_Code_Lengths; } - err = build_huffman(z_repeat, lencodes[:hlit]); - if err != nil { - return err; - } - - err = build_huffman(z_offset, lencodes[hlit:ntot]); - if err != nil { - return err; - } - } - err = parse_huffman_block(z, z_repeat, z_offset); - // log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type); - if err != nil { - return err; + build_huffman(z_repeat, lencodes[:hlit]) or_return; + build_huffman(z_offset, lencodes[hlit:ntot]) or_return; } + parse_huffman_block(z, z_repeat, z_offset) or_return; } if final == 1 { break; @@ -698,9 +661,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e ctx.input_data = input; ctx.output = buf; - err = inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size); - - return err; + return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size); } inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) { @@ -712,4 +673,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals return inflate_raw(z=&ctx, expected_output_size=expected_output_size); } -inflate :: proc{inflate_from_context, inflate_from_byte_array}; \ No newline at end of file +inflate :: proc{inflate_from_context, inflate_from_byte_array}; \ No newline at end of file diff --git a/core/encoding/csv/writer.odin b/core/encoding/csv/writer.odin index bcb6ecc0d..2176e6781 100644 --- a/core/encoding/csv/writer.odin +++ b/core/encoding/csv/writer.odin @@ -64,21 +64,15 @@ write :: proc(w: ^Writer, record: []string) -> io.Error { field := record[field_idx]; if field_idx > 0 { - if _, err := io.write_rune(w.w, w.comma); err != nil { - return err; - } + io.write_rune(w.w, w.comma) or_return; } if !field_needs_quoting(w, field) { - if _, err := io.write_string(w.w, field); err != nil { - return err; - } + io.write_string(w.w, field) or_return; continue; } - if err := io.write_byte(w.w, '"'); err != nil { - return err; - } + io.write_byte(w.w, '"') or_return; for len(field) > 0 { i := strings.index_any(field, CHAR_SET); @@ -86,40 +80,28 @@ write :: proc(w: ^Writer, record: []string) -> io.Error { i = len(field); } - if _, err := io.write_string(w.w, field[:i]); err != nil { - return err; - } + io.write_string(w.w, field[:i]) or_return; field = field[i:]; if len(field) > 0 { switch field[0] { case '\r': if !w.use_crlf { - if err := io.write_byte(w.w, '\r'); err != nil { - return err; - } + io.write_byte(w.w, '\r') or_return; } case '\n': if w.use_crlf { - if _, err := io.write_string(w.w, "\r\n"); err != nil { - return err; - } + io.write_string(w.w, "\r\n") or_return; } else { - if err := io.write_byte(w.w, '\n'); err != nil { - return err; - } + io.write_byte(w.w, '\n') or_return; } case '"': - if _, err := io.write_string(w.w, `""`); err != nil { - return err; - } + io.write_string(w.w, `""`) or_return; } field = field[1:]; } } - if err := io.write_byte(w.w, '"'); err != nil { - return err; - } + io.write_byte(w.w, '"') or_return; } if w.use_crlf { @@ -132,10 +114,7 @@ write :: proc(w: ^Writer, record: []string) -> io.Error { // write_all writes multiple CSV records to w using write, and then flushes (if necessary). write_all :: proc(w: ^Writer, records: [][]string) -> io.Error { for record in records { - err := write(w, record); - if err != nil { - return err; - } + write(w, record) or_return; } return writer_flush(w); } diff --git a/core/image/png/png.odin b/core/image/png/png.odin index e3a36c2fe..587fa4042 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -372,8 +372,7 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont defer delete(data); if ok { - img, err = load_from_slice(data, options, allocator); - return; + return load_from_slice(data, options, allocator); } else { img = new(Image); return img, E_General.File_Not_Found; @@ -453,10 +452,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } seen_ihdr = true; - header, err = read_header(ctx); - if err != nil { - return img, err; - } + header = read_header(ctx) or_return; if .Paletted in header.color_type { // Color type 3 @@ -506,10 +502,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a return img, E_PNG.PLTE_Encountered_Unexpectedly; } - c, err = read_chunk(ctx); - if err != nil { - return img, err; - } + c = read_chunk(ctx) or_return; if c.header.length % 3 != 0 || c.header.length > 768 { return img, E_PNG.PLTE_Invalid_Length; @@ -540,10 +533,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a next := ch.type; for next == .IDAT { - c, err = read_chunk(ctx); - if err != nil { - return img, err; - } + c = read_chunk(ctx) or_return; bytes.buffer_write(&idat_b, c.data); idat_length += c.header.length; @@ -560,19 +550,13 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a } seen_idat = true; case .IEND: - c, err = read_chunk(ctx); - if err != nil { - return img, err; - } + c = read_chunk(ctx) or_return; seen_iend = true; case .bKGD: // TODO: Make sure that 16-bit bKGD + tRNS chunks return u16 instead of u16be - c, err = read_chunk(ctx); - if err != nil { - return img, err; - } + c = read_chunk(ctx) or_return; seen_bkgd = true; if .return_metadata in options { append(&info.chunks, c); @@ -604,10 +588,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a img.background = [3]u16{u16(col[0]), u16(col[1]), u16(col[2])}; } case .tRNS: - c, err = read_chunk(ctx); - if err != nil { - return img, err; - } + c = read_chunk(ctx) or_return; if .Alpha in info.header.color_type { return img, E_PNG.TRNS_Encountered_Unexpectedly; @@ -646,10 +627,8 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a return img, E_PNG.PNG_Does_Not_Adhere_to_Spec; case: // Unhandled type - c, err = read_chunk(ctx); - if err != nil { - return img, err; - } + c = read_chunk(ctx) or_return; + if .return_metadata in options { // NOTE: Chunk cata is currently allocated on the temp allocator. append(&info.chunks, c); diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index 1446ceb4d..de65a9d41 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -298,10 +298,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s for fi in fis { n := fi.name; - matched, err := match(pattern, n); - if err != nil { - return m, err; - } + matched := match(pattern, n) or_return; if matched { append(&m, join(dir, n)); } diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/sync2/primitives_pthreads.odin index 7e45e0565..d0484e09e 100644 --- a/core/sync/sync2/primitives_pthreads.odin +++ b/core/sync/sync2/primitives_pthreads.odin @@ -129,7 +129,7 @@ _Recursive_Mutex :: struct { } _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) { - tid := runtime.current_thread_id(); + tid := _current_thread_id(); if tid != m.impl.owner { mutex_lock(&m.impl.mutex); } From ac08d37ca0b2f8232669e8b2459905a6507fe9c2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 18:29:49 +0100 Subject: [PATCH 07/16] Add `or_return_operator` to examples/demo --- examples/demo/demo.odin | 104 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index eed633cd6..81bed8ce5 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1998,9 +1998,9 @@ relative_data_types :: proc() { fmt.println(rel_slice[1]); } -or_else_procedure :: proc() { +or_else_operator :: proc() { fmt.println("\n#'or_else'"); - // IMPORTANT NOTE: 'or_else' is experimental features and subject to change/removal + // IMPORTANT NOTE: 'or_else' is an experimental feature and subject to change/removal { m: map[string]int; i: int; @@ -2029,6 +2029,102 @@ or_else_procedure :: proc() { } } +or_return_operator :: proc() { + fmt.println("\n#'or_return'"); + // IMPORTANT NOTE: 'or_return' is an experimental feature and subject to change/removal + // + // The concept of 'or_return' will work by popping off the end value in a multiple + // valued expression and checking whether it was not 'nil' or 'false', and if so, + // set the end return value to value if possible. If the procedure only has one + // return value, it will do a simple return. If the procedure had multiple return + // values, 'or_return' will require that all parameters be named so that the end + // value could be assigned to by name and then an empty return could be called. + + Error :: enum { + None, + Something_Bad, + Something_Worse, + The_Worst, + Your_Mum, + }; + + caller_1 :: proc() -> Error { + return .None; + } + + caller_2 :: proc() -> (int, Error) { + return 123, .None; + } + + foo_1 :: proc() -> Error { + // This can be a common idiom in many code bases + n0, err := caller_2(); + if err != nil { + return err; + } + + // The above idiom can be transformed into the follow + n1 := caller_2() or_return; + + + // And if the expression has no other, it can be used like this + caller_1() or_return; + // which is functionally equivalen to + if err1 := caller_1(); err1 != nil { + return err1; + } + + _, _ = n0, n1; + return .None; + } + foo_2 :: proc() -> (n: int, err: Error) { + // It is more common that your procedure turns multiple values + // If 'or_return' is used within a procedure multiple parameters (2+), + // then all the parameters must be named so that the remaining parameters + // so that a bare 'return' statement can be used + + // This can be a common idiom in many code bases + x: int; + x, err = caller_2(); + if err != nil { + return; + } + + // The above idiom can be transformed + y := caller_2() or_return; + + // And if the expression has no other, it can be used like this + caller_1() or_return; + + // which is functionally equivalen to + if err1 := caller_1(); err1 != nil { + err = err1; + return; + } + + // If a the other values need to be set depending on what the end value is, + // the 'defer if' is can be used + defer if err != nil { + n = -1; + } + + // If a non-bare return is required, then a normal if is a lot clearer + // and gets around the short circuiting + if z, zerr := caller_2(); zerr != nil { + n = -z; + err = zerr; + return; + } + + n = 123; + return; + } + + foo_1(); + foo_2(); +} + + main :: proc() { when true { the_basics(); @@ -2061,7 +2157,7 @@ main :: proc() { union_maybe(); explicit_context_definition(); relative_data_types(); - or_else_procedure(); + or_else_operator(); + or_return_operator(); } } -// \ No newline at end of file From dc8cfcf92aa65ccec88293249ee8214c81e83902 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 18:36:34 +0100 Subject: [PATCH 08/16] Fix typos and improve clarity of `or_return_operator` --- examples/demo/demo.odin | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 81bed8ce5..2948f7682 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2063,13 +2063,13 @@ or_return_operator :: proc() { return err; } - // The above idiom can be transformed into the follow + // The above idiom can be transformed into the following n1 := caller_2() or_return; - // And if the expression has no other, it can be used like this + // And if the expression is 1-valued, it can be used like this caller_1() or_return; - // which is functionally equivalen to + // which is functionally equivalent to if err1 := caller_1(); err1 != nil { return err1; } @@ -2090,30 +2090,28 @@ or_return_operator :: proc() { return; } - // The above idiom can be transformed + // The above idiom can be transformed into the following y := caller_2() or_return; - // And if the expression has no other, it can be used like this + // And if the expression is 1-valued, it can be used like this caller_1() or_return; - // which is functionally equivalen to + // which is functionally equivalent to if err1 := caller_1(); err1 != nil { err = err1; return; } - // If a the other values need to be set depending on what the end value is, - // the 'defer if' is can be used - defer if err != nil { - n = -1; + // If a non-bare 'return' is required, then a normal 'if' can be used as it is + // a lot clearer to read + if z, zerr := caller_2(); zerr != nil { + return -345 * z, zerr; } - // If a non-bare return is required, then a normal if is a lot clearer - // and gets around the short circuiting - if z, zerr := caller_2(); zerr != nil { - n = -z; - err = zerr; - return; + // If the other return values need to be set depending on what the end value is, + // the 'defer if' idiom is can be used + defer if err != nil { + n = -1; } n = 123; From 1a7f508dd94671b8575ee9decabf5ec9a52777c2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 18:44:50 +0100 Subject: [PATCH 09/16] Improve comment --- examples/demo/demo.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 2948f7682..d896e4eb5 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2102,8 +2102,8 @@ or_return_operator :: proc() { return; } - // If a non-bare 'return' is required, then a normal 'if' can be used as it is - // a lot clearer to read + // If using a non-bare 'return' statement is required, setting the return values + // using the normal idiom is a better choice and clearer to read. if z, zerr := caller_2(); zerr != nil { return -345 * z, zerr; } From 3e2788afdcb3e846caea261ab04d15a19909a2ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 18:51:20 +0100 Subject: [PATCH 10/16] Add extra example to `or_return_operator` --- examples/demo/demo.odin | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index d896e4eb5..bf3620388 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2055,6 +2055,9 @@ or_return_operator :: proc() { caller_2 :: proc() -> (int, Error) { return 123, .None; } + caller_3 :: proc() -> (int, int, Error) { + return 123, 345, .None; + } foo_1 :: proc() -> Error { // This can be a common idiom in many code bases @@ -2074,7 +2077,10 @@ or_return_operator :: proc() { return err1; } - _, _ = n0, n1; + // Multiple return values still work with 'or_return' as it only + // pops off the end value in the multi-valued expression + n0, n1 = caller_3() or_return; + return .None; } foo_2 :: proc() -> (n: int, err: Error) { From 4e1c9b71f43a2cd14635b0c21e138f49dcd32045 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 19:05:55 +0100 Subject: [PATCH 11/16] Update `core:odin/*` for `or_else` and `or_return` --- core/odin/ast/ast.odin | 26 ++++--- core/odin/ast/clone.odin | 9 +-- core/odin/ast/walk.odin | 9 +-- core/odin/parser/parser.odin | 111 +++++++++++++++++------------ core/odin/printer/visit.odin | 13 ++-- core/odin/tokenizer/token.odin | 12 ++-- core/odin/tokenizer/tokenizer.odin | 2 +- 7 files changed, 105 insertions(+), 77 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index b213c4b74..9d41a0adc 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -241,15 +241,6 @@ Field_Value :: struct { value: ^Expr, } -Ternary_Expr :: struct { - using node: Expr, - cond: ^Expr, - op1: tokenizer.Token, - x: ^Expr, - op2: tokenizer.Token, - y: ^Expr, -} - Ternary_If_Expr :: struct { using node: Expr, x: ^Expr, @@ -261,13 +252,26 @@ Ternary_If_Expr :: struct { Ternary_When_Expr :: struct { using node: Expr, - x: ^Expr, + x: ^Expr, op1: tokenizer.Token, cond: ^Expr, op2: tokenizer.Token, y: ^Expr, } +Or_Else_Expr :: struct { + using node: Expr, + x: ^Expr, + token: tokenizer.Token, + y: ^Expr, +} + +Or_Return_Expr :: struct { + using node: Expr, + expr: ^Expr, + token: tokenizer.Token, +} + Type_Assertion :: struct { using node: Expr, expr: ^Expr, @@ -542,7 +546,7 @@ Field_Flag :: enum { No_Alias, C_Vararg, Auto_Cast, - In, + Any_Int, Results, Tags, diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index e9344e0b4..e80a4d05f 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -129,10 +129,6 @@ clone_node :: proc(node: ^Node) -> ^Node { case Field_Value: r.field = clone(r.field); r.value = clone(r.value); - case Ternary_Expr: - r.cond = clone(r.cond); - r.x = clone(r.x); - r.y = clone(r.y); case Ternary_If_Expr: r.x = clone(r.x); r.cond = clone(r.cond); @@ -141,6 +137,11 @@ clone_node :: proc(node: ^Node) -> ^Node { r.x = clone(r.x); r.cond = clone(r.cond); r.y = clone(r.y); + case Or_Else_Expr: + r.x = clone(r.x); + r.y = clone(r.y); + case Or_Return_Expr: + r.expr = clone(r.expr); case Type_Assertion: r.expr = clone(r.expr); r.type = clone(r.type); diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index 9f60b7e7d..c64d4d29c 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -126,10 +126,6 @@ walk :: proc(v: ^Visitor, node: ^Node) { case Field_Value: walk(v, n.field); walk(v, n.value); - case Ternary_Expr: - walk(v, n.cond); - walk(v, n.x); - walk(v, n.y); case Ternary_If_Expr: walk(v, n.x); walk(v, n.cond); @@ -138,6 +134,11 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.x); walk(v, n.cond); walk(v, n.y); + case Or_Else_Expr: + walk(v, n.x); + walk(v, n.y); + case Or_Return_Expr: + walk(v, n.expr); case Type_Assertion: walk(v, n.expr); if n.type != nil { diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index db3d84d2b..5021ee3df 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -374,11 +374,14 @@ expect_token_after :: proc(p: ^Parser, kind: tokenizer.Token_Kind, msg: string) expect_operator :: proc(p: ^Parser) -> tokenizer.Token { prev := p.curr_tok; - if prev.kind == .If || prev.kind == .When { + #partial switch prev.kind { + case .If, .When, .Or_Else, .Or_Return: // okay - } else if !tokenizer.is_operator(prev.kind) { - g := tokenizer.token_to_string(prev); - error(p, prev.pos, "expected an operator, got '%s'", g); + case: + if !tokenizer.is_operator(prev.kind) { + g := tokenizer.token_to_string(prev); + error(p, prev.pos, "expected an operator, got '%s'", g); + } } advance_token(p); return prev; @@ -1366,9 +1369,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { stmt := parse_stmt(p); switch name { case "bounds_check": - stmt.state_flags |= {.Bounds_Check}; + stmt.state_flags += {.Bounds_Check}; case "no_bounds_check": - stmt.state_flags |= {.No_Bounds_Check}; + stmt.state_flags += {.No_Bounds_Check}; } return stmt; case "partial": @@ -1449,7 +1452,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int { #partial switch kind { - case .Question, .If, .When: + case .Question, .If, .When, .Or_Else, .Or_Return: return 1; case .Ellipsis, .Range_Half, .Range_Full: if !p.allow_range { @@ -1578,8 +1581,8 @@ Field_Prefix :: enum { Using, No_Alias, C_Vararg, - In, Auto_Cast, + Any_Int, } Field_Prefixes :: distinct bit_set[Field_Prefix]; @@ -1626,19 +1629,15 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags, } is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix { - using Field_Prefix; #partial switch p.curr_tok.kind { case .EOF: - return Invalid; + return .Invalid; case .Using: advance_token(p); - return Using; - case .In: - advance_token(p); - return In; + return .Using; case .Auto_Cast: advance_token(p); - return Auto_Cast; + return .Auto_Cast; case .Hash: advance_token(p); defer advance_token(p); @@ -1646,14 +1645,16 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix { case .Ident: switch p.curr_tok.text { case "no_alias": - return No_Alias; + return .No_Alias; case "c_vararg": - return C_Vararg; + return .C_Vararg; + case "any_int": + return .Any_Int; } } - return Unknown; + return .Unknown; } - return Invalid; + return .Invalid; } parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags { @@ -1677,24 +1678,23 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags { for kind in Field_Prefix { count := counts[kind]; - using Field_Prefix; switch kind { - case Invalid, Unknown: // Ignore - case Using: + case .Invalid, .Unknown: // Ignore + case .Using: if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list"); } - if count > 0 { flags |= {.Using}; } - case No_Alias: + if count > 0 { flags += {.Using}; } + case .No_Alias: if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list"); } - if count > 0 { flags |= {.No_Alias}; } - case C_Vararg: + if count > 0 { flags += {.No_Alias}; } + case .C_Vararg: if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list"); } - if count > 0 { flags |= {.C_Vararg}; } - case In: - if count > 1 { error(p, p.curr_tok.pos, "multiple 'in' in this field list"); } - if count > 0 { flags |= {.In}; } - case Auto_Cast: + if count > 0 { flags += {.C_Vararg}; } + case .Auto_Cast: if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list"); } - if count > 0 { flags |= {.Auto_Cast}; } + if count > 0 { flags += {.Auto_Cast}; } + case .Any_Int: + if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list"); } + if count > 0 { flags += {.Any_Int}; } } } @@ -1705,7 +1705,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se flags = set_flags; if name_count > 1 && .Using in flags { error(p, p.curr_tok.pos, "cannot apply 'using' to more than one of the same type"); - flags &~= {.Using}; + flags -= {.Using}; } for flag in ast.Field_Flag { @@ -1719,12 +1719,12 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list"); case .Auto_Cast: error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list"); - case .In: - error(p, p.curr_tok.pos, "'in' is not allowed within this field list"); + case .Any_Int: + error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list"); case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token: panic("Impossible prefixes"); } - flags &~= {flag}; + flags -= {flag}; } } @@ -2062,10 +2062,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { ident := expect_token(p, .Ident); switch ident.text { - case "bounds_check": tags |= {.Bounds_Check}; - case "no_bounds_check": tags |= {.No_Bounds_Check}; - case "optional_ok": tags |= {.Optional_Ok}; - case "optional_second": tags |= {.Optional_Second}; + case "bounds_check": tags += {.Bounds_Check}; + case "no_bounds_check": tags += {.No_Bounds_Check}; + case "optional_ok": tags += {.Optional_Ok}; + case "optional_second": tags += {.Optional_Second}; case: } } @@ -2267,12 +2267,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { switch name.text { case "bounds_check": - operand.state_flags |= {.Bounds_Check}; + operand.state_flags += {.Bounds_Check}; if .No_Bounds_Check in operand.state_flags { error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together"); } case "no_bounds_check": - operand.state_flags |= {.No_Bounds_Check}; + operand.state_flags += {.No_Bounds_Check}; if .Bounds_Check in operand.state_flags { error(p, name.pos, "#bounds_check and #no_bounds_check cannot be applied together"); } @@ -3156,16 +3156,18 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr { } for prec := token_precedence(p, p.curr_tok.kind); prec >= prec_in; prec -= 1 { - for { + loop: for { op := p.curr_tok; op_prec := token_precedence(p, op.kind); if op_prec != prec { - break; + break loop; } - if op.kind == .If || op.kind == .When { + + #partial switch op.kind { + case .If, .When, .Or_Return, .Or_Else: if p.prev_tok.pos.line < op.pos.line { // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition - break; + break loop; } } @@ -3178,7 +3180,7 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr { x := parse_expr(p, lhs); colon := expect_token(p, .Colon); y := parse_expr(p, lhs); - te := ast.new(ast.Ternary_Expr, expr.pos, end_pos(p.prev_tok)); + te := ast.new(ast.Ternary_If_Expr, expr.pos, end_pos(p.prev_tok)); te.cond = cond; te.op1 = op; te.x = x; @@ -3212,6 +3214,21 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr { te.y = y; expr = te; + case .Or_Else: + x := expr; + y := parse_expr(p, lhs); + oe := ast.new(ast.Or_Else_Expr, expr.pos, end_pos(p.prev_tok)); + oe.x = x; + oe.token = op; + oe.y = y; + + expr = oe; + case .Or_Return: + oe := ast.new(ast.Or_Return_Expr, expr.pos, end_pos(p.prev_tok)); + oe.expr = expr; + oe.token = op; + + expr = oe; case: right := parse_binary_expr(p, false, prec+1); if right == nil { diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 3eab3b4b3..a6c3d9106 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -944,12 +944,6 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { case Auto_Cast: push_generic_token(p, v.op.kind, 1); visit_expr(p, v.expr); - case Ternary_Expr: - visit_expr(p, v.cond); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.x); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); case Ternary_If_Expr: visit_expr(p, v.x); push_generic_token(p, v.op1.kind, 1); @@ -962,6 +956,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_expr(p, v.cond); push_generic_token(p, v.op2.kind, 1); visit_expr(p, v.y); + case Or_Else_Expr: + visit_expr(p, v.x); + push_generic_token(p, v.token.kind, 1); + visit_expr(p, v.y); + case Or_Return_Expr: + visit_expr(p, v.expr); + push_generic_token(p, v.token.kind, 1); case Selector_Call_Expr: visit_expr(p, v.call.expr); push_generic_token(p, .Open_Paren, 1); diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin index 61aa351dd..5283ab590 100644 --- a/core/odin/tokenizer/token.odin +++ b/core/odin/tokenizer/token.odin @@ -144,10 +144,12 @@ Token_Kind :: enum u32 { Transmute, // transmute Distinct, // distinct Using, // using + Context, // context + Or_Else, // or_else + Or_Return, // or_return + Asm, // asm Inline, // inline No_Inline, // no_inline - Context, // context - Asm, // asm B_Keyword_End, COUNT, @@ -272,10 +274,12 @@ tokens := [Token_Kind.COUNT]string { "transmute", "distinct", "using", + "context", + "or_else", + "or_return", + "asm", "inline", "no_inline", - "context", - "asm", "", }; diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index f8a9c2c95..5d69cf3a9 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -724,7 +724,7 @@ scan :: proc(t: ^Tokenizer) -> Token { case .Ident, .Context, .Typeid, .Break, .Continue, .Fallthrough, .Return, .Integer, .Float, .Imag, .Rune, .String, .Undef, .Question, .Pointer, .Close_Paren, .Close_Bracket, .Close_Brace, - .Increment, .Decrement: + .Increment, .Decrement, .Or_Return: /*fallthrough*/ t.insert_semicolon = true; case: From b2097604d5a462c0c45a8c11607e7b49c9f7af68 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 23:10:52 +0100 Subject: [PATCH 12/16] Add `clone_ast` for `or_else` and `or_return` --- src/parser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index 9e684028d..c00585f37 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -187,6 +187,13 @@ Ast *clone_ast(Ast *node) { n->TernaryWhenExpr.cond = clone_ast(n->TernaryWhenExpr.cond); n->TernaryWhenExpr.y = clone_ast(n->TernaryWhenExpr.y); break; + case Ast_OrElseExpr: + n->OrElseExpr.x = clone_ast(n->OrElseExpr.x); + n->OrElseExpr.y = clone_ast(n->OrElseExpr.y); + break; + case Ast_OrReturnExpr: + n->OrReturnExpr.expr = clone_ast(n->OrReturnExpr.expr); + break; case Ast_TypeAssertion: n->TypeAssertion.expr = clone_ast(n->TypeAssertion.expr); n->TypeAssertion.type = clone_ast(n->TypeAssertion.type); From f293d7c997ea39bca7b28fdc359465e91a9aff0d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 23:11:15 +0100 Subject: [PATCH 13/16] Update package encoding/json for `or_return` --- core/encoding/json/parser.odin | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index 57b68946b..8fafdcda4 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -133,9 +133,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) { } parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) { - if err = expect_token(p, .Open_Bracket); err != .None { - return; - } + expect_token(p, .Open_Bracket) or_return; array: Array; array.allocator = p.allocator; @@ -147,11 +145,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) { } for p.curr_token.kind != .Close_Bracket { - elem, elem_err := parse_value(p); - if elem_err != .None { - err = elem_err; - return; - } + elem := parse_value(p) or_return; append(&array, elem); // Disallow trailing commas for the time being @@ -162,10 +156,7 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) { } } - if err = expect_token(p, .Close_Bracket); err != .None { - return; - } - + expect_token(p, .Close_Bracket) or_return; value = array; return; } @@ -200,9 +191,7 @@ parse_object_key :: proc(p: ^Parser) -> (key: string, err: Error) { } parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) { - if err = expect_token(p, .Open_Brace); err != .None { - return; - } + expect_token(p, .Open_Brace) or_return; obj: Object; obj.allocator = p.allocator; @@ -227,11 +216,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) { return; } - elem, elem_err := parse_value(p); - if elem_err != .None { - err = elem_err; - return; - } + elem := parse_value(p) or_return; if key in obj { err = .Duplicate_Object_Key; @@ -256,10 +241,7 @@ parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) { } } - if err = expect_token(p, .Close_Brace); err != .None { - return; - } - + expect_token(p, .Close_Brace) or_return; value = obj; return; } From 0996cc82a7e03de9217135b93be5fc3992666ee4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Aug 2021 23:17:12 +0100 Subject: [PATCH 14/16] Keep -vet happy --- examples/demo/demo.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index bf3620388..ccbfea75d 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2098,6 +2098,7 @@ or_return_operator :: proc() { // The above idiom can be transformed into the following y := caller_2() or_return; + _ = y; // And if the expression is 1-valued, it can be used like this caller_1() or_return; From 4c306a6f9958a01302cf09fdff8f7d4ff143c605 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Aug 2021 11:08:37 +0100 Subject: [PATCH 15/16] Correct `or_return` logic for debug printing and expression is not used checking --- src/check_expr.cpp | 15 +++++++++++++++ src/check_stmt.cpp | 25 +++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c4715f67e..30f44a59f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6637,6 +6637,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (x.mode == Addressing_Invalid) { o->mode = Addressing_Value; o->type = t_invalid; + o->expr = node; return Expr_Expr; } @@ -6645,6 +6646,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (y.mode == Addressing_Invalid) { o->mode = Addressing_Value; o->type = t_invalid; + o->expr = node; return Expr_Expr; } @@ -6664,6 +6666,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } o->mode = Addressing_Value; o->type = left_type; + o->expr = node; return Expr_Expr; case_end; @@ -6674,6 +6677,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (x.mode == Addressing_Invalid) { o->mode = Addressing_Value; o->type = t_invalid; + o->expr = node; return Expr_Expr; } @@ -6724,6 +6728,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } + o->expr = node; o->type = left_type; if (left_type != nullptr) { o->mode = Addressing_Value; @@ -8701,6 +8706,16 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { str = write_expr_to_string(str, te->y, shorthand); case_end; + case_ast_node(oe, OrElseExpr, node); + str = write_expr_to_string(str, oe->x, shorthand); + str = gb_string_appendc(str, " or_else "); + str = write_expr_to_string(str, oe->y, shorthand); + case_end; + + case_ast_node(oe, OrReturnExpr, node); + str = write_expr_to_string(str, oe->expr, shorthand); + str = gb_string_appendc(str, " or_return"); + case_end; case_ast_node(pe, ParenExpr, node); str = gb_string_append_rune(str, '('); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 236b5a9f5..6c5da5197 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1456,6 +1456,21 @@ bool all_operands_valid(Array const &operands) { return true; } +Ast *strip_or_return_expr(Ast *node) { + for (;;) { + if (node == nullptr) { + return node; + } + if (node->kind == Ast_OrReturnExpr) { + node = node->OrReturnExpr.expr; + } else if (node->kind == Ast_ParenExpr) { + node = node->ParenExpr.expr; + } else { + return node; + } + } +} + void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -1480,8 +1495,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (kind == Expr_Stmt) { return; } - if (operand.expr->kind == Ast_CallExpr) { - AstCallExpr *ce = &operand.expr->CallExpr; + Ast *expr = strip_or_return_expr(operand.expr); + + if (expr->kind == Ast_CallExpr) { + AstCallExpr *ce = &expr->CallExpr; Type *t = type_of_expr(ce->proc); if (is_type_proc(t)) { if (t->Proc.require_results) { @@ -1491,8 +1508,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } } return; - } else if (operand.expr->kind == Ast_SelectorCallExpr) { - AstSelectorCallExpr *se = &operand.expr->SelectorCallExpr; + } else if (expr->kind == Ast_SelectorCallExpr) { + AstSelectorCallExpr *se = &expr->SelectorCallExpr; ast_node(ce, CallExpr, se->call); Type *t = type_of_expr(ce->proc); if (is_type_proc(t)) { From e3fef2dadef2b10342222f0314583f6f53e39ff4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Aug 2021 11:58:50 +0100 Subject: [PATCH 16/16] Improve parsing for `or_return`; allow `#force_inline foo() or_return;` --- core/math/big/helpers.odin | 36 ++++++++++++++++++------------------ core/math/big/internal.odin | 18 +++++++++--------- core/math/big/prime.odin | 2 +- core/math/big/private.odin | 8 ++++---- core/math/big/public.odin | 12 ++++++------ src/check_stmt.cpp | 15 --------------- src/parser.cpp | 27 +++++++++++++++++++++------ 7 files changed, 59 insertions(+), 59 deletions(-) diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 92fce3c52..ab686b914 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -42,7 +42,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator : Check that `src` is usable and `dest` isn't immutable. */ assert_if_nil(dest); - (#force_inline internal_error_if_immutable(dest)) or_return; + #force_inline internal_error_if_immutable(dest) or_return; return #force_inline internal_int_set_from_integer(dest, src, minimize); } @@ -64,8 +64,8 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca assert_if_nil(dest, src); context.allocator = allocator; - (#force_inline internal_clear_if_uninitialized(src)) or_return; - (#force_inline internal_error_if_immutable(dest)) or_return; + #force_inline internal_clear_if_uninitialized(src) or_return; + #force_inline internal_error_if_immutable(dest) or_return; return #force_inline internal_int_copy(dest, src, minimize); } @@ -92,8 +92,8 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) assert_if_nil(dest, src); context.allocator = allocator; - (#force_inline internal_clear_if_uninitialized(src)) or_return; - (#force_inline internal_error_if_immutable(dest)) or_return; + #force_inline internal_clear_if_uninitialized(src) or_return; + #force_inline internal_error_if_immutable(dest) or_return; return #force_inline internal_int_abs(dest, src); } @@ -113,8 +113,8 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) assert_if_nil(dest, src); context.allocator = allocator; - (#force_inline internal_clear_if_uninitialized(src)) or_return; - (#force_inline internal_error_if_immutable(dest)) or_return; + #force_inline internal_clear_if_uninitialized(src) or_return; + #force_inline internal_error_if_immutable(dest) or_return; return #force_inline internal_int_neg(dest, src); } @@ -134,7 +134,7 @@ int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.a assert_if_nil(a); context.allocator = allocator; - (#force_inline internal_clear_if_uninitialized(a)) or_return; + #force_inline internal_clear_if_uninitialized(a) or_return; return #force_inline internal_int_bitfield_extract(a, offset, count); } @@ -148,7 +148,7 @@ shrink :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); context.allocator = allocator; - (#force_inline internal_clear_if_uninitialized(a)) or_return; + #force_inline internal_clear_if_uninitialized(a) or_return; return #force_inline internal_shrink(a); } @@ -305,7 +305,7 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T, Check that `a` is usable. */ assert_if_nil(a); - (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + #force_inline internal_clear_if_uninitialized(a, allocator) or_return; return #force_inline internal_int_get(a, T); } get :: proc { int_get, }; @@ -315,7 +315,7 @@ int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err Check that `a` is usable. */ assert_if_nil(a); - (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + #force_inline internal_clear_if_uninitialized(a, allocator) or_return; return #force_inline internal_int_get_float(a); } @@ -327,7 +327,7 @@ count_bits :: proc(a: ^Int, allocator := context.allocator) -> (count: int, err: Check that `a` is usable. */ assert_if_nil(a); - (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + #force_inline internal_clear_if_uninitialized(a, allocator) or_return; return #force_inline internal_count_bits(a), nil; } @@ -340,7 +340,7 @@ int_count_lsb :: proc(a: ^Int, allocator := context.allocator) -> (count: int, e Check that `a` is usable. */ assert_if_nil(a); - (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + #force_inline internal_clear_if_uninitialized(a, allocator) or_return; return #force_inline internal_int_count_lsb(a); } @@ -398,7 +398,7 @@ clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocato assert_if_nil(..args); for i in &args { - (#force_inline internal_clear_if_uninitialized_single(i, allocator)) or_return; + #force_inline internal_clear_if_uninitialized_single(i, allocator) or_return; } return err; } @@ -425,7 +425,7 @@ int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err integers := integers; for a in &integers { - (#force_inline internal_clear(a, true, allocator)) or_return; + #force_inline internal_clear(a, true, allocator) or_return; } return nil; } @@ -440,7 +440,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator Check that `src` is usable and `dest` isn't immutable. */ assert_if_nil(dest, src); - (#force_inline internal_clear_if_uninitialized(src)) or_return; + #force_inline internal_clear_if_uninitialized(src) or_return; digits = min(digits, len(src.digit), len(dest.digit)); return #force_inline internal_copy_digits(dest, src, digits); @@ -454,7 +454,7 @@ copy_digits :: proc(dest, src: ^Int, digits: int, allocator := context.allocator */ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) { assert_if_nil(a); - (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + #force_inline internal_clear_if_uninitialized(a, allocator) or_return; for a.used > 0 && a.digit[a.used - 1] == 0 { a.used -= 1; @@ -472,7 +472,7 @@ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) { */ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) { assert_if_nil(a); - (#force_inline internal_clear_if_uninitialized(a, allocator)) or_return; + #force_inline internal_clear_if_uninitialized(a, allocator) or_return; size_in_bits := internal_count_bits(a); diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index e23c484b2..2c988f91e 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -852,7 +852,7 @@ internal_div :: proc { internal_int_div, }; Asssumes quotient, numerator and denominator to have been initialized and not to be nil. */ internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) { - (#force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator)) or_return; + #force_inline internal_int_divmod(nil, remainder, numerator, denominator, allocator) or_return; if remainder.used == 0 || denominator.sign == remainder.sign { return nil; } @@ -864,7 +864,7 @@ internal_mod :: proc{ internal_int_mod, }; remainder = (number + addend) % modulus. */ internal_int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - (#force_inline internal_add(remainder, number, addend, allocator)) or_return; + #force_inline internal_add(remainder, number, addend, allocator) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_addmod :: proc { internal_int_addmod, }; @@ -873,7 +873,7 @@ internal_addmod :: proc { internal_int_addmod, }; remainder = (number - decrease) % modulus. */ internal_int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - (#force_inline internal_sub(remainder, number, decrease, allocator)) or_return; + #force_inline internal_sub(remainder, number, decrease, allocator) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_submod :: proc { internal_int_submod, }; @@ -882,7 +882,7 @@ internal_submod :: proc { internal_int_submod, }; remainder = (number * multiplicand) % modulus. */ internal_int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - (#force_inline internal_mul(remainder, number, multiplicand, allocator)) or_return; + #force_inline internal_mul(remainder, number, multiplicand, allocator) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_mulmod :: proc { internal_int_mulmod, }; @@ -891,7 +891,7 @@ internal_mulmod :: proc { internal_int_mulmod, }; remainder = (number * number) % modulus. */ internal_int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) { - (#force_inline internal_sqr(remainder, number, allocator)) or_return; + #force_inline internal_sqr(remainder, number, allocator) or_return; return #force_inline internal_mod(remainder, remainder, modulus, allocator); } internal_sqrmod :: proc { internal_int_sqrmod, }; @@ -914,7 +914,7 @@ internal_int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator return #force_inline internal_set(res, _factorial_table[n]); } - (#force_inline internal_set(res, _factorial_table[i - 1])) or_return; + #force_inline internal_set(res, _factorial_table[i - 1]) or_return; for { if err = #force_inline internal_mul(res, res, DIGIT(i)); err != nil || i == n { return err; @@ -1629,7 +1629,7 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al internal_set :: proc { internal_int_set_from_integer, internal_int_copy }; internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int) -> (err: Error) { - (#force_inline internal_error_if_immutable(dest)) or_return; + #force_inline internal_error_if_immutable(dest) or_return; /* If dest == src, do nothing @@ -2436,7 +2436,7 @@ internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context /* Resize `quotient` to accomodate extra digits. */ - (#force_inline internal_grow(quotient, quotient.used + digits)) or_return; + #force_inline internal_grow(quotient, quotient.used + digits) or_return; /* Increment the used by the shift amount then copy upwards. @@ -2534,7 +2534,7 @@ internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator : digits += 1; } - (#force_inline internal_grow(dest, digits)) or_return; + #force_inline internal_grow(dest, digits) or_return; for i := 0; i < digits; i += 1 { dest.digit[i] = int_random_digit(r) & _MASK; diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index 90eb2e4f7..b022870a6 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -22,7 +22,7 @@ int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res: internal_clear_if_uninitialized(a) or_return; for prime in _private_prime_table { - rem := (#force_inline int_mod_digit(a, prime)) or_return; + rem := #force_inline int_mod_digit(a, prime) or_return; if rem == 0 { return true, nil; } diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 14c2464d0..a99d6119f 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -1268,17 +1268,17 @@ _private_int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) - } low = high; - (#force_inline internal_copy(bracket_low, bracket_high)) or_return; + #force_inline internal_copy(bracket_low, bracket_high) or_return; high <<= 1; - (#force_inline internal_sqr(bracket_high, bracket_high)) or_return; + #force_inline internal_sqr(bracket_high, bracket_high) or_return; } for (high - low) > 1 { mid := (high + low) >> 1; - (#force_inline internal_pow(t, bi_base, mid - low)) or_return; + #force_inline internal_pow(t, bi_base, mid - low) or_return; - (#force_inline internal_mul(bracket_mid, bracket_low, t)) or_return; + #force_inline internal_mul(bracket_mid, bracket_low, t) or_return; mc := #force_inline internal_cmp(a, bracket_mid); switch mc { diff --git a/core/math/big/public.odin b/core/math/big/public.odin index edcee106d..7804978a5 100644 --- a/core/math/big/public.odin +++ b/core/math/big/public.odin @@ -196,7 +196,7 @@ int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator : internal_clear_if_uninitialized(numerator) or_return; - _ = (#force_inline internal_divmod(quotient, numerator, denominator)) or_return; + _ = #force_inline internal_divmod(quotient, numerator, denominator) or_return; return; } div :: proc { int_div, int_div_digit, }; @@ -311,12 +311,12 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) - n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{}; defer internal_destroy(n_fac, k_fac, n_minus_k_fac); - (#force_inline internal_int_factorial(n_minus_k_fac, n - k)) or_return; - (#force_inline internal_int_factorial(k_fac, k)) or_return; - (#force_inline internal_mul(k_fac, k_fac, n_minus_k_fac)) or_return; + #force_inline internal_int_factorial(n_minus_k_fac, n - k) or_return; + #force_inline internal_int_factorial(k_fac, k) or_return; + #force_inline internal_mul(k_fac, k_fac, n_minus_k_fac) or_return; - (#force_inline internal_int_factorial(n_fac, n)) or_return; - (#force_inline internal_div(res, n_fac, k_fac)) or_return; + #force_inline internal_int_factorial(n_fac, n) or_return; + #force_inline internal_div(res, n_fac, k_fac) or_return; return; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6c5da5197..504c23d53 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1456,21 +1456,6 @@ bool all_operands_valid(Array const &operands) { return true; } -Ast *strip_or_return_expr(Ast *node) { - for (;;) { - if (node == nullptr) { - return node; - } - if (node->kind == Ast_OrReturnExpr) { - node = node->OrReturnExpr.expr; - } else if (node->kind == Ast_ParenExpr) { - node = node->ParenExpr.expr; - } else { - return node; - } - } -} - void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { diff --git a/src/parser.cpp b/src/parser.cpp index c00585f37..8f3ffb8cc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1698,6 +1698,22 @@ Ast *unselector_expr(Ast *node) { return node; } +Ast *strip_or_return_expr(Ast *node) { + for (;;) { + if (node == nullptr) { + return node; + } + if (node->kind == Ast_OrReturnExpr) { + node = node->OrReturnExpr.expr; + } else if (node->kind == Ast_ParenExpr) { + node = node->ParenExpr.expr; + } else { + return node; + } + } +} + + Ast *parse_value(AstFile *f); Array parse_element_list(AstFile *f) { @@ -1916,7 +1932,7 @@ bool ast_on_same_line(Ast *x, Ast *y) { Ast *parse_force_inlining_operand(AstFile *f, Token token) { Ast *expr = parse_unary_expr(f, false); - Ast *e = unparen_expr(expr); + Ast *e = strip_or_return_expr(expr); if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) { syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind])); return ast_bad_expr(f, token, f->curr_token); @@ -2801,6 +2817,10 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) { operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer)); break; + case Token_or_return: + operand = ast_or_return_expr(f, operand, expect_token(f, Token_or_return)); + break; + case Token_OpenBrace: if (!lhs && is_literal_type(operand) && f->expr_level >= 0) { operand = parse_literal_value(f, operand); @@ -2895,7 +2915,6 @@ i32 token_precedence(AstFile *f, TokenKind t) { case Token_if: case Token_when: case Token_or_else: - case Token_or_return: return 1; case Token_Ellipsis: case Token_RangeFull: @@ -2954,8 +2973,6 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { switch (op.kind) { case Token_if: case Token_when: - case Token_or_else: - case Token_or_return: if (prev.pos.line < op.pos.line) { // NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition goto loop_end; @@ -2989,8 +3006,6 @@ Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) { Ast *x = expr; Ast *y = parse_expr(f, lhs); expr = ast_or_else_expr(f, x, op, y); - } else if (op.kind == Token_or_return) { - expr = ast_or_return_expr(f, expr, op); } else { Ast *right = parse_binary_expr(f, false, prec+1); if (right == nullptr) {