diff --git a/asm/lumbda.s b/asm/lumbda.s index 907c0c2..b66b39c 100644 --- a/asm/lumbda.s +++ b/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