marwood 1.0.0

Scheme R7RS Virtual Machine
Documentation
use crate::error::Error;
use crate::vm::builtin::{pop_argc, pop_string, pop_symbol};
use crate::vm::vcell::VCell;
use crate::vm::Vm;
use crate::{lex, parse};

pub fn load_builtins(vm: &mut Vm) {
    vm.load_builtin("string->symbol", string_symbol);
    vm.load_builtin("symbol->string", symbol_string);
    vm.load_builtin("symbol=?", symbol_eq);
}

pub fn string_symbol(vm: &mut Vm) -> Result<VCell, Error> {
    pop_argc(vm, 1, Some(1), "string->symbol")?;
    let s = pop_string(vm, "string->append")?;
    let s = s.borrow();
    let s = s.as_str();
    let sym = s
        .char_indices()
        .map(|(idx, c)| match c {
            c if idx == 0 && lex::is_initial_identifier(c) => c.to_string(),
            c if idx > 0 && lex::is_subsequent_identifier(c) => c.to_string(),
            c => format!("\\x{:x};", c as u32),
        })
        .collect::<String>();
    Ok(VCell::symbol(sym))
}

pub fn symbol_string(vm: &mut Vm) -> Result<VCell, Error> {
    pop_argc(vm, 1, Some(1), "symbol->string")?;
    let sym = pop_symbol(vm, "symbol->string")?;
    let s = parse::parse_string(sym.as_str())?;
    Ok(VCell::string(s.to_string()))
}

fn symbol_eq(vm: &mut Vm) -> Result<VCell, Error> {
    let argc = pop_argc(vm, 1, None, "symbol=?")?;
    let mut result = true;

    let mut y = pop_symbol(vm, "symbol=?")?;
    for _ in 0..argc - 1 {
        let x = pop_symbol(vm, "symbol=?")?;
        {
            if x.as_str() != y.as_str() {
                result = false;
            }
        }
        y = x;
    }

    Ok(result.into())
}