diff options
| author | 2026-10-14 15:54:04 +0330 | |
|---|---|---|
| committer | 2026-10-14 15:54:04 +0330 | |
| commit | 0879d0a42d137054057cd2a1e37437e6be78ed0b (patch) | |
| tree | fcb16d3185c1f80fae8d54cd9062bd68d6c0c88d /src/compiler/base.zc | |
| parent | merge spec conformance suite (diff) | |
| parent | merge main into work/line-tables (diff) | |
merge line tables
Diffstat (limited to 'src/compiler/base.zc')
| -rw-r--r-- | src/compiler/base.zc | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/src/compiler/base.zc b/src/compiler/base.zc index d83dc9d..2f802b9 100644 --- a/src/compiler/base.zc +++ b/src/compiler/base.zc @@ -224,6 +224,16 @@ char[1100] tbuf_initial; char* tbuf = tbuf_initial; int tbufcap = 1100; // collects them in dbuf, dlast is the line of the last one, and dline the // line of the token that follows them. only when docs are on. int docs_on; // docs on; keeps them: a symbol "doc name" holds a byte string +// line tables: lines on; (the default) records, for each function compiled, its entry, its end and the +// source line of each statement, as a line block among the code that rt.line_blocks chains (see +// rt.zc). lt_buf holds the pairs of the functions being compiled, innermost last, each as a frame +// [outer frame, entry, name, file, 0, offset << 32 | line ...]; lt_base is the innermost frame. +// lt_head is the newest block of an image being built, whose own rt.line_blocks it will become. +int lines_on = 1; +// //:lines NAME (see mark_line): the markers the lexer has met, [lines before the file, NAME] each, and the +// one in force, which a top-level item applies when it is reached +word lt_marks; int lt_nmarks, lt_markcap, lt_next_mark; char* lt_mark_file; int lt_mark_base; +word lt_buf, lt_head, lt_file_at; int lt_top, lt_cap, lt_base = 0 - 1, lt_file_img; char* lt_file; char[2100] dbuf_initial; char* dbuf = dbuf_initial; int docbufcap = 2100; int dn, dlast, dline, docpending, dsect; char[2100] dsnap_initial; char* dsnap = dsnap_initial; int docsnapcap = 2100; int dsn, dnm; char[300] dnmb_initial; char* dnmb = dnmb_initial; int docnamecap = 300; int pk_tk, pk_tv, pq_n; word[4] pq_tk; word[4] pq_tv; word[4] pq_gl; word[4] pq_ln; // up to 4 tokens of lookahead @@ -299,7 +309,7 @@ word tdstk; int ntd, tdcap; word readonly_types; int dty, dtag; // result of dtype() int s_typedef; -int s_lt, s_gt, s_shr, s_le, s_ge, s_eqeq, s_ne, s_plus, s_struct, s_type, s_typecheck, s_docs, s_small, s_std, s_icon, s_on, s_off, s_new, s_new_t; +int s_lt, s_gt, s_shr, s_le, s_ge, s_eqeq, s_ne, s_plus, s_struct, s_type, s_typecheck, s_docs, s_lines, s_small, s_std, s_icon, s_on, s_off, s_new, s_new_t; int s_o3, s_lfa, s_outside, s_new_raw, s_new_oz, s_oob; int s_ld8, s_st8, s_ld16, s_st16, s_ld32, s_st32; // ---- o3 region state ---- @@ -1222,6 +1232,83 @@ int hole() { lit(rt.MW - 1); return a; } +// ---- line tables ---- + +// make room for n more words of pairs. +int lt_room(int n) { + int cap = lt_cap; + if (lt_top + n <= cap) return 0; + if (cap < 256) cap = 256; + while (lt_top + n > cap) cap = cap * 2; + lt_buf = chk_resize(lt_buf, lt_top, cap); lt_cap = cap; + return 0; +} +// start recording the function whose code begins at entry, named name, with its header on line. +// returns the frame to give lt_end, or -1 when no table is being made (lines off, a dry run, +// check mode). +int lt_begin(int entry, char* name, int line) { + int b; + if (!lines_on || dry || cmode) return 0 - 1; + lt_room(8); + b = lt_top; + lt_buf[b] = lt_base; lt_buf[b + 1] = entry; lt_buf[b + 2] = name; lt_buf[b + 3] = curinc; lt_buf[b + 4] = 0; + if (!curinc) { lt_buf[b + 3] = lt_mark_file; lt_buf[b + 4] = lt_mark_base; } // the main source may be marked as a file of its own + lt_top = b + 5; lt_base = b; + lt_buf[lt_top] = line - lt_buf[b + 4]; lt_top++; // the code before the first statement belongs to the header's line + return b; +} +// a statement begins at the current token, and its code at here. +int lt_stmt() { + int off, n; + if (lt_base < 0 || dry) return 0; + off = here - lt_buf[lt_base + 1]; + if (off < 0) return 0; + lt_room(2); + if (lt_top > lt_base + 5 && (lt_buf[lt_top - 1] >> 32) == off) lt_top--; // same place: the later statement is the one + n = tline - lt_buf[lt_base + 4]; + if (lt_top > lt_base + 5 && (lt_buf[lt_top - 1] & 4294967295) == n) return 0; + lt_buf[lt_top] = off * 4294967296 + n; lt_top++; + return 0; +} +// the file name in a block: the include's path, or <stdin> for the main source. one copy of the +// bytes is shared by the blocks that follow it. +int lt_file_data(char* f) { + if (!f) f = "<stdin>"; + if (lt_file_at && lt_file_img == image_active && rt.eq_w(lt_file, f)) return lt_file_at; + lt_file_at = bstrdata(f); lt_file_img = image_active; + lt_file = chk_resize(0, 0, rt.len_w(f) + 1); rt.copy_w(lt_file, f, rt.len_w(f) + 1); + return lt_file_at; +} +// finish the function begun at frame b, whose code ends at end: put its line block among the code +// and chain it. a block is [next, entry, end, name, file, count, pairs...]. +int lt_end(int b, int end) { + int entry, count, i = 0, name, file, blk, need; word head; char* nm; char* fl; + if (b < 0) return 0; + entry = lt_buf[b + 1]; nm = lt_buf[b + 2]; fl = lt_buf[b + 3]; count = lt_top - (b + 5); + if (!nm) nm = "<fn>"; + if (!fl) fl = "<stdin>"; + if (end >= entry && !dry) { + need = 8 + count + ((rt.len_w(nm) + 7) >> 3) + 2 + ((rt.len_w(fl) + 7) >> 3) + 2; + reserve_code(need); + name = bstrdata(nm); file = lt_file_data(fl); + if (image_active) head = lt_head; else head = rt.line_blocks; + blk = here; + emit(head); emit(entry); emit(end); emit(name); emit(file); emit(count); + while (i < count) { emit(lt_buf[b + 5 + i]); i++; } + if (image_active) lt_head = blk; else rt.line_blocks = blk; + } + lt_top = b; lt_base = lt_buf[b]; + return 0; +} +// at the top level, a marker that comes before the item takes effect: lines are on, in its file. +int lt_apply_marks() { + if (incdepth || ginst) return 0; + while (lt_next_mark < lt_nmarks && lt_marks[lt_next_mark * 2] < tline) { + lt_mark_base = lt_marks[lt_next_mark * 2]; lt_mark_file = lt_marks[lt_next_mark * 2 + 1]; + lines_on = 1; lt_next_mark++; + } + return 0; +} // forward references. calling a function that is not defined yet creates a // symbol with F_DEF clear whose value is the place of its first use (for the // "never defined" error). each call site emits a placeholder literal and adds |
