error.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. enum ErrorValueKind : u32 {
  2. ErrorValue_Error,
  3. ErrorValue_Warning,
  4. };
  5. struct ErrorValue {
  6. ErrorValueKind kind;
  7. TokenPos pos;
  8. TokenPos end;
  9. Array<String> msgs;
  10. };
  11. struct ErrorCollector {
  12. TokenPos prev;
  13. std::atomic<i64> count;
  14. std::atomic<i64> warning_count;
  15. std::atomic<bool> in_block;
  16. RecursiveMutex mutex;
  17. BlockingMutex path_mutex;
  18. Array<ErrorValue> error_values;
  19. ErrorValue curr_error_value;
  20. std::atomic<bool> curr_error_value_set;
  21. };
  22. gb_global ErrorCollector global_error_collector;
  23. gb_internal void push_error_value(TokenPos const &pos, ErrorValueKind kind = ErrorValue_Error) {
  24. GB_ASSERT(global_error_collector.curr_error_value_set.load() == false);
  25. ErrorValue ev = {kind, pos};
  26. ev.msgs.allocator = heap_allocator();
  27. global_error_collector.curr_error_value = ev;
  28. global_error_collector.curr_error_value_set.store(true);
  29. }
  30. gb_internal void pop_error_value(void) {
  31. if (global_error_collector.curr_error_value_set.load()) {
  32. array_add(&global_error_collector.error_values, global_error_collector.curr_error_value);
  33. global_error_collector.curr_error_value = {};
  34. global_error_collector.curr_error_value_set.store(false);
  35. }
  36. }
  37. gb_internal void try_pop_error_value(void) {
  38. if (!global_error_collector.in_block.load()) {
  39. pop_error_value();
  40. }
  41. }
  42. gb_internal ErrorValue *get_error_value(void) {
  43. GB_ASSERT(global_error_collector.curr_error_value_set.load() == true);
  44. return &global_error_collector.curr_error_value;
  45. }
  46. gb_internal bool any_errors(void) {
  47. return global_error_collector.count.load() != 0;
  48. }
  49. gb_internal void init_global_error_collector(void) {
  50. array_init(&global_error_collector.error_values, heap_allocator());
  51. array_init(&global_file_path_strings, heap_allocator(), 1, 4096);
  52. array_init(&global_files, heap_allocator(), 1, 4096);
  53. }
  54. gb_internal isize MAX_ERROR_COLLECTOR_COUNT(void);
  55. // temporary
  56. // defined in build_settings.cpp
  57. gb_internal char *token_pos_to_string(TokenPos const &pos);
  58. gb_internal bool set_file_path_string(i32 index, String const &path) {
  59. bool ok = false;
  60. GB_ASSERT(index >= 0);
  61. mutex_lock(&global_error_collector.path_mutex);
  62. if (index >= global_file_path_strings.count) {
  63. array_resize(&global_file_path_strings, index+1);
  64. }
  65. String prev = global_file_path_strings[index];
  66. if (prev.len == 0) {
  67. global_file_path_strings[index] = path;
  68. ok = true;
  69. }
  70. mutex_unlock(&global_error_collector.path_mutex);
  71. return ok;
  72. }
  73. gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
  74. bool ok = false;
  75. GB_ASSERT(index >= 0);
  76. mutex_lock(&global_error_collector.path_mutex);
  77. if (index >= global_files.count) {
  78. array_resize(&global_files, index+1);
  79. }
  80. AstFile *prev = global_files[index];
  81. if (prev == nullptr) {
  82. global_files[index] = file;
  83. ok = true;
  84. }
  85. mutex_unlock(&global_error_collector.path_mutex);
  86. return ok;
  87. }
  88. gb_internal String get_file_path_string(i32 index) {
  89. GB_ASSERT(index >= 0);
  90. mutex_lock(&global_error_collector.path_mutex);
  91. String path = {};
  92. if (index < global_file_path_strings.count) {
  93. path = global_file_path_strings[index];
  94. }
  95. mutex_unlock(&global_error_collector.path_mutex);
  96. return path;
  97. }
  98. gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
  99. GB_ASSERT(index >= 0);
  100. mutex_lock(&global_error_collector.path_mutex);
  101. AstFile *file = nullptr;
  102. if (index < global_files.count) {
  103. file = global_files[index];
  104. }
  105. mutex_unlock(&global_error_collector.path_mutex);
  106. return file;
  107. }
  108. // NOTE: defined in build_settings.cpp
  109. gb_internal bool global_warnings_as_errors(void);
  110. gb_internal bool global_ignore_warnings(void);
  111. gb_internal bool show_error_line(void);
  112. gb_internal bool terse_errors(void);
  113. gb_internal bool json_errors(void);
  114. gb_internal bool has_ansi_terminal_colours(void);
  115. gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset);
  116. gb_internal void warning(Token const &token, char const *fmt, ...);
  117. gb_internal void error(Token const &token, char const *fmt, ...);
  118. gb_internal void error(TokenPos pos, char const *fmt, ...);
  119. gb_internal void error_line(char const *fmt, ...);
  120. gb_internal void syntax_error(Token const &token, char const *fmt, ...);
  121. gb_internal void syntax_error(TokenPos pos, char const *fmt, ...);
  122. gb_internal void syntax_warning(Token const &token, char const *fmt, ...);
  123. gb_internal void compiler_error(char const *fmt, ...);
  124. gb_internal void print_all_errors(void);
  125. #define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va)
  126. typedef ERROR_OUT_PROC(ErrorOutProc);
  127. gb_internal ERROR_OUT_PROC(default_error_out_va) {
  128. char buf[4096] = {};
  129. isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
  130. isize n = len-1;
  131. if (n > 0) {
  132. String msg = copy_string(permanent_allocator(), {(u8 *)buf, n});
  133. ErrorValue *ev = get_error_value();
  134. array_add(&ev->msgs, msg);
  135. }
  136. }
  137. gb_global ErrorOutProc *error_out_va = default_error_out_va;
  138. gb_internal void begin_error_block(void) {
  139. mutex_lock(&global_error_collector.mutex);
  140. global_error_collector.in_block.store(true);
  141. }
  142. gb_internal void end_error_block(void) {
  143. pop_error_value();
  144. global_error_collector.in_block.store(false);
  145. mutex_unlock(&global_error_collector.mutex);
  146. }
  147. #define ERROR_BLOCK() begin_error_block(); defer (end_error_block())
  148. gb_internal void error_out(char const *fmt, ...) {
  149. va_list va;
  150. va_start(va, fmt);
  151. error_out_va(fmt, va);
  152. va_end(va);
  153. }
  154. enum TerminalStyle {
  155. TerminalStyle_Normal,
  156. TerminalStyle_Bold,
  157. TerminalStyle_Underline,
  158. };
  159. enum TerminalColour {
  160. TerminalColour_White,
  161. TerminalColour_Red,
  162. TerminalColour_Yellow,
  163. TerminalColour_Green,
  164. TerminalColour_Cyan,
  165. TerminalColour_Blue,
  166. TerminalColour_Purple,
  167. TerminalColour_Black,
  168. };
  169. gb_internal void terminal_set_colours(TerminalStyle style, TerminalColour foreground) {
  170. if (has_ansi_terminal_colours()) {
  171. char const *ss = "0";
  172. switch (style) {
  173. case TerminalStyle_Normal: ss = "0"; break;
  174. case TerminalStyle_Bold: ss = "1"; break;
  175. case TerminalStyle_Underline: ss = "4"; break;
  176. }
  177. switch (foreground) {
  178. case TerminalColour_White: error_out("\x1b[%s;37m", ss); break;
  179. case TerminalColour_Red: error_out("\x1b[%s;31m", ss); break;
  180. case TerminalColour_Yellow: error_out("\x1b[%s;33m", ss); break;
  181. case TerminalColour_Green: error_out("\x1b[%s;32m", ss); break;
  182. case TerminalColour_Cyan: error_out("\x1b[%s;36m", ss); break;
  183. case TerminalColour_Blue: error_out("\x1b[%s;34m", ss); break;
  184. case TerminalColour_Purple: error_out("\x1b[%s;35m", ss); break;
  185. case TerminalColour_Black: error_out("\x1b[%s;30m", ss); break;
  186. }
  187. }
  188. }
  189. gb_internal void terminal_reset_colours(void) {
  190. if (has_ansi_terminal_colours()) {
  191. error_out("\x1b[0m");
  192. }
  193. }
  194. gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
  195. get_error_value()->end = end;
  196. if (!show_error_line()) {
  197. return false;
  198. }
  199. i32 offset = 0;
  200. gbString the_line = get_file_line_as_string(pos, &offset);
  201. defer (gb_string_free(the_line));
  202. if (the_line != nullptr) {
  203. char const *line_text = the_line;
  204. isize line_len = gb_string_length(the_line);
  205. // TODO(bill): This assumes ASCII
  206. enum {
  207. MAX_LINE_LENGTH = 80,
  208. MAX_TAB_WIDTH = 8,
  209. ELLIPSIS_PADDING = 8, // `... ...`
  210. MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING,
  211. };
  212. error_out("\t");
  213. terminal_set_colours(TerminalStyle_Bold, TerminalColour_White);
  214. i32 error_length = gb_max(end.offset - pos.offset, 1);
  215. isize squiggle_extra = 0;
  216. if (line_len > MAX_LINE_LENGTH_PADDED) {
  217. i32 left = MAX_TAB_WIDTH;
  218. if (offset > 0) {
  219. line_text += offset-left;
  220. line_len -= offset-left;
  221. offset = left+MAX_TAB_WIDTH/2;
  222. }
  223. if (line_len > MAX_LINE_LENGTH_PADDED) {
  224. line_len = MAX_LINE_LENGTH_PADDED;
  225. if (error_length > line_len-left) {
  226. error_length = cast(i32)line_len - left;
  227. squiggle_extra = 1;
  228. }
  229. }
  230. if (offset > 0) {
  231. error_out("... %.*s ...", cast(i32)line_len, line_text);
  232. } else {
  233. error_out("%.*s ...", cast(i32)line_len, line_text);
  234. }
  235. } else {
  236. error_out("%.*s", cast(i32)line_len, line_text);
  237. }
  238. error_out("\n\t");
  239. for (i32 i = 0; i < offset; i++) {
  240. error_out(" ");
  241. }
  242. terminal_set_colours(TerminalStyle_Bold, TerminalColour_Green);
  243. error_out("^");
  244. if (end.file_id == pos.file_id) {
  245. if (end.line > pos.line) {
  246. for (i32 i = offset; i < line_len; i++) {
  247. error_out("~");
  248. }
  249. } else if (end.line == pos.line && end.column > pos.column) {
  250. for (i32 i = 1; i < error_length-1+squiggle_extra; i++) {
  251. error_out("~");
  252. }
  253. if (error_length > 1 && squiggle_extra == 0) {
  254. error_out("^");
  255. }
  256. }
  257. }
  258. terminal_reset_colours();
  259. error_out("\n");
  260. return true;
  261. }
  262. return false;
  263. }
  264. gb_internal void error_out_empty(void) {
  265. error_out("");
  266. }
  267. gb_internal void error_out_pos(TokenPos pos) {
  268. terminal_set_colours(TerminalStyle_Bold, TerminalColour_White);
  269. error_out("%s ", token_pos_to_string(pos));
  270. terminal_reset_colours();
  271. }
  272. gb_internal void error_out_coloured(char const *str, TerminalStyle style, TerminalColour foreground) {
  273. terminal_set_colours(style, foreground);
  274. error_out(str);
  275. terminal_reset_colours();
  276. }
  277. gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
  278. global_error_collector.count.fetch_add(1);
  279. if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
  280. print_all_errors();
  281. gb_exit(1);
  282. }
  283. mutex_lock(&global_error_collector.mutex);
  284. push_error_value(pos, ErrorValue_Error);
  285. // NOTE(bill): Duplicate error, skip it
  286. if (pos.line == 0) {
  287. error_out_empty();
  288. error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
  289. error_out_va(fmt, va);
  290. error_out("\n");
  291. } else if (global_error_collector.prev != pos) {
  292. global_error_collector.prev = pos;
  293. error_out_pos(pos);
  294. if (has_ansi_terminal_colours()) {
  295. error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
  296. }
  297. error_out_va(fmt, va);
  298. error_out("\n");
  299. show_error_on_line(pos, end);
  300. } else {
  301. global_error_collector.count.fetch_sub(1);
  302. }
  303. try_pop_error_value();
  304. mutex_unlock(&global_error_collector.mutex);
  305. }
  306. gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
  307. if (global_warnings_as_errors()) {
  308. error_va(pos, end, fmt, va);
  309. return;
  310. }
  311. global_error_collector.warning_count.fetch_add(1);
  312. mutex_lock(&global_error_collector.mutex);
  313. push_error_value(pos, ErrorValue_Warning);
  314. if (!global_ignore_warnings()) {
  315. // NOTE(bill): Duplicate error, skip it
  316. if (pos.line == 0) {
  317. error_out_empty();
  318. error_out_coloured("Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
  319. error_out_va(fmt, va);
  320. error_out("\n");
  321. } else if (global_error_collector.prev != pos) {
  322. global_error_collector.prev = pos;
  323. error_out_pos(pos);
  324. error_out_coloured("Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
  325. error_out_va(fmt, va);
  326. error_out("\n");
  327. show_error_on_line(pos, end);
  328. }
  329. }
  330. try_pop_error_value();
  331. mutex_unlock(&global_error_collector.mutex);
  332. }
  333. gb_internal void error_line_va(char const *fmt, va_list va) {
  334. error_out_va(fmt, va);
  335. }
  336. gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
  337. global_error_collector.count.fetch_add(1);
  338. if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) {
  339. print_all_errors();
  340. gb_exit(1);
  341. }
  342. mutex_lock(&global_error_collector.mutex);
  343. push_error_value(pos, ErrorValue_Error);
  344. // NOTE(bill): Duplicate error, skip it
  345. if (pos.line == 0) {
  346. error_out_empty();
  347. error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
  348. error_out_va(fmt, va);
  349. } else if (global_error_collector.prev != pos) {
  350. global_error_collector.prev = pos;
  351. error_out_pos(pos);
  352. if (has_ansi_terminal_colours()) {
  353. error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
  354. }
  355. error_out_va(fmt, va);
  356. }
  357. try_pop_error_value();
  358. mutex_unlock(&global_error_collector.mutex);
  359. }
  360. gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
  361. global_error_collector.count.fetch_add(1);
  362. if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
  363. print_all_errors();
  364. gb_exit(1);
  365. }
  366. mutex_lock(&global_error_collector.mutex);
  367. push_error_value(pos, ErrorValue_Warning);
  368. // NOTE(bill): Duplicate error, skip it
  369. if (global_error_collector.prev != pos) {
  370. global_error_collector.prev = pos;
  371. error_out_pos(pos);
  372. error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
  373. error_out_va(fmt, va);
  374. error_out("\n");
  375. // show_error_on_line(pos, end);
  376. } else if (pos.line == 0) {
  377. error_out_empty();
  378. error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
  379. error_out_va(fmt, va);
  380. error_out("\n");
  381. }
  382. try_pop_error_value();
  383. mutex_unlock(&global_error_collector.mutex);
  384. }
  385. gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
  386. global_error_collector.count.fetch_add(1);
  387. if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
  388. print_all_errors();
  389. gb_exit(1);
  390. }
  391. mutex_lock(&global_error_collector.mutex);
  392. push_error_value(pos, ErrorValue_Warning);
  393. // NOTE(bill): Duplicate error, skip it
  394. if (pos.line == 0) {
  395. error_out_empty();
  396. error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
  397. error_out_va(fmt, va);
  398. error_out("\n");
  399. } else if (global_error_collector.prev != pos) {
  400. global_error_collector.prev = pos;
  401. error_out_pos(pos);
  402. if (has_ansi_terminal_colours()) {
  403. error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
  404. }
  405. error_out_va(fmt, va);
  406. error_out("\n");
  407. show_error_on_line(pos, end);
  408. }
  409. try_pop_error_value();
  410. mutex_unlock(&global_error_collector.mutex);
  411. }
  412. gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
  413. if (global_warnings_as_errors()) {
  414. syntax_error_va(pos, end, fmt, va);
  415. return;
  416. }
  417. mutex_lock(&global_error_collector.mutex);
  418. global_error_collector.warning_count++;
  419. push_error_value(pos, ErrorValue_Warning);
  420. if (!global_ignore_warnings()) {
  421. // NOTE(bill): Duplicate error, skip it
  422. if (global_error_collector.prev != pos) {
  423. global_error_collector.prev = pos;
  424. error_out_pos(pos);
  425. error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
  426. error_out_va(fmt, va);
  427. error_out("\n");
  428. // show_error_on_line(pos, end);
  429. } else if (pos.line == 0) {
  430. error_out_empty();
  431. error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
  432. error_out_va(fmt, va);
  433. error_out("\n");
  434. }
  435. }
  436. try_pop_error_value();
  437. mutex_unlock(&global_error_collector.mutex);
  438. }
  439. gb_internal void warning(Token const &token, char const *fmt, ...) {
  440. va_list va;
  441. va_start(va, fmt);
  442. warning_va(token.pos, {}, fmt, va);
  443. va_end(va);
  444. }
  445. gb_internal void error(Token const &token, char const *fmt, ...) {
  446. va_list va;
  447. va_start(va, fmt);
  448. error_va(token.pos, {}, fmt, va);
  449. va_end(va);
  450. }
  451. gb_internal void error(TokenPos pos, char const *fmt, ...) {
  452. va_list va;
  453. va_start(va, fmt);
  454. Token token = {};
  455. token.pos = pos;
  456. error_va(pos, {}, fmt, va);
  457. va_end(va);
  458. }
  459. gb_internal void error_line(char const *fmt, ...) {
  460. va_list va;
  461. va_start(va, fmt);
  462. error_line_va(fmt, va);
  463. va_end(va);
  464. }
  465. gb_internal void syntax_error(Token const &token, char const *fmt, ...) {
  466. va_list va;
  467. va_start(va, fmt);
  468. syntax_error_va(token.pos, {}, fmt, va);
  469. va_end(va);
  470. }
  471. gb_internal void syntax_error(TokenPos pos, char const *fmt, ...) {
  472. va_list va;
  473. va_start(va, fmt);
  474. syntax_error_va(pos, {}, fmt, va);
  475. va_end(va);
  476. }
  477. gb_internal void syntax_warning(Token const &token, char const *fmt, ...) {
  478. va_list va;
  479. va_start(va, fmt);
  480. syntax_warning_va(token.pos, {}, fmt, va);
  481. va_end(va);
  482. }
  483. gb_internal void syntax_error_with_verbose(TokenPos pos, TokenPos end, char const *fmt, ...) {
  484. va_list va;
  485. va_start(va, fmt);
  486. syntax_error_with_verbose_va(pos, end, fmt, va);
  487. va_end(va);
  488. }
  489. gb_internal void compiler_error(char const *fmt, ...) {
  490. print_all_errors();
  491. va_list va;
  492. va_start(va, fmt);
  493. gb_printf_err("Internal Compiler Error: %s\n",
  494. gb_bprintf_va(fmt, va));
  495. va_end(va);
  496. GB_DEBUG_TRAP();
  497. gb_exit(1);
  498. }
  499. gb_internal int error_value_cmp(void const *a, void const *b) {
  500. ErrorValue *x = cast(ErrorValue *)a;
  501. ErrorValue *y = cast(ErrorValue *)b;
  502. return token_pos_cmp(x->pos, y->pos);
  503. }
  504. gb_internal void print_all_errors(void) {
  505. auto const &escape_char = [](gbFile *f, u8 c) {
  506. switch (c) {
  507. case '\n': gb_file_write(f, "\\n", 2); break;
  508. case '"': gb_file_write(f, "\\\"", 2); break;
  509. case '\\': gb_file_write(f, "\\\\", 2); break;
  510. case '\b': gb_file_write(f, "\\b", 2); break;
  511. case '\f': gb_file_write(f, "\\f", 2); break;
  512. case '\r': gb_file_write(f, "\\r", 2); break;
  513. case '\t': gb_file_write(f, "\\t", 2); break;
  514. default:
  515. if ('\x00' <= c && c <= '\x1f') {
  516. gb_fprintf(f, "\\u%04x", c);
  517. } else {
  518. gb_file_write(f, &c, 1);
  519. }
  520. break;
  521. }
  522. };
  523. GB_ASSERT(any_errors());
  524. gbFile *f = gb_file_get_standard(gbFileStandard_Error);
  525. array_sort(global_error_collector.error_values, error_value_cmp);
  526. if (json_errors()) {
  527. gb_fprintf(f, "{\n");
  528. gb_fprintf(f, "\t\"error_count\": %td,\n", global_error_collector.error_values.count);
  529. gb_fprintf(f, "\t\"errors\": [\n");
  530. for_array(i, global_error_collector.error_values) {
  531. ErrorValue ev = global_error_collector.error_values[i];
  532. gb_fprintf(f, "\t\t{\n");
  533. gb_fprintf(f, "\t\t\t\"pos\": {\n");
  534. if (ev.pos.file_id) {
  535. gb_fprintf(f, "\t\t\t\t\"file\": \"");
  536. String file = get_file_path_string(ev.pos.file_id);
  537. for (isize k = 0; k < file.len; k++) {
  538. escape_char(f, file.text[k]);
  539. }
  540. gb_fprintf(f, "\",\n");
  541. gb_fprintf(f, "\t\t\t\t\"line\": %d,\n", ev.pos.line);
  542. gb_fprintf(f, "\t\t\t\t\"column\": %d,\n", ev.pos.column);
  543. i32 end_column = gb_max(ev.end.column, ev.pos.column);
  544. gb_fprintf(f, "\t\t\t\t\"end_column\": %d\n", end_column);
  545. gb_fprintf(f, "\t\t\t},\n");
  546. }
  547. gb_fprintf(f, "\t\t\t\"msgs\": [\n");
  548. if (ev.msgs.count > 1) {
  549. gb_fprintf(f, "\t\t\t\t\"");
  550. for (isize j = 1; j < ev.msgs.count; j++) {
  551. String msg = ev.msgs[j];
  552. for (isize k = 0; k < msg.len; k++) {
  553. u8 c = msg.text[k];
  554. if (c == '\n') {
  555. if (k+1 == msg.len && j+1 == ev.msgs.count) {
  556. // don't do the last one
  557. } else {
  558. gb_fprintf(f, "\",\n");
  559. gb_fprintf(f, "\t\t\t\t\"");
  560. }
  561. } else {
  562. escape_char(f, c);
  563. }
  564. }
  565. }
  566. gb_fprintf(f, "\"\n");
  567. }
  568. gb_fprintf(f, "\t\t\t]\n");
  569. gb_fprintf(f, "\t\t}");
  570. if (i+1 != global_error_collector.error_values.count) {
  571. gb_fprintf(f, ",");
  572. }
  573. gb_fprintf(f, "\n");
  574. }
  575. gb_fprintf(f, "\t]\n");
  576. gb_fprintf(f, "}\n");
  577. } else {
  578. for_array(i, global_error_collector.error_values) {
  579. ErrorValue ev = global_error_collector.error_values[i];
  580. for (isize j = 0; j < ev.msgs.count; j++) {
  581. String msg = ev.msgs[j];
  582. gb_file_write(f, msg.text, msg.len);
  583. if (terse_errors() && string_contains_char(msg, '\n')) {
  584. break;
  585. }
  586. }
  587. }
  588. }
  589. }