ksl 0.1.30

KSL core library and interpreter
Documentation
//! # ksl::builtin::thread
//!
//! Built-in function `Thread`.

use crate::{
    Environment,
    INIT_STACK_SIZE,
    eval::apply::eval_apply,
    init_environment,
    is_invalid_symbol,
    read_from_environment,
    value::Value,
};

pub(crate) fn builtin(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [symbol, syms, applicable] = args {
        let var_name = match symbol {
            Value::Symbol(var) => {
                if is_invalid_symbol(var) {
                    return Err(std::sync::Arc::from(format!(
                        concat!(
                            "Error[ksl::builtin::Thread]: ",
                            "Rebinding of symbol `{}` is not permitted."
                        ),
                        var
                    )));
                }
                var.clone()
            }
            e => {
                return Err(std::sync::Arc::from(format!(
                    concat!(
                        "Error[ksl::builtin::Thread]: ",
                        "Expected a Symbol for thread name, but got `{}`."
                    ),
                    e
                )));
            }
        };
        // thread environment
        let thread_env = init_environment(None);
        match syms {
            Value::List(symbols) => {
                // capture symbols
                for symbol in symbols.iter() {
                    match symbol {
                        Value::Symbol(name) => {
                            if let Some(val) = read_from_environment(&env, name) {
                                let _ = thread_env.store.write().insert(name.clone(), val);
                            } else {
                                return Err(std::sync::Arc::from(format!(
                                    concat!(
                                        "Error[ksl::builtin::Thread]: ",
                                        "Unknown symbol `{}` in capture list."
                                    ),
                                    name
                                )));
                            }
                        }
                        e => {
                            return Err(std::sync::Arc::from(format!(
                                concat!(
                                    "Error[ksl::builtin::Thread]: ",
                                    "Unexpected value in capture list: `{}`."
                                ),
                                e
                            )));
                        }
                    }
                }
            }
            e => {
                return Err(std::sync::Arc::from(format!(
                    concat!(
                        "Error[ksl::builtin::Thread]: ",
                        "Expected a List of symbols to capture, but got `{}`."
                    ),
                    e
                )));
            }
        }
        // prepare execution body
        let execution_node = match applicable {
            Value::Symbol(func_sym) => match read_from_environment(&env, func_sym) {
                Some(func_body) => Value::Apply(Vec::new(), func_body),
                None => {
                    return Err(std::sync::Arc::from(format!(
                        "Error[ksl::builtin::Thread]: Unknown function symbol `{}`.",
                        func_sym
                    )));
                }
            },
            node @ Value::Apply(_, _) => node.clone(),
            func @ (Value::Lambda(_, _, _) | Value::Plugin(_, _)) => {
                Value::Apply(Vec::new(), std::sync::Arc::new(func.clone()))
            }
            e => {
                return Err(std::sync::Arc::from(format!(
                    "Error[ksl::builtin::Thread]: Invalid applicable value: `{}`.",
                    e
                )));
            }
        };

        // start thread
        let thread_handle_res = std::thread::Builder::new()
            .stack_size(INIT_STACK_SIZE)
            .spawn(move || eval_apply(&execution_node, thread_env));

        match thread_handle_res {
            Ok(handle) => {
                let _ = env.store.write().insert(
                    var_name,
                    std::sync::Arc::new(Value::Thread(std::sync::Arc::new(parking_lot::Mutex::new(
                        Some(handle),
                    )))),
                );
                Ok(Value::Unit)
            }
            Err(e) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::Thread]: Failed to spawn thread: `{}`.",
                e
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::Thread]: Expected 3 parameters, but {} were passed.",
            args.len()
        )))
    }
}