From: Brendan Hansen Date: Tue, 27 Sep 2022 14:37:34 +0000 (-0500) Subject: added '#deprecated'; revamped error/warning system X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=27ff791dc1cd90d479243c8504b6f6f84ad43efd;p=onyx.git added '#deprecated'; revamped error/warning system --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 66f0a2b7..f52e2f00 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1251,6 +1251,8 @@ struct AstFunction { bh_arr(AstTyped *) tags; + AstStrLit *deprecated_warning; + // Polymorphic procedures use the following fields Scope *parent_scope_of_poly_proc; bh_arr(AstPolyParam) poly_params; diff --git a/compiler/include/errors.h b/compiler/include/errors.h index 9df95def..c9420d46 100644 --- a/compiler/include/errors.h +++ b/compiler/include/errors.h @@ -33,6 +33,8 @@ typedef struct OnyxErrors { extern OnyxErrors msgs; void onyx_errors_init(bh_arr(bh_file_contents)* files); +void onyx_errors_enable(); +void onyx_errors_disable(); void onyx_submit_error(OnyxError error); void onyx_report_error(OnyxFilePos pos, OnyxErrorRank rank, char * format, ...); void onyx_submit_warning(OnyxError error); diff --git a/compiler/src/checker.c b/compiler/src/checker.c index ddc3977b..e184f08b 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -761,6 +761,13 @@ CheckStatus check_call(AstCall** pcall) { return Check_Return_To_Symres; } + if (callee->kind == Ast_Kind_Function && callee->deprecated_warning) { + onyx_report_warning(callee->token->pos, "Calling a deprecated function: %b", + callee->deprecated_warning->token->text, callee->deprecated_warning->token->length); + + onyx_report_warning(call->token->pos, "Here is where the deprecated function was called."); + } + return Check_Success; } @@ -1758,7 +1765,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { // constraints relay on Check_Error being returned, not Check_Yield_Macro. For // this reason, I have to produce an error at the last minute, BEFORE the loop // enters a cycle detected state, when there is no point of return. - if (!context.cycle_almost_detected) { + if (!context.cycle_almost_detected && !context.cycle_detected) { // Skipping the slightly expensive symbol lookup // below by not using YIELD_ERROR. return Check_Yield_Macro; @@ -2430,15 +2437,14 @@ CheckStatus check_struct_defaults(AstStructType* s_node) { } CheckStatus check_temp_function_header(AstFunction* func) { - CheckStatus cs = check_function_header(func); - if (cs == Check_Error) { - if (func->flags & Ast_Flag_Header_Check_No_Error) { - onyx_clear_errors(); - } - - return Check_Failed; + if (func->flags & Ast_Flag_Header_Check_No_Error) { + onyx_errors_disable(); } + CheckStatus cs = check_function_header(func); + onyx_errors_enable(); + + if (cs == Check_Error) return Check_Failed; if (cs != Check_Success) return cs; return Check_Complete; @@ -2543,6 +2549,13 @@ CheckStatus check_function_header(AstFunction* func) { if (func->return_type != NULL) CHECK(type, &func->return_type); + if (func->deprecated_warning) { + CHECK(expression, (AstTyped **) &func->deprecated_warning); + if (func->deprecated_warning->kind != Ast_Kind_StrLit) { + ERROR(func->token->pos, "Expected deprecation warning to be a string literal."); + } + } + func->type = type_build_function_type(context.ast_alloc, func); if (func->type == NULL) YIELD(func->token->pos, "Waiting for function type to be constructed"); @@ -2878,12 +2891,14 @@ CheckStatus check_constraint(AstConstraint *constraint) { } case Constraint_Phase_Checking_Expressions: { + onyx_errors_disable(); + fori (i, constraint->expr_idx, bh_arr_length(constraint->exprs)) { InterfaceConstraint* ic = &constraint->exprs[i]; CheckStatus cs = check_expression(&ic->expr); if (cs == Check_Return_To_Symres || cs == Check_Yield_Macro) { - onyx_clear_errors(); + onyx_errors_enable(); return cs; } @@ -2898,6 +2913,7 @@ CheckStatus check_constraint(AstConstraint *constraint) { if (ic->expected_type_expr) { cs = check_type(&ic->expected_type_expr); if (cs == Check_Return_To_Symres || cs == Check_Yield_Macro) { + onyx_errors_enable(); return cs; } @@ -2923,6 +2939,7 @@ CheckStatus check_constraint(AstConstraint *constraint) { ic->expected_type = type_lookup_by_id(ic->expected_type_expr->type_id); } else { + onyx_errors_enable(); YIELD(ic->expected_type_expr->token->pos, "Waiting on expected type expression to be resolved."); } } @@ -2937,19 +2954,19 @@ CheckStatus check_constraint(AstConstraint *constraint) { continue; constraint_error: - // HACK HACK HACK - onyx_clear_errors(); + onyx_errors_enable(); *constraint->report_status = Constraint_Check_Status_Failed; return Check_Failed; } // HACK HACK HACK - onyx_clear_errors(); + onyx_errors_enable(); *constraint->report_status = Constraint_Check_Status_Success; return Check_Complete; } } + onyx_errors_enable(); return Check_Success; } diff --git a/compiler/src/errors.c b/compiler/src/errors.c index f6811ca6..35731588 100644 --- a/compiler/src/errors.c +++ b/compiler/src/errors.c @@ -2,6 +2,7 @@ #include "utils.h" OnyxErrors errors; +static b32 errors_enabled = 1; void onyx_errors_init(bh_arr(bh_file_contents)* files) { errors.file_contents = files; @@ -84,8 +85,25 @@ void onyx_errors_print() { } } +void onyx_errors_enable() { + errors_enabled = 1; +} + +void onyx_errors_disable() { + if (context.cycle_detected) { + errors_enabled = 1; + return; + } + + errors_enabled = 0; +} + b32 onyx_has_errors() { - return bh_arr_length(errors.errors) > 0; + bh_arr_each(OnyxError, err, errors.errors) { + if (err->rank >= Error_Waiting_On) return 1; + } + + return 0; } void onyx_clear_errors() { @@ -95,10 +113,13 @@ void onyx_clear_errors() { } void onyx_submit_error(OnyxError error) { + if (!errors_enabled) return; + bh_arr_push(errors.errors, error); } void onyx_report_error(OnyxFilePos pos, OnyxErrorRank rank, char * format, ...) { + if (!errors_enabled) return; va_list vargs; va_start(vargs, format); @@ -115,6 +136,8 @@ void onyx_report_error(OnyxFilePos pos, OnyxErrorRank rank, char * format, ...) } void onyx_submit_warning(OnyxError error) { + if (!errors_enabled) return; + bh_file_contents file_contents = { 0 }; bh_arr_each(bh_file_contents, fc, *errors.file_contents) { if (!strcmp(fc->filename, error.pos.filename)) { @@ -128,6 +151,8 @@ void onyx_submit_warning(OnyxError error) { // This definitely doesn't do what I thought it did? void onyx_report_warning(OnyxFilePos pos, char* format, ...) { + if (!errors_enabled) return; + va_list vargs; va_start(vargs, format); char* msg = bh_bprintf_va(format, vargs); @@ -136,7 +161,7 @@ void onyx_report_warning(OnyxFilePos pos, char* format, ...) { OnyxError err = { .pos = pos, .rank = Error_Warning, - .text = msg, + .text = bh_strdup(errors.msg_alloc, msg), }; bh_arr_push(errors.errors, err); diff --git a/compiler/src/onyx.c b/compiler/src/onyx.c index 0f3790ba..628adfb4 100644 --- a/compiler/src/onyx.c +++ b/compiler/src/onyx.c @@ -609,6 +609,10 @@ static i32 onyx_compile() { } #endif + // Mostly a preventative thing to ensure that even if somehow + // errors were left disabled, they are re-enabled in this cycle. + onyx_errors_enable(); + entity_heap_remove_top(&context.entities); b32 changed = process_entity(ent); @@ -656,6 +660,7 @@ static i32 onyx_compile() { entity_heap_insert_existing(&context.entities, ent); } + onyx_errors_print(); u64 duration = bh_time_duration(start_time); if (context.options->verbose_output > 0) { @@ -798,7 +803,6 @@ int main(int argc, char *argv[]) { switch (compiler_progress) { case ONYX_COMPILER_PROGRESS_ERROR: - onyx_errors_print(); break; case ONYX_COMPILER_PROGRESS_FAILED_OUTPUT: diff --git a/compiler/src/parser.c b/compiler/src/parser.c index 7ffd0912..d5309853 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -2501,6 +2501,10 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok func_def->flags |= Ast_Flag_Proc_Is_Null; } + else if (parse_possible_directive(parser, "deprecated")) { + func_def->deprecated_warning = (AstStrLit *) parse_expression(parser, 0); + } + else { OnyxToken* directive_token = expect_token(parser, '#'); OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol); diff --git a/compiler/src/symres.c b/compiler/src/symres.c index 7042740f..81481d6b 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -1133,6 +1133,10 @@ SymresStatus symres_function_header(AstFunction* func) { SYMRES(type, &func->return_type); + if (func->deprecated_warning) { + SYMRES(expression, (AstTyped **) &func->deprecated_warning); + } + scope_leave(); return Symres_Success; @@ -1598,12 +1602,12 @@ static SymresStatus symres_polyquery(AstPolyQuery *query) { if (param->local->type_node != NULL) { resolved_a_symbol = 0; + onyx_errors_disable(); param->local->flags |= Ast_Flag_Symbol_Invisible; symres_type(¶m->local->type_node); param->local->flags &= ~Ast_Flag_Symbol_Invisible; - - onyx_clear_errors(); - + onyx_errors_enable(); + if (resolved_a_symbol) query->successful_symres = 1; } } diff --git a/core/io/reader.onyx b/core/io/reader.onyx index 31c8aae4..e894bd23 100644 --- a/core/io/reader.onyx +++ b/core/io/reader.onyx @@ -24,6 +24,7 @@ Reader :: struct { greedy : bool; is_empty :: reader_empty; + empty :: reader_empty; read_all :: read_all; read_byte :: read_byte; unread_byte :: unread_byte; diff --git a/core/string.onyx b/core/string.onyx index 578f32fa..0b44023b 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -197,7 +197,11 @@ ends_with :: (s: str, suffix: str) -> bool { return true; } -is_empty :: (s: str) => s.count == 0 || s.data == null; +empty :: (s: str) => s.count == 0 || s.data == null; + +is_empty :: (s: str) -> bool #deprecated "Use 'string.empty' instead." { + s.count == 0 || s.data == null; +} index_of :: (s: str, c: u8) -> i32 { for s.count { diff --git a/core/test/testing.onyx b/core/test/testing.onyx index 6ee3e2b6..d786c13b 100644 --- a/core/test/testing.onyx +++ b/core/test/testing.onyx @@ -73,13 +73,13 @@ run_tests :: (packages: [] package_id = .[], log := true) -> bool { if failed_cases.count > 0 do printf("Failing test cases:\n"); for failed_cases { - printf("[{}]\n", it.name if !string.is_empty(it.name) else "Unnamed test"); + printf("[{}]\n", it.name if !string.empty(it.name) else "Unnamed test"); for ^ it.assertions { if it.passed do continue; printf(" {} at {}:{}\n", - it.name if !string.is_empty(it.name) else "Unnamed assertion", + it.name if !string.empty(it.name) else "Unnamed assertion", it.loc.file, it.loc.line); } } diff --git a/scripts/onyx-pkg.onyx b/scripts/onyx-pkg.onyx index 3ea34de9..926040ed 100644 --- a/scripts/onyx-pkg.onyx +++ b/scripts/onyx-pkg.onyx @@ -494,7 +494,7 @@ attempt_remove_native_library :: (package_folder: str) -> bool { result, error := parse_ini_file(^r, ^inner_config); if result != .Success do return false; - if string.is_empty(inner_config.native_library.library) do return false; + if string.empty(inner_config.native_library.library) do return false; os.remove_file(tprintf("{}/{}{}", config.config.lib_bin_directory, inner_config.native_library.library, native_library_suffix)); } @@ -528,7 +528,7 @@ run_native_library_installation :: (folder: str) -> bool { result, error := parse_ini_file(^r, ^inner_config); if result != .Success do return false; - if string.is_empty(inner_config.native_library.build_cmd) do return true; + if string.empty(inner_config.native_library.build_cmd) do return true; args := string.split(inner_config.native_library.build_cmd, #char " ", context.temp_allocator); cmd := args[0]; @@ -873,7 +873,7 @@ Config :: struct { load_config_file :: () -> bool { file_data := os.get_contents(global_arguments.config_file); - if string.is_empty(file_data) { + if string.empty(file_data) { return false; }