boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs

commit cf5649c34ff07930d8d5bff5b9c6f37d332d5aba
parent 48971a6c16a856b6b0fd6beafa72d2a170cab648
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 23 Apr 2026 17:20:19 -0700

m1pp.M1: port local labels (:@name, &@name)

Diffstat:
Mm1pp/m1pp.M1 | 261++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 259 insertions(+), 2 deletions(-)

diff --git a/m1pp/m1pp.M1 b/m1pp/m1pp.M1 @@ -1901,6 +1901,15 @@ DEFINE EXPR_INVALID 1100000000000000 la_br &err_bad_macro_header bne_t0,t1 + # expansion_id = ++next_expansion_id (monotonic; used by local-label + # rewriting in the body-copy path to rename :@name / &@name tokens). + la_a0 &next_expansion_id + ld_t0,a0,0 + addi_t0,t0,1 + st_t0,a0,0 + la_a1 &emt_expansion_id + st_t0,a1,0 + # Snapshot call_end_pos -> emt_after_pos before the body walk, so # nothing in the substitution loop can clobber the resume position. la_a0 &call_end_pos @@ -1946,8 +1955,9 @@ DEFINE EXPR_INVALID 1100000000000000 la_br &find_param call - # if (param_idx == 0) fall through to copy literal body token - la_br &emt_copy_literal + # if (param_idx == 0) body-native token: check for local-label rewrite, + # else fall through to substitute logic. + la_br &emt_check_local_label beqz_a0 # param_idx != 0: substitute. emt_do_substitute_* will re-derive @@ -2001,6 +2011,218 @@ DEFINE EXPR_INVALID 1100000000000000 la_br &emt_do_substitute_plain b +## emt_check_local_label: body-native token at body_pos. If it's a +## TOK_WORD whose text starts with ":@" or "&@" and has at least one +## char after the '@', rewrite it to ":name__NN" / "&name__NN" (NN = +## emt_expansion_id) and push as TOK_WORD. Otherwise fall through to +## emt_copy_literal, which copies the body token verbatim. +:emt_check_local_label + # t0 = body_tok ptr + la_a0 &emt_body_pos + ld_t0,a0,0 + # kind must be TOK_WORD (== 0) + ld_a1,t0,0 + la_br &emt_copy_literal + bnez_a1 + # len must be >= 3 (sigil + '@' + >=1 tail char) + ld_a2,t0,16 + li_a3 %3 %0 + la_br &emt_copy_literal + blt_a2,a3 + # first byte must be ':' (58) or '&' (38) + ld_a3,t0,8 + lb_a1,a3,0 + li_a2 %58 %0 + la_br &emt_check_local_label_at + beq_a1,a2 + li_a2 %38 %0 + la_br &emt_copy_literal + bne_a1,a2 +:emt_check_local_label_at + # second byte must be '@' (64) + lb_a1,a3,1 + li_a2 %64 %0 + la_br &emt_copy_literal + bne_a1,a2 + # Local label! Fall through to rewrite. + +## emt_rewrite_local_label: build "sigil + tail + __ + decimal(NN)" in +## local_label_scratch, stash it into text_buf via append_text, and push +## a TOK_WORD to expand_pool. +:emt_rewrite_local_label + # Stash body_tok text_ptr / text_len into BSS so they survive + # function calls (append_text is non-leaf via its arena bump). + la_a0 &emt_body_pos + ld_t0,a0,0 + ld_a1,t0,8 + la_a2 &ll_src_ptr + st_a1,a2,0 + ld_a1,t0,16 + la_a2 &ll_src_len + st_a1,a2,0 + + # --- Convert emt_expansion_id to decimal, reverse-fill into + # --- local_label_digits[0..24). Write right-to-left starting at + # --- offset 23 so digits are adjacent at [cursor, &scratch+24). + la_a0 &emt_expansion_id + ld_t0,a0,0 # t0 = id (mutated) + la_t1 &local_label_digits + li_a2 %24 %0 + add_t1,t1,a2 # t1 = end (one past last slot) + mov_t2,t1 # t2 = cursor (moves left) + + # Special-case id == 0 -> single '0' digit. + la_br &emt_rldg_loop + bnez_t0 + addi_t2,t2,neg1 + li_a0 %48 %0 + sb_a0,t2,0 + la_br &emt_rldg_done + b +:emt_rldg_loop + la_br &emt_rldg_done + beqz_t0 + # digit = id % 10 + mov_a0,t0 + li_a1 %10 %0 + rem_a2,a0,a1 # a2 = id % 10 + addi_a2,a2,48 # a2 = '0' + digit + addi_t2,t2,neg1 + sb_a2,t2,0 # *--cursor = digit + # id = id / 10 + mov_a0,t0 + li_a1 %10 %0 + div_a0,a0,a1 + mov_t0,a0 + la_br &emt_rldg_loop + b +:emt_rldg_done + # digit_count = end - cursor + la_a1 &local_label_digits + li_a2 %24 %0 + add_a1,a1,a2 # a1 = end + sub_a0,a1,t2 # a0 = digit_count + la_a1 &ll_digit_count + st_a0,a1,0 + # Save cursor (start of digits) for the copy step. + la_a1 &ll_digit_cursor + st_t2,a1,0 + + # --- Build final text in local_label_scratch --- + # Layout: [0]=sigil, [1..1+tail_len)=tail, then "__", then digits. + # tail_len = len - 2 + + # Write sigil (src_ptr[0]) to scratch[0]. + la_a0 &ll_src_ptr + ld_a1,a0,0 + lb_a2,a1,0 + la_a3 &local_label_scratch + sb_a2,a3,0 + + # Copy tail: scratch[1..1+tail_len) <- src_ptr[2..2+tail_len). + la_a0 &ll_src_len + ld_a1,a0,0 + li_a2 %2 %0 + sub_t0,a1,a2 # t0 = tail_len = src_len - 2 + la_a0 &ll_src_ptr + ld_a1,a0,0 # a1 = src_ptr + addi_a1,a1,2 # a1 = src_ptr + 2 (tail start) + la_a2 &local_label_scratch + addi_a2,a2,1 # a2 = scratch + 1 (dst tail start) + li_t1 %0 %0 # t1 = i +:emt_rlbuild_tail_loop + la_br &emt_rlbuild_tail_done + beq_t1,t0 + add_a3,a1,t1 + lb_a3,a3,0 + add_t2,a2,t1 + sb_a3,t2,0 + addi_t1,t1,1 + la_br &emt_rlbuild_tail_loop + b +:emt_rlbuild_tail_done + # Save tail_len for later offset math. + la_a0 &ll_tail_len + st_t0,a0,0 + + # Write "__" at scratch[1+tail_len], scratch[2+tail_len]. + la_a2 &local_label_scratch + addi_a2,a2,1 + add_a2,a2,t0 # a2 = &scratch[1+tail_len] + li_a3 %95 %0 # '_' + sb_a3,a2,0 + addi_a2,a2,1 + sb_a3,a2,0 + + # Copy digits: scratch[3+tail_len..3+tail_len+digit_count) <- digit_cursor[0..digit_count). + la_a0 &ll_digit_count + ld_t1,a0,0 # t1 = digit_count + la_a0 &ll_digit_cursor + ld_a1,a0,0 # a1 = digit_cursor (src) + la_a0 &ll_tail_len + ld_t0,a0,0 # t0 = tail_len + la_a2 &local_label_scratch + addi_a2,a2,3 + add_a2,a2,t0 # a2 = &scratch[3+tail_len] (dst) + li_t2 %0 %0 # t2 = i +:emt_rlbuild_digits_loop + la_br &emt_rlbuild_digits_done + beq_t2,t1 + add_a3,a1,t2 + lb_a3,a3,0 + add_a0,a2,t2 + sb_a3,a0,0 + addi_t2,t2,1 + la_br &emt_rlbuild_digits_loop + b +:emt_rlbuild_digits_done + + # total_len = 1 + tail_len + 2 + digit_count = 3 + tail_len + digit_count + la_a0 &ll_tail_len + ld_a1,a0,0 + la_a0 &ll_digit_count + ld_a2,a0,0 + add_a1,a1,a2 + addi_a1,a1,3 + la_a0 &ll_total_len + st_a1,a0,0 + + # durable_ptr = append_text(&local_label_scratch, total_len) + la_a0 &local_label_scratch + la_br &append_text + call + # a0 = durable_ptr (into text_buf) + + # Push TOK_WORD { kind=0, text_ptr=durable_ptr, text_len=total_len } to expand_pool. + la_a1 &pool_used + ld_t0,a1,0 + li_a2 M1PP_EXPAND_CAP + la_br &err_token_overflow + beq_t0,a2 + la_a3 &expand_pool + add_a3,a3,t0 # a3 = dst slot + # kind = TOK_WORD + li_a2 TOK_WORD + st_a2,a3,0 + # text_ptr + st_a0,a3,8 + # text_len + la_a0 &ll_total_len + ld_a2,a0,0 + st_a2,a3,16 + # pool_used += 24 + addi_t0,t0,24 + la_a1 &pool_used + st_t0,a1,0 + + # body_pos += 24 + la_a0 &emt_body_pos + ld_t0,a0,0 + addi_t0,t0,24 + st_t0,a0,0 + la_br &emt_loop + b + :emt_copy_literal # Append *body_pos to expand_pool. Check overflow. la_a0 &pool_used @@ -4424,6 +4646,41 @@ ZERO8 ZERO8 :emt_body_start ZERO8 + +## Local-label rewrite (ยง1). next_expansion_id is the monotonic counter +## (never reset); emt_expansion_id snapshots it at the start of each +## expand_macro_tokens call so nested-call BSS reuse is safe. +## ll_* slots hold body-token span + derived sizes while building the +## renamed text in local_label_scratch. +:next_expansion_id +ZERO8 +:emt_expansion_id +ZERO8 +:ll_src_ptr +ZERO8 +:ll_src_len +ZERO8 +:ll_tail_len +ZERO8 +:ll_digit_count +ZERO8 +:ll_digit_cursor +ZERO8 +:ll_total_len +ZERO8 + +## local_label_digits: 24-byte reverse-fill scratch for the decimal +## rendering of emt_expansion_id (fits any u64 value). +:local_label_digits +ZERO8 ZERO8 ZERO8 + +## local_label_scratch: 128-byte working buffer for the renamed text +## (sigil + tail + "__" + digits) before it's copied into text_buf via +## append_text. Caps the combined tail + digit length at ~125 bytes, +## which is ample for any realistic local-label name. +:local_label_scratch +ZERO32 ZERO32 ZERO32 ZERO32 + :fp_macro ZERO8 :fp_tok