//! Built-in word definitions and lookup for the Forth VM.

mod compile;
mod core;
mod effects;
mod midi;
mod music;
mod sequencing;
mod sound;

use std::collections::HashMap;
use std::sync::LazyLock;

pub(crate) use compile::compile_word;

/// How a word is compiled into ops.
#[derive(Clone, Copy)]
pub enum WordCompile {
    Simple,
    Context(&'static str),
    Param,
    Probability(f64),
}

/// Metadata for a built-in Forth word.
#[derive(Clone, Copy)]
pub struct Word {
    pub name: &'static str,
    pub aliases: &'static [&'static str],
    pub category: &'static str,
    pub stack: &'static str,
    pub desc: &'static str,
    pub example: &'static str,
    pub compile: WordCompile,
    pub varargs: bool,
}

/// All built-in words, aggregated from every category module.
pub static WORDS: LazyLock<Vec<Word>> = LazyLock::new(|| {
    let mut words = Vec::new();
    words.extend_from_slice(self::core::WORDS);
    words.extend_from_slice(sound::WORDS);
    words.extend_from_slice(effects::WORDS);
    words.extend_from_slice(sequencing::WORDS);
    words.extend_from_slice(music::WORDS);
    words.extend_from_slice(midi::WORDS);
    words
});

/// Index mapping word names and aliases to their definitions.
static WORD_MAP: LazyLock<HashMap<&'static str, &'static Word>> = LazyLock::new(|| {
    let mut map = HashMap::with_capacity(WORDS.len() * 2);
    for word in WORDS.iter() {
        map.insert(word.name, word);
        for alias in word.aliases {
            map.insert(alias, word);
        }
    }
    map
});

/// Find a word by name or alias.
pub fn lookup_word(name: &str) -> Option<&'static Word> {
    WORD_MAP.get(name).copied()
}
