asm: when/unless as always-on special forms (defect #31)
ecdsa cross-tier validation blocked on `when` and `unless` being
unbound on the asm tier. R7RS standard control forms — present on
Python (lumbda.py) and C (c/) tiers, but absent on asm because the
existing macro facility (define-macro) only ships under CL_FULL.
Path B chosen (special-form dispatch table extension):
- sf_when / sf_unless length-prefixed symbol names
- sym_when_val / sym_unless_val interned at init_special_forms
- dispatch cases in .eval_top alongside .ev_and / .ev_or
- .ev_when / .ev_unless evaluators reuse .ev_begin for the body
branch and .ev_begin_void for the skip branch (TCO preserved)
Available on every asm tier (plain `lumbda`, `lumbda-gc`,
`lumbda-full`). Binary size impact:
lumbda 60488 → 60768 (+280, +0.46%)
lumbda-gc 69224 → 69496 (+272, +0.39%)
lumbda-full 71720 → 72000 (+280, +0.39%)
All 158 asm tests still pass. Tested truthy/falsy/multi-form bodies
on all three tiers. ecdsa search.lsp now runs on asm-full with output
byte-identical to Python tier (v3-clifford-only winner, score 0).
Note: ecdsa search.lsp also depends on `case`, which is only present
under CL_FULL (carved into cl_full_prelude as a define-macro form).
That gap blocks lumbda-gc cross-tier validation and is out of scope
for this commit.
This commit is contained in:
parent
297ae976e2
commit
865be28091
1 changed files with 62 additions and 0 deletions
62
asm/lumbda.s
62
asm/lumbda.s
|
|
@ -246,6 +246,8 @@ sf_define_mac: .byte 12; .ascii "define-macro"
|
|||
sf_and: .byte 3; .ascii "and"
|
||||
sf_or: .byte 2; .ascii "or"
|
||||
sf_else: .byte 4; .ascii "else"
|
||||
sf_when: .byte 4; .ascii "when"
|
||||
sf_unless: .byte 6; .ascii "unless"
|
||||
|
||||
# Builtin names (length-prefixed)
|
||||
bn_add: .byte 1; .ascii "+"
|
||||
|
|
@ -554,6 +556,8 @@ sym_define_mac_val: .quad 0
|
|||
sym_and_val: .quad 0
|
||||
sym_or_val: .quad 0
|
||||
sym_else_val: .quad 0
|
||||
sym_when_val: .quad 0
|
||||
sym_unless_val: .quad 0
|
||||
|
||||
# ============================================================
|
||||
.bss
|
||||
|
|
@ -2811,6 +2815,10 @@ eval:
|
|||
je .ev_and
|
||||
cmpq sym_or_val(%rip), %rbx
|
||||
je .ev_or
|
||||
cmpq sym_when_val(%rip), %rbx
|
||||
je .ev_when
|
||||
cmpq sym_unless_val(%rip), %rbx
|
||||
je .ev_unless
|
||||
.ifdef CL_FULL
|
||||
cmpq sym_quasiquote_val(%rip), %rbx
|
||||
je .ev_quasiquote
|
||||
|
|
@ -3517,6 +3525,52 @@ env_set_both:
|
|||
popq %rbx
|
||||
ret
|
||||
|
||||
# ---- when ----
|
||||
# (when test body...) — if test is truthy, eval body as begin;
|
||||
# else return void. Available on every asm tier (defect #31 in our
|
||||
# ecdsa cross-tier validation: when/unless are R7RS standard but
|
||||
# previously only reachable on tiers carrying define-macro).
|
||||
.ev_when:
|
||||
# %r12 = (test body...)
|
||||
cmpq $VAL_NIL, %r12
|
||||
je .ev_begin_void # (when) → void (degenerate)
|
||||
movq %r12, %rax
|
||||
andq $-8, %rax
|
||||
movq (%rax), %rdi # test expr
|
||||
movq 8(%rax), %r12 # body forms
|
||||
pushq %r12
|
||||
movq %rbp, %rsi
|
||||
call eval
|
||||
popq %r12
|
||||
cmpq $VAL_FALSE, %rax
|
||||
je .ev_begin_void
|
||||
cmpq $VAL_NIL, %rax
|
||||
je .ev_begin_void
|
||||
# Truthy → run body via begin (TCO on last form)
|
||||
jmp .ev_begin
|
||||
|
||||
# ---- unless ----
|
||||
# (unless test body...) — inverse of when.
|
||||
.ev_unless:
|
||||
cmpq $VAL_NIL, %r12
|
||||
je .ev_begin_void # (unless) → void
|
||||
movq %r12, %rax
|
||||
andq $-8, %rax
|
||||
movq (%rax), %rdi # test expr
|
||||
movq 8(%rax), %r12 # body forms
|
||||
pushq %r12
|
||||
movq %rbp, %rsi
|
||||
call eval
|
||||
popq %r12
|
||||
cmpq $VAL_FALSE, %rax
|
||||
je .ev_unless_run
|
||||
cmpq $VAL_NIL, %rax
|
||||
je .ev_unless_run
|
||||
# Truthy → skip body, return void
|
||||
jmp .ev_begin_void
|
||||
.ev_unless_run:
|
||||
jmp .ev_begin
|
||||
|
||||
.ifdef CL_FULL
|
||||
# ---- quasiquote (CL_FULL only) ----
|
||||
# (quasiquote template) walks `template`:
|
||||
|
|
@ -8606,6 +8660,14 @@ init_special_forms:
|
|||
call intern_static
|
||||
movq %rax, sym_else_val(%rip)
|
||||
|
||||
leaq sf_when(%rip), %rdi
|
||||
call intern_static
|
||||
movq %rax, sym_when_val(%rip)
|
||||
|
||||
leaq sf_unless(%rip), %rdi
|
||||
call intern_static
|
||||
movq %rax, sym_unless_val(%rip)
|
||||
|
||||
# Intern the multi-value marker symbol used by (values) and
|
||||
# (call-with-values). Stored once at init.
|
||||
leaq bn_mval_tag(%rip), %rdi
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue