1
//! `PAIR?` — true when the argument is a non-empty cons cell. A
2
//! compile-time list literal folds to a constant; a runtime `PairRef`
3
//! chain emits `ref.is_null` + `i32.eqz` (non-null ≡ a real cell). Nil
4
//! and atoms are never pairs.
5

            
6
use crate::ast::{Expr, WasmType};
7
use crate::compiler::context::CompileContext;
8
use crate::compiler::emit::FunctionEmitter;
9
use crate::compiler::expr::{compile_for_stack, eval_value, serialize_stack_to_output};
10
use crate::error::{Error, Result};
11
use crate::runtime::SymbolTable;
12

            
13
use super::super::comparison::bool_result;
14

            
15
340
fn is_const_pair(expr: &Expr) -> bool {
16
340
    match expr {
17
        Expr::Cons(_, _) => true,
18
136
        Expr::List(elems) => !elems.is_empty(),
19
136
        Expr::Quote(inner) => is_const_pair(inner),
20
68
        _ => false,
21
    }
22
340
}
23

            
24
pub(super) fn pair_p(symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
25
    if args.len() != 1 {
26
        return Err(Error::Arity {
27
            name: "PAIR?".to_string(),
28
            expected: 1,
29
            actual: args.len(),
30
        });
31
    }
32
    let arg = eval_value(symbols, &args[0])?;
33
    if matches!(arg.wasm_type(), Some(WasmType::PairRef(_))) {
34
        return Ok(Expr::WasmRuntime(WasmType::Bool));
35
    }
36
    Ok(bool_result(is_const_pair(&arg)))
37
}
38

            
39
272
pub(super) fn compile_pair_p(
40
272
    ctx: &mut CompileContext,
41
272
    emit: &mut FunctionEmitter,
42
272
    symbols: &mut SymbolTable,
43
272
    args: &[Expr],
44
272
) -> Result<()> {
45
272
    let ty = compile_pair_p_to_stack(ctx, emit, symbols, args)?;
46
272
    serialize_stack_to_output(ctx, emit, ty)
47
272
}
48

            
49
272
pub(super) fn compile_pair_p_to_stack(
50
272
    ctx: &mut CompileContext,
51
272
    emit: &mut FunctionEmitter,
52
272
    symbols: &mut SymbolTable,
53
272
    args: &[Expr],
54
272
) -> Result<WasmType> {
55
272
    if args.len() != 1 {
56
        return Err(Error::Arity {
57
            name: "PAIR?".to_string(),
58
            expected: 1,
59
            actual: args.len(),
60
        });
61
272
    }
62
272
    let resolved = eval_value(symbols, &args[0])?;
63
272
    if matches!(resolved.wasm_type(), Some(WasmType::PairRef(_))) {
64
68
        compile_for_stack(ctx, emit, symbols, &args[0])?;
65
68
        emit.ref_is_null();
66
68
        emit.i32_eqz();
67
68
        return Ok(WasmType::Bool);
68
204
    }
69
204
    emit.i32_const(i32::from(is_const_pair(&resolved)));
70
204
    Ok(WasmType::Bool)
71
272
}