bh_arr(AstTyped *) tags;
+ AstStrLit *deprecated_warning;
+
// Polymorphic procedures use the following fields
Scope *parent_scope_of_poly_proc;
bh_arr(AstPolyParam) poly_params;
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);
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;
}
// 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;
}
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;
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");
}
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;
}
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;
}
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.");
}
}
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;
}
#include "utils.h"
OnyxErrors errors;
+static b32 errors_enabled = 1;
void onyx_errors_init(bh_arr(bh_file_contents)* files) {
errors.file_contents = files;
}
}
+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() {
}
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);
}
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)) {
// 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);
OnyxError err = {
.pos = pos,
.rank = Error_Warning,
- .text = msg,
+ .text = bh_strdup(errors.msg_alloc, msg),
};
bh_arr_push(errors.errors, err);
}
#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);
entity_heap_insert_existing(&context.entities, ent);
}
+ onyx_errors_print();
u64 duration = bh_time_duration(start_time);
if (context.options->verbose_output > 0) {
switch (compiler_progress) {
case ONYX_COMPILER_PROGRESS_ERROR:
- onyx_errors_print();
break;
case ONYX_COMPILER_PROGRESS_FAILED_OUTPUT:
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);
SYMRES(type, &func->return_type);
+ if (func->deprecated_warning) {
+ SYMRES(expression, (AstTyped **) &func->deprecated_warning);
+ }
+
scope_leave();
return Symres_Success;
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;
}
}
greedy : bool;
is_empty :: reader_empty;
+ empty :: reader_empty;
read_all :: read_all;
read_byte :: read_byte;
unread_byte :: unread_byte;
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 {
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);
}
}
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));
}
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];
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;
}