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
355
fn is_const_pair(expr: &Expr) -> bool {
16
355
    match expr {
17
        Expr::Cons(_, _) => true,
18
142
        Expr::List(elems) => !elems.is_empty(),
19
142
        Expr::Quote(inner) => is_const_pair(inner),
20
71
        _ => false,
21
    }
22
355
}
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
284
pub(super) fn compile_pair_p(
40
284
    ctx: &mut CompileContext,
41
284
    emit: &mut FunctionEmitter,
42
284
    symbols: &mut SymbolTable,
43
284
    args: &[Expr],
44
284
) -> Result<()> {
45
284
    let ty = compile_pair_p_to_stack(ctx, emit, symbols, args)?;
46
284
    serialize_stack_to_output(ctx, emit, ty)
47
284
}
48

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