Message_Kind :: enum { Log; Warning; Error; Internal_Error; } Compiler_Message :: struct { message_kind : Message_Kind; message : string; path : string; source_locations : [..]Source_Range; report_source_location : bool = true; } indent :: (builder : *String_Builder, indentation : int) { for 1..indentation append(builder, " "); } newline :: (builder : *String_Builder) { append(builder, "\n"); } green :: (builder : *String_Builder) { append(builder, green()); } green :: () -> string { return "\x1b[92m"; } red :: (builder : *String_Builder) { append(builder, red()); } red :: () -> string { return "\x1b[91m"; } yellow :: (builder : *String_Builder) { append(builder, yellow()); } yellow :: () -> string { return "\x1b[93m"; } cyan :: (builder : *String_Builder) { append(builder, cyan()); } cyan :: () -> string { return "\x1b[96m"; } white :: (builder : *String_Builder) { append(builder, white()); } white :: () -> string { return "\x1b[97m"; } reset_color :: () -> string { return "\x1b[0m"; } reset_color :: (builder : *String_Builder) { append(builder, reset_color()); } add_message :: (messages : *[..]Compiler_Message, text : string, path : string, kind : Message_Kind) { message : Compiler_Message; message.message = text; message.path = path; message.report_source_location = false; message.message_kind = kind; array_add(messages, message); } log_message :: (messages : *[..]Compiler_Message, text : string, path : string) { add_message(messages, text, path, .Log); } warning_message :: (messages : *[..]Compiler_Message, text : string, path : string) { add_message(messages, text, path, .Warning); } error_message :: (messages : *[..]Compiler_Message, text : string, path : string) { add_message(messages, text, path, .Error); } internal_error_message :: (messages : *[..]Compiler_Message, text : string, path : string) { add_message(messages, text, path, .Internal_Error); } copy_messages :: (source : []Compiler_Message, dest : *[..]Compiler_Message) { for message : source { array_add(dest, message); } } report_messages :: (messages : []Compiler_Message) -> string { builder : String_Builder; init_string_builder(*builder); for message : messages { report_message(*builder, message); } return builder_to_string(*builder); } report_message :: (builder : *String_Builder, message : Compiler_Message) { report_message(builder, message.path, message.message, message.source_locations, message.message_kind, message.report_source_location); } report_message :: (builder : *String_Builder, path : string, message : string, source_locations : []Source_Range, kind : Message_Kind, report_source_location : bool = false) { append(builder, "\x1b[1;37m"); if path.count > 0 { print_to_builder(builder, "%:", path); } else { append(builder, "internal:"); } print_to_builder(builder, "%,%: ", source_locations[0].main_token.line, source_locations[0].main_token.column); if kind == .Log { append(builder, "\x1b[31mlog: "); } else if kind == .Error { append(builder, "\x1b[31merror: "); } append(builder, "\x1b[37m"); print_to_builder(builder, "%\n", message); append(builder, "\x1b[36m"); if report_source_location { for location : source_locations { append(builder, "\t"); print_from_source_location(builder, location); append(builder, "\n\t"); begin := location.begin; print_token_pointer(builder, location.main_token); append(builder, "\n"); } } append(builder, "\x1b[37m"); }